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_3x3_cuda(torch::Tensor x, torch::Tensor w, torch::Tensor b,\n int64_t stride, int64_t padding, int64_t dilation, int64_t groups);\n\ntorch::Tensor conv2d_forward(torch::Tensor x, torch::Tensor w, torch::Tensor b,\n int64_t stride, int64_t padding, int64_t dilation, int64_t groups) {\n return conv2d_3x3_cuda(x, w, b, stride, padding, dilation, groups);\n}\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 TILE_M 64\n#define TILE_N 32\n#define BK 8\n\n__global__ __launch_bounds__(128, 2)\nvoid conv3x3_s1p0_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W,\n int Kout, int OH, int OW,\n int tiles_h, int has_bias) {\n __shared__ float As[TILE_M * BK];\n __shared__ float Bs[BK * TILE_N];\n\n const int tx = threadIdx.x; // 0..127\n const int tile_x = blockIdx.x; // 8-wide spatial tile in W\n const int by = blockIdx.y;\n const int n = by / tiles_h;\n const int tile_y = by - n * tiles_h; // 8-high spatial tile in H\n const int n_tile = blockIdx.z; // 32 output-channel tile\n\n const int m_group = tx & 15; // 16 groups in M\n const int n_group = tx >> 4; // 8 groups in N, each computes 4 channels\n\n float acc[4][4];\n #pragma unroll\n for (int i = 0; i < 4; ++i) {\n #pragma unroll\n for (int j = 0; j < 4; ++j) acc[i][j] = 0.0f;\n }\n\n const int ow_base = tile_x << 3;\n const int oh_base = tile_y << 3;\n const int oc_base = n_tile * TILE_N;\n const int Ktot = C * 9;\n\n for (int k0 = 0; k0 < Ktot; k0 += BK) {\n // Load im2col A tile: 64 output pixels x 8 reduction entries\n #pragma unroll\n for (int l = 0; l < 4; ++l) {\n int idx = tx + l * 128; // 0..511\n int mr = idx >> 3; // / BK\n int kk = idx & 7;\n int kval = k0 + kk;\n int ic = kval / 9;\n int rs = kval - ic * 9;\n int rr = rs / 3;\n int ss = rs - rr * 3;\n int dy = mr >> 3;\n int dx = mr & 7;\n int oh = oh_base + dy;\n int ow = ow_base + dx;\n float v = 0.0f;\n if (oh < OH && ow < OW) {\n v = __ldg(x + (((n * C + ic) * H + (oh + rr)) * W + (ow + ss)));\n }\n As[mr * BK + kk] = v;\n }\n\n // Load B tile: 8 reduction entries x 32 output channels.\n #pragma unroll\n for (int l = 0; l < 2; ++l) {\n int idx = tx + l * 128; // 0..255\n int col = idx >> 3; // output-channel within tile\n int kk = idx & 7;\n int oc = oc_base + col;\n float v = 0.0f;\n if (oc < Kout) {\n v = __ldg(w + oc * Ktot + (k0 + kk));\n }\n Bs[kk * TILE_N + col] = v;\n }\n __syncthreads();\n\n #pragma unroll\n for (int kk = 0; kk < BK; ++kk) {\n float a0 = As[(m_group + 0) * BK + kk];\n float a1 = As[(m_group + 16) * BK + kk];\n float a2 = As[(m_group + 32) * BK + kk];\n float a3 = As[(m_group + 48) * BK + kk];\n float b0 = Bs[kk * TILE_N + n_group * 4 + 0];\n float b1 = Bs[kk * TILE_N + n_group * 4 + 1];\n float b2 = Bs[kk * TILE_N + n_group * 4 + 2];\n float b3 = Bs[kk * TILE_N + n_group * 4 + 3];\n acc[0][0] = fmaf(a0, b0, acc[0][0]);\n acc[0][1] = fmaf(a0, b1, acc[0][1]);\n acc[0][2] = fmaf(a0, b2, acc[0][2]);\n acc[0][3] = fmaf(a0, b3, acc[0][3]);\n acc[1][0] = fmaf(a1, b0, acc[1][0]);\n acc[1][1] = fmaf(a1, b1, acc[1][1]);\n acc[1][2] = fmaf(a1, b2, acc[1][2]);\n acc[1][3] = fmaf(a1, b3, acc[1][3]);\n acc[2][0] = fmaf(a2, b0, acc[2][0]);\n acc[2][1] = fmaf(a2, b1, acc[2][1]);\n acc[2][2] = fmaf(a2, b2, acc[2][2]);\n acc[2][3] = fmaf(a2, b3, acc[2][3]);\n acc[3][0] = fmaf(a3, b0, acc[3][0]);\n acc[3][1] = fmaf(a3, b1, acc[3][1]);\n acc[3][2] = fmaf(a3, b2, acc[3][2]);\n acc[3][3] = fmaf(a3, b3, acc[3][3]);\n }\n __syncthreads();\n }\n\n #pragma unroll\n for (int ii = 0; ii < 4; ++ii) {\n int mr = m_group + ii * 16;\n int dy = mr >> 3;\n int dx = mr & 7;\n int oh = oh_base + dy;\n int ow = ow_base + dx;\n if (oh < OH && ow < OW) {\n #pragma unroll\n for (int jj = 0; jj < 4; ++jj) {\n int oc = oc_base + n_group * 4 + jj;\n if (oc < Kout) {\n float v = acc[ii][jj] + (has_bias ? __ldg(bias + oc) : 0.0f);\n y[((n * Kout + oc) * OH + oh) * OW + ow] = v;\n }\n }\n }\n }\n}\n\n// Generic but slower reference-style CUDA kernel for uncommon constructor arguments.\n__global__ void conv2d_generic_kernel(const float* __restrict__ x, const float* __restrict__ w,\n const float* __restrict__ bias, float* __restrict__ y,\n int N, int C, int H, int Wd, int Kout, int KH, int KW,\n int OH, int OW, int stride, int pad, int dil, int groups, int has_bias,\n long total) {\n long idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int ow = idx % OW;\n long t = idx / OW;\n int oh = t % OH;\n t /= OH;\n int oc = t % Kout;\n int n = t / Kout;\n int cpg = C / groups;\n int kpg = Kout / groups;\n int g = oc / kpg;\n int c0 = g * cpg;\n float sum = has_bias ? __ldg(bias + oc) : 0.0f;\n for (int icg = 0; icg < cpg; ++icg) {\n int ic = c0 + icg;\n for (int r = 0; r < KH; ++r) {\n int ih = oh * stride - pad + r * dil;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int s = 0; s < KW; ++s) {\n int iw = ow * stride - pad + s * dil;\n if ((unsigned)iw < (unsigned)Wd) {\n sum = fmaf(__ldg(x + ((n*C + ic)*H + ih)*Wd + iw),\n __ldg(w + (((oc*cpg + icg)*KH + r)*KW + s)), sum);\n }\n }\n }\n }\n y[idx] = sum;\n}\n\ntorch::Tensor conv2d_3x3_cuda(torch::Tensor x, torch::Tensor w, torch::Tensor b,\n int64_t stride, int64_t padding, int64_t dilation, int64_t groups) {\n x = x.contiguous();\n w = w.contiguous();\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 Wd = (int)x.size(3);\n const int Kout = (int)w.size(0);\n const int KH = (int)w.size(2);\n const int KW = (int)w.size(3);\n const int OH = (H + 2*(int)padding - (int)dilation*(KH-1) - 1) / (int)stride + 1;\n const int OW = (Wd + 2*(int)padding - (int)dilation*(KW-1) - 1) / (int)stride + 1;\n auto y = torch::empty({N, Kout, OH, OW}, x.options());\n const int has_bias = (b.numel() != 0);\n const float* bp = has_bias ? b.data_ptr<float>() : nullptr;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (x.scalar_type() == at::kFloat && C == 64 && Kout == 128 && KH == 3 && KW == 3 &&\n stride == 1 && padding == 0 && dilation == 1 && groups == 1) {\n const int tiles_w = (OW + 7) >> 3;\n const int tiles_h = (OH + 7) >> 3;\n dim3 grid(tiles_w, N * tiles_h, (Kout + TILE_N - 1) / TILE_N);\n conv3x3_s1p0_kernel<<<grid, 128, 0, stream>>>(x.data_ptr<float>(), w.data_ptr<float>(), bp, y.data_ptr<float>(),\n N, C, H, Wd, Kout, OH, OW, tiles_h, has_bias);\n } else {\n long total = (long)N * Kout * OH * OW;\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n conv2d_generic_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), w.data_ptr<float>(), bp, y.data_ptr<float>(),\n N, C, H, Wd, Kout, KH, KW, OH, OW,\n (int)stride, (int)padding, (int)dilation, (int)groups, has_bias, total);\n }\n return y;\n}\n'''\n\n_ext = load_inline(\n name='conv2d_3x3_asym_ext_v1',\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 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 return _ext.conv2d_forward(x, self.conv2d.weight, b, self._stride, self._padding, self._dilation, self._groups)\n"
}