gpt-5.5-priority · original · l123_single_gpt
incorrect 31_VisionAttention.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
—
ref runtime
21.70 μs
speedup
—
started
2026-05-05T00:02:03Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel runtime
—
ref runtime
21.70 μs
speedup
—
kernel mean / median / std
—
ref mean / median / std
21.70 / — / 0.12 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
1.000
dram util %
70.1%
compute util %
100.0%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
2349.31 GB/s
dram util %
70.1%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
212.1%
bottleneck
compute-bound
dominant pipe %
145.3%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
427.1%
ld sectors / req
76.00
st sectors / req
—
regs / thread
658
smem / block
90112 B
block size
768
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
23700.5%
short_scoreboard
2264.6%
mio_throttle
1841.3%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self, embed_dim, num_heads):
        """
        Attention Block using Multihead Self-Attention.
        :param embed_dim: Embedding dimension (the number of channels)
        :param num_heads: Number of attention heads
        """
        super(Model, self).__init__()
        self.attn = nn.MultiheadAttention(embed_dim, num_heads)
        self.norm = nn.LayerNorm(embed_dim)

    def forward(self, x):
        """
        Forward pass of the AttentionBlock.
        :param x: Input tensor of shape (B, C, H, W)
        :return: Output tensor of the same shape (B, C, H, W)
        """
        B, C, H, W = x.shape
        x = x.view(B, C, H * W).permute(2, 0, 1)  # (seq_len, batch_size, embed_dim)
        attn_output, _ = self.attn(x, x, x)
        x = self.norm(attn_output + x)  # (seq_len, batch_size, embed_dim)
        x = x.permute(1, 2, 0).view(B, C, H, W)
        return x

embed_dim = 128
num_heads = 4
batch_size = 2
num_channels = embed_dim
image_height = 128
image_width = 128

def get_inputs():
    return [torch.rand(batch_size, num_channels, image_height, image_width)]

def get_init_inputs():
    return [embed_dim, num_heads]
turn 0 · FINAL · 1 tool call(s) · 287.5s turn · 287.5s LLM · 9,969 chars (click to expand)
turn 0287.5s turn · 287.5s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n\ntorch::Tensor nchw_to_blc(torch::Tensor x);\ntorch::Tensor attention_forward(torch::Tensor qkv, int64_t num_heads);\ntorch::Tensor resid_ln_to_nchw(torch::Tensor attn, torch::Tensor resid, torch::Tensor gamma, torch::Tensor beta, int64_t H, int64_t W, double eps);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n#include <cmath>\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n\n__global__ void nchw_to_blc_kernel(const float* __restrict__ x, float* __restrict__ y,\n int B, int C, int H, int W, int L) {\n long long n = (long long)B * L * C;\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long stride = (long long)blockDim.x * gridDim.x;\n for (; idx < n; idx += stride) {\n int c = (int)(idx % C);\n long long t = idx / C;\n int l = (int)(t % L);\n int b = (int)(t / L);\n int h = l / W;\n int w = l - h * W;\n y[idx] = x[((b * C + c) * H + h) * W + w];\n }\n}\n\n// One CUDA block computes one attention output vector (B, head, query).\n// Optimized for the benchmark dimensions: C=128, heads=4, head_dim=32.\n__global__ void attention_kernel_d32(const float* __restrict__ qkv, float* __restrict__ out,\n int B, int L, int C, int num_heads) {\n const int D = 32;\n int q = blockIdx.x;\n int h = blockIdx.y;\n int b = blockIdx.z;\n int tid = threadIdx.x;\n\n __shared__ float sh[128 * 33];\n float* red = sh;\n float* qv = sh + 128;\n\n const int base_q = ((b * L + q) * (3 * C)) + h * D;\n if (tid < D) qv[tid] = qkv[base_q + tid];\n __syncthreads();\n\n const float scale = 0.17677669529663687f; // 1/sqrt(32)\n\n float local_max = -FLT_MAX;\n for (int k = tid; k < L; k += 128) {\n const float* kp = qkv + ((b * L + k) * (3 * C)) + C + h * D;\n float dot = 0.0f;\n #pragma unroll\n for (int d = 0; d < D; ++d) dot = fmaf(qv[d], kp[d], dot);\n float s = dot * scale;\n local_max = fmaxf(local_max, s);\n }\n red[tid] = local_max;\n __syncthreads();\n for (int off = 64; off > 0; off >>= 1) {\n if (tid < off) red[tid] = fmaxf(red[tid], red[tid + off]);\n __syncthreads();\n }\n float m = red[0];\n\n float denom = 0.0f;\n float acc[D];\n #pragma unroll\n for (int d = 0; d < D; ++d) acc[d] = 0.0f;\n\n for (int k = tid; k < L; k += 128) {\n const float* kp = qkv + ((b * L + k) * (3 * C)) + C + h * D;\n float dot = 0.0f;\n #pragma unroll\n for (int d = 0; d < D; ++d) dot = fmaf(qv[d], kp[d], dot);\n float ww = expf(dot * scale - m);\n denom += ww;\n const float* vp = qkv + ((b * L + k) * (3 * C)) + 2 * C + h * D;\n #pragma unroll\n for (int d = 0; d < D; ++d) acc[d] = fmaf(ww, vp[d], acc[d]);\n }\n\n red[tid] = denom;\n __syncthreads();\n for (int off = 64; off > 0; off >>= 1) {\n if (tid < off) red[tid] += red[tid + off];\n __syncthreads();\n }\n float inv_denom = 1.0f / red[0];\n\n #pragma unroll\n for (int d = 0; d < D; ++d) {\n red[tid] = acc[d];\n __syncthreads();\n for (int off = 64; off > 0; off >>= 1) {\n if (tid < off) red[tid] += red[tid + off];\n __syncthreads();\n }\n if (tid == 0) {\n out[(b * L + q) * C + h * D + d] = red[0] * inv_denom;\n }\n __syncthreads();\n }\n}\n\n__global__ void resid_ln_to_nchw_kernel(const float* __restrict__ attn,\n const float* __restrict__ resid,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int B, int L, int C, int H, int W, float eps) {\n int row = blockIdx.x; // 0..B*L-1\n int tid = threadIdx.x;\n int b = row / L;\n int l = row - b * L;\n int hw_h = l / W;\n int hw_w = l - hw_h * W;\n __shared__ float sh[128];\n\n float v = 0.0f;\n if (tid < C) v = attn[row * C + tid] + resid[row * C + tid];\n sh[tid] = (tid < C) ? v : 0.0f;\n __syncthreads();\n for (int off = 64; off > 0; off >>= 1) {\n if (tid < off) sh[tid] += sh[tid + off];\n __syncthreads();\n }\n float mean = sh[0] * (1.0f / 128.0f);\n\n float diff = (tid < C) ? (v - mean) : 0.0f;\n sh[tid] = diff * diff;\n __syncthreads();\n for (int off = 64; off > 0; off >>= 1) {\n if (tid < off) sh[tid] += sh[tid + off];\n __syncthreads();\n }\n float inv_std = rsqrtf(sh[0] * (1.0f / 128.0f) + eps);\n if (tid < C) {\n float y = diff * inv_std * gamma[tid] + beta[tid];\n out[((b * C + tid) * H + hw_h) * W + hw_w] = y;\n }\n}\n\ntorch::Tensor nchw_to_blc(torch::Tensor x) {\n CHECK_CUDA(x); CHECK_CONTIGUOUS(x); CHECK_FLOAT(x);\n int B = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int L = H * W;\n auto y = torch::empty({B, L, C}, x.options());\n int threads = 256;\n int blocks = (int)std::min<long long>(65535, ((long long)B * L * C + threads - 1) / threads);\n nchw_to_blc_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), y.data_ptr<float>(), B, C, H, W, L);\n return y;\n}\n\ntorch::Tensor attention_forward(torch::Tensor qkv, int64_t num_heads) {\n CHECK_CUDA(qkv); CHECK_CONTIGUOUS(qkv); CHECK_FLOAT(qkv);\n int B = (int)qkv.size(0);\n int L = (int)qkv.size(1);\n int threeC = (int)qkv.size(2);\n int C = threeC / 3;\n TORCH_CHECK(C == 128 && num_heads == 4, \"this optimized kernel expects embed_dim=128,num_heads=4\");\n auto out = torch::empty({B, L, C}, qkv.options());\n dim3 grid(L, (unsigned)num_heads, B);\n attention_kernel_d32<<<grid, 128, 0, at::cuda::getCurrentCUDAStream()>>>(\n qkv.data_ptr<float>(), out.data_ptr<float>(), B, L, C, (int)num_heads);\n return out;\n}\n\ntorch::Tensor resid_ln_to_nchw(torch::Tensor attn, torch::Tensor resid, torch::Tensor gamma, torch::Tensor beta,\n int64_t H64, int64_t W64, double eps64) {\n CHECK_CUDA(attn); CHECK_CUDA(resid); CHECK_CUDA(gamma); CHECK_CUDA(beta);\n CHECK_CONTIGUOUS(attn); CHECK_CONTIGUOUS(resid); CHECK_CONTIGUOUS(gamma); CHECK_CONTIGUOUS(beta);\n CHECK_FLOAT(attn); CHECK_FLOAT(resid); CHECK_FLOAT(gamma); CHECK_FLOAT(beta);\n int B = (int)attn.size(0), L = (int)attn.size(1), C = (int)attn.size(2);\n int H = (int)H64, W = (int)W64;\n TORCH_CHECK(C == 128 && L == H * W, \"bad shape\");\n auto out = torch::empty({B, C, H, W}, attn.options());\n resid_ln_to_nchw_kernel<<<B * L, 128, 0, at::cuda::getCurrentCUDAStream()>>>(\n attn.data_ptr<float>(), resid.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n out.data_ptr<float>(), B, L, C, H, W, (float)eps64);\n return out;\n}\n'''\n\n_ext = load_inline(\n name='mha_ln_custom_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['nchw_to_blc', 'attention_forward', 'resid_ln_to_nchw'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, embed_dim, num_heads):\n super(ModelNew, self).__init__()\n self.attn = nn.MultiheadAttention(embed_dim, num_heads)\n self.norm = nn.LayerNorm(embed_dim)\n self.embed_dim = embed_dim\n self.num_heads = num_heads\n\n def forward(self, x):\n B, C, H, W = x.shape\n # Build the exact (batch, sequence, channel) tensor used by the reference.\n xb = _ext.nchw_to_blc(x.contiguous())\n qkv = F.linear(xb, self.attn.in_proj_weight, self.attn.in_proj_bias).contiguous()\n ctx = _ext.attention_forward(qkv, self.num_heads)\n proj = F.linear(ctx, self.attn.out_proj.weight, self.attn.out_proj.bias).contiguous()\n return _ext.resid_ln_to_nchw(proj, xb, self.norm.weight, self.norm.bias, H, W, self.norm.eps)\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: correctness check did not pass ((0 / 5) trials). correctness_issue: Output mismatch max_difference: ['1.635308', '1.568782', '1.855099', '1.620916', '1.644100'] avg_difference: ['0.000089', '0.000119', '0.000159', '0.000072', '0.000133']
final submitted kernel (225 lines, 8,425 chars) — full source, untruncated
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.cpp_extension import load_inline

_cpp_src = r'''
#include <torch/extension.h>

torch::Tensor nchw_to_blc(torch::Tensor x);
torch::Tensor attention_forward(torch::Tensor qkv, int64_t num_heads);
torch::Tensor resid_ln_to_nchw(torch::Tensor attn, torch::Tensor resid, torch::Tensor gamma, torch::Tensor beta, int64_t H, int64_t W, double eps);
'''

_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>
#include <cmath>

#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x " must be a CUDA tensor")
#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous")
#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x " must be float32")

__global__ void nchw_to_blc_kernel(const float* __restrict__ x, float* __restrict__ y,
                                   int B, int C, int H, int W, int L) {
    long long n = (long long)B * L * C;
    long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;
    long long stride = (long long)blockDim.x * gridDim.x;
    for (; idx < n; idx += stride) {
        int c = (int)(idx % C);
        long long t = idx / C;
        int l = (int)(t % L);
        int b = (int)(t / L);
        int h = l / W;
        int w = l - h * W;
        y[idx] = x[((b * C + c) * H + h) * W + w];
    }
}

// One CUDA block computes one attention output vector (B, head, query).
// Optimized for the benchmark dimensions: C=128, heads=4, head_dim=32.
__global__ void attention_kernel_d32(const float* __restrict__ qkv, float* __restrict__ out,
                                     int B, int L, int C, int num_heads) {
    const int D = 32;
    int q = blockIdx.x;
    int h = blockIdx.y;
    int b = blockIdx.z;
    int tid = threadIdx.x;

    __shared__ float sh[128 * 33];
    float* red = sh;
    float* qv = sh + 128;

    const int base_q = ((b * L + q) * (3 * C)) + h * D;
    if (tid < D) qv[tid] = qkv[base_q + tid];
    __syncthreads();

    const float scale = 0.17677669529663687f; // 1/sqrt(32)

    float local_max = -FLT_MAX;
    for (int k = tid; k < L; k += 128) {
        const float* kp = qkv + ((b * L + k) * (3 * C)) + C + h * D;
        float dot = 0.0f;
        #pragma unroll
        for (int d = 0; d < D; ++d) dot = fmaf(qv[d], kp[d], dot);
        float s = dot * scale;
        local_max = fmaxf(local_max, s);
    }
    red[tid] = local_max;
    __syncthreads();
    for (int off = 64; off > 0; off >>= 1) {
        if (tid < off) red[tid] = fmaxf(red[tid], red[tid + off]);
        __syncthreads();
    }
    float m = red[0];

    float denom = 0.0f;
    float acc[D];
    #pragma unroll
    for (int d = 0; d < D; ++d) acc[d] = 0.0f;

    for (int k = tid; k < L; k += 128) {
        const float* kp = qkv + ((b * L + k) * (3 * C)) + C + h * D;
        float dot = 0.0f;
        #pragma unroll
        for (int d = 0; d < D; ++d) dot = fmaf(qv[d], kp[d], dot);
        float ww = expf(dot * scale - m);
        denom += ww;
        const float* vp = qkv + ((b * L + k) * (3 * C)) + 2 * C + h * D;
        #pragma unroll
        for (int d = 0; d < D; ++d) acc[d] = fmaf(ww, vp[d], acc[d]);
    }

    red[tid] = denom;
    __syncthreads();
    for (int off = 64; off > 0; off >>= 1) {
        if (tid < off) red[tid] += red[tid + off];
        __syncthreads();
    }
    float inv_denom = 1.0f / red[0];

    #pragma unroll
    for (int d = 0; d < D; ++d) {
        red[tid] = acc[d];
        __syncthreads();
        for (int off = 64; off > 0; off >>= 1) {
            if (tid < off) red[tid] += red[tid + off];
            __syncthreads();
        }
        if (tid == 0) {
            out[(b * L + q) * C + h * D + d] = red[0] * inv_denom;
        }
        __syncthreads();
    }
}

__global__ void resid_ln_to_nchw_kernel(const float* __restrict__ attn,
                                        const float* __restrict__ resid,
                                        const float* __restrict__ gamma,
                                        const float* __restrict__ beta,
                                        float* __restrict__ out,
                                        int B, int L, int C, int H, int W, float eps) {
    int row = blockIdx.x; // 0..B*L-1
    int tid = threadIdx.x;
    int b = row / L;
    int l = row - b * L;
    int hw_h = l / W;
    int hw_w = l - hw_h * W;
    __shared__ float sh[128];

    float v = 0.0f;
    if (tid < C) v = attn[row * C + tid] + resid[row * C + tid];
    sh[tid] = (tid < C) ? v : 0.0f;
    __syncthreads();
    for (int off = 64; off > 0; off >>= 1) {
        if (tid < off) sh[tid] += sh[tid + off];
        __syncthreads();
    }
    float mean = sh[0] * (1.0f / 128.0f);

    float diff = (tid < C) ? (v - mean) : 0.0f;
    sh[tid] = diff * diff;
    __syncthreads();
    for (int off = 64; off > 0; off >>= 1) {
        if (tid < off) sh[tid] += sh[tid + off];
        __syncthreads();
    }
    float inv_std = rsqrtf(sh[0] * (1.0f / 128.0f) + eps);
    if (tid < C) {
        float y = diff * inv_std * gamma[tid] + beta[tid];
        out[((b * C + tid) * H + hw_h) * W + hw_w] = y;
    }
}

torch::Tensor nchw_to_blc(torch::Tensor x) {
    CHECK_CUDA(x); CHECK_CONTIGUOUS(x); CHECK_FLOAT(x);
    int B = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);
    int L = H * W;
    auto y = torch::empty({B, L, C}, x.options());
    int threads = 256;
    int blocks = (int)std::min<long long>(65535, ((long long)B * L * C + threads - 1) / threads);
    nchw_to_blc_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(
        x.data_ptr<float>(), y.data_ptr<float>(), B, C, H, W, L);
    return y;
}

torch::Tensor attention_forward(torch::Tensor qkv, int64_t num_heads) {
    CHECK_CUDA(qkv); CHECK_CONTIGUOUS(qkv); CHECK_FLOAT(qkv);
    int B = (int)qkv.size(0);
    int L = (int)qkv.size(1);
    int threeC = (int)qkv.size(2);
    int C = threeC / 3;
    TORCH_CHECK(C == 128 && num_heads == 4, "this optimized kernel expects embed_dim=128,num_heads=4");
    auto out = torch::empty({B, L, C}, qkv.options());
    dim3 grid(L, (unsigned)num_heads, B);
    attention_kernel_d32<<<grid, 128, 0, at::cuda::getCurrentCUDAStream()>>>(
        qkv.data_ptr<float>(), out.data_ptr<float>(), B, L, C, (int)num_heads);
    return out;
}

torch::Tensor resid_ln_to_nchw(torch::Tensor attn, torch::Tensor resid, torch::Tensor gamma, torch::Tensor beta,
                               int64_t H64, int64_t W64, double eps64) {
    CHECK_CUDA(attn); CHECK_CUDA(resid); CHECK_CUDA(gamma); CHECK_CUDA(beta);
    CHECK_CONTIGUOUS(attn); CHECK_CONTIGUOUS(resid); CHECK_CONTIGUOUS(gamma); CHECK_CONTIGUOUS(beta);
    CHECK_FLOAT(attn); CHECK_FLOAT(resid); CHECK_FLOAT(gamma); CHECK_FLOAT(beta);
    int B = (int)attn.size(0), L = (int)attn.size(1), C = (int)attn.size(2);
    int H = (int)H64, W = (int)W64;
    TORCH_CHECK(C == 128 && L == H * W, "bad shape");
    auto out = torch::empty({B, C, H, W}, attn.options());
    resid_ln_to_nchw_kernel<<<B * L, 128, 0, at::cuda::getCurrentCUDAStream()>>>(
        attn.data_ptr<float>(), resid.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),
        out.data_ptr<float>(), B, L, C, H, W, (float)eps64);
    return out;
}
'''

_ext = load_inline(
    name='mha_ln_custom_ext_v1',
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=['nchw_to_blc', 'attention_forward', 'resid_ln_to_nchw'],
    extra_cflags=['-O3'],
    extra_cuda_cflags=['-O3'],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super(ModelNew, self).__init__()
        self.attn = nn.MultiheadAttention(embed_dim, num_heads)
        self.norm = nn.LayerNorm(embed_dim)
        self.embed_dim = embed_dim
        self.num_heads = num_heads

    def forward(self, x):
        B, C, H, W = x.shape
        # Build the exact (batch, sequence, channel) tensor used by the reference.
        xb = _ext.nchw_to_blc(x.contiguous())
        qkv = F.linear(xb, self.attn.in_proj_weight, self.attn.in_proj_bias).contiguous()
        ctx = _ext.attention_forward(qkv, self.num_heads)
        proj = F.linear(ctx, self.attn.out_proj.weight, self.attn.out_proj.bias).contiguous()
        return _ext.resid_ln_to_nchw(proj, xb, self.norm.weight, self.norm.bias, H, W, self.norm.eps)