incorrect
55_Matmul_MaxPool_Sum_Scale.py
started
2026-05-05T00:02:02Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel mean / median / std
—
ref mean / median / std
5.30 / — / 0.01 μs
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
1395.52 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):
"""
Model that performs matrix multiplication, max pooling, sum, and scaling.
"""
def __init__(self, in_features, out_features, kernel_size, scale_factor):
super(Model, self).__init__()
self.matmul = nn.Linear(in_features, out_features)
self.max_pool = nn.MaxPool1d(kernel_size)
self.scale_factor = scale_factor
def forward(self, x):
"""
Args:
x (torch.Tensor): Input tensor of shape (batch_size, in_features).
Returns:
torch.Tensor: Output tensor of shape (batch_size, out_features).
"""
x = self.matmul(x)
x = self.max_pool(x.unsqueeze(1)).squeeze(1)
x = torch.sum(x, dim=1)
x = x * self.scale_factor
return x
batch_size = 128
in_features = 32768
out_features = 32768
kernel_size = 2
scale_factor = 0.5
def get_inputs():
return [torch.rand(batch_size, in_features)]
def get_init_inputs():
return [in_features, out_features, kernel_size, scale_factor]turn 0 · FINAL · 1 tool call(s) · 182.4s turn · 182.4s LLM · 6,445 chars (click to expand)
turn 0182.4s turn · 182.4s LLM · 0.0s tools · FINAL
reasoning
**Evaluating performance in PyTorch**
I’m considering if calling at::linear could be faster, though I’m not sure it can beat the reference implementation, especially since it includes operations like matmul, which tends to dominate performance. I think I might also need to account for overhead from materialization and pooling. However, linear does utilize cuBLAS, which could potentially help with performance. So, I’ll have to look closely at these trade-offs to figure out the best approach.
**Optimizing code compilation**
I'm aiming to save on maxpool overhead, which sounds good. I think I need to compile code with load_inline and maybe optimize for float only. I'll focus on correctness with fp32. There shouldn’t be a need for try/except here. I’ll also include the CUDA source and the cpp wrapper. It seems like load_inline requires cpp_sources with declarations, and fortunately, I don't need PyBind for this.
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\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor pool_sum_forward(torch::Tensor y, int64_t kernel_size, double scale);\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#include <cfloat>\n\n__global__ void pool_sum_k2_kernel(const float* __restrict__ y,\n float* __restrict__ out,\n int B, int N, float scale) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n const float* base = y + ((long long)row) * N;\n int pairs = N >> 1;\n\n float acc = 0.0f;\n for (int p = tid; p < pairs; p += blockDim.x) {\n float a = base[(p << 1)];\n float b = base[(p << 1) + 1];\n acc += fmaxf(a, b);\n }\n\n __shared__ float smem[256];\n smem[tid] = acc;\n __syncthreads();\n\n // blockDim is launched as 256\n if (tid < 128) smem[tid] += smem[tid + 128];\n __syncthreads();\n if (tid < 64) smem[tid] += smem[tid + 64];\n __syncthreads();\n\n if (tid < 32) {\n float v = smem[tid];\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 if (tid == 0) out[row] = v * scale;\n }\n}\n\n__global__ void pool_sum_generic_kernel(const float* __restrict__ y,\n float* __restrict__ out,\n int B, int N, int K, float scale) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n const float* base = y + ((long long)row) * N;\n int windows = N / K;\n\n float acc = 0.0f;\n for (int w = tid; w < windows; w += blockDim.x) {\n const float* ptr = base + ((long long)w) * K;\n float m = -FLT_MAX;\n for (int j = 0; j < K; ++j) {\n m = fmaxf(m, ptr[j]);\n }\n acc += m;\n }\n\n __shared__ float smem[256];\n smem[tid] = acc;\n __syncthreads();\n\n if (tid < 128) smem[tid] += smem[tid + 128];\n __syncthreads();\n if (tid < 64) smem[tid] += smem[tid + 64];\n __syncthreads();\n\n if (tid < 32) {\n float v = smem[tid];\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 if (tid == 0) out[row] = v * scale;\n }\n}\n\ntorch::Tensor pool_sum_forward(torch::Tensor y, int64_t kernel_size, double scale) {\n const int B = (int)y.size(0);\n const int N = (int)y.size(1);\n auto out = torch::empty({B}, y.options());\n const int threads = 256;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (kernel_size == 2) {\n pool_sum_k2_kernel<<<B, threads, 0, stream>>>(y.data_ptr<float>(), out.data_ptr<float>(), B, N, (float)scale);\n } else {\n pool_sum_generic_kernel<<<B, threads, 0, stream>>>(y.data_ptr<float>(), out.data_ptr<float>(), B, N, (int)kernel_size, (float)scale);\n }\n return out;\n}\n\"\"\"\n\n_pool_sum_ext = load_inline(\n name=\"pool_sum_linear_post_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"pool_sum_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n \"\"\"Faster equivalent: cuBLAS linear followed by a fused CUDA maxpool+sum+scale.\"\"\"\n def __init__(self, in_features, out_features, kernel_size, scale_factor):\n super(ModelNew, self).__init__()\n self.matmul = nn.Linear(in_features, out_features)\n self.kernel_size = int(kernel_size)\n self.scale_factor = float(scale_factor)\n\n def forward(self, x):\n y = F.linear(x, self.matmul.weight, self.matmul.bias)\n return _pool_sum_ext.pool_sum_forward(y, self.kernel_size, self.scale_factor)\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: correctness check did not pass ((0 / 5) trials).
correctness_issue: Output mismatch
max_difference: ['785.948486', '782.778076', '782.372314', '785.258667', '780.138062']
avg_difference: ['765.328247', '763.831909', '764.912231', '764.984009', '764.288025']
final submitted kernel (129 lines, 4,093 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
_cpp_src = r"""
#include <torch/extension.h>
torch::Tensor pool_sum_forward(torch::Tensor y, int64_t kernel_size, double scale);
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>
__global__ void pool_sum_k2_kernel(const float* __restrict__ y,
float* __restrict__ out,
int B, int N, float scale) {
int row = blockIdx.x;
int tid = threadIdx.x;
const float* base = y + ((long long)row) * N;
int pairs = N >> 1;
float acc = 0.0f;
for (int p = tid; p < pairs; p += blockDim.x) {
float a = base[(p << 1)];
float b = base[(p << 1) + 1];
acc += fmaxf(a, b);
}
__shared__ float smem[256];
smem[tid] = acc;
__syncthreads();
// blockDim is launched as 256
if (tid < 128) smem[tid] += smem[tid + 128];
__syncthreads();
if (tid < 64) smem[tid] += smem[tid + 64];
__syncthreads();
if (tid < 32) {
float v = smem[tid];
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);
if (tid == 0) out[row] = v * scale;
}
}
__global__ void pool_sum_generic_kernel(const float* __restrict__ y,
float* __restrict__ out,
int B, int N, int K, float scale) {
int row = blockIdx.x;
int tid = threadIdx.x;
const float* base = y + ((long long)row) * N;
int windows = N / K;
float acc = 0.0f;
for (int w = tid; w < windows; w += blockDim.x) {
const float* ptr = base + ((long long)w) * K;
float m = -FLT_MAX;
for (int j = 0; j < K; ++j) {
m = fmaxf(m, ptr[j]);
}
acc += m;
}
__shared__ float smem[256];
smem[tid] = acc;
__syncthreads();
if (tid < 128) smem[tid] += smem[tid + 128];
__syncthreads();
if (tid < 64) smem[tid] += smem[tid + 64];
__syncthreads();
if (tid < 32) {
float v = smem[tid];
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);
if (tid == 0) out[row] = v * scale;
}
}
torch::Tensor pool_sum_forward(torch::Tensor y, int64_t kernel_size, double scale) {
const int B = (int)y.size(0);
const int N = (int)y.size(1);
auto out = torch::empty({B}, y.options());
const int threads = 256;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
if (kernel_size == 2) {
pool_sum_k2_kernel<<<B, threads, 0, stream>>>(y.data_ptr<float>(), out.data_ptr<float>(), B, N, (float)scale);
} else {
pool_sum_generic_kernel<<<B, threads, 0, stream>>>(y.data_ptr<float>(), out.data_ptr<float>(), B, N, (int)kernel_size, (float)scale);
}
return out;
}
"""
_pool_sum_ext = load_inline(
name="pool_sum_linear_post_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["pool_sum_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
class ModelNew(nn.Module):
"""Faster equivalent: cuBLAS linear followed by a fused CUDA maxpool+sum+scale."""
def __init__(self, in_features, out_features, kernel_size, scale_factor):
super(ModelNew, self).__init__()
self.matmul = nn.Linear(in_features, out_features)
self.kernel_size = int(kernel_size)
self.scale_factor = float(scale_factor)
def forward(self, x):
y = F.linear(x, self.matmul.weight, self.matmul.bias)
return _pool_sum_ext.pool_sum_forward(y, self.kernel_size, self.scale_factor)