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 depthwise_conv_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t stride, int64_t padding);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#define CHECK_CUDA(x) TORCH_CHECK((x).is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK((x).is_contiguous(), #x \" must be contiguous\")\n\nstatic constexpr int TILE_H = 8;\n\n__global__ void dw3x3_s1p0_tiled_kernel(\n 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 Hout, int Wout, int has_bias)\n{\n extern __shared__ float sh[];\n float* sw = sh + (TILE_H + 2) * W;\n\n const int tx = threadIdx.x; // 0..63\n const int ty = threadIdx.y; // 0..7\n const int z = blockIdx.z;\n const int c = z % C;\n const int n = z / C;\n const int h0 = blockIdx.y * TILE_H;\n const int tile_rows = min(TILE_H, Hout - h0);\n const int load_rows = tile_rows + 2;\n\n const float* xbase = x + ((n * C + c) * H + h0) * W;\n const float* wbase = w + c * 9;\n\n const int tid = ty * blockDim.x + tx;\n if (tid < 9) sw[tid] = wbase[tid];\n\n // Load the input tile: (tile_rows+2) x W. This avoids the 9x rereads\n // that a direct depthwise implementation would perform.\n for (int rr = ty; rr < load_rows; rr += blockDim.y) {\n const float* src = xbase + rr * W;\n float* dst = sh + rr * W;\n for (int col = tx; col < W; col += blockDim.x) {\n dst[col] = src[col];\n }\n }\n __syncthreads();\n\n if (ty < tile_rows) {\n const float w0 = sw[0], w1 = sw[1], w2 = sw[2];\n const float w3 = sw[3], w4 = sw[4], w5 = sw[5];\n const float w6 = sw[6], w7 = sw[7], w8 = sw[8];\n const float bv = has_bias ? b[c] : 0.0f;\n float* yrow = y + ((n * C + c) * Hout + (h0 + ty)) * Wout;\n\n for (int ow = tx; ow < Wout; ow += blockDim.x) {\n const float* p = sh + ty * W + ow;\n float acc = bv;\n acc = fmaf(p[0], w0, acc);\n acc = fmaf(p[1], w1, acc);\n acc = fmaf(p[2], w2, acc);\n acc = fmaf(p[W], w3, acc);\n acc = fmaf(p[W + 1], w4, acc);\n acc = fmaf(p[W + 2], w5, acc);\n acc = fmaf(p[2 * W], w6, acc);\n acc = fmaf(p[2 * W+1], w7, acc);\n acc = fmaf(p[2 * W+2], w8, acc);\n yrow[ow] = acc;\n }\n }\n}\n\n__global__ void depthwise_generic_kernel(\n const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n long long total, int C, int H, int W, int K, int stride, int pad, int Hout, int Wout, int has_bias)\n{\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n\n int ow = (int)(idx % Wout);\n long long t = idx / Wout;\n int oh = (int)(t % Hout);\n t /= Hout;\n int c = (int)(t % C);\n int n = (int)(t / C);\n\n const float* xnc = x + ((n * C + c) * H) * W;\n const float* wc = w + c * K * K;\n float acc = has_bias ? b[c] : 0.0f;\n\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;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < K; ++kw) {\n int iw = iw0 + kw;\n if ((unsigned)iw < (unsigned)W) {\n acc = fmaf(xnc[ih * W + iw], wc[kh * K + kw], acc);\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor depthwise_conv_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t stride64, int64_t padding64) {\n CHECK_CUDA(x);\n CHECK_CUDA(weight);\n CHECK_CONTIGUOUS(x);\n CHECK_CONTIGUOUS(weight);\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n TORCH_CHECK(weight.scalar_type() == at::kFloat, \"only float32 weights are supported\");\n\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 K = (int)weight.size(2);\n const int stride = (int)stride64;\n const int pad = (int)padding64;\n const int Hout = (H + 2 * pad - K) / stride + 1;\n const int Wout = (W + 2 * pad - K) / stride + 1;\n\n auto y = torch::empty({N, C, Hout, Wout}, x.options());\n const int has_bias = (bias.defined() && bias.numel() > 0) ? 1 : 0;\n const float* bptr = has_bias ? bias.data_ptr<float>() : nullptr;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (K == 3 && stride == 1 && pad == 0 && W > 0 && Wout > 0) {\n dim3 block(64, TILE_H, 1);\n dim3 grid(1, (Hout + TILE_H - 1) / TILE_H, N * C);\n size_t smem = ((TILE_H + 2) * (size_t)W + 9) * sizeof(float);\n dw3x3_s1p0_tiled_kernel<<<grid, block, smem, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bptr, y.data_ptr<float>(),\n N, C, H, W, Hout, Wout, has_bias);\n } else {\n long long total = (long long)N * C * Hout * Wout;\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n depthwise_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bptr, y.data_ptr<float>(),\n total, C, H, W, K, stride, pad, Hout, Wout, has_bias);\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"depthwise_conv2d_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"depthwise_conv_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\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, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv2d = nn.Conv2d(in_channels, in_channels, kernel_size, stride=stride, padding=padding, groups=in_channels, bias=bias)\n self.stride = stride\n self.padding = padding\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n bias = self.conv2d.bias\n if bias is None:\n bias = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.depthwise_conv_forward(x, self.conv2d.weight, bias, int(self.stride), int(self.padding))\n"
}