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#include <ATen/ATen.h>\n#include <ATen/ops/linear.h>\n\nvoid postprocess_launch(torch::Tensor y, torch::Tensor bias, torch::Tensor gn_weight, torch::Tensor gn_bias, int64_t num_groups);\n\ntorch::Tensor fused_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor lin_bias,\n torch::Tensor bias,\n torch::Tensor gn_weight,\n torch::Tensor gn_bias,\n int64_t num_groups) {\n // Use the same cuBLAS/ATen GEMM path as PyTorch for numerical parity, then\n // fuse all remaining elementwise ops and per-(N,group) normalization below.\n auto y = at::linear(x, weight, lin_bias);\n postprocess_launch(y, bias, gn_weight, gn_bias, num_groups);\n return y;\n}\n'''\n\n_cuda_src = r'''\n#include <ATen/ATen.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <stdint.h>\n\nstatic __device__ __forceinline__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v += __shfl_down_sync(0xffffffff, v, offset);\n }\n return v;\n}\n\n__global__ void postprocess_gn32_kernel(float* __restrict__ y,\n const float* __restrict__ bias,\n const float* __restrict__ gn_weight,\n const float* __restrict__ gn_bias,\n int N, int C, int G) {\n // One warp computes one group of one batch item. For the benchmark\n // C=8192,G=256, so group size is exactly 32.\n const int n = blockIdx.y;\n const int g = blockIdx.x;\n const int lane = threadIdx.x;\n const int group_size = C / G;\n const int c = g * group_size + lane;\n\n float v = 0.0f;\n if (lane < group_size) {\n const int idx = n * C + c;\n v = y[idx] + bias[c];\n // Hardtanh default range [-1, 1]\n v = fminf(1.0f, fmaxf(-1.0f, v));\n // Mish: x * tanh(softplus(x)); x is already in [-1,1].\n v = v * tanhf(log1pf(expf(v)));\n }\n\n float sum = warp_sum(v);\n float sum2 = warp_sum(v * v);\n float mean = sum * (1.0f / (float)group_size);\n float var = sum2 * (1.0f / (float)group_size) - mean * mean;\n var = fmaxf(var, 0.0f);\n float inv_std = rsqrtf(var + 1.0e-5f);\n\n if (lane < group_size) {\n y[n * C + c] = (v - mean) * inv_std * gn_weight[c] + gn_bias[c];\n }\n}\n\n// A generic-but-still-warp based version for safety if constructor arguments vary.\n__global__ void postprocess_gn_generic_kernel(float* __restrict__ y,\n const float* __restrict__ bias,\n const float* __restrict__ gn_weight,\n const float* __restrict__ gn_bias,\n int N, int C, int G) {\n const int n = blockIdx.y;\n const int g = blockIdx.x;\n const int tid = threadIdx.x;\n const int group_size = C / G;\n const int base = n * C + g * group_size;\n\n float sum = 0.0f;\n float sum2 = 0.0f;\n for (int i = tid; i < group_size; i += blockDim.x) {\n int c = g * group_size + i;\n float v = y[base + i] + bias[c];\n v = fminf(1.0f, fmaxf(-1.0f, v));\n v = v * tanhf(log1pf(expf(v)));\n sum += v;\n sum2 += v * v;\n }\n __shared__ float smem[64];\n // reduce within block (blockDim <= 256 expected)\n for (int offset = 16; offset > 0; offset >>= 1) {\n sum += __shfl_down_sync(0xffffffff, sum, offset);\n sum2 += __shfl_down_sync(0xffffffff, sum2, offset);\n }\n int warp = tid >> 5;\n int lane = tid & 31;\n if (lane == 0) { smem[warp] = sum; smem[warp + 32] = sum2; }\n __syncthreads();\n if (warp == 0) {\n sum = (lane < ((blockDim.x + 31) >> 5)) ? smem[lane] : 0.0f;\n sum2 = (lane < ((blockDim.x + 31) >> 5)) ? smem[lane + 32] : 0.0f;\n for (int offset = 16; offset > 0; offset >>= 1) {\n sum += __shfl_down_sync(0xffffffff, sum, offset);\n sum2 += __shfl_down_sync(0xffffffff, sum2, offset);\n }\n if (lane == 0) { smem[0] = sum; smem[1] = sum2; }\n }\n __syncthreads();\n float mean = smem[0] / (float)group_size;\n float var = smem[1] / (float)group_size - mean * mean;\n float inv_std = rsqrtf(fmaxf(var, 0.0f) + 1.0e-5f);\n for (int i = tid; i < group_size; i += blockDim.x) {\n int c = g * group_size + i;\n float v = y[base + i] + bias[c];\n v = fminf(1.0f, fmaxf(-1.0f, v));\n v = v * tanhf(log1pf(expf(v)));\n y[base + i] = (v - mean) * inv_std * gn_weight[c] + gn_bias[c];\n }\n}\n\nvoid postprocess_launch(torch::Tensor y, torch::Tensor bias, torch::Tensor gn_weight, torch::Tensor gn_bias, int64_t num_groups) {\n const int N = (int)y.size(0);\n const int C = (int)y.size(1);\n const int G = (int)num_groups;\n dim3 grid(G, N, 1);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (C / G == 32) {\n postprocess_gn32_kernel<<<grid, 32, 0, stream>>>(\n y.data_ptr<float>(), bias.data_ptr<float>(), gn_weight.data_ptr<float>(), gn_bias.data_ptr<float>(), N, C, G);\n } else {\n int gs = C / G;\n int threads = 32;\n if (gs > 32) threads = 64;\n if (gs > 64) threads = 128;\n if (gs > 128) threads = 256;\n postprocess_gn_generic_kernel<<<grid, threads, 0, stream>>>(\n y.data_ptr<float>(), bias.data_ptr<float>(), gn_weight.data_ptr<float>(), gn_bias.data_ptr<float>(), N, C, G);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n}\n'''\n\n_ext = load_inline(\n name='fused_linear_mish_groupnorm_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['fused_forward'],\n with_cuda=True,\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Fused implementation of: Linear -> add bias -> Hardtanh -> Mish -> GroupNorm.\n \"\"\"\n def __init__(self, in_features, out_features, bias_shape, num_groups):\n super(ModelNew, self).__init__()\n self.gemm = nn.Linear(in_features, out_features)\n self.bias = nn.Parameter(torch.randn(bias_shape))\n self.hardtanh = nn.Hardtanh()\n self.mish = nn.Mish()\n self.groupnorm = nn.GroupNorm(num_groups=num_groups, num_channels=out_features)\n\n def forward(self, x):\n return _ext.fused_forward(\n x,\n self.gemm.weight,\n self.gemm.bias,\n self.bias,\n self.groupnorm.weight,\n self.groupnorm.bias,\n self.groupnorm.num_groups,\n )\n"
}