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 conv2d_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t pad_h, int64_t pad_w,\n int64_t dil_h, int64_t dil_w);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Specialized kernel for the benchmark case:\n// N=8, IC=32, OC=64, KH=5, KW=9, stride=1, padding=(2,4), dilation=(2,3).\n// One block computes 32 spatial positions and all 64 output channels. The input\n// patch values are loaded once into shared memory and reused by all channel warps.\ntemplate <bool HAS_BIAS>\n__global__ __launch_bounds__(256, 2)\nvoid conv5x9_dilated_spec_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int H, int W, int Hout, int Wout, int M) {\n constexpr int BM = 32;\n constexpr int BN = 64;\n constexpr int BK = 32;\n constexpr int KTOTAL = 32 * 5 * 9; // 1440, divisible by BK\n __shared__ float As[BK * BM]; // [k][m]\n __shared__ float Bs[BK * BN]; // [k][oc]\n\n const int tx = threadIdx.x; // 0..31: spatial lane\n const int ty = threadIdx.y; // 0..7: output-channel warp group\n const int tid = ty * 32 + tx;\n const int m = blockIdx.x * BM + tx;\n\n float acc0 = 0.f, acc1 = 0.f, acc2 = 0.f, acc3 = 0.f;\n float acc4 = 0.f, acc5 = 0.f, acc6 = 0.f, acc7 = 0.f;\n\n int n = 0, oh = 0, ow = 0;\n if (m < M) {\n const int plane = Hout * Wout;\n n = m / plane;\n const int r = m - n * plane;\n oh = r / Wout;\n ow = r - oh * Wout;\n }\n\n #pragma unroll\n for (int kb = 0; kb < KTOTAL; kb += BK) {\n // load A tile: 32 spatial positions x 32 reduction entries\n #pragma unroll\n for (int idx = tid; idx < BM * BK; idx += 256) {\n const int kk_in = idx >> 5; // / BM\n const int mm = idx & 31; // % BM\n const int gm = blockIdx.x * BM + mm;\n float v = 0.f;\n if (gm < M) {\n const int plane = Hout * Wout;\n const int nn = gm / plane;\n const int rr = gm - nn * plane;\n const int ooh = rr / Wout;\n const int oow = rr - ooh * Wout;\n const int kglob = kb + kk_in;\n const int ic = kglob / 45;\n const int rem = kglob - ic * 45;\n const int kh = rem / 9;\n const int kw = rem - kh * 9;\n const int ih = ooh - 2 + kh * 2;\n const int iw = oow - 4 + kw * 3;\n if ((unsigned)ih < (unsigned)H && (unsigned)iw < (unsigned)W) {\n v = x[((nn * 32 + ic) * H + ih) * W + iw];\n }\n }\n As[kk_in * BM + mm] = v;\n }\n\n // load B tile: 32 reduction entries x 64 output channels\n #pragma unroll\n for (int idx = tid; idx < BK * BN; idx += 256) {\n const int kk_in = idx >> 6; // / 64\n const int oc = idx & 63; // % 64\n Bs[kk_in * BN + oc] = w[oc * KTOTAL + (kb + kk_in)];\n }\n __syncthreads();\n\n #pragma unroll\n for (int kk = 0; kk < BK; ++kk) {\n const float a = As[kk * BM + tx];\n acc0 = fmaf(a, Bs[kk * BN + (ty + 0)], acc0);\n acc1 = fmaf(a, Bs[kk * BN + (ty + 8)], acc1);\n acc2 = fmaf(a, Bs[kk * BN + (ty + 16)], acc2);\n acc3 = fmaf(a, Bs[kk * BN + (ty + 24)], acc3);\n acc4 = fmaf(a, Bs[kk * BN + (ty + 32)], acc4);\n acc5 = fmaf(a, Bs[kk * BN + (ty + 40)], acc5);\n acc6 = fmaf(a, Bs[kk * BN + (ty + 48)], acc6);\n acc7 = fmaf(a, Bs[kk * BN + (ty + 56)], acc7);\n }\n __syncthreads();\n }\n\n if (m < M) {\n const int plane = Hout * Wout;\n const int base0 = (n * 64 * plane) + oh * Wout + ow;\n const int oc0 = ty + 0;\n if constexpr (HAS_BIAS) {\n acc0 += bias[oc0 + 0]; acc1 += bias[oc0 + 8];\n acc2 += bias[oc0 + 16]; acc3 += bias[oc0 + 24];\n acc4 += bias[oc0 + 32]; acc5 += bias[oc0 + 40];\n acc6 += bias[oc0 + 48]; acc7 += bias[oc0 + 56];\n }\n out[base0 + (oc0 + 0) * plane] = acc0;\n out[base0 + (oc0 + 8) * plane] = acc1;\n out[base0 + (oc0 + 16) * plane] = acc2;\n out[base0 + (oc0 + 24) * plane] = acc3;\n out[base0 + (oc0 + 32) * plane] = acc4;\n out[base0 + (oc0 + 40) * plane] = acc5;\n out[base0 + (oc0 + 48) * plane] = acc6;\n out[base0 + (oc0 + 56) * plane] = acc7;\n }\n}\n\n// A simple generic correctness kernel for non-benchmark constructor values.\n__global__ void conv2d_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int N, int C, int H, int W, int OC,\n int KH, int KW, int Hout, int Wout,\n int stride, int pad_h, int pad_w, int dil_h, int dil_w,\n int has_bias, long total) {\n long idx = (long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int ow = idx % Wout;\n long t = idx / Wout;\n int oh = t % Hout;\n t /= Hout;\n int oc = t % OC;\n int n = t / OC;\n float sum = has_bias ? bias[oc] : 0.f;\n for (int c = 0; c < C; ++c) {\n for (int kh = 0; kh < KH; ++kh) {\n int ih = oh * stride - pad_h + kh * dil_h;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < KW; ++kw) {\n int iw = ow * stride - pad_w + kw * dil_w;\n if ((unsigned)iw < (unsigned)W) {\n sum = fmaf(x[((n*C + c)*H + ih)*W + iw],\n w[((oc*C + c)*KH + kh)*KW + kw], sum);\n }\n }\n }\n }\n out[idx] = sum;\n}\n\ntorch::Tensor conv2d_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t pad_h, int64_t pad_w,\n int64_t dil_h, int64_t dil_w) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int OC = (int)weight.size(0);\n const int KH = (int)weight.size(2);\n const int KW = (int)weight.size(3);\n const int Hout = (H + 2*(int)pad_h - (int)dil_h * (KH - 1) - 1) / (int)stride + 1;\n const int Wout = (W + 2*(int)pad_w - (int)dil_w * (KW - 1) - 1) / (int)stride + 1;\n auto out = torch::empty({N, OC, Hout, Wout}, x.options());\n const bool has_bias = bias.numel() != 0;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (x.scalar_type() == at::kFloat && C == 32 && OC == 64 && KH == 5 && KW == 9 &&\n stride == 1 && pad_h == 2 && pad_w == 4 && dil_h == 2 && dil_w == 3) {\n const int M = N * Hout * Wout;\n dim3 block(32, 8, 1);\n dim3 grid((M + 31) / 32, 1, 1);\n if (has_bias) {\n conv5x9_dilated_spec_kernel<true><<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n out.data_ptr<float>(), H, W, Hout, Wout, M);\n } else {\n conv5x9_dilated_spec_kernel<false><<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), nullptr,\n out.data_ptr<float>(), H, W, Hout, Wout, M);\n }\n } else {\n long total = (long)N * OC * Hout * Wout;\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n conv2d_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), has_bias ? bias.data_ptr<float>() : nullptr,\n out.data_ptr<float>(), N, C, H, W, OC, KH, KW, Hout, Wout,\n (int)stride, (int)pad_h, (int)pad_w, (int)dil_h, (int)dil_w, has_bias ? 1 : 0, total);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return out;\n}\n'''\n\n_ext = load_inline(\n name='conv2d_5x9_dilated_custom_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['conv2d_forward_cuda'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: tuple,\n stride: int = 1, padding: tuple = (0, 0), dilation: tuple = (1, 1),\n bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size, stride=stride,\n padding=padding, dilation=dilation, bias=bias)\n self.stride = int(stride)\n self.padding = (int(padding[0]), int(padding[1]))\n self.dilation = (int(dilation[0]), int(dilation[1]))\n self.register_buffer('_empty_bias', torch.empty(0), persistent=False)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n b = self.conv2d.bias if self.conv2d.bias is not None else self._empty_bias\n return _ext.conv2d_forward_cuda(x, self.conv2d.weight, b,\n self.stride, self.padding[0], self.padding[1],\n self.dilation[0], self.dilation[1])\n"
}