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 bn_softmax_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var, double eps);\ntorch::Tensor softmax_cuda(torch::Tensor x);\n\ntorch::Tensor bn_softmax_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var, double eps) {\n return bn_softmax_cuda(x, weight, bias, running_mean, running_var, eps);\n}\n\ntorch::Tensor softmax_forward(torch::Tensor x) {\n return softmax_cuda(x);\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n\n__global__ void bn_softmax_kernel(const float* __restrict__ x,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ out,\n int rows, int C, int H, int W, float eps) {\n int row = blockIdx.x;\n if (row >= rows) return;\n int tid = threadIdx.x;\n int c = (row / H) % C;\n int base = row * W;\n float scale = gamma[c] * rsqrtf(var[c] + eps);\n float shift = beta[c] - mean[c] * scale;\n\n __shared__ float smem[256];\n float m = -FLT_MAX;\n for (int i = tid; i < W; i += blockDim.x) {\n float v = x[base + i] * scale + shift;\n m = fmaxf(m, v);\n }\n smem[tid] = m;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) smem[tid] = fmaxf(smem[tid], smem[tid + s]);\n __syncthreads();\n }\n float mx = smem[0];\n float sum = 0.0f;\n for (int i = tid; i < W; i += blockDim.x) {\n float v = x[base + i] * scale + shift;\n sum += __expf(v - mx);\n }\n smem[tid] = sum;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n float inv = 1.0f / smem[0];\n for (int i = tid; i < W; i += blockDim.x) {\n float v = x[base + i] * scale + shift;\n out[base + i] = __expf(v - mx) * inv;\n }\n}\n\n__global__ void softmax_kernel(const float* __restrict__ x, float* __restrict__ out,\n int rows, int W) {\n int row = blockIdx.x;\n if (row >= rows) return;\n int tid = threadIdx.x;\n int base = row * W;\n __shared__ float smem[256];\n float m = -FLT_MAX;\n for (int i = tid; i < W; i += blockDim.x) m = fmaxf(m, x[base + i]);\n smem[tid] = m;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) smem[tid] = fmaxf(smem[tid], smem[tid + s]);\n __syncthreads();\n }\n float mx = smem[0];\n float sum = 0.0f;\n for (int i = tid; i < W; i += blockDim.x) sum += __expf(x[base + i] - mx);\n smem[tid] = sum;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n float inv = 1.0f / smem[0];\n for (int i = tid; i < W; i += blockDim.x) out[base + i] = __expf(x[base + i] - mx) * inv;\n}\n\ntorch::Tensor bn_softmax_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor running_mean, torch::Tensor running_var, double eps) {\n auto out = torch::empty_like(x);\n int64_t N = x.size(0), C = x.size(1), H = x.size(2), W = x.size(3);\n int rows = (int)(N * C * H);\n bn_softmax_kernel<<<rows, 256>>>(x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n running_mean.data_ptr<float>(), running_var.data_ptr<float>(),\n out.data_ptr<float>(), rows, (int)C, (int)H, (int)W, (float)eps);\n return out;\n}\n\ntorch::Tensor softmax_cuda(torch::Tensor x) {\n auto out = torch::empty_like(x);\n int64_t rows64 = x.numel() / x.size(3);\n int W = (int)x.size(3);\n softmax_kernel<<<(int)rows64, 256>>>(x.data_ptr<float>(), out.data_ptr<float>(), (int)rows64, W);\n return out;\n}\n'''\n\n_ext = load_inline(\n name='unet_bn_softmax_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['bn_softmax_forward', 'softmax_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\nclass DoubleConv(nn.Module):\n def __init__(self, in_channels, out_channels):\n super().__init__()\n self.double_conv = nn.Sequential(\n nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),\n nn.BatchNorm2d(out_channels),\n nn.Softmax(dim=-1),\n nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),\n nn.BatchNorm2d(out_channels),\n nn.Softmax(dim=-1)\n )\n\n def forward(self, x):\n return self.double_conv(x)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, features):\n super(ModelNew, self).__init__()\n self.encoder1 = DoubleConv(in_channels, features)\n self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n self.encoder2 = DoubleConv(features, features * 2)\n self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n self.encoder3 = DoubleConv(features * 2, features * 4)\n self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)\n self.encoder4 = DoubleConv(features * 4, features * 8)\n self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)\n\n self.bottleneck = DoubleConv(features * 8, features * 16)\n\n self.upconv4 = nn.ConvTranspose2d(features * 16, features * 8, kernel_size=2, stride=2)\n self.decoder4 = DoubleConv(features * 16, features * 8)\n self.upconv3 = nn.ConvTranspose2d(features * 8, features * 4, kernel_size=2, stride=2)\n self.decoder3 = DoubleConv(features * 8, features * 4)\n self.upconv2 = nn.ConvTranspose2d(features * 4, features * 2, kernel_size=2, stride=2)\n self.decoder2 = DoubleConv(features * 4, features * 2)\n self.upconv1 = nn.ConvTranspose2d(features * 2, features, kernel_size=2, stride=2)\n self.decoder1 = DoubleConv(features * 2, features)\n\n self.final_conv = nn.Conv2d(features, out_channels, kernel_size=1)\n\n def _bn_sm(self, x, bn):\n # eval path fuses affine batchnorm and softmax into one CUDA kernel.\n # training path preserves BatchNorm's exact running-stat update semantics.\n if bn.training:\n y = F.batch_norm(x, bn.running_mean, bn.running_var, bn.weight, bn.bias,\n True, bn.momentum, bn.eps)\n return _ext.softmax_forward(y.contiguous())\n else:\n return _ext.bn_softmax_forward(x.contiguous(), bn.weight, bn.bias,\n bn.running_mean, bn.running_var, bn.eps)\n\n def _dc(self, x, dc):\n m = dc.double_conv\n c0 = m[0]\n x = F.conv2d(x, c0.weight, c0.bias, c0.stride, c0.padding, c0.dilation, c0.groups)\n x = self._bn_sm(x, m[1])\n c1 = m[3]\n x = F.conv2d(x, c1.weight, c1.bias, c1.stride, c1.padding, c1.dilation, c1.groups)\n x = self._bn_sm(x, m[4])\n return x\n\n def forward(self, x):\n enc1 = self._dc(x, self.encoder1)\n enc2 = self._dc(F.max_pool2d(enc1, 2, 2), self.encoder2)\n enc3 = self._dc(F.max_pool2d(enc2, 2, 2), self.encoder3)\n enc4 = self._dc(F.max_pool2d(enc3, 2, 2), self.encoder4)\n\n bottleneck = self._dc(F.max_pool2d(enc4, 2, 2), self.bottleneck)\n\n u = self.upconv4\n dec4 = F.conv_transpose2d(bottleneck, u.weight, u.bias, u.stride, u.padding, u.output_padding, u.groups, u.dilation)\n dec4 = self._dc(torch.cat((dec4, enc4), dim=1), self.decoder4)\n\n u = self.upconv3\n dec3 = F.conv_transpose2d(dec4, u.weight, u.bias, u.stride, u.padding, u.output_padding, u.groups, u.dilation)\n dec3 = self._dc(torch.cat((dec3, enc3), dim=1), self.decoder3)\n\n u = self.upconv2\n dec2 = F.conv_transpose2d(dec3, u.weight, u.bias, u.stride, u.padding, u.output_padding, u.groups, u.dilation)\n dec2 = self._dc(torch.cat((dec2, enc2), dim=1), self.decoder2)\n\n u = self.upconv1\n dec1 = F.conv_transpose2d(dec2, u.weight, u.bias, u.stride, u.padding, u.output_padding, u.groups, u.dilation)\n dec1 = self._dc(torch.cat((dec1, enc1), dim=1), self.decoder1)\n\n c = self.final_conv\n return F.conv2d(dec1, c.weight, c.bias, c.stride, c.padding, c.dilation, c.groups)\n"
}