call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_source = r'''\n#include <torch/extension.h>\n\ntorch::Tensor bn_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#ifndef CHECK_CUDA\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#endif\n\nstatic __inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1)\n val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n\nstatic __inline__ __device__ float block_reduce_sum(float val) {\n __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n\n__global__ void partial_stats_kernel(const float* __restrict__ x,\n float* __restrict__ psum,\n float* __restrict__ psq,\n int C, int S, int N, int P) {\n int c = blockIdx.x;\n int p = blockIdx.y;\n int tid = threadIdx.x;\n int64_t M = (int64_t)N * S;\n int64_t stride = (int64_t)P * blockDim.x;\n float sum = 0.0f;\n float sq = 0.0f;\n // S is 512*512 in the benchmark (power of two); division compiles efficiently for constant? still ok.\n for (int64_t i = (int64_t)p * blockDim.x + tid; i < M; i += stride) {\n int n = (int)(i / S);\n int s = (int)(i - (int64_t)n * S);\n float v = x[((int64_t)n * C + c) * S + s];\n sum += v;\n sq = fmaf(v, v, sq);\n }\n sum = block_reduce_sum(sum);\n sq = block_reduce_sum(sq);\n if (tid == 0) {\n psum[c * P + p] = sum;\n psq[c * P + p] = sq;\n }\n}\n\n__global__ void final_stats_kernel(const float* __restrict__ psum,\n const float* __restrict__ psq,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ running_mean,\n float* __restrict__ running_var,\n float* __restrict__ mean_out,\n float* __restrict__ inv_out,\n int C, int S, int N, int P,\n float momentum, float eps,\n bool update_running) {\n int c = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sq = 0.0f;\n for (int i = tid; i < P; i += blockDim.x) {\n sum += psum[c * P + i];\n sq += psq[c * P + i];\n }\n sum = block_reduce_sum(sum);\n sq = block_reduce_sum(sq);\n if (tid == 0) {\n float M = (float)((int64_t)N * S);\n float mean = sum / M;\n float var = fmaxf(sq / M - mean * mean, 0.0f);\n float inv = rsqrtf(var + eps);\n mean_out[c] = mean;\n inv_out[c] = inv;\n if (update_running) {\n float unbiased = var * (M / (M - 1.0f));\n running_mean[c] = running_mean[c] * (1.0f - momentum) + momentum * mean;\n running_var[c] = running_var[c] * (1.0f - momentum) + momentum * unbiased;\n }\n }\n}\n\n__global__ void normalize_train_kernel(const float* __restrict__ x,\n const float* __restrict__ mean,\n const float* __restrict__ inv,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int C, int S, int N, int Pout) {\n int c = blockIdx.x;\n int p = blockIdx.y;\n int tid = threadIdx.x;\n float m = mean[c];\n float scale = inv[c] * weight[c];\n float b = bias[c] - m * scale;\n int64_t M = (int64_t)N * S;\n int64_t stride = (int64_t)Pout * blockDim.x;\n for (int64_t i = (int64_t)p * blockDim.x + tid; i < M; i += stride) {\n int n = (int)(i / S);\n int s = (int)(i - (int64_t)n * S);\n int64_t off = ((int64_t)n * C + c) * S + s;\n y[off] = fmaf(x[off], scale, b);\n }\n}\n\n__global__ void normalize_eval_kernel(const float* __restrict__ x,\n const float* __restrict__ running_mean,\n const float* __restrict__ running_var,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int64_t total, int C, int S, float eps) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n int64_t stride = (int64_t)gridDim.x * blockDim.x;\n for (; idx < total; idx += stride) {\n int c = (int)((idx / S) % C);\n float scale = rsqrtf(running_var[c] + eps) * weight[c];\n float b = bias[c] - running_mean[c] * scale;\n y[idx] = fmaf(x[idx], scale, b);\n }\n}\n\ntorch::Tensor bn_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps) {\n CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(bias);\n TORCH_CHECK(x.scalar_type() == torch::kFloat32, \"only float32 supported\");\n TORCH_CHECK(x.dim() == 4, \"expected NCHW 4D\");\n auto y = torch::empty_like(x);\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 S = H * W;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const int threads = 256;\n if (training) {\n int P = (S + threads - 1) / threads;\n // cap/adjust partial count for unusual sizes; benchmark gives 1024.\n if (P < 1) P = 1;\n auto opts = x.options();\n auto psum = torch::empty({C, P}, opts);\n auto psq = torch::empty({C, P}, opts);\n auto mean = torch::empty({C}, opts);\n auto inv = torch::empty({C}, opts);\n dim3 grid1(C, P);\n partial_stats_kernel<<<grid1, threads, 0, stream>>>(x.data_ptr<float>(), psum.data_ptr<float>(), psq.data_ptr<float>(), C, S, N, P);\n final_stats_kernel<<<C, threads, 0, stream>>>(psum.data_ptr<float>(), psq.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(), mean.data_ptr<float>(), inv.data_ptr<float>(), C, S, N, P, (float)momentum, (float)eps, true);\n int Pout = 4096;\n dim3 grid2(C, Pout);\n normalize_train_kernel<<<grid2, threads, 0, stream>>>(x.data_ptr<float>(), mean.data_ptr<float>(), inv.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), y.data_ptr<float>(), C, S, N, Pout);\n } else {\n int64_t total = x.numel();\n int blocks = 4096;\n normalize_eval_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), y.data_ptr<float>(), total, C, S, (float)eps);\n }\n return y;\n}\n'''\n\n_bn_ext = load_inline(name='bn2d_custom_ext_v1', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['bn_forward'], extra_cuda_cflags=['-O3', '--use_fast_math'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_features: int):\n super(ModelNew, self).__init__()\n self.bn = nn.BatchNorm2d(num_features=num_features)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.bn.training:\n self.bn.num_batches_tracked.add_(1)\n return _bn_ext.bn_forward(x, self.bn.weight, self.bn.bias, self.bn.running_mean, self.bn.running_var,\n bool(self.bn.training), float(self.bn.momentum), float(self.bn.eps))\n"
}