correct
13_QuantVLA_SelectiveLayoutFusion.py
started
2026-05-05T00:01:55Z
timingkernelbench.timing
kernel mean / median / std
0.04 / — / 9.33e-04 μs
ref mean / median / std
0.10 / — / 0.03 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
10.67x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
# 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).
def _fake_quant_symmetric_int8(x: torch.Tensor, scale: torch.Tensor) -> torch.Tensor:
"""Symmetric int8 fake-quant: round(x/scale) clamped to [-127, 127], times scale."""
q = torch.clamp(torch.round(x / scale), -127.0, 127.0)
return q * scale
class Model(nn.Module):
"""
**QuantVLA selective layout fusion** (reference target for a fused CUDA/Triton kernel).
Vision–language–action stacks often use **token-wise mixed precision**: some
timesteps or modalities tolerate aggressive quantization while others stay in
full precision. This module fuses in **one forward**:
1. **Layout routing** — ``sigmoid(layout_logits)`` yields a per-token mix
coefficient in ``(0, 1)`` (quant vs FP residual).
2. **Quantitative path** — global symmetric **int8-style fake quantization**
(scale from the tensor max, ``/ 127``).
3. **Selective blend** — ``α · x_quant + (1 - α) · x``.
4. **Head** — linear projection on the mixed activations.
This matches a “quantitative selective layout” block: the layout logits (from a
router, modality tags, or calibration) choose how strongly each position uses the
quantized layout vs the identity layout.
"""
def __init__(self, dim: int):
super().__init__()
self.dim = dim
self.out_proj = nn.Linear(dim, dim, bias=True)
def forward(self, x: torch.Tensor, layout_logits: torch.Tensor) -> torch.Tensor:
"""
Args:
x: (B, T, D) VLA token activations (fused modalities).
layout_logits: (B, T) unbounded logits; larger → more mass on quantized path.
Returns:
(B, T, D) updated activations.
"""
B, T, D = x.shape
assert D == self.dim
assert layout_logits.shape == (B, T)
alpha = torch.sigmoid(layout_logits).unsqueeze(-1)
with torch.no_grad():
amax = x.detach().abs().max().clamp(min=1e-8)
scale = amax / 127.0
x_q = _fake_quant_symmetric_int8(x, scale)
mixed = alpha * x_q + (1.0 - alpha) * x
return self.out_proj(mixed)
class ModelNew(nn.Module):
"""KernelBench candidate entry point; default delegates to ``Model``."""
def __init__(self, dim: int):
super().__init__()
self._impl = Model(dim)
def forward(self, x: torch.Tensor, layout_logits: torch.Tensor) -> torch.Tensor:
return self._impl(x, layout_logits)
batch_size = 8
seq_len = 64
dim = 128
def get_inputs():
p = popcorn_pri
x = torch.randn(p.jitter_int(batch_size), p.jitter_int(seq_len), dim)
layout_logits = torch.randn(p.jitter_int(batch_size), p.jitter_int(seq_len))
return [x, layout_logits]
def get_init_inputs():
return [dim]
turn 0 · FINAL · 1 tool call(s) · 40.1s turn · 40.1s LLM · 6,114 chars (click to expand)
turn 040.1s turn · 40.1s LLM · 0.0s tools · FINAL
reasoning
**Examining rounding methods**
I’m looking into the semantics of rounding functions, specifically how torch.round operates. It seems to follow the "round half to even" rule. But I wonder about CUDA's roundf; it appears to round to the nearest integer but always away from zero, or is it strictly rounding halfway away from zero? Hmm, it looks like I need to clarify if PyTorch's torch.round uses nearbyint for this rounding behavior. There's quite a bit of detail in all 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\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor qvla_forward(torch::Tensor x, torch::Tensor layout_logits, 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 <math.h>\n\n__global__ void reduce_absmax_kernel(const float* __restrict__ x, float* __restrict__ out, long long total) {\n extern __shared__ float sdata[];\n int tid = threadIdx.x;\n float m = 0.0f;\n for (long long i = tid; i < total; i += blockDim.x) {\n float v = fabsf(x[i]);\n m = fmaxf(m, v);\n }\n sdata[tid] = m;\n __syncthreads();\n\n for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {\n if (tid < stride) sdata[tid] = fmaxf(sdata[tid], sdata[tid + stride]);\n __syncthreads();\n }\n if (tid == 0) out[0] = fmaxf(sdata[0], 1.0e-8f);\n}\n\n#define TILE 16\n\n__global__ void qvla_linear_kernel(\n const float* __restrict__ x,\n const float* __restrict__ logits,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n const float* __restrict__ amax_ptr,\n float* __restrict__ y,\n int N, int D) {\n\n __shared__ float As[TILE][TILE + 1];\n __shared__ float Bs[TILE][TILE + 1];\n\n int tx = threadIdx.x;\n int ty = threadIdx.y;\n int row = blockIdx.y * TILE + ty;\n int col = blockIdx.x * TILE + tx;\n\n float alpha = 0.0f;\n if (row < N) {\n float l = logits[row];\n alpha = 1.0f / (1.0f + expf(-l));\n }\n\n float scale = (*amax_ptr) * (1.0f / 127.0f);\n float inv_scale = 127.0f / (*amax_ptr);\n float acc = 0.0f;\n\n for (int tile = 0; tile < D; tile += TILE) {\n int ka = tile + tx;\n if (row < N && ka < D) {\n float v = x[row * D + ka];\n float q = nearbyintf(v * inv_scale);\n q = fminf(127.0f, fmaxf(-127.0f, q));\n float qv = q * scale;\n As[ty][tx] = v + alpha * (qv - v);\n } else {\n As[ty][tx] = 0.0f;\n }\n\n int kb = tile + ty;\n if (col < D && kb < D) {\n Bs[ty][tx] = weight[col * D + kb];\n } else {\n Bs[ty][tx] = 0.0f;\n }\n __syncthreads();\n\n #pragma unroll\n for (int k = 0; k < TILE; ++k) {\n acc += As[ty][k] * Bs[k][tx];\n }\n __syncthreads();\n }\n\n if (row < N && col < D) {\n y[row * D + col] = acc + bias[col];\n }\n}\n\ntorch::Tensor qvla_forward(torch::Tensor x, torch::Tensor layout_logits, torch::Tensor weight, torch::Tensor bias) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n auto y = torch::empty_like(x);\n auto tmp = torch::empty({1}, x.options());\n\n const int B = (int)x.size(0);\n const int T = (int)x.size(1);\n const int D = (int)x.size(2);\n const int N = B * T;\n const long long total = (long long)N * (long long)D;\n\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const int rthreads = 256;\n reduce_absmax_kernel<<<1, rthreads, rthreads * sizeof(float), stream>>>(\n x.data_ptr<float>(), tmp.data_ptr<float>(), total);\n\n dim3 block(TILE, TILE);\n dim3 grid((D + TILE - 1) / TILE, (N + TILE - 1) / TILE);\n qvla_linear_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(),\n layout_logits.data_ptr<float>(),\n weight.data_ptr<float>(),\n bias.data_ptr<float>(),\n tmp.data_ptr<float>(),\n y.data_ptr<float>(),\n N, D);\n return y;\n}\n\"\"\"\n\n_qvla_ext = load_inline(\n name=\"qvla_selective_layout_fused_ext\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"qvla_forward\"],\n with_cuda=True,\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int):\n super().__init__()\n self.dim = dim\n self.out_proj = nn.Linear(dim, dim, bias=True)\n\n def forward(self, x: torch.Tensor, layout_logits: torch.Tensor) -> torch.Tensor:\n return _qvla_ext.qvla_forward(x, layout_logits, self.out_proj.weight, self.out_proj.bias)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 0.04 μs
Runtime stats: mean=0.04μs median=?μs std=0.00μs
Numerical precision: max_abs_err=5.96e-07 mean_abs_err=4.37e-08 max_rel_err=8.45e-02
Memory: 33.63 MB peak (ref: 34.38 MB, ratio: 0.9781x)
Kernel launches: 3 (ref: 32, fusion ratio: 10.6667)
SOL score: 0.0717
final submitted kernel (149 lines, 4,215 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 qvla_forward(torch::Tensor x, torch::Tensor layout_logits, 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 <math.h>
__global__ void reduce_absmax_kernel(const float* __restrict__ x, float* __restrict__ out, long long total) {
extern __shared__ float sdata[];
int tid = threadIdx.x;
float m = 0.0f;
for (long long i = tid; i < total; i += blockDim.x) {
float v = fabsf(x[i]);
m = fmaxf(m, v);
}
sdata[tid] = m;
__syncthreads();
for (int stride = blockDim.x >> 1; stride > 0; stride >>= 1) {
if (tid < stride) sdata[tid] = fmaxf(sdata[tid], sdata[tid + stride]);
__syncthreads();
}
if (tid == 0) out[0] = fmaxf(sdata[0], 1.0e-8f);
}
#define TILE 16
__global__ void qvla_linear_kernel(
const float* __restrict__ x,
const float* __restrict__ logits,
const float* __restrict__ weight,
const float* __restrict__ bias,
const float* __restrict__ amax_ptr,
float* __restrict__ y,
int N, int D) {
__shared__ float As[TILE][TILE + 1];
__shared__ float Bs[TILE][TILE + 1];
int tx = threadIdx.x;
int ty = threadIdx.y;
int row = blockIdx.y * TILE + ty;
int col = blockIdx.x * TILE + tx;
float alpha = 0.0f;
if (row < N) {
float l = logits[row];
alpha = 1.0f / (1.0f + expf(-l));
}
float scale = (*amax_ptr) * (1.0f / 127.0f);
float inv_scale = 127.0f / (*amax_ptr);
float acc = 0.0f;
for (int tile = 0; tile < D; tile += TILE) {
int ka = tile + tx;
if (row < N && ka < D) {
float v = x[row * D + ka];
float q = nearbyintf(v * inv_scale);
q = fminf(127.0f, fmaxf(-127.0f, q));
float qv = q * scale;
As[ty][tx] = v + alpha * (qv - v);
} else {
As[ty][tx] = 0.0f;
}
int kb = tile + ty;
if (col < D && kb < D) {
Bs[ty][tx] = weight[col * D + kb];
} else {
Bs[ty][tx] = 0.0f;
}
__syncthreads();
#pragma unroll
for (int k = 0; k < TILE; ++k) {
acc += As[ty][k] * Bs[k][tx];
}
__syncthreads();
}
if (row < N && col < D) {
y[row * D + col] = acc + bias[col];
}
}
torch::Tensor qvla_forward(torch::Tensor x, torch::Tensor layout_logits, torch::Tensor weight, torch::Tensor bias) {
const c10::cuda::CUDAGuard device_guard(x.device());
auto y = torch::empty_like(x);
auto tmp = torch::empty({1}, x.options());
const int B = (int)x.size(0);
const int T = (int)x.size(1);
const int D = (int)x.size(2);
const int N = B * T;
const long long total = (long long)N * (long long)D;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
const int rthreads = 256;
reduce_absmax_kernel<<<1, rthreads, rthreads * sizeof(float), stream>>>(
x.data_ptr<float>(), tmp.data_ptr<float>(), total);
dim3 block(TILE, TILE);
dim3 grid((D + TILE - 1) / TILE, (N + TILE - 1) / TILE);
qvla_linear_kernel<<<grid, block, 0, stream>>>(
x.data_ptr<float>(),
layout_logits.data_ptr<float>(),
weight.data_ptr<float>(),
bias.data_ptr<float>(),
tmp.data_ptr<float>(),
y.data_ptr<float>(),
N, D);
return y;
}
"""
_qvla_ext = load_inline(
name="qvla_selective_layout_fused_ext",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["qvla_forward"],
with_cuda=True,
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3"],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self, dim: int):
super().__init__()
self.dim = dim
self.out_proj = nn.Linear(dim, dim, bias=True)
def forward(self, x: torch.Tensor, layout_logits: torch.Tensor) -> torch.Tensor:
return _qvla_ext.qvla_forward(x, layout_logits, self.out_proj.weight, self.out_proj.bias)