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 bn_softmax_cuda(torch::Tensor x,\n torch::Tensor gamma,\n torch::Tensor beta,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor scale,\n double eps,\n double momentum,\n bool training);\n\ntorch::Tensor bn_softmax_forward(torch::Tensor x,\n torch::Tensor gamma,\n torch::Tensor beta,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor scale,\n double eps,\n double momentum,\n bool training) {\n return bn_softmax_cuda(x, gamma, beta, running_mean, running_var, scale, eps, momentum, training);\n}\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#include <cfloat>\n\n__global__ void bn_stats_kernel(const float* __restrict__ x,\n float* __restrict__ mean,\n float* __restrict__ invstd,\n float* __restrict__ running_mean,\n float* __restrict__ running_var,\n int N, int C, float eps, float momentum) {\n int tx = threadIdx.x; // column inside tile, 0..31\n int ty = threadIdx.y; // reducer lane over rows, 0..7\n int col = blockIdx.x * 32 + tx;\n\n float s = 0.0f;\n float q = 0.0f;\n if (col < C) {\n for (int r = ty; r < N; r += 8) {\n float v = x[(long long)r * C + col];\n s += v;\n q += v * v;\n }\n }\n\n __shared__ float sh_s[8][32];\n __shared__ float sh_q[8][32];\n sh_s[ty][tx] = s;\n sh_q[ty][tx] = q;\n __syncthreads();\n\n if (ty == 0 && col < C) {\n float sum = 0.0f;\n float ssq = 0.0f;\n #pragma unroll\n for (int k = 0; k < 8; ++k) {\n sum += sh_s[k][tx];\n ssq += sh_q[k][tx];\n }\n float m = sum / (float)N;\n float var = ssq / (float)N - m * m;\n var = var < 0.0f ? 0.0f : var;\n mean[col] = m;\n invstd[col] = rsqrtf(var + eps);\n\n float unbiased = var * ((float)N / (float)(N - 1));\n running_mean[col] = running_mean[col] * (1.0f - momentum) + momentum * m;\n running_var[col] = running_var[col] * (1.0f - momentum) + momentum * unbiased;\n }\n}\n\n__device__ __forceinline__ float block_reduce_max(float v, float* smem) {\n int tid = threadIdx.x;\n smem[tid] = v;\n __syncthreads();\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (tid < stride) {\n float other = smem[tid + stride];\n smem[tid] = smem[tid] > other ? smem[tid] : other;\n }\n __syncthreads();\n }\n return smem[0];\n}\n\n__device__ __forceinline__ float block_reduce_sum(float v, float* smem) {\n int tid = threadIdx.x;\n smem[tid] = v;\n __syncthreads();\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (tid < stride) smem[tid] += smem[tid + stride];\n __syncthreads();\n }\n return smem[0];\n}\n\n__global__ void softmax_train_kernel(const float* __restrict__ x,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ invstd,\n const float* __restrict__ scale,\n float* __restrict__ out,\n int N, int C) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sc = scale[0];\n extern __shared__ float smem[];\n\n float mx = -FLT_MAX;\n long long base = (long long)row * C;\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - mean[c]) * invstd[c] * gamma[c] + beta[c]) * sc;\n mx = mx > z ? mx : z;\n }\n mx = block_reduce_max(mx, smem);\n\n float ss = 0.0f;\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - mean[c]) * invstd[c] * gamma[c] + beta[c]) * sc;\n ss += __expf(z - mx);\n }\n ss = block_reduce_sum(ss, smem);\n float inv = 1.0f / ss;\n\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - mean[c]) * invstd[c] * gamma[c] + beta[c]) * sc;\n out[base + c] = __expf(z - mx) * inv;\n }\n}\n\n__global__ void softmax_eval_kernel(const float* __restrict__ x,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ running_mean,\n const float* __restrict__ running_var,\n const float* __restrict__ scale,\n float* __restrict__ out,\n int N, int C, float eps) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sc = scale[0];\n extern __shared__ float smem[];\n\n float mx = -FLT_MAX;\n long long base = (long long)row * C;\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - running_mean[c]) * rsqrtf(running_var[c] + eps) * gamma[c] + beta[c]) * sc;\n mx = mx > z ? mx : z;\n }\n mx = block_reduce_max(mx, smem);\n\n float ss = 0.0f;\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - running_mean[c]) * rsqrtf(running_var[c] + eps) * gamma[c] + beta[c]) * sc;\n ss += __expf(z - mx);\n }\n ss = block_reduce_sum(ss, smem);\n float inv = 1.0f / ss;\n\n for (int c = tid; c < C; c += blockDim.x) {\n float z = ((x[base + c] - running_mean[c]) * rsqrtf(running_var[c] + eps) * gamma[c] + beta[c]) * sc;\n out[base + c] = __expf(z - mx) * inv;\n }\n}\n\ntorch::Tensor bn_softmax_cuda(torch::Tensor x,\n torch::Tensor gamma,\n torch::Tensor beta,\n torch::Tensor running_mean,\n torch::Tensor running_var,\n torch::Tensor scale,\n double eps,\n double momentum,\n bool training) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n auto out = torch::empty_like(x);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n const int threads = 256;\n const size_t shmem = threads * sizeof(float);\n\n if (training) {\n auto mean = torch::empty({C}, x.options());\n auto invstd = torch::empty({C}, x.options());\n dim3 block_stats(32, 8);\n dim3 grid_stats((C + 31) / 32);\n bn_stats_kernel<<<grid_stats, block_stats, 0, stream>>>(\n x.data_ptr<float>(), mean.data_ptr<float>(), invstd.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(),\n N, C, (float)eps, (float)momentum);\n softmax_train_kernel<<<N, threads, shmem, stream>>>(\n x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n mean.data_ptr<float>(), invstd.data_ptr<float>(), scale.data_ptr<float>(),\n out.data_ptr<float>(), N, C);\n } else {\n softmax_eval_kernel<<<N, threads, shmem, stream>>>(\n x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(), scale.data_ptr<float>(),\n out.data_ptr<float>(), N, C, (float)eps);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return out;\n}\n'''\n\n_ext = load_inline(\n name='gemm_bn_scale_softmax_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['bn_softmax_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n \"\"\"Fused replacement for Linear -> BatchNorm1d -> scalar scale -> Softmax.\"\"\"\n def __init__(self, in_features, out_features, bn_eps=1e-5, bn_momentum=0.1, scale_shape=(1,)):\n super(ModelNew, self).__init__()\n self.gemm = nn.Linear(in_features, out_features)\n self.bn = nn.BatchNorm1d(out_features, eps=bn_eps, momentum=bn_momentum)\n self.scale = nn.Parameter(torch.ones(scale_shape))\n\n def forward(self, x):\n y = torch.nn.functional.linear(x, self.gemm.weight, self.gemm.bias)\n training = bool(self.training and self.bn.training and self.bn.track_running_stats)\n if training:\n self.bn.num_batches_tracked.add_(1)\n if self.bn.momentum is None:\n mom = 1.0 / float(self.bn.num_batches_tracked.item())\n else:\n mom = float(self.bn.momentum)\n else:\n mom = float(self.bn.momentum if self.bn.momentum is not None else 0.0)\n return _ext.bn_softmax_forward(y, self.bn.weight, self.bn.bias,\n self.bn.running_mean, self.bn.running_var,\n self.scale, float(self.bn.eps), mom, training)\n"
}