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 vertical_conv_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride,\n int64_t padding,\n int64_t dilation);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void dw_vertical_k3_s1p0_vec4_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,\n int Hout, int Wout,\n bool has_bias) {\n int ow = (blockIdx.x * blockDim.x + threadIdx.x) * 4;\n int oh0 = blockIdx.y * 4;\n int nc = blockIdx.z;\n if (ow >= Wout || oh0 >= Hout) return;\n\n int c = nc % C;\n float w0 = w[c * 3 + 0];\n float w1 = w[c * 3 + 1];\n float w2 = w[c * 3 + 2];\n float bv = has_bias ? bias[c] : 0.0f;\n\n const float* in = x + ((int64_t)nc * H) * W;\n float* o = out + ((int64_t)nc * Hout) * Wout;\n\n // Fast path for the overwhelmingly common full 4-column by 4-row tile.\n if (ow + 3 < Wout && oh0 + 3 < Hout) {\n const float4 r0 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 0) * W + ow);\n const float4 r1 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 1) * W + ow);\n const float4 r2 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 2) * W + ow);\n const float4 r3 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 3) * W + ow);\n const float4 r4 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 4) * W + ow);\n const float4 r5 = *reinterpret_cast<const float4*>(in + (int64_t)(oh0 + 5) * W + ow);\n\n float4 y0, y1, y2, y3;\n y0.x = r0.x*w0 + r1.x*w1 + r2.x*w2 + bv;\n y0.y = r0.y*w0 + r1.y*w1 + r2.y*w2 + bv;\n y0.z = r0.z*w0 + r1.z*w1 + r2.z*w2 + bv;\n y0.w = r0.w*w0 + r1.w*w1 + r2.w*w2 + bv;\n\n y1.x = r1.x*w0 + r2.x*w1 + r3.x*w2 + bv;\n y1.y = r1.y*w0 + r2.y*w1 + r3.y*w2 + bv;\n y1.z = r1.z*w0 + r2.z*w1 + r3.z*w2 + bv;\n y1.w = r1.w*w0 + r2.w*w1 + r3.w*w2 + bv;\n\n y2.x = r2.x*w0 + r3.x*w1 + r4.x*w2 + bv;\n y2.y = r2.y*w0 + r3.y*w1 + r4.y*w2 + bv;\n y2.z = r2.z*w0 + r3.z*w1 + r4.z*w2 + bv;\n y2.w = r2.w*w0 + r3.w*w1 + r4.w*w2 + bv;\n\n y3.x = r3.x*w0 + r4.x*w1 + r5.x*w2 + bv;\n y3.y = r3.y*w0 + r4.y*w1 + r5.y*w2 + bv;\n y3.z = r3.z*w0 + r4.z*w1 + r5.z*w2 + bv;\n y3.w = r3.w*w0 + r4.w*w1 + r5.w*w2 + bv;\n\n *reinterpret_cast<float4*>(o + (int64_t)(oh0 + 0) * Wout + ow) = y0;\n *reinterpret_cast<float4*>(o + (int64_t)(oh0 + 1) * Wout + ow) = y1;\n *reinterpret_cast<float4*>(o + (int64_t)(oh0 + 2) * Wout + ow) = y2;\n *reinterpret_cast<float4*>(o + (int64_t)(oh0 + 3) * Wout + ow) = y3;\n } else {\n // Boundary tiles (only the last row tile for the benchmark shape).\n #pragma unroll\n for (int rr = 0; rr < 4; ++rr) {\n int oh = oh0 + rr;\n if (oh < Hout) {\n #pragma unroll\n for (int jj = 0; jj < 4; ++jj) {\n int col = ow + jj;\n if (col < Wout) {\n float v = in[(int64_t)(oh + 0) * W + col] * w0\n + in[(int64_t)(oh + 1) * W + col] * w1\n + in[(int64_t)(oh + 2) * W + col] * w2\n + bv;\n o[(int64_t)oh * Wout + col] = v;\n }\n }\n }\n }\n }\n}\n\n__global__ void dw_vertical_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,\n int Hout, int Wout, int K,\n int stride, int padding, int dilation,\n bool has_bias,\n int64_t total) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n\n int ow = idx % Wout;\n int64_t t = idx / Wout;\n int oh = t % Hout;\n t /= Hout;\n int c = t % C;\n int n = t / C;\n\n int ih0 = oh * stride - padding;\n int iw = ow * stride - padding;\n float sum = 0.0f;\n if ((unsigned)iw < (unsigned)W) {\n for (int k = 0; k < K; ++k) {\n int ih = ih0 + k * dilation;\n if ((unsigned)ih < (unsigned)H) {\n sum += x[((int64_t)n * C + c) * H * W + (int64_t)ih * W + iw] * w[c * K + k];\n }\n }\n }\n if (has_bias) sum += bias[c];\n out[idx] = sum;\n}\n\ntorch::Tensor vertical_conv_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride64,\n int64_t padding64,\n int64_t dilation64) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(weight.is_cuda(), \"weight must be CUDA\");\n TORCH_CHECK(x.scalar_type() == torch::kFloat32, \"only float32 is supported\");\n TORCH_CHECK(weight.scalar_type() == torch::kFloat32, \"only float32 weights are supported\");\n c10::cuda::CUDAGuard device_guard(x.device());\n\n auto xc = x.contiguous();\n auto wc = weight.contiguous();\n auto bc = bias.numel() ? bias.contiguous() : bias;\n\n int N = (int)xc.size(0);\n int C = (int)xc.size(1);\n int H = (int)xc.size(2);\n int W = (int)xc.size(3);\n int K = (int)wc.size(2);\n int stride = (int)stride64;\n int padding = (int)padding64;\n int dilation = (int)dilation64;\n\n int Hout = (H + 2 * padding - dilation * (K - 1) - 1) / stride + 1;\n int Wout = (W + 2 * padding - 1) / stride + 1;\n auto out = torch::empty({N, C, Hout, Wout}, xc.options());\n\n bool has_bias = (bc.numel() > 0);\n const float* bptr = has_bias ? bc.data_ptr<float>() : nullptr;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (K == 3 && stride == 1 && padding == 0 && dilation == 1 && Wout == W) {\n dim3 block(128);\n dim3 grid((Wout + (int)block.x * 4 - 1) / ((int)block.x * 4),\n (Hout + 3) / 4,\n N * C);\n dw_vertical_k3_s1p0_vec4_kernel<<<grid, block, 0, stream>>>(\n xc.data_ptr<float>(), wc.data_ptr<float>(), bptr, out.data_ptr<float>(),\n N, C, H, W, Hout, Wout, has_bias);\n } else {\n int64_t total = (int64_t)N * C * Hout * Wout;\n dim3 block(256);\n dim3 grid((unsigned int)((total + block.x - 1) / block.x));\n dw_vertical_generic_kernel<<<grid, block, 0, stream>>>(\n xc.data_ptr<float>(), wc.data_ptr<float>(), bptr, out.data_ptr<float>(),\n N, C, H, W, Hout, Wout, K, stride, padding, dilation, has_bias, total);\n }\n return out;\n}\n'''\n\n_ext = load_inline(\n name=\"dw_vertical_conv_inline_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"vertical_conv_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: int, kernel_size: int, stride: int = 1, padding: int = 0, dilation: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv2d = nn.Conv2d(in_channels, in_channels, kernel_size=(kernel_size, 1), stride=stride, padding=padding, dilation=dilation, groups=in_channels, bias=bias)\n self._stride_i = stride if isinstance(stride, int) else stride[0]\n self._padding_i = padding if isinstance(padding, int) else padding[0]\n self._dilation_i = dilation if isinstance(dilation, int) else dilation[0]\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\n if b is None:\n b = self._empty_bias\n if b.device != x.device or b.dtype != x.dtype:\n b = x.new_empty((0,))\n return _ext.vertical_conv_forward(x, self.conv2d.weight, b, self._stride_i, self._padding_i, self._dilation_i)\n"
}