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>\ntorch::Tensor affine_relu(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor depthwise_conv_bn_relu(torch::Tensor x, torch::Tensor w, torch::Tensor gamma, torch::Tensor beta, torch::Tensor mean, torch::Tensor var, int64_t stride, double eps);\ntorch::Tensor avgpool_linear(torch::Tensor x, torch::Tensor w, torch::Tensor b);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void affine_relu_kernel(float* __restrict__ x,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int c = (idx / HW) % C;\n float scale = gamma[c] * rsqrtf(var[c] + eps);\n float y = x[idx] * scale + (beta[c] - mean[c] * scale);\n x[idx] = y > 0.0f ? y : 0.0f;\n}\n\ntorch::Tensor affine_relu(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor mean, torch::Tensor var, double eps) {\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int total = N * C * H * W;\n const int threads = 256;\n affine_relu_kernel<<<(total + threads - 1) / threads, threads>>>(\n x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), total, C, H * W, (float)eps);\n return x;\n}\n\n__global__ void depthwise_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ y,\n int total, int C, int H, int Wd, int Ho, int Wo,\n int stride, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int ow = idx % Wo;\n int t = idx / Wo;\n int oh = t % Ho;\n t /= Ho;\n int c = t % C;\n int n = t / C;\n\n int ih0 = oh * stride - 1;\n int iw0 = ow * stride - 1;\n const float* xp = x + ((n * C + c) * H) * Wd;\n const float* wp = w + c * 9;\n float acc = 0.0f;\n#pragma unroll\n for (int ky = 0; ky < 3; ++ky) {\n int ih = ih0 + ky;\n if ((unsigned)ih < (unsigned)H) {\n#pragma unroll\n for (int kx = 0; kx < 3; ++kx) {\n int iw = iw0 + kx;\n if ((unsigned)iw < (unsigned)Wd) {\n acc += xp[ih * Wd + iw] * wp[ky * 3 + kx];\n }\n }\n }\n }\n float scale = gamma[c] * rsqrtf(var[c] + eps);\n acc = acc * scale + (beta[c] - mean[c] * scale);\n y[idx] = acc > 0.0f ? acc : 0.0f;\n}\n\ntorch::Tensor depthwise_conv_bn_relu(torch::Tensor x, torch::Tensor w,\n torch::Tensor gamma, torch::Tensor beta,\n torch::Tensor mean, torch::Tensor var,\n int64_t stride, double eps) {\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), Wd = (int)x.size(3);\n int s = (int)stride;\n int Ho = (H - 1) / s + 1;\n int Wo = (Wd - 1) / s + 1;\n auto y = torch::empty({N, C, Ho, Wo}, x.options());\n int total = N * C * Ho * Wo;\n const int threads = 256;\n depthwise_kernel<<<(total + threads - 1) / threads, threads>>>(\n x.data_ptr<float>(), w.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), y.data_ptr<float>(), total, C, H, Wd, Ho, Wo, s, (float)eps);\n return y;\n}\n\n__global__ void avg_kernel(const float* __restrict__ x, float* __restrict__ avg,\n int NC, int H, int Wd) {\n int idx = blockIdx.x;\n int tid = threadIdx.x;\n int HW = H * Wd;\n float s = 0.0f;\n const float* xp = x + idx * HW;\n for (int i = tid; i < HW; i += blockDim.x) s += xp[i];\n __shared__ float sm[64];\n sm[tid] = s;\n __syncthreads();\n if (tid < 32) sm[tid] += sm[tid + 32];\n __syncthreads();\n if (tid < 16) sm[tid] += sm[tid + 16];\n __syncthreads();\n if (tid < 8) sm[tid] += sm[tid + 8];\n __syncthreads();\n if (tid < 4) sm[tid] += sm[tid + 4];\n __syncthreads();\n if (tid < 2) sm[tid] += sm[tid + 2];\n __syncthreads();\n if (tid == 0) avg[idx] = (sm[0] + sm[1]) / (float)HW;\n}\n\n__global__ void linear_kernel(const float* __restrict__ avg,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ out,\n int N, int C, int K) {\n int k = blockIdx.x;\n int n = blockIdx.y;\n int tid = threadIdx.x;\n float s = 0.0f;\n const float* ap = avg + n * C;\n const float* wp = w + k * C;\n for (int c = tid; c < C; c += blockDim.x) s += ap[c] * wp[c];\n __shared__ float sm[256];\n sm[tid] = s;\n __syncthreads();\n for (int off = 128; off > 0; off >>= 1) {\n if (tid < off) sm[tid] += sm[tid + off];\n __syncthreads();\n }\n if (tid == 0) out[n * K + k] = sm[0] + b[k];\n}\n\ntorch::Tensor avgpool_linear(torch::Tensor x, torch::Tensor w, torch::Tensor b) {\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), Wd = (int)x.size(3);\n int K = (int)w.size(0);\n auto avg = torch::empty({N, C}, x.options());\n auto out = torch::empty({N, K}, x.options());\n avg_kernel<<<N * C, 64>>>(x.data_ptr<float>(), avg.data_ptr<float>(), N * C, H, Wd);\n dim3 grid(K, N);\n linear_kernel<<<grid, 256>>>(avg.data_ptr<float>(), w.data_ptr<float>(), b.data_ptr<float>(), out.data_ptr<float>(), N, C, K);\n return out;\n}\n'''\n\n_mobilenet_ext = load_inline(\n name='mobilenetv1_fused_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['affine_relu', 'depthwise_conv_bn_relu', 'avgpool_linear'],\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, num_classes=1000, input_channels=3, alpha=1.0):\n super(ModelNew, self).__init__()\n def conv_bn(inp, oup, stride):\n return nn.Sequential(\n nn.Conv2d(inp, oup, 3, stride, 1, bias=False),\n nn.BatchNorm2d(oup),\n nn.ReLU(inplace=True)\n )\n def conv_dw(inp, oup, stride):\n return nn.Sequential(\n nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),\n nn.BatchNorm2d(inp),\n nn.ReLU(inplace=True),\n nn.Conv2d(inp, oup, 1, 1, 0, bias=False),\n nn.BatchNorm2d(oup),\n nn.ReLU(inplace=True),\n )\n self.model = nn.Sequential(\n conv_bn(input_channels, int(32 * alpha), 2),\n conv_dw(int(32 * alpha), int(64 * alpha), 1),\n conv_dw(int(64 * alpha), int(128 * alpha), 2),\n conv_dw(int(128 * alpha), int(128 * alpha), 1),\n conv_dw(int(128 * alpha), int(256 * alpha), 2),\n conv_dw(int(256 * alpha), int(256 * alpha), 1),\n conv_dw(int(256 * alpha), int(512 * alpha), 2),\n conv_dw(int(512 * alpha), int(512 * alpha), 1),\n conv_dw(int(512 * alpha), int(512 * alpha), 1),\n conv_dw(int(512 * alpha), int(512 * alpha), 1),\n conv_dw(int(512 * alpha), int(512 * alpha), 1),\n conv_dw(int(512 * alpha), int(512 * alpha), 1),\n conv_dw(int(512 * alpha), int(1024 * alpha), 2),\n conv_dw(int(1024 * alpha), int(1024 * alpha), 1),\n nn.AvgPool2d(7),\n )\n self.fc = nn.Linear(int(1024 * alpha), num_classes)\n\n def _eval_forward(self, x):\n x = x.contiguous()\n m0 = self.model[0]\n x = F.conv2d(x, m0[0].weight, None, stride=m0[0].stride, padding=m0[0].padding, dilation=m0[0].dilation, groups=1)\n bn = m0[1]\n x = _mobilenet_ext.affine_relu(x, bn.weight, bn.bias, bn.running_mean, bn.running_var, bn.eps)\n for i in range(1, 14):\n blk = self.model[i]\n dw = blk[0]; bn1 = blk[1]\n x = _mobilenet_ext.depthwise_conv_bn_relu(x, dw.weight, bn1.weight, bn1.bias, bn1.running_mean, bn1.running_var, dw.stride[0], bn1.eps)\n pw = blk[3]; bn2 = blk[4]\n x = F.conv2d(x, pw.weight, None, stride=1, padding=0, dilation=1, groups=1)\n x = _mobilenet_ext.affine_relu(x, bn2.weight, bn2.bias, bn2.running_mean, bn2.running_var, bn2.eps)\n return _mobilenet_ext.avgpool_linear(x, self.fc.weight, self.fc.bias)\n\n def forward(self, x):\n if (not self.training) and x.is_cuda and x.dtype is torch.float32:\n return self._eval_forward(x)\n # Training mode must preserve BatchNorm batch-statistics and running-stat updates.\n for i in range(14):\n x = self.model[i](x)\n if x.is_cuda and x.dtype is torch.float32:\n return _mobilenet_ext.avgpool_linear(x.contiguous(), self.fc.weight, self.fc.bias)\n x = self.model[14](x)\n x = x.view(x.size(0), -1)\n return self.fc(x)\n"
}