correct
39_Fused1DTemporalConvolution.py
started
2026-05-05T01:12:32Z
timingkernelbench.timing
kernel mean / median / std
0.11 / — / 5.81e-04 μs
ref mean / median / std
0.08 / — / 0.00 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
2.88x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
789.61 GB/s
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F
# Default ModelNew is PyTorch-only. run_and_check: use check_kernel=False with backend=cuda
# until the candidate file contains a real CUDA kernel (see kernel_static_checker).
class Model(nn.Module):
"""
**Fused depthwise–pointwise 1D temporal convolution** on ``(B, C, T)`` sequences.
Fuses a **temporal depthwise** ``k``-tap conv (per-channel along time) with
**SiLU** and a **pointwise** ``1×1`` mix—standard in temporal encoders for
proprio, audio, or token-wise time series in robotics / VLA backbones.
Padding uses dilated effective radius so length is unchanged for odd
``kernel_size``.
"""
def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: int,
dilation: int = 1,
):
super().__init__()
assert kernel_size % 2 == 1, "odd kernel_size keeps T unchanged with symmetric padding"
assert dilation >= 1
self.padding = ((kernel_size - 1) * dilation) // 2
self.dw = nn.Conv1d(
in_channels,
in_channels,
kernel_size,
padding=self.padding,
dilation=dilation,
groups=in_channels,
bias=False,
)
self.pw = nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=False)
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, C_in, T) temporal features.
Returns:
(B, C_out, T)
"""
x = self.dw(x)
x = F.silu(x)
return self.pw(x)
class ModelNew(nn.Module):
"""KernelBench candidate entry point; default delegates to ``Model``."""
def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: int,
dilation: int = 1,
):
super().__init__()
self._impl = Model(in_channels, out_channels, kernel_size, dilation=dilation)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self._impl(x)
batch_size = 16
in_channels = 128
out_channels = 128
kernel_size = 5
dilation = 2
seq_len = 2048
def get_inputs():
p = popcorn_pri
x = torch.randn(p.jitter_int(batch_size), in_channels, p.jitter_int(seq_len))
return [x]
def get_init_inputs():
return [in_channels, out_channels, kernel_size, dilation]
turn 0 · FINAL · 1 tool call(s) · 45.5s turn · 45.5s LLM · 6,135 chars (click to expand)
turn 045.5s turn · 45.5s LLM · 0.0s tools · FINAL
reasoning
**Considering function calls and optimization**
I’m looking at whether I should call x.contiguous() to check if it returns the same object. I need to ensure weights are contiguous but not call for weights unnecessarily. The functions list contains ["fused_dw_silu_pw_cuda"], and the Python module should match that. I’m also contemplating whether to set verbose to false and considering potential compile issues with multiple instantiations. I could use unique names with load_inline and set the options for CUDA to improve performance, balancing accuracy with speed.
**Finalizing PYBIND Submission**
I'm working on the generated PYBIND, which will be in a CPP file that includes the CPP sources. It will call `m.def("fused_dw_silu_pw_cuda", torch::wrap_pybind_function(fused_dw_silu_pw_cuda), "...");`. So, I think the declaration is enough, but I need to make sure there isn’t any custom PYBIND. Alright, I’ll go ahead and submit it!
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor fused_dw_silu_pw_cuda(torch::Tensor x,\n torch::Tensor dw_w,\n torch::Tensor pw_w,\n int64_t dilation,\n int64_t padding);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void dw_silu_kernel(const float* __restrict__ x,\n const float* __restrict__ dw,\n float* __restrict__ tmp,\n int B, int C, int T, int K, int dilation, int padding) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int n = B * T * C;\n if (idx >= n) return;\n\n int c = idx % C;\n int m = idx / C; // m = b*T + t\n int t = m % T;\n int b = m / T;\n\n float acc = 0.0f;\n const float* xbc = x + ((b * C + c) * T);\n const float* dwc = dw + c * K;\n\n // K is 5 for the benchmark, but keep the loop generic.\n #pragma unroll\n for (int k = 0; k < 16; ++k) {\n if (k >= K) break;\n int tt = t + k * dilation - padding;\n if ((unsigned)tt < (unsigned)T) {\n acc += xbc[tt] * dwc[k];\n }\n }\n\n // SiLU: x * sigmoid(x)\n float sig = 1.0f / (1.0f + expf(-acc));\n tmp[idx] = acc * sig;\n}\n\ntorch::Tensor fused_dw_silu_pw_cuda(torch::Tensor x,\n torch::Tensor dw_w,\n torch::Tensor pw_w,\n int64_t dilation,\n int64_t padding) {\n const int B = (int)x.size(0);\n const int C = (int)x.size(1);\n const int T = (int)x.size(2);\n const int K = (int)dw_w.size(2);\n const int O = (int)pw_w.size(0);\n\n // Intermediate is laid out as (B*T, C), directly consumable by GEMM.\n auto tmp = torch::empty({(int64_t)B * T, C}, x.options());\n\n const int threads = 256;\n const int total = B * T * C;\n const int blocks = (total + threads - 1) / threads;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n dw_silu_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), dw_w.data_ptr<float>(), tmp.data_ptr<float>(),\n B, C, T, K, (int)dilation, (int)padding);\n\n // Pointwise conv is a matrix multiply: (B*T,C) x (C,O).\n auto pw2 = pw_w.view({O, C}).transpose(0, 1);\n auto out2 = at::mm(tmp, pw2);\n\n // Return logical (B,O,T) without a physical transpose/copy.\n return out2.view({B, T, O}).permute({0, 2, 1});\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"fused_dw_silu_pw1d_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_dw_silu_pw_cuda\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n with_cuda=True,\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(\n self,\n in_channels: int,\n out_channels: int,\n kernel_size: int,\n dilation: int = 1,\n ):\n super().__init__()\n assert kernel_size % 2 == 1, \"odd kernel_size keeps T unchanged with symmetric padding\"\n assert dilation >= 1\n self.padding = ((kernel_size - 1) * dilation) // 2\n self.dilation = dilation\n self.dw = nn.Conv1d(\n in_channels,\n in_channels,\n kernel_size,\n padding=self.padding,\n dilation=dilation,\n groups=in_channels,\n bias=False,\n )\n self.pw = nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=False)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.fused_dw_silu_pw_cuda(x.contiguous(), self.dw.weight, self.pw.weight, self.dilation, self.padding)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 0.11 μs
Runtime stats: mean=0.11μs median=?μs std=0.00μs
Numerical precision: max_abs_err=8.62e-05 mean_abs_err=2.64e-08 max_rel_err=9.91e+00
Memory: 81.13 MB peak (ref: 81.13 MB, ratio: 1.0x)
Kernel launches: 8 (ref: 23, fusion ratio: 2.875)
SOL score: 0.6789
final submitted kernel (124 lines, 3,895 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_dw_silu_pw_cuda(torch::Tensor x,
torch::Tensor dw_w,
torch::Tensor pw_w,
int64_t dilation,
int64_t padding);
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/ATen.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
__global__ void dw_silu_kernel(const float* __restrict__ x,
const float* __restrict__ dw,
float* __restrict__ tmp,
int B, int C, int T, int K, int dilation, int padding) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int n = B * T * C;
if (idx >= n) return;
int c = idx % C;
int m = idx / C; // m = b*T + t
int t = m % T;
int b = m / T;
float acc = 0.0f;
const float* xbc = x + ((b * C + c) * T);
const float* dwc = dw + c * K;
// K is 5 for the benchmark, but keep the loop generic.
#pragma unroll
for (int k = 0; k < 16; ++k) {
if (k >= K) break;
int tt = t + k * dilation - padding;
if ((unsigned)tt < (unsigned)T) {
acc += xbc[tt] * dwc[k];
}
}
// SiLU: x * sigmoid(x)
float sig = 1.0f / (1.0f + expf(-acc));
tmp[idx] = acc * sig;
}
torch::Tensor fused_dw_silu_pw_cuda(torch::Tensor x,
torch::Tensor dw_w,
torch::Tensor pw_w,
int64_t dilation,
int64_t padding) {
const int B = (int)x.size(0);
const int C = (int)x.size(1);
const int T = (int)x.size(2);
const int K = (int)dw_w.size(2);
const int O = (int)pw_w.size(0);
// Intermediate is laid out as (B*T, C), directly consumable by GEMM.
auto tmp = torch::empty({(int64_t)B * T, C}, x.options());
const int threads = 256;
const int total = B * T * C;
const int blocks = (total + threads - 1) / threads;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
dw_silu_kernel<<<blocks, threads, 0, stream>>>(
x.data_ptr<float>(), dw_w.data_ptr<float>(), tmp.data_ptr<float>(),
B, C, T, K, (int)dilation, (int)padding);
// Pointwise conv is a matrix multiply: (B*T,C) x (C,O).
auto pw2 = pw_w.view({O, C}).transpose(0, 1);
auto out2 = at::mm(tmp, pw2);
// Return logical (B,O,T) without a physical transpose/copy.
return out2.view({B, T, O}).permute({0, 2, 1});
}
"""
_ext = load_inline(
name="fused_dw_silu_pw1d_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["fused_dw_silu_pw_cuda"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3"],
with_cuda=True,
verbose=False,
)
class ModelNew(nn.Module):
def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: int,
dilation: int = 1,
):
super().__init__()
assert kernel_size % 2 == 1, "odd kernel_size keeps T unchanged with symmetric padding"
assert dilation >= 1
self.padding = ((kernel_size - 1) * dilation) // 2
self.dilation = dilation
self.dw = nn.Conv1d(
in_channels,
in_channels,
kernel_size,
padding=self.padding,
dilation=dilation,
groups=in_channels,
bias=False,
)
self.pw = nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=False)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return _ext.fused_dw_silu_pw_cuda(x.contiguous(), self.dw.weight, self.pw.weight, self.dilation, self.padding)