gpt-5.5-priority · popcorn · l123_single_gpt
correct 13_QuantVLA_SelectiveLayoutFusion.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.04 μs
ref runtime
0.10 μs
speedup
2.42x
started
2026-05-05T00:01:55Z
timingkernelbench.timing
kernel runtime
0.04 μs
ref runtime
0.10 μs
speedup
2.42x
kernel mean / median / std
0.04 / — / 9.33e-04 μs
ref mean / median / std
0.10 / — / 0.03 μs
numerical precisioneval_kernel_against_ref
max abs error
5.96e-07
mean abs error
4.37e-08
max rel error
0.08
mean rel error
9.96e-07
gpu memoryextended_metrics.measure_memory
kernel peak
33.63 MB
ref peak
34.38 MB
kernel / ref
0.98x
kernel launches / fusiontorch.profiler
kernel launches
3
ref launches
32
fusion ratio (ref / kernel)
10.67x
total cuda time
132 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.072
dram util %
1.3%
compute util %
7.2%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
43.22 GB/s
dram util %
1.3%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
36.3%
bottleneck
compute-bound
dominant pipe %
7.2%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
166.8%
ld sectors / req
12.63
st sectors / req
—
regs / thread
55
smem / block
5248 B
block size
512
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
3981.0%
short_scoreboard
219.1%
mio_throttle
133.8%
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)