gpt-5.5-priority · original · l12_default_gpt
correct 86_conv_depthwise_separable_2D.py
model
gpt-5.5-priority
turns / max
8 / 10
tool calls
8
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
2.84 μs
ref runtime
3.68 μs
speedup
1.30x
started
2026-05-02T20:43:00Z
timingkernelbench.timing
kernel runtime
2.84 μs
ref runtime
3.68 μs
speedup
1.30x
kernel mean / median / std
2.84 / — / 0.13 μs
ref mean / median / std
3.68 / — / 0.22 μs
numerical precisioneval_kernel_against_ref
max abs error
0.00
mean abs error
0.00
max rel error
0.00
mean rel error
0.00
gpu memoryextended_metrics.measure_memory
kernel peak
4129.07 MB
ref peak
4129.07 MB
kernel / ref
1.00x
kernel launches / fusiontorch.profiler
kernel launches
2
ref launches
10
fusion ratio (ref / kernel)
5.00x
total cuda time
28 μs
energyNVML (pynvml)
kernel mJ / run
322.56
ref mJ / run
319.04
ratio (ref / kernel)
0.99x
avg power
115.03 W
ref avg power
88.21 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
1.000
dram util %
100.0%
compute util %
13.5%
bottleneck
memory-bound
dominant pipe
tensor-core
arithmetic intensity
—
ridge point
295.22
roofline / occupancynsight_hardware_counters
dram bandwidth
4062.06 GB/s
dram util %
100.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
85.5%
bottleneck
memory-bound
dominant pipe %
13.5%
arithmetic intensity
—
ridge point
295.22
L1 hit %
—
L2 hit %
151.7%
ld sectors / req
13.10
st sectors / req
—
regs / thread
207
smem / block
233472 B
block size
640
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
2149.7%
short_scoreboard
110.6%
mio_throttle
36.1%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Performs a depthwise-separable 2D convolution operation.

    Args:
        in_channels (int): Number of channels in the input tensor.
        out_channels (int): Number of channels produced by the convolution.
        kernel_size (int): Size of the convolution kernel.
        stride (int, optional): Stride of the convolution. Defaults to 1.
        padding (int, optional): Padding applied to the input. Defaults to 0.
        dilation (int, optional): Spacing between kernel elements. Defaults to 1.
        bias (bool, optional): If `True`, adds a learnable bias to the output. Defaults to `False`.
    """
    def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):
        super(Model, self).__init__()
        self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride, padding=padding, dilation=dilation, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=bias)
        
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        Performs the depthwise-separable 2D convolution.

        Args:
            x (torch.Tensor): Input tensor of shape (batch_size, in_channels, height, width).

        Returns:
            torch.Tensor: Output tensor of shape (batch_size, out_channels, height_out, width_out).
        """
        x = self.depthwise(x)
        x = self.pointwise(x)
        return x

# Test code
batch_size = 16
in_channels = 64
out_channels = 128
kernel_size = 3
width = 512
height = 512
stride = 1
padding = 1
dilation = 1

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

def get_init_inputs():
    return [in_channels, out_channels, kernel_size, stride, padding, dilation]
turn 07.2s turn · 7.2s LLM · 0.0s tools
call → get_gpu_specs
callget_gpu_specs {}
result ← get_gpu_specs (ok)
okget_gpu_specs GPU specs for NVIDIA H100 80GB HBM3: total memory (runtime): 79.1 GB spec entry: H100 GPU Architecture: Hopper GPU Memory: 80GB Memory Bandwidth: 3.35 TB/s FP64 TFLOPS: 34 FP64 Tensor Core TFLOPS: 67 FP32 TFLOPS: 67 TF32 Tensor Core TFLOPS: 989 with sparsity BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity FP16 Tensor Core TFLOPS: 1979 with sparsity FP8 Tensor Core TFLOPS: 3958 with sparsity INT8 Tensor Core TOPS: 3958 with sparsity Register File Size: 64K 32-bit registers per SM Maximum number of registers per thread: 255 Maximum number of thread blocks per SM: 32 Shared memory capacity per SM: 228 KB Maximum shared memory per thread block: 227 KB
turn 1 · 1 tool call(s) · 59.3s turn · 59.3s LLM · 11,005 chars (click to expand)
turn 159.3s turn · 59.3s LLM · 0.0s tools
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream);\nvoid add_pw_bias_launcher(float* y, const float* b, int OC, long P, cudaStream_t stream);\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w,\n at::Tensor dw_b, at::Tensor pw_b,\n int64_t stride, int64_t padding, int64_t dilation) {\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int K = (int)dw_w.size(2);\n int OC = (int)pw_w.size(0);\n int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n int Wo = (W + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n auto inter = at::empty({N, C, Ho, Wo}, x.options());\n auto out = at::empty({N, OC, Ho, Wo}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* db = dw_b.numel() ? dw_b.data_ptr<float>() : nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(),\n N, C, H, W, K, (int)stride, (int)padding, (int)dilation, Ho, Wo, dw_b.numel()!=0, stream);\n // out[OC, P] row-major = pw_w[OC,C] * inter[C,P], where P=N*Ho*Wo with inter laid out by channel planes inside N.\n // Actually inter is N,C,Ho,Wo, not C,NHW. Need special layout? We'll handle only NCHW flattened gives per n chunks.\n // Do batched GEMM per batch: out_n[OC,HW] = W[OC,C] * inter_n[C,HW]\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n const float alpha = 1.0f, beta = 0.0f;\n long S = (long)Ho * (long)Wo;\n for (int n=0; n<N; ++n) {\n const float* B = inter.data_ptr<float>() + (long)n * C * S;\n float* Y = out.data_ptr<float>() + (long)n * OC * S;\n // row-major (OC x S) = (OC x C) * (C x S). Column-major trick: m=S,n=OC,k=C.\n cublasStatus_t stat = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C,\n &alpha,\n B, (int)S,\n pw_w.data_ptr<float>(), C,\n &beta,\n Y, (int)S);\n TORCH_CHECK(stat == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n }\n if (pw_b.numel()) {\n add_pw_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, (long)N*Ho*Wo, stream);\n }\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void depthwise_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, int K,\n int stride, int pad, int dil, int Ho, int Wo,\n bool has_bias) {\n const int ITEMS = 4;\n int plane = blockIdx.y; // n*C+c\n int n = plane / C;\n int c = plane - n*C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = Ho * Wo;\n const float* xbase = x + ((long)n*C + c) * H * W;\n const float* wbase = w + (long)c * K * K;\n float* ybase = y + ((long)n*C + c) * S;\n #pragma unroll\n for (int it=0; it<ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int oh = idx / Wo;\n int ow = idx - oh * Wo;\n float acc = has_bias ? b[c] : 0.0f;\n int ih0 = oh * stride - pad;\n int iw0 = ow * stride - pad;\n for (int kh=0; kh<K; ++kh) {\n int ih = ih0 + kh * dil;\n if ((unsigned)ih < (unsigned)H) {\n for (int kw=0; kw<K; ++kw) {\n int iw = iw0 + kw * dil;\n if ((unsigned)iw < (unsigned)W) {\n acc = fmaf(xbase[ih * W + iw], wbase[kh * K + kw], acc);\n }\n }\n }\n }\n ybase[idx] = acc;\n }\n }\n}\n\n__global__ void depthwise_3x3s1p1_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, bool has_bias) {\n const int ITEMS = 4;\n int plane = blockIdx.y;\n int n = plane / C;\n int c = plane - n*C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = H * W;\n const float* xb = x + ((long)n*C + c) * S;\n const float* wb = w + (long)c * 9;\n float* yb = y + ((long)n*C + c) * S;\n float w00=wb[0], w01=wb[1], w02=wb[2], w10=wb[3], w11=wb[4], w12=wb[5], w20=wb[6], w21=wb[7], w22=wb[8];\n #pragma unroll\n for (int it=0; it<ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int h = idx / W;\n int col = idx - h * W;\n float acc = has_bias ? b[c] : 0.0f;\n if (h > 0) {\n int r = idx - W;\n if (col > 0) acc = fmaf(xb[r-1], w00, acc);\n acc = fmaf(xb[r ], w01, acc);\n if (col < W-1) acc = fmaf(xb[r+1], w02, acc);\n }\n if (col > 0) acc = fmaf(xb[idx-1], w10, acc);\n acc = fmaf(xb[idx ], w11, acc);\n if (col < W-1) acc = fmaf(xb[idx+1], w12, acc);\n if (h < H-1) {\n int r = idx + W;\n if (col > 0) acc = fmaf(xb[r-1], w20, acc);\n acc = fmaf(xb[r ], w21, acc);\n if (col < W-1) acc = fmaf(xb[r+1], w22, acc);\n }\n yb[idx] = acc;\n }\n }\n}\n\n__global__ void add_pw_bias_kernel(float* __restrict__ y, const float* __restrict__ b, int OC, long P) {\n long idx = (long)blockIdx.x * blockDim.x + threadIdx.x;\n long total = (long)OC * P;\n if (idx < total) {\n long s = idx % ((long)OC * (P / gridDim.y)); // unused path not robust\n }\n}\n\n__global__ void add_bias_nchw_kernel(float* __restrict__ y, const float* __restrict__ b, int OC, long S, long total) {\n long idx = (long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n long t = idx / S;\n int oc = (int)(t % OC);\n y[idx] += b[oc];\n }\n}\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream) {\n dim3 block(256);\n int S = Ho * Wo;\n dim3 grid((S + block.x * 4 - 1) / (block.x * 4), N * C);\n if (K == 3 && stride == 1 && pad == 1 && dil == 1 && Ho == H && Wo == W) {\n depthwise_3x3s1p1_kernel<<<grid, block, 0, stream>>>(x,w,b,y,N,C,H,W,has_bias);\n } else {\n depthwise_generic_kernel<<<grid, block, 0, stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);\n }\n}\n\nvoid add_pw_bias_launcher(float* y, const float* b, int OC, long P, cudaStream_t stream) {\n // P is N*S, but y layout is N,OC,S. Need S unavailable; not used in benchmark bias=False.\n}\n'''\n\n_ext = load_inline(name='dwsep_ext_v1', cpp_sources=cpp_sources, cuda_sources=cuda_sources,\n functions=['depthwise_sep_forward'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride, padding=padding, dilation=dilation, groups=in_channels, bias=bias)\n self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=bias)\n self.stride = stride\n self.padding = padding\n self.dilation = dilation\n self._empty = None\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self._empty is None or self._empty.device != x.device:\n self._empty = torch.empty(0, device=x.device, dtype=x.dtype)\n db = self.depthwise.bias if self.depthwise.bias is not None else self._empty\n pb = self.pointwise.bias if self.pointwise.bias is not None else self._empty\n return _ext.depthwise_sep_forward(x, self.depthwise.weight, self.pointwise.weight, db, pb, self.stride, self.padding, self.dilation)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2 · 1 tool call(s) · 14.5s turn · 14.5s LLM · 8,394 chars (click to expand)
turn 214.5s turn · 14.5s LLM · 0.0s tools
reasoning
**Evaluating correctness issues** I’m thinking about correctness, specifically regarding the addition of potential bias in the process, although that shouldn’t have an effect. The cublas per batch layout seems okay, but I’m considering whether I need to tolerate some differences, maybe due to pointwise operations differing from PyTorch's convolution. Is PyTorch using TF32? I need to check whether the reference for fp32 versus TF32 is accurate. Usually, I reference full fp32, but I think using tolerances with PyTorch might be necessary. I'll run some tests.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream);\nvoid add_pw_bias_launcher(float* y, const float* b, int OC, long P, cudaStream_t stream);\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w,\n at::Tensor dw_b, at::Tensor pw_b,\n int64_t stride, int64_t padding, int64_t dilation) {\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int K = (int)dw_w.size(2);\n int OC = (int)pw_w.size(0);\n int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n int Wo = (W + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n auto inter = at::empty({N, C, Ho, Wo}, x.options());\n auto out = at::empty({N, OC, Ho, Wo}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* db = dw_b.numel() ? dw_b.data_ptr<float>() : nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(),\n N, C, H, W, K, (int)stride, (int)padding, (int)dilation, Ho, Wo, dw_b.numel()!=0, stream);\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n const float alpha = 1.0f, beta = 0.0f;\n long S = (long)Ho * (long)Wo;\n for (int n=0; n<N; ++n) {\n const float* B = inter.data_ptr<float>() + (long)n * C * S;\n float* Y = out.data_ptr<float>() + (long)n * OC * S;\n cublasStatus_t stat = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C,\n &alpha, B, (int)S,\n pw_w.data_ptr<float>(), C,\n &beta, Y, (int)S);\n TORCH_CHECK(stat == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n }\n if (pw_b.numel()) { add_pw_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, (long)N*Ho*Wo, stream); }\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda.h>\n#include <cuda_runtime.h>\n__global__ void depthwise_generic_kernel(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias){const int ITEMS=4;int plane=blockIdx.y;int n=plane/C;int c=plane-n*C;int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS;int S=Ho*Wo;const float* xbase=x+((long)n*C+c)*H*W;const float* wbase=w+(long)c*K*K;float* ybase=y+((long)n*C+c)*S;#pragma unroll\nfor(int it=0;it<ITEMS;++it){int idx=base+it;if(idx<S){int oh=idx/Wo;int ow=idx-oh*Wo;float acc=has_bias?b[c]:0.0f;int ih0=oh*stride-pad;int iw0=ow*stride-pad;for(int kh=0;kh<K;++kh){int ih=ih0+kh*dil;if((unsigned)ih<(unsigned)H){for(int kw=0;kw<K;++kw){int iw=iw0+kw*dil;if((unsigned)iw<(unsigned)W){acc=fmaf(xbase[ih*W+iw],wbase[kh*K+kw],acc);}}}}ybase[idx]=acc;}}}\n__global__ void depthwise_3x3s1p1_kernel(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,bool has_bias){const int ITEMS=4;int plane=blockIdx.y;int n=plane/C;int c=plane-n*C;int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS;int S=H*W;const float* xb=x+((long)n*C+c)*S;const float* wb=w+(long)c*9;float* yb=y+((long)n*C+c)*S;float w00=wb[0],w01=wb[1],w02=wb[2],w10=wb[3],w11=wb[4],w12=wb[5],w20=wb[6],w21=wb[7],w22=wb[8];#pragma unroll\nfor(int it=0;it<ITEMS;++it){int idx=base+it;if(idx<S){int h=idx/W;int col=idx-h*W;float acc=has_bias?b[c]:0.0f;if(h>0){int r=idx-W;if(col>0)acc=fmaf(xb[r-1],w00,acc);acc=fmaf(xb[r],w01,acc);if(col<W-1)acc=fmaf(xb[r+1],w02,acc);}if(col>0)acc=fmaf(xb[idx-1],w10,acc);acc=fmaf(xb[idx],w11,acc);if(col<W-1)acc=fmaf(xb[idx+1],w12,acc);if(h<H-1){int r=idx+W;if(col>0)acc=fmaf(xb[r-1],w20,acc);acc=fmaf(xb[r],w21,acc);if(col<W-1)acc=fmaf(xb[r+1],w22,acc);}yb[idx]=acc;}}}\nvoid depthwise_kernel_launcher(const float* x,const float* w,const float* b,float* y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias,cudaStream_t stream){dim3 block(256);int S=Ho*Wo;dim3 grid((S+block.x*4-1)/(block.x*4),N*C);if(K==3&&stride==1&&pad==1&&dil==1&&Ho==H&&Wo==W)depthwise_3x3s1p1_kernel<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,has_bias);else depthwise_generic_kernel<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);}void add_pw_bias_launcher(float* y,const float* b,int OC,long P,cudaStream_t stream){}\n'''\n_ext = load_inline(name='dwsep_ext_v1c', cpp_sources=cpp_sources, cuda_sources=cuda_sources, functions=['depthwise_sep_forward'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, in_channels:int,out_channels:int,kernel_size:int,stride:int=1,padding:int=0,dilation:int=1,bias:bool=False):\n super().__init__(); self.depthwise=nn.Conv2d(in_channels,in_channels,kernel_size,stride=stride,padding=padding,dilation=dilation,groups=in_channels,bias=bias); self.pointwise=nn.Conv2d(in_channels,out_channels,kernel_size=1,bias=bias); self.stride=stride; self.padding=padding; self.dilation=dilation; self._empty=None\n def forward(self,x):\n if self._empty is None or self._empty.device!=x.device: self._empty=torch.empty(0,device=x.device,dtype=x.dtype)\n return _ext.depthwise_sep_forward(x,self.depthwise.weight,self.pointwise.weight,self.depthwise.bias if self.depthwise.bias is not None else self._empty,self.pointwise.bias if self.pointwise.bias is not None else self._empty,self.stride,self.padding,self.dilation)\n" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: persistent build/lock contention after retries. Please try a different kernel.
turn 3 · 1 tool call(s) · 24.6s turn · 24.6s LLM · 9,506 chars (click to expand)
turn 324.6s turn · 24.6s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream);\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w,\n at::Tensor dw_b, at::Tensor pw_b,\n int64_t stride, int64_t padding, int64_t dilation) {\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int K = (int)dw_w.size(2), OC = (int)pw_w.size(0);\n int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n int Wo = (W + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n auto inter = at::empty({N, C, Ho, Wo}, x.options());\n auto out = at::empty({N, OC, Ho, Wo}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* db = dw_b.numel() ? dw_b.data_ptr<float>() : nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(),\n N, C, H, W, K, (int)stride, (int)padding, (int)dilation, Ho, Wo, dw_b.numel()!=0, stream);\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n cublasSetMathMode(handle, CUBLAS_PEDANTIC_MATH);\n const float alpha = 1.0f, beta = 0.0f;\n long S = (long)Ho * (long)Wo;\n for (int n=0; n<N; ++n) {\n const float* B = inter.data_ptr<float>() + (long)n * C * S;\n float* Y = out.data_ptr<float>() + (long)n * OC * S;\n cublasStatus_t stat = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C, &alpha, B, (int)S,\n pw_w.data_ptr<float>(), C, &beta, Y, (int)S);\n TORCH_CHECK(stat == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n }\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void depthwise_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, int K,\n int stride, int pad, int dil, int Ho, int Wo,\n bool has_bias) {\n const int ITEMS = 4;\n int plane = blockIdx.y;\n int n = plane / C;\n int c = plane - n*C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = Ho * Wo;\n const float* xbase = x + ((long)n*C + c) * H * W;\n const float* wbase = w + (long)c * K * K;\n float* ybase = y + ((long)n*C + c) * S;\n #pragma unroll\n for (int it=0; it<ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int oh = idx / Wo;\n int ow = idx - oh * Wo;\n float acc = has_bias ? b[c] : 0.0f;\n int ih0 = oh * stride - pad;\n int iw0 = ow * stride - pad;\n for (int kh=0; kh<K; ++kh) {\n int ih = ih0 + kh * dil;\n if ((unsigned)ih < (unsigned)H) {\n for (int kw=0; kw<K; ++kw) {\n int iw = iw0 + kw * dil;\n if ((unsigned)iw < (unsigned)W) acc = fmaf(xbase[ih * W + iw], wbase[kh * K + kw], acc);\n }\n }\n }\n ybase[idx] = acc;\n }\n }\n}\n\n__global__ void depthwise_3x3s1p1_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, bool has_bias) {\n const int ITEMS = 4;\n int plane = blockIdx.y;\n int n = plane / C;\n int c = plane - n*C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = H * W;\n const float* xb = x + ((long)n*C + c) * S;\n const float* wb = w + (long)c * 9;\n float* yb = y + ((long)n*C + c) * S;\n float w00=wb[0], w01=wb[1], w02=wb[2], w10=wb[3], w11=wb[4], w12=wb[5], w20=wb[6], w21=wb[7], w22=wb[8];\n #pragma unroll\n for (int it=0; it<ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int h = idx / W;\n int col = idx - h * W;\n float acc = has_bias ? b[c] : 0.0f;\n if (h > 0) {\n int r = idx - W;\n if (col > 0) acc = fmaf(xb[r-1], w00, acc);\n acc = fmaf(xb[r], w01, acc);\n if (col < W-1) acc = fmaf(xb[r+1], w02, acc);\n }\n if (col > 0) acc = fmaf(xb[idx-1], w10, acc);\n acc = fmaf(xb[idx], w11, acc);\n if (col < W-1) acc = fmaf(xb[idx+1], w12, acc);\n if (h < H-1) {\n int r = idx + W;\n if (col > 0) acc = fmaf(xb[r-1], w20, acc);\n acc = fmaf(xb[r], w21, acc);\n if (col < W-1) acc = fmaf(xb[r+1], w22, acc);\n }\n yb[idx] = acc;\n }\n }\n}\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream) {\n dim3 block(256);\n int S = Ho * Wo;\n dim3 grid((S + block.x * 4 - 1) / (block.x * 4), N * C);\n if (K == 3 && stride == 1 && pad == 1 && dil == 1 && Ho == H && Wo == W) {\n depthwise_3x3s1p1_kernel<<<grid, block, 0, stream>>>(x,w,b,y,N,C,H,W,has_bias);\n } else {\n depthwise_generic_kernel<<<grid, block, 0, stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);\n }\n}\n'''\n\n_ext = load_inline(name='dwsep_ext_v2uniq', cpp_sources=cpp_sources, cuda_sources=cuda_sources,\n functions=['depthwise_sep_forward'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride, padding=padding, dilation=dilation, groups=in_channels, bias=bias)\n self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=bias)\n self.stride = stride; self.padding = padding; self.dilation = dilation; self._empty = None\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self._empty is None or self._empty.device != x.device: self._empty = torch.empty(0, device=x.device, dtype=x.dtype)\n db = self.depthwise.bias if self.depthwise.bias is not None else self._empty\n pb = self.pointwise.bias if self.pointwise.bias is not None else self._empty\n return _ext.depthwise_sep_forward(x, self.depthwise.weight, self.pointwise.weight, db, pb, self.stride, self.padding, self.dilation)\n" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['0.000377', '0.000373', '0.000377', '0.000369', '0.000386'] avg_difference: ['0.000048', '0.000048', '0.000048', '0.000048', '0.000048']
turn 4 · 1 tool call(s) · 18.5s turn · 18.5s LLM · 6,851 chars (click to expand)
turn 418.5s turn · 18.5s LLM · 0.0s tools
reasoning
**Evaluating PyTorch precision settings** I’m delving into how PyTorch handles conv layers by default with TF32 on Ampere, unless that’s turned off. The correctness tolerance of 1e-4 needs consideration, but matching with TF32 is tricky since solutions might suggest using torch.set_float32_matmul_precision, which isn’t applicable here. I guess I should factor in cublas TF32 and check if we’re avoiding mismatches due to PyTorch’s handling. My next step is to test the defaults without being too strict.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\nvoid depthwise_kernel_launcher(const float*,const float*,const float*,float*,int,int,int,int,int,int,int,int,int,int,bool,cudaStream_t);\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be CUDA\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type()==at::kFloat, #x \" must float\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" contig\")\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w, at::Tensor dw_b, at::Tensor pw_b, int64_t stride, int64_t padding, int64_t dilation){\n CHECK_CUDA(x);CHECK_FLOAT(x);CHECK_CONTIGUOUS(x);CHECK_CONTIGUOUS(dw_w);CHECK_CONTIGUOUS(pw_w);\n int N=x.size(0),C=x.size(1),H=x.size(2),W=x.size(3),K=dw_w.size(2),OC=pw_w.size(0); int Ho=(H+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1; int Wo=(W+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1;\n auto inter=at::empty({N,C,Ho,Wo},x.options()); auto out=at::empty({N,OC,Ho,Wo},x.options()); cudaStream_t stream=at::cuda::getCurrentCUDAStream(); const float* db=dw_b.numel()?dw_b.data_ptr<float>():nullptr; depthwise_kernel_launcher(x.data_ptr<float>(),dw_w.data_ptr<float>(),db,inter.data_ptr<float>(),N,C,H,W,K,stride,padding,dilation,Ho,Wo,dw_b.numel()!=0,stream);\n cublasHandle_t handle=at::cuda::getCurrentCUDABlasHandle(); cublasSetStream(handle,stream); cublasSetMathMode(handle,CUBLAS_TF32_TENSOR_OP_MATH); const float alpha=1.0f,beta=0.0f; long S=(long)Ho*Wo; for(int n=0;n<N;++n){const float* B=inter.data_ptr<float>()+(long)n*C*S; float* Y=out.data_ptr<float>()+(long)n*OC*S; cublasStatus_t stat=cublasSgemm(handle,CUBLAS_OP_N,CUBLAS_OP_N,(int)S,OC,C,&alpha,B,(int)S,pw_w.data_ptr<float>(),C,&beta,Y,(int)S); TORCH_CHECK(stat==CUBLAS_STATUS_SUCCESS,\"gemm failed\");} return out;}\n'''\ncuda_sources = r'''\n#include <cuda_runtime.h>\n__global__ void dw3(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,bool has_bias){const int ITEMS=4;int plane=blockIdx.y;int n=plane/C;int c=plane-n*C;int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS;int S=H*W;const float* xb=x+((long)n*C+c)*S;const float* wb=w+(long)c*9;float* yb=y+((long)n*C+c)*S;float w00=wb[0],w01=wb[1],w02=wb[2],w10=wb[3],w11=wb[4],w12=wb[5],w20=wb[6],w21=wb[7],w22=wb[8];\n#pragma unroll\nfor(int it=0;it<ITEMS;++it){int idx=base+it;if(idx<S){int h=idx/W;int col=idx-h*W;float acc=has_bias?b[c]:0.0f;if(h>0){int r=idx-W;if(col>0)acc=fmaf(xb[r-1],w00,acc);acc=fmaf(xb[r],w01,acc);if(col<W-1)acc=fmaf(xb[r+1],w02,acc);}if(col>0)acc=fmaf(xb[idx-1],w10,acc);acc=fmaf(xb[idx],w11,acc);if(col<W-1)acc=fmaf(xb[idx+1],w12,acc);if(h<H-1){int r=idx+W;if(col>0)acc=fmaf(xb[r-1],w20,acc);acc=fmaf(xb[r],w21,acc);if(col<W-1)acc=fmaf(xb[r+1],w22,acc);}yb[idx]=acc;}}}\n__global__ void dwgen(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias){int plane=blockIdx.y;int n=plane/C;int c=plane-n*C;int idx=blockIdx.x*blockDim.x+threadIdx.x;int S=Ho*Wo;if(idx<S){int oh=idx/Wo,ow=idx-oh*Wo;float acc=has_bias?b[c]:0.f;const float* xb=x+((long)n*C+c)*H*W;const float* wb=w+(long)c*K*K;for(int kh=0;kh<K;++kh){int ih=oh*stride-pad+kh*dil;if((unsigned)ih<(unsigned)H)for(int kw=0;kw<K;++kw){int iw=ow*stride-pad+kw*dil;if((unsigned)iw<(unsigned)W)acc=fmaf(xb[ih*W+iw],wb[kh*K+kw],acc);}}y[((long)n*C+c)*S+idx]=acc;}}\nvoid depthwise_kernel_launcher(const float* x,const float* w,const float* b,float* y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias,cudaStream_t stream){dim3 block(256);int S=Ho*Wo;if(K==3&&stride==1&&pad==1&&dil==1&&Ho==H&&Wo==W){dim3 grid((S+block.x*4-1)/(block.x*4),N*C);dw3<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,has_bias);}else{dim3 grid((S+block.x-1)/block.x,N*C);dwgen<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);}}\n'''\n_ext=load_inline(name='dwsep_ext_tf32test',cpp_sources=cpp_sources,cuda_sources=cuda_sources,functions=['depthwise_sep_forward'],extra_cflags=['-O3'],extra_cuda_cflags=['-O3'],extra_ldflags=['-lcublas'],verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_channels:int,out_channels:int,kernel_size:int,stride:int=1,padding:int=0,dilation:int=1,bias:bool=False):\n super().__init__(); self.depthwise=nn.Conv2d(in_channels,in_channels,kernel_size,stride=stride,padding=padding,dilation=dilation,groups=in_channels,bias=bias); self.pointwise=nn.Conv2d(in_channels,out_channels,1,bias=bias); self.stride=stride; self.padding=padding; self.dilation=dilation; self._empty=None\n def forward(self,x):\n if self._empty is None or self._empty.device!=x.device: self._empty=torch.empty(0,device=x.device,dtype=x.dtype)\n return _ext.depthwise_sep_forward(x,self.depthwise.weight,self.pointwise.weight,self.depthwise.bias if self.depthwise.bias is not None else self._empty,self.pointwise.bias if self.pointwise.bias is not None else self._empty,self.stride,self.padding,self.dilation)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 5 · 1 tool call(s) · 29.0s turn · 29.0s LLM · 8,233 chars (click to expand)
turn 529.0s turn · 29.0s LLM · 0.0s tools
reasoning
**Considering implementation details** I’m thinking about implementing pointwise bias with proper S, but it might not be strictly necessary. If I do use static correctness, maybe bias only applies if it's false. Adding add_bias_nchw with S is something I could consider for robustness. I need to think about how depthwise bias affects interconnections and pointwise results, plus optimizing performance between my implementation and PyTorch and ensuring everything works well with cublas.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\nvoid depthwise_kernel_launcher(const float*,const float*,const float*,float*,int,int,int,int,int,int,int,int,int,int,bool,cudaStream_t);\nvoid add_bias_launcher(float*,const float*,int,long,long,cudaStream_t);\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be CUDA\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type()==at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w, at::Tensor dw_b, at::Tensor pw_b, int64_t stride, int64_t padding, int64_t dilation){\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n int N=x.size(0), C=x.size(1), H=x.size(2), W=x.size(3), K=dw_w.size(2), OC=pw_w.size(0);\n int Ho=(H+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1;\n int Wo=(W+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1;\n auto inter=at::empty({N,C,Ho,Wo}, x.options());\n auto out=at::empty({N,OC,Ho,Wo}, x.options());\n cudaStream_t stream=at::cuda::getCurrentCUDAStream();\n const float* db=dw_b.numel()?dw_b.data_ptr<float>():nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(), N,C,H,W,K,(int)stride,(int)padding,(int)dilation,Ho,Wo,dw_b.numel()!=0,stream);\n cublasHandle_t handle=at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n const float alpha=1.0f, beta=0.0f; long long S=(long long)Ho*Wo;\n cublasStatus_t stat=cublasSgemmStridedBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C, &alpha,\n inter.data_ptr<float>(), (int)S, (long long)C*S,\n pw_w.data_ptr<float>(), C, 0LL,\n &beta,\n out.data_ptr<float>(), (int)S, (long long)OC*S,\n N);\n TORCH_CHECK(stat==CUBLAS_STATUS_SUCCESS, \"cublasSgemmStridedBatched failed\");\n if(pw_b.numel()) add_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, S, (long long)N*OC*S, stream);\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda_runtime.h>\n__global__ void dw3(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,bool has_bias){\n const int ITEMS=4; int plane=blockIdx.y; int n=plane/C; int c=plane-n*C; int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS; int S=H*W;\n const float* xb=x+((long)n*C+c)*S; const float* wb=w+(long)c*9; float* yb=y+((long)n*C+c)*S;\n float w00=wb[0],w01=wb[1],w02=wb[2],w10=wb[3],w11=wb[4],w12=wb[5],w20=wb[6],w21=wb[7],w22=wb[8];\n #pragma unroll\n for(int it=0;it<ITEMS;++it){int idx=base+it; if(idx<S){int h=idx/W; int col=idx-h*W; float acc=has_bias?b[c]:0.f;\n if(h>0){int r=idx-W; if(col>0) acc=fmaf(xb[r-1],w00,acc); acc=fmaf(xb[r],w01,acc); if(col<W-1) acc=fmaf(xb[r+1],w02,acc);} \n if(col>0) acc=fmaf(xb[idx-1],w10,acc); acc=fmaf(xb[idx],w11,acc); if(col<W-1) acc=fmaf(xb[idx+1],w12,acc);\n if(h<H-1){int r=idx+W; if(col>0) acc=fmaf(xb[r-1],w20,acc); acc=fmaf(xb[r],w21,acc); if(col<W-1) acc=fmaf(xb[r+1],w22,acc);} yb[idx]=acc;}}\n}\n__global__ void dwgen(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias){\n const int ITEMS=2; int plane=blockIdx.y; int n=plane/C; int c=plane-n*C; int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS; int S=Ho*Wo; const float* xb=x+((long)n*C+c)*H*W; const float* wb=w+(long)c*K*K; float* yb=y+((long)n*C+c)*S;\n #pragma unroll\n for(int it=0;it<ITEMS;++it){int idx=base+it; if(idx<S){int oh=idx/Wo, ow=idx-oh*Wo; float acc=has_bias?b[c]:0.f; int ih0=oh*stride-pad, iw0=ow*stride-pad; for(int kh=0;kh<K;++kh){int ih=ih0+kh*dil; if((unsigned)ih<(unsigned)H){for(int kw=0;kw<K;++kw){int iw=iw0+kw*dil; if((unsigned)iw<(unsigned)W) acc=fmaf(xb[ih*W+iw], wb[kh*K+kw], acc);}}} yb[idx]=acc;}}\n}\n__global__ void add_bias(float* __restrict__ y,const float* __restrict__ b,int OC,long S,long total){long idx=(long)blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int oc=(int)((idx/S)%OC); y[idx]+=b[oc];}}\nvoid depthwise_kernel_launcher(const float* x,const float* w,const float* b,float* y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias,cudaStream_t stream){dim3 block(256); int S=Ho*Wo; if(K==3&&stride==1&&pad==1&&dil==1&&Ho==H&&Wo==W){dim3 grid((S+block.x*4-1)/(block.x*4),N*C); dw3<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,has_bias);} else {dim3 grid((S+block.x*2-1)/(block.x*2),N*C); dwgen<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);}}\nvoid add_bias_launcher(float* y,const float* b,int OC,long S,long total,cudaStream_t stream){dim3 block(256); dim3 grid((total+255)/256); add_bias<<<grid,block,0,stream>>>(y,b,OC,S,total);}\n'''\n_ext=load_inline(name='dwsep_ext_finaltest', cpp_sources=cpp_sources, cuda_sources=cuda_sources, functions=['depthwise_sep_forward'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, in_channels:int, out_channels:int, kernel_size:int, stride:int=1, padding:int=0, dilation:int=1, bias:bool=False):\n super().__init__(); self.depthwise=nn.Conv2d(in_channels,in_channels,kernel_size,stride=stride,padding=padding,dilation=dilation,groups=in_channels,bias=bias); self.pointwise=nn.Conv2d(in_channels,out_channels,1,bias=bias); self.stride=stride; self.padding=padding; self.dilation=dilation; self._empty=None\n def forward(self,x:torch.Tensor)->torch.Tensor:\n if self._empty is None or self._empty.device!=x.device or self._empty.dtype!=x.dtype: self._empty=torch.empty(0,device=x.device,dtype=x.dtype)\n return _ext.depthwise_sep_forward(x,self.depthwise.weight,self.pointwise.weight,self.depthwise.bias if self.depthwise.bias is not None else self._empty,self.pointwise.bias if self.pointwise.bias is not None else self._empty,self.stride,self.padding,self.dilation)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 6 · 1 tool call(s) · 13.1s turn · 13.1s LLM · 7,540 chars (click to expand)
turn 613.1s turn · 13.1s LLM · 0.0s tools
call → static_check
callstatic_check { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\nvoid depthwise_kernel_launcher(const float*,const float*,const float*,float*,int,int,int,int,int,int,int,int,int,int,bool,cudaStream_t);\nvoid add_bias_launcher(float*,const float*,int,long,long,cudaStream_t);\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be CUDA\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type()==at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w, at::Tensor dw_b, at::Tensor pw_b, int64_t stride, int64_t padding, int64_t dilation){\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_w);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n int N=x.size(0), C=x.size(1), H=x.size(2), W=x.size(3), K=dw_w.size(2), OC=pw_w.size(0);\n int Ho=(H+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1;\n int Wo=(W+2*(int)padding-(int)dilation*(K-1)-1)/(int)stride+1;\n auto inter=at::empty({N,C,Ho,Wo}, x.options());\n auto out=at::empty({N,OC,Ho,Wo}, x.options());\n cudaStream_t stream=at::cuda::getCurrentCUDAStream();\n const float* db=dw_b.numel()?dw_b.data_ptr<float>():nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(), N,C,H,W,K,(int)stride,(int)padding,(int)dilation,Ho,Wo,dw_b.numel()!=0,stream);\n cublasHandle_t handle=at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n const float alpha=1.0f, beta=0.0f; long long S=(long long)Ho*Wo;\n cublasStatus_t stat=cublasSgemmStridedBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C, &alpha,\n inter.data_ptr<float>(), (int)S, (long long)C*S,\n pw_w.data_ptr<float>(), C, 0LL,\n &beta,\n out.data_ptr<float>(), (int)S, (long long)OC*S,\n N);\n TORCH_CHECK(stat==CUBLAS_STATUS_SUCCESS, \"cublasSgemmStridedBatched failed\");\n if(pw_b.numel()) add_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, S, (long long)N*OC*S, stream);\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda_runtime.h>\n__global__ void dw3(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,bool has_bias){\n const int ITEMS=4; int plane=blockIdx.y; int n=plane/C; int c=plane-n*C; int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS; int S=H*W;\n const float* xb=x+((long)n*C+c)*S; const float* wb=w+(long)c*9; float* yb=y+((long)n*C+c)*S;\n float w00=wb[0],w01=wb[1],w02=wb[2],w10=wb[3],w11=wb[4],w12=wb[5],w20=wb[6],w21=wb[7],w22=wb[8];\n #pragma unroll\n for(int it=0;it<ITEMS;++it){int idx=base+it; if(idx<S){int h=idx/W; int col=idx-h*W; float acc=has_bias?b[c]:0.f;\n if(h>0){int r=idx-W; if(col>0) acc=fmaf(xb[r-1],w00,acc); acc=fmaf(xb[r],w01,acc); if(col<W-1) acc=fmaf(xb[r+1],w02,acc);} \n if(col>0) acc=fmaf(xb[idx-1],w10,acc); acc=fmaf(xb[idx],w11,acc); if(col<W-1) acc=fmaf(xb[idx+1],w12,acc);\n if(h<H-1){int r=idx+W; if(col>0) acc=fmaf(xb[r-1],w20,acc); acc=fmaf(xb[r],w21,acc); if(col<W-1) acc=fmaf(xb[r+1],w22,acc);} yb[idx]=acc;}}\n}\n__global__ void dwgen(const float* __restrict__ x,const float* __restrict__ w,const float* __restrict__ b,float* __restrict__ y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias){\n const int ITEMS=2; int plane=blockIdx.y; int n=plane/C; int c=plane-n*C; int base=(blockIdx.x*blockDim.x+threadIdx.x)*ITEMS; int S=Ho*Wo; const float* xb=x+((long)n*C+c)*H*W; const float* wb=w+(long)c*K*K; float* yb=y+((long)n*C+c)*S;\n #pragma unroll\n for(int it=0;it<ITEMS;++it){int idx=base+it; if(idx<S){int oh=idx/Wo, ow=idx-oh*Wo; float acc=has_bias?b[c]:0.f; int ih0=oh*stride-pad, iw0=ow*stride-pad; for(int kh=0;kh<K;++kh){int ih=ih0+kh*dil; if((unsigned)ih<(unsigned)H){for(int kw=0;kw<K;++kw){int iw=iw0+kw*dil; if((unsigned)iw<(unsigned)W) acc=fmaf(xb[ih*W+iw], wb[kh*K+kw], acc);}}} yb[idx]=acc;}}\n}\n__global__ void add_bias(float* __restrict__ y,const float* __restrict__ b,int OC,long S,long total){long idx=(long)blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int oc=(int)((idx/S)%OC); y[idx]+=b[oc];}}\nvoid depthwise_kernel_launcher(const float* x,const float* w,const float* b,float* y,int N,int C,int H,int W,int K,int stride,int pad,int dil,int Ho,int Wo,bool has_bias,cudaStream_t stream){dim3 block(256); int S=Ho*Wo; if(K==3&&stride==1&&pad==1&&dil==1&&Ho==H&&Wo==W){dim3 grid((S+block.x*4-1)/(block.x*4),N*C); dw3<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,has_bias);} else {dim3 grid((S+block.x*2-1)/(block.x*2),N*C); dwgen<<<grid,block,0,stream>>>(x,w,b,y,N,C,H,W,K,stride,pad,dil,Ho,Wo,has_bias);}}\nvoid add_bias_launcher(float* y,const float* b,int OC,long S,long total,cudaStream_t stream){dim3 block(256); dim3 grid((total+255)/256); add_bias<<<grid,block,0,stream>>>(y,b,OC,S,total);}\n'''\n_ext=load_inline(name='dwsep_ext_static', cpp_sources=cpp_sources, cuda_sources=cuda_sources, functions=['depthwise_sep_forward'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, in_channels:int, out_channels:int, kernel_size:int, stride:int=1, padding:int=0, dilation:int=1, bias:bool=False):\n super().__init__(); self.depthwise=nn.Conv2d(in_channels,in_channels,kernel_size,stride=stride,padding=padding,dilation=dilation,groups=in_channels,bias=bias); self.pointwise=nn.Conv2d(in_channels,out_channels,1,bias=bias); self.stride=stride; self.padding=padding; self.dilation=dilation; self._empty=None\n def forward(self,x:torch.Tensor)->torch.Tensor:\n if self._empty is None or self._empty.device!=x.device or self._empty.dtype!=x.dtype: self._empty=torch.empty(0,device=x.device,dtype=x.dtype)\n return _ext.depthwise_sep_forward(x,self.depthwise.weight,self.pointwise.weight,self.depthwise.bias if self.depthwise.bias is not None else self._empty,self.pointwise.bias if self.pointwise.bias is not None else self._empty,self.stride,self.padding,self.dilation)\n" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 7 · FINAL · 1 tool call(s) · 24.4s turn · 24.4s LLM · 10,632 chars (click to expand)
turn 724.4s turn · 24.4s 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\ncpp_sources = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <ATen/cuda/CUDABlas.h>\n#include <cublas_v2.h>\n\nvoid depthwise_kernel_launcher(const float*, const float*, const float*, float*,\n int, int, int, int, int, int, int, int, int, int, bool, cudaStream_t);\nvoid add_bias_launcher(float*, const float*, int, long, long, cudaStream_t);\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be CUDA\")\n#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n\nat::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w,\n at::Tensor dw_b, at::Tensor pw_b,\n int64_t stride, int64_t padding, int64_t dilation) {\n CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);\n CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);\n\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int K = (int)dw_w.size(2);\n int OC = (int)pw_w.size(0);\n int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n int Wo = (W + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n\n auto inter = at::empty({N, C, Ho, Wo}, x.options());\n auto out = at::empty({N, OC, Ho, Wo}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n const float* db = dw_b.numel() ? dw_b.data_ptr<float>() : nullptr;\n depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(),\n N, C, H, W, K, (int)stride, (int)padding, (int)dilation, Ho, Wo,\n dw_b.numel() != 0, stream);\n\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cublasSetStream(handle, stream);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n\n const float alpha = 1.0f, beta = 0.0f;\n long long S = (long long)Ho * (long long)Wo;\n cublasStatus_t stat = cublasSgemmStridedBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N,\n (int)S, OC, C,\n &alpha,\n inter.data_ptr<float>(), (int)S, (long long)C * S,\n pw_w.data_ptr<float>(), C, 0LL,\n &beta,\n out.data_ptr<float>(), (int)S, (long long)OC * S,\n N);\n TORCH_CHECK(stat == CUBLAS_STATUS_SUCCESS, \"cublasSgemmStridedBatched failed\");\n\n if (pw_b.numel()) {\n add_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, (long)S,\n (long)((long long)N * OC * S), stream);\n }\n return out;\n}\n'''\n\ncuda_sources = r'''\n#include <cuda_runtime.h>\n\n__global__ void dw3_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, bool has_bias) {\n const int ITEMS = 4;\n int plane = blockIdx.y;\n int n = plane / C;\n int c = plane - n * C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = H * W;\n\n const float* xb = x + ((long)n * C + c) * S;\n const float* wb = w + (long)c * 9;\n float* yb = y + ((long)n * C + c) * S;\n\n float w00 = wb[0], w01 = wb[1], w02 = wb[2];\n float w10 = wb[3], w11 = wb[4], w12 = wb[5];\n float w20 = wb[6], w21 = wb[7], w22 = wb[8];\n\n #pragma unroll\n for (int it = 0; it < ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int h = idx / W;\n int col = idx - h * W;\n float acc = has_bias ? b[c] : 0.0f;\n\n if (h > 0) {\n int r = idx - W;\n if (col > 0) acc = fmaf(xb[r - 1], w00, acc);\n acc = fmaf(xb[r], w01, acc);\n if (col < W-1) acc = fmaf(xb[r + 1], w02, acc);\n }\n if (col > 0) acc = fmaf(xb[idx - 1], w10, acc);\n acc = fmaf(xb[idx], w11, acc);\n if (col < W-1) acc = fmaf(xb[idx + 1], w12, acc);\n if (h < H-1) {\n int r = idx + W;\n if (col > 0) acc = fmaf(xb[r - 1], w20, acc);\n acc = fmaf(xb[r], w21, acc);\n if (col < W-1) acc = fmaf(xb[r + 1], w22, acc);\n }\n yb[idx] = acc;\n }\n }\n}\n\n__global__ void dw_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int C, int H, int W, int K,\n int stride, int pad, int dil, int Ho, int Wo,\n bool has_bias) {\n const int ITEMS = 2;\n int plane = blockIdx.y;\n int n = plane / C;\n int c = plane - n * C;\n int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;\n int S = Ho * Wo;\n const float* xb = x + ((long)n * C + c) * H * W;\n const float* wb = w + (long)c * K * K;\n float* yb = y + ((long)n * C + c) * S;\n\n #pragma unroll\n for (int it = 0; it < ITEMS; ++it) {\n int idx = base + it;\n if (idx < S) {\n int oh = idx / Wo;\n int ow = idx - oh * Wo;\n int ih0 = oh * stride - pad;\n int iw0 = ow * stride - pad;\n float acc = has_bias ? b[c] : 0.0f;\n for (int kh = 0; kh < K; ++kh) {\n int ih = ih0 + kh * dil;\n if ((unsigned)ih < (unsigned)H) {\n for (int kw = 0; kw < K; ++kw) {\n int iw = iw0 + kw * dil;\n if ((unsigned)iw < (unsigned)W) {\n acc = fmaf(xb[ih * W + iw], wb[kh * K + kw], acc);\n }\n }\n }\n }\n yb[idx] = acc;\n }\n }\n}\n\n__global__ void add_bias_kernel(float* __restrict__ y, const float* __restrict__ b,\n int OC, long S, long total) {\n long idx = (long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n int oc = (int)((idx / S) % OC);\n y[idx] += b[oc];\n }\n}\n\nvoid depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,\n int N, int C, int H, int W, int K, int stride, int pad, int dil,\n int Ho, int Wo, bool has_bias, cudaStream_t stream) {\n dim3 block(256);\n int S = Ho * Wo;\n if (K == 3 && stride == 1 && pad == 1 && dil == 1 && Ho == H && Wo == W) {\n dim3 grid((S + (int)block.x * 4 - 1) / ((int)block.x * 4), N * C);\n dw3_kernel<<<grid, block, 0, stream>>>(x, w, b, y, N, C, H, W, has_bias);\n } else {\n dim3 grid((S + (int)block.x * 2 - 1) / ((int)block.x * 2), N * C);\n dw_generic_kernel<<<grid, block, 0, stream>>>(x, w, b, y, N, C, H, W, K,\n stride, pad, dil, Ho, Wo, has_bias);\n }\n}\n\nvoid add_bias_launcher(float* y, const float* b, int OC, long S, long total, cudaStream_t stream) {\n dim3 block(256);\n dim3 grid((total + 255) / 256);\n add_bias_kernel<<<grid, block, 0, stream>>>(y, b, OC, S, total);\n}\n'''\n\n_ext = load_inline(\n name='dwsep_h100_submit_v1',\n cpp_sources=cpp_sources,\n cuda_sources=cuda_sources,\n functions=['depthwise_sep_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: int,\n stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride,\n padding=padding, dilation=dilation, groups=in_channels, bias=bias)\n self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=bias)\n self.stride = stride\n self.padding = padding\n self.dilation = dilation\n self._empty = None\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self._empty is None or self._empty.device != x.device or self._empty.dtype != x.dtype:\n self._empty = torch.empty(0, device=x.device, dtype=x.dtype)\n db = self.depthwise.bias if self.depthwise.bias is not None else self._empty\n pb = self.pointwise.bias if self.pointwise.bias is not None else self._empty\n return _ext.depthwise_sep_forward(x, self.depthwise.weight, self.pointwise.weight,\n db, pb, self.stride, self.padding, self.dilation)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 2.84 μs Runtime stats: mean=2.84μs median=?μs std=0.13μs Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00 Memory: 4129.07 MB peak (ref: 4129.07 MB, ratio: 1.0x) Kernel launches: 2 (ref: 10, fusion ratio: 5.0) Energy: 322.56 mJ/run (ref: 319.04 mJ, ratio: 0.9891x) SOL score: 1.0
final submitted kernel (222 lines, 9,124 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

cpp_sources = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <ATen/cuda/CUDABlas.h>
#include <cublas_v2.h>

void depthwise_kernel_launcher(const float*, const float*, const float*, float*,
                               int, int, int, int, int, int, int, int, int, int, bool, cudaStream_t);
void add_bias_launcher(float*, const float*, int, long, long, cudaStream_t);

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

at::Tensor depthwise_sep_forward(at::Tensor x, at::Tensor dw_w, at::Tensor pw_w,
                                 at::Tensor dw_b, at::Tensor pw_b,
                                 int64_t stride, int64_t padding, int64_t dilation) {
    CHECK_CUDA(x); CHECK_CUDA(dw_w); CHECK_CUDA(pw_w); CHECK_CUDA(dw_b); CHECK_CUDA(pw_b);
    CHECK_FLOAT(x); CHECK_FLOAT(dw_w); CHECK_FLOAT(pw_w); CHECK_FLOAT(dw_b); CHECK_FLOAT(pw_b);
    CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(dw_w); CHECK_CONTIGUOUS(pw_w); CHECK_CONTIGUOUS(dw_b); CHECK_CONTIGUOUS(pw_b);

    int N = (int)x.size(0);
    int C = (int)x.size(1);
    int H = (int)x.size(2);
    int W = (int)x.size(3);
    int K = (int)dw_w.size(2);
    int OC = (int)pw_w.size(0);
    int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;
    int Wo = (W + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;

    auto inter = at::empty({N, C, Ho, Wo}, x.options());
    auto out = at::empty({N, OC, Ho, Wo}, x.options());
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();

    const float* db = dw_b.numel() ? dw_b.data_ptr<float>() : nullptr;
    depthwise_kernel_launcher(x.data_ptr<float>(), dw_w.data_ptr<float>(), db, inter.data_ptr<float>(),
                              N, C, H, W, K, (int)stride, (int)padding, (int)dilation, Ho, Wo,
                              dw_b.numel() != 0, stream);

    cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();
    cublasSetStream(handle, stream);
    cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);

    const float alpha = 1.0f, beta = 0.0f;
    long long S = (long long)Ho * (long long)Wo;
    cublasStatus_t stat = cublasSgemmStridedBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N,
        (int)S, OC, C,
        &alpha,
        inter.data_ptr<float>(), (int)S, (long long)C * S,
        pw_w.data_ptr<float>(), C, 0LL,
        &beta,
        out.data_ptr<float>(), (int)S, (long long)OC * S,
        N);
    TORCH_CHECK(stat == CUBLAS_STATUS_SUCCESS, "cublasSgemmStridedBatched failed");

    if (pw_b.numel()) {
        add_bias_launcher(out.data_ptr<float>(), pw_b.data_ptr<float>(), OC, (long)S,
                          (long)((long long)N * OC * S), stream);
    }
    return out;
}
'''

cuda_sources = r'''
#include <cuda_runtime.h>

__global__ void dw3_kernel(const float* __restrict__ x,
                           const float* __restrict__ w,
                           const float* __restrict__ b,
                           float* __restrict__ y,
                           int N, int C, int H, int W, bool has_bias) {
    const int ITEMS = 4;
    int plane = blockIdx.y;
    int n = plane / C;
    int c = plane - n * C;
    int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;
    int S = H * W;

    const float* xb = x + ((long)n * C + c) * S;
    const float* wb = w + (long)c * 9;
    float* yb = y + ((long)n * C + c) * S;

    float w00 = wb[0], w01 = wb[1], w02 = wb[2];
    float w10 = wb[3], w11 = wb[4], w12 = wb[5];
    float w20 = wb[6], w21 = wb[7], w22 = wb[8];

    #pragma unroll
    for (int it = 0; it < ITEMS; ++it) {
        int idx = base + it;
        if (idx < S) {
            int h = idx / W;
            int col = idx - h * W;
            float acc = has_bias ? b[c] : 0.0f;

            if (h > 0) {
                int r = idx - W;
                if (col > 0)   acc = fmaf(xb[r - 1], w00, acc);
                acc = fmaf(xb[r], w01, acc);
                if (col < W-1) acc = fmaf(xb[r + 1], w02, acc);
            }
            if (col > 0)       acc = fmaf(xb[idx - 1], w10, acc);
            acc = fmaf(xb[idx], w11, acc);
            if (col < W-1)     acc = fmaf(xb[idx + 1], w12, acc);
            if (h < H-1) {
                int r = idx + W;
                if (col > 0)   acc = fmaf(xb[r - 1], w20, acc);
                acc = fmaf(xb[r], w21, acc);
                if (col < W-1) acc = fmaf(xb[r + 1], w22, acc);
            }
            yb[idx] = acc;
        }
    }
}

__global__ void dw_generic_kernel(const float* __restrict__ x,
                                  const float* __restrict__ w,
                                  const float* __restrict__ b,
                                  float* __restrict__ y,
                                  int N, int C, int H, int W, int K,
                                  int stride, int pad, int dil, int Ho, int Wo,
                                  bool has_bias) {
    const int ITEMS = 2;
    int plane = blockIdx.y;
    int n = plane / C;
    int c = plane - n * C;
    int base = (blockIdx.x * blockDim.x + threadIdx.x) * ITEMS;
    int S = Ho * Wo;
    const float* xb = x + ((long)n * C + c) * H * W;
    const float* wb = w + (long)c * K * K;
    float* yb = y + ((long)n * C + c) * S;

    #pragma unroll
    for (int it = 0; it < ITEMS; ++it) {
        int idx = base + it;
        if (idx < S) {
            int oh = idx / Wo;
            int ow = idx - oh * Wo;
            int ih0 = oh * stride - pad;
            int iw0 = ow * stride - pad;
            float acc = has_bias ? b[c] : 0.0f;
            for (int kh = 0; kh < K; ++kh) {
                int ih = ih0 + kh * dil;
                if ((unsigned)ih < (unsigned)H) {
                    for (int kw = 0; kw < K; ++kw) {
                        int iw = iw0 + kw * dil;
                        if ((unsigned)iw < (unsigned)W) {
                            acc = fmaf(xb[ih * W + iw], wb[kh * K + kw], acc);
                        }
                    }
                }
            }
            yb[idx] = acc;
        }
    }
}

__global__ void add_bias_kernel(float* __restrict__ y, const float* __restrict__ b,
                                int OC, long S, long total) {
    long idx = (long)blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < total) {
        int oc = (int)((idx / S) % OC);
        y[idx] += b[oc];
    }
}

void depthwise_kernel_launcher(const float* x, const float* w, const float* b, float* y,
                               int N, int C, int H, int W, int K, int stride, int pad, int dil,
                               int Ho, int Wo, bool has_bias, cudaStream_t stream) {
    dim3 block(256);
    int S = Ho * Wo;
    if (K == 3 && stride == 1 && pad == 1 && dil == 1 && Ho == H && Wo == W) {
        dim3 grid((S + (int)block.x * 4 - 1) / ((int)block.x * 4), N * C);
        dw3_kernel<<<grid, block, 0, stream>>>(x, w, b, y, N, C, H, W, has_bias);
    } else {
        dim3 grid((S + (int)block.x * 2 - 1) / ((int)block.x * 2), N * C);
        dw_generic_kernel<<<grid, block, 0, stream>>>(x, w, b, y, N, C, H, W, K,
                                                      stride, pad, dil, Ho, Wo, has_bias);
    }
}

void add_bias_launcher(float* y, const float* b, int OC, long S, long total, cudaStream_t stream) {
    dim3 block(256);
    dim3 grid((total + 255) / 256);
    add_bias_kernel<<<grid, block, 0, stream>>>(y, b, OC, S, total);
}
'''

_ext = load_inline(
    name='dwsep_h100_submit_v1',
    cpp_sources=cpp_sources,
    cuda_sources=cuda_sources,
    functions=['depthwise_sep_forward'],
    extra_cflags=['-O3'],
    extra_cuda_cflags=['-O3'],
    extra_ldflags=['-lcublas'],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, in_channels: int, out_channels: int, kernel_size: int,
                 stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):
        super(ModelNew, self).__init__()
        self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride,
                                   padding=padding, dilation=dilation, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=bias)
        self.stride = stride
        self.padding = padding
        self.dilation = dilation
        self._empty = None

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if self._empty is None or self._empty.device != x.device or self._empty.dtype != x.dtype:
            self._empty = torch.empty(0, device=x.device, dtype=x.dtype)
        db = self.depthwise.bias if self.depthwise.bias is not None else self._empty
        pb = self.pointwise.bias if self.pointwise.bias is not None else self._empty
        return _ext.depthwise_sep_forward(x, self.depthwise.weight, self.pointwise.weight,
                                          db, pb, self.stride, self.padding, self.dilation)