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 trans_forward_cuda(torch::Tensor x,\n torch::Tensor bn_weight,\n torch::Tensor bn_bias,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor conv_weight,\n bool training,\n double momentum,\n double eps);\n\ntorch::Tensor trans_forward(torch::Tensor x,\n torch::Tensor bn_weight,\n torch::Tensor bn_bias,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor conv_weight,\n bool training,\n double momentum,\n double eps) {\n return trans_forward_cuda(x, bn_weight, bn_bias, running_mean, running_var,\n conv_weight, training, momentum, eps);\n}\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 SP_TILE 16\n#define CO_TILE 32\n#define CIN_FIXED 32\n#define BPC 256\n\n__global__ void eval_scale_shift_kernel(const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ rmean,\n const float* __restrict__ rvar,\n float* __restrict__ scale,\n float* __restrict__ shift,\n float eps, int C) {\n int c = blockIdx.x * blockDim.x + threadIdx.x;\n if (c < C) {\n float sc = gamma[c] * rsqrtf(rvar[c] + eps);\n scale[c] = sc;\n shift[c] = beta[c] - rmean[c] * sc;\n }\n}\n\n__global__ void reduce_sum_sumsq_kernel(const float* __restrict__ x,\n double* __restrict__ psum,\n double* __restrict__ psq,\n int N, int C, int H, int W) {\n int c = blockIdx.x;\n int b = blockIdx.y;\n long long HW = (long long)H * W;\n long long M = (long long)N * HW;\n double sum = 0.0;\n double sq = 0.0;\n for (long long m = (long long)b * blockDim.x + threadIdx.x; m < M; m += (long long)BPC * blockDim.x) {\n long long n = m / HW;\n long long hw = m - n * HW;\n float v = x[n * (long long)C * HW + c * HW + hw];\n sum += (double)v;\n sq += (double)v * (double)v;\n }\n __shared__ double ssum[256];\n __shared__ double ssq[256];\n ssum[threadIdx.x] = sum;\n ssq[threadIdx.x] = sq;\n __syncthreads();\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n ssum[threadIdx.x] += ssum[threadIdx.x + stride];\n ssq[threadIdx.x] += ssq[threadIdx.x + stride];\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) {\n psum[c * BPC + b] = ssum[0];\n psq[c * BPC + b] = ssq[0];\n }\n}\n\n__global__ void train_scale_shift_kernel(const double* __restrict__ psum,\n const double* __restrict__ psq,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ running_mean,\n float* __restrict__ running_var,\n float* __restrict__ scale,\n float* __restrict__ shift,\n int N, int H, int W,\n float momentum, float eps, int C) {\n int c = blockIdx.x;\n __shared__ double ssum[256];\n __shared__ double ssq[256];\n double a = (threadIdx.x < BPC) ? psum[c * BPC + threadIdx.x] : 0.0;\n double b = (threadIdx.x < BPC) ? psq[c * BPC + threadIdx.x] : 0.0;\n ssum[threadIdx.x] = a;\n ssq[threadIdx.x] = b;\n __syncthreads();\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n ssum[threadIdx.x] += ssum[threadIdx.x + stride];\n ssq[threadIdx.x] += ssq[threadIdx.x + stride];\n }\n __syncthreads();\n }\n if (threadIdx.x == 0) {\n double M = (double)N * (double)H * (double)W;\n double mean = ssum[0] / M;\n double var = ssq[0] / M - mean * mean;\n if (var < 0.0) var = 0.0;\n float inv = rsqrtf((float)var + eps);\n float sc = gamma[c] * inv;\n scale[c] = sc;\n shift[c] = beta[c] - (float)mean * sc;\n // PyTorch BatchNorm running_var uses the unbiased variance estimate.\n float unb = (float)(var * (M / (M - 1.0)));\n running_mean[c] = running_mean[c] * (1.0f - momentum) + momentum * (float)mean;\n running_var[c] = running_var[c] * (1.0f - momentum) + momentum * unb;\n }\n}\n\n__global__ void fused_pool_conv_kernel(const float* __restrict__ x,\n const float* __restrict__ scale,\n const float* __restrict__ shift,\n const float* __restrict__ w,\n float* __restrict__ out,\n int N, int H, int W, int Cout) {\n __shared__ float act[SP_TILE * CIN_FIXED];\n __shared__ float wt[CO_TILE * CIN_FIXED];\n\n const int tx = threadIdx.x; // spatial row within tile: 0..15\n const int ty = threadIdx.y; // output channel within tile: 0..31\n const int tid = ty * SP_TILE + tx;\n\n const int OH = H >> 1;\n const int OW = W >> 1;\n const int OHW = OH * OW;\n const int S = N * OHW;\n const int spatial_base = blockIdx.x * SP_TILE;\n const int co_base = blockIdx.y * CO_TILE;\n\n // Load pooled BN+ReLU activations. Layout is act[spatial][ci].\n if (tid < SP_TILE * CIN_FIXED) {\n int ci = tid / SP_TILE;\n int sr = tid - ci * SP_TILE;\n int s = spatial_base + sr;\n float av = 0.0f;\n if (s < S) {\n int n = s / OHW;\n int r = s - n * OHW;\n int oh = r / OW;\n int ow = r - oh * OW;\n long long base = ((long long)n * CIN_FIXED + ci) * (long long)H * W + (long long)(oh << 1) * W + (ow << 1);\n float sc = scale[ci];\n float sh = shift[ci];\n float v0 = fmaf(sc, x[base], sh); v0 = v0 > 0.0f ? v0 : 0.0f;\n float v1 = fmaf(sc, x[base + 1], sh); v1 = v1 > 0.0f ? v1 : 0.0f;\n float v2 = fmaf(sc, x[base + W], sh); v2 = v2 > 0.0f ? v2 : 0.0f;\n float v3 = fmaf(sc, x[base + W + 1], sh); v3 = v3 > 0.0f ? v3 : 0.0f;\n av = (v0 + v1 + v2 + v3) * 0.25f;\n }\n act[sr * CIN_FIXED + ci] = av;\n }\n\n // Load a 32x32 weight tile, w is [Cout, 32, 1, 1].\n for (int k = tid; k < CO_TILE * CIN_FIXED; k += SP_TILE * CO_TILE) {\n int lco = k / CIN_FIXED;\n int ci = k - lco * CIN_FIXED;\n int co = co_base + lco;\n wt[lco * CIN_FIXED + ci] = (co < Cout) ? w[co * CIN_FIXED + ci] : 0.0f;\n }\n __syncthreads();\n\n int s = spatial_base + tx;\n int co = co_base + ty;\n if (s < S && co < Cout) {\n float sum = 0.0f;\n #pragma unroll\n for (int ci = 0; ci < CIN_FIXED; ++ci) {\n sum = fmaf(act[tx * CIN_FIXED + ci], wt[ty * CIN_FIXED + ci], sum);\n }\n int n = s / OHW;\n int r = s - n * OHW;\n out[((long long)n * Cout + co) * (long long)OHW + r] = sum;\n }\n}\n\ntorch::Tensor trans_forward_cuda(torch::Tensor x,\n torch::Tensor bn_weight,\n torch::Tensor bn_bias,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor conv_weight,\n bool training,\n double momentum,\n double eps) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == torch::kFloat32, \"only float32 supported\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous NCHW\");\n TORCH_CHECK(conv_weight.is_contiguous(), \"conv weight must be contiguous\");\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int Cout = (int)conv_weight.size(0);\n TORCH_CHECK(C == CIN_FIXED, \"this optimized kernel expects 32 input channels\");\n TORCH_CHECK((H % 2) == 0 && (W % 2) == 0, \"H and W must be even\");\n\n c10::cuda::CUDAGuard device_guard(x.device());\n auto out = torch::empty({N, Cout, H / 2, W / 2}, x.options());\n auto scale = torch::empty({C}, x.options());\n auto shift = torch::empty({C}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (training) {\n auto dopt = x.options().dtype(torch::kFloat64);\n auto psum = torch::empty({C, BPC}, dopt);\n auto psq = torch::empty({C, BPC}, dopt);\n dim3 rg(C, BPC);\n reduce_sum_sumsq_kernel<<<rg, 256, 0, stream>>>(x.data_ptr<float>(), psum.data_ptr<double>(), psq.data_ptr<double>(), N, C, H, W);\n train_scale_shift_kernel<<<C, 256, 0, stream>>>(psum.data_ptr<double>(), psq.data_ptr<double>(),\n bn_weight.data_ptr<float>(), bn_bias.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(),\n scale.data_ptr<float>(), shift.data_ptr<float>(), N, H, W, (float)momentum, (float)eps, C);\n } else {\n eval_scale_shift_kernel<<<1, 64, 0, stream>>>(bn_weight.data_ptr<float>(), bn_bias.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), (float)eps, C);\n }\n\n int OH = H / 2, OW = W / 2;\n int S = N * OH * OW;\n dim3 block(SP_TILE, CO_TILE);\n dim3 grid((S + SP_TILE - 1) / SP_TILE, (Cout + CO_TILE - 1) / CO_TILE);\n fused_pool_conv_kernel<<<grid, block, 0, stream>>>(x.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(),\n conv_weight.data_ptr<float>(), out.data_ptr<float>(), N, H, W, Cout);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return out;\n}\n'''\n\n_ext = load_inline(\n name=\"transition_fused_pool_conv_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"trans_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, num_input_features: int, num_output_features: int):\n super(ModelNew, self).__init__()\n self.transition = nn.Sequential(\n nn.BatchNorm2d(num_input_features),\n nn.ReLU(inplace=True),\n nn.Conv2d(num_input_features, num_output_features, kernel_size=1, bias=False),\n nn.AvgPool2d(kernel_size=2, stride=2),\n )\n\n def forward(self, x):\n bn = self.transition[0]\n conv = self.transition[2]\n if self.training and bn.track_running_stats:\n bn.num_batches_tracked.add_(1)\n mom = 0.1 if bn.momentum is None else float(bn.momentum)\n return _ext.trans_forward(x, bn.weight, bn.bias, bn.running_mean, bn.running_var,\n conv.weight, bool(self.training), mom, float(bn.eps))\n"
}