Skip to content
KernelIndex
Search⌘K

submission 490602

KernelAgent · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

No package. Vendor the mirrored source: 166 lines, June 9 Researcher Reciprocity License v1.0.

conv2d_py_H100_gpt-5_ka_submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-conv2d-v2-490602?include=source"
interfacepython
Compatibility
measured onNVIDIA H100
declared hardwareNVIDIA H100
architecturessm_90
dtypesfp32

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
2D convolutionsuite of 5 cases
NVIDIA H100
515.2ms
#33 of 35
2026-02-14

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:03a65ac39994c288f973811757b55bf13f1418f2722a69a3bc7f37aba23f578b
license declaredunknown
license concludedunknown
authorsKernelAgent
imported2026-08-15

Techniques

Extracted from the mirrored source by pattern, never inferred. Each row cites its line.

autotune@triton.autotune(
fused-epilogueIf bias/activation existed, they would be natural to fuse in the epilogue.
num-warps = 4triton.Config({"BLOCK_W": 32}, num_warps=4, num_stages=2),
stages = 2triton.Config({"BLOCK_W": 32}, num_warps=4, num_stages=2),

Kernel source

conv2d_py_H100_gpt-5_ka_submission.py166 lines
import torch
import triton
import triton.language as tl


@triton.autotune(
    configs=[
        triton.Config({"BLOCK_W": 32}, num_warps=4, num_stages=2),
        triton.Config({"BLOCK_W": 64}, num_warps=4, num_stages=3),
        triton.Config({"BLOCK_W": 128}, num_warps=8, num_stages=3),
    ],
    key=["OW", "K"],
)
@triton.jit
def conv2d_nopad_kernel(
    x_ptr, w_ptr, y_ptr,
    B, IC, OC, H, W, OH, OW,
    stride_xb, stride_xc, stride_xh, stride_xw,
    stride_wo, stride_wc, stride_wkh, stride_wkw,
    stride_yb, stride_yc, stride_yh, stride_yw,
    BLOCK_W: tl.constexpr,
    K: tl.constexpr,
):
    """
    Direct 2D convolution without padding and stride=1.

    Each program instance computes a vector tile of OW of size BLOCK_W for a single (b, oc, oh).
    Accumulation is done in fp32 for numerical stability and then cast to the output dtype.

    Parameters:
        x_ptr: [B, IC, H, W]
        w_ptr: [OC, IC, K, K]
        y_ptr: [B, OC, OH, OW]
        K: kernel size (square, tl.constexpr)
        BLOCK_W: width tile size (tl.constexpr)
    """
    pid_m = tl.program_id(axis=0)  # flatten over (B, OC, OH)
    pid_n = tl.program_id(axis=1)  # tile along OW

    # Decompose pid_m into (b, oc, oh)
    tmp = pid_m
    oh = tmp % OH
    tmp = tmp // OH
    oc = tmp % OC
    b = tmp // OC

    # Compute tile offsets along width
    col_start = pid_n * BLOCK_W
    offs_ow = col_start + tl.arange(0, BLOCK_W)
    mask = offs_ow < OW

    # Initialize accumulator (vector across BLOCK_W)
    acc = tl.zeros((BLOCK_W,), dtype=tl.float32)

    # Loop over input channels and kernel spatial dims
    # IC can be dynamic; kernel dims K are constexpr for better unrolling.
    for ic in tl.range(0, IC):
        # Base pointers that don't depend on kx/ky or ow
        x_base = x_ptr + b * stride_xb + ic * stride_xc
        w_ic_base = w_ptr + oc * stride_wo + ic * stride_wc
        for ky in range(0, K):
            x_row_base = x_base + (oh + ky) * stride_xh
            w_row_base = w_ic_base + ky * stride_wkh
            for kx in range(0, K):
                # Load scalar weight w[oc, ic, ky, kx]
                w_val = tl.load(w_row_base + kx * stride_wkw)
                w_val_f32 = w_val.to(tl.float32)

                # Load input vector x[b, ic, oh+ky, offs_ow + kx]
                x_ptrs = x_row_base + (offs_ow + kx) * stride_xw
                x_vec = tl.load(x_ptrs, mask=mask, other=0.0)
                x_vec_f32 = x_vec.to(tl.float32)

                # FMA accumulate
                acc += x_vec_f32 * w_val_f32

    # Store results
    y_ptrs = y_ptr + b * stride_yb + oc * stride_yc + oh * stride_yh + offs_ow * stride_yw
    tl.store(y_ptrs, acc.to(y_ptr.dtype.element_ty), mask=mask)


def kernel_function(x: torch.Tensor, w: torch.Tensor, out: torch.Tensor = None):
    """
    Triton-backed 2D convolution without padding and stride=1.

    This wrapper:
    - Validates shapes/dtypes/devices.
    - Allocates the output if not provided.
    - Configures the launch grid and meta-parameters.
    - Launches a single fused Triton kernel that performs the full convolution.
      No intermediate PyTorch compute ops are used; all math happens in the Triton kernel.

    Fusion note:
    - There are no extra operations (bias, activation) in the test pipeline.
      As such, the implementation consists of a single pass conv2d kernel.
      If bias/activation existed, they would be natural to fuse in the epilogue.

    Args:
        x: Input tensor of shape [B, C_in, H, W], contiguous.
        w: Weight tensor of shape [C_out, C_in, K, K], contiguous.
        out: Optional preallocated output tensor [B, C_out, H-K+1, W-K+1].

    Returns:
        Output tensor y of shape [B, C_out, H-K+1, W-K+1], dtype = x.dtype, device = x.device.
    """
    # Basic checks
    assert isinstance(x, torch.Tensor) and isinstance(w, torch.Tensor)
    assert x.is_cuda and w.is_cuda, "Input and weights must be on CUDA"
    assert x.is_contiguous() and w.is_contiguous(), "Input and weights must be contiguous"

    B, IC, H, W = x.shape
    OC, IC_w, KH, KW = w.shape
    assert IC_w == IC, "Weight in_channels must match input channels"
    assert KH == KW, "Only square kernels are supported"
    K = KH
    OH = H - K + 1
    OW = W - K + 1
    assert OH > 0 and OW > 0, "Kernel larger than input (no padding) produces non-positive output spatial size"

    # Prepare output
    if out is None:
        out = torch.empty((B, OC, OH, OW), device=x.device, dtype=x.dtype)
    else:
        assert out.is_cuda, "Output must be on CUDA"
        assert out.dtype == x.dtype, "Output dtype must match input dtype"
        assert out.is_contiguous(), "Output must be contiguous"
        assert tuple(out.shape) == (B, OC, OH, OW), "Output shape mismatch"

    # Extract strides
    stride_xb, stride_xc, stride_xh, stride_xw = x.stride()
    stride_wo, stride_wc, stride_wkh, stride_wkw = w.stride()
    stride_yb, stride_yc, stride_yh, stride_yw = out.stride()

    # Launch configuration: 2D grid over (B * OC * OH) x ceil(OW / BLOCK_W)
    def grid(META):
        return (B * OC * OH, triton.cdiv(OW, META["BLOCK_W"]))

    # Launch the kernel
    conv2d_nopad_kernel[grid](
        x, w, out,
        B, IC, OC, H, W, OH, OW,
        stride_xb, stride_xc, stride_xh, stride_xw,
        stride_wo, stride_wc, stride_wkh, stride_wkw,
        stride_yb, stride_yc, stride_yh, stride_yw,
        K=K,
    )

    return out

import inspect

def custom_kernel(input):
    sig = inspect.signature(kernel_function)
    num_params = len(sig.parameters)

    if len(input) == num_params:
        return kernel_function(*input)
    return kernel_function(input)


# Ensure deterministic cuBLAS.
import os
if os.environ.get("CUBLAS_WORKSPACE_CONFIG", "") not in (":4096:8", ":16:8"):
    os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"

scrolls · 166 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 489489.

+ import torch
import triton
import triton.language as tl
- import torch
+ @triton.autotune(
+ configs=[
+ triton.Config({"BLOCK_W": 32}, num_warps=4, num_stages=2),
+ triton.Config({"BLOCK_W": 64}, num_warps=4, num_stages=3),
+ triton.Config({"BLOCK_W": 128}, num_warps=8, num_stages=3),
+ ],
+ key=["OW", "K"],
+ )
@triton.jit
- def conv2d_kernel(
- input_ptr, # Pointer to input tensor [B, C, H, W]
- kernel_ptr, # Pointer to kernel tensor [C_out, C_in, KH, KW]
- output_ptr, # Pointer to output tensor [B, C_out, OH, OW]
- # Dimensions
- batch: tl.constexpr,
- in_channels: tl.constexpr,
- out_channels: tl.constexpr,
- in_height: tl.constexpr,
- in_width: tl.constexpr,
- kernel_size: tl.constexpr,
- out_height: tl.constexpr,
- out_width: tl.constexpr,
- # Block sizes
- BLOCK_OH: tl.constexpr,
- BLOCK_OW: tl.constexpr,
+ def conv2d_nopad_kernel(
+ x_ptr, w_ptr, y_ptr,
+ B, IC, OC, H, W, OH, OW,
+ stride_xb, stride_xc, stride_xh, stride_xw,
+ stride_wo, stride_wc, stride_wkh, stride_wkw,
+ stride_yb, stride_yc, stride_yh, stride_yw,
+ BLOCK_W: tl.constexpr,
+ K: tl.constexpr,
):
"""
- Fused 2D convolution kernel.
- Each program computes a block of output pixels for one (batch, out_channel) pair.
- The convolution sum over in_channels and kernel spatial dimensions is computed inline.
+ Direct 2D convolution without padding and stride=1.
+
+ Each program instance computes a vector tile of OW of size BLOCK_W for a single (b, oc, oh).
+ Accumulation is done in fp32 for numerical stability and then cast to the output dtype.
+
+ Parameters:
+ x_ptr: [B, IC, H, W]
+ w_ptr: [OC, IC, K, K]
+ y_ptr: [B, OC, OH, OW]
+ K: kernel size (square, tl.constexpr)
+ BLOCK_W: width tile size (tl.constexpr)
"""
- # Program IDs
- pid_b = tl.program_id(0) # batch index
- pid_oc = tl.program_id(1) # output channel index
- pid_spatial = tl.program_id(2) # spatial block index
-
- # Calculate spatial block position
- num_blocks_ow = tl.cdiv(out_width, BLOCK_OW)
- pid_oh = pid_spatial // num_blocks_ow
- pid_ow = pid_spatial % num_blocks_ow
-
- # Output pixel offsets within this block
- offs_oh = pid_oh * BLOCK_OH + tl.arange(0, BLOCK_OH)
- offs_ow = pid_ow * BLOCK_OW + tl.arange(0, BLOCK_OW)
-
- # Masks for valid output positions
- mask_oh = offs_oh < out_height
- mask_ow = offs_ow < out_width
-
- # Initialize accumulator for this block of output pixels
- acc = tl.zeros((BLOCK_OH, BLOCK_OW), dtype=tl.float32)
-
- # Loop over input channels
- for ic in range(in_channels):
- # Loop over kernel height
- for kh in range(kernel_size):
- # Loop over kernel width
- for kw in range(kernel_size):
- # Load kernel weight for this (oc, ic, kh, kw)
- # Kernel layout: [out_channels, in_channels, kernel_size, kernel_size]
- kernel_offset = (pid_oc * in_channels * kernel_size * kernel_size +
- ic * kernel_size * kernel_size +
- kh * kernel_size + kw)
- w = tl.load(kernel_ptr + kernel_offset)
-
- # Input positions: ih = oh + kh, iw = ow + kw
- # Input layout: [batch, channels, height, width]
- # offs_ih = offs_oh + kh (shape: BLOCK_OH)
- # offs_iw = offs_ow + kw (shape: BLOCK_OW)
-
- # Load input values for this block
- # We need to load input[pid_b, ic, offs_oh + kh, offs_ow + kw]
- input_base = (pid_b * in_channels * in_height * in_width +
- ic * in_height * in_width)
-
- # Calculate input offsets for each output position
- # input_offset[i, j] = input_base + (offs_oh[i] + kh) * in_width + (offs_ow[j] + kw)
- offs_ih = offs_oh + kh # [BLOCK_OH]
- offs_iw = offs_ow + kw # [BLOCK_OW]
-
- # Create 2D offset grid
- input_offsets = input_base + offs_ih[:, None] * in_width + offs_iw[None, :]
-
- # Create mask (input positions are always valid since we only compute valid output positions)
- mask = mask_oh[:, None] & mask_ow[None, :]
-
- # Load input values
- x = tl.load(input_ptr + input_offsets, mask=mask, other=0.0)
-
- # Accumulate: acc += x * w
- acc += x * w
-
- # Store output
- # Output layout: [batch, out_channels, out_height, out_width]
- output_base = (pid_b * out_channels * out_height * out_width +
- pid_oc * out_height * out_width)
- output_offsets = output_base + offs_oh[:, None] * out_width + offs_ow[None, :]
- output_mask = mask_oh[:, None] & mask_ow[None, :]
-
- tl.store(output_ptr + output_offsets, acc, mask=output_mask)
+ pid_m = tl.program_id(axis=0) # flatten over (B, OC, OH)
+ pid_n = tl.program_id(axis=1) # tile along OW
+ # Decompose pid_m into (b, oc, oh)
+ tmp = pid_m
+ oh = tmp % OH
+ tmp = tmp // OH
+ oc = tmp % OC
+ b = tmp // OC
- def kernel_function(input_tensor: torch.Tensor, kernel: torch.Tensor, output_tensor: torch.Tensor) -> torch.Tensor:
+ # Compute tile offsets along width
+ col_start = pid_n * BLOCK_W
+ offs_ow = col_start + tl.arange(0, BLOCK_W)
+ mask = offs_ow < OW
+
+ # Initialize accumulator (vector across BLOCK_W)
+ acc = tl.zeros((BLOCK_W,), dtype=tl.float32)
+
+ # Loop over input channels and kernel spatial dims
+ # IC can be dynamic; kernel dims K are constexpr for better unrolling.
+ for ic in tl.range(0, IC):
+ # Base pointers that don't depend on kx/ky or ow
+ x_base = x_ptr + b * stride_xb + ic * stride_xc
+ w_ic_base = w_ptr + oc * stride_wo + ic * stride_wc
+ for ky in range(0, K):
+ x_row_base = x_base + (oh + ky) * stride_xh
+ w_row_base = w_ic_base + ky * stride_wkh
+ for kx in range(0, K):
+ # Load scalar weight w[oc, ic, ky, kx]
+ w_val = tl.load(w_row_base + kx * stride_wkw)
+ w_val_f32 = w_val.to(tl.float32)
+
+ # Load input vector x[b, ic, oh+ky, offs_ow + kx]
+ x_ptrs = x_row_base + (offs_ow + kx) * stride_xw
+ x_vec = tl.load(x_ptrs, mask=mask, other=0.0)
+ x_vec_f32 = x_vec.to(tl.float32)
+
+ # FMA accumulate
+ acc += x_vec_f32 * w_val_f32
+
+ # Store results
+ y_ptrs = y_ptr + b * stride_yb + oc * stride_yc + oh * stride_yh + offs_ow * stride_yw
+ tl.store(y_ptrs, acc.to(y_ptr.dtype.element_ty), mask=mask)
+
+
+ def kernel_function(x: torch.Tensor, w: torch.Tensor, out: torch.Tensor = None):
"""
- Wrapper for 2D convolution using Triton.
-
- This is a fused implementation that computes the entire convolution in a single kernel:
- - For each output position, accumulates over all input channels and kernel spatial positions
- - No separate im2col or matrix multiplication steps
-
+ Triton-backed 2D convolution without padding and stride=1.
+
+ This wrapper:
+ - Validates shapes/dtypes/devices.
+ - Allocates the output if not provided.
+ - Configures the launch grid and meta-parameters.
+ - Launches a single fused Triton kernel that performs the full convolution.
+ No intermediate PyTorch compute ops are used; all math happens in the Triton kernel.
+
+ Fusion note:
+ - There are no extra operations (bias, activation) in the test pipeline.
+ As such, the implementation consists of a single pass conv2d kernel.
+ If bias/activation existed, they would be natural to fuse in the epilogue.
+
Args:
- input_tensor: Input tensor of shape [batch, in_channels, height, width]
- kernel: Convolution kernel of shape [out_channels, in_channels, kH, kW]
- output_tensor: Pre-allocated output tensor of shape [batch, out_channels, oH, oW]
-
+ x: Input tensor of shape [B, C_in, H, W], contiguous.
+ w: Weight tensor of shape [C_out, C_in, K, K], contiguous.
+ out: Optional preallocated output tensor [B, C_out, H-K+1, W-K+1].
+
Returns:
- output_tensor filled with convolution result
+ Output tensor y of shape [B, C_out, H-K+1, W-K+1], dtype = x.dtype, device = x.device.
"""
- # Extract dimensions
- batch, in_channels, in_height, in_width = input_tensor.shape
- out_channels, _, kernel_h, kernel_w = kernel.shape
-
- # For this problem, kernel is square and in_channels == out_channels
- assert kernel_h == kernel_w, "Only square kernels supported"
- kernel_size = kernel_h
-
- # Output dimensions (stride=1, padding=0)
- out_height = in_height - kernel_size + 1
- out_width = in_width - kernel_size + 1
-
- # Verify output shape
- assert output_tensor.shape == (batch, out_channels, out_height, out_width)
-
- # Block sizes for output spatial dimensions
- BLOCK_OH = 8
- BLOCK_OW = 8
-
- # Grid dimensions
- num_blocks_oh = triton.cdiv(out_height, BLOCK_OH)
- num_blocks_ow = triton.cdiv(out_width, BLOCK_OW)
- num_spatial_blocks = num_blocks_oh * num_blocks_ow
-
- grid = (batch, out_channels, num_spatial_blocks)
-
- # Launch kernel
- conv2d_kernel[grid](
- input_tensor,
- kernel,
- output_tensor,
- batch,
- in_channels,
- out_channels,
- in_height,
- in_width,
- kernel_size,
- out_height,
- out_width,
- BLOCK_OH,
- BLOCK_OW,
+ # Basic checks
+ assert isinstance(x, torch.Tensor) and isinstance(w, torch.Tensor)
+ assert x.is_cuda and w.is_cuda, "Input and weights must be on CUDA"
+ assert x.is_contiguous() and w.is_contiguous(), "Input and weights must be contiguous"
+
+ B, IC, H, W = x.shape
+ OC, IC_w, KH, KW = w.shape
+ assert IC_w == IC, "Weight in_channels must match input channels"
+ assert KH == KW, "Only square kernels are supported"
+ K = KH
+ OH = H - K + 1
+ OW = W - K + 1
+ assert OH > 0 and OW > 0, "Kernel larger than input (no padding) produces non-positive output spatial size"
+
+ # Prepare output
+ if out is None:
+ out = torch.empty((B, OC, OH, OW), device=x.device, dtype=x.dtype)
+ else:
+ assert out.is_cuda, "Output must be on CUDA"
+ assert out.dtype == x.dtype, "Output dtype must match input dtype"
+ assert out.is_contiguous(), "Output must be contiguous"
+ assert tuple(out.shape) == (B, OC, OH, OW), "Output shape mismatch"
+
+ # Extract strides
+ stride_xb, stride_xc, stride_xh, stride_xw = x.stride()
+ stride_wo, stride_wc, stride_wkh, stride_wkw = w.stride()
+ stride_yb, stride_yc, stride_yh, stride_yw = out.stride()
+
+ # Launch configuration: 2D grid over (B * OC * OH) x ceil(OW / BLOCK_W)
+ def grid(META):
+ return (B * OC * OH, triton.cdiv(OW, META["BLOCK_W"]))
+
+ # Launch the kernel
+ conv2d_nopad_kernel[grid](
+ x, w, out,
+ B, IC, OC, H, W, OH, OW,
+ stride_xb, stride_xc, stride_xh, stride_xw,
+ stride_wo, stride_wc, stride_wkh, stride_wkw,
+ stride_yb, stride_yc, stride_yh, stride_yw,
+ K=K,
)
-
- return output_tensor
+ return out
+
import inspect
def custom_kernel(input):
scrolls · 296 diff lines total

Best evidence level for this revision: reported

JSON