call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor depthwise_conv2d_vertical(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t dilation, bool has_bias);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void dw_vert3_4rows_vec4_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int C, int H, int W, int Ho,\n int vecs_per_row, bool has_bias) {\n int w4 = blockIdx.x * blockDim.x + threadIdx.x;\n if (w4 >= vecs_per_row) return;\n int g = blockIdx.y;\n int oh = g << 2;\n int nc = blockIdx.z;\n int c = nc % C;\n int n = nc / C;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x);\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y);\n long long xbase = ((long long)nc * H + oh) * vecs_per_row + w4;\n long long ybase = ((long long)nc * Ho + oh) * vecs_per_row + w4;\n float k0 = w[(long long)c * 3 + 0];\n float k1 = w[(long long)c * 3 + 1];\n float k2 = w[(long long)c * 3 + 2];\n float bv = has_bias ? b[c] : 0.0f;\n\n if (oh + 3 < Ho) {\n float4 a0 = x4[xbase];\n float4 a1 = x4[xbase + vecs_per_row];\n float4 a2 = x4[xbase + 2LL*vecs_per_row];\n float4 a3 = x4[xbase + 3LL*vecs_per_row];\n float4 a4 = x4[xbase + 4LL*vecs_per_row];\n float4 a5 = x4[xbase + 5LL*vecs_per_row];\n float4 o0, o1, o2, o3;\n o0.x = a0.x*k0 + a1.x*k1 + a2.x*k2 + bv;\n o0.y = a0.y*k0 + a1.y*k1 + a2.y*k2 + bv;\n o0.z = a0.z*k0 + a1.z*k1 + a2.z*k2 + bv;\n o0.w = a0.w*k0 + a1.w*k1 + a2.w*k2 + bv;\n o1.x = a1.x*k0 + a2.x*k1 + a3.x*k2 + bv;\n o1.y = a1.y*k0 + a2.y*k1 + a3.y*k2 + bv;\n o1.z = a1.z*k0 + a2.z*k1 + a3.z*k2 + bv;\n o1.w = a1.w*k0 + a2.w*k1 + a3.w*k2 + bv;\n o2.x = a2.x*k0 + a3.x*k1 + a4.x*k2 + bv;\n o2.y = a2.y*k0 + a3.y*k1 + a4.y*k2 + bv;\n o2.z = a2.z*k0 + a3.z*k1 + a4.z*k2 + bv;\n o2.w = a2.w*k0 + a3.w*k1 + a4.w*k2 + bv;\n o3.x = a3.x*k0 + a4.x*k1 + a5.x*k2 + bv;\n o3.y = a3.y*k0 + a4.y*k1 + a5.y*k2 + bv;\n o3.z = a3.z*k0 + a4.z*k1 + a5.z*k2 + bv;\n o3.w = a3.w*k0 + a4.w*k1 + a5.w*k2 + bv;\n y4[ybase] = o0;\n y4[ybase + vecs_per_row] = o1;\n y4[ybase + 2LL*vecs_per_row] = o2;\n y4[ybase + 3LL*vecs_per_row] = o3;\n } else {\n // only the final partial group (for Ho not divisible by 4)\n for (int r = 0; r < 4 && oh + r < Ho; ++r) {\n float4 a0 = x4[xbase + (long long)r*vecs_per_row];\n float4 a1 = x4[xbase + (long long)(r+1)*vecs_per_row];\n float4 a2 = x4[xbase + (long long)(r+2)*vecs_per_row];\n float4 o;\n o.x = a0.x*k0 + a1.x*k1 + a2.x*k2 + bv;\n o.y = a0.y*k0 + a1.y*k1 + a2.y*k2 + bv;\n o.z = a0.z*k0 + a1.z*k1 + a2.z*k2 + bv;\n o.w = a0.w*k0 + a1.w*k1 + a2.w*k2 + bv;\n y4[ybase + (long long)r*vecs_per_row] = o;\n }\n }\n}\n\n__global__ void dw_vertical_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 Ho, int Wo,\n int K, int stride, int padding, int dilation,\n bool has_bias) {\n long long total = (long long)N * C * Ho * Wo;\n for (long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n idx < total;\n idx += (long long)blockDim.x * gridDim.x) {\n int ow = idx % Wo;\n long long t = idx / Wo;\n int oh = t % Ho;\n t /= Ho;\n int c = t % C;\n int n = t / C;\n float acc = has_bias ? b[c] : 0.0f;\n int iw = ow * stride - padding;\n if ((unsigned)iw < (unsigned)W) {\n for (int kh = 0; kh < K; ++kh) {\n int ih = oh * stride - padding + kh * dilation;\n if ((unsigned)ih < (unsigned)H) {\n acc += x[((long long)n*C + c)*H*W + (long long)ih*W + iw] * w[(long long)c*K + kh];\n }\n }\n }\n y[idx] = acc;\n }\n}\n\ntorch::Tensor depthwise_conv2d_vertical(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t dilation, bool has_bias) {\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 supported\");\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)weight.size(2);\n int Ho = (H + 2*(int)padding - (int)dilation*(K-1) - 1) / (int)stride + 1;\n int Wo = (W + 2*(int)padding - 1) / (int)stride + 1;\n auto y = torch::empty({N, C, Ho, Wo}, x.options());\n if (N == 0 || C == 0 || Ho <= 0 || Wo <= 0) return y;\n const float* bp = has_bias ? bias.data_ptr<float>() : nullptr;\n if (K == 3 && stride == 1 && padding == 0 && dilation == 1 && Wo == W && (W % 4 == 0)) {\n int vecs = W >> 2;\n dim3 block(128);\n dim3 grid((vecs + block.x - 1) / block.x, (Ho + 3) >> 2, N * C);\n dw_vert3_4rows_vec4_kernel<<<grid, block>>>(x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), C, H, W, Ho, vecs, has_bias);\n } else {\n const int threads = 256;\n long long total = (long long)N * C * Ho * Wo;\n int blocks = (int)min((long long)131072, (total + threads - 1) / threads);\n dw_vertical_generic_kernel<<<blocks, threads>>>(x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), N, C, H, W, Ho, Wo, K, (int)stride, (int)padding, (int)dilation, has_bias);\n }\n return y;\n}\n'''\n\n_ext = load_inline(name='dw_vertical_ext_v3', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['depthwise_conv2d_vertical'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\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 = stride\n self.padding = padding\n self.dilation = dilation\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n b = self.conv2d.bias\n if b is None:\n b = self.conv2d.weight.new_empty((0,))\n has_b = False\n else:\n has_b = True\n return _ext.depthwise_conv2d_vertical(x, self.conv2d.weight, b, self.stride, self.padding, self.dilation, has_b)\n"
}