correct
56_Matmul_Sigmoid_Sum.py
started
2026-05-02T06:22:23Z
timingkernelbench.timing
kernel mean / median / std
1.57 / — / 0.01 μs
ref mean / median / std
5.44 / — / 0.21 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
3.50x
energyNVML (pynvml)
ratio (ref / kernel)
3.00x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
3194.56 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 matrix multiplication, applies sigmoid, and sums the result.
"""
def __init__(self, input_size, hidden_size):
super(Model, self).__init__()
self.linear = nn.Linear(input_size, hidden_size)
def forward(self, x):
"""
Args:
x: Input tensor of shape (batch_size, input_size).
Returns:
Output tensor of shape (batch_size, 1).
"""
x = self.linear(x)
x = torch.sigmoid(x)
x = torch.sum(x, dim=1, keepdim=True)
return x
batch_size = 128
input_size = 32768
hidden_size = 32768
def get_inputs():
return [torch.rand(batch_size, input_size)]
def get_init_inputs():
return [input_size, hidden_size]turn 010.6s turn · 10.6s LLM · 0.0s tools
reasoning
**Considering CUDA optimizations**
I'm exploring whether a "custom CUDA kernel" can call torch.mm for efficiency. It could be faster to use cublasSgemm and then apply a custom reduction. The reference already discusses using cuBLAS with a separate sigmoid and sum. If I go straight to using cublas, I might consider a custom fused sigmoid reduction to avoid producing a sigmoid output first. However, it seems I would still need C storage if using cuBLAS.
call → get_gpu_specs
callget_gpu_specs
{}
result ← get_gpu_specs (ok)
okget_gpu_specs
GPU specs for NVIDIA H100 80GB HBM3:
total memory (runtime): 79.1 GB
spec entry: H100
GPU Architecture: Hopper
GPU Memory: 80GB
Memory Bandwidth: 3.35 TB/s
FP64 TFLOPS: 34
FP64 Tensor Core TFLOPS: 67
FP32 TFLOPS: 67
TF32 Tensor Core TFLOPS: 989 with sparsity
BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity
FP16 Tensor Core TFLOPS: 1979 with sparsity
FP8 Tensor Core TFLOPS: 3958 with sparsity
INT8 Tensor Core TOPS: 3958 with sparsity
Register File Size: 64K 32-bit registers per SM
Maximum number of registers per thread: 255
Maximum number of thread blocks per SM: 32
Shared memory capacity per SM: 228 KB
Maximum shared memory per thread block: 227 KB
turn 126.2s turn · 26.2s LLM · 0.0s tools
reasoning
**Evaluating CUDA and Tensor Operations**
I'm considering CUDA sources and if they need to be visible; perhaps I should use C++ sources with declarations. It looks like I need to include definitions in the CUDA source, but I'm uncertain if compile flags need to include `-lcublas`. I'll also look at how to use load_inline with C++ and CUDA sources. For the reduction kernel, I’m estimating my thread and block configuration, and thinking through potential variance in outputs. It looks like I need to test this setup.
call → compile_kernel
callcompile_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>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int M, int N) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n const float* rowptr = tmp + (long long)row * N;\n for (int i = tid; i < N; i += blockDim.x) {\n float z = rowptr[i] + bias[i];\n float s = 1.0f / (1.0f + __expf(-z));\n sum += s;\n }\n // block reduce\n __shared__ float smem[256];\n smem[tid] = sum;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 32; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n if (tid < 32) {\n float v = smem[tid];\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1)\n v += __shfl_down_sync(0xffffffff, v, offset);\n if (tid == 0) out[row] = v;\n }\n}\n\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {\n c10::cuda::CUDAGuard device_guard(x.device());\n const int M = (int)x.size(0);\n const int K = (int)x.size(1);\n const int N = (int)weight.size(0);\n auto tmp = torch::empty({M, N}, x.options());\n auto out = torch::empty({M, 1}, x.options());\n\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n float alpha = 1.0f, beta = 0.0f;\n // Compute tmp(row-major MxN) = x(MxK) * weight^T(KxN).\n // Interpreted column-major: tmp is NxM, x is KxM, weight is KxN; tmp = weight^T * x.\n cublasGemmEx(handle,\n CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), CUDA_R_32F, K,\n x.data_ptr<float>(), CUDA_R_32F, K,\n &beta,\n tmp.data_ptr<float>(), CUDA_R_32F, N,\n CUBLAS_COMPUTE_32F_FAST_TF32,\n CUBLAS_GEMM_DEFAULT_TENSOR_OP);\n\n sigmoid_sum_kernel<<<M, 256, 0, stream>>>(tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(name=\"fused_linear_sigmoid_sum_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_linear_sigmoid_sum\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size):\n super(ModelNew, self).__init__()\n self.linear = nn.Linear(input_size, hidden_size)\n def forward(self, x):\n return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 26.3s turn · 6.3s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int M, int N) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n const float* rowptr = tmp + (long long)row * N;\n for (int i = tid; i < N; i += blockDim.x) {\n float z = rowptr[i] + bias[i];\n float s = 1.0f / (1.0f + __expf(-z));\n sum += s;\n }\n __shared__ float smem[256];\n smem[tid] = sum;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 32; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n if (tid < 32) {\n float v = smem[tid];\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1)\n v += __shfl_down_sync(0xffffffff, v, offset);\n if (tid == 0) out[row] = v;\n }\n}\n\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {\n c10::cuda::CUDAGuard device_guard(x.device());\n const int M = (int)x.size(0);\n const int K = (int)x.size(1);\n const int N = (int)weight.size(0);\n auto tmp = torch::empty({M, N}, x.options());\n auto out = torch::empty({M, 1}, x.options());\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n float alpha = 1.0f, beta = 0.0f;\n cublasGemmEx(handle, CUBLAS_OP_T, CUBLAS_OP_N, N, M, K, &alpha,\n weight.data_ptr<float>(), CUDA_R_32F, K,\n x.data_ptr<float>(), CUDA_R_32F, K, &beta,\n tmp.data_ptr<float>(), CUDA_R_32F, N,\n CUBLAS_COMPUTE_32F_FAST_TF32, CUBLAS_GEMM_DEFAULT_TENSOR_OP);\n sigmoid_sum_kernel<<<M, 256, 0, stream>>>(tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(name=\"fused_linear_sigmoid_sum_ext_v1c\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_linear_sigmoid_sum\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size):\n super(ModelNew, self).__init__()\n self.linear = nn.Linear(input_size, hidden_size)\n def forward(self, x):\n return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)\n"
}
result ← run_correctness (fail)
failrun_correctness
run_correctness FAILED: (0 / 5) trials did not all match.
correctness_issue: Output mismatch
max_difference: ['8207.913086', '8204.604492', '8208.501953', '8209.611328', '8205.103516']
avg_difference: ['8193.007812', '8192.818359', '8192.847656', '8193.498047', '8192.763672']
turn 325.6s turn · 25.6s LLM · 0.0s tools
reasoning
**Examining model outputs**
I'm thinking about the output size and whether it's summing only half of N — like, could that mean N equals the weight size? I'm mulling over the idea of syncing model weights and whether correctness might rely on reference outputs. I wonder if cublas needs to set the pointer mode for the device I'm using. I'll check for errors and add a check with TORCH_CHECK to reveal any correctness issues. It's all very technical!
**Analyzing differences in outputs**
I'm considering if I'm using FAST_TF32 while PyTorch is using full FP32, which might explain some differences, like a small error in the sigmoid sum. I wonder if cublas math might be affecting how I set my dimensions. Testing with torch::matmul could help clarify things, but I’m hesitant about that approach. I should also ponder whether the output shape is a factor or if the hidden size of 16,384 is causing discrepancies. It's all rather complicated!
**Assessing output discrepancies**
I’m wondering if the output mismatch averages around 8192, with a maximum of 8208, might indicate that my output could be zero. If the reference is closer to 8192 and I'm working with a hidden size of 16,384, then my output might be entirely zeros. But wait, if the task specifies a hidden size of 32,768, then the reference should be about 16,384. I need to keep in mind that correctness tools are reporting differences, not specific values. It's a bit confusing!
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,const float* __restrict__ bias,float* __restrict__ out,int M,int N){int row=blockIdx.x,tid=threadIdx.x;float sum=0.f;const float* rowptr=tmp+(long long)row*N;for(int i=tid;i<N;i+=blockDim.x){float z=rowptr[i]+bias[i];sum+=1.f/(1.f+__expf(-z));}__shared__ float smem[256];smem[tid]=sum;__syncthreads();for(int s=128;s>32;s>>=1){if(tid<s)smem[tid]+=smem[tid+s];__syncthreads();}if(tid<32){float v=smem[tid];for(int off=16;off>0;off>>=1)v+=__shfl_down_sync(0xffffffff,v,off);if(tid==0)out[row]=v;}}\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias){c10::cuda::CUDAGuard device_guard(x.device());int M=x.size(0),K=x.size(1),N=weight.size(0);auto tmp=torch::empty({M,N},x.options());auto out=torch::empty({M,1},x.options());cublasHandle_t handle=at::cuda::getCurrentCUDABlasHandle();cudaStream_t stream=at::cuda::getCurrentCUDAStream();cublasSetStream(handle,stream);cublasSetPointerMode(handle,CUBLAS_POINTER_MODE_HOST);float alpha=1.f,beta=0.f;cublasStatus_t st=cublasGemmEx(handle,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&alpha,weight.data_ptr<float>(),CUDA_R_32F,K,x.data_ptr<float>(),CUDA_R_32F,K,&beta,tmp.data_ptr<float>(),CUDA_R_32F,N,CUBLAS_COMPUTE_32F_FAST_TF32,CUBLAS_GEMM_DEFAULT_TENSOR_OP);TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublasGemmEx failed \", (int)st);sigmoid_sum_kernel<<<M,256,0,stream>>>(tmp.data_ptr<float>(),bias.data_ptr<float>(),out.data_ptr<float>(),M,N);C10_CUDA_KERNEL_LAUNCH_CHECK();return out;}\n\"\"\"\n_ext=load_inline(name=\"fused_linear_sigmoid_sum_ext_dbg\",cpp_sources=_cpp_src,cuda_sources=_cuda_src,functions=[\"fused_linear_sigmoid_sum\"],extra_cuda_cflags=[\"-O3\",\"--use_fast_math\"],extra_cflags=[\"-O3\"],extra_ldflags=[\"-lcublas\"],verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,input_size,hidden_size):\n super(ModelNew,self).__init__(); self.linear=nn.Linear(input_size,hidden_size)\n def forward(self,x):\n return _ext.fused_linear_sigmoid_sum(x,self.linear.weight,self.linear.bias)\n"
}
result ← run_correctness (fail)
failrun_correctness
run_correctness FAILED: (0 / 5) trials did not all match.
correctness_issue: Output mismatch
max_difference: ['8207.913086', '8204.604492', '8208.501953', '8209.611328', '8205.103516']
avg_difference: ['8193.007812', '8192.818359', '8192.847656', '8193.498047', '8192.763672']
turn 413.7s turn · 13.7s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src=r\"\"\"#include <torch/extension.h>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\"\"\"\n_cuda_src=r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n__global__ void k(const float* tmp,const float* bias,float* out,int M,int N){int row=blockIdx.x,tid=threadIdx.x;float sum=0;const float* p=tmp+(long long)row*N;for(int i=tid;i<N;i+=blockDim.x)sum+=1.f/(1.f+__expf(-(p[i]+bias[i])));__shared__ float s[256];s[tid]=sum;__syncthreads();for(int d=128;d>0;d>>=1){if(tid<d)s[tid]+=s[tid+d];__syncthreads();}if(tid==0)out[row]=s[0];}\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias){int M=x.size(0),K=x.size(1),N=weight.size(0);auto tmp=torch::empty({M,N},x.options());auto out=torch::empty({M,1},x.options());auto handle=at::cuda::getCurrentCUDABlasHandle();auto stream=at::cuda::getCurrentCUDAStream();cublasSetStream(handle,stream);cublasSetPointerMode(handle,CUBLAS_POINTER_MODE_HOST);float a=1,b=0;auto st=cublasGemmEx(handle,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&a,weight.data_ptr<float>(),CUDA_R_32F,K,x.data_ptr<float>(),CUDA_R_32F,K,&b,tmp.data_ptr<float>(),CUDA_R_32F,N,CUBLAS_COMPUTE_32F_FAST_TF32,CUBLAS_GEMM_DEFAULT_TENSOR_OP);TORCH_CHECK(st==0,\"cublas fail\");k<<<M,256,0,stream>>>(tmp.data_ptr<float>(),bias.data_ptr<float>(),out.data_ptr<float>(),M,N);cudaStreamSynchronize(stream);float h;cudaMemcpy(&h,out.data_ptr<float>(),sizeof(float),cudaMemcpyDeviceToHost);TORCH_CHECK(false,\"dims \",M,\" \",N,\" \",K,\" out0 \",h);return out;}\n\"\"\"\n_ext=load_inline(name=\"dbg_vals_ext\",cpp_sources=_cpp_src,cuda_sources=_cuda_src,functions=[\"fused_linear_sigmoid_sum\"],extra_cuda_cflags=[\"-O3\",\"--use_fast_math\"],extra_ldflags=[\"-lcublas\"],verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,input_size,hidden_size):\n super().__init__(); self.linear=nn.Linear(input_size,hidden_size)\n def forward(self,x): return _ext.fused_linear_sigmoid_sum(x,self.linear.weight,self.linear.bias)\n"
}
result ← run_correctness (fail)
failrun_correctness
run_correctness FAILED: ? trials did not all match.
runtime_error: dims 128 32768 32768 out0 16378.2
turn 516.5s turn · 16.5s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nclass ModelNew(nn.Module):\n def __init__(self,input_size,hidden_size):\n super().__init__(); self.linear=nn.Linear(input_size,hidden_size)\n def forward(self,x):\n return torch.zeros((x.shape[0],1),device=x.device,dtype=x.dtype)\n"
}
result ← run_correctness (fail)
failrun_correctness
run_correctness FAILED: (0 / 5) trials did not all match.
correctness_issue: Output mismatch
max_difference: ['16402.449219', '16395.468750', '16399.783203', '16400.281250', '16396.214844']
avg_difference: ['16381.892578', '16380.684570', '16381.755859', '16382.173828', '16380.912109']
turn 611.0s turn · 11.0s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"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>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int M, int N) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n const float* rowptr = tmp + (long long)row * N;\n for (int i = tid; i < N; i += blockDim.x) {\n float z = rowptr[i] + bias[i];\n sum += 1.0f / (1.0f + __expf(-z));\n }\n __shared__ float smem[256];\n smem[tid] = sum;\n __syncthreads();\n for (int s = 128; s >= 32; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n if (tid < 32) {\n float v = smem[tid];\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1)\n v += __shfl_down_sync(0xffffffff, v, offset);\n if (tid == 0) out[row] = v;\n }\n}\n\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {\n c10::cuda::CUDAGuard device_guard(x.device());\n const int M = (int)x.size(0);\n const int K = (int)x.size(1);\n const int N = (int)weight.size(0);\n auto tmp = torch::empty({M, N}, x.options());\n auto out = torch::empty({M, 1}, x.options());\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_HOST);\n float alpha = 1.0f, beta = 0.0f;\n cublasGemmEx(handle, CUBLAS_OP_T, CUBLAS_OP_N, N, M, K, &alpha,\n weight.data_ptr<float>(), CUDA_R_32F, K,\n x.data_ptr<float>(), CUDA_R_32F, K, &beta,\n tmp.data_ptr<float>(), CUDA_R_32F, N,\n CUBLAS_COMPUTE_32F_FAST_TF32, CUBLAS_GEMM_DEFAULT_TENSOR_OP);\n sigmoid_sum_kernel<<<M, 256, 0, stream>>>(tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(name=\"fused_linear_sigmoid_sum_ext_v2\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_linear_sigmoid_sum\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size):\n super(ModelNew, self).__init__()\n self.linear = nn.Linear(input_size, hidden_size)\n def forward(self, x):\n return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.17e-02 mean_abs_err=2.74e-03 max_rel_err=7.15e-07
turn 712.5s turn · 12.5s LLM · 0.0s tools
reasoning
**Evaluating PyTorch Linear Functionality**
I'm thinking about how PyTorch's linear function might use `addmm` with the bias epilogue. It seems like it could incorporate bias in cuBLASLt. I wonder if the General Matrix Multiply (GEMM) function without bias aligns with that, and if reduction adds bias in a similar way. I’m curious about potential correctness if the input is non-contiguous, but I’m not too worried about it right now. A static check might clarify things.
call → static_check
callstatic_check
{
"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>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int M, int N) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n const float* rowptr = tmp + (long long)row * N;\n for (int i = tid; i < N; i += blockDim.x) {\n float z = rowptr[i] + bias[i];\n sum += 1.0f / (1.0f + __expf(-z));\n }\n __shared__ float smem[256];\n smem[tid] = sum;\n __syncthreads();\n for (int s = 128; s >= 32; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n if (tid < 32) {\n float v = smem[tid];\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1)\n v += __shfl_down_sync(0xffffffff, v, offset);\n if (tid == 0) out[row] = v;\n }\n}\n\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {\n c10::cuda::CUDAGuard device_guard(x.device());\n const int M = (int)x.size(0);\n const int K = (int)x.size(1);\n const int N = (int)weight.size(0);\n auto tmp = torch::empty({M, N}, x.options());\n auto out = torch::empty({M, 1}, x.options());\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_HOST);\n float alpha = 1.0f, beta = 0.0f;\n cublasGemmEx(handle, CUBLAS_OP_T, CUBLAS_OP_N, N, M, K, &alpha,\n weight.data_ptr<float>(), CUDA_R_32F, K,\n x.data_ptr<float>(), CUDA_R_32F, K, &beta,\n tmp.data_ptr<float>(), CUDA_R_32F, N,\n CUBLAS_COMPUTE_32F_FAST_TF32, CUBLAS_GEMM_DEFAULT_TENSOR_OP);\n sigmoid_sum_kernel<<<M, 256, 0, stream>>>(tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(name=\"fused_linear_sigmoid_sum_ext_final\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_linear_sigmoid_sum\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size):\n super(ModelNew, self).__init__()\n self.linear = nn.Linear(input_size, hidden_size)\n def forward(self, x):\n return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)\n"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 814.8s turn · 14.8s 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>\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n\n__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,\n const float* __restrict__ bias,\n float* __restrict__ out,\n int M, int N) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n const float* rowptr = tmp + (long long)row * N;\n\n for (int i = tid; i < N; i += blockDim.x) {\n float z = rowptr[i] + bias[i];\n sum += 1.0f / (1.0f + __expf(-z));\n }\n\n __shared__ float smem[256];\n smem[tid] = sum;\n __syncthreads();\n\n for (int s = 128; s >= 32; s >>= 1) {\n if (tid < s) smem[tid] += smem[tid + s];\n __syncthreads();\n }\n\n if (tid < 32) {\n float v = smem[tid];\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v += __shfl_down_sync(0xffffffff, v, offset);\n }\n if (tid == 0) out[row] = v;\n }\n}\n\ntorch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {\n c10::cuda::CUDAGuard device_guard(x.device());\n\n const int M = (int)x.size(0);\n const int K = (int)x.size(1);\n const int N = (int)weight.size(0);\n\n auto tmp = torch::empty({M, N}, x.options());\n auto out = torch::empty({M, 1}, x.options());\n\n cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_HOST);\n\n float alpha = 1.0f;\n float beta = 0.0f;\n\n // Row-major tmp[M,N] = x[M,K] * weight[N,K]^T.\n // cuBLAS is column-major, so this is C_col[N,M] = weight^T[N,K] * x[K,M].\n cublasGemmEx(handle,\n CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), CUDA_R_32F, K,\n x.data_ptr<float>(), CUDA_R_32F, K,\n &beta,\n tmp.data_ptr<float>(), CUDA_R_32F, N,\n CUBLAS_COMPUTE_32F_FAST_TF32,\n CUBLAS_GEMM_DEFAULT_TENSOR_OP);\n\n sigmoid_sum_kernel<<<M, 256, 0, stream>>>(\n tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);\n\n return out;\n}\n\"\"\"\n\n_ext = load_inline(name=\"fused_linear_sigmoid_sum_ext_submit\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_linear_sigmoid_sum\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n extra_cflags=[\"-O3\"],\n extra_ldflags=[\"-lcublas\"],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size):\n super(ModelNew, self).__init__()\n self.linear = nn.Linear(input_size, hidden_size)\n\n def forward(self, x):\n return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 1.57 μs
Runtime stats: mean=1.57μs median=?μs std=0.01μs
Numerical precision: max_abs_err=1.17e-02 mean_abs_err=2.74e-03 max_rel_err=7.15e-07
Memory: 8257.25 MB peak (ref: 8273.25 MB, ratio: 0.9981x)
Kernel launches: 2 (ref: 7, fusion ratio: 3.5)
Energy: 377.12 mJ/run (ref: 1131.6 mJ, ratio: 3.0006x)
SOL score: 0.9536
final submitted kernel (105 lines, 3,373 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 fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias);
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
__global__ void sigmoid_sum_kernel(const float* __restrict__ tmp,
const float* __restrict__ bias,
float* __restrict__ out,
int M, int N) {
int row = blockIdx.x;
int tid = threadIdx.x;
float sum = 0.0f;
const float* rowptr = tmp + (long long)row * N;
for (int i = tid; i < N; i += blockDim.x) {
float z = rowptr[i] + bias[i];
sum += 1.0f / (1.0f + __expf(-z));
}
__shared__ float smem[256];
smem[tid] = sum;
__syncthreads();
for (int s = 128; s >= 32; s >>= 1) {
if (tid < s) smem[tid] += smem[tid + s];
__syncthreads();
}
if (tid < 32) {
float v = smem[tid];
#pragma unroll
for (int offset = 16; offset > 0; offset >>= 1) {
v += __shfl_down_sync(0xffffffff, v, offset);
}
if (tid == 0) out[row] = v;
}
}
torch::Tensor fused_linear_sigmoid_sum(torch::Tensor x, torch::Tensor weight, torch::Tensor bias) {
c10::cuda::CUDAGuard device_guard(x.device());
const int M = (int)x.size(0);
const int K = (int)x.size(1);
const int N = (int)weight.size(0);
auto tmp = torch::empty({M, N}, x.options());
auto out = torch::empty({M, 1}, x.options());
cublasHandle_t handle = at::cuda::getCurrentCUDABlasHandle();
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
cublasSetStream(handle, stream);
cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_HOST);
float alpha = 1.0f;
float beta = 0.0f;
// Row-major tmp[M,N] = x[M,K] * weight[N,K]^T.
// cuBLAS is column-major, so this is C_col[N,M] = weight^T[N,K] * x[K,M].
cublasGemmEx(handle,
CUBLAS_OP_T, CUBLAS_OP_N,
N, M, K,
&alpha,
weight.data_ptr<float>(), CUDA_R_32F, K,
x.data_ptr<float>(), CUDA_R_32F, K,
&beta,
tmp.data_ptr<float>(), CUDA_R_32F, N,
CUBLAS_COMPUTE_32F_FAST_TF32,
CUBLAS_GEMM_DEFAULT_TENSOR_OP);
sigmoid_sum_kernel<<<M, 256, 0, stream>>>(
tmp.data_ptr<float>(), bias.data_ptr<float>(), out.data_ptr<float>(), M, N);
return out;
}
"""
_ext = load_inline(name="fused_linear_sigmoid_sum_ext_submit",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["fused_linear_sigmoid_sum"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
extra_cflags=["-O3"],
extra_ldflags=["-lcublas"],
verbose=False)
class ModelNew(nn.Module):
def __init__(self, input_size, hidden_size):
super(ModelNew, self).__init__()
self.linear = nn.Linear(input_size, hidden_size)
def forward(self, x):
return _ext.fused_linear_sigmoid_sum(x, self.linear.weight, self.linear.bias)