correct
28_FusedGroupNormSiLU.py
started
2026-05-02T20:26:30Z
timingkernelbench.timing
kernel mean / median / std
0.01 / — / 2.45e-04 μs
ref mean / median / std
0.03 / — / 5.95e-04 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
6.00x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
706.83 GB/s
warp stalls (top 5)nsight
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 09.5s turn · 9.5s LLM · 0.0s tools
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) · 15.2s turn · 15.2s LLM · 8,466 chars (click to expand)
turn 115.2s turn · 15.2s LLM · 0.0s tools
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v += __shfl_down_sync(0xffffffff, v, offset);\n }\n return v;\n}\n\n__inline__ __device__ float block_sum(float v) {\n __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n v = warp_sum(v);\n if (lane == 0) shared[wid] = v;\n __syncthreads();\n v = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) v = warp_sum(v);\n return v;\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n\n float s = 0.0f;\n float ss = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n float v = x[base + i];\n s += v;\n ss += v * v;\n }\n float sum = block_sum(s);\n float sumsq = block_sum(ss);\n\n __shared__ float sh_mean;\n __shared__ float sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = sum * inv_m;\n float var = sumsq * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int c_local = i / HW;\n int c = g * cpg + c_local;\n float v = (x[base + i] - mean) * rstd;\n if (affine) {\n v = v * weight[c] + bias[c];\n }\n float sig = 1.0f / (1.0f + expf(-v));\n y[base + i] = v * sig;\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int G = (int)num_groups;\n int blocks = N * G;\n int threads = 256;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n groupnorm_silu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_v1',\n cpp_sources='',\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n else:\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← compile_kernel (fail)
failcompile_kernel
compile_kernel FAILED: RuntimeError.
RuntimeError: Error building extension 'gn_silu_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=gn_silu_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/tejas/PopcornBench/runs/l12_default/popcorn/gpt-5.5-priority/level_2_problem_28_cache/k_9ae03b066aab/gn_silu_ext_v1/main.cpp -o main.o
FAILED: [code=1] main.o
/opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=gn_silu_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/tejas/PopcornBench/runs/l12_default/popcorn/gpt-5.5-priority/level_2_problem_28_cache/k_9ae03b066aab/gn_silu_ext_v1/main.cpp -o main.o
/scratch/tejas/PopcornBench/runs/l12_default/popcorn/gpt-5.5-priority/level_2_problem_28_cache/k_9ae03b066aab/gn_silu_ext_v1/main.cpp: In function 'void pybind11_init_gn_silu_ext_v1(pybind11::module_&)':
/scratch/tejas/PopcornBench/runs/l12_default/popcorn/gpt-5.5-priority/level_2_problem_28_cache/k_9ae03b066aab/gn_silu_ext_v1/main.cpp:4:61: error: 'groupnorm_silu_forward' was not declared in this scope
4 | m.def("groupnorm_silu_forward", torch::wrap_pybind_function(groupnorm_silu_forward), "groupnorm_silu_forward");
| ^~~~~~~~~~~~~~~~~~~~~~
[2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=gn_silu_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 --use_fast_math -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/popcorn/gpt-5.5-priority/level_2_problem_28_cache/k_9ae03b066aab/gn_silu_ext_v1/cuda.cu -o cuda.cuda.o
nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used
ninja: build stopped: subcommand failed.
turn 2 · 1 tool call(s) · 9.1s turn · 9.1s LLM · 6,213 chars (click to expand)
turn 29.1s turn · 9.1s LLM · 0.0s tools
reasoning
**Clarifying cpp and cuda integration**
I need to declare something in cpp_sources. I’m thinking about using a host wrapper in cpp, while the kernel is in cuda. If the host wrapper in cuda isn't visible, I should use cpp_sources with a prototype for the function: `torch::Tensor groupnorm_silu_forward(...)`. I'll make sure to include `torch/extension.h` in cpp_sources for it to compile correctly. Finally, I should include the cpp_sources content in main.cpp before calling `m.def`. It’s time to compile again!
call → compile_kernel
callcompile_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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v += __shfl_down_sync(0xffffffff, v, offset);\n }\n return v;\n}\n\n__inline__ __device__ float block_sum(float v) {\n __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n v = warp_sum(v);\n if (lane == 0) shared[wid] = v;\n __syncthreads();\n v = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) v = warp_sum(v);\n return v;\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n\n float s = 0.0f;\n float ss = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n float v = x[base + i];\n s += v;\n ss += v * v;\n }\n float sum = block_sum(s);\n float sumsq = block_sum(ss);\n\n __shared__ float sh_mean;\n __shared__ float sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = sum * inv_m;\n float var = sumsq * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int c_local = i / HW;\n int c = g * cpg + c_local;\n float v = (x[base + i] - mean) * rstd;\n if (affine) {\n v = v * weight[c] + bias[c];\n }\n float sig = 1.0f / (1.0f + expf(-v));\n y[base + i] = v * sig;\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int G = (int)num_groups;\n int blocks = N * G;\n int threads = 256;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n groupnorm_silu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_v2',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 39.4s turn · 9.4s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v += __shfl_down_sync(0xffffffff, v, offset);\n }\n return v;\n}\n\n__inline__ __device__ float block_sum(float v) {\n __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n v = warp_sum(v);\n if (lane == 0) shared[wid] = v;\n __syncthreads();\n v = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) v = warp_sum(v);\n return v;\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n\n float s = 0.0f;\n float ss = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n float v = x[base + i];\n s += v;\n ss += v * v;\n }\n float sum = block_sum(s);\n float sumsq = block_sum(ss);\n\n __shared__ float sh_mean;\n __shared__ float sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = sum * inv_m;\n float var = sumsq * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int c_local = i / HW;\n int c = g * cpg + c_local;\n float v = (x[base + i] - mean) * rstd;\n if (affine) {\n v = v * weight[c] + bias[c];\n }\n float sig = 1.0f / (1.0f + expf(-v));\n y[base + i] = v * sig;\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0);\n int C = (int)x.size(1);\n int H = (int)x.size(2);\n int W = (int)x.size(3);\n int G = (int)num_groups;\n int blocks = N * G;\n int threads = 256;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n groupnorm_silu_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_v2',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.43e-06 mean_abs_err=2.68e-08 max_rel_err=8.97e-03
turn 4 · 1 tool call(s) · 36.5s turn · 36.5s LLM · 8,500 chars (click to expand)
turn 436.5s turn · 36.5s LLM · 0.0s tools
reasoning
**Evaluating race conditions**
I'm pondering the race condition between the previous read and the next write by non-warp0. It seems non-warp0 can’t proceed with the next call until it finishes the current one, while warp0 might still be reading during this time. This is an interesting scenario. I think correctness is okay, but I wonder if it’s robust enough. I need to explore possible solutions to ensure this process is reliable!
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__inline__ __device__ void block_reduce_pair(float &s, float &q) {\n __shared__ float shs[32];\n __shared__ float shq[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n s = warp_sum(s);\n q = warp_sum(q);\n if (lane == 0) { shs[wid] = s; shq[wid] = q; }\n __syncthreads();\n s = (threadIdx.x < (blockDim.x >> 5)) ? shs[lane] : 0.0f;\n q = (threadIdx.x < (blockDim.x >> 5)) ? shq[lane] : 0.0f;\n if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }\n}\n\n__device__ __forceinline__ float silu_f(float v) {\n return v / (1.0f + expf(-v));\n}\n\n__global__ void gn_silu_256_32_24_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n float eps, int affine) {\n int bg = blockIdx.x; // N*32\n int g = bg & 31;\n int base = bg * 4608; // ((n*256 + g*8)*576)\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);\n float s = 0.0f, q = 0.0f;\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n s += a.x + a.y + a.z + a.w;\n q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float mean = s * (1.0f / 4608.0f);\n float var = q * (1.0f / 4608.0f) - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);\n #pragma unroll 1\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n int c = g * 8 + (vi / 144);\n float w = affine ? weight[c] : 1.0f;\n float b = affine ? bias[c] : 0.0f;\n float4 o;\n float v;\n v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);\n v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);\n v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);\n v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);\n y4[vi] = o;\n }\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n float s = 0.0f, q = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n float v = x[base + i]; s += v; q += v * v;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = s * inv_m;\n float var = q * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean; sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean, rstd = sh_rstd;\n for (int cl = 0; cl < cpg; ++cl) {\n int c = g * cpg + cl;\n float w = affine ? weight[c] : 1.0f;\n float b = affine ? bias[c] : 0.0f;\n int off = base + cl * HW;\n for (int hw = threadIdx.x; hw < HW; hw += blockDim.x) {\n float v = (x[off + hw] - mean) * rstd;\n v = v * w + b;\n y[off + hw] = silu_f(v);\n }\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int G = (int)num_groups;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n int threads = 256;\n if (C == 256 && G == 32 && H == 24 && W == 24) {\n gn_silu_256_32_24_kernel<<<N * 32, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps, affine ? 1 : 0);\n } else {\n groupnorm_silu_kernel<<<N * G, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_v3',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.43e-06 mean_abs_err=2.69e-08 max_rel_err=7.03e-03
turn 5 · 1 tool call(s) · 30.3s turn · 30.3s LLM · 8,267 chars (click to expand)
turn 530.3s turn · 30.3s LLM · 0.0s tools
reasoning
**Evaluating compilation settings**
I'm thinking I need to set special at 256 and generic at a different value. Compile might not be necessary, but I do want to ensure correctness. Pair reduction assumes shared[32], and it looks like a thread dimension of 512 allows for 16 warps, which seems okay. I should benchmark with fixed default affine set to true and make sure to add affine true without branching. Time to focus on compiling for correctness!
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__inline__ __device__ void block_reduce_pair(float &s, float &q) {\n __shared__ float shs[32];\n __shared__ float shq[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n s = warp_sum(s);\n q = warp_sum(q);\n if (lane == 0) { shs[wid] = s; shq[wid] = q; }\n __syncthreads();\n int nw = blockDim.x >> 5;\n s = (threadIdx.x < nw) ? shs[lane] : 0.0f;\n q = (threadIdx.x < nw) ? shq[lane] : 0.0f;\n if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }\n}\n\n__device__ __forceinline__ float silu_f(float v) {\n return v / (1.0f + expf(-v));\n}\n\n__global__ void gn_silu_256_32_24_affine_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n float eps) {\n int bg = blockIdx.x;\n int g = bg & 31;\n int base = bg * 4608;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);\n float s = 0.0f, q = 0.0f;\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n s += a.x + a.y + a.z + a.w;\n q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float mean = s * (1.0f / 4608.0f);\n float var = q * (1.0f / 4608.0f) - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n int c = g * 8 + (vi / 144);\n float w = weight[c];\n float b = bias[c];\n float4 o;\n float v;\n v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);\n v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);\n v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);\n v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);\n y4[vi] = o;\n }\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n float s = 0.0f, q = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) { float v = x[base + i]; s += v; q += v * v; }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = s * inv_m;\n float var = q * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean; sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean, rstd = sh_rstd;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int cl = i / HW;\n int c = g * cpg + cl;\n float v = (x[base + i] - mean) * rstd;\n if (affine) v = v * weight[c] + bias[c];\n y[base + i] = silu_f(v);\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int G = (int)num_groups;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n if (affine && C == 256 && G == 32 && H == 24 && W == 24) {\n gn_silu_256_32_24_affine_kernel<<<N * 32, 512, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps);\n } else {\n groupnorm_silu_kernel<<<N * G, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_v4',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.43e-06 mean_abs_err=2.70e-08 max_rel_err=8.97e-03
turn 6 · 1 tool call(s) · 19.1s turn · 19.1s LLM · 8,187 chars (click to expand)
turn 619.1s turn · 19.1s LLM · 0.0s tools
reasoning
**Evaluating code structure**
I'm considering a static check on the final code with a size of 1024. I think we can produce the code without needing a try/except block, which might streamline things. Maybe doing it statically simplifies our approach? I wonder if this is the best way to enhance performance while maintaining robustness. It seems like a straightforward solution, but I need to ensure it’s effective and meets our requirements. Let's see how this develops!
call → static_check
callstatic_check
{
"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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__inline__ __device__ void block_reduce_pair(float &s, float &q) {\n __shared__ float shs[32];\n __shared__ float shq[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n s = warp_sum(s);\n q = warp_sum(q);\n if (lane == 0) { shs[wid] = s; shq[wid] = q; }\n __syncthreads();\n int nw = blockDim.x >> 5;\n s = (threadIdx.x < nw) ? shs[lane] : 0.0f;\n q = (threadIdx.x < nw) ? shq[lane] : 0.0f;\n if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }\n}\n\n__device__ __forceinline__ float silu_f(float v) {\n return v / (1.0f + expf(-v));\n}\n\n__global__ void gn_silu_256_32_24_affine_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n float eps) {\n int bg = blockIdx.x;\n int g = bg & 31;\n int base = bg * 4608;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);\n float s = 0.0f, q = 0.0f;\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n s += a.x + a.y + a.z + a.w;\n q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float mean = s * (1.0f / 4608.0f);\n float var = q * (1.0f / 4608.0f) - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n int c = g * 8 + (vi / 144);\n float w = weight[c];\n float b = bias[c];\n float4 o;\n float v;\n v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);\n v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);\n v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);\n v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);\n y4[vi] = o;\n }\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n float s = 0.0f, q = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) { float v = x[base + i]; s += v; q += v * v; }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = s * inv_m;\n float var = q * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean; sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean, rstd = sh_rstd;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int cl = i / HW;\n int c = g * cpg + cl;\n float v = (x[base + i] - mean) * rstd;\n if (affine) v = v * weight[c] + bias[c];\n y[base + i] = silu_f(v);\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int G = (int)num_groups;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n if (affine && C == 256 && G == 32 && H == 24 && W == 24) {\n gn_silu_256_32_24_affine_kernel<<<N * 32, 1024, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps);\n } else {\n groupnorm_silu_kernel<<<N * G, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_final',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 7 · 1 tool call(s) · 13.9s turn · 13.9s LLM · 8,248 chars (click to expand)
turn 713.9s turn · 13.9s LLM · 0.0s tools
reasoning
**Considering compilation and correctness**
I’m thinking about the correctness related to 1024. It seems static compiled might not be the best route since it may not involve a run for correctness. I suspect that 1024 is likely correct, but I wonder about resource registration. I think it wouldn’t compile statically, so maybe I should compile. But since we have calls, it might be better to use run correctness for the final check.
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__inline__ __device__ void block_reduce_pair(float &s, float &q) {\n __shared__ float shs[32];\n __shared__ float shq[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n s = warp_sum(s);\n q = warp_sum(q);\n if (lane == 0) { shs[wid] = s; shq[wid] = q; }\n __syncthreads();\n int nw = blockDim.x >> 5;\n s = (threadIdx.x < nw) ? shs[lane] : 0.0f;\n q = (threadIdx.x < nw) ? shq[lane] : 0.0f;\n if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }\n}\n\n__device__ __forceinline__ float silu_f(float v) {\n return v / (1.0f + expf(-v));\n}\n\n__global__ void gn_silu_256_32_24_affine_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n float eps) {\n int bg = blockIdx.x;\n int g = bg & 31;\n int base = bg * 4608;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);\n float s = 0.0f, q = 0.0f;\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n s += a.x + a.y + a.z + a.w;\n q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float mean = s * (1.0f / 4608.0f);\n float var = q * (1.0f / 4608.0f) - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n int c = g * 8 + (vi / 144);\n float w = weight[c];\n float b = bias[c];\n float4 o;\n float v;\n v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);\n v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);\n v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);\n v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);\n y4[vi] = o;\n }\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n float s = 0.0f, q = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) { float v = x[base + i]; s += v; q += v * v; }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = s * inv_m;\n float var = q * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean; sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean, rstd = sh_rstd;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int cl = i / HW;\n int c = g * cpg + cl;\n float v = (x[base + i] - mean) * rstd;\n if (affine) v = v * weight[c] + bias[c];\n y[base + i] = silu_f(v);\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int G = (int)num_groups;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n if (affine && C == 256 && G == 32 && H == 24 && W == 24) {\n gn_silu_256_32_24_affine_kernel<<<N * 32, 1024, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps);\n } else {\n groupnorm_silu_kernel<<<N * G, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_final2',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.43e-06 mean_abs_err=2.68e-08 max_rel_err=2.06e-03
turn 8 · FINAL · 1 tool call(s) · 26.2s turn · 26.2s LLM · 9,118 chars (click to expand)
turn 826.2s turn · 26.2s LLM · 0.0s tools · FINAL
reasoning
**Analyzing thread and block configurations**
I'm exploring how many blocks and threads to use in a CUDA context. It seems that I can use 512 threads per block, but there’s a maximum of 256 blocks, which leads me to think I might get around two blocks per Streaming Multiprocessor (SM). With considerations for warps and the scheduler, I might also consider configurations of 512 or 1024 threads. It seems like there are potential optimizations, especially with integer divisions and ensuring proper alignment. In summary, I'm weighing options for maximizing efficiency and reducing overhead.
**Considering name collision issues**
I'm thinking about the potential issue of name collisions with extensions. It seems that using a unique name for the final answer code could really help avoid confusion. If I don't need to make it static, then I might consider submitting it as is. The key here is ensuring that any reused names in evaluation don’t cause problems. I think I need to pass a static check for the final submission, but the name must remain unique. Time to finalize everything!
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>\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__inline__ __device__ void block_reduce_pair(float &s, float &q) {\n __shared__ float shs[32];\n __shared__ float shq[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n s = warp_sum(s);\n q = warp_sum(q);\n if (lane == 0) { shs[wid] = s; shq[wid] = q; }\n __syncthreads();\n int nw = blockDim.x >> 5;\n s = (threadIdx.x < nw) ? shs[lane] : 0.0f;\n q = (threadIdx.x < nw) ? shq[lane] : 0.0f;\n if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }\n}\n\n__device__ __forceinline__ float silu_f(float v) {\n return v / (1.0f + expf(-v));\n}\n\n__global__ void gn_silu_256_32_24_affine_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n float eps) {\n int bg = blockIdx.x;\n int g = bg & 31;\n int base = bg * 4608;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);\n float s = 0.0f, q = 0.0f;\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n s += a.x + a.y + a.z + a.w;\n q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;\n }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float mean = s * (1.0f / 4608.0f);\n float var = q * (1.0f / 4608.0f) - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean;\n float rstd = sh_rstd;\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);\n for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {\n float4 a = x4[vi];\n int c = g * 8 + (vi / 144);\n float w = weight[c];\n float b = bias[c];\n float4 o;\n float v;\n v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);\n v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);\n v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);\n v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);\n y4[vi] = o;\n }\n}\n\n__global__ void groupnorm_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ y,\n int N, int C, int H, int W, int G,\n float eps, int affine) {\n int bg = blockIdx.x;\n int n = bg / G;\n int g = bg - n * G;\n int HW = H * W;\n int cpg = C / G;\n int m = cpg * HW;\n int base = ((n * C) + g * cpg) * HW;\n float s = 0.0f, q = 0.0f;\n for (int i = threadIdx.x; i < m; i += blockDim.x) { float v = x[base + i]; s += v; q += v * v; }\n block_reduce_pair(s, q);\n __shared__ float sh_mean, sh_rstd;\n if (threadIdx.x == 0) {\n float inv_m = 1.0f / (float)m;\n float mean = s * inv_m;\n float var = q * inv_m - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean; sh_rstd = rsqrtf(var + eps);\n }\n __syncthreads();\n float mean = sh_mean, rstd = sh_rstd;\n for (int i = threadIdx.x; i < m; i += blockDim.x) {\n int cl = i / HW;\n int c = g * cpg + cl;\n float v = (x[base + i] - mean) * rstd;\n if (affine) v = v * weight[c] + bias[c];\n y[base + i] = silu_f(v);\n }\n}\n\ntorch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t num_groups, double eps, bool affine) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"x must be float32\");\n TORCH_CHECK(x.dim() == 4, \"x must be NCHW\");\n TORCH_CHECK(x.is_contiguous(), \"x must be contiguous\");\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto y = torch::empty_like(x);\n int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);\n int G = (int)num_groups;\n const float* wptr = affine ? weight.data_ptr<float>() : nullptr;\n const float* bptr = affine ? bias.data_ptr<float>() : nullptr;\n if (affine && C == 256 && G == 32 && H == 24 && W == 24) {\n gn_silu_256_32_24_affine_kernel<<<N * 32, 1024, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps);\n } else {\n groupnorm_silu_kernel<<<N * G, 256, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='gn_silu_ext_submit',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['groupnorm_silu_forward'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n extra_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, num_channels: int, num_groups: int, eps: float = 1e-5, affine: bool = True):\n super().__init__()\n assert num_channels % num_groups == 0\n self.num_groups = num_groups\n self.eps = eps\n self.affine = affine\n self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)\n empty = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 0.01 μs
Runtime stats: mean=0.01μs median=?μs std=0.00μs
Numerical precision: max_abs_err=1.43e-06 mean_abs_err=2.68e-08 max_rel_err=2.06e-03
Memory: 42.0 MB peak (ref: 46.5 MB, ratio: 0.9032x)
Kernel launches: 2 (ref: 12, fusion ratio: 6.0)
SOL score: 0.211
final submitted kernel (170 lines, 6,539 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>
torch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
int64_t num_groups, double eps, bool affine);
'''
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <c10/cuda/CUDAException.h>
#include <cuda.h>
#include <cuda_runtime.h>
__inline__ __device__ float warp_sum(float v) {
#pragma unroll
for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);
return v;
}
__inline__ __device__ void block_reduce_pair(float &s, float &q) {
__shared__ float shs[32];
__shared__ float shq[32];
int lane = threadIdx.x & 31;
int wid = threadIdx.x >> 5;
s = warp_sum(s);
q = warp_sum(q);
if (lane == 0) { shs[wid] = s; shq[wid] = q; }
__syncthreads();
int nw = blockDim.x >> 5;
s = (threadIdx.x < nw) ? shs[lane] : 0.0f;
q = (threadIdx.x < nw) ? shq[lane] : 0.0f;
if (wid == 0) { s = warp_sum(s); q = warp_sum(q); }
}
__device__ __forceinline__ float silu_f(float v) {
return v / (1.0f + expf(-v));
}
__global__ void gn_silu_256_32_24_affine_kernel(const float* __restrict__ x,
const float* __restrict__ weight,
const float* __restrict__ bias,
float* __restrict__ y,
float eps) {
int bg = blockIdx.x;
int g = bg & 31;
int base = bg * 4608;
const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + base);
float s = 0.0f, q = 0.0f;
for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {
float4 a = x4[vi];
s += a.x + a.y + a.z + a.w;
q += a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;
}
block_reduce_pair(s, q);
__shared__ float sh_mean, sh_rstd;
if (threadIdx.x == 0) {
float mean = s * (1.0f / 4608.0f);
float var = q * (1.0f / 4608.0f) - mean * mean;
if (var < 0.0f) var = 0.0f;
sh_mean = mean;
sh_rstd = rsqrtf(var + eps);
}
__syncthreads();
float mean = sh_mean;
float rstd = sh_rstd;
float4* __restrict__ y4 = reinterpret_cast<float4*>(y + base);
for (int vi = threadIdx.x; vi < 1152; vi += blockDim.x) {
float4 a = x4[vi];
int c = g * 8 + (vi / 144);
float w = weight[c];
float b = bias[c];
float4 o;
float v;
v = (a.x - mean) * rstd; v = v * w + b; o.x = silu_f(v);
v = (a.y - mean) * rstd; v = v * w + b; o.y = silu_f(v);
v = (a.z - mean) * rstd; v = v * w + b; o.z = silu_f(v);
v = (a.w - mean) * rstd; v = v * w + b; o.w = silu_f(v);
y4[vi] = o;
}
}
__global__ void groupnorm_silu_kernel(const float* __restrict__ x,
const float* __restrict__ weight,
const float* __restrict__ bias,
float* __restrict__ y,
int N, int C, int H, int W, int G,
float eps, int affine) {
int bg = blockIdx.x;
int n = bg / G;
int g = bg - n * G;
int HW = H * W;
int cpg = C / G;
int m = cpg * HW;
int base = ((n * C) + g * cpg) * HW;
float s = 0.0f, q = 0.0f;
for (int i = threadIdx.x; i < m; i += blockDim.x) { float v = x[base + i]; s += v; q += v * v; }
block_reduce_pair(s, q);
__shared__ float sh_mean, sh_rstd;
if (threadIdx.x == 0) {
float inv_m = 1.0f / (float)m;
float mean = s * inv_m;
float var = q * inv_m - mean * mean;
if (var < 0.0f) var = 0.0f;
sh_mean = mean; sh_rstd = rsqrtf(var + eps);
}
__syncthreads();
float mean = sh_mean, rstd = sh_rstd;
for (int i = threadIdx.x; i < m; i += blockDim.x) {
int cl = i / HW;
int c = g * cpg + cl;
float v = (x[base + i] - mean) * rstd;
if (affine) v = v * weight[c] + bias[c];
y[base + i] = silu_f(v);
}
}
torch::Tensor groupnorm_silu_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,
int64_t num_groups, double eps, bool affine) {
TORCH_CHECK(x.is_cuda(), "x must be CUDA");
TORCH_CHECK(x.scalar_type() == at::kFloat, "x must be float32");
TORCH_CHECK(x.dim() == 4, "x must be NCHW");
TORCH_CHECK(x.is_contiguous(), "x must be contiguous");
const at::cuda::OptionalCUDAGuard device_guard(device_of(x));
auto y = torch::empty_like(x);
int N = (int)x.size(0), C = (int)x.size(1), H = (int)x.size(2), W = (int)x.size(3);
int G = (int)num_groups;
const float* wptr = affine ? weight.data_ptr<float>() : nullptr;
const float* bptr = affine ? bias.data_ptr<float>() : nullptr;
if (affine && C == 256 && G == 32 && H == 24 && W == 24) {
gn_silu_256_32_24_affine_kernel<<<N * 32, 1024, 0, at::cuda::getCurrentCUDAStream()>>>(
x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), (float)eps);
} else {
groupnorm_silu_kernel<<<N * G, 256, 0, at::cuda::getCurrentCUDAStream()>>>(
x.data_ptr<float>(), wptr, bptr, y.data_ptr<float>(), N, C, H, W, G, (float)eps, affine ? 1 : 0);
}
C10_CUDA_KERNEL_LAUNCH_CHECK();
return y;
}
'''
_ext = load_inline(
name='gn_silu_ext_submit',
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=['groupnorm_silu_forward'],
extra_cuda_cflags=['-O3', '--use_fast_math'],
extra_cflags=['-O3'],
verbose=False,
)
class ModelNew(nn.Module):
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.num_groups = num_groups
self.eps = eps
self.affine = affine
self.norm = nn.GroupNorm(num_groups=num_groups, num_channels=num_channels, eps=eps, affine=affine)
def forward(self, x: torch.Tensor) -> torch.Tensor:
if self.affine:
return _ext.groupnorm_silu_forward(x, self.norm.weight, self.norm.bias, self.num_groups, self.eps, True)
empty = torch.empty(0, device=x.device, dtype=x.dtype)
return _ext.groupnorm_silu_forward(x, empty, empty, self.num_groups, self.eps, False)