incorrect
24_LogSoftmax.py
started
2026-05-05T00:34:39Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel mean / median / std
—
ref mean / median / std
8.86 / — / 0.57 μs
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
2775.27 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 LogSoftmax activation.
"""
def __init__(self, dim: int = 1):
super(Model, self).__init__()
self.dim = dim
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Applies LogSoftmax activation to the input tensor.
Args:
x (torch.Tensor): Input tensor of shape (batch_size, dim).
Returns:
torch.Tensor: Output tensor with LogSoftmax applied, same shape as input.
"""
return torch.log_softmax(x, dim=self.dim)
batch_size = 4096
dim = 393216
def get_inputs():
x = torch.rand(batch_size, dim)
return [x]
def get_init_inputs():
return [] # No special initialization inputs neededturn 0 · FINAL · 1 tool call(s) · 21.5s turn · 21.5s LLM · 7,645 chars (click to expand)
turn 021.5s turn · 21.5s LLM · 0.0s tools · FINAL
reasoning
**Optimizing log_softmax calculation**
I need to provide a complete file and optimize the log_softmax for a shape of 4096 x 393216, which totals about 1.6 billion floats—around 6.4 GB for input/output. This seems infeasible! I consider hidden evaluations with the tensor size but aim for faster than PyTorch. The process requires calculating the max and sum for each row. A custom implementation might be necessary, with one tool call. I need to ensure the setup compiles well too.
**Evaluating precision in log_softmax**
I’m considering memory coalescing within rows and whether to use a fast exponential function. I need an accuracy tolerance of 1e-4. The log_softmax function uses expf and logf; maybe __expf could introduce slight errors, but its speed might be beneficial. I need to check error limits for sum computations. It seems I must use expf for safety. I also question the need for benchmarking against PyTorch due to its optimized functions. I can assume inputs to be uniform in [0,1], and I may have to implement a fallback for dimension handling.
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 declaration\ntorch::Tensor logsoftmax_forward_cuda(torch::Tensor x, int64_t dim);\n\n// Host wrapper exposed to Python\ntorch::Tensor logsoftmax_forward(torch::Tensor x, int64_t dim) {\n return logsoftmax_forward_cuda(x, dim);\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 <float.h>\n\n#ifndef WARP_SIZE\n#define WARP_SIZE 32\n#endif\n\ntemplate<int BLOCK>\n__device__ __forceinline__ float block_reduce_max(float v) {\n __shared__ float smem[BLOCK / WARP_SIZE];\n int lane = threadIdx.x & (WARP_SIZE - 1);\n int wid = threadIdx.x >> 5;\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, off));\n if (lane == 0) smem[wid] = v;\n __syncthreads();\n v = (threadIdx.x < (BLOCK / WARP_SIZE)) ? smem[lane] : -FLT_MAX;\n if (wid == 0) {\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, off));\n }\n return __shfl_sync(0xffffffff, v, 0);\n}\n\ntemplate<int BLOCK>\n__device__ __forceinline__ float block_reduce_sum(float v) {\n __shared__ float smem[BLOCK / WARP_SIZE];\n int lane = threadIdx.x & (WARP_SIZE - 1);\n int wid = threadIdx.x >> 5;\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) v += __shfl_down_sync(0xffffffff, v, off);\n if (lane == 0) smem[wid] = v;\n __syncthreads();\n v = (threadIdx.x < (BLOCK / WARP_SIZE)) ? smem[lane] : 0.0f;\n if (wid == 0) {\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) v += __shfl_down_sync(0xffffffff, v, off);\n }\n return __shfl_sync(0xffffffff, v, 0);\n}\n\ntemplate<int BLOCK>\n__global__ void logsoftmax_dim1_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int cols) {\n int row = blockIdx.x;\n if (row >= rows) return;\n const float* __restrict__ xr = x + (long long)row * cols;\n float* __restrict__ yr = y + (long long)row * cols;\n\n float vmax = -FLT_MAX;\n // vector-friendly strided loop. cols is large; use all threads in one CTA per row.\n for (int c = threadIdx.x; c < cols; c += BLOCK) {\n vmax = fmaxf(vmax, xr[c]);\n }\n vmax = block_reduce_max<BLOCK>(vmax);\n\n float sum = 0.0f;\n for (int c = threadIdx.x; c < cols; c += BLOCK) {\n sum += expf(xr[c] - vmax);\n }\n sum = block_reduce_sum<BLOCK>(sum);\n float lsum = logf(sum) + vmax;\n\n for (int c = threadIdx.x; c < cols; c += BLOCK) {\n yr[c] = xr[c] - lsum;\n }\n}\n\n// Special case for dim=0, not expected for the benchmark but implemented for completeness.\ntemplate<int BLOCK>\n__global__ void logsoftmax_dim0_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int cols) {\n int col = blockIdx.x;\n if (col >= cols) return;\n float vmax = -FLT_MAX;\n for (int r = threadIdx.x; r < rows; r += BLOCK) {\n vmax = fmaxf(vmax, x[(long long)r * cols + col]);\n }\n vmax = block_reduce_max<BLOCK>(vmax);\n float sum = 0.0f;\n for (int r = threadIdx.x; r < rows; r += BLOCK) {\n sum += expf(x[(long long)r * cols + col] - vmax);\n }\n sum = block_reduce_sum<BLOCK>(sum);\n float lsum = logf(sum) + vmax;\n for (int r = threadIdx.x; r < rows; r += BLOCK) {\n y[(long long)r * cols + col] = x[(long long)r * cols + col] - lsum;\n }\n}\n\ntorch::Tensor logsoftmax_forward_cuda(torch::Tensor x, int64_t dim) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n TORCH_CHECK(x.dim() == 2, \"only 2D tensors are supported\");\n if (!x.is_contiguous()) x = x.contiguous();\n int64_t nd = x.dim();\n if (dim < 0) dim += nd;\n TORCH_CHECK(dim == 0 || dim == 1, \"dim out of range\");\n auto y = torch::empty_like(x);\n int rows = (int)x.size(0);\n int cols = (int)x.size(1);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n constexpr int BLOCK = 256;\n if (dim == 1) {\n logsoftmax_dim1_kernel<BLOCK><<<rows, BLOCK, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, cols);\n } else {\n logsoftmax_dim0_kernel<BLOCK><<<cols, BLOCK, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, cols);\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"logsoftmax_custom_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"logsoftmax_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Simple model that performs a LogSoftmax activation using a custom CUDA kernel.\n \"\"\"\n def __init__(self, dim: int = 1):\n super(ModelNew, self).__init__()\n self.dim = dim\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.logsoftmax_forward(x, int(self.dim))\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: correctness check did not pass ((0 / 5) trials).
correctness_issue: Output mismatch
max_difference: ['inf', 'inf', 'inf', 'inf', 'inf']
avg_difference: ['inf', 'inf', 'inf', 'inf', 'inf']
final submitted kernel (153 lines, 5,060 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 declaration
torch::Tensor logsoftmax_forward_cuda(torch::Tensor x, int64_t dim);
// Host wrapper exposed to Python
torch::Tensor logsoftmax_forward(torch::Tensor x, int64_t dim) {
return logsoftmax_forward_cuda(x, dim);
}
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <float.h>
#ifndef WARP_SIZE
#define WARP_SIZE 32
#endif
template<int BLOCK>
__device__ __forceinline__ float block_reduce_max(float v) {
__shared__ float smem[BLOCK / WARP_SIZE];
int lane = threadIdx.x & (WARP_SIZE - 1);
int wid = threadIdx.x >> 5;
#pragma unroll
for (int off = 16; off > 0; off >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, off));
if (lane == 0) smem[wid] = v;
__syncthreads();
v = (threadIdx.x < (BLOCK / WARP_SIZE)) ? smem[lane] : -FLT_MAX;
if (wid == 0) {
#pragma unroll
for (int off = 16; off > 0; off >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, off));
}
return __shfl_sync(0xffffffff, v, 0);
}
template<int BLOCK>
__device__ __forceinline__ float block_reduce_sum(float v) {
__shared__ float smem[BLOCK / WARP_SIZE];
int lane = threadIdx.x & (WARP_SIZE - 1);
int wid = threadIdx.x >> 5;
#pragma unroll
for (int off = 16; off > 0; off >>= 1) v += __shfl_down_sync(0xffffffff, v, off);
if (lane == 0) smem[wid] = v;
__syncthreads();
v = (threadIdx.x < (BLOCK / WARP_SIZE)) ? smem[lane] : 0.0f;
if (wid == 0) {
#pragma unroll
for (int off = 16; off > 0; off >>= 1) v += __shfl_down_sync(0xffffffff, v, off);
}
return __shfl_sync(0xffffffff, v, 0);
}
template<int BLOCK>
__global__ void logsoftmax_dim1_kernel(const float* __restrict__ x, float* __restrict__ y,
int rows, int cols) {
int row = blockIdx.x;
if (row >= rows) return;
const float* __restrict__ xr = x + (long long)row * cols;
float* __restrict__ yr = y + (long long)row * cols;
float vmax = -FLT_MAX;
// vector-friendly strided loop. cols is large; use all threads in one CTA per row.
for (int c = threadIdx.x; c < cols; c += BLOCK) {
vmax = fmaxf(vmax, xr[c]);
}
vmax = block_reduce_max<BLOCK>(vmax);
float sum = 0.0f;
for (int c = threadIdx.x; c < cols; c += BLOCK) {
sum += expf(xr[c] - vmax);
}
sum = block_reduce_sum<BLOCK>(sum);
float lsum = logf(sum) + vmax;
for (int c = threadIdx.x; c < cols; c += BLOCK) {
yr[c] = xr[c] - lsum;
}
}
// Special case for dim=0, not expected for the benchmark but implemented for completeness.
template<int BLOCK>
__global__ void logsoftmax_dim0_kernel(const float* __restrict__ x, float* __restrict__ y,
int rows, int cols) {
int col = blockIdx.x;
if (col >= cols) return;
float vmax = -FLT_MAX;
for (int r = threadIdx.x; r < rows; r += BLOCK) {
vmax = fmaxf(vmax, x[(long long)r * cols + col]);
}
vmax = block_reduce_max<BLOCK>(vmax);
float sum = 0.0f;
for (int r = threadIdx.x; r < rows; r += BLOCK) {
sum += expf(x[(long long)r * cols + col] - vmax);
}
sum = block_reduce_sum<BLOCK>(sum);
float lsum = logf(sum) + vmax;
for (int r = threadIdx.x; r < rows; r += BLOCK) {
y[(long long)r * cols + col] = x[(long long)r * cols + col] - lsum;
}
}
torch::Tensor logsoftmax_forward_cuda(torch::Tensor x, int64_t dim) {
TORCH_CHECK(x.is_cuda(), "x must be CUDA");
TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 is supported");
TORCH_CHECK(x.dim() == 2, "only 2D tensors are supported");
if (!x.is_contiguous()) x = x.contiguous();
int64_t nd = x.dim();
if (dim < 0) dim += nd;
TORCH_CHECK(dim == 0 || dim == 1, "dim out of range");
auto y = torch::empty_like(x);
int rows = (int)x.size(0);
int cols = (int)x.size(1);
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
constexpr int BLOCK = 256;
if (dim == 1) {
logsoftmax_dim1_kernel<BLOCK><<<rows, BLOCK, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, cols);
} else {
logsoftmax_dim0_kernel<BLOCK><<<cols, BLOCK, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, cols);
}
return y;
}
"""
_ext = load_inline(
name="logsoftmax_custom_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["logsoftmax_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
class ModelNew(nn.Module):
"""
Simple model that performs a LogSoftmax activation using a custom CUDA kernel.
"""
def __init__(self, dim: int = 1):
super(ModelNew, self).__init__()
self.dim = dim
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.logsoftmax_forward(x, int(self.dim))