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 conv_transpose2d_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride,\n int64_t padding,\n int64_t output_padding,\n int64_t groups);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n\n#define ACCUM8(v, wp) \\\n acc0 = fmaf((v), __ldg((wp) + 0*9), acc0); \\\n acc1 = fmaf((v), __ldg((wp) + 1*9), acc1); \\\n acc2 = fmaf((v), __ldg((wp) + 2*9), acc2); \\\n acc3 = fmaf((v), __ldg((wp) + 3*9), acc3); \\\n acc4 = fmaf((v), __ldg((wp) + 4*9), acc4); \\\n acc5 = fmaf((v), __ldg((wp) + 5*9), acc5); \\\n acc6 = fmaf((v), __ldg((wp) + 6*9), acc6); \\\n acc7 = fmaf((v), __ldg((wp) + 7*9), acc7)\n\n__global__ void deconv3x3_s1p0_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int IC, int OC,\n int H, int W, int OH, int OW,\n int has_bias) {\n const int tx = threadIdx.x; // 0..31: neighbouring output pixels\n const int ty = threadIdx.y; // several output-channel groups per block\n const int pix = blockIdx.x * blockDim.x + tx; // flattened N*OH*OW\n const int ocg = (blockIdx.y * blockDim.y + ty) * 8;\n\n const int total_pix = N * OH * OW;\n if (pix >= total_pix || ocg >= OC) return;\n\n const int OHW = OH * OW;\n const int HW = H * W;\n const int n = pix / OHW;\n const int sp = pix - n * OHW;\n const int oh = sp / OW;\n const int ow = sp - oh * OW;\n\n float acc0 = 0.0f, acc1 = 0.0f, acc2 = 0.0f, acc3 = 0.0f;\n float acc4 = 0.0f, acc5 = 0.0f, acc6 = 0.0f, acc7 = 0.0f;\n\n // Fast path used by essentially all pixels for the benchmark shape.\n if (ocg + 7 < OC && oh >= 2 && oh < H && ow >= 2 && ow < W) {\n const float* x_n = x + n * IC * HW;\n #pragma unroll 1\n for (int ic = 0; ic < IC; ++ic) {\n const float* x_c = x_n + ic * HW;\n const float* w_c = w + (ic * OC + ocg) * 9;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int ih = oh - kh;\n #pragma unroll\n for (int kw = 0; kw < 3; ++kw) {\n const int iw = ow - kw;\n const float v = __ldg(x_c + ih * W + iw);\n const float* wp = w_c + kh * 3 + kw;\n ACCUM8(v, wp);\n }\n }\n }\n if (has_bias) {\n acc0 += __ldg(bias + ocg + 0); acc1 += __ldg(bias + ocg + 1);\n acc2 += __ldg(bias + ocg + 2); acc3 += __ldg(bias + ocg + 3);\n acc4 += __ldg(bias + ocg + 4); acc5 += __ldg(bias + ocg + 5);\n acc6 += __ldg(bias + ocg + 6); acc7 += __ldg(bias + ocg + 7);\n }\n float* y_n = y + n * OC * OHW + sp;\n y_n[(ocg + 0) * OHW] = acc0;\n y_n[(ocg + 1) * OHW] = acc1;\n y_n[(ocg + 2) * OHW] = acc2;\n y_n[(ocg + 3) * OHW] = acc3;\n y_n[(ocg + 4) * OHW] = acc4;\n y_n[(ocg + 5) * OHW] = acc5;\n y_n[(ocg + 6) * OHW] = acc6;\n y_n[(ocg + 7) * OHW] = acc7;\n return;\n }\n\n // Generic edge/tail path for the one-pixel-wide transposed-convolution border.\n const float* x_n = x + n * IC * HW;\n #pragma unroll 1\n for (int ic = 0; ic < IC; ++ic) {\n const float* x_c = x_n + ic * HW;\n const float* w_c = w + (ic * OC + ocg) * 9;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int ih = oh - kh;\n if ((unsigned)ih >= (unsigned)H) continue;\n #pragma unroll\n for (int kw = 0; kw < 3; ++kw) {\n const int iw = ow - kw;\n if ((unsigned)iw >= (unsigned)W) continue;\n const float v = __ldg(x_c + ih * W + iw);\n const float* wp = w_c + kh * 3 + kw;\n if (ocg + 7 < OC) {\n ACCUM8(v, wp);\n } else {\n if (ocg + 0 < OC) acc0 = fmaf(v, __ldg(wp + 0*9), acc0);\n if (ocg + 1 < OC) acc1 = fmaf(v, __ldg(wp + 1*9), acc1);\n if (ocg + 2 < OC) acc2 = fmaf(v, __ldg(wp + 2*9), acc2);\n if (ocg + 3 < OC) acc3 = fmaf(v, __ldg(wp + 3*9), acc3);\n if (ocg + 4 < OC) acc4 = fmaf(v, __ldg(wp + 4*9), acc4);\n if (ocg + 5 < OC) acc5 = fmaf(v, __ldg(wp + 5*9), acc5);\n if (ocg + 6 < OC) acc6 = fmaf(v, __ldg(wp + 6*9), acc6);\n if (ocg + 7 < OC) acc7 = fmaf(v, __ldg(wp + 7*9), acc7);\n }\n }\n }\n }\n float* y_n = y + n * OC * OHW + sp;\n if (has_bias) {\n if (ocg + 0 < OC) acc0 += __ldg(bias + ocg + 0);\n if (ocg + 1 < OC) acc1 += __ldg(bias + ocg + 1);\n if (ocg + 2 < OC) acc2 += __ldg(bias + ocg + 2);\n if (ocg + 3 < OC) acc3 += __ldg(bias + ocg + 3);\n if (ocg + 4 < OC) acc4 += __ldg(bias + ocg + 4);\n if (ocg + 5 < OC) acc5 += __ldg(bias + ocg + 5);\n if (ocg + 6 < OC) acc6 += __ldg(bias + ocg + 6);\n if (ocg + 7 < OC) acc7 += __ldg(bias + ocg + 7);\n }\n if (ocg + 0 < OC) y_n[(ocg + 0) * OHW] = acc0;\n if (ocg + 1 < OC) y_n[(ocg + 1) * OHW] = acc1;\n if (ocg + 2 < OC) y_n[(ocg + 2) * OHW] = acc2;\n if (ocg + 3 < OC) y_n[(ocg + 3) * OHW] = acc3;\n if (ocg + 4 < OC) y_n[(ocg + 4) * OHW] = acc4;\n if (ocg + 5 < OC) y_n[(ocg + 5) * OHW] = acc5;\n if (ocg + 6 < OC) y_n[(ocg + 6) * OHW] = acc6;\n if (ocg + 7 < OC) y_n[(ocg + 7) * OHW] = acc7;\n}\n\n// Simple fully-generic fp32 fallback for uncommon stride/padding/groups settings.\n__global__ void deconv_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int IC, int OC, int H, int W, int K,\n int stride, int padding, int groups,\n int OH, int OW, int has_bias) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * OC * OH * OW;\n if (idx >= total) return;\n int ow = idx % OW;\n int t = idx / OW;\n int oh = t % OH;\n t /= OH;\n int oc = t % OC;\n int n = t / OC;\n int ocpg = OC / groups;\n int icpg = IC / groups;\n int g = oc / ocpg;\n float acc = 0.0f;\n for (int ic0 = 0; ic0 < icpg; ++ic0) {\n int ic = g * icpg + ic0;\n for (int kh = 0; kh < K; ++kh) {\n int num_h = oh + padding - kh;\n if (num_h % stride) continue;\n int ih = num_h / stride;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < K; ++kw) {\n int num_w = ow + padding - kw;\n if (num_w % stride) continue;\n int iw = num_w / stride;\n if ((unsigned)iw >= (unsigned)W) continue;\n float xv = __ldg(x + ((n * IC + ic) * H + ih) * W + iw);\n float wv = __ldg(w + (((ic * ocpg + (oc - g * ocpg)) * K + kh) * K + kw));\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n if (has_bias) acc += __ldg(bias + oc);\n y[idx] = acc;\n}\n\ntorch::Tensor conv_transpose2d_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride,\n int64_t padding,\n int64_t output_padding,\n int64_t groups) {\n const at::cuda::CUDAGuard device_guard(x.device());\n const int N = (int)x.size(0);\n const int IC = (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 OC = (int)weight.size(1) * (int)groups;\n const int OH = (H - 1) * (int)stride - 2 * (int)padding + K + (int)output_padding;\n const int OW = (W - 1) * (int)stride - 2 * (int)padding + K + (int)output_padding;\n auto y = torch::empty({N, OC, OH, OW}, x.options());\n const int has_bias = (bias.numel() > 0);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (K == 3 && stride == 1 && padding == 0 && output_padding == 0 && groups == 1) {\n dim3 block(32, 4, 1);\n dim3 grid((N * OH * OW + block.x - 1) / block.x, (OC + 8 * block.y - 1) / (8 * block.y), 1);\n deconv3x3_s1p0_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), has_bias ? bias.data_ptr<float>() : nullptr,\n y.data_ptr<float>(), N, IC, OC, H, W, OH, OW, has_bias);\n } else {\n int total = N * OC * OH * OW;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n deconv_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), has_bias ? bias.data_ptr<float>() : nullptr,\n y.data_ptr<float>(), N, IC, OC, H, W, K, (int)stride, (int)padding, (int)groups, OH, OW, has_bias);\n }\n return y;\n}\n'''\n\n_ext = load_inline(\n name='deconv2d_3x3_s1_ext',\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=['conv_transpose2d_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, output_padding: int = 0, groups: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv_transpose2d = nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=stride, padding=padding, output_padding=output_padding, groups=groups, bias=bias)\n self.stride = stride\n self.padding = padding\n self.output_padding = output_padding\n self.groups = groups\n self.register_buffer('_empty_bias', torch.empty(0), persistent=False)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n b = self.conv_transpose2d.bias\n if b is None:\n b = self._empty_bias\n return _ext.conv_transpose2d_forward(x, self.conv_transpose2d.weight, b, self.stride, self.padding, self.output_padding, self.groups)\n"
}