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_transpose_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t dilation);\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__global__ void fill_bias_kernel(float* __restrict__ out, const float* __restrict__ bias,\n long long total, int Cout, int HWout) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long step = (long long)blockDim.x * gridDim.x;\n for (; idx < total; idx += step) {\n int oc = (idx / HWout) % Cout;\n out[idx] = bias[oc];\n }\n}\n\n// Specialized for the benchmark shape: Cin=32, Cout=64, K=3, stride=5, pad=1, dilation=2.\n// One block computes all 64*3*3 non-zero values generated by one input pixel.\n__global__ void deconv2d_s5p1d2_k3_c32_c64_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n float* __restrict__ out,\n int N, int H, int W,\n int Hout, int Wout,\n bool has_bias) {\n int sp = blockIdx.x;\n int iw = sp % W;\n int t = sp / W;\n int ih = t % H;\n int n = t / H;\n\n __shared__ float sx[32];\n if (threadIdx.x < 32) {\n sx[threadIdx.x] = x[((n * 32 + threadIdx.x) * H + ih) * W + iw];\n }\n __syncthreads();\n\n // idx = oc*9 + kh*3 + kw, matching contiguous weight layout for each input channel.\n for (int idx = threadIdx.x; idx < 576; idx += blockDim.x) {\n int k = idx - (idx / 9) * 9;\n int oc = idx / 9;\n int kh = k / 3;\n int kw = k - kh * 3;\n int oh = ih * 5 - 1 + kh * 2;\n int ow = iw * 5 - 1 + kw * 2;\n if ((unsigned)oh < (unsigned)Hout && (unsigned)ow < (unsigned)Wout) {\n float sum = 0.0f;\n #pragma unroll\n for (int c = 0; c < 32; ++c) {\n sum = fmaf(sx[c], w[c * 576 + idx], sum);\n }\n long long oidx = (((long long)n * 64 + oc) * Hout + oh) * Wout + ow;\n if (has_bias) out[oidx] += sum;\n else out[oidx] = sum;\n }\n }\n}\n\n__global__ void deconv2d_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n float* __restrict__ out,\n int N, int Cin, int H, int W,\n int Cout, int K, int stride, int pad, int dil,\n int Hout, int Wout,\n bool has_bias, bool use_atomic) {\n int sp = blockIdx.x;\n int iw = sp % W;\n int tmp = sp / W;\n int ih = tmp % H;\n int n = tmp / H;\n\n extern __shared__ float sx[];\n for (int c = threadIdx.x; c < Cin; c += blockDim.x) {\n sx[c] = x[((n * Cin + c) * H + ih) * W + iw];\n }\n __syncthreads();\n\n int KK = K * K;\n int total = Cout * KK;\n for (int idx = threadIdx.x; idx < total; idx += blockDim.x) {\n int kk = idx % KK;\n int oc = idx / KK;\n int kh = kk / K;\n int kw = kk - kh * K;\n int oh = ih * stride - pad + kh * dil;\n int ow = iw * stride - pad + kw * dil;\n if ((unsigned)oh < (unsigned)Hout && (unsigned)ow < (unsigned)Wout) {\n float sum = 0.0f;\n for (int c = 0; c < Cin; ++c) {\n sum = fmaf(sx[c], w[((c * Cout + oc) * K + kh) * K + kw], sum);\n }\n long long oidx = (((long long)n * Cout + oc) * Hout + oh) * Wout + ow;\n if (use_atomic) {\n atomicAdd(out + oidx, sum);\n } else {\n if (has_bias) out[oidx] += sum;\n else out[oidx] = sum;\n }\n }\n }\n}\n\ntorch::Tensor conv_transpose_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride64, int64_t padding64, int64_t dilation64) {\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 Cout = (int)weight.size(1);\n const int K = (int)weight.size(2);\n const int stride = (int)stride64;\n const int pad = (int)padding64;\n const int dil = (int)dilation64;\n const int Hout = (H - 1) * stride - 2 * pad + dil * (K - 1) + 1;\n const int Wout = (W - 1) * stride - 2 * pad + dil * (K - 1) + 1;\n\n auto out = torch::empty({N, Cout, Hout, Wout}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const bool has_bias = (bias.numel() != 0);\n long long total_out = (long long)N * Cout * Hout * Wout;\n\n if (has_bias) {\n int threads = 256;\n int blocks = (int)min(65535LL, (total_out + threads - 1) / threads);\n fill_bias_kernel<<<blocks, threads, 0, stream>>>(out.data_ptr<float>(), bias.data_ptr<float>(), total_out, Cout, Hout * Wout);\n } else {\n cudaMemsetAsync(out.data_ptr<float>(), 0, total_out * sizeof(float), stream);\n }\n\n int blocks_sp = N * H * W;\n int threads = 256;\n if (Cin == 32 && Cout == 64 && K == 3 && stride == 5 && pad == 1 && dil == 2) {\n deconv2d_s5p1d2_k3_c32_c64_kernel<<<blocks_sp, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), out.data_ptr<float>(), N, H, W, Hout, Wout, has_bias);\n } else {\n // Spatial overlap occurs when adjacent input pixels can write the same output pixel.\n bool use_atomic = (stride <= dil * (K - 1));\n deconv2d_generic_kernel<<<blocks_sp, threads, (size_t)Cin * sizeof(float), stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), out.data_ptr<float>(),\n N, Cin, H, W, Cout, K, stride, pad, dil, Hout, Wout, has_bias, use_atomic);\n }\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"deconv2d_transpose_sparse_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"conv_transpose_forward\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\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, 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, bias=bias)\n self.stride = stride\n self.padding = padding\n self.dilation = dilation\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_transpose_forward(x, self.conv_transpose2d.weight, b, self.stride, self.padding, self.dilation)\n"
}