gpt-5.5-priority · original · l123_single_gpt
correct 8_Conv3d_Divide_Max_GlobalAvgPool_BiasAdd_Sum.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
8.52 μs
ref runtime
2.58 μs
speedup
0.30x
started
2026-05-05T01:07:29Z
timingkernelbench.timing
kernel runtime
8.52 μs
ref runtime
2.58 μs
speedup
0.30x
kernel mean / median / std
8.52 / — / 0.02 μs
ref mean / median / std
2.58 / — / 0.56 μs
numerical precisioneval_kernel_against_ref
max abs error
1.69e-05
mean abs error
1.16e-05
max rel error
1.89e-05
mean rel error
1.30e-05
gpu memoryextended_metrics.measure_memory
kernel peak
289.04 MB
ref peak
1385.92 MB
kernel / ref
0.21x
kernel launches / fusiontorch.profiler
kernel launches
2
ref launches
19
fusion ratio (ref / kernel)
9.50x
total cuda time
29 μs
energyNVML (pynvml)
kernel mJ / run
2645.88
ref mJ / run
240.82
ratio (ref / kernel)
0.09x
avg power
311.11 W
ref avg power
95.07 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.128
dram util %
1.1%
compute util %
12.8%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
35.48 GB/s
dram util %
1.1%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
18.5%
bottleneck
compute-bound
dominant pipe %
12.8%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
192.7%
ld sectors / req
24.01
st sectors / req
—
regs / thread
284
smem / block
3072 B
block size
384
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
2172.6%
short_scoreboard
128.6%
mio_throttle
0.0%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Model that performs a 3D convolution, divides by a constant, applies max pooling,
    global average pooling, adds a bias term, and sums along a specific dimension.
    """
    def __init__(self, in_channels, out_channels, kernel_size, divisor, pool_size, bias_shape, sum_dim):
        super(Model, self).__init__()
        self.conv = nn.Conv3d(in_channels, out_channels, kernel_size)
        self.divisor = divisor
        self.max_pool = nn.MaxPool3d(pool_size)
        self.global_avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1))
        self.bias = nn.Parameter(torch.randn(bias_shape))
        self.sum_dim = sum_dim

    def forward(self, x):
        x = self.conv(x)
        x = x / self.divisor
        x = self.max_pool(x)
        x = self.global_avg_pool(x)
        x = x + self.bias
        x = torch.sum(x, dim=self.sum_dim)
        return x

batch_size   = 128  
in_channels  = 8            
out_channels = 16  
depth = 16; height = width = 64 
kernel_size = (3, 3, 3)
divisor = 2.0
pool_size = (2, 2, 2)
bias_shape = (out_channels, 1, 1, 1)
sum_dim = 1

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

def get_init_inputs():
    return [in_channels, out_channels, kernel_size, divisor, pool_size, bias_shape, sum_dim]
turn 0 · FINAL · 1 tool call(s) · 53.1s turn · 53.1s LLM · 9,166 chars (click to expand)
turn 053.1s turn · 53.1s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\ntorch::Tensor fused_conv_pool_sum_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor conv_bias, torch::Tensor add_bias, double divisor);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n\n#ifndef CHECK_CUDA\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#endif\n#ifndef CHECK_CONTIGUOUS\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n#endif\n\n__global__ void conv3d_div_maxpool_gap_kernel(\n const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ cb,\n float* __restrict__ tmp,\n int N, int IC, int D, int H, int W,\n int OC, int KD, int KH, int KW,\n int OD, int OH, int OW,\n int PD, int PH, int PW,\n float inv_div)\n{\n int boc = blockIdx.x;\n int n = blockIdx.y;\n int tid = threadIdx.x;\n int pool_count = PD * PH * PW;\n float local = 0.0f;\n\n // Specialized fast path for the benchmark shape: IC=8 and 3x3x3 kernel.\n if (IC == 8 && KD == 3 && KH == 3 && KW == 3) {\n for (int p = tid; p < pool_count; p += blockDim.x) {\n int t = p;\n int pw = t % PW; t /= PW;\n int ph = t % PH;\n int pd = t / PH;\n int od0 = pd << 1;\n int oh0 = ph << 1;\n int ow0 = pw << 1;\n float m = -FLT_MAX;\n\n #pragma unroll\n for (int md = 0; md < 2; ++md) {\n #pragma unroll\n for (int mh = 0; mh < 2; ++mh) {\n #pragma unroll\n for (int mw = 0; mw < 2; ++mw) {\n int id0 = od0 + md;\n int ih0 = oh0 + mh;\n int iw0 = ow0 + mw;\n float acc = cb[boc];\n const float* wp = w + (((boc * IC) * 3) * 3) * 3;\n const float* xp_c0 = x + (((n * IC) * D + id0) * H + ih0) * W + iw0;\n #pragma unroll\n for (int ic = 0; ic < 8; ++ic) {\n const float* xp = xp_c0 + ic * D * H * W;\n #pragma unroll\n for (int kd = 0; kd < 3; ++kd) {\n const float* xpd = xp + kd * H * W;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const float* xph = xpd + kh * W;\n acc = fmaf(xph[0], wp[0], acc);\n acc = fmaf(xph[1], wp[1], acc);\n acc = fmaf(xph[2], wp[2], acc);\n wp += 3;\n }\n }\n }\n m = fmaxf(m, acc);\n }\n }\n }\n local += m * inv_div;\n }\n } else {\n for (int p = tid; p < pool_count; p += blockDim.x) {\n int t = p;\n int pw = t % PW; t /= PW;\n int ph = t % PH;\n int pd = t / PH;\n float m = -FLT_MAX;\n for (int md = 0; md < 2; ++md) {\n for (int mh = 0; mh < 2; ++mh) {\n for (int mw = 0; mw < 2; ++mw) {\n int od = pd * 2 + md;\n int oh = ph * 2 + mh;\n int ow = pw * 2 + mw;\n float acc = cb[boc];\n for (int ic = 0; ic < IC; ++ic) {\n for (int kd = 0; kd < KD; ++kd) {\n for (int kh = 0; kh < KH; ++kh) {\n for (int kw = 0; kw < KW; ++kw) {\n float xv = x[((((n * IC + ic) * D + od + kd) * H + oh + kh) * W + ow + kw)];\n float wv = w[(((((boc * IC + ic) * KD + kd) * KH + kh) * KW + kw))];\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n }\n m = fmaxf(m, acc);\n }\n }\n }\n local += m * inv_div;\n }\n }\n\n __shared__ float smem[256];\n smem[tid] = local;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n if (tid == 0) {\n tmp[n * OC + boc] = smem[0] / (float)pool_count;\n }\n}\n\n__global__ void channel_sum_bias_kernel(\n const float* __restrict__ tmp,\n const float* __restrict__ add_bias,\n float* __restrict__ out,\n int N, int OC)\n{\n int n = blockIdx.x * blockDim.x + threadIdx.x;\n if (n >= N) return;\n float s = 0.0f;\n // OC is 16 in the benchmark; keep generic loop for safety.\n for (int oc = 0; oc < OC; ++oc) {\n s += tmp[n * OC + oc] + add_bias[oc];\n }\n out[n] = s;\n}\n\ntorch::Tensor fused_conv_pool_sum_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor conv_bias, torch::Tensor add_bias, double divisor) {\n CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(conv_bias); CHECK_CUDA(add_bias);\n x = x.contiguous();\n weight = weight.contiguous();\n conv_bias = conv_bias.contiguous();\n add_bias = add_bias.contiguous();\n TORCH_CHECK(x.scalar_type() == torch::kFloat32, \"only float32 supported\");\n\n const int N = (int)x.size(0);\n const int IC = (int)x.size(1);\n const int D = (int)x.size(2);\n const int H = (int)x.size(3);\n const int W = (int)x.size(4);\n const int OC = (int)weight.size(0);\n const int KD = (int)weight.size(2);\n const int KH = (int)weight.size(3);\n const int KW = (int)weight.size(4);\n const int OD = D - KD + 1;\n const int OH = H - KH + 1;\n const int OW = W - KW + 1;\n const int PD = OD / 2;\n const int PH = OH / 2;\n const int PW = OW / 2;\n\n auto tmp = torch::empty({N, OC}, x.options());\n auto out = torch::empty({N, 1, 1, 1}, x.options());\n\n dim3 grid(OC, N, 1);\n const int threads = 256;\n float inv_div = 1.0f / (float)divisor;\n conv3d_div_maxpool_gap_kernel<<<grid, threads>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), conv_bias.data_ptr<float>(), tmp.data_ptr<float>(),\n N, IC, D, H, W, OC, KD, KH, KW, OD, OH, OW, PD, PH, PW, inv_div);\n\n int threads2 = 128;\n int blocks2 = (N + threads2 - 1) / threads2;\n channel_sum_bias_kernel<<<blocks2, threads2>>>(tmp.data_ptr<float>(), add_bias.data_ptr<float>(), out.data_ptr<float>(), N, OC);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"fused_conv3d_pool_gap_sum_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_conv_pool_sum_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divisor, pool_size, bias_shape, sum_dim):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv3d(in_channels, out_channels, kernel_size)\n self.divisor = divisor\n self.max_pool = nn.MaxPool3d(pool_size)\n self.global_avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1))\n self.bias = nn.Parameter(torch.randn(bias_shape))\n self.sum_dim = sum_dim\n\n def forward(self, x):\n return _ext.fused_conv_pool_sum_forward(x, self.conv.weight, self.conv.bias, self.bias, float(self.divisor))\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 8.52 μs Runtime stats: mean=8.52μs median=?μs std=0.02μs Numerical precision: max_abs_err=1.69e-05 mean_abs_err=1.16e-05 max_rel_err=1.89e-05 Memory: 289.04 MB peak (ref: 1385.92 MB, ratio: 0.2086x) Kernel launches: 2 (ref: 19, fusion ratio: 9.5) Energy: 2645.88 mJ/run (ref: 240.82 mJ, ratio: 0.091x) SOL score: 0.128
final submitted kernel (210 lines, 7,689 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

_cpp_src = r"""
#include <torch/extension.h>
torch::Tensor fused_conv_pool_sum_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor conv_bias, torch::Tensor add_bias, double divisor);
"""

_cuda_src = r"""
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>

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

__global__ void conv3d_div_maxpool_gap_kernel(
    const float* __restrict__ x,
    const float* __restrict__ w,
    const float* __restrict__ cb,
    float* __restrict__ tmp,
    int N, int IC, int D, int H, int W,
    int OC, int KD, int KH, int KW,
    int OD, int OH, int OW,
    int PD, int PH, int PW,
    float inv_div)
{
    int boc = blockIdx.x;
    int n = blockIdx.y;
    int tid = threadIdx.x;
    int pool_count = PD * PH * PW;
    float local = 0.0f;

    // Specialized fast path for the benchmark shape: IC=8 and 3x3x3 kernel.
    if (IC == 8 && KD == 3 && KH == 3 && KW == 3) {
        for (int p = tid; p < pool_count; p += blockDim.x) {
            int t = p;
            int pw = t % PW; t /= PW;
            int ph = t % PH;
            int pd = t / PH;
            int od0 = pd << 1;
            int oh0 = ph << 1;
            int ow0 = pw << 1;
            float m = -FLT_MAX;

            #pragma unroll
            for (int md = 0; md < 2; ++md) {
                #pragma unroll
                for (int mh = 0; mh < 2; ++mh) {
                    #pragma unroll
                    for (int mw = 0; mw < 2; ++mw) {
                        int id0 = od0 + md;
                        int ih0 = oh0 + mh;
                        int iw0 = ow0 + mw;
                        float acc = cb[boc];
                        const float* wp = w + (((boc * IC) * 3) * 3) * 3;
                        const float* xp_c0 = x + (((n * IC) * D + id0) * H + ih0) * W + iw0;
                        #pragma unroll
                        for (int ic = 0; ic < 8; ++ic) {
                            const float* xp = xp_c0 + ic * D * H * W;
                            #pragma unroll
                            for (int kd = 0; kd < 3; ++kd) {
                                const float* xpd = xp + kd * H * W;
                                #pragma unroll
                                for (int kh = 0; kh < 3; ++kh) {
                                    const float* xph = xpd + kh * W;
                                    acc = fmaf(xph[0], wp[0], acc);
                                    acc = fmaf(xph[1], wp[1], acc);
                                    acc = fmaf(xph[2], wp[2], acc);
                                    wp += 3;
                                }
                            }
                        }
                        m = fmaxf(m, acc);
                    }
                }
            }
            local += m * inv_div;
        }
    } else {
        for (int p = tid; p < pool_count; p += blockDim.x) {
            int t = p;
            int pw = t % PW; t /= PW;
            int ph = t % PH;
            int pd = t / PH;
            float m = -FLT_MAX;
            for (int md = 0; md < 2; ++md) {
                for (int mh = 0; mh < 2; ++mh) {
                    for (int mw = 0; mw < 2; ++mw) {
                        int od = pd * 2 + md;
                        int oh = ph * 2 + mh;
                        int ow = pw * 2 + mw;
                        float acc = cb[boc];
                        for (int ic = 0; ic < IC; ++ic) {
                            for (int kd = 0; kd < KD; ++kd) {
                                for (int kh = 0; kh < KH; ++kh) {
                                    for (int kw = 0; kw < KW; ++kw) {
                                        float xv = x[((((n * IC + ic) * D + od + kd) * H + oh + kh) * W + ow + kw)];
                                        float wv = w[(((((boc * IC + ic) * KD + kd) * KH + kh) * KW + kw))];
                                        acc = fmaf(xv, wv, acc);
                                    }
                                }
                            }
                        }
                        m = fmaxf(m, acc);
                    }
                }
            }
            local += m * inv_div;
        }
    }

    __shared__ float smem[256];
    smem[tid] = local;
    __syncthreads();
    for (int s = blockDim.x >> 1; s > 0; s >>= 1) {
        if (tid < s) smem[tid] += smem[tid + s];
        __syncthreads();
    }
    if (tid == 0) {
        tmp[n * OC + boc] = smem[0] / (float)pool_count;
    }
}

__global__ void channel_sum_bias_kernel(
    const float* __restrict__ tmp,
    const float* __restrict__ add_bias,
    float* __restrict__ out,
    int N, int OC)
{
    int n = blockIdx.x * blockDim.x + threadIdx.x;
    if (n >= N) return;
    float s = 0.0f;
    // OC is 16 in the benchmark; keep generic loop for safety.
    for (int oc = 0; oc < OC; ++oc) {
        s += tmp[n * OC + oc] + add_bias[oc];
    }
    out[n] = s;
}

torch::Tensor fused_conv_pool_sum_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor conv_bias, torch::Tensor add_bias, double divisor) {
    CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(conv_bias); CHECK_CUDA(add_bias);
    x = x.contiguous();
    weight = weight.contiguous();
    conv_bias = conv_bias.contiguous();
    add_bias = add_bias.contiguous();
    TORCH_CHECK(x.scalar_type() == torch::kFloat32, "only float32 supported");

    const int N = (int)x.size(0);
    const int IC = (int)x.size(1);
    const int D = (int)x.size(2);
    const int H = (int)x.size(3);
    const int W = (int)x.size(4);
    const int OC = (int)weight.size(0);
    const int KD = (int)weight.size(2);
    const int KH = (int)weight.size(3);
    const int KW = (int)weight.size(4);
    const int OD = D - KD + 1;
    const int OH = H - KH + 1;
    const int OW = W - KW + 1;
    const int PD = OD / 2;
    const int PH = OH / 2;
    const int PW = OW / 2;

    auto tmp = torch::empty({N, OC}, x.options());
    auto out = torch::empty({N, 1, 1, 1}, x.options());

    dim3 grid(OC, N, 1);
    const int threads = 256;
    float inv_div = 1.0f / (float)divisor;
    conv3d_div_maxpool_gap_kernel<<<grid, threads>>>(
        x.data_ptr<float>(), weight.data_ptr<float>(), conv_bias.data_ptr<float>(), tmp.data_ptr<float>(),
        N, IC, D, H, W, OC, KD, KH, KW, OD, OH, OW, PD, PH, PW, inv_div);

    int threads2 = 128;
    int blocks2 = (N + threads2 - 1) / threads2;
    channel_sum_bias_kernel<<<blocks2, threads2>>>(tmp.data_ptr<float>(), add_bias.data_ptr<float>(), out.data_ptr<float>(), N, OC);
    return out;
}
"""

_ext = load_inline(
    name="fused_conv3d_pool_gap_sum_ext_v1",
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=["fused_conv_pool_sum_forward"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, divisor, pool_size, bias_shape, sum_dim):
        super(ModelNew, self).__init__()
        self.conv = nn.Conv3d(in_channels, out_channels, kernel_size)
        self.divisor = divisor
        self.max_pool = nn.MaxPool3d(pool_size)
        self.global_avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1))
        self.bias = nn.Parameter(torch.randn(bias_shape))
        self.sum_dim = sum_dim

    def forward(self, x):
        return _ext.fused_conv_pool_sum_forward(x, self.conv.weight, self.conv.bias, self.bias, float(self.divisor))