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(torch::Tensor x, torch::Tensor w, torch::Tensor b,\n int64_t stride, int64_t padding, int64_t dilation,\n int64_t groups, bool has_bias);\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\n__global__ void conv3x3_c16_oc8_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int H, int W, int O,\n int OH, int OW, int has_bias) {\n constexpr int C = 16;\n constexpr int OCPT = 8;\n constexpr int ITEMS = 2;\n int oc_base = blockIdx.y * OCPT;\n int tid = threadIdx.x;\n int P = N * OH * OW;\n int p0 = (blockIdx.x * (blockDim.x * ITEMS)) + tid;\n int p1 = p0 + blockDim.x;\n int64_t S = (int64_t)OH * OW;\n int64_t HW = (int64_t)H * W;\n\n if (p1 < P) {\n int n0 = p0 / (int)S;\n int r0 = p0 - n0 * (int)S;\n int oh0 = r0 / OW;\n int ow0 = r0 - oh0 * OW;\n int n1 = p1 / (int)S;\n int r1 = p1 - n1 * (int)S;\n int oh1 = r1 / OW;\n int ow1 = r1 - oh1 * OW;\n\n float a0[OCPT], a1[OCPT];\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n float bv = (has_bias && (oc_base + j) < O) ? __ldg(b + oc_base + j) : 0.0f;\n a0[j] = bv; a1[j] = bv;\n }\n\n int64_t in_base0 = ((int64_t)n0 * C) * HW + (int64_t)oh0 * W + ow0;\n int64_t in_base1 = ((int64_t)n1 * C) * HW + (int64_t)oh1 * W + ow1;\n #pragma unroll\n for (int c = 0; c < C; ++c) {\n int64_t xb0 = in_base0 + (int64_t)c * HW;\n int64_t xb1 = in_base1 + (int64_t)c * HW;\n #pragma unroll\n for (int kk = 0; kk < 9; ++kk) {\n int ky = kk / 3;\n int kx = kk - ky * 3;\n float v0 = __ldg(x + xb0 + (int64_t)ky * W + kx);\n float v1 = __ldg(x + xb1 + (int64_t)ky * W + kx);\n int woff = c * 9 + kk;\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n int oc = oc_base + j;\n if (oc < O) {\n float ww = __ldg(w + (int64_t)oc * C * 9 + woff);\n a0[j] = fmaf(v0, ww, a0[j]);\n a1[j] = fmaf(v1, ww, a1[j]);\n }\n }\n }\n }\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n int oc = oc_base + j;\n if (oc < O) {\n y[((int64_t)n0 * O + oc) * S + r0] = a0[j];\n y[((int64_t)n1 * O + oc) * S + r1] = a1[j];\n }\n }\n } else if (p0 < P) {\n int n0 = p0 / (int)S;\n int r0 = p0 - n0 * (int)S;\n int oh0 = r0 / OW;\n int ow0 = r0 - oh0 * OW;\n float a0[OCPT];\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n a0[j] = (has_bias && (oc_base + j) < O) ? __ldg(b + oc_base + j) : 0.0f;\n }\n int64_t in_base0 = ((int64_t)n0 * C) * HW + (int64_t)oh0 * W + ow0;\n #pragma unroll\n for (int c = 0; c < C; ++c) {\n int64_t xb0 = in_base0 + (int64_t)c * HW;\n #pragma unroll\n for (int kk = 0; kk < 9; ++kk) {\n int ky = kk / 3;\n int kx = kk - ky * 3;\n float v0 = __ldg(x + xb0 + (int64_t)ky * W + kx);\n int woff = c * 9 + kk;\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n int oc = oc_base + j;\n if (oc < O) {\n float ww = __ldg(w + (int64_t)oc * C * 9 + woff);\n a0[j] = fmaf(v0, ww, a0[j]);\n }\n }\n }\n }\n #pragma unroll\n for (int j = 0; j < OCPT; ++j) {\n int oc = oc_base + j;\n if (oc < O) y[((int64_t)n0 * O + oc) * S + r0] = a0[j];\n }\n }\n}\n\n__global__ void conv2d_general_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 Wd, int O, int K,\n int OH, int OW, int stride, int pad,\n int dil, int groups, int has_bias) {\n int64_t total = (int64_t)N * O * OH * OW;\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int ow = idx % OW;\n int64_t t = idx / OW;\n int oh = t % OH;\n t /= OH;\n int oc = t % O;\n int n = t / O;\n int ocpg = O / groups;\n int cpg = C / groups;\n int g = oc / ocpg;\n float acc = has_bias ? __ldg(b + oc) : 0.0f;\n for (int ci = 0; ci < cpg; ++ci) {\n int ic = g * cpg + ci;\n for (int ky = 0; ky < K; ++ky) {\n int ih = oh * stride - pad + ky * dil;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kx = 0; kx < K; ++kx) {\n int iw = ow * stride - pad + kx * dil;\n if ((unsigned)iw >= (unsigned)Wd) continue;\n float xv = __ldg(x + ((int64_t)n * C + ic) * H * Wd + (int64_t)ih * Wd + iw);\n float wv = __ldg(w + (((int64_t)oc * cpg + ci) * K + ky) * K + kx);\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor conv2d_forward(torch::Tensor x, torch::Tensor w, torch::Tensor b,\n int64_t stride, int64_t padding, int64_t dilation,\n int64_t groups, bool has_bias) {\n CHECK_CUDA(x); CHECK_CUDA(w);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(w);\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 Wd = (int)x.size(3);\n int O = (int)w.size(0);\n int K = (int)w.size(2);\n int OH = (H + 2 * (int)padding - (int)dilation * (K - 1) - 1) / (int)stride + 1;\n int OW = (Wd + 2 * (int)padding - (int)dilation * (K - 1) - 1) / (int)stride + 1;\n auto y = torch::empty({N, O, OH, OW}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (C == 16 && K == 3 && stride == 1 && padding == 0 && dilation == 1 && groups == 1) {\n dim3 block(256);\n dim3 grid(((N * OH * OW) + block.x * 2 - 1) / (block.x * 2), (O + 7) / 8);\n conv3x3_c16_oc8_kernel<<<grid, block, 0, stream>>>(x.data_ptr<float>(), w.data_ptr<float>(),\n has_bias ? b.data_ptr<float>() : nullptr, y.data_ptr<float>(), N, H, Wd, O, OH, OW, has_bias ? 1 : 0);\n } else {\n int threads = 256;\n int64_t total = (int64_t)N * O * OH * OW;\n int blocks = (int)((total + threads - 1) / threads);\n conv2d_general_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), w.data_ptr<float>(),\n has_bias ? b.data_ptr<float>() : nullptr, y.data_ptr<float>(), N, C, H, Wd, O, K, OH, OW,\n (int)stride, (int)padding, (int)dilation, (int)groups, has_bias ? 1 : 0);\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"conv2d_specialized_inline_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"conv2d_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n with_cuda=True,\n verbose=False,\n)\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, groups: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv2d = nn.Conv2d(in_channels, out_channels, (kernel_size, kernel_size), stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)\n self._stride = stride\n self._padding = padding\n self._dilation = dilation\n self._groups = groups\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n b = self.conv2d.bias\n if b is None:\n b = torch.empty(0, device=x.device, dtype=x.dtype)\n has_bias = False\n else:\n has_bias = True\n return _ext.conv2d_forward(x, self.conv2d.weight, b, self._stride, self._padding, self._dilation, self._groups, has_bias)\n"
}