call → compile_kernel
callcompile_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>\ntorch::Tensor fused_forward(torch::Tensor x, torch::Tensor w, torch::Tensor linear_bias,\n torch::Tensor bn_w, torch::Tensor bn_b,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cmath>\n\n__device__ __forceinline__ float gelu_relu_val(float z) {\n if (z <= 0.0f) return 0.0f;\n return 0.5f * z * (1.0f + erff(z * 0.70710678118654752440f));\n}\n\n__global__ void stats_warp32_kernel(const float* __restrict__ y,\n float* __restrict__ psum,\n float* __restrict__ psq,\n int B, int C, int splits, int rows_per_split) {\n int tile = blockIdx.x;\n int split = blockIdx.y;\n int lane = threadIdx.x;\n int c = tile * 32 + lane;\n if (c >= C) return;\n int r0 = split * rows_per_split;\n int r1 = min(B, r0 + rows_per_split);\n float s = 0.0f;\n float q = 0.0f;\n const float* ptr = y + (int64_t)r0 * C + c;\n for (int r = r0; r < r1; ++r) {\n float v = *ptr;\n s += v;\n q = fmaf(v, v, q);\n ptr += C;\n }\n int out = split * C + c;\n psum[out] = s;\n psq[out] = q;\n}\n\n__global__ void finalize_stats_kernel(const float* __restrict__ psum,\n const float* __restrict__ psq,\n float* __restrict__ mean,\n float* __restrict__ invstd,\n float* __restrict__ running_mean,\n float* __restrict__ running_var,\n int B, int C, int splits, float momentum, float eps) {\n int tile = blockIdx.x;\n int lane = threadIdx.x;\n int c = tile * 32 + lane;\n if (c >= C) return;\n float s = 0.0f, q = 0.0f;\n for (int sp = 0; sp < splits; ++sp) {\n int idx = sp * C + c;\n s += psum[idx];\n q += psq[idx];\n }\n float m = s / (float)B;\n float var = q / (float)B - m * m;\n var = fmaxf(var, 0.0f);\n float inv = rsqrtf(var + eps);\n mean[c] = m;\n invstd[c] = inv;\n running_mean[c] = running_mean[c] * (1.0f - momentum) + momentum * m;\n float unbiased = var * ((float)B / (float)(B - 1));\n running_var[c] = running_var[c] * (1.0f - momentum) + momentum * unbiased;\n}\n\n__global__ void apply_train_bn_gelu_kernel(float* __restrict__ y,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ invstd,\n int B, int C, int rows_per_chunk) {\n int tile = blockIdx.x;\n int chunk = blockIdx.y;\n int lane = threadIdx.x;\n int c = tile * 32 + lane;\n if (c >= C) return;\n float g = gamma[c];\n float be = beta[c];\n float m = mean[c];\n float inv = invstd[c];\n int r0 = chunk * rows_per_chunk;\n int r1 = min(B, r0 + rows_per_chunk);\n float* ptr = y + (int64_t)r0 * C + c;\n for (int r = r0; r < r1; ++r) {\n float z = ((*ptr - m) * inv) * g + be;\n *ptr = gelu_relu_val(z);\n ptr += C;\n }\n}\n\n__global__ void bn_gelu_relu_kernel(float* __restrict__ y,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n int64_t total, int C, float eps) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n int64_t stride = (int64_t)blockDim.x * gridDim.x;\n for (; idx < total; idx += stride) {\n int c = (C == 4096) ? (int)(idx & 4095) : (int)(idx % C);\n float z = (y[idx] - mean[c]) * rsqrtf(var[c] + eps) * gamma[c] + beta[c];\n y[idx] = gelu_relu_val(z);\n }\n}\n\n__global__ void gelu_relu_kernel(float* __restrict__ y, int64_t total) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n int64_t stride = (int64_t)blockDim.x * gridDim.x;\n for (; idx < total; idx += stride) y[idx] = gelu_relu_val(y[idx]);\n}\n\nvoid launch_eval(torch::Tensor y, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor mean, torch::Tensor var, double eps) {\n int64_t total = y.numel(); int C = (int)y.size(1);\n int threads = 256;\n int blocks = (int)std::min<int64_t>((total + threads - 1) / threads, 65535);\n bn_gelu_relu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n y.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), total, C, (float)eps);\n}\n\nvoid launch_gelu(torch::Tensor y) {\n int64_t total = y.numel(); int threads = 256;\n int blocks = (int)std::min<int64_t>((total + threads - 1) / threads, 65535);\n gelu_relu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(y.data_ptr<float>(), total);\n}\n\nvoid launch_train_custom(torch::Tensor y, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor running_mean, torch::Tensor running_var,\n double momentum, double eps) {\n int B = (int)y.size(0);\n int C = (int)y.size(1);\n const int splits = 16;\n const int rows_per_split = (B + splits - 1) / splits;\n auto opts = y.options();\n auto psum = torch::empty({splits, C}, opts);\n auto psq = torch::empty({splits, C}, opts);\n auto mean = torch::empty({C}, opts);\n auto invstd = torch::empty({C}, opts);\n dim3 grid_stats((C + 31) / 32, splits);\n stats_warp32_kernel<<<grid_stats, 32, 0, at::cuda::getCurrentCUDAStream()>>>(\n y.data_ptr<float>(), psum.data_ptr<float>(), psq.data_ptr<float>(), B, C, splits, rows_per_split);\n finalize_stats_kernel<<<(C + 31) / 32, 32, 0, at::cuda::getCurrentCUDAStream()>>>(\n psum.data_ptr<float>(), psq.data_ptr<float>(), mean.data_ptr<float>(), invstd.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(), B, C, splits, (float)momentum, (float)eps);\n const int rows_per_chunk = 128;\n dim3 grid_apply((C + 31) / 32, (B + rows_per_chunk - 1) / rows_per_chunk);\n apply_train_bn_gelu_kernel<<<grid_apply, 32, 0, at::cuda::getCurrentCUDAStream()>>>(\n y.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), mean.data_ptr<float>(), invstd.data_ptr<float>(),\n B, C, rows_per_chunk);\n}\n\ntorch::Tensor fused_forward(torch::Tensor x, torch::Tensor w, torch::Tensor linear_bias,\n torch::Tensor bn_w, torch::Tensor bn_b,\n torch::Tensor running_mean, torch::Tensor running_var,\n bool training, double momentum, double eps) {\n auto y = at::linear(x, w, linear_bias);\n if (training && y.scalar_type() == at::kFloat && y.dim() == 2 && ((int)y.size(1) % 32 == 0)) {\n launch_train_custom(y, bn_w, bn_b, running_mean, running_var, momentum, eps);\n } else if (training) {\n y = at::batch_norm(y, bn_w, bn_b, running_mean, running_var, true, momentum, eps, true);\n launch_gelu(y);\n } else {\n launch_eval(y, bn_w, bn_b, running_mean, running_var, eps);\n }\n return y;\n}\n'''\n\n_ext = load_inline(name='fused_linear_bn_gelu_relu_ext_v3',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['fused_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_features, out_features):\n super(ModelNew, self).__init__()\n self.gemm = nn.Linear(in_features, out_features)\n self.batch_norm = nn.BatchNorm1d(out_features)\n\n def forward(self, x):\n mom = self.batch_norm.momentum\n if mom is None:\n mom = 0.1\n return _ext.fused_forward(x, self.gemm.weight, self.gemm.bias,\n self.batch_norm.weight, self.batch_norm.bias,\n self.batch_norm.running_mean, self.batch_norm.running_var,\n self.training, float(mom), float(self.batch_norm.eps))\n"
}