submission 99179
Petr_Rocoss · python · License unknown
Use it
Vendorable · source mirrored · license unknownView source →
No package. Vendor the mirrored source: 162 lines, June 9 Researcher Reciprocity License v1.0.
100.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-conv2d-v2-99179?include=source"interfacepython
Compatibility
measured onNVIDIA A100
declared hardwareNVIDIA A100
architecturessm_80
dtypesfp32
Benchmark evidence
1 measurement across 1 GPU, fastest first.
Operation / workload
Hardware
Latency
Rank
Observed
Reported · How evidence levels are derived →
Source and license
sourceavailable
revision digestsha256:2f26fdcb89230f4a896d4ed34c61d8e30c8225ba1fd16e3c61393a4d2ca61905
license declaredunknown
license concludedunknown
authorsPetr_Rocoss
imported2026-08-15
Techniques
Extracted from the mirrored source by pattern, never inferred. Each row cites its line.
autotune
@triton.autotune(num-warps = 8
triton.Config({'BLOCK_H': 8, 'BLOCK_W': 128}, num_warps=8, num_stages=6),stages = 6
triton.Config({'BLOCK_H': 8, 'BLOCK_W': 128}, num_warps=8, num_stages=6),Kernel source
100.py162 lines
import torch
import triton
import triton.language as tl
@triton.autotune(
configs=[
# === A100 / H100 Optimized Configs ===
# Большой BLOCK_W для векторизации + высокий num_stages для HBM prefetch
triton.Config({'BLOCK_H': 8, 'BLOCK_W': 128}, num_warps=8, num_stages=6),
triton.Config({'BLOCK_H': 4, 'BLOCK_W': 256}, num_warps=8, num_stages=5),
triton.Config({'BLOCK_H': 8, 'BLOCK_W': 64}, num_warps=4, num_stages=5),
triton.Config({'BLOCK_H': 16, 'BLOCK_W': 64}, num_warps=8, num_stages=4),
# === Fallback / Smaller GPUs (L4) ===
triton.Config({'BLOCK_H': 4, 'BLOCK_W': 128}, num_warps=4, num_stages=4),
triton.Config({'BLOCK_H': 2, 'BLOCK_W': 64}, num_warps=4, num_stages=3),
],
key=['W_OUT', 'H_OUT', 'C_IN', 'K'],
)
@triton.jit
def conv2d_kernel_a100(
input_ptr, weight_ptr, output_ptr,
stride_in_n, stride_in_c, stride_in_h, stride_in_w,
stride_w_out, stride_w_in, stride_w_h, stride_w_w,
stride_out_n, stride_out_c, stride_out_h, stride_out_w,
H_IN, W_IN, H_OUT, W_OUT, C_IN, C_OUT, K,
BLOCK_H: tl.constexpr, BLOCK_W: tl.constexpr
):
# --- 1. Инициализация Grid ---
pid_w = tl.program_id(0)
pid_h = tl.program_id(1)
pid_z = tl.program_id(2)
batch_idx = pid_z // C_OUT
out_ch = pid_z % C_OUT
# --- 2. Предварительный расчет смещений (Offsets) ---
# Генерируем индексы для текущего тайла [BLOCK_H, BLOCK_W]
offs_h = pid_h * BLOCK_H + tl.arange(0, BLOCK_H)
offs_w = pid_w * BLOCK_W + tl.arange(0, BLOCK_W)
# --- 3. Расчет Масок (Masks) ---
# Вычисляем маски один раз.
# Примечание: при stride=1 и padding=0, если выходной индекс валиден,
# то соответствующий входной (out + k) тоже валиден (при корректных input shapes).
mask_h = offs_h < H_OUT
mask_w = offs_w < W_OUT
# Комбинированная маска [BLOCK_H, BLOCK_W]
mask_block = mask_h[:, None] & mask_w[None, :]
# --- 4. Базовые указатели (Pointers Setup) ---
# Указатель вывода: Base + Batch + OutCh + (H_range, W_range)
# Используем broadcasting для создания 2D сетки адресов
ptr_out = output_ptr + \
batch_idx * stride_out_n + \
out_ch * stride_out_c + \
(offs_h[:, None] * stride_out_h) + \
(offs_w[None, :] * stride_out_w)
# Базовый указатель входа. Начинается с верхнего левого угла окна свертки.
# ptr_in[h, w] соответствует пикселю input[h, w] (так как stride=1)
ptr_in_base = input_ptr + \
batch_idx * stride_in_n + \
(offs_h[:, None] * stride_in_h) + \
(offs_w[None, :] * stride_in_w)
# Базовый указатель весов для текущего выходного канала
ptr_wei_base = weight_ptr + out_ch * stride_w_out
# Аккумулятор (Registers)
acc = tl.zeros([BLOCK_H, BLOCK_W], dtype=tl.float32)
# --- 5. Основной цикл (Pointer Chasing Optimization) ---
# Инициализируем текущие указатели
curr_in_ch = ptr_in_base
curr_wei_ch = ptr_wei_base
for cin in range(C_IN):
# Временные указатели для spatial loops, чтобы не портить указатели каналов
curr_in_spatial = curr_in_ch
curr_wei_spatial = curr_wei_ch
# Разворачиваем циклы ядра (Spatial Loops)
for kh in range(K):
# Вычисляем смещения для текущей строки ядра
# Для входа это смещение по высоте
# Для веса это смещение по высоте
for kw in range(K):
# A. Загрузка Веса (Scalar Broadcast)
# Считываем одно значение веса и рассылаем всем нитям блока
# Адрес: curr_wei + kw * stride_w
w_val = tl.load(curr_wei_spatial + kw * stride_w_w)
# B. Загрузка Входа (Vectorized Block Load)
# Адрес: curr_in + kw * stride_w
# Благодаря broadcasting при инициализации, это загружает блок [BLOCK_H, BLOCK_W]
# Сдвигаем окно вправо на kw
in_val = tl.load(curr_in_spatial + kw * stride_in_w, mask=mask_block, other=0.0)
# C. FMA (Fused Multiply-Add)
acc = acc + in_val * w_val
# Pointer Update (Vertical Shift)
# Сдвигаем указатели вниз на одну строку
curr_in_spatial += stride_in_h
curr_wei_spatial += stride_w_h
# Pointer Update (Channel Shift)
# Переходим к следующему входному каналу
curr_in_ch += stride_in_c
curr_wei_ch += stride_w_in
# --- 6. Запись результата ---
tl.store(ptr_out, acc, mask=mask_block)
def custom_kernel(data):
"""
Wrapper function ensuring optimal memory layout for A100 kernel.
"""
input_tensor, kernel, output_tensor = data
# 1. Contiguous Memory: Критически важно для векторизации на A100.
# Без этого Triton будет генерировать неэффективные загрузки (scalar loads).
if not input_tensor.is_contiguous():
input_tensor = input_tensor.contiguous()
if not kernel.is_contiguous():
kernel = kernel.contiguous()
# 2. Извлечение размеров
batch, c_in, h_in, w_in = input_tensor.shape
c_out, _, k_h, k_w = kernel.shape
h_out = h_in - k_h + 1
w_out = w_in - k_w + 1
# 3. Определение Grid запуска
# Делим выходное изображение на тайлы [BLOCK_H, BLOCK_W]
grid = lambda META: (
triton.cdiv(w_out, META['BLOCK_W']),
triton.cdiv(h_out, META['BLOCK_H']),
batch * c_out
)
# 4. Запуск ядра
conv2d_kernel_a100[grid](
input_tensor, kernel, output_tensor,
# Strides (шаги в памяти)
*input_tensor.stride(),
*kernel.stride(),
*output_tensor.stride(),
# Размеры (Dimensions)
h_in, w_in, h_out, w_out,
c_in, c_out, k_h,
# Константы BLOCK_H/BLOCK_W подставит autotuner
)
return output_tensor
scrolls · 162 lines total
Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0
Changes from previous submission
Against this author's previous submission submission 99160.
⋯ 3 unchanged lines@triton.autotune(configs=[- # === High-End (A100, H100, B200) ===- # Максимальный prefetch (stages=6) скрывает латентность HBM+ # === A100 / H100 Optimized Configs ===+ # Большой BLOCK_W для векторизации + высокий num_stages для HBM prefetchtriton.Config({'BLOCK_H': 8, 'BLOCK_W': 128}, num_warps=8, num_stages=6),- triton.Config({'BLOCK_H': 4, 'BLOCK_W': 256}, num_warps=8, num_stages=6),- triton.Config({'BLOCK_H': 4, 'BLOCK_W': 128}, num_warps=8, num_stages=5),+ triton.Config({'BLOCK_H': 4, 'BLOCK_W': 256}, num_warps=8, num_stages=5),+ triton.Config({'BLOCK_H': 8, 'BLOCK_W': 64}, num_warps=4, num_stages=5),+ triton.Config({'BLOCK_H': 16, 'BLOCK_W': 64}, num_warps=8, num_stages=4),- # === Mid-Range / General ===- triton.Config({'BLOCK_H': 4, 'BLOCK_W': 64}, num_warps=4, num_stages=4),- triton.Config({'BLOCK_H': 2, 'BLOCK_W': 128}, num_warps=4, num_stages=4),-- # === Small sizes / Latency ===+ # === Fallback / Smaller GPUs (L4) ===+ triton.Config({'BLOCK_H': 4, 'BLOCK_W': 128}, num_warps=4, num_stages=4),triton.Config({'BLOCK_H': 2, 'BLOCK_W': 64}, num_warps=4, num_stages=3),],key=['W_OUT', 'H_OUT', 'C_IN', 'K'],)@triton.jit- def conv2d_kernel_ultimate(+ def conv2d_kernel_a100(input_ptr, weight_ptr, output_ptr,stride_in_n, stride_in_c, stride_in_h, stride_in_w,stride_w_out, stride_w_in, stride_w_h, stride_w_w,⋯ 1 unchanged linesH_IN, W_IN, H_OUT, W_OUT, C_IN, C_OUT, K,BLOCK_H: tl.constexpr, BLOCK_W: tl.constexpr):- """- Ultimate Optimized Conv2D Kernel.- Особенности:- 1. 2D Tiling (H, W) для переиспользования данных в L1 кэше.- 2. Pointer Induction: замена умножения на сложение в циклах.- 3. Pre-calculated Masks: вынос логики масок из горячих циклов.- """-- # --- 1. Setup Grid & Indices ---+ # --- 1. Инициализация Grid ---pid_w = tl.program_id(0)pid_h = tl.program_id(1)pid_z = tl.program_id(2)-+batch_idx = pid_z // C_OUTout_ch = pid_z % C_OUT-- # --- 2. Offsets & Masks (Computed ONCE) ----- # Output Y offsets [BLOCK_H]++ # --- 2. Предварительный расчет смещений (Offsets) ---+ # Генерируем индексы для текущего тайла [BLOCK_H, BLOCK_W]offs_h = pid_h * BLOCK_H + tl.arange(0, BLOCK_H)- # Output X offsets [BLOCK_W]offs_w = pid_w * BLOCK_W + tl.arange(0, BLOCK_W)-- # Pre-calculate mask [BLOCK_H, BLOCK_W]- # Примечание: при валидных размерах тензоров и stride=1,- # проверка выхода гарантирует валидность входа для padding=0.++ # --- 3. Расчет Масок (Masks) ---+ # Вычисляем маски один раз.+ # Примечание: при stride=1 и padding=0, если выходной индекс валиден,+ # то соответствующий входной (out + k) тоже валиден (при корректных input shapes).mask_h = offs_h < H_OUTmask_w = offs_w < W_OUT+ # Комбинированная маска [BLOCK_H, BLOCK_W]mask_block = mask_h[:, None] & mask_w[None, :]++ # --- 4. Базовые указатели (Pointers Setup) ---- # --- 3. Initial Pointers Setup ----- # Output Pointer [BLOCK_H, BLOCK_W] (Broadcasting)- # Base + Batch + Channel + H_offset + W_offset+ # Указатель вывода: Base + Batch + OutCh + (H_range, W_range)+ # Используем broadcasting для создания 2D сетки адресовptr_out = output_ptr + \batch_idx * stride_out_n + \out_ch * stride_out_c + \(offs_h[:, None] * stride_out_h) + \(offs_w[None, :] * stride_out_w)- # Input Pointer Base [BLOCK_H, BLOCK_W]- # Мы начинаем с позиции, соответствующей верхнему левому углу окна для первого пикселя блока.- # Так как stride=1, input_h == output_h+ # Базовый указатель входа. Начинается с верхнего левого угла окна свертки.+ # ptr_in[h, w] соответствует пикселю input[h, w] (так как stride=1)ptr_in_base = input_ptr + \batch_idx * stride_in_n + \(offs_h[:, None] * stride_in_h) + \(offs_w[None, :] * stride_in_w)- # Weight Pointer Base+ # Базовый указатель весов для текущего выходного каналаptr_wei_base = weight_ptr + out_ch * stride_w_out-- # Accumulator++ # Аккумулятор (Registers)acc = tl.zeros([BLOCK_H, BLOCK_W], dtype=tl.float32)++ # --- 5. Основной цикл (Pointer Chasing Optimization) ---- # --- 4. Main Loop (Pointer Chasing) ----- # Текущие указатели для начала канала+ # Инициализируем текущие указателиcurr_in_ch = ptr_in_basecurr_wei_ch = ptr_wei_base-+for cin in range(C_IN):- # Временные указатели для Spatial Loop- curr_in_row = curr_in_ch- curr_wei_row = curr_wei_ch+ # Временные указатели для spatial loops, чтобы не портить указатели каналов+ curr_in_spatial = curr_in_ch+ curr_wei_spatial = curr_wei_ch+ # Разворачиваем циклы ядра (Spatial Loops)for kh in range(K):- # Смещение внутри строки (kw)- # Мы не меняем указатель строки, а вычисляем смещения от него,- # так как K обычно мал, и компилятор хорошо разворачивает это.- # Однако для строки мы делаем инкремент.+ # Вычисляем смещения для текущей строки ядра+ # Для входа это смещение по высоте+ # Для веса это смещение по высотеfor kw in range(K):- # Load Weight: Scalar -> Broadcast- # ptr + kw * stride_w- wei_val = tl.load(curr_wei_row + kw * stride_w_w)+ # A. Загрузка Веса (Scalar Broadcast)+ # Считываем одно значение веса и рассылаем всем нитям блока+ # Адрес: curr_wei + kw * stride_w+ w_val = tl.load(curr_wei_spatial + kw * stride_w_w)- # Load Input: 2D Block- # ptr + kw * stride_in (т.к. contiguous по W, это просто смещение на kw)- # Input Stride W обычно равен 1, но используем переменную для универсальности.- val_in = tl.load(curr_in_row + kw * stride_in_w, mask=mask_block, other=0.0)+ # B. Загрузка Входа (Vectorized Block Load)+ # Адрес: curr_in + kw * stride_w+ # Благодаря broadcasting при инициализации, это загружает блок [BLOCK_H, BLOCK_W]+ # Сдвигаем окно вправо на kw+ in_val = tl.load(curr_in_spatial + kw * stride_in_w, mask=mask_block, other=0.0)- # FMA- acc = acc + val_in * wei_val+ # C. FMA (Fused Multiply-Add)+ acc = acc + in_val * w_val- # Инкремент указателей строк (сдвиг вниз по H)- curr_in_row += stride_in_h- curr_wei_row += stride_w_h-- # Инкремент указателей каналов (Pointer Induction)- # Это заменяет умножение `cin * stride` на сложение+ # Pointer Update (Vertical Shift)+ # Сдвигаем указатели вниз на одну строку+ curr_in_spatial += stride_in_h+ curr_wei_spatial += stride_w_h++ # Pointer Update (Channel Shift)+ # Переходим к следующему входному каналуcurr_in_ch += stride_in_ccurr_wei_ch += stride_w_in- # --- 5. Store Result ---+ # --- 6. Запись результата ---tl.store(ptr_out, acc, mask=mask_block)def custom_kernel(data):"""- Optimized Conv2D entry point.+ Wrapper function ensuring optimal memory layout for A100 kernel."""input_tensor, kernel, output_tensor = data- # 1. Ensure contiguous layout (Critical for vectorization)+ # 1. Contiguous Memory: Критически важно для векторизации на A100.+ # Без этого Triton будет генерировать неэффективные загрузки (scalar loads).if not input_tensor.is_contiguous():input_tensor = input_tensor.contiguous()if not kernel.is_contiguous():kernel = kernel.contiguous()- # 2. Extract shapes+ # 2. Извлечение размеровbatch, c_in, h_in, w_in = input_tensor.shapec_out, _, k_h, k_w = kernel.shapeh_out = h_in - k_h + 1w_out = w_in - k_w + 1- # 3. Grid definition+ # 3. Определение Grid запуска+ # Делим выходное изображение на тайлы [BLOCK_H, BLOCK_W]grid = lambda META: (triton.cdiv(w_out, META['BLOCK_W']),triton.cdiv(h_out, META['BLOCK_H']),batch * c_out)- # 4. Launch- conv2d_kernel_ultimate[grid](+ # 4. Запуск ядра+ conv2d_kernel_a100[grid](input_tensor, kernel, output_tensor,- # Strides+ # Strides (шаги в памяти)*input_tensor.stride(),*kernel.stride(),*output_tensor.stride(),- # Dims+ # Размеры (Dimensions)h_in, w_in, h_out, w_out,c_in, c_out, k_h,+ # Константы BLOCK_H/BLOCK_W подставит autotuner)return output_tensor
scrolls · 233 diff lines total
Best evidence level for this revision: reported
JSON