gpt-5.5-priority · original · l3_default_gpt
correct 26_ShuffleNet.py
model
gpt-5.5-priority
turns / max
7 / 15
tool calls
7
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
9.57 μs
ref runtime
9.78 μs
speedup
1.02x
started
2026-05-04T20:53:29Z
timingkernelbench.timing
kernel runtime
9.57 μs
ref runtime
9.78 μs
speedup
1.02x
kernel mean / median / std
9.57 / — / 0.49 μs
ref mean / median / std
9.78 / — / 13.70 μs
numerical precisioneval_kernel_against_ref
max abs error
1.48e-05
mean abs error
2.74e-06
max rel error
0.32
mean rel error
9.43e-05
gpu memoryextended_metrics.measure_memory
kernel peak
467.87 MB
ref peak
496.58 MB
kernel / ref
0.94x
kernel launches / fusiontorch.profiler
kernel launches
322
ref launches
882
fusion ratio (ref / kernel)
2.74x
total cuda time
19545 μs
energyNVML (pynvml)
kernel mJ / run
1527.24
ref mJ / run
1527.26
ratio (ref / kernel)
1.00x
avg power
162.93 W
ref avg power
184.11 W
SOL (speed-of-light)heuristic_from_speedup
SOL score (0–1)
0.102
dram util %
—
compute util %
—
bottleneck
unknown
dominant pipe
—
arithmetic intensity
—
ridge point
—
roofline / occupancyheuristic
dram bandwidth
—
dram util %
—
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
—
bottleneck
—
dominant pipe %
—
arithmetic intensity
—
ridge point
—
L1 hit %
—
L2 hit %
—
ld sectors / req
—
st sectors / req
—
regs / thread
—
smem / block
—
block size
—
peak bw
—
peak fp32 tflops
—
peak fp16 tflops
—
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F

class ShuffleNetUnit(nn.Module):
    def __init__(self, in_channels, out_channels, groups=3):
        """
        ShuffleNet unit implementation.

        :param in_channels: Number of input channels.
        :param out_channels: Number of output channels.
        :param groups: Number of groups for group convolution.
        """
        super(ShuffleNetUnit, self).__init__()
        
        # Ensure the output channels are divisible by groups
        assert out_channels % 4 == 0
        mid_channels = out_channels // 4
        
        # First 1x1 group convolution
        self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, stride=1, padding=0, groups=groups, bias=False)
        self.bn1 = nn.BatchNorm2d(mid_channels)
        
        # Depthwise 3x3 convolution
        self.conv2 = nn.Conv2d(mid_channels, mid_channels, kernel_size=3, stride=1, padding=1, groups=mid_channels, bias=False)
        self.bn2 = nn.BatchNorm2d(mid_channels)
        
        # Second 1x1 group convolution
        self.conv3 = nn.Conv2d(mid_channels, out_channels, kernel_size=1, stride=1, padding=0, groups=groups, bias=False)
        self.bn3 = nn.BatchNorm2d(out_channels)
        
        # Shuffle operation
        self.shuffle = ChannelShuffle(groups)
        
        # Shortcut connection if input and output channels are the same
        if in_channels == out_channels:
            self.shortcut = nn.Sequential()
        else:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(out_channels)
            )
    
    def forward(self, x):
        """
        Forward pass for ShuffleNet unit.

        :param x: Input tensor, shape (batch_size, in_channels, height, width)
        :return: Output tensor, shape (batch_size, out_channels, height, width)
        """
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out = self.shuffle(out)
        out = F.relu(self.bn3(self.conv3(out)))
        
        out += self.shortcut(x)
        return out

class ChannelShuffle(nn.Module):
    def __init__(self, groups):
        """
        Channel shuffle operation.

        :param groups: Number of groups for shuffling.
        """
        super(ChannelShuffle, self).__init__()
        self.groups = groups
    
    def forward(self, x):
        """
        Forward pass for channel shuffle.

        :param x: Input tensor, shape (batch_size, channels, height, width)
        :return: Output tensor, shape (batch_size, channels, height, width)
        """
        batch_size, channels, height, width = x.size()
        channels_per_group = channels // self.groups
        
        # Reshape
        x = x.view(batch_size, self.groups, channels_per_group, height, width)
        
        # Transpose
        x = x.transpose(1, 2).contiguous()
        
        # Flatten
        x = x.view(batch_size, -1, height, width)
        
        return x

class Model(nn.Module):
    def __init__(self, num_classes=1000, groups=3, stages_repeats=[3, 7, 3], stages_out_channels=[24, 240, 480, 960]):
        """
        ShuffleNet architecture.

        :param num_classes: Number of output classes.
        :param groups: Number of groups for group convolution.
        :param stages_repeats: List of ints specifying the number of repeats for each stage.
        :param stages_out_channels: List of ints specifying the output channels for each stage.
        """
        super(Model, self).__init__()
        
        self.conv1 = nn.Conv2d(3, stages_out_channels[0], kernel_size=3, stride=2, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(stages_out_channels[0])
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        
        self.stage2 = self._make_stage(stages_out_channels[0], stages_out_channels[1], stages_repeats[0], groups)
        self.stage3 = self._make_stage(stages_out_channels[1], stages_out_channels[2], stages_repeats[1], groups)
        self.stage4 = self._make_stage(stages_out_channels[2], stages_out_channels[3], stages_repeats[2], groups)
        
        self.conv5 = nn.Conv2d(stages_out_channels[3], 1024, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn5 = nn.BatchNorm2d(1024)
        
        self.fc = nn.Linear(1024, num_classes)
    
    def _make_stage(self, in_channels, out_channels, repeats, groups):
        """
        Helper function to create a stage of ShuffleNet units.

        :param in_channels: Number of input channels.
        :param out_channels: Number of output channels.
        :param repeats: Number of ShuffleNet units in the stage.
        :param groups: Number of groups for group convolution.
        :return: nn.Sequential containing the stage.
        """
        layers = []
        layers.append(ShuffleNetUnit(in_channels, out_channels, groups))
        for _ in range(1, repeats):
            layers.append(ShuffleNetUnit(out_channels, out_channels, groups))
        return nn.Sequential(*layers)
    
    def forward(self, x):
        """
        Forward pass for ShuffleNet.

        :param x: Input tensor, shape (batch_size, 3, height, width)
        :return: Output tensor, shape (batch_size, num_classes)
        """
        x = F.relu(self.bn1(self.conv1(x)))
        x = self.maxpool(x)
        
        x = self.stage2(x)
        x = self.stage3(x)
        x = self.stage4(x)
        
        x = F.relu(self.bn5(self.conv5(x)))
        x = F.adaptive_avg_pool2d(x, (1, 1))
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        
        return x

# Test code
batch_size = 10
input_channels = 3
height = 224
width = 224
num_classes = 1000

def get_inputs():
    return [torch.rand(batch_size, input_channels, height, width)]

def get_init_inputs():
    return [num_classes]
turn 012.4s turn · 12.4s LLM · 0.0s tools
reasoning
**Evaluating ModelNew implementation** I need to fully understand how to craft ModelNew. I’m considering instantiating it with the same arguments and copying the state_dict from the original Model. To do this, I’ll implement modules to hold weights with the same names, possibly subclassing nn.Module for consistent layers and torch operations. I'm also pondering how to replace the forward pass with a custom CUDA kernel since using many small ops might be inefficient. This task requires me to focus on speed improvements while maintaining functionality. **Considering model evaluation challenges** I’m exploring potential speedups during model evaluation, specifically regarding BatchNorm behavior. The harness likely calls model.eval(), which is important since many benchmarks compare outputs with models initialized with random weights. If the model's in training mode, BatchNorm uses batch statistics, which could complicate things if I want to ensure consistency. In previous tasks, they instantiated Model and ModelNew while copying parameters and using random inputs without explicitly setting eval. It’s crucial to determine if I should mimic this setup. Maybe there's a way to implement the architecture directly using PyTorch modules for optimal performance. **Exploring kernel implementation options** I’m considering implementing a kernel that applies BatchNorm and shuffle directly to avoid intermediate outputs. I could use the output from F.conv2d for convolution and then follow it with a custom bn_shuffle to streamline the process. It might also be worth looking into whether combining BN and ReLU kernels could be faster than PyTorch, especially for smaller tensors, since there might be some overhead with PyTorch's cuDNN. Of course, I also need to ensure that all module names match when loading the state_dict.
call → get_gpu_specs
callget_gpu_specs {}
result ← get_gpu_specs (ok)
okget_gpu_specs GPU specs for NVIDIA H100 80GB HBM3: total memory (runtime): 79.1 GB spec entry: H100 GPU Architecture: Hopper GPU Memory: 80GB Memory Bandwidth: 3.35 TB/s FP64 TFLOPS: 34 FP64 Tensor Core TFLOPS: 67 FP32 TFLOPS: 67 TF32 Tensor Core TFLOPS: 989 with sparsity BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity FP16 Tensor Core TFLOPS: 1979 with sparsity FP8 Tensor Core TFLOPS: 3958 with sparsity INT8 Tensor Core TOPS: 3958 with sparsity Register File Size: 64K 32-bit registers per SM Maximum number of registers per thread: 255 Maximum number of thread blocks per SM: 32 Shared memory capacity per SM: 228 KB Maximum shared memory per thread block: 227 KB
turn 1 · 1 tool call(s) · 74.8s turn · 74.8s LLM · 14,243 chars (click to expand)
turn 174.8s turn · 74.8s LLM · 0.0s tools
reasoning
**Considering convolutional layers** I’m thinking about how to structure this with conv3 followed by batch normalization and a ReLU activation function. For the shortcut, I could either use the input x or a convolution followed by batch normalization without ReLU. Hmm, I wonder if I should use PyTorch for adding the results together. I’m contemplating whether to use a custom add function since there’s some overhead with the built-in torch add. Keeping the kernel design simple seems like a good plan too! **Considering wrapper function implementation** I'm thinking about crafting wrapper functions in C++ that return `torch::Tensor` and include launcher declarations for the CUDA source. I need to ensure that functions in `cpp_sources` have appropriate calls and use `TORCH_CHECK`. There’s a note on a duplicate module, so I’ll skip PYBIND for now. I should list the wrapper names and focus on implementing `bnaffine` kernels. To start, I might need to use them effectively. **Investigating BatchNorm settings** I’m considering the potential issue with BatchNorm, particularly around the default epsilon value of 1e-5 and the momentum during evaluation. I think it’s essential to pay attention to these settings as they could impact model performance. I’ll need to code this out and check how these parameters behave, especially during evaluation. It's interesting to see how small changes can lead to different outcomes! Let’s get to coding!
call → compile_kernel
callcompile_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_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n int c = (idx / HW) % C;\n float scale = w[c] * rsqrtf(v[c] + eps);\n float val = (x[idx] - m[c]) * scale + b[c];\n y[idx] = val > 0.0f ? val : 0.0f;\n }\n}\n\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n int c = (idx / HW) % C;\n float scale = w[c] * rsqrtf(v[c] + eps);\n y[idx] = (x[idx] - m[c]) * scale + b[c];\n }\n}\n\n__global__ void bn_shuffle_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, int groups, float eps) {\n int out_idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (out_idx < total) {\n int hw = out_idx % HW;\n int tmp = out_idx / HW;\n int out_c = tmp % C;\n int n = tmp / C;\n int cpg = C / groups;\n int cp = out_c / groups;\n int gr = out_c - cp * groups;\n int in_c = gr * cpg + cp;\n int in_idx = (n * C + in_c) * HW + hw;\n float scale = w[in_c] * rsqrtf(v[in_c] + eps);\n y[out_idx] = (x[in_idx] - m[in_c]) * scale + b[in_c];\n }\n}\n\n__global__ void add_kernel(const float* __restrict__ a, const float* __restrict__ b, float* __restrict__ y, int total) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) y[idx] = a[idx] + b[idx];\n}\n\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int N, int C, int HW, float eps) {\n int nc = blockIdx.x;\n int c = nc % C;\n int n = nc / C;\n const float* base = x + (n * C + c) * HW;\n float scale = w[c] * rsqrtf(v[c] + eps);\n float sum = 0.0f;\n // 256 threads per block reduction\n for (int i = threadIdx.x; i < HW; i += blockDim.x) {\n float val = (base[i] - m[c]) * scale + b[c];\n sum += val > 0.0f ? val : 0.0f;\n }\n __shared__ float smem[256];\n smem[threadIdx.x] = sum;\n __syncthreads();\n for (int stride = blockDim.x/2; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) smem[threadIdx.x] += smem[threadIdx.x + stride];\n __syncthreads();\n }\n if (threadIdx.x == 0) y[n * C + c] = smem[0] / (float)HW;\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_relu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (float)eps);\n return y;\n}\n\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (float)eps);\n return y;\n}\n\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_shuffle_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (int)groups, (float)eps);\n return y;\n}\n\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b) {\n auto y = torch::empty_like(a);\n int total = a.numel();\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n add_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(), b.data_ptr<float>(), y.data_ptr<float>(), total);\n return y;\n}\n\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n int N = x.size(0);\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n auto y = torch::empty({N, C}, x.options());\n bn_relu_avg_kernel<<<N*C, 256, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), N, C, HW, (float)eps);\n return y;\n}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v1', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups):\n super().__init__(); self.groups = groups\n def forward(self, x):\n n,c,h,w = x.size(); g = self.groups\n return x.view(n, g, c//g, h, w).transpose(1,2).contiguous().view(n, c, h, w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self, in_channels, out_channels, groups=3):\n super().__init__()\n assert out_channels % 4 == 0\n mid_channels = out_channels // 4\n self.conv1 = nn.Conv2d(in_channels, mid_channels, 1, 1, 0, groups=groups, bias=False)\n self.bn1 = nn.BatchNorm2d(mid_channels)\n self.conv2 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, groups=mid_channels, bias=False)\n self.bn2 = nn.BatchNorm2d(mid_channels)\n self.conv3 = nn.Conv2d(mid_channels, out_channels, 1, 1, 0, groups=groups, bias=False)\n self.bn3 = nn.BatchNorm2d(out_channels)\n self.shuffle = ChannelShuffle(groups)\n if in_channels == out_channels:\n self.shortcut = nn.Sequential()\n else:\n self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=False), nn.BatchNorm2d(out_channels))\n self.groups = groups\n def forward(self, x):\n if self.training or x.dtype != torch.float32 or not x.is_cuda:\n out = F.relu(self.bn1(self.conv1(x)))\n out = self.bn2(self.conv2(out))\n out = self.shuffle(out)\n out = F.relu(self.bn3(self.conv3(out)))\n out = out + self.shortcut(x)\n return out\n out = F.conv2d(x, self.conv1.weight, None, 1, 0, 1, self.conv1.groups)\n out = _ext.bn_relu_eval_cuda(out, self.bn1.weight, self.bn1.bias, self.bn1.running_mean, self.bn1.running_var, self.bn1.eps)\n out = F.conv2d(out, self.conv2.weight, None, 1, 1, 1, self.conv2.groups)\n out = _ext.bn_shuffle_eval_cuda(out, self.bn2.weight, self.bn2.bias, self.bn2.running_mean, self.bn2.running_var, self.groups, self.bn2.eps)\n out = F.conv2d(out, self.conv3.weight, None, 1, 0, 1, self.conv3.groups)\n out = _ext.bn_relu_eval_cuda(out, self.bn3.weight, self.bn3.bias, self.bn3.running_mean, self.bn3.running_var, self.bn3.eps)\n if len(self.shortcut) == 0:\n sc = x\n else:\n sc = F.conv2d(x, self.shortcut[0].weight, None, 1, 0, 1, 1)\n sc = _ext.bn_eval_cuda(sc, self.shortcut[1].weight, self.shortcut[1].bias, self.shortcut[1].running_mean, self.shortcut[1].running_var, self.shortcut[1].eps)\n return _ext.add_cuda(out, sc)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_classes=1000, groups=3, stages_repeats=[3, 7, 3], stages_out_channels=[24, 240, 480, 960]):\n super().__init__()\n self.conv1 = nn.Conv2d(3, stages_out_channels[0], 3, 2, 1, bias=False)\n self.bn1 = nn.BatchNorm2d(stages_out_channels[0])\n self.maxpool = nn.MaxPool2d(3, 2, 1)\n self.stage2 = self._make_stage(stages_out_channels[0], stages_out_channels[1], stages_repeats[0], groups)\n self.stage3 = self._make_stage(stages_out_channels[1], stages_out_channels[2], stages_repeats[1], groups)\n self.stage4 = self._make_stage(stages_out_channels[2], stages_out_channels[3], stages_repeats[2], groups)\n self.conv5 = nn.Conv2d(stages_out_channels[3], 1024, 1, 1, 0, bias=False)\n self.bn5 = nn.BatchNorm2d(1024)\n self.fc = nn.Linear(1024, num_classes)\n def _make_stage(self, in_channels, out_channels, repeats, groups):\n layers = [ShuffleNetUnitNew(in_channels, out_channels, groups)]\n for _ in range(1, repeats):\n layers.append(ShuffleNetUnitNew(out_channels, out_channels, groups))\n return nn.Sequential(*layers)\n def forward(self, x):\n if self.training or x.dtype != torch.float32 or not x.is_cuda:\n x = F.relu(self.bn1(self.conv1(x)))\n x = self.maxpool(x)\n x = self.stage2(x); x = self.stage3(x); x = self.stage4(x)\n x = F.relu(self.bn5(self.conv5(x)))\n x = F.adaptive_avg_pool2d(x, (1,1))\n x = x.view(x.size(0), -1)\n return self.fc(x)\n x = F.conv2d(x, self.conv1.weight, None, 2, 1, 1, 1)\n x = _ext.bn_relu_eval_cuda(x, self.bn1.weight, self.bn1.bias, self.bn1.running_mean, self.bn1.running_var, self.bn1.eps)\n x = F.max_pool2d(x, 3, 2, 1)\n x = self.stage2(x); x = self.stage3(x); x = self.stage4(x)\n x = F.conv2d(x, self.conv5.weight, None, 1, 0, 1, 1)\n x = _ext.bn_relu_avg_cuda(x, self.bn5.weight, self.bn5.bias, self.bn5.running_mean, self.bn5.running_var, self.bn5.eps)\n return F.linear(x, self.fc.weight, self.fc.bias)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2 · 1 tool call(s) · 34.7s turn · 34.7s LLM · 12,756 chars (click to expand)
turn 234.7s turn · 34.7s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "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_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n int c = (idx / HW) % C;\n float scale = w[c] * rsqrtf(v[c] + eps);\n float val = (x[idx] - m[c]) * scale + b[c];\n y[idx] = val > 0.0f ? val : 0.0f;\n }\n}\n\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, float eps) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) {\n int c = (idx / HW) % C;\n float scale = w[c] * rsqrtf(v[c] + eps);\n y[idx] = (x[idx] - m[c]) * scale + b[c];\n }\n}\n\n__global__ void bn_shuffle_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int total, int C, int HW, int groups, float eps) {\n int out_idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (out_idx < total) {\n int hw = out_idx % HW;\n int tmp = out_idx / HW;\n int out_c = tmp % C;\n int n = tmp / C;\n int cpg = C / groups;\n int cp = out_c / groups;\n int gr = out_c - cp * groups;\n int in_c = gr * cpg + cp;\n int in_idx = (n * C + in_c) * HW + hw;\n float scale = w[in_c] * rsqrtf(v[in_c] + eps);\n y[out_idx] = (x[in_idx] - m[in_c]) * scale + b[in_c];\n }\n}\n\n__global__ void add_kernel(const float* __restrict__ a, const float* __restrict__ b, float* __restrict__ y, int total) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < total) y[idx] = a[idx] + b[idx];\n}\n\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x, float* __restrict__ y,\n const float* __restrict__ w, const float* __restrict__ b, const float* __restrict__ m, const float* __restrict__ v,\n int N, int C, int HW, float eps) {\n int nc = blockIdx.x;\n int c = nc % C;\n int n = nc / C;\n const float* base = x + (n * C + c) * HW;\n float scale = w[c] * rsqrtf(v[c] + eps);\n float sum = 0.0f;\n for (int i = threadIdx.x; i < HW; i += blockDim.x) {\n float val = (base[i] - m[c]) * scale + b[c];\n sum += val > 0.0f ? val : 0.0f;\n }\n __shared__ float smem[256];\n smem[threadIdx.x] = sum;\n __syncthreads();\n for (int stride = blockDim.x/2; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) smem[threadIdx.x] += smem[threadIdx.x + stride];\n __syncthreads();\n }\n if (threadIdx.x == 0) y[n * C + c] = smem[0] / (float)HW;\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_relu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (float)eps);\n return y;\n}\n\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (float)eps);\n return y;\n}\n\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps) {\n auto y = torch::empty_like(x);\n int total = x.numel();\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n bn_shuffle_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), total, C, HW, (int)groups, (float)eps);\n return y;\n}\n\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b) {\n auto y = torch::empty_like(a);\n int total = a.numel();\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n add_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(), b.data_ptr<float>(), y.data_ptr<float>(), total);\n return y;\n}\n\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps) {\n int N = x.size(0);\n int C = x.size(1);\n int HW = x.size(2) * x.size(3);\n auto y = torch::empty({N, C}, x.options());\n bn_relu_avg_kernel<<<N*C, 256, 0, at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(), y.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(), mean.data_ptr<float>(), var.data_ptr<float>(), N, C, HW, (float)eps);\n return y;\n}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v1', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups):\n super().__init__(); self.groups = groups\n def forward(self, x):\n n,c,h,w = x.size(); g = self.groups\n return x.view(n, g, c//g, h, w).transpose(1,2).contiguous().view(n, c, h, w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self, in_channels, out_channels, groups=3):\n super().__init__()\n assert out_channels % 4 == 0\n mid_channels = out_channels // 4\n self.conv1 = nn.Conv2d(in_channels, mid_channels, 1, 1, 0, groups=groups, bias=False)\n self.bn1 = nn.BatchNorm2d(mid_channels)\n self.conv2 = nn.Conv2d(mid_channels, mid_channels, 3, 1, 1, groups=mid_channels, bias=False)\n self.bn2 = nn.BatchNorm2d(mid_channels)\n self.conv3 = nn.Conv2d(mid_channels, out_channels, 1, 1, 0, groups=groups, bias=False)\n self.bn3 = nn.BatchNorm2d(out_channels)\n self.shuffle = ChannelShuffle(groups)\n if in_channels == out_channels:\n self.shortcut = nn.Sequential()\n else:\n self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, 1, 1, 0, bias=False), nn.BatchNorm2d(out_channels))\n self.groups = groups\n def forward(self, x):\n if self.training or x.dtype != torch.float32 or not x.is_cuda:\n out = F.relu(self.bn1(self.conv1(x)))\n out = self.bn2(self.conv2(out))\n out = self.shuffle(out)\n out = F.relu(self.bn3(self.conv3(out)))\n out = out + self.shortcut(x)\n return out\n out = F.conv2d(x, self.conv1.weight, None, 1, 0, 1, self.conv1.groups)\n out = _ext.bn_relu_eval_cuda(out, self.bn1.weight, self.bn1.bias, self.bn1.running_mean, self.bn1.running_var, self.bn1.eps)\n out = F.conv2d(out, self.conv2.weight, None, 1, 1, 1, self.conv2.groups)\n out = _ext.bn_shuffle_eval_cuda(out, self.bn2.weight, self.bn2.bias, self.bn2.running_mean, self.bn2.running_var, self.groups, self.bn2.eps)\n out = F.conv2d(out, self.conv3.weight, None, 1, 0, 1, self.conv3.groups)\n out = _ext.bn_relu_eval_cuda(out, self.bn3.weight, self.bn3.bias, self.bn3.running_mean, self.bn3.running_var, self.bn3.eps)\n if len(self.shortcut) == 0:\n sc = x\n else:\n sc = F.conv2d(x, self.shortcut[0].weight, None, 1, 0, 1, 1)\n sc = _ext.bn_eval_cuda(sc, self.shortcut[1].weight, self.shortcut[1].bias, self.shortcut[1].running_mean, self.shortcut[1].running_var, self.shortcut[1].eps)\n return _ext.add_cuda(out, sc)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_classes=1000, groups=3, stages_repeats=[3, 7, 3], stages_out_channels=[24, 240, 480, 960]):\n super().__init__()\n self.conv1 = nn.Conv2d(3, stages_out_channels[0], 3, 2, 1, bias=False)\n self.bn1 = nn.BatchNorm2d(stages_out_channels[0])\n self.maxpool = nn.MaxPool2d(3, 2, 1)\n self.stage2 = self._make_stage(stages_out_channels[0], stages_out_channels[1], stages_repeats[0], groups)\n self.stage3 = self._make_stage(stages_out_channels[1], stages_out_channels[2], stages_repeats[1], groups)\n self.stage4 = self._make_stage(stages_out_channels[2], stages_out_channels[3], stages_repeats[2], groups)\n self.conv5 = nn.Conv2d(stages_out_channels[3], 1024, 1, 1, 0, bias=False)\n self.bn5 = nn.BatchNorm2d(1024)\n self.fc = nn.Linear(1024, num_classes)\n def _make_stage(self, in_channels, out_channels, repeats, groups):\n layers = [ShuffleNetUnitNew(in_channels, out_channels, groups)]\n for _ in range(1, repeats):\n layers.append(ShuffleNetUnitNew(out_channels, out_channels, groups))\n return nn.Sequential(*layers)\n def forward(self, x):\n if self.training or x.dtype != torch.float32 or not x.is_cuda:\n x = F.relu(self.bn1(self.conv1(x)))\n x = self.maxpool(x)\n x = self.stage2(x); x = self.stage3(x); x = self.stage4(x)\n x = F.relu(self.bn5(self.conv5(x)))\n x = F.adaptive_avg_pool2d(x, (1,1))\n x = x.view(x.size(0), -1)\n return self.fc(x)\n x = F.conv2d(x, self.conv1.weight, None, 2, 1, 1, 1)\n x = _ext.bn_relu_eval_cuda(x, self.bn1.weight, self.bn1.bias, self.bn1.running_mean, self.bn1.running_var, self.bn1.eps)\n x = F.max_pool2d(x, 3, 2, 1)\n x = self.stage2(x); x = self.stage3(x); x = self.stage4(x)\n x = F.conv2d(x, self.conv5.weight, None, 1, 0, 1, 1)\n x = _ext.bn_relu_avg_cuda(x, self.bn5.weight, self.bn5.bias, self.bn5.running_mean, self.bn5.running_var, self.bn5.eps)\n return F.linear(x, self.fc.weight, self.fc.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 3 · 1 tool call(s) · 41.5s turn · 41.5s LLM · 15,662 chars (click to expand)
turn 341.5s turn · 41.5s LLM · 0.0s tools
call → compile_kernel
callcompile_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 bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t groups, double eps);\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; float val=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c]; y[idx]=val>0.f?val:0.f;}}\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; y[idx]=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c];}}\n__global__ void bn_shuffle_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,int groups,float eps){int out_idx=blockIdx.x*blockDim.x+threadIdx.x; if(out_idx<total){int hw=out_idx%HW; int tmp=out_idx/HW; int oc=tmp%C; int n=tmp/C; int cpg=C/groups; int cp=oc/groups; int gr=oc-cp*groups; int ic=gr*cpg+cp; int ii=(n*C+ic)*HW+hw; y[out_idx]=(x[ii]-m[ic])*(w[ic]*rsqrtf(v[ic]+eps))+b[ic];}}\n__global__ void add_kernel(const float* __restrict__ a,const float* __restrict__ b,float* __restrict__ y,int total){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total)y[idx]=a[idx]+b[idx];}\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int N,int C,int HW,float eps){int nc=blockIdx.x; int c=nc%C; int n=nc/C; const float* base=x+(n*C+c)*HW; float sc=w[c]*rsqrtf(v[c]+eps), sum=0.f; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-m[c])*sc+b[c]; sum+=val>0.f?val:0.f;} __shared__ float sm[256]; sm[threadIdx.x]=sum; __syncthreads(); for(int s=128;s>0;s>>=1){if(threadIdx.x<s)sm[threadIdx.x]+=sm[threadIdx.x+s]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW;}\n\ntemplate<int RELU, int SHUFFLE>\n__global__ void bn_train_ch_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,int groups,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n int oc=c; if(SHUFFLE){int cpg=C/groups; int gr=c/cpg; int cp=c-gr*cpg; oc=cp*groups+gr;}\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=(x[(n*C+c)*HW+hw]-mean)*sc+bb; if(RELU) val=val>0.f?val:0.f; y[(n*C+oc)*HW+hw]=val;}\n}\n\n__global__ void bn_relu_avg_train_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n for(int n=0;n<N;n++){float s=0.f; const float* base=x+(n*C+c)*HW; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-mean)*sc+bb; s+=val>0.f?val:0.f;} sm[threadIdx.x]=s; __syncthreads(); for(int stride=blockDim.x/2;stride>0;stride>>=1){if(threadIdx.x<stride)sm[threadIdx.x]+=sm[threadIdx.x+stride]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW; __syncthreads();}\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_relu_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,int64_t groups,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_shuffle_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor add_cuda(torch::Tensor a,torch::Tensor b){auto y=torch::empty_like(a); int total=a.numel(), th=256, bl=(total+th-1)/th; add_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(),b.data_ptr<float>(),y.data_ptr<float>(),total); return y;}\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_kernel<<<N*C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),N,C,HW,(float)eps); return y;}\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<1,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,int64_t groups,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,1><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_train_kernel<<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(float)eps); return y;}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v2', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda','bn_relu_train_cuda','bn_train_cuda','bn_shuffle_train_cuda','bn_relu_avg_train_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups): super().__init__(); self.groups=groups\n def forward(self,x):\n n,c,h,w=x.size(); g=self.groups\n return x.view(n,g,c//g,h,w).transpose(1,2).contiguous().view(n,c,h,w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self,in_channels,out_channels,groups=3):\n super().__init__(); assert out_channels%4==0; mid=out_channels//4; self.groups=groups\n self.conv1=nn.Conv2d(in_channels,mid,1,1,0,groups=groups,bias=False); self.bn1=nn.BatchNorm2d(mid)\n self.conv2=nn.Conv2d(mid,mid,3,1,1,groups=mid,bias=False); self.bn2=nn.BatchNorm2d(mid)\n self.conv3=nn.Conv2d(mid,out_channels,1,1,0,groups=groups,bias=False); self.bn3=nn.BatchNorm2d(out_channels)\n self.shuffle=ChannelShuffle(groups)\n self.shortcut=nn.Sequential() if in_channels==out_channels else nn.Sequential(nn.Conv2d(in_channels,out_channels,1,1,0,bias=False),nn.BatchNorm2d(out_channels))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n out=F.relu(self.bn1(self.conv1(x))); out=self.shuffle(self.bn2(self.conv2(out))); out=F.relu(self.bn3(self.conv3(out))); return out+self.shortcut(x)\n out=F.conv2d(x,self.conv1.weight,None,1,0,1,self.conv1.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n out=F.conv2d(out,self.conv2.weight,None,1,1,1,self.conv2.groups)\n out=(_ext.bn_shuffle_train_cuda(out,self.bn2.weight,self.bn2.bias,self.groups,self.bn2.eps) if self.training else _ext.bn_shuffle_eval_cuda(out,self.bn2.weight,self.bn2.bias,self.bn2.running_mean,self.bn2.running_var,self.groups,self.bn2.eps))\n out=F.conv2d(out,self.conv3.weight,None,1,0,1,self.conv3.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.running_mean,self.bn3.running_var,self.bn3.eps))\n if len(self.shortcut)==0: sc=x\n else:\n sc=F.conv2d(x,self.shortcut[0].weight,None,1,0,1,1)\n sc=(_ext.bn_train_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].eps) if self.training else _ext.bn_eval_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].running_mean,self.shortcut[1].running_var,self.shortcut[1].eps))\n return _ext.add_cuda(out,sc)\n\nclass ModelNew(nn.Module):\n def __init__(self,num_classes=1000,groups=3,stages_repeats=[3,7,3],stages_out_channels=[24,240,480,960]):\n super().__init__(); self.conv1=nn.Conv2d(3,stages_out_channels[0],3,2,1,bias=False); self.bn1=nn.BatchNorm2d(stages_out_channels[0]); self.maxpool=nn.MaxPool2d(3,2,1)\n self.stage2=self._make_stage(stages_out_channels[0],stages_out_channels[1],stages_repeats[0],groups); self.stage3=self._make_stage(stages_out_channels[1],stages_out_channels[2],stages_repeats[1],groups); self.stage4=self._make_stage(stages_out_channels[2],stages_out_channels[3],stages_repeats[2],groups)\n self.conv5=nn.Conv2d(stages_out_channels[3],1024,1,1,0,bias=False); self.bn5=nn.BatchNorm2d(1024); self.fc=nn.Linear(1024,num_classes)\n def _make_stage(self,ic,oc,repeats,groups): return nn.Sequential(*([ShuffleNetUnitNew(ic,oc,groups)]+[ShuffleNetUnitNew(oc,oc,groups) for _ in range(1,repeats)]))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n x=F.relu(self.bn1(self.conv1(x))); x=self.maxpool(x); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.relu(self.bn5(self.conv5(x))); x=F.adaptive_avg_pool2d(x,(1,1)); return self.fc(x.view(x.size(0),-1))\n x=F.conv2d(x,self.conv1.weight,None,2,1,1,1)\n x=(_ext.bn_relu_train_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n x=F.max_pool2d(x,3,2,1); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.conv2d(x,self.conv5.weight,None,1,0,1,1)\n x=(_ext.bn_relu_avg_train_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.eps) if self.training else _ext.bn_relu_avg_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.running_mean,self.bn5.running_var,self.bn5.eps))\n return F.linear(x,self.fc.weight,self.fc.bias)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 4 · 1 tool call(s) · 26.3s turn · 26.3s LLM · 15,764 chars (click to expand)
turn 426.3s turn · 26.3s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "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 bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t groups, double eps);\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; float val=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c]; y[idx]=val>0.f?val:0.f;}}\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; y[idx]=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c];}}\n__global__ void bn_shuffle_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,int groups,float eps){int out_idx=blockIdx.x*blockDim.x+threadIdx.x; if(out_idx<total){int hw=out_idx%HW; int tmp=out_idx/HW; int oc=tmp%C; int n=tmp/C; int cpg=C/groups; int cp=oc/groups; int gr=oc-cp*groups; int ic=gr*cpg+cp; int ii=(n*C+ic)*HW+hw; y[out_idx]=(x[ii]-m[ic])*(w[ic]*rsqrtf(v[ic]+eps))+b[ic];}}\n__global__ void add_kernel(const float* __restrict__ a,const float* __restrict__ b,float* __restrict__ y,int total){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total)y[idx]=a[idx]+b[idx];}\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int N,int C,int HW,float eps){int nc=blockIdx.x; int c=nc%C; int n=nc/C; const float* base=x+(n*C+c)*HW; float sc=w[c]*rsqrtf(v[c]+eps), sum=0.f; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-m[c])*sc+b[c]; sum+=val>0.f?val:0.f;} __shared__ float sm[256]; sm[threadIdx.x]=sum; __syncthreads(); for(int s=128;s>0;s>>=1){if(threadIdx.x<s)sm[threadIdx.x]+=sm[threadIdx.x+s]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW;}\n\ntemplate<int RELU, int SHUFFLE>\n__global__ void bn_train_ch_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,int groups,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n int oc=c; if(SHUFFLE){int cpg=C/groups; int gr=c/cpg; int cp=c-gr*cpg; oc=cp*groups+gr;}\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=(x[(n*C+c)*HW+hw]-mean)*sc+bb; if(RELU) val=val>0.f?val:0.f; y[(n*C+oc)*HW+hw]=val;}\n}\n\n__global__ void bn_relu_avg_train_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n for(int n=0;n<N;n++){float s=0.f; const float* base=x+(n*C+c)*HW; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-mean)*sc+bb; s+=val>0.f?val:0.f;} sm[threadIdx.x]=s; __syncthreads(); for(int stride=blockDim.x/2;stride>0;stride>>=1){if(threadIdx.x<stride)sm[threadIdx.x]+=sm[threadIdx.x+stride]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW; __syncthreads();}\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_relu_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,int64_t groups,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_shuffle_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor add_cuda(torch::Tensor a,torch::Tensor b){auto y=torch::empty_like(a); int total=a.numel(), th=256, bl=(total+th-1)/th; add_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(),b.data_ptr<float>(),y.data_ptr<float>(),total); return y;}\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_kernel<<<N*C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),N,C,HW,(float)eps); return y;}\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<1,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,int64_t groups,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,1><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_train_kernel<<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(float)eps); return y;}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v2', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda','bn_relu_train_cuda','bn_train_cuda','bn_shuffle_train_cuda','bn_relu_avg_train_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups): super().__init__(); self.groups=groups\n def forward(self,x):\n n,c,h,w=x.size(); g=self.groups\n return x.view(n,g,c//g,h,w).transpose(1,2).contiguous().view(n,c,h,w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self,in_channels,out_channels,groups=3):\n super().__init__(); assert out_channels%4==0; mid=out_channels//4; self.groups=groups\n self.conv1=nn.Conv2d(in_channels,mid,1,1,0,groups=groups,bias=False); self.bn1=nn.BatchNorm2d(mid)\n self.conv2=nn.Conv2d(mid,mid,3,1,1,groups=mid,bias=False); self.bn2=nn.BatchNorm2d(mid)\n self.conv3=nn.Conv2d(mid,out_channels,1,1,0,groups=groups,bias=False); self.bn3=nn.BatchNorm2d(out_channels)\n self.shuffle=ChannelShuffle(groups)\n self.shortcut=nn.Sequential() if in_channels==out_channels else nn.Sequential(nn.Conv2d(in_channels,out_channels,1,1,0,bias=False),nn.BatchNorm2d(out_channels))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n out=F.relu(self.bn1(self.conv1(x))); out=self.shuffle(self.bn2(self.conv2(out))); out=F.relu(self.bn3(self.conv3(out))); return out+self.shortcut(x)\n out=F.conv2d(x,self.conv1.weight,None,1,0,1,self.conv1.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n out=F.conv2d(out,self.conv2.weight,None,1,1,1,self.conv2.groups)\n out=(_ext.bn_shuffle_train_cuda(out,self.bn2.weight,self.bn2.bias,self.groups,self.bn2.eps) if self.training else _ext.bn_shuffle_eval_cuda(out,self.bn2.weight,self.bn2.bias,self.bn2.running_mean,self.bn2.running_var,self.groups,self.bn2.eps))\n out=F.conv2d(out,self.conv3.weight,None,1,0,1,self.conv3.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.running_mean,self.bn3.running_var,self.bn3.eps))\n if len(self.shortcut)==0: sc=x\n else:\n sc=F.conv2d(x,self.shortcut[0].weight,None,1,0,1,1)\n sc=(_ext.bn_train_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].eps) if self.training else _ext.bn_eval_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].running_mean,self.shortcut[1].running_var,self.shortcut[1].eps))\n return _ext.add_cuda(out,sc)\n\nclass ModelNew(nn.Module):\n def __init__(self,num_classes=1000,groups=3,stages_repeats=[3,7,3],stages_out_channels=[24,240,480,960]):\n super().__init__(); self.conv1=nn.Conv2d(3,stages_out_channels[0],3,2,1,bias=False); self.bn1=nn.BatchNorm2d(stages_out_channels[0]); self.maxpool=nn.MaxPool2d(3,2,1)\n self.stage2=self._make_stage(stages_out_channels[0],stages_out_channels[1],stages_repeats[0],groups); self.stage3=self._make_stage(stages_out_channels[1],stages_out_channels[2],stages_repeats[1],groups); self.stage4=self._make_stage(stages_out_channels[2],stages_out_channels[3],stages_repeats[2],groups)\n self.conv5=nn.Conv2d(stages_out_channels[3],1024,1,1,0,bias=False); self.bn5=nn.BatchNorm2d(1024); self.fc=nn.Linear(1024,num_classes)\n def _make_stage(self,ic,oc,repeats,groups): return nn.Sequential(*([ShuffleNetUnitNew(ic,oc,groups)]+[ShuffleNetUnitNew(oc,oc,groups) for _ in range(1,repeats)]))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n x=F.relu(self.bn1(self.conv1(x))); x=self.maxpool(x); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.relu(self.bn5(self.conv5(x))); x=F.adaptive_avg_pool2d(x,(1,1)); return self.fc(x.view(x.size(0),-1))\n x=F.conv2d(x,self.conv1.weight,None,2,1,1,1)\n x=(_ext.bn_relu_train_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n x=F.max_pool2d(x,3,2,1); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.conv2d(x,self.conv5.weight,None,1,0,1,1)\n x=(_ext.bn_relu_avg_train_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.eps) if self.training else _ext.bn_relu_avg_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.running_mean,self.bn5.running_var,self.bn5.eps))\n return F.linear(x,self.fc.weight,self.fc.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=1.48e-05 mean_abs_err=2.74e-06 max_rel_err=3.20e-01
turn 5 · 1 tool call(s) · 35.8s turn · 35.8s LLM · 18,070 chars (click to expand)
turn 535.8s turn · 35.8s LLM · 0.0s tools
reasoning
**Optimizing batch normalization** I'm considering benchmarks and potential optimizations for our Batch Normalization (BN) training. It might be beneficial to submit only the final version to save time. I notice our current BN training is likely slow due to two passes and low parallelism. PyTorch’s BN may achieve better performance by using more blocks. I'm exploring fusion techniques, like combining ReLU, shuffle, and average operations, which could impact the performance. If it slows down, I'll cross-reference for performance improvements. **Considering batch normalization optimizations** I'm pondering if using `model.eval()` later would affect timing during correctness checks. It seems like they might mostly compare timings separately without considering state. I wonder whether I could integrate the addition into the conv3 BN layer. If I customize the `bn_relu_add_train`, I could handle identity shortcuts more efficiently, which might allow me to fuse adds into BN training. This fusion could save memory and reduce the number of kernels needed, resulting in performance improvements. It sounds promising overall! **Exploring shortcut fusion possibilities** I'm looking into the possibility of fusing shortcut BN and addition for the non-identity units in the first stage. I think after the conv3 BN and ReLU, I could output the shortcut conv result. Perhaps I could create a function called `bn_train_add_cuda` to return the sum of the shortcut BN and the output, though it seems storing the conv3 output might not be necessary since there are only three units. I feel confident about implementing the identity addition fused version, but I need to keep an eye on the code length. **Evaluating code optimization** The final code is lengthy, and adding more functions may increase compilation time, but it could be worth it. I’m considering combining the bn2 train and shuffle while using stats per input C for writing output. Perhaps I should switch to `torch.add(out, sc)` instead of using a custom addition function, since our add kernel has no overhead. Also, I might use `torch.nn.functional.max_pool2d`. I need to decide on submitting v2 after a final static check.
call → static_check
callstatic_check { "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 bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t groups, double eps);\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; float val=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c]; y[idx]=val>0.f?val:0.f;}}\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; y[idx]=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c];}}\n__global__ void bn_shuffle_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,int groups,float eps){int out_idx=blockIdx.x*blockDim.x+threadIdx.x; if(out_idx<total){int hw=out_idx%HW; int tmp=out_idx/HW; int oc=tmp%C; int n=tmp/C; int cpg=C/groups; int cp=oc/groups; int gr=oc-cp*groups; int ic=gr*cpg+cp; int ii=(n*C+ic)*HW+hw; y[out_idx]=(x[ii]-m[ic])*(w[ic]*rsqrtf(v[ic]+eps))+b[ic];}}\n__global__ void add_kernel(const float* __restrict__ a,const float* __restrict__ b,float* __restrict__ y,int total){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total)y[idx]=a[idx]+b[idx];}\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int N,int C,int HW,float eps){int nc=blockIdx.x; int c=nc%C; int n=nc/C; const float* base=x+(n*C+c)*HW; float sc=w[c]*rsqrtf(v[c]+eps), sum=0.f; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-m[c])*sc+b[c]; sum+=val>0.f?val:0.f;} __shared__ float sm[256]; sm[threadIdx.x]=sum; __syncthreads(); for(int s=128;s>0;s>>=1){if(threadIdx.x<s)sm[threadIdx.x]+=sm[threadIdx.x+s]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW;}\n\ntemplate<int RELU, int SHUFFLE>\n__global__ void bn_train_ch_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,int groups,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n int oc=c; if(SHUFFLE){int cpg=C/groups; int gr=c/cpg; int cp=c-gr*cpg; oc=cp*groups+gr;}\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=(x[(n*C+c)*HW+hw]-mean)*sc+bb; if(RELU) val=val>0.f?val:0.f; y[(n*C+oc)*HW+hw]=val;}\n}\n\n__global__ void bn_relu_avg_train_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n for(int n=0;n<N;n++){float s=0.f; const float* base=x+(n*C+c)*HW; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-mean)*sc+bb; s+=val>0.f?val:0.f;} sm[threadIdx.x]=s; __syncthreads(); for(int stride=blockDim.x/2;stride>0;stride>>=1){if(threadIdx.x<stride)sm[threadIdx.x]+=sm[threadIdx.x+stride]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW; __syncthreads();}\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_relu_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,int64_t groups,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_shuffle_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor add_cuda(torch::Tensor a,torch::Tensor b){auto y=torch::empty_like(a); int total=a.numel(), th=256, bl=(total+th-1)/th; add_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(),b.data_ptr<float>(),y.data_ptr<float>(),total); return y;}\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_kernel<<<N*C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),N,C,HW,(float)eps); return y;}\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<1,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,int64_t groups,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,1><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_train_kernel<<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(float)eps); return y;}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v2', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda','bn_relu_train_cuda','bn_train_cuda','bn_shuffle_train_cuda','bn_relu_avg_train_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups): super().__init__(); self.groups=groups\n def forward(self,x):\n n,c,h,w=x.size(); g=self.groups\n return x.view(n,g,c//g,h,w).transpose(1,2).contiguous().view(n,c,h,w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self,in_channels,out_channels,groups=3):\n super().__init__(); assert out_channels%4==0; mid=out_channels//4; self.groups=groups\n self.conv1=nn.Conv2d(in_channels,mid,1,1,0,groups=groups,bias=False); self.bn1=nn.BatchNorm2d(mid)\n self.conv2=nn.Conv2d(mid,mid,3,1,1,groups=mid,bias=False); self.bn2=nn.BatchNorm2d(mid)\n self.conv3=nn.Conv2d(mid,out_channels,1,1,0,groups=groups,bias=False); self.bn3=nn.BatchNorm2d(out_channels)\n self.shuffle=ChannelShuffle(groups)\n self.shortcut=nn.Sequential() if in_channels==out_channels else nn.Sequential(nn.Conv2d(in_channels,out_channels,1,1,0,bias=False),nn.BatchNorm2d(out_channels))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n out=F.relu(self.bn1(self.conv1(x))); out=self.shuffle(self.bn2(self.conv2(out))); out=F.relu(self.bn3(self.conv3(out))); return out+self.shortcut(x)\n out=F.conv2d(x,self.conv1.weight,None,1,0,1,self.conv1.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n out=F.conv2d(out,self.conv2.weight,None,1,1,1,self.conv2.groups)\n out=(_ext.bn_shuffle_train_cuda(out,self.bn2.weight,self.bn2.bias,self.groups,self.bn2.eps) if self.training else _ext.bn_shuffle_eval_cuda(out,self.bn2.weight,self.bn2.bias,self.bn2.running_mean,self.bn2.running_var,self.groups,self.bn2.eps))\n out=F.conv2d(out,self.conv3.weight,None,1,0,1,self.conv3.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.running_mean,self.bn3.running_var,self.bn3.eps))\n if len(self.shortcut)==0: sc=x\n else:\n sc=F.conv2d(x,self.shortcut[0].weight,None,1,0,1,1)\n sc=(_ext.bn_train_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].eps) if self.training else _ext.bn_eval_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].running_mean,self.shortcut[1].running_var,self.shortcut[1].eps))\n return _ext.add_cuda(out,sc)\n\nclass ModelNew(nn.Module):\n def __init__(self,num_classes=1000,groups=3,stages_repeats=[3,7,3],stages_out_channels=[24,240,480,960]):\n super().__init__(); self.conv1=nn.Conv2d(3,stages_out_channels[0],3,2,1,bias=False); self.bn1=nn.BatchNorm2d(stages_out_channels[0]); self.maxpool=nn.MaxPool2d(3,2,1)\n self.stage2=self._make_stage(stages_out_channels[0],stages_out_channels[1],stages_repeats[0],groups); self.stage3=self._make_stage(stages_out_channels[1],stages_out_channels[2],stages_repeats[1],groups); self.stage4=self._make_stage(stages_out_channels[2],stages_out_channels[3],stages_repeats[2],groups)\n self.conv5=nn.Conv2d(stages_out_channels[3],1024,1,1,0,bias=False); self.bn5=nn.BatchNorm2d(1024); self.fc=nn.Linear(1024,num_classes)\n def _make_stage(self,ic,oc,repeats,groups): return nn.Sequential(*([ShuffleNetUnitNew(ic,oc,groups)]+[ShuffleNetUnitNew(oc,oc,groups) for _ in range(1,repeats)]))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n x=F.relu(self.bn1(self.conv1(x))); x=self.maxpool(x); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.relu(self.bn5(self.conv5(x))); x=F.adaptive_avg_pool2d(x,(1,1)); return self.fc(x.view(x.size(0),-1))\n x=F.conv2d(x,self.conv1.weight,None,2,1,1,1)\n x=(_ext.bn_relu_train_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n x=F.max_pool2d(x,3,2,1); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.conv2d(x,self.conv5.weight,None,1,0,1,1)\n x=(_ext.bn_relu_avg_train_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.eps) if self.training else _ext.bn_relu_avg_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.running_mean,self.bn5.running_var,self.bn5.eps))\n return F.linear(x,self.fc.weight,self.fc.bias)\n" }
result ← static_check (ok)
okstatic_check static_check PASSED (with warnings): WARNING: Uses torch.nn.functional op: F.relu WARNING: Uses torch.nn compute layer (only containers, Parameter, init allowed)
turn 6 · FINAL · 1 tool call(s) · 23.3s turn · 23.3s LLM · 16,023 chars (click to expand)
turn 623.3s turn · 23.3s LLM · 0.0s tools · FINAL
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 bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);\ntorch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t groups, double eps);\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);\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__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; float val=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c]; y[idx]=val>0.f?val:0.f;}}\n__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; y[idx]=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c];}}\n__global__ void bn_shuffle_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,int groups,float eps){int out_idx=blockIdx.x*blockDim.x+threadIdx.x; if(out_idx<total){int hw=out_idx%HW; int tmp=out_idx/HW; int oc=tmp%C; int n=tmp/C; int cpg=C/groups; int cp=oc/groups; int gr=oc-cp*groups; int ic=gr*cpg+cp; int ii=(n*C+ic)*HW+hw; y[out_idx]=(x[ii]-m[ic])*(w[ic]*rsqrtf(v[ic]+eps))+b[ic];}}\n__global__ void add_kernel(const float* __restrict__ a,const float* __restrict__ b,float* __restrict__ y,int total){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total)y[idx]=a[idx]+b[idx];}\n__global__ void bn_relu_avg_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int N,int C,int HW,float eps){int nc=blockIdx.x; int c=nc%C; int n=nc/C; const float* base=x+(n*C+c)*HW; float sc=w[c]*rsqrtf(v[c]+eps), sum=0.f; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-m[c])*sc+b[c]; sum+=val>0.f?val:0.f;} __shared__ float sm[256]; sm[threadIdx.x]=sum; __syncthreads(); for(int s=128;s>0;s>>=1){if(threadIdx.x<s)sm[threadIdx.x]+=sm[threadIdx.x+s]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW;}\n\ntemplate<int RELU, int SHUFFLE>\n__global__ void bn_train_ch_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,int groups,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n int oc=c; if(SHUFFLE){int cpg=C/groups; int gr=c/cpg; int cp=c-gr*cpg; oc=cp*groups+gr;}\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=(x[(n*C+c)*HW+hw]-mean)*sc+bb; if(RELU) val=val>0.f?val:0.f; y[(n*C+oc)*HW+hw]=val;}\n}\n\n__global__ void bn_relu_avg_train_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,float eps){\n int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;\n for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}\n __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();\n for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}\n float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];\n for(int n=0;n<N;n++){float s=0.f; const float* base=x+(n*C+c)*HW; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-mean)*sc+bb; s+=val>0.f?val:0.f;} sm[threadIdx.x]=s; __syncthreads(); for(int stride=blockDim.x/2;stride>0;stride>>=1){if(threadIdx.x<stride)sm[threadIdx.x]+=sm[threadIdx.x+stride]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW; __syncthreads();}\n}\n\ntorch::Tensor bn_relu_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_relu_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}\ntorch::Tensor bn_shuffle_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,int64_t groups,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_shuffle_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor add_cuda(torch::Tensor a,torch::Tensor b){auto y=torch::empty_like(a); int total=a.numel(), th=256, bl=(total+th-1)/th; add_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(),b.data_ptr<float>(),y.data_ptr<float>(),total); return y;}\ntorch::Tensor bn_relu_avg_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_kernel<<<N*C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),N,C,HW,(float)eps); return y;}\ntorch::Tensor bn_relu_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<1,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}\ntorch::Tensor bn_shuffle_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,int64_t groups,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,1><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(int)groups,(float)eps); return y;}\ntorch::Tensor bn_relu_avg_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_train_kernel<<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(float)eps); return y;}\n'''\n\n_ext = load_inline(name='shufflenet_ext_v2', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda','bn_relu_train_cuda','bn_train_cuda','bn_shuffle_train_cuda','bn_relu_avg_train_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)\n\nclass ChannelShuffle(nn.Module):\n def __init__(self, groups): super().__init__(); self.groups=groups\n def forward(self,x):\n n,c,h,w=x.size(); g=self.groups\n return x.view(n,g,c//g,h,w).transpose(1,2).contiguous().view(n,c,h,w)\n\nclass ShuffleNetUnitNew(nn.Module):\n def __init__(self,in_channels,out_channels,groups=3):\n super().__init__(); assert out_channels%4==0; mid=out_channels//4; self.groups=groups\n self.conv1=nn.Conv2d(in_channels,mid,1,1,0,groups=groups,bias=False); self.bn1=nn.BatchNorm2d(mid)\n self.conv2=nn.Conv2d(mid,mid,3,1,1,groups=mid,bias=False); self.bn2=nn.BatchNorm2d(mid)\n self.conv3=nn.Conv2d(mid,out_channels,1,1,0,groups=groups,bias=False); self.bn3=nn.BatchNorm2d(out_channels)\n self.shuffle=ChannelShuffle(groups)\n self.shortcut=nn.Sequential() if in_channels==out_channels else nn.Sequential(nn.Conv2d(in_channels,out_channels,1,1,0,bias=False),nn.BatchNorm2d(out_channels))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n out=F.relu(self.bn1(self.conv1(x))); out=self.shuffle(self.bn2(self.conv2(out))); out=F.relu(self.bn3(self.conv3(out))); return out+self.shortcut(x)\n out=F.conv2d(x,self.conv1.weight,None,1,0,1,self.conv1.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n out=F.conv2d(out,self.conv2.weight,None,1,1,1,self.conv2.groups)\n out=(_ext.bn_shuffle_train_cuda(out,self.bn2.weight,self.bn2.bias,self.groups,self.bn2.eps) if self.training else _ext.bn_shuffle_eval_cuda(out,self.bn2.weight,self.bn2.bias,self.bn2.running_mean,self.bn2.running_var,self.groups,self.bn2.eps))\n out=F.conv2d(out,self.conv3.weight,None,1,0,1,self.conv3.groups)\n out=(_ext.bn_relu_train_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.running_mean,self.bn3.running_var,self.bn3.eps))\n if len(self.shortcut)==0: sc=x\n else:\n sc=F.conv2d(x,self.shortcut[0].weight,None,1,0,1,1)\n sc=(_ext.bn_train_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].eps) if self.training else _ext.bn_eval_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].running_mean,self.shortcut[1].running_var,self.shortcut[1].eps))\n return _ext.add_cuda(out,sc)\n\nclass ModelNew(nn.Module):\n def __init__(self,num_classes=1000,groups=3,stages_repeats=[3,7,3],stages_out_channels=[24,240,480,960]):\n super().__init__(); self.conv1=nn.Conv2d(3,stages_out_channels[0],3,2,1,bias=False); self.bn1=nn.BatchNorm2d(stages_out_channels[0]); self.maxpool=nn.MaxPool2d(3,2,1)\n self.stage2=self._make_stage(stages_out_channels[0],stages_out_channels[1],stages_repeats[0],groups); self.stage3=self._make_stage(stages_out_channels[1],stages_out_channels[2],stages_repeats[1],groups); self.stage4=self._make_stage(stages_out_channels[2],stages_out_channels[3],stages_repeats[2],groups)\n self.conv5=nn.Conv2d(stages_out_channels[3],1024,1,1,0,bias=False); self.bn5=nn.BatchNorm2d(1024); self.fc=nn.Linear(1024,num_classes)\n def _make_stage(self,ic,oc,repeats,groups): return nn.Sequential(*([ShuffleNetUnitNew(ic,oc,groups)]+[ShuffleNetUnitNew(oc,oc,groups) for _ in range(1,repeats)]))\n def forward(self,x):\n if x.dtype!=torch.float32 or not x.is_cuda:\n x=F.relu(self.bn1(self.conv1(x))); x=self.maxpool(x); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.relu(self.bn5(self.conv5(x))); x=F.adaptive_avg_pool2d(x,(1,1)); return self.fc(x.view(x.size(0),-1))\n x=F.conv2d(x,self.conv1.weight,None,2,1,1,1)\n x=(_ext.bn_relu_train_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))\n x=F.max_pool2d(x,3,2,1); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.conv2d(x,self.conv5.weight,None,1,0,1,1)\n x=(_ext.bn_relu_avg_train_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.eps) if self.training else _ext.bn_relu_avg_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.running_mean,self.bn5.running_var,self.bn5.eps))\n return F.linear(x,self.fc.weight,self.fc.bias)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 9.57 μs Runtime stats: mean=9.57μs median=?μs std=0.49μs Numerical precision: max_abs_err=1.48e-05 mean_abs_err=2.74e-06 max_rel_err=3.20e-01 Memory: 467.87 MB peak (ref: 496.58 MB, ratio: 0.9422x) Kernel launches: 322 (ref: 882, fusion ratio: 2.7391) Energy: 1527.24 mJ/run (ref: 1527.26 mJ, ratio: 1.0x) SOL score: 0.1022
final submitted kernel (107 lines, 14,269 chars) — full source, untruncated
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.cpp_extension import load_inline

_cpp_src = r'''
#include <torch/extension.h>
torch::Tensor bn_relu_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);
torch::Tensor bn_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);
torch::Tensor bn_shuffle_eval_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, int64_t groups, double eps);
torch::Tensor add_cuda(torch::Tensor a, torch::Tensor b);
torch::Tensor bn_relu_avg_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, torch::Tensor mean, torch::Tensor var, double eps);
torch::Tensor bn_relu_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);
torch::Tensor bn_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);
torch::Tensor bn_shuffle_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, int64_t groups, double eps);
torch::Tensor bn_relu_avg_train_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double eps);
'''

_cuda_src = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <ATen/cuda/CUDAContext.h>

__global__ void bn_relu_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; float val=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c]; y[idx]=val>0.f?val:0.f;}}
__global__ void bn_kernel(const float* __restrict__ x, float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,float eps){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total){int c=(idx/HW)%C; y[idx]=(x[idx]-m[c])*(w[c]*rsqrtf(v[c]+eps))+b[c];}}
__global__ void bn_shuffle_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int total,int C,int HW,int groups,float eps){int out_idx=blockIdx.x*blockDim.x+threadIdx.x; if(out_idx<total){int hw=out_idx%HW; int tmp=out_idx/HW; int oc=tmp%C; int n=tmp/C; int cpg=C/groups; int cp=oc/groups; int gr=oc-cp*groups; int ic=gr*cpg+cp; int ii=(n*C+ic)*HW+hw; y[out_idx]=(x[ii]-m[ic])*(w[ic]*rsqrtf(v[ic]+eps))+b[ic];}}
__global__ void add_kernel(const float* __restrict__ a,const float* __restrict__ b,float* __restrict__ y,int total){int idx=blockIdx.x*blockDim.x+threadIdx.x; if(idx<total)y[idx]=a[idx]+b[idx];}
__global__ void bn_relu_avg_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,const float* __restrict__ m,const float* __restrict__ v,int N,int C,int HW,float eps){int nc=blockIdx.x; int c=nc%C; int n=nc/C; const float* base=x+(n*C+c)*HW; float sc=w[c]*rsqrtf(v[c]+eps), sum=0.f; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-m[c])*sc+b[c]; sum+=val>0.f?val:0.f;} __shared__ float sm[256]; sm[threadIdx.x]=sum; __syncthreads(); for(int s=128;s>0;s>>=1){if(threadIdx.x<s)sm[threadIdx.x]+=sm[threadIdx.x+s]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW;}

template<int RELU, int SHUFFLE>
__global__ void bn_train_ch_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,int groups,float eps){
    int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;
    for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}
    __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();
    for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}
    float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];
    int oc=c; if(SHUFFLE){int cpg=C/groups; int gr=c/cpg; int cp=c-gr*cpg; oc=cp*groups+gr;}
    for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=(x[(n*C+c)*HW+hw]-mean)*sc+bb; if(RELU) val=val>0.f?val:0.f; y[(n*C+oc)*HW+hw]=val;}
}

__global__ void bn_relu_avg_train_kernel(const float* __restrict__ x,float* __restrict__ y,const float* __restrict__ w,const float* __restrict__ b,int N,int C,int HW,float eps){
    int c=blockIdx.x; int M=N*HW; float sum=0.f, ss=0.f;
    for(int j=threadIdx.x;j<M;j+=blockDim.x){int n=j/HW; int hw=j-n*HW; float val=x[(n*C+c)*HW+hw]; sum+=val; ss+=val*val;}
    __shared__ float sm[512]; sm[threadIdx.x]=sum; sm[threadIdx.x+blockDim.x]=ss; __syncthreads();
    for(int s=blockDim.x/2;s>0;s>>=1){if(threadIdx.x<s){sm[threadIdx.x]+=sm[threadIdx.x+s]; sm[threadIdx.x+blockDim.x]+=sm[threadIdx.x+blockDim.x+s];} __syncthreads();}
    float mean=sm[0]/(float)M; float var=sm[blockDim.x]/(float)M - mean*mean; if(var<0.f) var=0.f; float sc=w[c]*rsqrtf(var+eps); float bb=b[c];
    for(int n=0;n<N;n++){float s=0.f; const float* base=x+(n*C+c)*HW; for(int i=threadIdx.x;i<HW;i+=blockDim.x){float val=(base[i]-mean)*sc+bb; s+=val>0.f?val:0.f;} sm[threadIdx.x]=s; __syncthreads(); for(int stride=blockDim.x/2;stride>0;stride>>=1){if(threadIdx.x<stride)sm[threadIdx.x]+=sm[threadIdx.x+stride]; __syncthreads();} if(threadIdx.x==0)y[n*C+c]=sm[0]/(float)HW; __syncthreads();}
}

torch::Tensor bn_relu_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_relu_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}
torch::Tensor bn_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(float)eps); return y;}
torch::Tensor bn_shuffle_eval_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,int64_t groups,double eps){auto y=torch::empty_like(x); int total=x.numel(),C=x.size(1),HW=x.size(2)*x.size(3); int th=256, bl=(total+th-1)/th; bn_shuffle_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),total,C,HW,(int)groups,(float)eps); return y;}
torch::Tensor add_cuda(torch::Tensor a,torch::Tensor b){auto y=torch::empty_like(a); int total=a.numel(), th=256, bl=(total+th-1)/th; add_kernel<<<bl,th,0,at::cuda::getCurrentCUDAStream()>>>(a.data_ptr<float>(),b.data_ptr<float>(),y.data_ptr<float>(),total); return y;}
torch::Tensor bn_relu_avg_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,torch::Tensor mean,torch::Tensor var,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_kernel<<<N*C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),mean.data_ptr<float>(),var.data_ptr<float>(),N,C,HW,(float)eps); return y;}
torch::Tensor bn_relu_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<1,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}
torch::Tensor bn_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,0><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,1,(float)eps); return y;}
torch::Tensor bn_shuffle_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,int64_t groups,double eps){auto y=torch::empty_like(x); int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); bn_train_ch_kernel<0,1><<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(int)groups,(float)eps); return y;}
torch::Tensor bn_relu_avg_train_cuda(torch::Tensor x,torch::Tensor weight,torch::Tensor bias,double eps){int N=x.size(0),C=x.size(1),HW=x.size(2)*x.size(3); auto y=torch::empty({N,C},x.options()); bn_relu_avg_train_kernel<<<C,256,0,at::cuda::getCurrentCUDAStream()>>>(x.data_ptr<float>(),y.data_ptr<float>(),weight.data_ptr<float>(),bias.data_ptr<float>(),N,C,HW,(float)eps); return y;}
'''

_ext = load_inline(name='shufflenet_ext_v2', cpp_sources=[_cpp_src], cuda_sources=[_cuda_src], functions=['bn_relu_eval_cuda','bn_eval_cuda','bn_shuffle_eval_cuda','add_cuda','bn_relu_avg_cuda','bn_relu_train_cuda','bn_train_cuda','bn_shuffle_train_cuda','bn_relu_avg_train_cuda'], extra_cflags=['-O3'], extra_cuda_cflags=['-O3'], verbose=False)

class ChannelShuffle(nn.Module):
    def __init__(self, groups): super().__init__(); self.groups=groups
    def forward(self,x):
        n,c,h,w=x.size(); g=self.groups
        return x.view(n,g,c//g,h,w).transpose(1,2).contiguous().view(n,c,h,w)

class ShuffleNetUnitNew(nn.Module):
    def __init__(self,in_channels,out_channels,groups=3):
        super().__init__(); assert out_channels%4==0; mid=out_channels//4; self.groups=groups
        self.conv1=nn.Conv2d(in_channels,mid,1,1,0,groups=groups,bias=False); self.bn1=nn.BatchNorm2d(mid)
        self.conv2=nn.Conv2d(mid,mid,3,1,1,groups=mid,bias=False); self.bn2=nn.BatchNorm2d(mid)
        self.conv3=nn.Conv2d(mid,out_channels,1,1,0,groups=groups,bias=False); self.bn3=nn.BatchNorm2d(out_channels)
        self.shuffle=ChannelShuffle(groups)
        self.shortcut=nn.Sequential() if in_channels==out_channels else nn.Sequential(nn.Conv2d(in_channels,out_channels,1,1,0,bias=False),nn.BatchNorm2d(out_channels))
    def forward(self,x):
        if x.dtype!=torch.float32 or not x.is_cuda:
            out=F.relu(self.bn1(self.conv1(x))); out=self.shuffle(self.bn2(self.conv2(out))); out=F.relu(self.bn3(self.conv3(out))); return out+self.shortcut(x)
        out=F.conv2d(x,self.conv1.weight,None,1,0,1,self.conv1.groups)
        out=(_ext.bn_relu_train_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))
        out=F.conv2d(out,self.conv2.weight,None,1,1,1,self.conv2.groups)
        out=(_ext.bn_shuffle_train_cuda(out,self.bn2.weight,self.bn2.bias,self.groups,self.bn2.eps) if self.training else _ext.bn_shuffle_eval_cuda(out,self.bn2.weight,self.bn2.bias,self.bn2.running_mean,self.bn2.running_var,self.groups,self.bn2.eps))
        out=F.conv2d(out,self.conv3.weight,None,1,0,1,self.conv3.groups)
        out=(_ext.bn_relu_train_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.eps) if self.training else _ext.bn_relu_eval_cuda(out,self.bn3.weight,self.bn3.bias,self.bn3.running_mean,self.bn3.running_var,self.bn3.eps))
        if len(self.shortcut)==0: sc=x
        else:
            sc=F.conv2d(x,self.shortcut[0].weight,None,1,0,1,1)
            sc=(_ext.bn_train_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].eps) if self.training else _ext.bn_eval_cuda(sc,self.shortcut[1].weight,self.shortcut[1].bias,self.shortcut[1].running_mean,self.shortcut[1].running_var,self.shortcut[1].eps))
        return _ext.add_cuda(out,sc)

class ModelNew(nn.Module):
    def __init__(self,num_classes=1000,groups=3,stages_repeats=[3,7,3],stages_out_channels=[24,240,480,960]):
        super().__init__(); self.conv1=nn.Conv2d(3,stages_out_channels[0],3,2,1,bias=False); self.bn1=nn.BatchNorm2d(stages_out_channels[0]); self.maxpool=nn.MaxPool2d(3,2,1)
        self.stage2=self._make_stage(stages_out_channels[0],stages_out_channels[1],stages_repeats[0],groups); self.stage3=self._make_stage(stages_out_channels[1],stages_out_channels[2],stages_repeats[1],groups); self.stage4=self._make_stage(stages_out_channels[2],stages_out_channels[3],stages_repeats[2],groups)
        self.conv5=nn.Conv2d(stages_out_channels[3],1024,1,1,0,bias=False); self.bn5=nn.BatchNorm2d(1024); self.fc=nn.Linear(1024,num_classes)
    def _make_stage(self,ic,oc,repeats,groups): return nn.Sequential(*([ShuffleNetUnitNew(ic,oc,groups)]+[ShuffleNetUnitNew(oc,oc,groups) for _ in range(1,repeats)]))
    def forward(self,x):
        if x.dtype!=torch.float32 or not x.is_cuda:
            x=F.relu(self.bn1(self.conv1(x))); x=self.maxpool(x); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.relu(self.bn5(self.conv5(x))); x=F.adaptive_avg_pool2d(x,(1,1)); return self.fc(x.view(x.size(0),-1))
        x=F.conv2d(x,self.conv1.weight,None,2,1,1,1)
        x=(_ext.bn_relu_train_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.eps) if self.training else _ext.bn_relu_eval_cuda(x,self.bn1.weight,self.bn1.bias,self.bn1.running_mean,self.bn1.running_var,self.bn1.eps))
        x=F.max_pool2d(x,3,2,1); x=self.stage2(x); x=self.stage3(x); x=self.stage4(x); x=F.conv2d(x,self.conv5.weight,None,1,0,1,1)
        x=(_ext.bn_relu_avg_train_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.eps) if self.training else _ext.bn_relu_avg_cuda(x,self.bn5.weight,self.bn5.bias,self.bn5.running_mean,self.bn5.running_var,self.bn5.eps))
        return F.linear(x,self.fc.weight,self.fc.bias)