incorrect
39_L2Norm_.py
started
2026-05-05T00:13:43Z
correctness issue:
timingkernelbench.timing
kernel mean / median / std
—
ref mean / median / std
10.40 / — / 1.05 μs
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
1962.42 GB/s
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Simple model that performs L2 normalization.
"""
def __init__(self):
"""
Initializes the L2Norm layer.
Args:
dim (int): Dimension along which to normalize.
"""
super(Model, self).__init__()
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Applies L2 normalization to the input tensor.
Args:
x (torch.Tensor): Input tensor of shape (*, dim, *).
Returns:
torch.Tensor: Output tensor with L2 normalization applied, same shape as input.
"""
return x / torch.norm(x, p=2, dim=1, keepdim=True)
batch_size = 32768
# choose dim so total <2^31
dim = 65535
def get_inputs():
x = torch.rand(batch_size, dim)
return [x]
def get_init_inputs():
return []turn 041.2s turn · 41.2s LLM · 0.0s tools · FINAL
reasoning
**Considering CUDA integration**
I’m thinking about how we can include C++ host code within `cuda_sources`. It seems like using `load_inline` with `cuda_sources` can help incorporate C++ definitions that are compiled by NVCC. This approach makes sense since I need those functions to be visible for binding. It feels like a neat way to handle things, and I'm curious what it will look like in practice when I put this together.
**Considering memory allocation**
I’m thinking about calling contiguous but wondering if it will copy something I don’t want. The input's shape is contiguous, so maybe I can check with x.contiguous? If it’s already contiguous, no need to create a copy.
I’m also considering potential memory limits. If the output allocation is empty_like and set to 8.6GB, while the input is also 8.6GB, is it feasible to allocate around 24GB? This seems tricky!
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 l2norm_forward(torch::Tensor x);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_reduce_sum(float v) {\n v += __shfl_down_sync(0xffffffff, v, 16);\n v += __shfl_down_sync(0xffffffff, v, 8);\n v += __shfl_down_sync(0xffffffff, v, 4);\n v += __shfl_down_sync(0xffffffff, v, 2);\n v += __shfl_down_sync(0xffffffff, v, 1);\n return v;\n}\n\ntemplate<int BLOCK>\n__global__ void l2norm_rows_kernel(const float* __restrict__ x,\n float* __restrict__ y,\n int rows, int cols) {\n int row = blockIdx.x;\n if (row >= rows) return;\n int tid = threadIdx.x;\n long long base = (long long)row * (long long)cols;\n\n float ss = 0.0f;\n for (int c = tid; c < cols; c += BLOCK) {\n float v = x[base + c];\n ss = fmaf(v, v, ss);\n }\n\n ss = warp_reduce_sum(ss);\n\n __shared__ float smem[32];\n if ((tid & 31) == 0) smem[tid >> 5] = ss;\n __syncthreads();\n\n float total = 0.0f;\n if (tid < 32) {\n total = (tid < (BLOCK >> 5)) ? smem[tid] : 0.0f;\n total = warp_reduce_sum(total);\n if (tid == 0) smem[0] = rsqrtf(total);\n }\n __syncthreads();\n\n float inv = smem[0];\n for (int c = tid; c < cols; c += BLOCK) {\n y[base + c] = x[base + c] * inv;\n }\n}\n\ntorch::Tensor l2norm_forward(torch::Tensor x) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.dim() == 2, \"expected a 2D tensor\");\n auto xc = x.contiguous();\n auto y = torch::empty_like(xc);\n int rows = (int)xc.size(0);\n int cols = (int)xc.size(1);\n constexpr int BLOCK = 256;\n dim3 grid(rows);\n dim3 block(BLOCK);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n l2norm_rows_kernel<BLOCK><<<grid, block, 0, stream>>>(\n xc.data_ptr<float>(), y.data_ptr<float>(), rows, cols);\n return y;\n}\n'''\n\n_ext = load_inline(\n name='l2norm_dim1_ext_v1',\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=['l2norm_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super(ModelNew, self).__init__()\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.l2norm_forward(x)\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: correctness check did not pass (? trials).
runtime_error: CUDA out of memory. Tried to allocate 2.00 GiB. GPU 0 has a total capacity of 79.10 GiB of which 1.13 GiB is free. Process 1468161 has 714.00 MiB memory in use. Process 1054633 has 516.00 MiB memor...
final submitted kernel (94 lines, 2,588 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 l2norm_forward(torch::Tensor x);
'''
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
__inline__ __device__ float warp_reduce_sum(float v) {
v += __shfl_down_sync(0xffffffff, v, 16);
v += __shfl_down_sync(0xffffffff, v, 8);
v += __shfl_down_sync(0xffffffff, v, 4);
v += __shfl_down_sync(0xffffffff, v, 2);
v += __shfl_down_sync(0xffffffff, v, 1);
return v;
}
template<int BLOCK>
__global__ void l2norm_rows_kernel(const float* __restrict__ x,
float* __restrict__ y,
int rows, int cols) {
int row = blockIdx.x;
if (row >= rows) return;
int tid = threadIdx.x;
long long base = (long long)row * (long long)cols;
float ss = 0.0f;
for (int c = tid; c < cols; c += BLOCK) {
float v = x[base + c];
ss = fmaf(v, v, ss);
}
ss = warp_reduce_sum(ss);
__shared__ float smem[32];
if ((tid & 31) == 0) smem[tid >> 5] = ss;
__syncthreads();
float total = 0.0f;
if (tid < 32) {
total = (tid < (BLOCK >> 5)) ? smem[tid] : 0.0f;
total = warp_reduce_sum(total);
if (tid == 0) smem[0] = rsqrtf(total);
}
__syncthreads();
float inv = smem[0];
for (int c = tid; c < cols; c += BLOCK) {
y[base + c] = x[base + c] * inv;
}
}
torch::Tensor l2norm_forward(torch::Tensor x) {
TORCH_CHECK(x.is_cuda(), "x must be CUDA");
TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 supported");
TORCH_CHECK(x.dim() == 2, "expected a 2D tensor");
auto xc = x.contiguous();
auto y = torch::empty_like(xc);
int rows = (int)xc.size(0);
int cols = (int)xc.size(1);
constexpr int BLOCK = 256;
dim3 grid(rows);
dim3 block(BLOCK);
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
l2norm_rows_kernel<BLOCK><<<grid, block, 0, stream>>>(
xc.data_ptr<float>(), y.data_ptr<float>(), rows, cols);
return y;
}
'''
_ext = load_inline(
name='l2norm_dim1_ext_v1',
cpp_sources=[_cpp_src],
cuda_sources=[_cuda_src],
functions=['l2norm_forward'],
extra_cflags=['-O3'],
extra_cuda_cflags=['-O3'],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self):
super(ModelNew, self).__init__()
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.l2norm_forward(x)