correct
44_Average_Pooling_1D.py
started
2026-05-05T00:37:24Z
timingkernelbench.timing
kernel mean / median / std
2.76 / — / 3.02 μs
ref mean / median / std
5.46 / — / 0.06 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
6.00x
energyNVML (pynvml)
ratio (ref / kernel)
9.00x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
1750.00 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 1D Average Pooling.
"""
def __init__(self, kernel_size: int, stride: int = 1, padding: int = 0):
"""
Initializes the 1D Average Pooling layer.
Args:
kernel_size (int): Size of the pooling window.
stride (int, optional): Stride of the pooling operation. Defaults to 1.
padding (int, optional): Padding applied to the input tensor. Defaults to 0.
"""
super(Model, self).__init__()
self.avg_pool = nn.AvgPool1d(kernel_size=kernel_size, stride=stride, padding=padding)
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Applies 1D Average Pooling to the input tensor.
Args:
x (torch.Tensor): Input tensor of shape (batch_size, in_channels, input_length).
Returns:
torch.Tensor: Output tensor with 1D Average Pooling applied, shape (batch_size, in_channels, output_length).
"""
return self.avg_pool(x)
batch_size = 64
in_channels = 128
input_length = 65536
kernel_size = 8
stride = 1
padding = 4
def get_inputs():
x = torch.rand(batch_size, in_channels, input_length)
return [x]
def get_init_inputs():
return [kernel_size, stride, padding]turn 021.3s turn · 21.3s 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 avgpool1d_forward_cuda(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding);\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// Optimized specialization for the benchmark case: k=8, stride=1, pad=4, float32 contiguous.\ntemplate<int TILE>\n__global__ __launch_bounds__(256, 2)\nvoid avgpool1d_k8s1p4_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int L, int outL) {\n extern __shared__ float smem[];\n int row = blockIdx.y;\n int tile_start = blockIdx.x * TILE;\n int tid = threadIdx.x;\n\n const float* rowx = x + (long long)row * L;\n float* rowy = y + (long long)row * outL;\n\n // Load the input interval needed by this output tile: [tile_start-4, tile_start+TILE+2]\n // (TILE+7 values). Out-of-range values are zero padding.\n for (int i = tid; i < TILE + 7; i += blockDim.x) {\n int idx = tile_start + i - 4;\n smem[i] = (idx >= 0 && idx < L) ? rowx[idx] : 0.0f;\n }\n __syncthreads();\n\n int o = tile_start + tid;\n if (tid < TILE && o < outL) {\n // Window for output o is input[o-4 ... o+3], resident at smem[tid ... tid+7].\n float s0 = smem[tid] + smem[tid + 1];\n float s1 = smem[tid + 2] + smem[tid + 3];\n float s2 = smem[tid + 4] + smem[tid + 5];\n float s3 = smem[tid + 6] + smem[tid + 7];\n rowy[o] = (s0 + s1 + s2 + s3) * 0.125f;\n }\n}\n\n// Generic float32 fallback for other constructor arguments (still a real CUDA implementation).\n__global__ void avgpool1d_generic_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int L, int outL, int K, int S, int P) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = rows * outL;\n if (idx >= total) return;\n int o = idx % outL;\n int row = idx / outL;\n int start = o * S - P;\n const float* rowx = x + (long long)row * L;\n float sum = 0.0f;\n #pragma unroll 16\n for (int k = 0; k < K; ++k) {\n int xi = start + k;\n if (xi >= 0 && xi < L) sum += rowx[xi];\n }\n y[idx] = sum / (float)K; // AvgPool1d default count_include_pad=True\n}\n\ntorch::Tensor avgpool1d_forward_cuda(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n if (!x.is_contiguous()) x = x.contiguous();\n TORCH_CHECK(x.dim() == 3, \"expected 3D tensor\");\n int64_t B = x.size(0), C = x.size(1), L64 = x.size(2);\n int64_t outL64 = (L64 + 2 * padding - kernel_size) / stride + 1;\n auto y = torch::empty({B, C, outL64}, x.options());\n int rows = (int)(B * C);\n int L = (int)L64;\n int outL = (int)outL64;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (kernel_size == 8 && stride == 1 && padding == 4) {\n constexpr int TILE = 256;\n dim3 block(256);\n dim3 grid((outL + TILE - 1) / TILE, rows);\n size_t shmem = (TILE + 7) * sizeof(float);\n avgpool1d_k8s1p4_kernel<TILE><<<grid, block, shmem, stream>>>(\n x.data_ptr<float>(), y.data_ptr<float>(), rows, L, outL);\n } else {\n int total = rows * outL;\n dim3 block(256);\n dim3 grid((total + 255) / 256);\n avgpool1d_generic_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), y.data_ptr<float>(), rows, L, outL,\n (int)kernel_size, (int)stride, (int)padding);\n }\n return y;\n}\n'''\n\n_ext = load_inline(\n name='avgpool1d_custom_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['avgpool1d_forward_cuda'],\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, kernel_size: int, stride: int = 1, padding: int = 0):\n super(ModelNew, self).__init__()\n self.kernel_size = int(kernel_size)\n self.stride = int(stride)\n self.padding = int(padding)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.avgpool1d_forward_cuda(x, self.kernel_size, self.stride, self.padding)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 2.76 μs
Runtime stats: mean=2.76μs median=?μs std=3.02μs
Numerical precision: max_abs_err=1.79e-07 mean_abs_err=1.67e-08 max_rel_err=3.51e-07
Memory: 4129.03 MB peak (ref: 4129.03 MB, ratio: 1.0x)
Kernel launches: 1 (ref: 6, fusion ratio: 6.0)
Energy: 242.86 mJ/run (ref: 2185.98 mJ, ratio: 9.001x)
SOL score: 0.5224
final submitted kernel (119 lines, 4,388 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 avgpool1d_forward_cuda(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding);
'''
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
// Optimized specialization for the benchmark case: k=8, stride=1, pad=4, float32 contiguous.
template<int TILE>
__global__ __launch_bounds__(256, 2)
void avgpool1d_k8s1p4_kernel(const float* __restrict__ x, float* __restrict__ y,
int rows, int L, int outL) {
extern __shared__ float smem[];
int row = blockIdx.y;
int tile_start = blockIdx.x * TILE;
int tid = threadIdx.x;
const float* rowx = x + (long long)row * L;
float* rowy = y + (long long)row * outL;
// Load the input interval needed by this output tile: [tile_start-4, tile_start+TILE+2]
// (TILE+7 values). Out-of-range values are zero padding.
for (int i = tid; i < TILE + 7; i += blockDim.x) {
int idx = tile_start + i - 4;
smem[i] = (idx >= 0 && idx < L) ? rowx[idx] : 0.0f;
}
__syncthreads();
int o = tile_start + tid;
if (tid < TILE && o < outL) {
// Window for output o is input[o-4 ... o+3], resident at smem[tid ... tid+7].
float s0 = smem[tid] + smem[tid + 1];
float s1 = smem[tid + 2] + smem[tid + 3];
float s2 = smem[tid + 4] + smem[tid + 5];
float s3 = smem[tid + 6] + smem[tid + 7];
rowy[o] = (s0 + s1 + s2 + s3) * 0.125f;
}
}
// Generic float32 fallback for other constructor arguments (still a real CUDA implementation).
__global__ void avgpool1d_generic_kernel(const float* __restrict__ x, float* __restrict__ y,
int rows, int L, int outL, int K, int S, int P) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int total = rows * outL;
if (idx >= total) return;
int o = idx % outL;
int row = idx / outL;
int start = o * S - P;
const float* rowx = x + (long long)row * L;
float sum = 0.0f;
#pragma unroll 16
for (int k = 0; k < K; ++k) {
int xi = start + k;
if (xi >= 0 && xi < L) sum += rowx[xi];
}
y[idx] = sum / (float)K; // AvgPool1d default count_include_pad=True
}
torch::Tensor avgpool1d_forward_cuda(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding) {
TORCH_CHECK(x.is_cuda(), "x must be CUDA");
TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 is supported");
if (!x.is_contiguous()) x = x.contiguous();
TORCH_CHECK(x.dim() == 3, "expected 3D tensor");
int64_t B = x.size(0), C = x.size(1), L64 = x.size(2);
int64_t outL64 = (L64 + 2 * padding - kernel_size) / stride + 1;
auto y = torch::empty({B, C, outL64}, x.options());
int rows = (int)(B * C);
int L = (int)L64;
int outL = (int)outL64;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
if (kernel_size == 8 && stride == 1 && padding == 4) {
constexpr int TILE = 256;
dim3 block(256);
dim3 grid((outL + TILE - 1) / TILE, rows);
size_t shmem = (TILE + 7) * sizeof(float);
avgpool1d_k8s1p4_kernel<TILE><<<grid, block, shmem, stream>>>(
x.data_ptr<float>(), y.data_ptr<float>(), rows, L, outL);
} else {
int total = rows * outL;
dim3 block(256);
dim3 grid((total + 255) / 256);
avgpool1d_generic_kernel<<<grid, block, 0, stream>>>(
x.data_ptr<float>(), y.data_ptr<float>(), rows, L, outL,
(int)kernel_size, (int)stride, (int)padding);
}
return y;
}
'''
_ext = load_inline(
name='avgpool1d_custom_ext_v1',
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=['avgpool1d_forward_cuda'],
extra_cuda_cflags=['-O3', '--use_fast_math'],
extra_cflags=['-O3'],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self, kernel_size: int, stride: int = 1, padding: int = 0):
super(ModelNew, self).__init__()
self.kernel_size = int(kernel_size)
self.stride = int(stride)
self.padding = int(padding)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.avgpool1d_forward_cuda(x, self.kernel_size, self.stride, self.padding)