call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n\ntorch::Tensor mish_bn_forward_cuda(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\ntorch::Tensor mish_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 return mish_bn_forward_cuda(x, weight, bias, running_mean, running_var, training, momentum, eps);\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <ATen/cuda/CUDAContext.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 __device__ __forceinline__ float mish_f(float v) {\n float sp = (v > 20.0f) ? v : log1pf(expf(v));\n return v * tanhf(sp);\n}\n\ntemplate<int TPB>\n__global__ void mish_partials_kernel(const float* __restrict__ x, float* __restrict__ act,\n float* __restrict__ psum, float* __restrict__ psq,\n int N, int C, int HW, int parts) {\n int c = blockIdx.x;\n int p = blockIdx.y;\n int tid = threadIdx.x;\n int M = N * HW;\n int chunk = (M + parts - 1) / parts;\n int start = p * chunk;\n int end = start + chunk;\n if (end > M) end = M;\n\n float s = 0.0f, q = 0.0f;\n for (int k = start + tid; k < end; k += TPB) {\n int n = k / HW;\n int hw = k - n * HW;\n int idx = (n * C + c) * HW + hw;\n float z = mish_f(x[idx]);\n act[idx] = z;\n s += z;\n q = fmaf(z, z, q);\n }\n __shared__ float ss[TPB];\n __shared__ float qq[TPB];\n ss[tid] = s; qq[tid] = q;\n __syncthreads();\n for (int off = TPB/2; off > 0; off >>= 1) {\n if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }\n __syncthreads();\n }\n if (tid == 0) {\n psum[c * parts + p] = ss[0];\n psq[c * parts + p] = qq[0];\n }\n}\n\ntemplate<int TPB>\n__global__ void stats_kernel(const float* __restrict__ psum, const float* __restrict__ psq,\n const float* __restrict__ weight, const float* __restrict__ bias,\n float* __restrict__ running_mean, float* __restrict__ running_var,\n float* __restrict__ scale, float* __restrict__ shift,\n int C, int M, int parts, float momentum, float eps) {\n int c = blockIdx.x;\n int tid = threadIdx.x;\n float s = 0.0f, q = 0.0f;\n for (int p = tid; p < parts; p += TPB) {\n s += psum[c * parts + p];\n q += psq[c * parts + p];\n }\n __shared__ float ss[TPB];\n __shared__ float qq[TPB];\n ss[tid] = s; qq[tid] = q;\n __syncthreads();\n for (int off = TPB/2; off > 0; off >>= 1) {\n if (tid < off) { ss[tid] += ss[tid + off]; qq[tid] += qq[tid + off]; }\n __syncthreads();\n }\n if (tid == 0) {\n float mean = ss[0] / (float)M;\n float var = qq[0] / (float)M - mean * mean;\n var = var < 0.0f ? 0.0f : var;\n float inv = rsqrtf(var + eps);\n float g = weight[c];\n float b = bias[c];\n scale[c] = g * inv;\n shift[c] = b - mean * g * inv;\n // PyTorch BatchNorm updates running_var with the unbiased variance estimate.\n float unbiased = var * ((float)M / (float)(M - 1));\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__global__ void norm_kernel(const float* __restrict__ act, float* __restrict__ out,\n const float* __restrict__ scale, const float* __restrict__ shift,\n int total, int C, int HW) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int i = idx; i < total; i += stride) {\n int c = (i / HW) % C;\n out[i] = fmaf(act[i], scale[c], shift[c]);\n }\n}\n\n__global__ void mish_bn_eval_kernel(const float* __restrict__ x, float* __restrict__ out,\n const float* __restrict__ weight, const float* __restrict__ bias,\n const float* __restrict__ running_mean, const float* __restrict__ running_var,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int i = idx; i < total; i += stride) {\n int c = (i / HW) % C;\n float inv = rsqrtf(running_var[c] + eps);\n float z = mish_f(x[i]);\n out[i] = (z - running_mean[c]) * inv * weight[c] + bias[c];\n }\n}\n\ntorch::Tensor mish_bn_forward_cuda(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); CHECK_CUDA(running_mean); CHECK_CUDA(running_var);\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n auto out = torch::empty_like(x);\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int HW = H * W;\n const int total = N * C * HW;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (!training) {\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 4096) blocks = 4096;\n mish_bn_eval_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), out.data_ptr<float>(),\n weight.data_ptr<float>(), bias.data_ptr<float>(), running_mean.data_ptr<float>(), running_var.data_ptr<float>(),\n total, C, HW, (float)eps);\n return out;\n }\n const int parts = 16;\n auto act = torch::empty_like(x);\n auto opts = x.options();\n auto psum = torch::empty({C, parts}, opts);\n auto psq = torch::empty({C, parts}, opts);\n auto scale = torch::empty({C}, opts);\n auto shift = torch::empty({C}, opts);\n dim3 grid1(C, parts);\n mish_partials_kernel<256><<<grid1, 256, 0, stream>>>(x.data_ptr<float>(), act.data_ptr<float>(), psum.data_ptr<float>(), psq.data_ptr<float>(), N, C, HW, parts);\n stats_kernel<32><<<C, 32, 0, stream>>>(psum.data_ptr<float>(), psq.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), C, N*HW, parts, (float)momentum, (float)eps);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 4096) blocks = 4096;\n norm_kernel<<<blocks, threads, 0, stream>>>(act.data_ptr<float>(), out.data_ptr<float>(), scale.data_ptr<float>(), shift.data_ptr<float>(), total, C, HW);\n return out;\n}\n'''\n\n_ext = load_inline(\n name='mish_bn_fused_ext_v1',\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=['mish_bn_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, eps=1e-5, momentum=0.1):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.bn = nn.BatchNorm2d(out_channels, eps=eps, momentum=momentum)\n\n def forward(self, x):\n y = F.conv2d(x, self.conv.weight, self.conv.bias, self.conv.stride,\n self.conv.padding, self.conv.dilation, self.conv.groups)\n return _ext.mish_bn_forward(y.contiguous(), self.bn.weight, self.bn.bias,\n self.bn.running_mean, self.bn.running_var,\n self.bn.training, float(self.bn.momentum), float(self.bn.eps))\n"
}