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\ncuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <vector>\n\n__global__ void bn_relu_kernel(const float* __restrict__ x, const float* __restrict__ w, const float* __restrict__ b,\n const float* __restrict__ mean, const float* __restrict__ var,\n float* __restrict__ y, long total, int C, int H, int W, float eps){\n long idx = blockIdx.x * blockDim.x + threadIdx.x;\n if(idx >= total) return;\n int hw = H*W;\n int c = (idx / hw) % C;\n float v = x[idx];\n float a = w[c] * rsqrtf(var[c] + eps);\n float z = (v - mean[c]) * a + b[c];\n y[idx] = z > 0.0f ? z : 0.0f;\n}\n\n__global__ void avgpool2_kernel(const float* __restrict__ x, float* __restrict__ y, int N, int C, int H, int W){\n long total = (long)N*C*(H/2)*(W/2);\n long idx = blockIdx.x * blockDim.x + threadIdx.x;\n if(idx >= total) return;\n int Wo = W/2, Ho = H/2;\n int ow = idx % Wo;\n int oh = (idx / Wo) % Ho;\n int c = (idx / (Wo*Ho)) % C;\n int n = idx / (Wo*Ho*C);\n long base = ((long)n*C + c)*H*W + (2*oh)*W + 2*ow;\n y[idx] = 0.25f*(x[base] + x[base+1] + x[base+W] + x[base+W+1]);\n}\n\n__global__ void final_linear_kernel(const float* __restrict__ x,\n const float* __restrict__ bn_w, const float* __restrict__ bn_b,\n const float* __restrict__ mean, const float* __restrict__ var,\n const float* __restrict__ fc_w, const float* __restrict__ fc_b,\n float* __restrict__ out,\n int N, int C, int H, int W, int K, float eps){\n int nk = blockIdx.x;\n int tid = threadIdx.x;\n int n = nk / K;\n int k = nk - n*K;\n extern __shared__ float s[];\n float sum = 0.0f;\n int HW = H*W;\n int tot = C*HW;\n for(int t = tid; t < tot; t += blockDim.x){\n int c = t / HW;\n int r = t - c*HW;\n float v = x[((long)n*C + c)*HW + r];\n float z = (v - mean[c]) * (bn_w[c] * rsqrtf(var[c] + eps)) + bn_b[c];\n z = z > 0.0f ? z : 0.0f;\n sum += z * (fc_w[(long)k*C + c] / (float)HW);\n }\n s[tid] = sum;\n __syncthreads();\n for(int stride = blockDim.x/2; stride > 0; stride >>= 1){\n if(tid < stride) s[tid] += s[tid+stride];\n __syncthreads();\n }\n if(tid == 0) out[nk] = s[0] + fc_b[k];\n}\n\ntorch::Tensor bn_relu(torch::Tensor x, torch::Tensor w, torch::Tensor b, torch::Tensor mean, torch::Tensor var, double eps){\n auto y = torch::empty_like(x);\n int N=x.size(0), C=x.size(1), H=x.size(2), W=x.size(3);\n long total = (long)N*C*H*W;\n int threads=256;\n int blocks=(total+threads-1)/threads;\n bn_relu_kernel<<<blocks, threads>>>(x.data_ptr<float>(), w.data_ptr<float>(), b.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), y.data_ptr<float>(), total, C, H, W, (float)eps);\n return y;\n}\n\ntorch::Tensor avgpool2(torch::Tensor x){\n int N=x.size(0), C=x.size(1), H=x.size(2), W=x.size(3);\n auto y = torch::empty({N,C,H/2,W/2}, x.options());\n long total=(long)N*C*(H/2)*(W/2);\n int threads=256;\n int blocks=(total+threads-1)/threads;\n avgpool2_kernel<<<blocks, threads>>>(x.data_ptr<float>(), y.data_ptr<float>(), N,C,H,W);\n return y;\n}\n\ntorch::Tensor final_linear(torch::Tensor x, torch::Tensor bn_w, torch::Tensor bn_b, torch::Tensor mean, torch::Tensor var, torch::Tensor fc_w, torch::Tensor fc_b, double eps){\n int N=x.size(0), C=x.size(1), H=x.size(2), W=x.size(3), K=fc_w.size(0);\n auto out=torch::empty({N,K}, x.options());\n int threads=256;\n final_linear_kernel<<<N*K, threads, threads*sizeof(float)>>>(x.data_ptr<float>(), bn_w.data_ptr<float>(), bn_b.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), fc_w.data_ptr<float>(), fc_b.data_ptr<float>(), out.data_ptr<float>(), N,C,H,W,K,(float)eps);\n return out;\n}\n'''\n\n_ext = load_inline(name='densenet201_fused_ext_v1', cpp_sources='', cuda_sources=cuda_src,\n functions=['bn_relu','avgpool2','final_linear'], verbose=False,\n extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'])\n\nclass DenseBlock(nn.Module):\n def __init__(self, num_layers: int, num_input_features: int, growth_rate: int):\n super(DenseBlock, self).__init__()\n layers = []\n for i in range(num_layers):\n layers.append(self._make_layer(num_input_features + i * growth_rate, growth_rate))\n self.layers = nn.ModuleList(layers)\n def _make_layer(self, in_features: int, growth_rate: int):\n return nn.Sequential(\n nn.BatchNorm2d(in_features),\n nn.ReLU(inplace=True),\n nn.Conv2d(in_features, growth_rate, kernel_size=3, padding=1, bias=False),\n nn.Dropout(0.0)\n )\n\nclass TransitionLayer(nn.Module):\n def __init__(self, num_input_features: int, num_output_features: int):\n super(TransitionLayer, self).__init__()\n self.transition = nn.Sequential(\n nn.BatchNorm2d(num_input_features),\n nn.ReLU(inplace=True),\n nn.Conv2d(num_input_features, num_output_features, kernel_size=1, bias=False),\n nn.AvgPool2d(kernel_size=2, stride=2)\n )\n\nclass ModelNew(nn.Module):\n def __init__(self, growth_rate: int = 32, num_classes: int = 1000):\n super(ModelNew, self).__init__()\n self.features = nn.Sequential(\n nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False),\n nn.BatchNorm2d(64),\n nn.ReLU(inplace=True),\n nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n )\n num_features = 64\n block_layers = [6, 12, 48, 32]\n self.dense_blocks = nn.ModuleList()\n self.transition_layers = nn.ModuleList()\n for i, num_layers in enumerate(block_layers):\n block = DenseBlock(num_layers=num_layers, num_input_features=num_features, growth_rate=growth_rate)\n self.dense_blocks.append(block)\n num_features = num_features + num_layers * growth_rate\n if i != len(block_layers) - 1:\n transition = TransitionLayer(num_input_features=num_features, num_output_features=num_features // 2)\n self.transition_layers.append(transition)\n num_features = num_features // 2\n self.final_bn = nn.BatchNorm2d(num_features)\n self.classifier = nn.Linear(num_features, num_classes)\n\n def _bn_relu(self, x, bn):\n # The benchmark uses fp32 CUDA inference. For training or CPU, preserve exact PyTorch semantics.\n if x.is_cuda and x.dtype is torch.float32 and (not self.training):\n return _ext.bn_relu(x.contiguous(), bn.weight, bn.bias, bn.running_mean, bn.running_var, bn.eps)\n return F.relu(bn(x), inplace=True)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if not x.is_cuda or x.dtype is not torch.float32 or self.training:\n x = self.features(x)\n for i, block in enumerate(self.dense_blocks):\n features=[x]\n for layer in block.layers:\n new_feature = layer(x)\n features.append(new_feature)\n x = torch.cat(features, 1)\n if i != len(self.dense_blocks)-1:\n x = self.transition_layers[i].transition(x)\n x = self.final_bn(x)\n x = F.relu(x, inplace=True)\n x = F.adaptive_avg_pool2d(x, (1,1)).view(x.size(0), -1)\n return self.classifier(x)\n\n # initial stem: fuse batchnorm+relu, leave highly optimized conv/maxpool to cuDNN/ATen\n x = self.features[0](x)\n x = self._bn_relu(x, self.features[1])\n x = self.features[3](x)\n\n for bi, block in enumerate(self.dense_blocks):\n feats = [x]\n for layer in block.layers:\n z = self._bn_relu(x, layer[0])\n nf = layer[2](z)\n feats.append(nf)\n x = torch.cat(feats, 1)\n if bi != len(self.dense_blocks) - 1:\n tr = self.transition_layers[bi].transition\n z = self._bn_relu(x, tr[0])\n x = tr[2](z)\n x = _ext.avgpool2(x.contiguous())\n\n return _ext.final_linear(x.contiguous(), self.final_bn.weight, self.final_bn.bias,\n self.final_bn.running_mean, self.final_bn.running_var,\n self.classifier.weight, self.classifier.bias, self.final_bn.eps)\n"
}