grok-4.3 · popcorn · pop_l123_default_gpt
correct 28_FusedGroupNormSiLU.py
model
grok-4.3
turns / max
7 / 12
tool calls
7
tokens (total)
36194
wall clock
1251.1s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.61 μs
ref runtime
0.03 μs
speedup
0.04x
started
2026-05-11T13:04:40Z
timingkernelbench.timing
kernel runtime
0.61 μs
ref runtime
0.03 μs
speedup
0.04x
kernel mean / median / std
0.61 / — / 5.47e-04 μs
ref mean / median / std
0.03 / — / 0.01 μs
numerical precisioneval_kernel_against_ref
max abs error
7.39e-06
mean abs error
1.74e-07
max rel error
0.05
mean rel error
4.96e-07
gpu memoryextended_metrics.measure_memory
kernel peak
41.01 MB
ref peak
45.50 MB
kernel / ref
0.90x
kernel launches / fusiontorch.profiler
kernel launches
4
ref launches
12
fusion ratio (ref / kernel)
3.00x
total cuda time
72 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.349
dram util %
14.0%
compute util %
34.9%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
469.71 GB/s
dram util %
14.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
93.5%
bottleneck
compute-bound
dominant pipe %
34.9%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
102.5%
ld sectors / req
30.22
st sectors / req
—
regs / thread
49
smem / block
2048 B
block size
510
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
6913.0%
mio_throttle
200.2%
short_scoreboard
93.0%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F

# Default ModelNew is PyTorch-only. run_and_check with check_kernel=True and backend=cuda
# requires real CUDA (__global__ + load_inline/cpp_extension) in the kernel file—use
# check_kernel=False until you add a custom kernel implementation.

class Model(nn.Module):
    """
    Fused GroupNorm + SiLU (Swish), a common post-conv / residual-branch pattern in
    ResNet-family backbones (SiLU instead of ReLU) and in spatial blocks of diffusion
    transformers (DiT) where features are (N, C, H, W).

    Reference pipeline for a single fused kernel: normalize channels with
    `GroupNorm`, then apply `SiLU` elementwise (`x * sigmoid(x)`).
    """

    def __init__(
        self,
        num_channels: int,
        num_groups: int,
        eps: float = 1e-5,
        affine: bool = True,
    ):
        super().__init__()
        assert num_channels % num_groups == 0
        self.norm = nn.GroupNorm(
            num_groups=num_groups,
            num_channels=num_channels,
            eps=eps,
            affine=affine,
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        Args:
            x: (N, C, H, W) feature map
        Returns:
            Same shape as x
        """
        return F.silu(self.norm(x))


class ModelNew(nn.Module):
    """
    KernelBench candidate entry point. Replace with a fused CUDA/Triton kernel;
    default delegates to `Model` for harness smoke tests (same file as ref + kernel).
    """

    def __init__(
        self,
        num_channels: int,
        num_groups: int,
        eps: float = 1e-5,
        affine: bool = True,
    ):
        super().__init__()
        self._impl = Model(num_channels, num_groups, eps=eps, affine=affine)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self._impl(x)


batch_size = 8
num_channels = 256
num_groups = 32
height = 24
width = 24


def get_inputs():
    p = popcorn_pri
    x = torch.randn(p.jitter_int(batch_size), num_channels, p.jitter_int(height), p.jitter_int(width))
    return [x]


def get_init_inputs():
    return [num_channels, num_groups]
turn 086.2s turn · 15.4s LLM · 70.8s tools · tokens in=1,750 · out=6 · total=2,178
reasoning
The task is to replace the forward computation of a PyTorch model with a custom CUDA kernel. The model is a fused GroupNorm + SiLU. The task involves replacing the forward pass of a PyTorch model with a custom CUDA kernel for a fused GroupNorm + SiLU operation. The new model class, ModelNew, must match the original's constructor and forward signature, ensuring numerical equivalence, though truncated mid-sentence.
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 1215.5s turn · 17.5s LLM · 198.0s tools · tokens in=2,411 · out=487 · total=3,084
reasoning
GPU is H100, high bandwidth, good for memory bound ops like this.
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\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void groupnorm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ output,\n int N, int C, int H, int W, int G, int C_per_G, float eps\n) {\n // Simple implementation: each thread handles one element, but reductions need care\n // For now, placeholder - will use PyTorch for correctness first, but need real kernel\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n auto output = torch::empty_like(x);\n // TODO: launch kernel\n // For now, fall back? No, must implement\n return output;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=True,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n if not hasattr(self, '_cuda_module'):\n self._cuda_module = module\n gamma = self.norm.weight\n beta = self.norm.bias\n return self._cuda_module.groupnorm_silu_cuda(x, gamma, beta, self.num_groups, self.eps)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2168.5s turn · 17.5s LLM · 151.0s tools · tokens in=3,101 · out=653 · total=4,047
reasoning
It compiled but the kernel does nothing, just returns empty tensor. I need to implement the actual kernel or use reference inside for now? No, the instruction says do not use try/except fallbacks.
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\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void groupnorm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ output,\n int N, int C, int HW, int G, int C_per_G, float eps\n) {\n extern __shared__ float shared[];\n float* s_sum = shared;\n float* s_sq = shared + blockDim.x;\n\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total_elements = N * C * HW;\n float sum = 0.0f;\n float sq_sum = 0.0f;\n\n // Each thread processes multiple elements if needed, but for simplicity assume enough threads\n for (int i = idx; i < total_elements; i += gridDim.x * blockDim.x) {\n float val = input[i];\n sum += val;\n sq_sum += val * val;\n }\n\n // Block reduction - simple for now, use atomics to global instead for ease\n // To make it work, let's use global atomics per group\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n int HW = H * W;\n int G = num_groups;\n int C_per_G = C / G;\n auto output = torch::empty_like(x);\n\n // Use PyTorch's group_norm for now? No.\n // Actually to pass, I need full impl, but let's implement simple non-fused for test? No.\n // Fallback not allowed. Let's implement with multiple passes using atomics.\n return output;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=True,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n gamma = self.norm.weight\n beta = self.norm.bias\n return F.silu(self.norm(x)) # temp until kernel ready\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 3168.4s turn · 10.7s LLM · 157.7s tools · tokens in=4,064 · out=813 · total=4,939
reasoning
Still placeholder. I need a working kernel to pass correctness.
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\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void compute_stats(\n const float* __restrict__ input,\n float* __restrict__ mean,\n float* __restrict__ var,\n int N, int C, int HW, int G, int C_per_G, float eps\n) {\n int nc = blockIdx.x * blockDim.x + threadIdx.x;\n int total_nc = N * C;\n if (nc >= total_nc) return;\n int n = nc / C;\n int c = nc % C;\n int g = c / C_per_G;\n int group_idx = n * G + g;\n\n // This is per channel, not correct. Need per group reduction.\n // Redo.\n}\n\n__global__ void groupnorm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ output,\n const float* __restrict__ mean,\n const float* __restrict__ rstd,\n int N, int C, int HW, int G, int C_per_G\n) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * C * HW;\n if (idx >= total) return;\n\n int c = (idx / HW) % C;\n float m = mean[(idx / (C * HW)) * G + (c / C_per_G)];\n float r = rstd[(idx / (C * HW)) * G + (c / C_per_G)];\n float g = gamma[c];\n float b = beta[c];\n float val = input[idx];\n float normed = (val - m) * r * g + b;\n output[idx] = normed * (1.0f / (1.0f + expf(-normed)));\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n int HW = H * W;\n int G = num_groups;\n int C_per_G = C / G;\n auto output = torch::empty_like(x);\n auto mean = torch::empty({N, G}, x.options());\n auto var = torch::empty({N, G}, x.options());\n\n // Use built-in for stats to get working, but no.\n // For now return reference to pass? Can't.\n // Let's use F.group_norm inside temporarily? The point is to have CUDA kernel.\n // Actually to move forward, implement proper.\n return output;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=True,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n return F.silu(self.norm(x))\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 4204.2s turn · 13.6s LLM · 190.6s tools · tokens in=4,956 · out=1,043 · total=6,214
reasoning
I keep having incomplete kernel. To get a working one, I can use torch's implementation inside the CUDA function? But no, that wouldn't be custom kernel, and the point is CUDA.
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\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void compute_stats_kernel(\n const float* __restrict__ input,\n float* __restrict__ mean_out,\n float* __restrict__ rstd_out,\n int N, int C, int HW, int G, int CpG, float eps\n) {\n int ng = blockIdx.x * blockDim.x + threadIdx.x;\n int total_ng = N * G;\n if (ng >= total_ng) return;\n int n = ng / G;\n int g = ng % G;\n\n float sum = 0.0f;\n float sq_sum = 0.0f;\n int base = n * C * HW + g * CpG * HW;\n int count = CpG * HW;\n for (int i = 0; i < count; ++i) {\n float v = input[base + i];\n sum += v;\n sq_sum += v * v;\n }\n float mean = sum / count;\n float var = sq_sum / count - mean * mean;\n float rstd = rsqrtf(var + eps);\n mean_out[ng] = mean;\n rstd_out[ng] = rstd;\n}\n\n__global__ void apply_norm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ rstd,\n float* __restrict__ output,\n int N, int C, int HW, int G, int CpG\n) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * C * HW;\n if (idx >= total) return;\n\n int c = (idx / HW) % C;\n int g = c / CpG;\n int n = idx / (C * HW);\n int ng = n * G + g;\n float m = mean[ng];\n float r = rstd[ng];\n float g_ = gamma[c];\n float b = beta[c];\n float val = input[idx];\n float normed = (val - m) * r * g_ + b;\n output[idx] = normed * (1.0f / (1.0f + __expf(-normed)));\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n int HW = H * W;\n int G = num_groups;\n int CpG = C / G;\n auto output = torch::empty_like(x);\n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(x.device());\n auto mean = torch::empty({N, G}, options);\n auto rstd = torch::empty({N, G}, options);\n\n int total_ng = N * G;\n compute_stats_kernel<<<(total_ng + 255) / 255, 255>>>(x.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), N, C, HW, G, CpG, eps);\n\n int total = N * C * HW;\n apply_norm_silu_kernel<<<(total + 255) / 255, 255>>>(x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), output.data_ptr<float>(), N, C, HW, G, CpG);\n\n return output;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=True,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n gamma = self.norm.weight\n beta = self.norm.bias\n return module.groupnorm_silu_cuda(x.contiguous(), gamma, beta, self.num_groups, self.eps)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 5257.2s turn · 9.0s LLM · 248.3s tools · tokens in=6,231 · out=1,044 · total=7,281
reasoning
Compiled. Now test correctness.
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\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void compute_stats_kernel(\n const float* __restrict__ input,\n float* __restrict__ mean_out,\n float* __restrict__ rstd_out,\n int N, int C, int HW, int G, int CpG, float eps\n) {\n int ng = blockIdx.x * blockDim.x + threadIdx.x;\n int total_ng = N * G;\n if (ng >= total_ng) return;\n int n = ng / G;\n int g = ng % G;\n\n float sum = 0.0f;\n float sq_sum = 0.0f;\n int base = n * C * HW + g * CpG * HW;\n int count = CpG * HW;\n for (int i = 0; i < count; ++i) {\n float v = input[base + i];\n sum += v;\n sq_sum += v * v;\n }\n float mean = sum / count;\n float var = sq_sum / count - mean * mean;\n float rstd = rsqrtf(var + eps);\n mean_out[ng] = mean;\n rstd_out[ng] = rstd;\n}\n\n__global__ void apply_norm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ rstd,\n float* __restrict__ output,\n int N, int C, int HW, int G, int CpG\n) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * C * HW;\n if (idx >= total) return;\n\n int c = (idx / HW) % C;\n int g = c / CpG;\n int n = idx / (C * HW);\n int ng = n * G + g;\n float m = mean[ng];\n float r = rstd[ng];\n float g_ = gamma[c];\n float b = beta[c];\n float val = input[idx];\n float normed = (val - m) * r * g_ + b;\n output[idx] = normed * (1.0f / (1.0f + __expf(-normed)));\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n int HW = H * W;\n int G = num_groups;\n int CpG = C / G;\n auto output = torch::empty_like(x);\n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(x.device());\n auto mean = torch::empty({N, G}, options);\n auto rstd = torch::empty({N, G}, options);\n\n int total_ng = N * G;\n compute_stats_kernel<<<(total_ng + 255) / 255, 255>>>(x.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), N, C, HW, G, CpG, eps);\n\n int total = N * C * HW;\n apply_norm_silu_kernel<<<(total + 255) / 255, 255>>>(x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), output.data_ptr<float>(), N, C, HW, G, CpG);\n\n return output;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=False,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n gamma = self.norm.weight\n beta = self.norm.bias\n return module.groupnorm_silu_cuda(x.contiguous(), gamma, beta, self.num_groups, self.eps)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=7.39e-06 mean_abs_err=1.74e-07 max_rel_err=5.33e-02
turn 6151.0s turn · 8.8s LLM · 142.3s tools · tokens in=7,341 · out=1,043 · total=8,451 · FINAL
reasoning
Great, correctness passed! Now, to check if it's faster, I should submit or test timing, but since no direct timing tool, I'll use submit_kernel for 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\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void compute_stats_kernel(\n const float* __restrict__ input,\n float* __restrict__ mean_out,\n float* __restrict__ rstd_out,\n int N, int C, int HW, int G, int CpG, float eps\n) {\n int ng = blockIdx.x * blockDim.x + threadIdx.x;\n int total_ng = N * G;\n if (ng >= total_ng) return;\n int n = ng / G;\n int g = ng % G;\n\n float sum = 0.0f;\n float sq_sum = 0.0f;\n int base = n * C * HW + g * CpG * HW;\n int count = CpG * HW;\n for (int i = 0; i < count; ++i) {\n float v = input[base + i];\n sum += v;\n sq_sum += v * v;\n }\n float mean = sum / count;\n float var = sq_sum / count - mean * mean;\n float rstd = rsqrtf(var + eps);\n mean_out[ng] = mean;\n rstd_out[ng] = rstd;\n}\n\n__global__ void apply_norm_silu_kernel(\n const float* __restrict__ input,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n const float* __restrict__ mean,\n const float* __restrict__ rstd,\n float* __restrict__ output,\n int N, int C, int HW, int G, int CpG\n) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * C * HW;\n if (idx >= total) return;\n\n int c = (idx / HW) % C;\n int g = c / CpG;\n int n = idx / (C * HW);\n int ng = n * G + g;\n float m = mean[ng];\n float r = rstd[ng];\n float g_ = gamma[c];\n float b = beta[c];\n float val = input[idx];\n float normed = (val - m) * r * g_ + b;\n output[idx] = normed * (1.0f / (1.0f + __expf(-normed)));\n}\n\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {\n auto N = x.size(0);\n auto C = x.size(1);\n auto H = x.size(2);\n auto W = x.size(3);\n int HW = H * W;\n int G = num_groups;\n int CpG = C / G;\n auto output = torch::empty_like(x);\n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(x.device());\n auto mean = torch::empty({N, G}, options);\n auto rstd = torch::empty({N, G}, options);\n\n int total_ng = N * G;\n compute_stats_kernel<<<(total_ng + 255) / 255, 255>>>(x.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), N, C, HW, G, CpG, eps);\n\n int total = N * C * HW;\n apply_norm_silu_kernel<<<(total + 255) / 255, 255>>>(x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), output.data_ptr<float>(), N, C, HW, G, CpG);\n\n return output;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);\n\"\"\"\n\nmodule = load_inline(\n name=\"groupnorm_silu\",\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=[\"groupnorm_silu_cuda\"],\n verbose=False,\n extra_cuda_cflags=[\"-O3\"]\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):\n super().__init__()\n self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)\n self.num_groups = num_groups\n self.eps = eps\n\n def forward(self, x):\n gamma = self.norm.weight\n beta = self.norm.bias\n return module.groupnorm_silu_cuda(x.contiguous(), gamma, beta, self.num_groups, self.eps)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.61 μs Runtime stats: mean=0.61μs median=?μs std=0.00μs Numerical precision: max_abs_err=7.39e-06 mean_abs_err=1.74e-07 max_rel_err=5.33e-02 Memory: 41.01 MB peak (ref: 45.5 MB, ratio: 0.9012x) Kernel launches: 4 (ref: 12, fusion ratio: 3.0) SOL score: 0.3489
final submitted kernel (112 lines, 3,461 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

cuda_source = r"""
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>

__global__ void compute_stats_kernel(
    const float* __restrict__ input,
    float* __restrict__ mean_out,
    float* __restrict__ rstd_out,
    int N, int C, int HW, int G, int CpG, float eps
) {
    int ng = blockIdx.x * blockDim.x + threadIdx.x;
    int total_ng = N * G;
    if (ng >= total_ng) return;
    int n = ng / G;
    int g = ng % G;

    float sum = 0.0f;
    float sq_sum = 0.0f;
    int base = n * C * HW + g * CpG * HW;
    int count = CpG * HW;
    for (int i = 0; i < count; ++i) {
        float v = input[base + i];
        sum += v;
        sq_sum += v * v;
    }
    float mean = sum / count;
    float var = sq_sum / count - mean * mean;
    float rstd = rsqrtf(var + eps);
    mean_out[ng] = mean;
    rstd_out[ng] = rstd;
}

__global__ void apply_norm_silu_kernel(
    const float* __restrict__ input,
    const float* __restrict__ gamma,
    const float* __restrict__ beta,
    const float* __restrict__ mean,
    const float* __restrict__ rstd,
    float* __restrict__ output,
    int N, int C, int HW, int G, int CpG
) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = N * C * HW;
    if (idx >= total) return;

    int c = (idx / HW) % C;
    int g = c / CpG;
    int n = idx / (C * HW);
    int ng = n * G + g;
    float m = mean[ng];
    float r = rstd[ng];
    float g_ = gamma[c];
    float b = beta[c];
    float val = input[idx];
    float normed = (val - m) * r * g_ + b;
    output[idx] = normed * (1.0f / (1.0f + __expf(-normed)));
}

torch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps) {
    auto N = x.size(0);
    auto C = x.size(1);
    auto H = x.size(2);
    auto W = x.size(3);
    int HW = H * W;
    int G = num_groups;
    int CpG = C / G;
    auto output = torch::empty_like(x);
    auto options = torch::TensorOptions().dtype(torch::kFloat32).device(x.device());
    auto mean = torch::empty({N, G}, options);
    auto rstd = torch::empty({N, G}, options);

    int total_ng = N * G;
    compute_stats_kernel<<<(total_ng + 255) / 255, 255>>>(x.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), N, C, HW, G, CpG, eps);

    int total = N * C * HW;
    apply_norm_silu_kernel<<<(total + 255) / 255, 255>>>(x.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), mean.data_ptr<float>(), rstd.data_ptr<float>(), output.data_ptr<float>(), N, C, HW, G, CpG);

    return output;
}
"""

cpp_source = r"""
torch::Tensor groupnorm_silu_cuda(torch::Tensor x, torch::Tensor gamma, torch::Tensor beta, int num_groups, float eps);
"""

module = load_inline(
    name="groupnorm_silu",
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=["groupnorm_silu_cuda"],
    verbose=False,
    extra_cuda_cflags=["-O3"]
)

class ModelNew(nn.Module):
    def __init__(self, num_channels, num_groups, eps=1e-5, affine=True):
        super().__init__()
        self.norm = nn.GroupNorm(num_groups, num_channels, eps=eps, affine=affine)
        self.num_groups = num_groups
        self.eps = eps

    def forward(self, x):
        gamma = self.norm.weight
        beta = self.norm.bias
        return module.groupnorm_silu_cuda(x.contiguous(), gamma, beta, self.num_groups, self.eps)