gpt-5.5-priority · original · l123_single_gpt
compile_fail 24_EfficientNetB2.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
-1.00 μs
speedup
—
started
2026-05-05T02:53:42Z
compile error: /lib/x86_64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.15' not found (required by /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_24_cache/k_c6ff613a803a/efficientnet_b2_weird_fused_ext/efficientnet_b2_weird_fused_ext.so)
timingkernelbench.timing
kernel runtime
—
ref runtime
—
speedup
—
kernel mean / median / std
—
ref mean / median / std
—
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):
        """
        EfficientNetB2 architecture implementation.

        :param num_classes: The number of output classes (default is 1000 for ImageNet).
        """
        super(Model, self).__init__()
        
        # Define the EfficientNetB2 architecture components
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(32)
        self.relu = nn.ReLU(inplace=True)
        
        # Define the MBConv blocks
        self.mbconv1 = self._make_mbconv_block(32, 96, 1, 3)
        self.mbconv2 = self._make_mbconv_block(96, 144, 2, 6)
        self.mbconv3 = self._make_mbconv_block(144, 192, 2, 6)
        self.mbconv4 = self._make_mbconv_block(192, 288, 2, 6)
        self.mbconv5 = self._make_mbconv_block(288, 384, 1, 6)
        
        # Final layers
        self.conv_final = nn.Conv2d(384, 1408, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn_final = nn.BatchNorm2d(1408)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(1408, num_classes)
    
    def _make_mbconv_block(self, in_channels, out_channels, stride, expand_ratio):
        """
        Helper function to create a MBConv block.

        :param in_channels: Number of input channels.
        :param out_channels: Number of output channels.
        :param stride: Stride for the depthwise convolution.
        :param expand_ratio: Expansion ratio for the MBConv block.
        :return: A sequential container of layers forming the MBConv block.
        """
        layers = []
        expanded_channels = in_channels * expand_ratio
        
        # Expansion phase
        if expand_ratio != 1:
            layers.append(nn.Conv2d(in_channels, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))
            layers.append(nn.BatchNorm2d(expanded_channels))
            layers.append(nn.ReLU(inplace=True))
        
        # Depthwise convolution
        layers.append(nn.Conv2d(expanded_channels, expanded_channels, kernel_size=3, stride=stride, padding=1, groups=expanded_channels, bias=False))
        layers.append(nn.BatchNorm2d(expanded_channels))
        layers.append(nn.ReLU(inplace=True))
        
        # Squeeze and Excitation
        layers.append(nn.AdaptiveAvgPool2d((1, 1)))
        layers.append(nn.Conv2d(expanded_channels, expanded_channels // 4, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.ReLU(inplace=True))
        layers.append(nn.Conv2d(expanded_channels // 4, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.Sigmoid())
        
        # Output phase
        layers.append(nn.Conv2d(expanded_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.BatchNorm2d(out_channels))
        
        return nn.Sequential(*layers)
    
    def forward(self, x):
        """
        Forward pass of the EfficientNetB2 model.

        :param x: The input tensor, shape (batch_size, 3, 224, 224)
        :return: The output tensor, shape (batch_size, num_classes)
        """
        x = self.relu(self.bn1(self.conv1(x)))
        x = self.mbconv1(x)
        x = self.mbconv2(x)
        x = self.mbconv3(x)
        x = self.mbconv4(x)
        x = self.mbconv5(x)
        x = self.relu(self.bn_final(self.conv_final(x)))
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)
        return x

# Test code
batch_size = 2
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) · 80.7s turn · 80.7s LLM · 16,291 chars (click to expand)
turn 080.7s turn · 80.7s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n#include <vector>\n\ntorch::Tensor eff_forward(torch::Tensor x, std::vector<torch::Tensor> p);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <vector>\n#include <cmath>\n\n#define BN_EPS 1.0e-5f\n\n__device__ __forceinline__ float relu_f(float x){ return x > 0.0f ? x : 0.0f; }\n__device__ __forceinline__ float sigmoid_f(float x){ return 1.0f / (1.0f + __expf(-x)); }\n\n__global__ void conv1_bn_relu_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ y,\n int N) {\n const int Hout = 112, Wout = 112, Coo = 32, Cin = 3, Hin = 224, Win = 224;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * Coo * Hout * Wout;\n if (idx >= total) return;\n int ow = idx % Wout;\n int t = idx / Wout;\n int oh = t % Hout;\n t /= Hout;\n int co = t % Coo;\n int n = t / Coo;\n\n float sum = 0.0f;\n int ih0 = oh * 2 - 1;\n int iw0 = ow * 2 - 1;\n #pragma unroll\n for (int ci=0; ci<3; ++ci) {\n #pragma unroll\n for (int kh=0; kh<3; ++kh) {\n int ih = ih0 + kh;\n if ((unsigned)ih >= (unsigned)Hin) continue;\n #pragma unroll\n for (int kw=0; kw<3; ++kw) {\n int iw = iw0 + kw;\n if ((unsigned)iw >= (unsigned)Win) continue;\n float xv = x[((n*Cin + ci)*Hin + ih)*Win + iw];\n float wv = w[((co*Cin + ci)*3 + kh)*3 + kw];\n sum += xv * wv;\n }\n }\n }\n float v = (sum - mean[co]) * rsqrtf(var[co] + BN_EPS) * gamma[co] + beta[co];\n y[idx] = relu_f(v);\n}\n\n__global__ void conv1x1_bn_relu_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ y,\n int N, int Cin, int Cout, int HW) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * Cout * HW;\n if (idx >= total) return;\n int s = idx % HW;\n int t = idx / HW;\n int co = t % Cout;\n int n = t / Cout;\n float sum = 0.0f;\n const float* xp = x + n * Cin * HW + s;\n const float* wp = w + co * Cin;\n for (int ci=0; ci<Cin; ++ci) sum += xp[ci * HW] * wp[ci];\n float v = (sum - mean[co]) * rsqrtf(var[co] + BN_EPS) * gamma[co] + beta[co];\n y[idx] = relu_f(v);\n}\n\n__global__ void depthwise3x3_avg_bn_relu_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ out,\n int N, int C) {\n const int H = 112, Wd = 112, HW = 12544;\n int bc = blockIdx.x;\n int c = bc % C;\n int n = bc / C;\n int tid = threadIdx.x;\n __shared__ float sh[256];\n float acc = 0.0f;\n const float* xp = x + (n*C + c)*HW;\n const float* wp = w + c*9;\n for (int s = tid; s < HW; s += blockDim.x) {\n int oh = s / Wd;\n int ow = s - oh * Wd;\n float sum = 0.0f;\n #pragma unroll\n for (int kh=0; kh<3; ++kh) {\n int ih = oh + kh - 1;\n if ((unsigned)ih >= (unsigned)H) continue;\n #pragma unroll\n for (int kw=0; kw<3; ++kw) {\n int iw = ow + kw - 1;\n if ((unsigned)iw >= (unsigned)Wd) continue;\n sum += xp[ih*Wd + iw] * wp[kh*3 + kw];\n }\n }\n float v = (sum - mean[c]) * rsqrtf(var[c] + BN_EPS) * gamma[c] + beta[c];\n acc += relu_f(v);\n }\n sh[tid] = acc;\n __syncthreads();\n for (int off = 128; off > 0; off >>= 1) {\n if (tid < off) sh[tid] += sh[tid + off];\n __syncthreads();\n }\n if (tid == 0) out[n*C + c] = sh[0] * (1.0f / 12544.0f);\n}\n\n__global__ void matvec_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ bias,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ y,\n int N, int K, int M,\n int has_bias, int has_bn, int do_relu, int do_sigmoid) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * M;\n if (idx >= total) return;\n int m = idx % M;\n int n = idx / M;\n const float* xp = x + n*K;\n const float* wp = w + m*K;\n float sum = 0.0f;\n for (int k=0; k<K; ++k) sum += xp[k] * wp[k];\n if (has_bias) sum += bias[m];\n if (has_bn) sum = (sum - mean[m]) * rsqrtf(var[m] + BN_EPS) * gamma[m] + beta[m];\n if (do_relu) sum = relu_f(sum);\n if (do_sigmoid) sum = sigmoid_f(sum);\n y[idx] = sum;\n}\n\n__global__ void vector_dw_bn_relu_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ var,\n float* __restrict__ y,\n int N, int C) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N*C;\n if (idx >= total) return;\n int c = idx % C;\n float sum = x[idx] * w[c*9 + 4];\n float v = (sum - mean[c]) * rsqrtf(var[c] + BN_EPS) * gamma[c] + beta[c];\n y[idx] = relu_f(v);\n}\n\nstatic inline void launch_mat(torch::Tensor in, torch::Tensor w, torch::Tensor bias,\n torch::Tensor gamma, torch::Tensor beta, torch::Tensor mean, torch::Tensor var,\n torch::Tensor out, int N, int K, int M,\n int has_bias, int has_bn, int do_relu, int do_sigmoid) {\n int total = N*M;\n dim3 block(256);\n dim3 grid((total + 255) / 256);\n const float* bptr = has_bias ? bias.data_ptr<float>() : nullptr;\n const float* gptr = has_bn ? gamma.data_ptr<float>() : nullptr;\n const float* betaptr = has_bn ? beta.data_ptr<float>() : nullptr;\n const float* mptr = has_bn ? mean.data_ptr<float>() : nullptr;\n const float* vptr = has_bn ? var.data_ptr<float>() : nullptr;\n matvec_kernel<<<grid, block>>>(in.data_ptr<float>(), w.data_ptr<float>(), bptr, gptr, betaptr, mptr, vptr,\n out.data_ptr<float>(), N, K, M, has_bias, has_bn, do_relu, do_sigmoid);\n}\n\ntorch::Tensor eff_forward(torch::Tensor x, std::vector<torch::Tensor> p) {\n int N = (int)x.size(0);\n auto opts = x.options();\n const int HW = 112*112;\n torch::Tensor a = torch::empty({N, 32, 112, 112}, opts);\n torch::Tensor b = torch::empty({N, 96, 112, 112}, opts);\n torch::Tensor v = torch::empty({N, 96}, opts);\n\n int idx = 0;\n dim3 block(256);\n conv1_bn_relu_kernel<<<(N*32*HW + 255)/256, block>>>(x.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), a.data_ptr<float>(), N);\n idx += 5;\n\n // MBConv1 spatial part: expansion 32->96, depthwise+avg\n conv1x1_bn_relu_kernel<<<(N*96*HW + 255)/256, block>>>(a.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), b.data_ptr<float>(), N, 32, 96, HW);\n idx += 5;\n depthwise3x3_avg_bn_relu_kernel<<<N*96, block>>>(b.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), v.data_ptr<float>(), N, 96);\n idx += 5;\n\n // remaining per-vector layers. Consume rest of MBConv1 first.\n auto empty = torch::Tensor();\n torch::Tensor t1, t2;\n t1 = torch::empty({N, 24}, opts);\n launch_mat(v, p[idx], empty, empty, empty, empty, empty, t1, N, 96, 24, 0, 0, 1, 0); idx++;\n t2 = torch::empty({N, 96}, opts);\n launch_mat(t1, p[idx], empty, empty, empty, empty, empty, t2, N, 24, 96, 0, 0, 0, 1); idx++;\n v = torch::empty({N, 96}, opts);\n launch_mat(t2, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], v, N, 96, 96, 0, 1, 0, 0); idx += 5;\n\n // MBConv2..5\n int Cin_arr[4] = {96,144,192,288};\n int E_arr[4] = {576,864,1152,1728};\n int O_arr[4] = {144,192,288,384};\n for (int bi=0; bi<4; ++bi) {\n int Cin = Cin_arr[bi], E = E_arr[bi], O = O_arr[bi];\n t1 = torch::empty({N, E}, opts);\n launch_mat(v, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], t1, N, Cin, E, 0, 1, 1, 0); idx += 5;\n t2 = torch::empty({N, E}, opts);\n vector_dw_bn_relu_kernel<<<(N*E + 255)/256, block>>>(t1.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), t2.data_ptr<float>(), N, E);\n idx += 5;\n t1 = torch::empty({N, E/4}, opts);\n launch_mat(t2, p[idx], empty, empty, empty, empty, empty, t1, N, E, E/4, 0, 0, 1, 0); idx++;\n torch::Tensor sig = torch::empty({N, E}, opts);\n launch_mat(t1, p[idx], empty, empty, empty, empty, empty, sig, N, E/4, E, 0, 0, 0, 1); idx++;\n v = torch::empty({N, O}, opts);\n launch_mat(sig, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], v, N, E, O, 0, 1, 0, 0); idx += 5;\n }\n\n // final conv/bn/relu and FC\n t1 = torch::empty({N, 1408}, opts);\n launch_mat(v, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], t1, N, 384, 1408, 0, 1, 1, 0); idx += 5;\n int M = (int)p[idx].size(0);\n torch::Tensor out = torch::empty({N, M}, opts);\n launch_mat(t1, p[idx], p[idx+1], empty, empty, empty, empty, out, N, 1408, M, 1, 0, 0, 0);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"efficientnet_b2_weird_fused_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"eff_forward\"],\n with_cuda=True,\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_classes=1000):\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.relu = nn.ReLU(inplace=True)\n self.mbconv1 = self._make_mbconv_block(32, 96, 1, 3)\n self.mbconv2 = self._make_mbconv_block(96, 144, 2, 6)\n self.mbconv3 = self._make_mbconv_block(144, 192, 2, 6)\n self.mbconv4 = self._make_mbconv_block(192, 288, 2, 6)\n self.mbconv5 = self._make_mbconv_block(288, 384, 1, 6)\n self.conv_final = nn.Conv2d(384, 1408, kernel_size=1, stride=1, padding=0, bias=False)\n self.bn_final = nn.BatchNorm2d(1408)\n self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n self.fc = nn.Linear(1408, num_classes)\n\n def _make_mbconv_block(self, in_channels, out_channels, stride, expand_ratio):\n layers = []\n expanded_channels = in_channels * expand_ratio\n if expand_ratio != 1:\n layers.append(nn.Conv2d(in_channels, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))\n layers.append(nn.BatchNorm2d(expanded_channels))\n layers.append(nn.ReLU(inplace=True))\n layers.append(nn.Conv2d(expanded_channels, expanded_channels, kernel_size=3, stride=stride, padding=1, groups=expanded_channels, bias=False))\n layers.append(nn.BatchNorm2d(expanded_channels))\n layers.append(nn.ReLU(inplace=True))\n layers.append(nn.AdaptiveAvgPool2d((1, 1)))\n layers.append(nn.Conv2d(expanded_channels, expanded_channels // 4, kernel_size=1, stride=1, padding=0, bias=False))\n layers.append(nn.ReLU(inplace=True))\n layers.append(nn.Conv2d(expanded_channels // 4, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))\n layers.append(nn.Sigmoid())\n layers.append(nn.Conv2d(expanded_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False))\n layers.append(nn.BatchNorm2d(out_channels))\n return nn.Sequential(*layers)\n\n def _append_bn(self, params, bn):\n params.extend([bn.weight, bn.bias, bn.running_mean, bn.running_var])\n\n def _append_block(self, params, block):\n # all blocks in this model have expansion conv at indices 0/1\n params.append(block[0].weight); self._append_bn(params, block[1])\n params.append(block[3].weight); self._append_bn(params, block[4])\n params.append(block[7].weight)\n params.append(block[9].weight)\n params.append(block[11].weight); self._append_bn(params, block[12])\n\n def forward(self, x):\n params = []\n params.append(self.conv1.weight); self._append_bn(params, self.bn1)\n self._append_block(params, self.mbconv1)\n self._append_block(params, self.mbconv2)\n self._append_block(params, self.mbconv3)\n self._append_block(params, self.mbconv4)\n self._append_block(params, self.mbconv5)\n params.append(self.conv_final.weight); self._append_bn(params, self.bn_final)\n params.extend([self.fc.weight, self.fc.bias])\n return _ext.eff_forward(x.contiguous(), params)\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: kernel did not compile. /lib/x86_64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.15' not found (required by /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_24_cache/k_c6ff613a803a/efficientnet_b2_weird_fused_ext/efficientnet_b2_weird_fused_ext.so)
final submitted kernel (318 lines, 14,587 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

_cpp_src = r"""
#include <torch/extension.h>
#include <vector>

torch::Tensor eff_forward(torch::Tensor x, std::vector<torch::Tensor> p);
"""

_cuda_src = r"""
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <vector>
#include <cmath>

#define BN_EPS 1.0e-5f

__device__ __forceinline__ float relu_f(float x){ return x > 0.0f ? x : 0.0f; }
__device__ __forceinline__ float sigmoid_f(float x){ return 1.0f / (1.0f + __expf(-x)); }

__global__ void conv1_bn_relu_kernel(const float* __restrict__ x,
                                     const float* __restrict__ w,
                                     const float* __restrict__ gamma,
                                     const float* __restrict__ beta,
                                     const float* __restrict__ mean,
                                     const float* __restrict__ var,
                                     float* __restrict__ y,
                                     int N) {
    const int Hout = 112, Wout = 112, Coo = 32, Cin = 3, Hin = 224, Win = 224;
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = N * Coo * Hout * Wout;
    if (idx >= total) return;
    int ow = idx % Wout;
    int t = idx / Wout;
    int oh = t % Hout;
    t /= Hout;
    int co = t % Coo;
    int n = t / Coo;

    float sum = 0.0f;
    int ih0 = oh * 2 - 1;
    int iw0 = ow * 2 - 1;
    #pragma unroll
    for (int ci=0; ci<3; ++ci) {
        #pragma unroll
        for (int kh=0; kh<3; ++kh) {
            int ih = ih0 + kh;
            if ((unsigned)ih >= (unsigned)Hin) continue;
            #pragma unroll
            for (int kw=0; kw<3; ++kw) {
                int iw = iw0 + kw;
                if ((unsigned)iw >= (unsigned)Win) continue;
                float xv = x[((n*Cin + ci)*Hin + ih)*Win + iw];
                float wv = w[((co*Cin + ci)*3 + kh)*3 + kw];
                sum += xv * wv;
            }
        }
    }
    float v = (sum - mean[co]) * rsqrtf(var[co] + BN_EPS) * gamma[co] + beta[co];
    y[idx] = relu_f(v);
}

__global__ void conv1x1_bn_relu_kernel(const float* __restrict__ x,
                                       const float* __restrict__ w,
                                       const float* __restrict__ gamma,
                                       const float* __restrict__ beta,
                                       const float* __restrict__ mean,
                                       const float* __restrict__ var,
                                       float* __restrict__ y,
                                       int N, int Cin, int Cout, int HW) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = N * Cout * HW;
    if (idx >= total) return;
    int s = idx % HW;
    int t = idx / HW;
    int co = t % Cout;
    int n = t / Cout;
    float sum = 0.0f;
    const float* xp = x + n * Cin * HW + s;
    const float* wp = w + co * Cin;
    for (int ci=0; ci<Cin; ++ci) sum += xp[ci * HW] * wp[ci];
    float v = (sum - mean[co]) * rsqrtf(var[co] + BN_EPS) * gamma[co] + beta[co];
    y[idx] = relu_f(v);
}

__global__ void depthwise3x3_avg_bn_relu_kernel(const float* __restrict__ x,
                                                const float* __restrict__ w,
                                                const float* __restrict__ gamma,
                                                const float* __restrict__ beta,
                                                const float* __restrict__ mean,
                                                const float* __restrict__ var,
                                                float* __restrict__ out,
                                                int N, int C) {
    const int H = 112, Wd = 112, HW = 12544;
    int bc = blockIdx.x;
    int c = bc % C;
    int n = bc / C;
    int tid = threadIdx.x;
    __shared__ float sh[256];
    float acc = 0.0f;
    const float* xp = x + (n*C + c)*HW;
    const float* wp = w + c*9;
    for (int s = tid; s < HW; s += blockDim.x) {
        int oh = s / Wd;
        int ow = s - oh * Wd;
        float sum = 0.0f;
        #pragma unroll
        for (int kh=0; kh<3; ++kh) {
            int ih = oh + kh - 1;
            if ((unsigned)ih >= (unsigned)H) continue;
            #pragma unroll
            for (int kw=0; kw<3; ++kw) {
                int iw = ow + kw - 1;
                if ((unsigned)iw >= (unsigned)Wd) continue;
                sum += xp[ih*Wd + iw] * wp[kh*3 + kw];
            }
        }
        float v = (sum - mean[c]) * rsqrtf(var[c] + BN_EPS) * gamma[c] + beta[c];
        acc += relu_f(v);
    }
    sh[tid] = acc;
    __syncthreads();
    for (int off = 128; off > 0; off >>= 1) {
        if (tid < off) sh[tid] += sh[tid + off];
        __syncthreads();
    }
    if (tid == 0) out[n*C + c] = sh[0] * (1.0f / 12544.0f);
}

__global__ void matvec_kernel(const float* __restrict__ x,
                              const float* __restrict__ w,
                              const float* __restrict__ bias,
                              const float* __restrict__ gamma,
                              const float* __restrict__ beta,
                              const float* __restrict__ mean,
                              const float* __restrict__ var,
                              float* __restrict__ y,
                              int N, int K, int M,
                              int has_bias, int has_bn, int do_relu, int do_sigmoid) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = N * M;
    if (idx >= total) return;
    int m = idx % M;
    int n = idx / M;
    const float* xp = x + n*K;
    const float* wp = w + m*K;
    float sum = 0.0f;
    for (int k=0; k<K; ++k) sum += xp[k] * wp[k];
    if (has_bias) sum += bias[m];
    if (has_bn) sum = (sum - mean[m]) * rsqrtf(var[m] + BN_EPS) * gamma[m] + beta[m];
    if (do_relu) sum = relu_f(sum);
    if (do_sigmoid) sum = sigmoid_f(sum);
    y[idx] = sum;
}

__global__ void vector_dw_bn_relu_kernel(const float* __restrict__ x,
                                         const float* __restrict__ w,
                                         const float* __restrict__ gamma,
                                         const float* __restrict__ beta,
                                         const float* __restrict__ mean,
                                         const float* __restrict__ var,
                                         float* __restrict__ y,
                                         int N, int C) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = N*C;
    if (idx >= total) return;
    int c = idx % C;
    float sum = x[idx] * w[c*9 + 4];
    float v = (sum - mean[c]) * rsqrtf(var[c] + BN_EPS) * gamma[c] + beta[c];
    y[idx] = relu_f(v);
}

static inline void launch_mat(torch::Tensor in, torch::Tensor w, torch::Tensor bias,
                              torch::Tensor gamma, torch::Tensor beta, torch::Tensor mean, torch::Tensor var,
                              torch::Tensor out, int N, int K, int M,
                              int has_bias, int has_bn, int do_relu, int do_sigmoid) {
    int total = N*M;
    dim3 block(256);
    dim3 grid((total + 255) / 256);
    const float* bptr = has_bias ? bias.data_ptr<float>() : nullptr;
    const float* gptr = has_bn ? gamma.data_ptr<float>() : nullptr;
    const float* betaptr = has_bn ? beta.data_ptr<float>() : nullptr;
    const float* mptr = has_bn ? mean.data_ptr<float>() : nullptr;
    const float* vptr = has_bn ? var.data_ptr<float>() : nullptr;
    matvec_kernel<<<grid, block>>>(in.data_ptr<float>(), w.data_ptr<float>(), bptr, gptr, betaptr, mptr, vptr,
                                   out.data_ptr<float>(), N, K, M, has_bias, has_bn, do_relu, do_sigmoid);
}

torch::Tensor eff_forward(torch::Tensor x, std::vector<torch::Tensor> p) {
    int N = (int)x.size(0);
    auto opts = x.options();
    const int HW = 112*112;
    torch::Tensor a = torch::empty({N, 32, 112, 112}, opts);
    torch::Tensor b = torch::empty({N, 96, 112, 112}, opts);
    torch::Tensor v = torch::empty({N, 96}, opts);

    int idx = 0;
    dim3 block(256);
    conv1_bn_relu_kernel<<<(N*32*HW + 255)/256, block>>>(x.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), a.data_ptr<float>(), N);
    idx += 5;

    // MBConv1 spatial part: expansion 32->96, depthwise+avg
    conv1x1_bn_relu_kernel<<<(N*96*HW + 255)/256, block>>>(a.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), b.data_ptr<float>(), N, 32, 96, HW);
    idx += 5;
    depthwise3x3_avg_bn_relu_kernel<<<N*96, block>>>(b.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), v.data_ptr<float>(), N, 96);
    idx += 5;

    // remaining per-vector layers.  Consume rest of MBConv1 first.
    auto empty = torch::Tensor();
    torch::Tensor t1, t2;
    t1 = torch::empty({N, 24}, opts);
    launch_mat(v, p[idx], empty, empty, empty, empty, empty, t1, N, 96, 24, 0, 0, 1, 0); idx++;
    t2 = torch::empty({N, 96}, opts);
    launch_mat(t1, p[idx], empty, empty, empty, empty, empty, t2, N, 24, 96, 0, 0, 0, 1); idx++;
    v = torch::empty({N, 96}, opts);
    launch_mat(t2, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], v, N, 96, 96, 0, 1, 0, 0); idx += 5;

    // MBConv2..5
    int Cin_arr[4] = {96,144,192,288};
    int E_arr[4]   = {576,864,1152,1728};
    int O_arr[4]   = {144,192,288,384};
    for (int bi=0; bi<4; ++bi) {
        int Cin = Cin_arr[bi], E = E_arr[bi], O = O_arr[bi];
        t1 = torch::empty({N, E}, opts);
        launch_mat(v, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], t1, N, Cin, E, 0, 1, 1, 0); idx += 5;
        t2 = torch::empty({N, E}, opts);
        vector_dw_bn_relu_kernel<<<(N*E + 255)/256, block>>>(t1.data_ptr<float>(), p[idx].data_ptr<float>(), p[idx+1].data_ptr<float>(), p[idx+2].data_ptr<float>(), p[idx+3].data_ptr<float>(), p[idx+4].data_ptr<float>(), t2.data_ptr<float>(), N, E);
        idx += 5;
        t1 = torch::empty({N, E/4}, opts);
        launch_mat(t2, p[idx], empty, empty, empty, empty, empty, t1, N, E, E/4, 0, 0, 1, 0); idx++;
        torch::Tensor sig = torch::empty({N, E}, opts);
        launch_mat(t1, p[idx], empty, empty, empty, empty, empty, sig, N, E/4, E, 0, 0, 0, 1); idx++;
        v = torch::empty({N, O}, opts);
        launch_mat(sig, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], v, N, E, O, 0, 1, 0, 0); idx += 5;
    }

    // final conv/bn/relu and FC
    t1 = torch::empty({N, 1408}, opts);
    launch_mat(v, p[idx], empty, p[idx+1], p[idx+2], p[idx+3], p[idx+4], t1, N, 384, 1408, 0, 1, 1, 0); idx += 5;
    int M = (int)p[idx].size(0);
    torch::Tensor out = torch::empty({N, M}, opts);
    launch_mat(t1, p[idx], p[idx+1], empty, empty, empty, empty, out, N, 1408, M, 1, 0, 0, 0);
    return out;
}
"""

_ext = load_inline(
    name="efficientnet_b2_weird_fused_ext",
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=["eff_forward"],
    with_cuda=True,
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3", "--use_fast_math"],
    verbose=False,
)

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.relu = nn.ReLU(inplace=True)
        self.mbconv1 = self._make_mbconv_block(32, 96, 1, 3)
        self.mbconv2 = self._make_mbconv_block(96, 144, 2, 6)
        self.mbconv3 = self._make_mbconv_block(144, 192, 2, 6)
        self.mbconv4 = self._make_mbconv_block(192, 288, 2, 6)
        self.mbconv5 = self._make_mbconv_block(288, 384, 1, 6)
        self.conv_final = nn.Conv2d(384, 1408, kernel_size=1, stride=1, padding=0, bias=False)
        self.bn_final = nn.BatchNorm2d(1408)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(1408, num_classes)

    def _make_mbconv_block(self, in_channels, out_channels, stride, expand_ratio):
        layers = []
        expanded_channels = in_channels * expand_ratio
        if expand_ratio != 1:
            layers.append(nn.Conv2d(in_channels, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))
            layers.append(nn.BatchNorm2d(expanded_channels))
            layers.append(nn.ReLU(inplace=True))
        layers.append(nn.Conv2d(expanded_channels, expanded_channels, kernel_size=3, stride=stride, padding=1, groups=expanded_channels, bias=False))
        layers.append(nn.BatchNorm2d(expanded_channels))
        layers.append(nn.ReLU(inplace=True))
        layers.append(nn.AdaptiveAvgPool2d((1, 1)))
        layers.append(nn.Conv2d(expanded_channels, expanded_channels // 4, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.ReLU(inplace=True))
        layers.append(nn.Conv2d(expanded_channels // 4, expanded_channels, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.Sigmoid())
        layers.append(nn.Conv2d(expanded_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False))
        layers.append(nn.BatchNorm2d(out_channels))
        return nn.Sequential(*layers)

    def _append_bn(self, params, bn):
        params.extend([bn.weight, bn.bias, bn.running_mean, bn.running_var])

    def _append_block(self, params, block):
        # all blocks in this model have expansion conv at indices 0/1
        params.append(block[0].weight); self._append_bn(params, block[1])
        params.append(block[3].weight); self._append_bn(params, block[4])
        params.append(block[7].weight)
        params.append(block[9].weight)
        params.append(block[11].weight); self._append_bn(params, block[12])

    def forward(self, x):
        params = []
        params.append(self.conv1.weight); self._append_bn(params, self.bn1)
        self._append_block(params, self.mbconv1)
        self._append_block(params, self.mbconv2)
        self._append_block(params, self.mbconv3)
        self._append_block(params, self.mbconv4)
        self._append_block(params, self.mbconv5)
        params.append(self.conv_final.weight); self._append_bn(params, self.bn_final)
        params.extend([self.fc.weight, self.fc.bias])
        return _ext.eff_forward(x.contiguous(), params)