gpt-5.5-priority · popcorn · l123_single_gpt
incorrect 19_DepthwiseSeparableConv1D_GELU_ResAdd.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
—
ref runtime
1.85 μs
speedup
—
started
2026-05-05T00:01:56Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel runtime
—
ref runtime
1.85 μs
speedup
—
kernel mean / median / std
—
ref mean / median / std
1.85 / — / 0.65 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
1.000
dram util %
100.0%
compute util %
100.0%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
4448.18 GB/s
dram util %
100.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
193.8%
bottleneck
compute-bound
dominant pipe %
198.5%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
226.6%
ld sectors / req
13.75
st sectors / req
—
regs / thread
448
smem / block
102400 B
block size
1024
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
1943.8%
short_scoreboard
192.5%
mio_throttle
21.5%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    1D depthwise separable convolution block: pointwise Conv1d (channel mixing), depthwise Conv1d (spatial),
    GELU activation, and residual addition. Used in genomic foundation models (Enformer) for efficient
    sequence processing of DNA/RNA.
    """
    def __init__(self, channels, expanded_channels, kernel_size):
        super(Model, self).__init__()
        self.pointwise = nn.Conv1d(channels, expanded_channels, 1)
        self.depthwise = nn.Conv1d(expanded_channels, expanded_channels, kernel_size,
                                   padding=kernel_size // 2, groups=expanded_channels)
        self.activation = nn.GELU()
        self.project_back = nn.Conv1d(expanded_channels, channels, 1)

    def forward(self, x):
        residual = x
        x = self.pointwise(x)
        x = self.depthwise(x)
        x = self.activation(x)
        x = self.project_back(x)
        x = x + residual
        return x

batch_size = 32
channels = 256
expanded_channels = 512
seq_len = 4096
kernel_size = 9

def get_inputs():
    return [torch.randn(popcorn_pri.jitter_int(batch_size), channels, popcorn_pri.jitter_int(seq_len))]

def get_init_inputs():
    return [channels, expanded_channels, kernel_size]
turn 0 · FINAL · 1 tool call(s) · 83.5s turn · 83.5s LLM · 8,660 chars (click to expand)
turn 083.5s turn · 83.5s LLM · 0.0s tools · FINAL
reasoning
**Reviewing CUDA extension setup** I'm figuring out the nuances of using cublas in CUDA code. I think I need to include the `cublas_v2.h` header and link it correctly, possibly using `extra_ldflags=['-lcublas']`. It's interesting that the PyTorch extension likely links to `cudart`, not cublas directly. I’m checking if I need to set the stream in `cublasSetStream`, but usually, the handle from ATen is sufficient. I suspect there might be numerical equivalence issues within an acceptable tolerance when comparing results.
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>\n\ntorch::Tensor forward_cuda(torch::Tensor x,\n torch::Tensor pw_w, torch::Tensor pw_b,\n torch::Tensor dw_w, torch::Tensor dw_b,\n torch::Tensor pr_w, torch::Tensor pr_b);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/types.h>\n#include <ATen/ATen.h>\n#include <ATen/Context.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <math.h>\n\n#define CHECK_CUBLAS(expr) do { cublasStatus_t _s = (expr); TORCH_CHECK(_s == CUBLAS_STATUS_SUCCESS, \"cuBLAS error: \", (int)_s); } while (0)\n\n__global__ void depthwise_gelu_kernel(const float* __restrict__ p,\n const float* __restrict__ pw_b,\n const float* __restrict__ dw_w,\n const float* __restrict__ dw_b,\n float* __restrict__ g,\n int B, int E, int L, int K) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)B * E * L;\n if (idx >= total) return;\n\n int l = (int)(idx % L);\n long long t = idx / L;\n int e = (int)(t % E);\n int b = (int)(t / E);\n int pad = K >> 1;\n\n const float* pbe = p + ((long long)b * E + e) * L;\n const float* dwe = dw_w + (long long)e * K;\n float pb = pw_b[e];\n float acc = dw_b[e];\n\n #pragma unroll\n for (int j = 0; j < 16; ++j) {\n if (j >= K) break;\n int src = l + j - pad;\n if ((unsigned)src < (unsigned)L) {\n acc += dwe[j] * (pbe[src] + pb);\n }\n }\n\n const float inv_sqrt2 = 0.70710678118654752440f;\n float gelu = 0.5f * acc * (1.0f + erff(acc * inv_sqrt2));\n g[idx] = gelu;\n}\n\n__global__ void add_residual_bias_kernel(float* __restrict__ y,\n const float* __restrict__ x,\n const float* __restrict__ bias,\n int B, int C, int L) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)B * C * L;\n if (idx >= total) return;\n int l = (int)(idx % L);\n long long t = idx / L;\n int c = (int)(t % C);\n (void)l;\n y[idx] = y[idx] + x[idx] + bias[c];\n}\n\ntorch::Tensor forward_cuda(torch::Tensor x,\n torch::Tensor pw_w, torch::Tensor pw_b,\n torch::Tensor dw_w, torch::Tensor dw_b,\n torch::Tensor pr_w, torch::Tensor pr_b) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n TORCH_CHECK(pw_w.is_contiguous() && pw_b.is_contiguous() && dw_w.is_contiguous() && dw_b.is_contiguous() && pr_w.is_contiguous() && pr_b.is_contiguous(), \"weights must be contiguous\");\n\n const c10::cuda::CUDAGuard device_guard(x.device());\n\n int B = (int)x.size(0);\n int C = (int)x.size(1);\n int L = (int)x.size(2);\n int E = (int)pw_w.size(0);\n int K = (int)dw_w.size(2);\n\n auto p = at::empty({B, E, L}, x.options());\n auto g = at::empty({B, E, L}, x.options());\n auto y = at::empty({B, C, L}, x.options());\n\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n CHECK_CUBLAS(cublasSetStream(handle, stream));\n#if defined(CUBLAS_PEDANTIC_MATH)\n if (at::globalContext().allowTF32CuDNN() || at::globalContext().allowTF32CuBLAS()) {\n CHECK_CUBLAS(cublasSetMathMode(handle, CUBLAS_DEFAULT_MATH));\n } else {\n CHECK_CUBLAS(cublasSetMathMode(handle, CUBLAS_PEDANTIC_MATH));\n }\n#endif\n\n const float alpha = 1.0f;\n const float beta0 = 0.0f;\n\n // Pointwise 1x1 conv as B independent row-major GEMMs:\n // p[b](E x L) = pw_w(E x C) * x[b](C x L), stored contiguous row-major.\n CHECK_CUBLAS(cublasSgemmStridedBatched(\n handle, CUBLAS_OP_N, CUBLAS_OP_N,\n L, E, C,\n &alpha,\n x.data_ptr<float>(), L, (long long)C * L,\n pw_w.data_ptr<float>(), C, 0LL,\n &beta0,\n p.data_ptr<float>(), L, (long long)E * L,\n B));\n\n int threads = 256;\n long long total_ge = (long long)B * E * L;\n int blocks_ge = (int)((total_ge + threads - 1) / threads);\n depthwise_gelu_kernel<<<blocks_ge, threads, 0, stream>>>(\n p.data_ptr<float>(), pw_b.data_ptr<float>(), dw_w.data_ptr<float>(), dw_b.data_ptr<float>(),\n g.data_ptr<float>(), B, E, L, K);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n\n // Project back: y[b](C x L) = pr_w(C x E) * g[b](E x L).\n CHECK_CUBLAS(cublasSgemmStridedBatched(\n handle, CUBLAS_OP_N, CUBLAS_OP_N,\n L, C, E,\n &alpha,\n g.data_ptr<float>(), L, (long long)E * L,\n pr_w.data_ptr<float>(), E, 0LL,\n &beta0,\n y.data_ptr<float>(), L, (long long)C * L,\n B));\n\n long long total_y = (long long)B * C * L;\n int blocks_y = (int)((total_y + threads - 1) / threads);\n add_residual_bias_kernel<<<blocks_y, threads, 0, stream>>>(\n y.data_ptr<float>(), x.data_ptr<float>(), pr_b.data_ptr<float>(), B, C, L);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"dsconv1d_fused_cublas_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"forward_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n with_cuda=True,\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, channels, expanded_channels, kernel_size):\n super(ModelNew, self).__init__()\n self.pointwise = nn.Conv1d(channels, expanded_channels, 1)\n self.depthwise = nn.Conv1d(expanded_channels, expanded_channels, kernel_size,\n padding=kernel_size // 2, groups=expanded_channels)\n self.activation = nn.GELU()\n self.project_back = nn.Conv1d(expanded_channels, channels, 1)\n\n def forward(self, x):\n return _ext.forward_cuda(x,\n self.pointwise.weight, self.pointwise.bias,\n self.depthwise.weight, self.depthwise.bias,\n self.project_back.weight, self.project_back.bias)\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: correctness check did not pass ((0 / 5) trials). correctness_issue: Output mismatch max_difference: ['0.000306', '0.000282', '0.000326', '0.000291', '0.000283'] avg_difference: ['0.000038', '0.000038', '0.000038', '0.000038', '0.000038']
final submitted kernel (178 lines, 6,540 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 forward_cuda(torch::Tensor x,
                           torch::Tensor pw_w, torch::Tensor pw_b,
                           torch::Tensor dw_w, torch::Tensor dw_b,
                           torch::Tensor pr_w, torch::Tensor pr_b);
"""

_cuda_src = r"""
#include <torch/types.h>
#include <ATen/ATen.h>
#include <ATen/Context.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <c10/cuda/CUDAException.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <math.h>

#define CHECK_CUBLAS(expr) do { cublasStatus_t _s = (expr); TORCH_CHECK(_s == CUBLAS_STATUS_SUCCESS, "cuBLAS error: ", (int)_s); } while (0)

__global__ void depthwise_gelu_kernel(const float* __restrict__ p,
                                      const float* __restrict__ pw_b,
                                      const float* __restrict__ dw_w,
                                      const float* __restrict__ dw_b,
                                      float* __restrict__ g,
                                      int B, int E, int L, int K) {
    long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;
    long long total = (long long)B * E * L;
    if (idx >= total) return;

    int l = (int)(idx % L);
    long long t = idx / L;
    int e = (int)(t % E);
    int b = (int)(t / E);
    int pad = K >> 1;

    const float* pbe = p + ((long long)b * E + e) * L;
    const float* dwe = dw_w + (long long)e * K;
    float pb = pw_b[e];
    float acc = dw_b[e];

    #pragma unroll
    for (int j = 0; j < 16; ++j) {
        if (j >= K) break;
        int src = l + j - pad;
        if ((unsigned)src < (unsigned)L) {
            acc += dwe[j] * (pbe[src] + pb);
        }
    }

    const float inv_sqrt2 = 0.70710678118654752440f;
    float gelu = 0.5f * acc * (1.0f + erff(acc * inv_sqrt2));
    g[idx] = gelu;
}

__global__ void add_residual_bias_kernel(float* __restrict__ y,
                                         const float* __restrict__ x,
                                         const float* __restrict__ bias,
                                         int B, int C, int L) {
    long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;
    long long total = (long long)B * C * L;
    if (idx >= total) return;
    int l = (int)(idx % L);
    long long t = idx / L;
    int c = (int)(t % C);
    (void)l;
    y[idx] = y[idx] + x[idx] + bias[c];
}

torch::Tensor forward_cuda(torch::Tensor x,
                           torch::Tensor pw_w, torch::Tensor pw_b,
                           torch::Tensor dw_w, torch::Tensor dw_b,
                           torch::Tensor pr_w, torch::Tensor pr_b) {
    TORCH_CHECK(x.is_cuda(), "x must be CUDA");
    TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 is supported");
    TORCH_CHECK(x.is_contiguous(), "x must be contiguous");
    TORCH_CHECK(pw_w.is_contiguous() && pw_b.is_contiguous() && dw_w.is_contiguous() && dw_b.is_contiguous() && pr_w.is_contiguous() && pr_b.is_contiguous(), "weights must be contiguous");

    const c10::cuda::CUDAGuard device_guard(x.device());

    int B = (int)x.size(0);
    int C = (int)x.size(1);
    int L = (int)x.size(2);
    int E = (int)pw_w.size(0);
    int K = (int)dw_w.size(2);

    auto p = at::empty({B, E, L}, x.options());
    auto g = at::empty({B, E, L}, x.options());
    auto y = at::empty({B, C, L}, x.options());

    cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();
    CHECK_CUBLAS(cublasSetStream(handle, stream));
#if defined(CUBLAS_PEDANTIC_MATH)
    if (at::globalContext().allowTF32CuDNN() || at::globalContext().allowTF32CuBLAS()) {
        CHECK_CUBLAS(cublasSetMathMode(handle, CUBLAS_DEFAULT_MATH));
    } else {
        CHECK_CUBLAS(cublasSetMathMode(handle, CUBLAS_PEDANTIC_MATH));
    }
#endif

    const float alpha = 1.0f;
    const float beta0 = 0.0f;

    // Pointwise 1x1 conv as B independent row-major GEMMs:
    // p[b](E x L) = pw_w(E x C) * x[b](C x L), stored contiguous row-major.
    CHECK_CUBLAS(cublasSgemmStridedBatched(
        handle, CUBLAS_OP_N, CUBLAS_OP_N,
        L, E, C,
        &alpha,
        x.data_ptr<float>(), L, (long long)C * L,
        pw_w.data_ptr<float>(), C, 0LL,
        &beta0,
        p.data_ptr<float>(), L, (long long)E * L,
        B));

    int threads = 256;
    long long total_ge = (long long)B * E * L;
    int blocks_ge = (int)((total_ge + threads - 1) / threads);
    depthwise_gelu_kernel<<<blocks_ge, threads, 0, stream>>>(
        p.data_ptr<float>(), pw_b.data_ptr<float>(), dw_w.data_ptr<float>(), dw_b.data_ptr<float>(),
        g.data_ptr<float>(), B, E, L, K);
    C10_CUDA_KERNEL_LAUNCH_CHECK();

    // Project back: y[b](C x L) = pr_w(C x E) * g[b](E x L).
    CHECK_CUBLAS(cublasSgemmStridedBatched(
        handle, CUBLAS_OP_N, CUBLAS_OP_N,
        L, C, E,
        &alpha,
        g.data_ptr<float>(), L, (long long)E * L,
        pr_w.data_ptr<float>(), E, 0LL,
        &beta0,
        y.data_ptr<float>(), L, (long long)C * L,
        B));

    long long total_y = (long long)B * C * L;
    int blocks_y = (int)((total_y + threads - 1) / threads);
    add_residual_bias_kernel<<<blocks_y, threads, 0, stream>>>(
        y.data_ptr<float>(), x.data_ptr<float>(), pr_b.data_ptr<float>(), B, C, L);
    C10_CUDA_KERNEL_LAUNCH_CHECK();

    return y;
}
"""

_ext = load_inline(
    name="dsconv1d_fused_cublas_ext",
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=["forward_cuda"],
    extra_cuda_cflags=["-O3"],
    extra_ldflags=["-lcublas"],
    with_cuda=True,
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, channels, expanded_channels, kernel_size):
        super(ModelNew, self).__init__()
        self.pointwise = nn.Conv1d(channels, expanded_channels, 1)
        self.depthwise = nn.Conv1d(expanded_channels, expanded_channels, kernel_size,
                                   padding=kernel_size // 2, groups=expanded_channels)
        self.activation = nn.GELU()
        self.project_back = nn.Conv1d(expanded_channels, channels, 1)

    def forward(self, x):
        return _ext.forward_cuda(x,
                                 self.pointwise.weight, self.pointwise.bias,
                                 self.depthwise.weight, self.depthwise.bias,
                                 self.project_back.weight, self.project_back.bias)