compile_fail
2_GraphEdgeSoftmaxCSR.py
started
2026-05-11T09:24:34Z
compile error: Syntax error in custom generated code or ModelNew not found
timingkernelbench.timing
kernel mean / median / std
—
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 0 · FINAL · 1 tool call(s) · 500.8s turn · 18.2s LLM · tokens in=1,327 · out=1,636 · total=3,270 · 7,407 chars (click to expand)
turn 0500.8s turn · 18.2s LLM · 482.6s tools · tokens in=1,327 · out=1,636 · total=3,270 · FINAL
reasoning
The task is to replace the forward computation with a custom CUDA kernel for a row-wise softmax over edge scores in CSR format.
assistant```python
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>
__global__ void sparse_row_softmax_kernel(
const int* __restrict__ row_ptr,
const float* __restrict__ edge_scores,
float* __restrict__ out,
int num_nodes
) {
int node = blockIdx.x;
if (node >= num_nodes) return;
int start = row_ptr[node];
int end = row_ptr[node + 1];
int degree = end - start;
if (degree <= 0) return;
// Each block handles one row; use shared memory for reduction
extern __shared__ float sdata[];
float thread_max = -FLT_MAX;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
float val = edge_scores[start + i];
thread_max = fmaxf(thread_max, val);
}
// Block reduce max
sdata[threadIdx.x] = thread_max;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) {
sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]);
}
__syncthreads();
}
float row_max = sdata[0];
__syncthreads();
float thread_sum = 0.0f;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
float val = expf(edge_scores[start + i] - row_max);
out[start + i] = val; // temporarily store exp
thread_sum += val;
}
sdata[threadIdx.x] = thread_sum;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) {
sdata[threadIdx.x] += sdata[threadIdx.x + s];
}
__syncthreads();
}
float row_sum = sdata[0];
float inv_sum = 1.0f / row_sum;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
out[start + i] *= inv_sum;
}
}
torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {
int num_nodes = row_ptr.size(0) - 1;
auto out = torch::empty_like(edge_scores);
const int threads = 32; // one warp per row
dim3 blocks(num_nodes);
size_t shared_mem = threads * sizeof(float);
sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>(
row_ptr.data_ptr<int>(),
edge_scores.data_ptr<float>(),
out.data_ptr<float>(),
num_nodes
);
return out;
}
'''
cpp_source = '''
torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);
'''
sparse_softmax = load_inline(
name='sparse_softmax',
cpp_sources=[cpp_source],
cuda_sources=[cuda_source],
functions=['sparse_row_softmax_cuda'],
verbose=False,
extra_cuda_cflags=['-O3']
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:
return sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores)
```
This completes the submission.
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n\n__global__ void sparse_row_softmax_kernel(\n const int* __restrict__ row_ptr,\n const float* __restrict__ edge_scores,\n float* __restrict__ out,\n int num_nodes\n) {\n int node = blockIdx.x;\n if (node >= num_nodes) return;\n\n int start = row_ptr[node];\n int end = row_ptr[node + 1];\n int degree = end - start;\n\n if (degree <= 0) return;\n\n // Each block handles one row; use shared memory for reduction\n extern __shared__ float sdata[];\n\n float thread_max = -FLT_MAX;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n float val = edge_scores[start + i];\n thread_max = fmaxf(thread_max, val);\n }\n\n // Block reduce max\n sdata[threadIdx.x] = thread_max;\n __syncthreads();\n\n for (int s = blockDim.x / 2; s > 0; s >>= 1) {\n if (threadIdx.x < s) {\n sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]);\n }\n __syncthreads();\n }\n float row_max = sdata[0];\n __syncthreads();\n\n float thread_sum = 0.0f;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n float val = expf(edge_scores[start + i] - row_max);\n out[start + i] = val; // temporarily store exp\n thread_sum += val;\n }\n\n sdata[threadIdx.x] = thread_sum;\n __syncthreads();\n\n for (int s = blockDim.x / 2; s > 0; s >>= 1) {\n if (threadIdx.x < s) {\n sdata[threadIdx.x] += sdata[threadIdx.x + s];\n }\n __syncthreads();\n }\n float row_sum = sdata[0];\n\n float inv_sum = 1.0f / row_sum;\n for (int i = threadIdx.x; i < degree; i += blockDim.x) {\n out[start + i] *= inv_sum;\n }\n}\n\ntorch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {\n int num_nodes = row_ptr.size(0) - 1;\n auto out = torch::empty_like(edge_scores);\n\n const int threads = 32; // one warp per row\n dim3 blocks(num_nodes);\n\n size_t shared_mem = threads * sizeof(float);\n\n sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>(\n row_ptr.data_ptr<int>(),\n edge_scores.data_ptr<float>(),\n out.data_ptr<float>(),\n num_nodes\n );\n\n return out;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);\n'''\n\nsparse_softmax = load_inline(\n name='sparse_softmax',\n cpp_sources=[cpp_source],\n cuda_sources=[cuda_source],\n functions=['sparse_row_softmax_cuda'],\n verbose=False,\n extra_cuda_cflags=['-O3']\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 sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores)\n```"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: kernel did not compile.
Syntax error in custom generated code or ModelNew not found
final submitted kernel (111 lines, 2,943 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cfloat>
__global__ void sparse_row_softmax_kernel(
const int* __restrict__ row_ptr,
const float* __restrict__ edge_scores,
float* __restrict__ out,
int num_nodes
) {
int node = blockIdx.x;
if (node >= num_nodes) return;
int start = row_ptr[node];
int end = row_ptr[node + 1];
int degree = end - start;
if (degree <= 0) return;
// Each block handles one row; use shared memory for reduction
extern __shared__ float sdata[];
float thread_max = -FLT_MAX;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
float val = edge_scores[start + i];
thread_max = fmaxf(thread_max, val);
}
// Block reduce max
sdata[threadIdx.x] = thread_max;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) {
sdata[threadIdx.x] = fmaxf(sdata[threadIdx.x], sdata[threadIdx.x + s]);
}
__syncthreads();
}
float row_max = sdata[0];
__syncthreads();
float thread_sum = 0.0f;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
float val = expf(edge_scores[start + i] - row_max);
out[start + i] = val; // temporarily store exp
thread_sum += val;
}
sdata[threadIdx.x] = thread_sum;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) {
sdata[threadIdx.x] += sdata[threadIdx.x + s];
}
__syncthreads();
}
float row_sum = sdata[0];
float inv_sum = 1.0f / row_sum;
for (int i = threadIdx.x; i < degree; i += blockDim.x) {
out[start + i] *= inv_sum;
}
}
torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores) {
int num_nodes = row_ptr.size(0) - 1;
auto out = torch::empty_like(edge_scores);
const int threads = 32; // one warp per row
dim3 blocks(num_nodes);
size_t shared_mem = threads * sizeof(float);
sparse_row_softmax_kernel<<<blocks, threads, shared_mem>>>(
row_ptr.data_ptr<int>(),
edge_scores.data_ptr<float>(),
out.data_ptr<float>(),
num_nodes
);
return out;
}
'''
cpp_source = '''
torch::Tensor sparse_row_softmax_cuda(torch::Tensor row_ptr, torch::Tensor edge_scores);
'''
sparse_softmax = load_inline(
name='sparse_softmax',
cpp_sources=[cpp_source],
cuda_sources=[cuda_source],
functions=['sparse_row_softmax_cuda'],
verbose=False,
extra_cuda_cflags=['-O3']
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
def forward(self, row_ptr: torch.Tensor, edge_scores: torch.Tensor) -> torch.Tensor:
return sparse_softmax.sparse_row_softmax_cuda(row_ptr, edge_scores)
```