gpt-5.5-priority · original · l123_single_gpt
correct 52_Conv2d_Activation_BatchNorm.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
2.47 μs
ref runtime
3.56 μs
speedup
1.44x
started
2026-05-05T00:37:47Z
timingkernelbench.timing
kernel runtime
2.47 μs
ref runtime
3.56 μs
speedup
1.44x
kernel mean / median / std
2.47 / — / 0.01 μs
ref mean / median / std
3.56 / — / 0.55 μs
numerical precisioneval_kernel_against_ref
max abs error
7.16e-05
mean abs error
6.43e-06
max rel error
1.36e+07
mean rel error
0.31
gpu memoryextended_metrics.measure_memory
kernel peak
1777.96 MB
ref peak
1777.94 MB
kernel / ref
1.00x
kernel launches / fusiontorch.profiler
kernel launches
15
ref launches
22
fusion ratio (ref / kernel)
1.47x
total cuda time
6118 μs
energyNVML (pynvml)
kernel mJ / run
241.36
ref mJ / run
1690.00
ratio (ref / kernel)
7.00x
avg power
97.11 W
ref avg power
482.70 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
1.000
dram util %
100.0%
compute util %
65.2%
bottleneck
memory-bound
dominant pipe
tensor-core
arithmetic intensity
—
ridge point
295.22
roofline / occupancynsight_hardware_counters
dram bandwidth
10562.83 GB/s
dram util %
100.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
404.5%
bottleneck
memory-bound
dominant pipe %
65.2%
arithmetic intensity
—
ridge point
295.22
L1 hit %
—
L2 hit %
477.3%
ld sectors / req
32.40
st sectors / req
—
regs / thread
407
smem / block
83456 B
block size
1312
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
12904.1%
short_scoreboard
612.9%
mio_throttle
83.3%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Simple model that performs a convolution, applies activation, and then applies Batch Normalization.
    """
    def __init__(self, in_channels, out_channels, kernel_size, eps=1e-5, momentum=0.1):
        super(Model, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
        self.bn = nn.BatchNorm2d(out_channels, eps=eps, momentum=momentum)

    def forward(self, x):
        x = self.conv(x)
        x = torch.multiply(torch.tanh(torch.nn.functional.softplus(x)), x)
        x = self.bn(x)
        return x

batch_size = 64
in_channels = 64
out_channels = 128
height, width = 128, 128
kernel_size = 3

def get_inputs():
    return [torch.rand(batch_size, in_channels, height, width)]

def get_init_inputs():
    return [in_channels, out_channels, kernel_size]
turn 0 · FINAL · 1 tool call(s) · 47.9s turn · 47.9s LLM · 9,869 chars (click to expand)
turn 047.9s turn · 47.9s 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 mish_bn_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps);\n\ntorch::Tensor mish_bn_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps) {\n return mish_bn_forward_cuda(x, weight, bias, running_mean, running_var, training, momentum, eps);\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <ATen/cuda/CUDAContext.h>\n\n#ifndef CHECK_CUDA\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#endif\n\nstatic __device__ __forceinline__ float mish_f(float v) {\n float sp = (v > 20.0f) ? v : log1pf(expf(v));\n return v * tanhf(sp);\n}\n\ntemplate<int TPB>\n__global__ void mish_partials_kernel(const float* __restrict__ x, float* __restrict__ act,\n float* __restrict__ psum, float* __restrict__ psq,\n int N, int C, int HW, int parts) {\n int c = blockIdx.x;\n int p = blockIdx.y;\n int tid = threadIdx.x;\n int M = N * HW;\n int chunk = (M + parts - 1) / parts;\n int start = p * chunk;\n int end = start + chunk;\n if (end > M) end = M;\n\n float s = 0.0f, q = 0.0f;\n for (int k = start + tid; k < end; k += TPB) {\n int n = k / HW;\n int hw = k - n * HW;\n int idx = (n * C + c) * HW + hw;\n float z = mish_f(x[idx]);\n act[idx] = z;\n s += z;\n q = fmaf(z, z, q);\n }\n __shared__ float ss[TPB];\n __shared__ float qq[TPB];\n ss[tid] = s; qq[tid] = q;\n __syncthreads();\n for (int off = TPB/2; off > 0; off >>= 1) {\n if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }\n __syncthreads();\n }\n if (tid == 0) {\n psum[c * parts + p] = ss[0];\n psq[c * parts + p] = qq[0];\n }\n}\n\ntemplate<int TPB>\n__global__ void stats_kernel(const float* __restrict__ psum, const float* __restrict__ psq,\n const float* __restrict__ weight, const float* __restrict__ bias,\n float* __restrict__ running_mean, float* __restrict__ running_var,\n float* __restrict__ scale, float* __restrict__ shift,\n int C, int M, int parts, float momentum, float eps) {\n int c = blockIdx.x;\n int tid = threadIdx.x;\n float s = 0.0f, q = 0.0f;\n for (int p = tid; p < parts; p += TPB) {\n s += psum[c * parts + p];\n q += psq[c * parts + p];\n }\n __shared__ float ss[TPB];\n __shared__ float qq[TPB];\n ss[tid] = s; qq[tid] = q;\n __syncthreads();\n for (int off = TPB/2; off > 0; off >>= 1) {\n if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }\n __syncthreads();\n }\n if (tid == 0) {\n float mean = ss[0] / (float)M;\n float var = qq[0] / (float)M - mean * mean;\n var = var < 0.0f ? 0.0f : var;\n float inv = rsqrtf(var + eps);\n float g = weight[c];\n float b = bias[c];\n scale[c] = g * inv;\n shift[c] = b - mean * g * inv;\n // PyTorch BatchNorm updates running_var with the unbiased variance estimate.\n float unbiased = var * ((float)M / (float)(M - 1));\n running_mean[c] = running_mean[c] * (1.0f - momentum) + momentum * mean;\n running_var[c] = running_var[c] * (1.0f - momentum) + momentum * unbiased;\n }\n}\n\n__global__ void norm_kernel(const float* __restrict__ act, float* __restrict__ out,\n const float* __restrict__ scale, const float* __restrict__ shift,\n int total, int C, int HW) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int i = idx; i < total; i += stride) {\n int c = (i / HW) % C;\n out[i] = fmaf(act[i], scale[c], shift[c]);\n }\n}\n\n__global__ void mish_bn_eval_kernel(const float* __restrict__ x, float* __restrict__ out,\n const float* __restrict__ weight, const float* __restrict__ bias,\n const float* __restrict__ running_mean, const float* __restrict__ running_var,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int i = idx; i < total; i += stride) {\n int c = (i / HW) % C;\n float inv = rsqrtf(running_var[c] + eps);\n float z = mish_f(x[i]);\n out[i] = (z - running_mean[c]) * inv * weight[c] + bias[c];\n }\n}\n\ntorch::Tensor mish_bn_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps) {\n CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(bias); CHECK_CUDA(running_mean); CHECK_CUDA(running_var);\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n auto out = torch::empty_like(x);\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int HW = H * W;\n const int total = N * C * HW;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (!training) {\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 4096) blocks = 4096;\n mish_bn_eval_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<float>(),\n weight.data_ptr<float>(), bias.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(),\n total, C, HW, (float)eps);\n return out;\n }\n const int parts = 16;\n auto act = torch::empty_like(x);\n auto opts = x.options();\n auto psum = torch::empty({C, parts}, opts);\n auto psq = torch::empty({C, parts}, opts);\n auto scale = torch::empty({C}, opts);\n auto shift = torch::empty({C}, opts);\n dim3 grid1(C, parts);\n mish_partials_kernel<256><<<grid1, 256, 0, stream>>>(x.data_ptr<float>(), act.data_ptr<float>(), psum.data_ptr<float>(), psq.data_ptr<float>(), N, C, HW, parts);\n stats_kernel<32><<<C, 32, 0, stream>>>(psum.data_ptr<float>(), psq.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), C, N*HW, parts, (float)momentum, (float)eps);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 4096) blocks = 4096;\n norm_kernel<<<blocks, threads, 0, stream>>>(act.data_ptr<float>(), out.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), total, C, HW);\n return out;\n}\n'''\n\n_ext = load_inline(\n name='mish_bn_fused_ext_v1',\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=['mish_bn_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, eps=1e-5, momentum=0.1):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.bn = nn.BatchNorm2d(out_channels, eps=eps, momentum=momentum)\n\n def forward(self, x):\n y = F.conv2d(x, self.conv.weight, self.conv.bias, self.conv.stride,\n self.conv.padding, self.conv.dilation, self.conv.groups)\n return _ext.mish_bn_forward(y.contiguous(), self.bn.weight, self.bn.bias,\n self.bn.running_mean, self.bn.running_var,\n self.bn.training, float(self.bn.momentum), float(self.bn.eps))\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 2.47 μs Runtime stats: mean=2.47μs median=?μs std=0.01μs Numerical precision: max_abs_err=7.16e-05 mean_abs_err=6.43e-06 max_rel_err=1.36e+07 Memory: 1777.96 MB peak (ref: 1777.94 MB, ratio: 1.0x) Kernel launches: 15 (ref: 22, fusion ratio: 1.4667) Energy: 241.36 mJ/run (ref: 1690.0 mJ, ratio: 7.002x) SOL score: 1.0
final submitted kernel (198 lines, 8,325 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 mish_bn_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                                   torch::Tensor running_mean, torch::Tensor running_var,
                                   bool training, double momentum, double eps);

torch::Tensor mish_bn_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                              torch::Tensor running_mean, torch::Tensor running_var,
                              bool training, double momentum, double eps) {
    return mish_bn_forward_cuda(x, weight, bias, running_mean, running_var, training, momentum, eps);
}
'''

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

#ifndef CHECK_CUDA
#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x " must be a CUDA tensor")
#endif

static __device__ __forceinline__ float mish_f(float v) {
    float sp = (v > 20.0f) ? v : log1pf(expf(v));
    return v * tanhf(sp);
}

template<int TPB>
__global__ void mish_partials_kernel(const float* __restrict__ x, float* __restrict__ act,
                                     float* __restrict__ psum, float* __restrict__ psq,
                                     int N, int C, int HW, int parts) {
    int c = blockIdx.x;
    int p = blockIdx.y;
    int tid = threadIdx.x;
    int M = N * HW;
    int chunk = (M + parts - 1) / parts;
    int start = p * chunk;
    int end = start + chunk;
    if (end > M) end = M;

    float s = 0.0f, q = 0.0f;
    for (int k = start + tid; k < end; k += TPB) {
        int n = k / HW;
        int hw = k - n * HW;
        int idx = (n * C + c) * HW + hw;
        float z = mish_f(x[idx]);
        act[idx] = z;
        s += z;
        q = fmaf(z, z, q);
    }
    __shared__ float ss[TPB];
    __shared__ float qq[TPB];
    ss[tid] = s; qq[tid] = q;
    __syncthreads();
    for (int off = TPB/2; off > 0; off >>= 1) {
        if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }
        __syncthreads();
    }
    if (tid == 0) {
        psum[c * parts + p] = ss[0];
        psq[c * parts + p] = qq[0];
    }
}

template<int TPB>
__global__ void stats_kernel(const float* __restrict__ psum, const float* __restrict__ psq,
                             const float* __restrict__ weight, const float* __restrict__ bias,
                             float* __restrict__ running_mean, float* __restrict__ running_var,
                             float* __restrict__ scale, float* __restrict__ shift,
                             int C, int M, int parts, float momentum, float eps) {
    int c = blockIdx.x;
    int tid = threadIdx.x;
    float s = 0.0f, q = 0.0f;
    for (int p = tid; p < parts; p += TPB) {
        s += psum[c * parts + p];
        q += psq[c * parts + p];
    }
    __shared__ float ss[TPB];
    __shared__ float qq[TPB];
    ss[tid] = s; qq[tid] = q;
    __syncthreads();
    for (int off = TPB/2; off > 0; off >>= 1) {
        if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }
        __syncthreads();
    }
    if (tid == 0) {
        float mean = ss[0] / (float)M;
        float var = qq[0] / (float)M - mean * mean;
        var = var < 0.0f ? 0.0f : var;
        float inv = rsqrtf(var + eps);
        float g = weight[c];
        float b = bias[c];
        scale[c] = g * inv;
        shift[c] = b - mean * g * inv;
        // PyTorch BatchNorm updates running_var with the unbiased variance estimate.
        float unbiased = var * ((float)M / (float)(M - 1));
        running_mean[c] = running_mean[c] * (1.0f - momentum) + momentum * mean;
        running_var[c] = running_var[c] * (1.0f - momentum) + momentum * unbiased;
    }
}

__global__ void norm_kernel(const float* __restrict__ act, float* __restrict__ out,
                            const float* __restrict__ scale, const float* __restrict__ shift,
                            int total, int C, int HW) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int stride = blockDim.x * gridDim.x;
    for (int i = idx; i < total; i += stride) {
        int c = (i / HW) % C;
        out[i] = fmaf(act[i], scale[c], shift[c]);
    }
}

__global__ void mish_bn_eval_kernel(const float* __restrict__ x, float* __restrict__ out,
                                    const float* __restrict__ weight, const float* __restrict__ bias,
                                    const float* __restrict__ running_mean, const float* __restrict__ running_var,
                                    int total, int C, int HW, float eps) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int stride = blockDim.x * gridDim.x;
    for (int i = idx; i < total; i += stride) {
        int c = (i / HW) % C;
        float inv = rsqrtf(running_var[c] + eps);
        float z = mish_f(x[i]);
        out[i] = (z - running_mean[c]) * inv * weight[c] + bias[c];
    }
}

torch::Tensor mish_bn_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                                   torch::Tensor running_mean, torch::Tensor running_var,
                                   bool training, double momentum, double eps) {
    CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(bias); CHECK_CUDA(running_mean); CHECK_CUDA(running_var);
    TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 supported");
    TORCH_CHECK(x.is_contiguous(), "x must be contiguous");
    auto out = torch::empty_like(x);
    const int N = (int)x.size(0);
    const int C = (int)x.size(1);
    const int H = (int)x.size(2);
    const int W = (int)x.size(3);
    const int HW = H * W;
    const int total = N * C * HW;
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();
    if (!training) {
        int threads = 256;
        int blocks = (total + threads - 1) / threads;
        if (blocks > 4096) blocks = 4096;
        mish_bn_eval_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<float>(),
            weight.data_ptr<float>(), bias.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(),
            total, C, HW, (float)eps);
        return out;
    }
    const int parts = 16;
    auto act = torch::empty_like(x);
    auto opts = x.options();
    auto psum = torch::empty({C, parts}, opts);
    auto psq = torch::empty({C, parts}, opts);
    auto scale = torch::empty({C}, opts);
    auto shift = torch::empty({C}, opts);
    dim3 grid1(C, parts);
    mish_partials_kernel<256><<<grid1, 256, 0, stream>>>(x.data_ptr<float>(), act.data_ptr<float>(), psum.data_ptr<float>(), psq.data_ptr<float>(), N, C, HW, parts);
    stats_kernel<32><<<C, 32, 0, stream>>>(psum.data_ptr<float>(), psq.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),
        running_mean.data_ptr<float>(), running_var.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), C, N*HW, parts, (float)momentum, (float)eps);
    int threads = 256;
    int blocks = (total + threads - 1) / threads;
    if (blocks > 4096) blocks = 4096;
    norm_kernel<<<blocks, threads, 0, stream>>>(act.data_ptr<float>(), out.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), total, C, HW);
    return out;
}
'''

_ext = load_inline(
    name='mish_bn_fused_ext_v1',
    cpp_sources=[_cpp_src],
    cuda_sources=[_cuda_src],
    functions=['mish_bn_forward'],
    extra_cflags=['-O3'],
    extra_cuda_cflags=['-O3', '--use_fast_math'],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, eps=1e-5, momentum=0.1):
        super(ModelNew, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
        self.bn = nn.BatchNorm2d(out_channels, eps=eps, momentum=momentum)

    def forward(self, x):
        y = F.conv2d(x, self.conv.weight, self.conv.bias, self.conv.stride,
                     self.conv.padding, self.conv.dilation, self.conv.groups)
        return _ext.mish_bn_forward(y.contiguous(), self.bn.weight, self.bn.bias,
                                    self.bn.running_mean, self.bn.running_var,
                                    self.bn.training, float(self.bn.momentum), float(self.bn.eps))