incorrect
2_GraphEdgeSoftmaxCSR.py
started
2026-05-05T00:07:51Z
correctness issue:
timingkernelbench.timing
kernel mean / median / std
—
ref mean / median / std
19.50 / — / 0.38 μs
roofline / occupancynsight_hardware_counters
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Row-wise softmax over edge scores stored in CSR format.
This is a core primitive in graph attention networks and sparse attention on
irregular neighborhoods. Each node owns a contiguous edge segment in
`edge_scores[row_ptr[i]:row_ptr[i + 1]]`, and the kernel normalizes scores
independently within each segment.
"""
def __init__(self):
super().__init__()
def forward(
self,
row_ptr: torch.Tensor,
edge_scores: torch.Tensor,
) -> torch.Tensor:
"""
Args:
row_ptr: (num_nodes + 1,) CSR row offsets
edge_scores: (num_edges,) unnormalized attention logits
Returns:
(num_edges,) softmax-normalized edge weights per source node
"""
num_nodes = row_ptr.numel() - 1
out = torch.empty_like(edge_scores)
for node in range(num_nodes):
start = int(row_ptr[node].item())
end = int(row_ptr[node + 1].item())
if end > start:
out[start:end] = torch.softmax(edge_scores[start:end], dim=0)
return out
num_nodes = 512
avg_degree = 24
batchless_num_edges = num_nodes * avg_degree
def _make_row_ptr(num_nodes: int, avg_degree: int) -> torch.Tensor:
base = torch.full((num_nodes,), avg_degree, dtype=torch.int32)
return row_ptr
def get_inputs():
return list(popcorn_pri.make_csr_scalar_edge_scores(num_nodes, avg_degree))
def get_init_inputs():
return []
turn 017.0s turn · 17.0s 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\n// CUDA launcher implemented in cuda source\ntorch::Tensor csr_softmax_forward_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);\n\ntorch::Tensor csr_softmax_forward(torch::Tensor row_ptr, torch::Tensor edge_scores) {\n return csr_softmax_forward_cuda(row_ptr, edge_scores);\n}\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__device__ __forceinline__ float warp_reduce_max(float v) {\n unsigned mask = 0xffffffffu;\n v = fmaxf(v, __shfl_down_sync(mask, v, 16));\n v = fmaxf(v, __shfl_down_sync(mask, v, 8));\n v = fmaxf(v, __shfl_down_sync(mask, v, 4));\n v = fmaxf(v, __shfl_down_sync(mask, v, 2));\n v = fmaxf(v, __shfl_down_sync(mask, v, 1));\n return v;\n}\n\n__device__ __forceinline__ float warp_reduce_sum(float v) {\n unsigned mask = 0xffffffffu;\n v += __shfl_down_sync(mask, v, 16);\n v += __shfl_down_sync(mask, v, 8);\n v += __shfl_down_sync(mask, v, 4);\n v += __shfl_down_sync(mask, v, 2);\n v += __shfl_down_sync(mask, v, 1);\n return v;\n}\n\ntemplate<int WARPS_PER_BLOCK>\n__global__ void csr_softmax_warp_kernel(const int* __restrict__ row_ptr,\n const float* __restrict__ scores,\n float* __restrict__ out,\n int num_nodes) {\n int tid = threadIdx.x;\n int lane = tid & 31;\n int warp = tid >> 5;\n int row = blockIdx.x * WARPS_PER_BLOCK + warp;\n if (row >= num_nodes) return;\n\n int start = row_ptr[row];\n int end = row_ptr[row + 1];\n int n = end - start;\n if (n <= 0) return;\n\n float m = -FLT_MAX;\n for (int i = lane; i < n; i += 32) {\n m = fmaxf(m, scores[start + i]);\n }\n m = warp_reduce_max(m);\n\n float s = 0.0f;\n for (int i = lane; i < n; i += 32) {\n s += __expf(scores[start + i] - m);\n }\n s = warp_reduce_sum(s);\n float inv_s = 1.0f / s;\n\n for (int i = lane; i < n; i += 32) {\n out[start + i] = __expf(scores[start + i] - m) * inv_s;\n }\n}\n\ntorch::Tensor csr_softmax_forward_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {\n auto out = torch::empty_like(edge_scores);\n int num_nodes = (int)row_ptr.numel() - 1;\n if (num_nodes <= 0 || edge_scores.numel() == 0) return out;\n\n const int warps = 4;\n dim3 block(32 * warps);\n dim3 grid((num_nodes + warps - 1) / warps);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n csr_softmax_warp_kernel<warps><<<grid, block, 0, stream>>>(\n row_ptr.data_ptr<int>(), edge_scores.data_ptr<float>(), out.data_ptr<float>(), num_nodes);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"csr_row_softmax_ext_v1\",\n cpp_sources=[_cpp_src],\n cuda_sources=[_cuda_src],\n functions=[\"csr_softmax_forward\"],\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):\n super().__init__()\n\n def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:\n return _ext.csr_softmax_forward(row_ptr, edge_scores)\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: correctness check did not pass (? trials).
runtime_error: expected scalar type Int but found Float
final submitted kernel (109 lines, 3,294 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>
// CUDA launcher implemented in cuda source
torch::Tensor csr_softmax_forward_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);
torch::Tensor csr_softmax_forward(torch::Tensor row_ptr, torch::Tensor edge_scores) {
return csr_softmax_forward_cuda(row_ptr, edge_scores);
}
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>
__device__ __forceinline__ float warp_reduce_max(float v) {
unsigned mask = 0xffffffffu;
v = fmaxf(v, __shfl_down_sync(mask, v, 16));
v = fmaxf(v, __shfl_down_sync(mask, v, 8));
v = fmaxf(v, __shfl_down_sync(mask, v, 4));
v = fmaxf(v, __shfl_down_sync(mask, v, 2));
v = fmaxf(v, __shfl_down_sync(mask, v, 1));
return v;
}
__device__ __forceinline__ float warp_reduce_sum(float v) {
unsigned mask = 0xffffffffu;
v += __shfl_down_sync(mask, v, 16);
v += __shfl_down_sync(mask, v, 8);
v += __shfl_down_sync(mask, v, 4);
v += __shfl_down_sync(mask, v, 2);
v += __shfl_down_sync(mask, v, 1);
return v;
}
template<int WARPS_PER_BLOCK>
__global__ void csr_softmax_warp_kernel(const int* __restrict__ row_ptr,
const float* __restrict__ scores,
float* __restrict__ out,
int num_nodes) {
int tid = threadIdx.x;
int lane = tid & 31;
int warp = tid >> 5;
int row = blockIdx.x * WARPS_PER_BLOCK + warp;
if (row >= num_nodes) return;
int start = row_ptr[row];
int end = row_ptr[row + 1];
int n = end - start;
if (n <= 0) return;
float m = -FLT_MAX;
for (int i = lane; i < n; i += 32) {
m = fmaxf(m, scores[start + i]);
}
m = warp_reduce_max(m);
float s = 0.0f;
for (int i = lane; i < n; i += 32) {
s += __expf(scores[start + i] - m);
}
s = warp_reduce_sum(s);
float inv_s = 1.0f / s;
for (int i = lane; i < n; i += 32) {
out[start + i] = __expf(scores[start + i] - m) * inv_s;
}
}
torch::Tensor csr_softmax_forward_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {
auto out = torch::empty_like(edge_scores);
int num_nodes = (int)row_ptr.numel() - 1;
if (num_nodes <= 0 || edge_scores.numel() == 0) return out;
const int warps = 4;
dim3 block(32 * warps);
dim3 grid((num_nodes + warps - 1) / warps);
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
csr_softmax_warp_kernel<warps><<<grid, block, 0, stream>>>(
row_ptr.data_ptr<int>(), edge_scores.data_ptr<float>(), out.data_ptr<float>(), num_nodes);
return out;
}
"""
_ext = load_inline(
name="csr_row_softmax_ext_v1",
cpp_sources=[_cpp_src],
cuda_sources=[_cuda_src],
functions=["csr_softmax_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:
return _ext.csr_softmax_forward(row_ptr, edge_scores)