gpt-5.5-priority · original · l123_single_gpt
incorrect 22_EfficientNetB0.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
—
ref runtime
4.81 μs
speedup
—
started
2026-05-05T02:09:35Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel runtime
—
ref runtime
4.81 μs
speedup
—
kernel mean / median / std
—
ref mean / median / std
4.81 / — / 12.80 μs
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 Model(nn.Module):
    def __init__(self, num_classes=1000):
        """
        EfficientNetB0 architecture implementation in PyTorch.

        :param num_classes: The number of output classes (default is 1000 for ImageNet).
        """
        super(Model, self).__init__()
        
        # Initial convolutional layer
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(32)
        
        # MBConv blocks
        self.blocks = nn.Sequential(
            # MBConv1 (32, 16, 1, 1)
            MBConv(32, 16, kernel_size=3, stride=1, expand_ratio=1),
            # MBConv6 (16, 24, 2, 6)
            MBConv(16, 24, kernel_size=3, stride=2, expand_ratio=6),
            # MBConv6 (24, 24, 1, 6)
            MBConv(24, 24, kernel_size=3, stride=1, expand_ratio=6),
            # MBConv6 (24, 40, 2, 6)
            MBConv(24, 40, kernel_size=5, stride=2, expand_ratio=6),
            # MBConv6 (40, 40, 1, 6)
            MBConv(40, 40, kernel_size=5, stride=1, expand_ratio=6),
            # MBConv6 (40, 80, 2, 6)
            MBConv(40, 80, kernel_size=3, stride=2, expand_ratio=6),
            # MBConv6 (80, 80, 1, 6)
            MBConv(80, 80, kernel_size=3, stride=1, expand_ratio=6),
            # MBConv6 (80, 112, 1, 6)
            MBConv(80, 112, kernel_size=5, stride=1, expand_ratio=6),
            # MBConv6 (112, 112, 1, 6)
            MBConv(112, 112, kernel_size=5, stride=1, expand_ratio=6),
            # MBConv6 (112, 192, 2, 6)
            MBConv(112, 192, kernel_size=5, stride=2, expand_ratio=6),
            # MBConv6 (192, 192, 1, 6)
            MBConv(192, 192, kernel_size=5, stride=1, expand_ratio=6),
            # MBConv6 (192, 192, 1, 6)
            MBConv(192, 192, kernel_size=5, stride=1, expand_ratio=6),
            # MBConv6 (192, 320, 1, 6)
            MBConv(192, 320, kernel_size=3, stride=1, expand_ratio=6)
        )
        
        # Final convolutional layer
        self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn2 = nn.BatchNorm2d(1280)
        
        # Fully connected layer
        self.fc = nn.Linear(1280, num_classes)
    
    def forward(self, x):
        """
        Forward pass of the EfficientNetB0 model.

        :param x: The input tensor, shape (batch_size, 3, 224, 224)
        :return: The output tensor, shape (batch_size, num_classes)
        """
        x = F.relu(self.bn1(self.conv1(x)))
        x = self.blocks(x)
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.adaptive_avg_pool2d(x, (1, 1))
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

class MBConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio):
        """
        MBConv block implementation.

        :param in_channels: Number of input channels.
        :param out_channels: Number of output channels.
        :param kernel_size: Kernel size for the depthwise convolution.
        :param stride: Stride for the depthwise convolution.
        :param expand_ratio: Expansion ratio for the intermediate channels.
        """
        super(MBConv, self).__init__()
        
        self.use_residual = (stride == 1 and in_channels == out_channels)
        hidden_dim = in_channels * expand_ratio
        
        if expand_ratio != 1:
            self.expand_conv = nn.Sequential(
                nn.Conv2d(in_channels, hidden_dim, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(hidden_dim),
                nn.ReLU6(inplace=True)
            )
        
        self.depthwise_conv = nn.Sequential(
            nn.Conv2d(hidden_dim, hidden_dim, kernel_size=kernel_size, stride=stride, padding=(kernel_size-1)//2, groups=hidden_dim, bias=False),
            nn.BatchNorm2d(hidden_dim),
            nn.ReLU6(inplace=True)
        )
        
        self.project_conv = nn.Sequential(
            nn.Conv2d(hidden_dim, out_channels, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(out_channels)
        )
    
    def forward(self, x):
        """
        Forward pass of the MBConv block.

        :param x: The input tensor, shape (batch_size, in_channels, H, W)
        :return: The output tensor, shape (batch_size, out_channels, H', W')
        """
        identity = x
        
        if hasattr(self, 'expand_conv'):
            x = self.expand_conv(x)
        
        x = self.depthwise_conv(x)
        x = self.project_conv(x)
        
        if self.use_residual:
            x += identity
        
        return x

# Test code
batch_size = 10
num_classes = 1000

def get_inputs():
    return [torch.rand(batch_size, 3, 224, 224)]

def get_init_inputs():
    return [num_classes]
turn 0 · FINAL · 1 tool call(s) · 93.9s turn · 93.9s LLM · 12,585 chars (click to expand)
turn 093.9s turn · 93.9s LLM · 0.0s tools · FINAL
reasoning
**Analyzing PyTorch implementations** It seems like the custom average pooling with F.linear is functioning well, but using F.adaptive_avg_pool2d might offer better accuracy. I wonder if the differences might lead to noticeable errors — perhaps under 1e-6? For batch normalization, I think PyTorch’s evaluation might use a specific formula that could differ slightly from expectations, with a difference around 1e-5. Over multiple layers, those differences might amplify. To align with PyTorch closely, I could adjust using float scale and shift parameters. For the residual, it would be v = x*scale + shift + id. Let’s dig deeper for accuracy! **Evaluating EfficientNet with Batch Norm** I'm considering that using EfficientNet with batch normalization (BN) could lead to outputs that depend on batch statistics. However, the reference runtime includes slow reductions when training. It seems like my custom eval output isn't working properly. I wonder if calling PyTorch's batch normalization for training would help, but if it's self-training, I might need to consider fallback modules. I think implementing a custom training batch normalization fused method could improve correctness while training. **Considering tool calls** I'm thinking about how to approach the situation with the tools. If we refer to "harness calls train," it could mean something regarding evaluation, but I shouldn't assume that it's always necessary. Maybe the final answer should derive from a direct tool call since we only have one tool to use. It's important to get this right for clarity and efficiency! Let's make sure I'm following the best route possible here.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor bn_act_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor mean, torch::Tensor var, double eps, int act);\ntorch::Tensor bn_add_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor mean, torch::Tensor var, torch::Tensor residual, double eps);\ntorch::Tensor avgpool2d(torch::Tensor x);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n\n__global__ void bn_act_ch_kernel(float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n int C, int HW, float eps, int act) {\n int nc = blockIdx.x;\n int c = nc % C;\n long base = (long)nc * (long)HW;\n float scale = weight[c] * rsqrtf(var[c] + eps);\n float shift = bias[c] - mean[c] * scale;\n for (int i = threadIdx.x; i < HW; i += blockDim.x) {\n float v = fmaf(x[base + i], scale, shift);\n if (act == 1) {\n v = v > 0.0f ? v : 0.0f;\n } else if (act == 2) {\n v = v > 0.0f ? v : 0.0f;\n v = v < 6.0f ? v : 6.0f;\n }\n x[base + i] = v;\n }\n}\n\n__global__ void bn_add_ch_kernel(float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n const float* __restrict__ residual,\n int C, int HW, float eps) {\n int nc = blockIdx.x;\n int c = nc % C;\n long base = (long)nc * (long)HW;\n float scale = weight[c] * rsqrtf(var[c] + eps);\n float shift = bias[c] - mean[c] * scale;\n for (int i = threadIdx.x; i < HW; i += blockDim.x) {\n float v = fmaf(x[base + i], scale, shift);\n x[base + i] = v + residual[base + i];\n }\n}\n\n__global__ void avgpool_ch_kernel(const float* __restrict__ x,\n float* __restrict__ out,\n int C, int HW) {\n int nc = blockIdx.x;\n long base = (long)nc * (long)HW;\n float sum = 0.0f;\n for (int i = threadIdx.x; i < HW; i += blockDim.x) {\n sum += x[base + i];\n }\n __shared__ float smem[256];\n smem[threadIdx.x] = sum;\n __syncthreads();\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) smem[threadIdx.x] += smem[threadIdx.x + stride];\n __syncthreads();\n }\n if (threadIdx.x == 0) out[nc] = smem[0] / (float)HW;\n}\n\ntorch::Tensor bn_act_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor mean, torch::Tensor var, double eps, int act) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int HW = H * W;\n const int blocks = N * C;\n bn_act_ch_kernel<<<blocks, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), C, HW, (float)eps, act);\n return x;\n}\n\ntorch::Tensor bn_add_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n torch::Tensor mean, torch::Tensor var, torch::Tensor residual, double eps) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int HW = H * W;\n const int blocks = N * C;\n bn_add_ch_kernel<<<blocks, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), residual.data_ptr<float>(),\n C, HW, (float)eps);\n return x;\n}\n\ntorch::Tensor avgpool2d(torch::Tensor x) {\n const int N = (int)x.size(0);\n const int C = (int)x.size(1);\n const int H = (int)x.size(2);\n const int W = (int)x.size(3);\n const int HW = H * W;\n auto out = torch::empty({N, C}, x.options());\n avgpool_ch_kernel<<<N * C, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), out.data_ptr<float>(), C, HW);\n return out;\n}\n\"\"\"\n\n_effnet_fused = load_inline(\n name=\"effnet_b0_fused_bn_relu_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"bn_act_\", \"bn_add_\", \"avgpool2d\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\n\nclass _MBConvNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio):\n super(_MBConvNew, self).__init__()\n self.use_residual = (stride == 1 and in_channels == out_channels)\n hidden_dim = in_channels * expand_ratio\n if expand_ratio != 1:\n self.expand_conv = nn.Sequential(\n nn.Conv2d(in_channels, hidden_dim, kernel_size=1, stride=1, padding=0, bias=False),\n nn.BatchNorm2d(hidden_dim),\n nn.ReLU6(inplace=True),\n )\n self.depthwise_conv = nn.Sequential(\n nn.Conv2d(hidden_dim, hidden_dim, kernel_size=kernel_size, stride=stride,\n padding=(kernel_size - 1) // 2, groups=hidden_dim, bias=False),\n nn.BatchNorm2d(hidden_dim),\n nn.ReLU6(inplace=True),\n )\n self.project_conv = nn.Sequential(\n nn.Conv2d(hidden_dim, out_channels, kernel_size=1, stride=1, padding=0, bias=False),\n nn.BatchNorm2d(out_channels),\n )\n\n\nclass ModelNew(nn.Module):\n def __init__(self, num_classes=1000):\n super(ModelNew, self).__init__()\n self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False)\n self.bn1 = nn.BatchNorm2d(32)\n self.blocks = nn.Sequential(\n _MBConvNew(32, 16, kernel_size=3, stride=1, expand_ratio=1),\n _MBConvNew(16, 24, kernel_size=3, stride=2, expand_ratio=6),\n _MBConvNew(24, 24, kernel_size=3, stride=1, expand_ratio=6),\n _MBConvNew(24, 40, kernel_size=5, stride=2, expand_ratio=6),\n _MBConvNew(40, 40, kernel_size=5, stride=1, expand_ratio=6),\n _MBConvNew(40, 80, kernel_size=3, stride=2, expand_ratio=6),\n _MBConvNew(80, 80, kernel_size=3, stride=1, expand_ratio=6),\n _MBConvNew(80, 112, kernel_size=5, stride=1, expand_ratio=6),\n _MBConvNew(112, 112, kernel_size=5, stride=1, expand_ratio=6),\n _MBConvNew(112, 192, kernel_size=5, stride=2, expand_ratio=6),\n _MBConvNew(192, 192, kernel_size=5, stride=1, expand_ratio=6),\n _MBConvNew(192, 192, kernel_size=5, stride=1, expand_ratio=6),\n _MBConvNew(192, 320, kernel_size=3, stride=1, expand_ratio=6),\n )\n self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)\n self.bn2 = nn.BatchNorm2d(1280)\n self.fc = nn.Linear(1280, num_classes)\n\n @staticmethod\n def _bn_act_inplace(x, bn, act):\n return _effnet_fused.bn_act_(x, bn.weight, bn.bias, bn.running_mean, bn.running_var, float(bn.eps), int(act))\n\n @staticmethod\n def _bn_add_inplace(x, bn, residual):\n return _effnet_fused.bn_add_(x, bn.weight, bn.bias, bn.running_mean, bn.running_var, residual, float(bn.eps))\n\n def _forward_block(self, block, x):\n identity = x\n if hasattr(block, 'expand_conv'):\n conv = block.expand_conv[0]\n x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)\n x = self._bn_act_inplace(x, block.expand_conv[1], 2) # ReLU6\n conv = block.depthwise_conv[0]\n x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)\n x = self._bn_act_inplace(x, block.depthwise_conv[1], 2) # ReLU6\n conv = block.project_conv[0]\n x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)\n if block.use_residual:\n x = self._bn_add_inplace(x, block.project_conv[1], identity)\n else:\n x = self._bn_act_inplace(x, block.project_conv[1], 0)\n return x\n\n def forward(self, x):\n # Optimized inference path: cuDNN convolutions plus fused CUDA BN/activation kernels.\n x = F.conv2d(x, self.conv1.weight, None, self.conv1.stride, self.conv1.padding,\n self.conv1.dilation, self.conv1.groups)\n x = self._bn_act_inplace(x, self.bn1, 1) # ReLU\n for block in self.blocks:\n x = self._forward_block(block, x)\n x = F.conv2d(x, self.conv2.weight, None, self.conv2.stride, self.conv2.padding,\n self.conv2.dilation, self.conv2.groups)\n x = self._bn_act_inplace(x, self.bn2, 1) # ReLU\n x = _effnet_fused.avgpool2d(x)\n x = F.linear(x, self.fc.weight, self.fc.bias)\n return x\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: correctness check did not pass ((0 / 5) trials). correctness_issue: Output mismatch max_difference: ['0.852670', '0.778703', '0.831907', '0.806827', '0.849650'] avg_difference: ['0.182440', '0.182413', '0.182177', '0.182393', '0.181976']
final submitted kernel (219 lines, 9,349 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_act_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                      torch::Tensor mean, torch::Tensor var, double eps, int act);
torch::Tensor bn_add_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                      torch::Tensor mean, torch::Tensor var, torch::Tensor residual, double eps);
torch::Tensor avgpool2d(torch::Tensor x);
"""

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

__global__ void bn_act_ch_kernel(float* __restrict__ x,
                                 const float* __restrict__ weight,
                                 const float* __restrict__ bias,
                                 const float* __restrict__ mean,
                                 const float* __restrict__ var,
                                 int C, int HW, float eps, int act) {
    int nc = blockIdx.x;
    int c = nc % C;
    long base = (long)nc * (long)HW;
    float scale = weight[c] * rsqrtf(var[c] + eps);
    float shift = bias[c] - mean[c] * scale;
    for (int i = threadIdx.x; i < HW; i += blockDim.x) {
        float v = fmaf(x[base + i], scale, shift);
        if (act == 1) {
            v = v > 0.0f ? v : 0.0f;
        } else if (act == 2) {
            v = v > 0.0f ? v : 0.0f;
            v = v < 6.0f ? v : 6.0f;
        }
        x[base + i] = v;
    }
}

__global__ void bn_add_ch_kernel(float* __restrict__ x,
                                 const float* __restrict__ weight,
                                 const float* __restrict__ bias,
                                 const float* __restrict__ mean,
                                 const float* __restrict__ var,
                                 const float* __restrict__ residual,
                                 int C, int HW, float eps) {
    int nc = blockIdx.x;
    int c = nc % C;
    long base = (long)nc * (long)HW;
    float scale = weight[c] * rsqrtf(var[c] + eps);
    float shift = bias[c] - mean[c] * scale;
    for (int i = threadIdx.x; i < HW; i += blockDim.x) {
        float v = fmaf(x[base + i], scale, shift);
        x[base + i] = v + residual[base + i];
    }
}

__global__ void avgpool_ch_kernel(const float* __restrict__ x,
                                  float* __restrict__ out,
                                  int C, int HW) {
    int nc = blockIdx.x;
    long base = (long)nc * (long)HW;
    float sum = 0.0f;
    for (int i = threadIdx.x; i < HW; i += blockDim.x) {
        sum += x[base + i];
    }
    __shared__ float smem[256];
    smem[threadIdx.x] = sum;
    __syncthreads();
    for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {
        if (threadIdx.x < stride) smem[threadIdx.x] += smem[threadIdx.x + stride];
        __syncthreads();
    }
    if (threadIdx.x == 0) out[nc] = smem[0] / (float)HW;
}

torch::Tensor bn_act_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                      torch::Tensor mean, torch::Tensor var, double eps, int act) {
    const int N = (int)x.size(0);
    const int C = (int)x.size(1);
    const int H = (int)x.size(2);
    const int W = (int)x.size(3);
    const int HW = H * W;
    const int blocks = N * C;
    bn_act_ch_kernel<<<blocks, 256, 0, at::cuda::getCurrentCUDAStream()>>>(
        x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),
        mean.data_ptr<float>(), var.data_ptr<float>(), C, HW, (float)eps, act);
    return x;
}

torch::Tensor bn_add_(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
                      torch::Tensor mean, torch::Tensor var, torch::Tensor residual, double eps) {
    const int N = (int)x.size(0);
    const int C = (int)x.size(1);
    const int H = (int)x.size(2);
    const int W = (int)x.size(3);
    const int HW = H * W;
    const int blocks = N * C;
    bn_add_ch_kernel<<<blocks, 256, 0, at::cuda::getCurrentCUDAStream()>>>(
        x.data_ptr<float>(), weight.data_ptr<float>(), bias.data_ptr<float>(),
        mean.data_ptr<float>(), var.data_ptr<float>(), residual.data_ptr<float>(),
        C, HW, (float)eps);
    return x;
}

torch::Tensor avgpool2d(torch::Tensor x) {
    const int N = (int)x.size(0);
    const int C = (int)x.size(1);
    const int H = (int)x.size(2);
    const int W = (int)x.size(3);
    const int HW = H * W;
    auto out = torch::empty({N, C}, x.options());
    avgpool_ch_kernel<<<N * C, 256, 0, at::cuda::getCurrentCUDAStream()>>>(
        x.data_ptr<float>(), out.data_ptr<float>(), C, HW);
    return out;
}
"""

_effnet_fused = load_inline(
    name="effnet_b0_fused_bn_relu_ext",
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=["bn_act_", "bn_add_", "avgpool2d"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)


class _MBConvNew(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio):
        super(_MBConvNew, self).__init__()
        self.use_residual = (stride == 1 and in_channels == out_channels)
        hidden_dim = in_channels * expand_ratio
        if expand_ratio != 1:
            self.expand_conv = nn.Sequential(
                nn.Conv2d(in_channels, hidden_dim, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(hidden_dim),
                nn.ReLU6(inplace=True),
            )
        self.depthwise_conv = nn.Sequential(
            nn.Conv2d(hidden_dim, hidden_dim, kernel_size=kernel_size, stride=stride,
                      padding=(kernel_size - 1) // 2, groups=hidden_dim, bias=False),
            nn.BatchNorm2d(hidden_dim),
            nn.ReLU6(inplace=True),
        )
        self.project_conv = nn.Sequential(
            nn.Conv2d(hidden_dim, out_channels, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(out_channels),
        )


class ModelNew(nn.Module):
    def __init__(self, num_classes=1000):
        super(ModelNew, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(32)
        self.blocks = nn.Sequential(
            _MBConvNew(32, 16, kernel_size=3, stride=1, expand_ratio=1),
            _MBConvNew(16, 24, kernel_size=3, stride=2, expand_ratio=6),
            _MBConvNew(24, 24, kernel_size=3, stride=1, expand_ratio=6),
            _MBConvNew(24, 40, kernel_size=5, stride=2, expand_ratio=6),
            _MBConvNew(40, 40, kernel_size=5, stride=1, expand_ratio=6),
            _MBConvNew(40, 80, kernel_size=3, stride=2, expand_ratio=6),
            _MBConvNew(80, 80, kernel_size=3, stride=1, expand_ratio=6),
            _MBConvNew(80, 112, kernel_size=5, stride=1, expand_ratio=6),
            _MBConvNew(112, 112, kernel_size=5, stride=1, expand_ratio=6),
            _MBConvNew(112, 192, kernel_size=5, stride=2, expand_ratio=6),
            _MBConvNew(192, 192, kernel_size=5, stride=1, expand_ratio=6),
            _MBConvNew(192, 192, kernel_size=5, stride=1, expand_ratio=6),
            _MBConvNew(192, 320, kernel_size=3, stride=1, expand_ratio=6),
        )
        self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn2 = nn.BatchNorm2d(1280)
        self.fc = nn.Linear(1280, num_classes)

    @staticmethod
    def _bn_act_inplace(x, bn, act):
        return _effnet_fused.bn_act_(x, bn.weight, bn.bias, bn.running_mean, bn.running_var, float(bn.eps), int(act))

    @staticmethod
    def _bn_add_inplace(x, bn, residual):
        return _effnet_fused.bn_add_(x, bn.weight, bn.bias, bn.running_mean, bn.running_var, residual, float(bn.eps))

    def _forward_block(self, block, x):
        identity = x
        if hasattr(block, 'expand_conv'):
            conv = block.expand_conv[0]
            x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)
            x = self._bn_act_inplace(x, block.expand_conv[1], 2)  # ReLU6
        conv = block.depthwise_conv[0]
        x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)
        x = self._bn_act_inplace(x, block.depthwise_conv[1], 2)  # ReLU6
        conv = block.project_conv[0]
        x = F.conv2d(x, conv.weight, None, conv.stride, conv.padding, conv.dilation, conv.groups)
        if block.use_residual:
            x = self._bn_add_inplace(x, block.project_conv[1], identity)
        else:
            x = self._bn_act_inplace(x, block.project_conv[1], 0)
        return x

    def forward(self, x):
        # Optimized inference path: cuDNN convolutions plus fused CUDA BN/activation kernels.
        x = F.conv2d(x, self.conv1.weight, None, self.conv1.stride, self.conv1.padding,
                     self.conv1.dilation, self.conv1.groups)
        x = self._bn_act_inplace(x, self.bn1, 1)  # ReLU
        for block in self.blocks:
            x = self._forward_block(block, x)
        x = F.conv2d(x, self.conv2.weight, None, self.conv2.stride, self.conv2.padding,
                     self.conv2.dilation, self.conv2.groups)
        x = self._bn_act_inplace(x, self.bn2, 1)  # ReLU
        x = _effnet_fused.avgpool2d(x)
        x = F.linear(x, self.fc.weight, self.fc.bias)
        return x