correct
17_Conv2d_InstanceNorm_Divide.py
started
2026-05-05T01:12:15Z
timingkernelbench.timing
kernel mean / median / std
3.96 / — / 0.46 μs
ref mean / median / std
4.99 / — / 0.38 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
2.67x
energyNVML (pynvml)
ratio (ref / kernel)
0.29x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
9014.80 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 a convolution, applies Instance Normalization, and divides by a constant.
"""
def __init__(self, in_channels, out_channels, kernel_size, divide_by):
super(Model, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
self.instance_norm = nn.InstanceNorm2d(out_channels)
self.divide_by = divide_by
def forward(self, x):
x = self.conv(x)
x = self.instance_norm(x)
x = x / self.divide_by
return x
batch_size = 128
in_channels = 64
out_channels = 128
height = width = 128
kernel_size = 3
divide_by = 2.0
def get_inputs():
return [torch.rand(batch_size, in_channels, height, width)]
def get_init_inputs():
return [in_channels, out_channels, kernel_size, divide_by]turn 0 · FINAL · 1 tool call(s) · 42.6s turn · 42.6s LLM · 6,732 chars (click to expand)
turn 042.6s turn · 42.6s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor instance_norm_div(torch::Tensor input, double divide_by);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#ifndef BLOCK_SIZE\n#define BLOCK_SIZE 256\n#endif\n\n__global__ void inst_norm_div_vec4_kernel(const float* __restrict__ x,\n float* __restrict__ y,\n int m4,\n float div_by) {\n const int nc = blockIdx.x;\n const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + ((long long)nc) * ((long long)m4) * 4LL);\n float4* __restrict__ y4 = reinterpret_cast<float4*>(y + ((long long)nc) * ((long long)m4) * 4LL);\n\n float sum = 0.0f;\n float sumsq = 0.0f;\n\n for (int i = threadIdx.x; i < m4; i += BLOCK_SIZE) {\n float4 v = x4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq = fmaf(v.x, v.x, sumsq);\n sumsq = fmaf(v.y, v.y, sumsq);\n sumsq = fmaf(v.z, v.z, sumsq);\n sumsq = fmaf(v.w, v.w, sumsq);\n }\n\n __shared__ float s_sum[BLOCK_SIZE];\n __shared__ float s_sumsq[BLOCK_SIZE];\n s_sum[threadIdx.x] = sum;\n s_sumsq[threadIdx.x] = sumsq;\n __syncthreads();\n\n #pragma unroll\n for (int stride = BLOCK_SIZE / 2; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n s_sum[threadIdx.x] += s_sum[threadIdx.x + stride];\n s_sumsq[threadIdx.x] += s_sumsq[threadIdx.x + stride];\n }\n __syncthreads();\n }\n\n const float inv_m = 1.0f / (float)(m4 * 4);\n const float mean = s_sum[0] * inv_m;\n float var = s_sumsq[0] * inv_m - mean * mean;\n var = var > 0.0f ? var : 0.0f;\n const float scale = rsqrtf(var + 1.0e-5f) / div_by;\n\n for (int i = threadIdx.x; i < m4; i += BLOCK_SIZE) {\n float4 v = x4[i];\n v.x = (v.x - mean) * scale;\n v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale;\n v.w = (v.w - mean) * scale;\n y4[i] = v;\n }\n}\n\n__global__ void inst_norm_div_scalar_kernel(const float* __restrict__ x,\n float* __restrict__ y,\n int m,\n float div_by) {\n const int nc = blockIdx.x;\n const long long base = ((long long)nc) * (long long)m;\n\n float sum = 0.0f;\n float sumsq = 0.0f;\n for (int i = threadIdx.x; i < m; i += BLOCK_SIZE) {\n float v = x[base + i];\n sum += v;\n sumsq = fmaf(v, v, sumsq);\n }\n\n __shared__ float s_sum[BLOCK_SIZE];\n __shared__ float s_sumsq[BLOCK_SIZE];\n s_sum[threadIdx.x] = sum;\n s_sumsq[threadIdx.x] = sumsq;\n __syncthreads();\n\n #pragma unroll\n for (int stride = BLOCK_SIZE / 2; stride > 0; stride >>= 1) {\n if (threadIdx.x < stride) {\n s_sum[threadIdx.x] += s_sum[threadIdx.x + stride];\n s_sumsq[threadIdx.x] += s_sumsq[threadIdx.x + stride];\n }\n __syncthreads();\n }\n\n const float inv_m = 1.0f / (float)m;\n const float mean = s_sum[0] * inv_m;\n float var = s_sumsq[0] * inv_m - mean * mean;\n var = var > 0.0f ? var : 0.0f;\n const float scale = rsqrtf(var + 1.0e-5f) / div_by;\n\n for (int i = threadIdx.x; i < m; i += BLOCK_SIZE) {\n y[base + i] = (x[base + i] - mean) * scale;\n }\n}\n\ntorch::Tensor instance_norm_div(torch::Tensor input, double divide_by) {\n TORCH_CHECK(input.is_cuda(), \"input must be CUDA\");\n TORCH_CHECK(input.scalar_type() == at::kFloat, \"only float32 is supported\");\n TORCH_CHECK(input.dim() == 4, \"expected NCHW tensor\");\n TORCH_CHECK(input.is_contiguous(), \"input must be contiguous\");\n\n auto output = torch::empty_like(input);\n const int n = (int)input.size(0);\n const int c = (int)input.size(1);\n const int h = (int)input.size(2);\n const int w = (int)input.size(3);\n const int m = h * w;\n const int blocks = n * c;\n const float div = (float)divide_by;\n\n if (blocks > 0 && m > 0) {\n const float* x = input.data_ptr<float>();\n float* y = output.data_ptr<float>();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if ((m & 3) == 0) {\n inst_norm_div_vec4_kernel<<<blocks, BLOCK_SIZE, 0, stream>>>(x, y, m >> 2, div);\n } else {\n inst_norm_div_scalar_kernel<<<blocks, BLOCK_SIZE, 0, stream>>>(x, y, m, div);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n }\n return output;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"modelnew_instnorm_div_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"instance_norm_div\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n\n def forward(self, x):\n y = self.conv(x)\n return _ext.instance_norm_div(y, self.divide_by)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 3.96 μs
Runtime stats: mean=3.96μs median=?μs std=0.46μs
Numerical precision: max_abs_err=8.34e-06 mean_abs_err=1.35e-07 max_rel_err=7.01e+05
Memory: 2530.06 MB peak (ref: 2530.19 MB, ratio: 1.0x)
Kernel launches: 9 (ref: 24, fusion ratio: 2.6667)
Energy: 1682.76 mJ/run (ref: 481.22 mJ, ratio: 0.286x)
SOL score: 1.0
final submitted kernel (165 lines, 5,334 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 instance_norm_div(torch::Tensor input, double divide_by);
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAException.h>
#include <cuda.h>
#include <cuda_runtime.h>
#ifndef BLOCK_SIZE
#define BLOCK_SIZE 256
#endif
__global__ void inst_norm_div_vec4_kernel(const float* __restrict__ x,
float* __restrict__ y,
int m4,
float div_by) {
const int nc = blockIdx.x;
const float4* __restrict__ x4 = reinterpret_cast<const float4*>(x + ((long long)nc) * ((long long)m4) * 4LL);
float4* __restrict__ y4 = reinterpret_cast<float4*>(y + ((long long)nc) * ((long long)m4) * 4LL);
float sum = 0.0f;
float sumsq = 0.0f;
for (int i = threadIdx.x; i < m4; i += BLOCK_SIZE) {
float4 v = x4[i];
sum += v.x + v.y + v.z + v.w;
sumsq = fmaf(v.x, v.x, sumsq);
sumsq = fmaf(v.y, v.y, sumsq);
sumsq = fmaf(v.z, v.z, sumsq);
sumsq = fmaf(v.w, v.w, sumsq);
}
__shared__ float s_sum[BLOCK_SIZE];
__shared__ float s_sumsq[BLOCK_SIZE];
s_sum[threadIdx.x] = sum;
s_sumsq[threadIdx.x] = sumsq;
__syncthreads();
#pragma unroll
for (int stride = BLOCK_SIZE / 2; stride > 0; stride >>= 1) {
if (threadIdx.x < stride) {
s_sum[threadIdx.x] += s_sum[threadIdx.x + stride];
s_sumsq[threadIdx.x] += s_sumsq[threadIdx.x + stride];
}
__syncthreads();
}
const float inv_m = 1.0f / (float)(m4 * 4);
const float mean = s_sum[0] * inv_m;
float var = s_sumsq[0] * inv_m - mean * mean;
var = var > 0.0f ? var : 0.0f;
const float scale = rsqrtf(var + 1.0e-5f) / div_by;
for (int i = threadIdx.x; i < m4; i += BLOCK_SIZE) {
float4 v = x4[i];
v.x = (v.x - mean) * scale;
v.y = (v.y - mean) * scale;
v.z = (v.z - mean) * scale;
v.w = (v.w - mean) * scale;
y4[i] = v;
}
}
__global__ void inst_norm_div_scalar_kernel(const float* __restrict__ x,
float* __restrict__ y,
int m,
float div_by) {
const int nc = blockIdx.x;
const long long base = ((long long)nc) * (long long)m;
float sum = 0.0f;
float sumsq = 0.0f;
for (int i = threadIdx.x; i < m; i += BLOCK_SIZE) {
float v = x[base + i];
sum += v;
sumsq = fmaf(v, v, sumsq);
}
__shared__ float s_sum[BLOCK_SIZE];
__shared__ float s_sumsq[BLOCK_SIZE];
s_sum[threadIdx.x] = sum;
s_sumsq[threadIdx.x] = sumsq;
__syncthreads();
#pragma unroll
for (int stride = BLOCK_SIZE / 2; stride > 0; stride >>= 1) {
if (threadIdx.x < stride) {
s_sum[threadIdx.x] += s_sum[threadIdx.x + stride];
s_sumsq[threadIdx.x] += s_sumsq[threadIdx.x + stride];
}
__syncthreads();
}
const float inv_m = 1.0f / (float)m;
const float mean = s_sum[0] * inv_m;
float var = s_sumsq[0] * inv_m - mean * mean;
var = var > 0.0f ? var : 0.0f;
const float scale = rsqrtf(var + 1.0e-5f) / div_by;
for (int i = threadIdx.x; i < m; i += BLOCK_SIZE) {
y[base + i] = (x[base + i] - mean) * scale;
}
}
torch::Tensor instance_norm_div(torch::Tensor input, double divide_by) {
TORCH_CHECK(input.is_cuda(), "input must be CUDA");
TORCH_CHECK(input.scalar_type() == at::kFloat, "only float32 is supported");
TORCH_CHECK(input.dim() == 4, "expected NCHW tensor");
TORCH_CHECK(input.is_contiguous(), "input must be contiguous");
auto output = torch::empty_like(input);
const int n = (int)input.size(0);
const int c = (int)input.size(1);
const int h = (int)input.size(2);
const int w = (int)input.size(3);
const int m = h * w;
const int blocks = n * c;
const float div = (float)divide_by;
if (blocks > 0 && m > 0) {
const float* x = input.data_ptr<float>();
float* y = output.data_ptr<float>();
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
if ((m & 3) == 0) {
inst_norm_div_vec4_kernel<<<blocks, BLOCK_SIZE, 0, stream>>>(x, y, m >> 2, div);
} else {
inst_norm_div_scalar_kernel<<<blocks, BLOCK_SIZE, 0, stream>>>(x, y, m, div);
}
C10_CUDA_KERNEL_LAUNCH_CHECK();
}
return output;
}
"""
_ext = load_inline(
name="modelnew_instnorm_div_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["instance_norm_div"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size, divide_by):
super(ModelNew, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
self.instance_norm = nn.InstanceNorm2d(out_channels)
self.divide_by = float(divide_by)
def forward(self, x):
y = self.conv(x)
return _ext.instance_norm_div(y, self.divide_by)