call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n#include <vector>\n\nvoid gn_stats_cuda(torch::Tensor x, torch::Tensor stats, int64_t groups);\nvoid gn_pool_out_cuda(torch::Tensor x, torch::Tensor stats, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor scale, torch::Tensor out, int64_t groups, int64_t pool,\n double clamp_min, double clamp_max);\n\ntorch::Tensor gn_pool_forward(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor scale, int64_t groups, int64_t pool,\n double clamp_min, double clamp_max) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n TORCH_CHECK(gamma.is_cuda() && beta.is_cuda() && scale.is_cuda(), \"params must be CUDA\");\n const int64_t N = x.size(0);\n const int64_t C = x.size(1);\n const int64_t H = x.size(2);\n const int64_t W = x.size(3);\n const int64_t OH = (H - pool) / pool + 1;\n const int64_t OW = (W - pool) / pool + 1;\n auto stats = torch::empty({N, groups, 2}, x.options());\n auto out = torch::empty({N, C, OH, OW}, x.options());\n gn_stats_cuda(x, stats, groups);\n gn_pool_out_cuda(x, stats, gamma.contiguous(), beta.contiguous(), scale.contiguous(), out,\n groups, pool, clamp_min, clamp_max);\n return out;\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void gn_stats_kernel(const float* __restrict__ x, float* __restrict__ stats,\n int N, int C, int H, int W, int G) {\n const int bg = blockIdx.x;\n const int n = bg / G;\n const int g = bg - n * G;\n const int tid = threadIdx.x;\n const int HW = H * W;\n const int CG = C / G;\n const int total = CG * HW;\n float sum = 0.0f;\n float sum2 = 0.0f;\n const int c0 = g * CG;\n const int baseN = n * C * HW;\n\n for (int i = tid; i < total; i += blockDim.x) {\n int cg = i / HW;\n int hw = i - cg * HW;\n float v = x[baseN + (c0 + cg) * HW + hw];\n sum += v;\n sum2 += v * v;\n }\n\n __shared__ float ssum[256];\n __shared__ float ssq[256];\n ssum[tid] = sum;\n ssq[tid] = sum2;\n __syncthreads();\n\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) {\n ssum[tid] += ssum[tid + s];\n ssq[tid] += ssq[tid + s];\n }\n __syncthreads();\n }\n if (tid == 0) {\n float inv_count = 1.0f / (float)total;\n float mean = ssum[0] * inv_count;\n float var = ssq[0] * inv_count - mean * mean;\n var = var < 0.0f ? 0.0f : var;\n float invstd = rsqrtf(var + 1.0e-5f);\n int off = bg * 2;\n stats[off] = mean;\n stats[off + 1] = invstd;\n }\n}\n\n__global__ void gn_pool_out_kernel(const float* __restrict__ x, const float* __restrict__ stats,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n const float* __restrict__ scale, float* __restrict__ out,\n int N, int C, int H, int W, int G, int pool,\n int OH, int OW, float clamp_min, float clamp_max) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n const int64_t total = (int64_t)N * C * OH * OW;\n if (idx >= total) return;\n\n int ow = idx % OW;\n int64_t t = idx / OW;\n int oh = t % OH;\n t /= OH;\n int c = t % C;\n int n = t / C;\n\n int CG = C / G;\n int g = c / CG;\n int stat_off = (n * G + g) * 2;\n float mean = stats[stat_off];\n float invstd = stats[stat_off + 1];\n float gm = gamma[c];\n float bt = beta[c];\n float sc = scale[c];\n int HW = H * W;\n int base = (n * C + c) * HW + (oh * pool) * W + (ow * pool);\n\n float m = -FLT_MAX;\n #pragma unroll\n for (int ph = 0; ph < 4; ++ph) {\n #pragma unroll\n for (int pw = 0; pw < 4; ++pw) {\n float v = x[base + ph * W + pw];\n v = ((v - mean) * invstd * gm + bt) * sc;\n m = fmaxf(m, v);\n }\n }\n // Correct for non-4 pool sizes if ever used with same API.\n if (pool != 4) {\n m = -FLT_MAX;\n for (int ph = 0; ph < pool; ++ph) {\n for (int pw = 0; pw < pool; ++pw) {\n float v = x[base + ph * W + pw];\n v = ((v - mean) * invstd * gm + bt) * sc;\n m = fmaxf(m, v);\n }\n }\n }\n m = fminf(fmaxf(m, clamp_min), clamp_max);\n out[idx] = m;\n}\n\nvoid gn_stats_cuda(torch::Tensor x, torch::Tensor stats, int64_t groups) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const dim3 blocks(N * (int)groups);\n const dim3 threads(256);\n gn_stats_kernel<<<blocks, threads>>>(x.data_ptr<float>(), stats.data_ptr<float>(), N, C, H, W, (int)groups);\n}\n\nvoid gn_pool_out_cuda(torch::Tensor x, torch::Tensor stats, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor scale, torch::Tensor out, int64_t groups, int64_t pool,\n double clamp_min, double clamp_max) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int OH = (int)out.size(2);\n const int OW = (int)out.size(3);\n const int64_t total = (int64_t)N * C * OH * OW;\n const int threads = 256;\n const int blocks = (int)((total + threads - 1) / threads);\n gn_pool_out_kernel<<<blocks, threads>>>(x.data_ptr<float>(), stats.data_ptr<float>(),\n gamma.data_ptr<float>(), beta.data_ptr<float>(), scale.data_ptr<float>(), out.data_ptr<float>(),\n N, C, H, W, (int)groups, (int)pool, OH, OW, (float)clamp_min, (float)clamp_max);\n}\n'''\n\n_ext = load_inline(\n name=\"fused_gn_pool_clamp_ext_v1\",\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=[\"gn_pool_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n with_cuda=True,\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, num_groups, scale_shape,\n maxpool_kernel_size, clamp_min, clamp_max):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.group_norm = nn.GroupNorm(num_groups, out_channels)\n self.scale = nn.Parameter(torch.ones(scale_shape))\n self.maxpool_kernel_size = maxpool_kernel_size\n self.clamp_min = float(clamp_min)\n self.clamp_max = float(clamp_max)\n\n def forward(self, x):\n y = F.conv2d(x, self.conv.weight, self.conv.bias, stride=1, padding=0, dilation=1, groups=1)\n y = y.contiguous()\n return _ext.gn_pool_forward(y, self.group_norm.weight, self.group_norm.bias,\n self.scale, self.group_norm.num_groups,\n int(self.maxpool_kernel_size), self.clamp_min, self.clamp_max)\n"
}