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 convt_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n bool has_bias, int64_t stride_h, int64_t stride_w,\n int64_t pad_h, int64_t pad_w, int64_t outpad_h, int64_t outpad_w,\n int64_t dil_h, int64_t dil_w, int64_t groups);\n\ntorch::Tensor convt_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n bool has_bias, int64_t stride_h, int64_t stride_w,\n int64_t pad_h, int64_t pad_w, int64_t outpad_h, int64_t outpad_w,\n int64_t dil_h, int64_t dil_w, int64_t groups) {\n return convt_forward_cuda(x, weight, bias, has_bias, stride_h, stride_w, pad_h, pad_w,\n outpad_h, outpad_w, dil_h, dil_w, 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 BM 16\n#define BN 64\n#define BK 32\n\n// Specialized implicit-GEMM kernel for the benchmark shape:\n// N=64, Cin=64, HxW=128x256, Cout=128, K=3x5, stride=1, padding=0, dilation=1.\n// Computes a 16 x 64 tile of output per block; each thread accumulates 4 columns.\n__global__ __launch_bounds__(256, 2)\nvoid convt2d_64_128_3x5_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int has_bias) {\n __shared__ float As[BM][BK + 1];\n __shared__ float Bs[BK][BN + 1];\n\n const int tx = threadIdx.x; // 0..15\n const int ty = threadIdx.y; // 0..15\n const int tid = ty * 16 + tx;\n\n const int n = blockIdx.z;\n const int oc = blockIdx.y * BM + ty;\n const int col_base = blockIdx.x * BN;\n const int col0 = col_base + tx;\n const int col1 = col0 + 16;\n const int col2 = col0 + 32;\n const int col3 = col0 + 48;\n\n float acc0 = 0.0f, acc1 = 0.0f, acc2 = 0.0f, acc3 = 0.0f;\n\n #pragma unroll\n for (int k0 = 0; k0 < 960; k0 += BK) {\n // load A tile: weights laid out [IC, OC, KH, KW]\n for (int t = tid; t < BM * BK; t += 256) {\n const int r = t / BK;\n const int kk = t - r * BK;\n const int k = k0 + kk;\n const int ic = k / 15;\n const int rem = k - ic * 15;\n const int kh = rem / 5;\n const int kw = rem - kh * 5;\n const int ocr = blockIdx.y * BM + r;\n As[r][kk] = w[((ic * 128 + ocr) * 3 + kh) * 5 + kw];\n }\n\n // load B tile: implicit full-convolution input matrix\n for (int t = tid; t < BK * BN; t += 256) {\n const int kk = t / BN;\n const int c = t - kk * BN;\n const int k = k0 + kk;\n const int ic = k / 15;\n const int rem = k - ic * 15;\n const int kh = rem / 5;\n const int kw = rem - kh * 5;\n const int col = col_base + c;\n float v = 0.0f;\n if (col < 33800) {\n const int oh = col / 260;\n const int ow = col - oh * 260;\n const int ih = oh - kh;\n const int iw = ow - kw;\n if ((unsigned)ih < 128u && (unsigned)iw < 256u) {\n v = x[((n * 64 + ic) * 128 + ih) * 256 + iw];\n }\n }\n Bs[kk][c] = v;\n }\n __syncthreads();\n\n #pragma unroll\n for (int kk = 0; kk < BK; ++kk) {\n const float a = As[ty][kk];\n acc0 = fmaf(a, Bs[kk][tx], acc0);\n acc1 = fmaf(a, Bs[kk][tx + 16], acc1);\n acc2 = fmaf(a, Bs[kk][tx + 32], acc2);\n acc3 = fmaf(a, Bs[kk][tx + 48], acc3);\n }\n __syncthreads();\n }\n\n if (oc < 128) {\n const float b = has_bias ? bias[oc] : 0.0f;\n if (col0 < 33800) {\n const int oh = col0 / 260; const int ow = col0 - oh * 260;\n y[((n * 128 + oc) * 130 + oh) * 260 + ow] = acc0 + b;\n }\n if (col1 < 33800) {\n const int oh = col1 / 260; const int ow = col1 - oh * 260;\n y[((n * 128 + oc) * 130 + oh) * 260 + ow] = acc1 + b;\n }\n if (col2 < 33800) {\n const int oh = col2 / 260; const int ow = col2 - oh * 260;\n y[((n * 128 + oc) * 130 + oh) * 260 + ow] = acc2 + b;\n }\n if (col3 < 33800) {\n const int oh = col3 / 260; const int ow = col3 - oh * 260;\n y[((n * 128 + oc) * 130 + oh) * 260 + ow] = acc3 + b;\n }\n }\n}\n\n// Simple correctness fallback for unusual constructor arguments (not optimized).\n__global__ void convt2d_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int total, int B, int IC, int H, int Wd, int OC, int KH, int KW,\n int OH, int OW, int sh, int sw, int ph, int pw, int dh, int dw,\n int groups, int has_bias) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\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 int ocg = oc - g * OCpg;\n float acc = has_bias ? bias[oc] : 0.0f;\n for (int icg = 0; icg < ICpg; ++icg) {\n int ic = g * ICpg + icg;\n for (int kh = 0; kh < KH; ++kh) {\n int th = oh + ph - kh * dh;\n if (th % sh != 0) 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 != 0) continue;\n int iw = tw / sw;\n if ((unsigned)iw < (unsigned)Wd) {\n float xv = x[((n * IC + ic) * H + ih) * Wd + iw];\n float wv = w[((ic * OCpg + ocg) * KH + kh) * KW + kw];\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor convt_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n bool has_bias, int64_t stride_h, int64_t stride_w,\n int64_t pad_h, int64_t pad_w, int64_t outpad_h, int64_t outpad_w,\n int64_t dil_h, int64_t dil_w, int64_t groups) {\n TORCH_CHECK(x.is_cuda() && weight.is_cuda(), \"tensors must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat && weight.scalar_type() == at::kFloat, \"float32 only\");\n const int B = (int)x.size(0);\n const int IC = (int)x.size(1);\n const int H = (int)x.size(2);\n const int Wd = (int)x.size(3);\n const int KH = (int)weight.size(2);\n const int KW = (int)weight.size(3);\n const int OCpg = (int)weight.size(1);\n const int OC = OCpg * (int)groups;\n const int OH = (H - 1) * (int)stride_h - 2 * (int)pad_h + (int)dil_h * (KH - 1) + (int)outpad_h + 1;\n const int OW = (Wd - 1) * (int)stride_w - 2 * (int)pad_w + (int)dil_w * (KW - 1) + (int)outpad_w + 1;\n auto y = torch::empty({B, OC, OH, OW}, x.options());\n\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* bp = has_bias ? bias.data_ptr<float>() : nullptr;\n\n if (B == 64 && IC == 64 && H == 128 && Wd == 256 && OC == 128 && KH == 3 && KW == 5 &&\n stride_h == 1 && stride_w == 1 && pad_h == 0 && pad_w == 0 && outpad_h == 0 && outpad_w == 0 &&\n dil_h == 1 && dil_w == 1 && groups == 1 && x.is_contiguous() && weight.is_contiguous()) {\n dim3 block(16, 16, 1);\n dim3 grid((33800 + BN - 1) / BN, 8, 64);\n convt2d_64_128_3x5_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), has_bias ? 1 : 0);\n } else {\n int total = B * OC * OH * OW;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n convt2d_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), total, B, IC, H, Wd, OC, KH, KW,\n OH, OW, (int)stride_h, (int)stride_w, (int)pad_h, (int)pad_w, (int)dil_h, (int)dil_w,\n (int)groups, has_bias ? 1 : 0);\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"convt2d_asym_implicit_gemm_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"convt_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,\n stride: tuple = (1, 1), padding: tuple = (0, 0), output_padding: tuple = (0, 0),\n 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,\n stride=stride, padding=padding,\n output_padding=output_padding, dilation=dilation,\n groups=groups, bias=bias)\n self.stride = tuple(stride)\n self.padding = tuple(padding)\n self.output_padding = tuple(output_padding)\n self.dilation = tuple(dilation)\n self.groups = groups\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n w = self.conv_transpose2d.weight\n b = self.conv_transpose2d.bias\n has_bias = b is not None\n if not has_bias:\n b = w.new_empty((0,))\n # Benchmark inputs are contiguous; make the extension robust for occasional non-contiguous input.\n if not x.is_contiguous():\n x = x.contiguous()\n return _ext.convt_forward(x, w, b, has_bias,\n int(self.stride[0]), int(self.stride[1]),\n int(self.padding[0]), int(self.padding[1]),\n int(self.output_padding[0]), int(self.output_padding[1]),\n int(self.dilation[0]), int(self.dilation[1]), int(self.groups))\n"
}