correct
21_Sigmoid.py
started
2026-05-05T00:25:19Z
timingkernelbench.timing
kernel mean / median / std
4.81 / — / 0.71 μs
ref mean / median / std
4.32 / — / 0.28 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
0.50x
energyNVML (pynvml)
ratio (ref / kernel)
1.67x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
2837.29 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 Sigmoid activation.
"""
def __init__(self):
super(Model, self).__init__()
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Applies Sigmoid activation to the input tensor.
Args:
x (torch.Tensor): Input tensor of any shape.
Returns:
torch.Tensor: Output tensor with Sigmoid applied, same shape as input.
"""
return torch.sigmoid(x)
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) · 33.5s turn · 33.5s LLM · 6,331 chars (click to expand)
turn 033.5s turn · 33.5s LLM · 0.0s tools · FINAL
reasoning
**Calculating polynomial match**
I need to match within a tolerance of 1e-4. For the sigmoid approximation, I’m considering a polynomial of degree 5. When I compute the value at 1, I find an error that’s too high, so I adjust it and see that a degree 7 polynomial works well within my specified range. If x goes outside the range, maybe I could implement a separate approach. I want to ensure efficiency using FP32 tolerance and potentially faster calculations with degree 7.
**Verifying alignment**
I’m checking the alignment for a contiguous allocation with the torch library. I need to confirm if n is divisible by 4. Specifically, I'm looking at 4096 multiplied by 393216 to see if that’s also divisible by 4. If it is, I might want to proceed with a vectorized kernel for n4. This should help ensure everything runs smoothly, maximizing efficiency in the process!
**Evaluating a sigmoid implementation**
I'm considering the potential for using `torch.sigmoid` with `exp`, but I wonder if there's a memory bandwidth issue. My polynomial might be faster, but I think I have to check if the implementation works correctly when I use random values. Maybe `torch.rand` could come into play for those scenarios? It's an interesting challenge to optimize while ensuring accuracy. Let me mull over how to approach this!
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\ntorch::Tensor sigmoid_forward_cuda(torch::Tensor x);\n\ntorch::Tensor sigmoid_forward(torch::Tensor x) {\n return sigmoid_forward_cuda(x);\n}\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <stdint.h>\n\nstatic __forceinline__ __device__ float sigmoid_poly_or_exp(float x) {\n // For the benchmark inputs (torch.rand -> [0,1)) this degree-7 Taylor\n // polynomial is within ~2e-5 of the correctly rounded sigmoid, and avoids\n // the expensive exponential. The fallback keeps the operator accurate for\n // more general values.\n if (x >= -1.0f && x <= 1.0f) {\n float x2 = x * x;\n float p = -2.1081349206349206e-4f; // -17/80640\n p = fmaf(p, x2, 2.0833333333333333e-3f); // 1/480\n p = fmaf(p, x2, -2.0833333333333332e-2f);// -1/48\n p = fmaf(p, x2, 2.5e-1f); // 1/4\n return fmaf(p, x, 5.0e-1f); // 1/2 + x*p\n } else {\n return 1.0f / (1.0f + __expf(-x));\n }\n}\n\n__global__ void sigmoid_vec4_kernel(const float4* __restrict__ x,\n float4* __restrict__ y,\n uint64_t n4) {\n uint64_t tid = (uint64_t)blockIdx.x * blockDim.x + threadIdx.x;\n uint64_t stride = (uint64_t)blockDim.x * gridDim.x;\n for (uint64_t i = tid; i < n4; i += stride) {\n float4 v = x[i];\n float4 o;\n o.x = sigmoid_poly_or_exp(v.x);\n o.y = sigmoid_poly_or_exp(v.y);\n o.z = sigmoid_poly_or_exp(v.z);\n o.w = sigmoid_poly_or_exp(v.w);\n y[i] = o;\n }\n}\n\n__global__ void sigmoid_tail_kernel(const float* __restrict__ x,\n float* __restrict__ y,\n uint64_t start,\n uint64_t n) {\n uint64_t i = start + (uint64_t)blockIdx.x * blockDim.x + threadIdx.x;\n if (i < n) y[i] = sigmoid_poly_or_exp(x[i]);\n}\n\ntorch::Tensor sigmoid_forward_cuda(torch::Tensor x) {\n auto y = torch::empty_like(x);\n const uint64_t n = (uint64_t)x.numel();\n if (n == 0) return y;\n\n const int threads = 256;\n static int sm_count = 0;\n if (sm_count == 0) {\n int dev = 0;\n cudaGetDevice(&dev);\n cudaDeviceProp prop;\n cudaGetDeviceProperties(&prop, dev);\n sm_count = prop.multiProcessorCount;\n if (sm_count <= 0) sm_count = 108;\n }\n\n const float* xp = x.data_ptr<float>();\n float* yp = y.data_ptr<float>();\n\n uint64_t n4 = n >> 2;\n if (n4) {\n int blocks = sm_count * 8;\n uint64_t need = (n4 + threads - 1) / threads;\n if ((uint64_t)blocks > need) blocks = (int)need;\n sigmoid_vec4_kernel<<<blocks, threads>>>(reinterpret_cast<const float4*>(xp),\n reinterpret_cast<float4*>(yp), n4);\n }\n uint64_t start = n4 << 2;\n if (start < n) {\n int blocks = (int)((n - start + threads - 1) / threads);\n sigmoid_tail_kernel<<<blocks, threads>>>(xp, yp, start, n);\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"sigmoid_fast_poly_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"sigmoid_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super(ModelNew, self).__init__()\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.sigmoid_forward(x)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 4.81 μs
Runtime stats: mean=4.81μs median=?μs std=0.71μs
Numerical precision: max_abs_err=1.94e-05 mean_abs_err=1.97e-06 max_rel_err=2.66e-05
Memory: 12321.0 MB peak (ref: 12321.0 MB, ratio: 1.0x)
Kernel launches: 2 (ref: 1, fusion ratio: 0.5)
Energy: 726.22 mJ/run (ref: 1210.48 mJ, ratio: 1.6668x)
SOL score: 0.847
final submitted kernel (114 lines, 3,623 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 sigmoid_forward_cuda(torch::Tensor x);
torch::Tensor sigmoid_forward(torch::Tensor x) {
return sigmoid_forward_cuda(x);
}
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <stdint.h>
static __forceinline__ __device__ float sigmoid_poly_or_exp(float x) {
// For the benchmark inputs (torch.rand -> [0,1)) this degree-7 Taylor
// polynomial is within ~2e-5 of the correctly rounded sigmoid, and avoids
// the expensive exponential. The fallback keeps the operator accurate for
// more general values.
if (x >= -1.0f && x <= 1.0f) {
float x2 = x * x;
float p = -2.1081349206349206e-4f; // -17/80640
p = fmaf(p, x2, 2.0833333333333333e-3f); // 1/480
p = fmaf(p, x2, -2.0833333333333332e-2f);// -1/48
p = fmaf(p, x2, 2.5e-1f); // 1/4
return fmaf(p, x, 5.0e-1f); // 1/2 + x*p
} else {
return 1.0f / (1.0f + __expf(-x));
}
}
__global__ void sigmoid_vec4_kernel(const float4* __restrict__ x,
float4* __restrict__ y,
uint64_t n4) {
uint64_t tid = (uint64_t)blockIdx.x * blockDim.x + threadIdx.x;
uint64_t stride = (uint64_t)blockDim.x * gridDim.x;
for (uint64_t i = tid; i < n4; i += stride) {
float4 v = x[i];
float4 o;
o.x = sigmoid_poly_or_exp(v.x);
o.y = sigmoid_poly_or_exp(v.y);
o.z = sigmoid_poly_or_exp(v.z);
o.w = sigmoid_poly_or_exp(v.w);
y[i] = o;
}
}
__global__ void sigmoid_tail_kernel(const float* __restrict__ x,
float* __restrict__ y,
uint64_t start,
uint64_t n) {
uint64_t i = start + (uint64_t)blockIdx.x * blockDim.x + threadIdx.x;
if (i < n) y[i] = sigmoid_poly_or_exp(x[i]);
}
torch::Tensor sigmoid_forward_cuda(torch::Tensor x) {
auto y = torch::empty_like(x);
const uint64_t n = (uint64_t)x.numel();
if (n == 0) return y;
const int threads = 256;
static int sm_count = 0;
if (sm_count == 0) {
int dev = 0;
cudaGetDevice(&dev);
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, dev);
sm_count = prop.multiProcessorCount;
if (sm_count <= 0) sm_count = 108;
}
const float* xp = x.data_ptr<float>();
float* yp = y.data_ptr<float>();
uint64_t n4 = n >> 2;
if (n4) {
int blocks = sm_count * 8;
uint64_t need = (n4 + threads - 1) / threads;
if ((uint64_t)blocks > need) blocks = (int)need;
sigmoid_vec4_kernel<<<blocks, threads>>>(reinterpret_cast<const float4*>(xp),
reinterpret_cast<float4*>(yp), n4);
}
uint64_t start = n4 << 2;
if (start < n) {
int blocks = (int)((n - start + threads - 1) / threads);
sigmoid_tail_kernel<<<blocks, threads>>>(xp, yp, start, n);
}
return y;
}
"""
_ext = load_inline(
name="sigmoid_fast_poly_ext",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["sigmoid_forward"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self):
super(ModelNew, self).__init__()
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.sigmoid_forward(x)