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, torch::Tensor weight, torch::Tensor bias,\n int64_t stride_h, int64_t stride_w,\n int64_t pad_h, int64_t pad_w,\n int64_t dil_h, int64_t dil_w,\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 <c10/cuda/CUDAException.h>\n\n__global__ void deconv2d_3x5_s2x3_opt_kernel(\n 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 Ho, int Wo, bool has_bias)\n{\n // One thread computes all 16 output channels belonging to one group for one (n,oh,ow).\n // Specialized for Cin=32, Cout=64, groups=4, k=(3,5), stride=(2,3), pad=(1,2), dil=(2,1).\n const int G = 4;\n const int CinPG = 8;\n const int CoutPG = 16;\n long long tid = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)N * G * Ho * Wo;\n if (tid >= total) return;\n\n int ow = tid % Wo;\n tid /= Wo;\n int oh = tid % Ho;\n tid /= Ho;\n int g = tid % G;\n int n = tid / G;\n\n const int Cout = 64;\n const int Cin = 32;\n const long long out_base = ((long long)n * Cout + g * CoutPG) * Ho * Wo + (long long)oh * Wo + ow;\n\n // With pad_h=1,dil_h=2,stride_h=2, only odd output rows receive convolution contributions.\n if ((oh & 1) == 0) {\n #pragma unroll\n for (int oc = 0; oc < 16; ++oc) {\n y[out_base + (long long)oc * Ho * Wo] = has_bias ? b[g * CoutPG + oc] : 0.0f;\n }\n return;\n }\n\n float acc0 = has_bias ? b[g*CoutPG + 0] : 0.0f;\n float acc1 = has_bias ? b[g*CoutPG + 1] : 0.0f;\n float acc2 = has_bias ? b[g*CoutPG + 2] : 0.0f;\n float acc3 = has_bias ? b[g*CoutPG + 3] : 0.0f;\n float acc4 = has_bias ? b[g*CoutPG + 4] : 0.0f;\n float acc5 = has_bias ? b[g*CoutPG + 5] : 0.0f;\n float acc6 = has_bias ? b[g*CoutPG + 6] : 0.0f;\n float acc7 = has_bias ? b[g*CoutPG + 7] : 0.0f;\n float acc8 = has_bias ? b[g*CoutPG + 8] : 0.0f;\n float acc9 = has_bias ? b[g*CoutPG + 9] : 0.0f;\n float acc10 = has_bias ? b[g*CoutPG + 10] : 0.0f;\n float acc11 = has_bias ? b[g*CoutPG + 11] : 0.0f;\n float acc12 = has_bias ? b[g*CoutPG + 12] : 0.0f;\n float acc13 = has_bias ? b[g*CoutPG + 13] : 0.0f;\n float acc14 = has_bias ? b[g*CoutPG + 14] : 0.0f;\n float acc15 = has_bias ? b[g*CoutPG + 15] : 0.0f;\n\n const int ih_base = (oh + 1) >> 1;\n const int r = (ow + 2) % 3;\n\n #pragma unroll\n for (int icl = 0; icl < 8; ++icl) {\n const int ic = g * CinPG + icl;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int ih = ih_base - kh;\n if ((unsigned)ih < (unsigned)H) {\n #pragma unroll\n for (int kk = 0; kk < 2; ++kk) {\n int kw = r + kk * 3;\n if (kw < 5) {\n int iw = (ow + 2 - kw) / 3;\n if ((unsigned)iw < (unsigned)W) {\n float xv = x[((long long)n * Cin + ic) * H * W + (long long)ih * W + iw];\n const float* wp = w + ((ic * CoutPG) * 3 + kh) * 5 + kw;\n acc0 = fmaf(xv, wp[ 0 * 15], acc0);\n acc1 = fmaf(xv, wp[ 1 * 15], acc1);\n acc2 = fmaf(xv, wp[ 2 * 15], acc2);\n acc3 = fmaf(xv, wp[ 3 * 15], acc3);\n acc4 = fmaf(xv, wp[ 4 * 15], acc4);\n acc5 = fmaf(xv, wp[ 5 * 15], acc5);\n acc6 = fmaf(xv, wp[ 6 * 15], acc6);\n acc7 = fmaf(xv, wp[ 7 * 15], acc7);\n acc8 = fmaf(xv, wp[ 8 * 15], acc8);\n acc9 = fmaf(xv, wp[ 9 * 15], acc9);\n acc10 = fmaf(xv, wp[10 * 15], acc10);\n acc11 = fmaf(xv, wp[11 * 15], acc11);\n acc12 = fmaf(xv, wp[12 * 15], acc12);\n acc13 = fmaf(xv, wp[13 * 15], acc13);\n acc14 = fmaf(xv, wp[14 * 15], acc14);\n acc15 = fmaf(xv, wp[15 * 15], acc15);\n }\n }\n }\n }\n }\n }\n\n const long long ch_stride = (long long)Ho * Wo;\n y[out_base + 0 * ch_stride] = acc0;\n y[out_base + 1 * ch_stride] = acc1;\n y[out_base + 2 * ch_stride] = acc2;\n y[out_base + 3 * ch_stride] = acc3;\n y[out_base + 4 * ch_stride] = acc4;\n y[out_base + 5 * ch_stride] = acc5;\n y[out_base + 6 * ch_stride] = acc6;\n y[out_base + 7 * ch_stride] = acc7;\n y[out_base + 8 * ch_stride] = acc8;\n y[out_base + 9 * ch_stride] = acc9;\n y[out_base + 10 * ch_stride] = acc10;\n y[out_base + 11 * ch_stride] = acc11;\n y[out_base + 12 * ch_stride] = acc12;\n y[out_base + 13 * ch_stride] = acc13;\n y[out_base + 14 * ch_stride] = acc14;\n y[out_base + 15 * ch_stride] = acc15;\n}\n\n__global__ void deconv2d_generic_kernel(\n const float* __restrict__ x, const float* __restrict__ w, const float* __restrict__ b,\n float* __restrict__ y,\n int N, int Cin, int H, int W, int Cout, int Ho, int Wo,\n int kH, int kW, int sh, int sw, int ph, int pw, int dh, int dw, int groups, bool has_bias)\n{\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)N * Cout * Ho * Wo;\n if (idx >= total) return;\n int ow = idx % Wo; idx /= Wo;\n int oh = idx % Ho; idx /= Ho;\n int oc = idx % Cout;\n int n = idx / Cout;\n int CoutPG = Cout / groups;\n int CinPG = Cin / groups;\n int g = oc / CoutPG;\n int ocl = oc - g * CoutPG;\n float acc = has_bias ? b[oc] : 0.0f;\n for (int icl = 0; icl < CinPG; ++icl) {\n int ic = g * CinPG + icl;\n for (int kh = 0; kh < kH; ++kh) {\n int th = oh + ph - kh * dh;\n if (th % sh) continue;\n int ih = th / sh;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < kW; ++kw) {\n int tw = ow + pw - kw * dw;\n if (tw % sw) continue;\n int iw = tw / sw;\n if ((unsigned)iw < (unsigned)W) {\n float xv = x[((long long)n * Cin + ic) * H * W + (long long)ih * W + iw];\n float wv = w[((long long)ic * CoutPG + ocl) * kH * kW + kh * kW + kw];\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n }\n y[((long long)n * Cout + oc) * Ho * Wo + (long long)oh * Wo + ow] = acc;\n}\n\ntorch::Tensor conv_transpose2d_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride_h, int64_t stride_w,\n int64_t pad_h, int64_t pad_w,\n int64_t dil_h, int64_t dil_w,\n int64_t groups, bool has_bias) {\n const int N = (int)x.size(0);\n const int Cin = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int kH = (int)weight.size(2);\n const int kW = (int)weight.size(3);\n const int CoutPG = (int)weight.size(1);\n const int Cout = CoutPG * (int)groups;\n const int Ho = (H - 1) * (int)stride_h - 2 * (int)pad_h + (int)dil_h * (kH - 1) + 1;\n const int Wo = (W - 1) * (int)stride_w - 2 * (int)pad_w + (int)dil_w * (kW - 1) + 1;\n auto y = torch::empty({N, Cout, Ho, Wo}, x.options());\n\n const int threads = 128;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* bp = has_bias ? bias.data_ptr<float>() : nullptr;\n\n if (Cin == 32 && Cout == 64 && (int)groups == 4 && kH == 3 && kW == 5 &&\n stride_h == 2 && stride_w == 3 && pad_h == 1 && pad_w == 2 && dil_h == 2 && dil_w == 1) {\n long long total = (long long)N * (int)groups * Ho * Wo;\n int blocks = (int)((total + threads - 1) / threads);\n deconv2d_3x5_s2x3_opt_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), N, H, W, Ho, Wo, has_bias);\n } else {\n long long total = (long long)N * Cout * Ho * Wo;\n int blocks = (int)((total + threads - 1) / threads);\n deconv2d_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(),\n N, Cin, H, W, Cout, Ho, Wo, kH, kW, (int)stride_h, (int)stride_w,\n (int)pad_h, (int)pad_w, (int)dil_h, (int)dil_w, (int)groups, has_bias);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='deconv2d_asym_grouped_ext_v1',\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 verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: tuple, stride: tuple = (1, 1), padding: tuple = (0, 0), dilation: tuple = (1, 1), 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, 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.conv_transpose2d.bias\n has_bias = b is not None\n if b is None:\n b = x.new_empty((0,))\n return _ext.conv_transpose2d_forward(\n x, self.conv_transpose2d.weight, b,\n int(self.stride[0]), int(self.stride[1]),\n int(self.padding[0]), int(self.padding[1]),\n int(self.dilation[0]), int(self.dilation[1]),\n int(self.groups), bool(has_bias)\n )\n"
}