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#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.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#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n\ntorch::Tensor deconv_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t output_padding, 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#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#define CHECK_FLOAT(x) TORCH_CHECK(x.scalar_type() == at::kFloat, #x \" must be float32\")\n\n// Specialized path for the benchmark case: N x 32 x H x W, 32 output channels,\n// 3x3 kernel, stride=1, padding=0, groups=1. One warp computes the complete\n// 32-channel output vector for one spatial location. Input scalar loads are\n// broadcast within the warp, while weight loads are naturally coalesced over OC.\n__global__ __launch_bounds__(256, 2)\nvoid deconv_k3s1p0_c32_warp_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 OH, int OW,\n bool has_bias) {\n constexpr int WARPS_PER_BLOCK = 8;\n int warp_in_block = threadIdx.x >> 5;\n int lane = threadIdx.x & 31; // output channel\n long long warp_id = (long long)blockIdx.x * WARPS_PER_BLOCK + warp_in_block;\n long long npos = (long long)N * OH * OW;\n if (warp_id >= npos) return;\n\n int ow = (int)(warp_id % OW);\n long long t = warp_id / OW;\n int oh = (int)(t % OH);\n int n = (int)(t / OH);\n\n float acc = has_bias ? b[lane] : 0.0f;\n unsigned mask = 0xffffffffu;\n\n // Fast, branch-free interior. For k=3,p=0, all 9 input taps are valid iff\n // oh in [2,H-1] and ow in [2,W-1]. This covers almost all output pixels.\n if (oh >= 2 && oh < H && ow >= 2 && ow < W) {\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n int ih = oh - kh;\n #pragma unroll\n for (int kw = 0; kw < 3; ++kw) {\n int iw = ow - kw;\n #pragma unroll\n for (int ic = 0; ic < 32; ++ic) {\n float xv = 0.0f;\n if (lane == 0) xv = x[((n * 32 + ic) * H + ih) * W + iw];\n xv = __shfl_sync(mask, xv, 0);\n float wt = w[((ic * 32 + lane) * 3 + kh) * 3 + kw];\n acc = fmaf(xv, wt, acc);\n }\n }\n }\n } else {\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n int ih = oh - kh;\n if ((unsigned)ih < (unsigned)H) {\n #pragma unroll\n for (int kw = 0; kw < 3; ++kw) {\n int iw = ow - kw;\n if ((unsigned)iw < (unsigned)W) {\n #pragma unroll\n for (int ic = 0; ic < 32; ++ic) {\n float xv = 0.0f;\n if (lane == 0) xv = x[((n * 32 + ic) * H + ih) * W + iw];\n xv = __shfl_sync(mask, xv, 0);\n float wt = w[((ic * 32 + lane) * 3 + kh) * 3 + kw];\n acc = fmaf(xv, wt, acc);\n }\n }\n }\n }\n }\n }\n\n y[((n * 32 + lane) * OH + oh) * OW + ow] = acc;\n}\n\n// General correctness kernel for less common constructor arguments.\n__global__\nvoid deconv_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n long long total,\n int N, int inC, int H, int W,\n int outC, int OH, int OW,\n int kH, int kW,\n int stride, int padding, int groups,\n bool has_bias) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n\n int ow = (int)(idx % OW);\n long long q = idx / OW;\n int oh = (int)(q % OH);\n q /= OH;\n int oc = (int)(q % outC);\n int n = (int)(q / outC);\n\n int out_per_g = outC / groups;\n int in_per_g = inC / groups;\n int g = oc / out_per_g;\n int ocg = oc - g * out_per_g;\n int ic0 = g * in_per_g;\n int ic1 = ic0 + in_per_g;\n\n float acc = has_bias ? b[oc] : 0.0f;\n for (int ic = ic0; ic < ic1; ++ic) {\n for (int kh = 0; kh < kH; ++kh) {\n int th = oh + padding - kh;\n if (th % stride != 0) continue;\n int ih = th / stride;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < kW; ++kw) {\n int tw = ow + padding - kw;\n if (tw % stride != 0) continue;\n int iw = tw / stride;\n if ((unsigned)iw >= (unsigned)W) continue;\n float xv = x[((n * inC + ic) * H + ih) * W + iw];\n float wt = w[(((ic * out_per_g + ocg) * kH + kh) * kW + kw)];\n acc = fmaf(xv, wt, acc);\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor deconv_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride64, int64_t padding64, int64_t output_padding64, int64_t groups64) {\n CHECK_CUDA(x); CHECK_CUDA(weight);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(weight);\n CHECK_FLOAT(x); CHECK_FLOAT(weight);\n if (bias.numel() > 0) { CHECK_CUDA(bias); CHECK_CONTIGUOUS(bias); CHECK_FLOAT(bias); }\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n\n int N = (int)x.size(0);\n int inC = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int kH = (int)weight.size(2);\n int kW = (int)weight.size(3);\n int stride = (int)stride64;\n int padding = (int)padding64;\n int output_padding = (int)output_padding64;\n int groups = (int)groups64;\n int outC = (int)weight.size(1) * groups;\n int OH = (H - 1) * stride - 2 * padding + kH + output_padding;\n int OW = (W - 1) * stride - 2 * padding + kW + output_padding;\n\n auto y = torch::empty({N, outC, OH, OW}, x.options());\n bool has_bias = bias.numel() > 0;\n const float* bp = has_bias ? bias.data_ptr<float>() : nullptr;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (inC == 32 && outC == 32 && kH == 3 && kW == 3 && stride == 1 && padding == 0 && output_padding == 0 && groups == 1) {\n constexpr int threads = 256;\n constexpr int warps_per_block = 8;\n long long nwarps = (long long)N * OH * OW;\n int blocks = (int)((nwarps + warps_per_block - 1) / warps_per_block);\n deconv_k3s1p0_c32_warp_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), N, H, W, OH, OW, has_bias);\n } else {\n const int threads = 256;\n long long total = (long long)N * outC * OH * OW;\n int blocks = (int)((total + threads - 1) / threads);\n deconv_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), total,\n N, inC, H, W, outC, OH, OW, kH, kW, stride, padding, groups, has_bias);\n }\n return y;\n}\n'''\n\n_ext = load_inline(\n name='conv_transpose2d_32_k3_ext',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['deconv_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, 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 if isinstance(stride, int) else stride[0]\n self.padding = padding if isinstance(padding, int) else padding[0]\n self.output_padding = output_padding if isinstance(output_padding, int) else output_padding[0]\n self.groups = groups\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n # The benchmark inputs and module parameters are contiguous. Keeping this\n # explicit also preserves correctness for non-contiguous callers.\n xc = x.contiguous()\n w = self.conv_transpose2d.weight.contiguous()\n b = self.conv_transpose2d.bias\n if b is None:\n b = torch.empty(0, device=xc.device, dtype=xc.dtype)\n else:\n b = b.contiguous()\n return _ext.deconv_forward(xc, w, b, int(self.stride), int(self.padding), int(self.output_padding), int(self.groups))\n"
}