FW-GLM-5-1 · popcorn · pop_l123_default_gpt
correct 13_QuantVLA_SelectiveLayoutFusion.py
model
FW-GLM-5-1
turns / max
11 / 12
tool calls
11
tokens (total)
100523
wall clock
972.8s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.13 μs
ref runtime
0.16 μs
speedup
1.22x
started
2026-05-11T12:13:08Z
timingkernelbench.timing
kernel runtime
0.13 μs
ref runtime
0.16 μs
speedup
1.22x
kernel mean / median / std
0.13 / — / 0.27 μs
ref mean / median / std
0.16 / — / 0.02 μs
numerical precisioneval_kernel_against_ref
max abs error
4.77e-07
mean abs error
3.38e-08
max rel error
0.03
mean rel error
7.53e-07
gpu memoryextended_metrics.measure_memory
kernel peak
33.88 MB
ref peak
34.38 MB
kernel / ref
0.99x
kernel launches / fusiontorch.profiler
kernel launches
18
ref launches
32
fusion ratio (ref / kernel)
1.78x
total cuda time
527 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.264
dram util %
5.6%
compute util %
26.4%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
187.86 GB/s
dram util %
5.6%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
83.0%
bottleneck
compute-bound
dominant pipe %
26.4%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
647.5%
ld sectors / req
20.50
st sectors / req
—
regs / thread
243
smem / block
16128 B
block size
1344
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
2477.0%
short_scoreboard
579.9%
mio_throttle
27.3%
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 085.1s turn · 5.1s LLM · 80.0s tools · tokens in=1,970 · out=229 · total=2,199
reasoning
Let me analyze this task. I need to create a custom CUDA kernel that replaces the forward computation of the Model class. The Model does: 1. `alpha = torch.sigmoid(layout_logits).unsqueeze(-1)` - sigmoid per-token, shape (B, T, 1) 2. `amax = x.detach().abs().max().clamp(min=1e-8)` - global max over entire tensor 3. `scale = amax / 127.0` 4. `x_q = _fake_quant_symmetric_int8(x, scale)` - fake quantization: clamp(round(x/scale), -127, 127) * scale 5. `mixed = alpha * x_q + (1.0 - alpha) * x` - blend 6. `return self.out_proj(mixed)` - linear projection I need to fuse operations 1-5 into a single CUDA kernel, then do the linear projection. The linear projection could potentially be fused too, but let me start with the quantization blend part. Let me get GPU specs first to understand the hardware.
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 1 · 1 tool call(s) · 192.4s turn · 33.6s LLM · tokens in=2,218 · out=3,101 · total=5,319 · 12,960 chars (click to expand)
turn 1192.4s turn · 33.6s LLM · 158.8s tools · tokens in=2,218 · out=3,101 · total=5,319
reasoning
Now let me understand the computation: 1. `alpha = sigmoid(layout_logits)` - (B, T) 2. `amax = max(abs(x))` - scalar 3. `scale = amax / 127.0` - scalar 4. `x_q = round(x / scale)` clamped to [-127, 127], then * scale 5. `mixed = alpha * x_q + (1-alpha) * x` 6. `out_proj(mixed)` - linear layer For the linear projection, I can use `torch.nn.functional.linear` which should be efficient. The key optimization is fusing steps 1-5 into a single kernel. Let me write a CUDA kernel that: 1. Computes sigmoid of layout_logits in-place (or stores alpha) 2. Finds the global max of abs(x) using reduction 3. Computes scale = amax / 127.0 4. For each element: compute x_q, blend with alpha, and output Actually, since we need the global max first, we might need two passes: 1. First pass: compute amax via reduction 2. Second pass: sigmoid + quantize + blend Or we could use a single kernel with atomicMax to find the maximum, but that would have race conditions. Let me think about this more carefully. The computation requires: - Global reduction for amax - Element-wise sigmoid - Element-wise fake quant and blend A fused kernel would need to: 1. Compute amax via parallel reduction 2. Then use amax for the element-wise operations One approach is to use a single kernel that does: 1. Each thread computes local max of its portion 2. Use warp reduction then block reduction to find block max 3. Use atomicMax to update global max 4. __syncthreads() or grid sync 5. Then compute the element-wise operations But this is complex. Let me try a simpler approach: - Use a separate reduction kernel for amax - Or use PyTorch's amax computation (which should be fast) - Then a fused kernel for the rest Actually, let me look at what operations PyTorch is doing: 1. `layout_logits.sigmoid()` - element-wise 2. `x.detach().abs().max().clamp(min=1e-8)` - reduction + scalar ops 3. `torch.clamp(torch.round(x / scale), -127.0, 127.0) * scale` - element-wise 4. `alpha * x_q + (1.0 - alpha) * x` - element-wise blend 5. Linear projection - GEMM The reduction in step 2 is likely a bottleneck, but let me see if I can fuse everything else. My strategy: 1. Compute amax using PyTorch (or a fast CUDA reduction) 2. Fused kernel for: sigmoid + quantize + blend Actually, let me try a fully fused kernel. The reduction can be done efficiently with a single-pass approach using shared memory. Here's my plan: 1. First kernel: compute amax via parallel reduction 2. Second kernel: given amax, compute sigmoid + quantize + blend Or I could use cooperative groups for grid synchronization, but that's more complex. Let me start with the simple approach: - Use torch for amax (fast) - Fused CUDA kernel for the rest Actually, let me check - the reference uses: ```python with torch.no_grad(): amax = x.detach().abs().max().clamp(min=1e-8) ``` This is computing the maximum over all elements. In CUDA, this would be a full reduction over B*T*D elements. For 8*64*128 = 65536 elements, this is small enough that a single warp or block could handle it. Let me write a kernel that: 1. First, each thread computes its local max (multiple elements per thread if needed) 2. Warp reduce to get warp max 3. Store warp max to shared memory 4. Block reduce to get block max 5. AtomicMax to get global max 6. Grid sync (or just launch a second kernel) 7. Use amax for the rest Actually, for simplicity and correctness first, let me use a two-kernel approach: 1. amax kernel (reduction) 2. sigmoid + quantize + blend kernel Or even simpler, use PyTorch for amax and only write the second kernel. Let me write the kernel:
assistantI'll analyze the reference implementation and create an optimized CUDA kernel. The key operations are: 1. Compute sigmoid of layout_logits (element-wise) 2. Find global max of |x| (reduction) 3. Fake quantize x with scale = amax/127 4. Blend quantized and original: α * x_q + (1-α) * x 5. Linear projection Let me start by writing a fused kernel for operations 1-4:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\n# Fused kernel for: sigmoid(layout_logits) + fake_quant + blend\n# Input: x (B,T,D), layout_logits (B,T)\n# Output: mixed (B,T,D)\n# Also computes amax internally\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <c10/cuda/CUDAException.h>\n#include <cmath>\n\ntemplate <typename scalar_t>\n__device__ __forceinline__ scalar_t sigmoid_device(scalar_t x) {\n return scalar_t(1.0) / (scalar_t(1.0) + exp(-x));\n}\n\n// Reduction kernel to find max(abs(x))\ntemplate <typename scalar_t>\n__global__ void amax_kernel(\n const scalar_t* __restrict__ x,\n scalar_t* __restrict__ amax_out,\n int64_t total_elements\n) {\n __shared__ scalar_t shared_max[256]; // One per thread in block\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n scalar_t local_max = scalar_t(0.0);\n \n // Grid-stride loop\n for (int i = idx; i < total_elements; i += blockDim.x * gridDim.x) {\n scalar_t val = fabsf(x[i]);\n if (val > local_max) local_max = val;\n }\n \n shared_max[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) {\n if (shared_max[tid + s] > shared_max[tid]) {\n shared_max[tid] = shared_max[tid + s];\n }\n }\n __syncthreads();\n }\n \n // Write block result\n if (tid == 0) {\n atomicMax(reinterpret_cast<float*>(amax_out), __half2float(shared_max[0]));\n }\n}\n\n// Fused kernel: sigmoid + fake_quant + blend\ntemplate <typename scalar_t>\n__global__ void fused_quant_blend_kernel(\n const scalar_t* __restrict__ x,\n const scalar_t* __restrict__ layout_logits,\n scalar_t* __restrict__ out,\n const scalar_t scale,\n const int64_t B,\n const int64_t T,\n const int64_t D\n) {\n int64_t idx = blockIdx.x * blockDim.x + threadIdx.x;\n int64_t total = B * T * D;\n \n for (int64_t i = idx; i < total; i += blockDim.x * gridDim.x) {\n // Get batch and token indices\n int64_t d = i % D;\n int64_t bt = i / D;\n int64_t t = bt % T;\n int64_t b = bt / T;\n \n // Layout logit index\n int64_t logit_idx = b * T + t;\n \n // Compute alpha = sigmoid(layout_logits)\n scalar_t alpha = sigmoid_device(layout_logits[logit_idx]);\n \n // Fake quantize\n scalar_t x_val = x[i];\n scalar_t q = roundf(x_val / scale);\n // Clamp to [-127, 127]\n if (q < scalar_t(-127.0)) q = scalar_t(-127.0);\n if (q > scalar_t(127.0)) q = scalar_t(127.0);\n scalar_t x_q = q * scale;\n \n // Blend: alpha * x_q + (1 - alpha) * x\n out[i] = alpha * x_q + (scalar_t(1.0) - alpha) * x_val;\n }\n}\n\n// Specialization for float\n__global__ void amax_kernel_float(\n const float* __restrict__ x,\n float* __restrict__ amax_out,\n int64_t total_elements\n) {\n __shared__ float shared_max[256];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n float local_max = 0.0f;\n \n for (int64_t i = idx; i < total_elements; i += blockDim.x * gridDim.x) {\n float val = fabsf(x[i]);\n if (val > local_max) local_max = val;\n }\n \n shared_max[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) {\n if (shared_max[tid + s] > shared_max[tid]) {\n shared_max[tid] = shared_max[tid + s];\n }\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n atomicMax(amax_out, shared_max[0]);\n }\n}\n\n__global__ void fused_quant_blend_kernel_float(\n const float* __restrict__ x,\n const float* __restrict__ layout_logits,\n float* __restrict__ out,\n const float scale,\n const int64_t B,\n const int64_t T,\n const int64_t D\n) {\n int64_t idx = blockIdx.x * blockDim.x + threadIdx.x;\n int64_t total = B * T * D;\n \n for (int64_t i = idx; i < total; i += blockDim.x * gridDim.x) {\n int64_t d = i % D;\n int64_t bt = i / D;\n int64_t t = bt % T;\n int64_t b = bt / T;\n \n int64_t logit_idx = b * T + t;\n \n float alpha = sigmoid_device(layout_logits[logit_idx]);\n \n float x_val = x[i];\n float q = roundf(x_val / scale);\n q = fmaxf(fminf(q, 127.0f), -127.0f);\n float x_q = q * scale;\n \n out[i] = alpha * x_q + (1.0f - alpha) * x_val;\n }\n}\n\n// Host functions\ntorch::Tensor compute_amax_cuda(torch::Tensor x) {\n int64_t total_elements = x.numel();\n \n // Create output tensor initialized to 0\n auto amax_out = torch::zeros({1}, x.options());\n \n const int block_size = 256;\n int num_blocks = (total_elements + block_size - 1) / block_size;\n num_blocks = std::min(num_blocks, 1024); // Limit blocks\n \n AT_DISPATCH_FLOATING_TYPES(x.scalar_type(), \"amax_kernel\", ([&] {\n amax_kernel<scalar_t><<<num_blocks, block_size>>>(\n x.data_ptr<scalar_t>(),\n amax_out.data_ptr<scalar_t>(),\n total_elements\n );\n }));\n \n // Clamp to minimum\n auto result = amax_out.clamp(1e-8);\n return result;\n}\n\ntorch::Tensor fused_quant_blend_cuda(\n torch::Tensor x,\n torch::Tensor layout_logits,\n torch::Tensor scale_tensor\n) {\n auto out = torch::empty_like(x);\n \n int64_t B = x.size(0);\n int64_t T = x.size(1);\n int64_t D = x.size(2);\n int64_t total = B * T * D;\n \n float scale = scale_tensor.item<float>();\n \n const int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n AT_DISPATCH_FLOATING_TYPES(x.scalar_type(), \"fused_quant_blend_kernel\", ([&] {\n fused_quant_blend_kernel<scalar_t><<<num_blocks, block_size>>>(\n x.data_ptr<scalar_t>(),\n layout_logits.data_ptr<scalar_t>(),\n out.data_ptr<scalar_t>(),\n scalar_t(scale),\n B, T, D\n );\n }));\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax_cuda(torch::Tensor x);\ntorch::Tensor fused_quant_blend_cuda(torch::Tensor x, torch::Tensor layout_logits, torch::Tensor scale);\n\"\"\"\n\nmodule = load_inline(\n name='quant_vla_fused',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax_cuda', 'fused_quant_blend_cuda'],\n verbose=True\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 self.fused_module = module\n\n def forward(self, x: torch.Tensor, layout_logits: torch.Tensor) -> torch.Tensor:\n B, T, D = x.shape\n assert D == self.dim\n assert layout_logits.shape == (B, T)\n \n # Make sure inputs are contiguous\n x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Step 1: Compute amax using fused kernel\n amax = self.fused_module.compute_amax_cuda(x)\n \n # Step 2: Compute scale\n scale = amax / 127.0\n \n # Step 3: Fused sigmoid + quantize + blend\n mixed = self.fused_module.fused_quant_blend_cuda(x, layout_logits, scale)\n \n # Step 4: Linear projection (use PyTorch's optimized GEMM)\n return self.out_proj(mixed)" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'quant_vla_fused'
turn 243.9s turn · 12.7s LLM · 31.2s tools · tokens in=4,405 · out=1,149 · total=5,554
reasoning
The compilation failed. Let me try a simpler approach with more detailed error handling. Let me try a cleaner CUDA kernel implementation.
assistantLet me try a simpler approach with cleaner code:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__device__ __forceinline__ float sigmoid_f(float x) {\n return 1.0f / (1.0f + expf(-x));\n}\n\n__global__ void amax_reduce_kernel(\n const float* __restrict__ x,\n float* __restrict__ amax_out,\n int64_t total_elements\n) {\n __shared__ float shared_max[256];\n \n int tid = threadIdx.x;\n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = blockIdx.x * blockDim.x + tid; i < total_elements; i += blockDim.x * gridDim.x) {\n float val = fabsf(x[i]);\n if (val > local_max) local_max = val;\n }\n \n shared_max[tid] = local_max;\n __syncthreads();\n \n // Reduction in shared memory\n for (int s = 128; s > 0; s >>= 1) {\n if (tid < s && shared_max[tid + s] > shared_max[tid]) {\n shared_max[tid] = shared_max[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n atomicMax(amax_out, shared_max[0]);\n }\n}\n\n__global__ void fused_quant_blend_kernel(\n const float* __restrict__ x,\n const float* __restrict__ layout_logits,\n float* __restrict__ out,\n float scale,\n int64_t B,\n int64_t T,\n int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n int64_t d = i % D;\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n float alpha = sigmoid_f(layout_logits[b * T + t]);\n float x_val = x[i];\n \n // Fake quant\n float q = roundf(x_val / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float x_q = q * scale;\n \n // Blend\n out[i] = alpha * x_q + (1.0f - alpha) * x_val;\n }\n}\n\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t total_elements = x.numel();\n auto amax_out = torch::zeros({1}, x.options());\n \n const int block_size = 256;\n int num_blocks = std::min((int)((total_elements + block_size - 1) / block_size), 1024);\n \n amax_reduce_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n amax_out.data_ptr<float>(),\n total_elements\n );\n \n return amax_out.clamp(1e-8);\n}\n\ntorch::Tensor fused_quant_blend(torch::Tensor x, torch::Tensor layout_logits, float scale) {\n auto out = torch::empty_like(x);\n \n int64_t B = x.size(0);\n int64_t T = x.size(1);\n int64_t D = x.size(2);\n int64_t total = B * T * D;\n \n const int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n fused_quant_blend_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n layout_logits.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor fused_quant_blend(torch::Tensor x, torch::Tensor layout_logits, float scale);\n\"\"\"\n\nmodule = load_inline(\n name='quant_vla_fused_v2',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'fused_quant_blend'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 B, T, D = x.shape\n assert D == self.dim\n assert layout_logits.shape == (B, T)\n \n x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax and scale\n amax = module.compute_amax(x)\n scale = amax / 127.0\n \n # Fused quant blend\n mixed = module.fused_quant_blend(x, layout_logits, scale.item())\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'quant_vla_fused_v2'
turn 341.7s turn · 11.0s LLM · 30.7s tools · tokens in=5,553 · out=943 · total=6,496
reasoning
The error message is not giving me details. Let me try to simplify further and see if I can get it to compile. Maybe there's an issue with the CUDA code syntax.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n\n__global__ void simple_amax_kernel(const float* x, float* out, int64_t n) {\n __shared__ float sdata[256];\n int tid = threadIdx.x;\n float my_max = 0.0f;\n \n for (int64_t i = blockIdx.x * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > my_max) my_max = v;\n }\n \n sdata[tid] = my_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && sdata[tid + s] > sdata[tid]) {\n sdata[tid] = sdata[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) atomicMax(out, sdata[0]);\n}\n\n__global__ void quant_blend_kernel(\n const float* __restrict__ x,\n const float* __restrict__ logits,\n float* __restrict__ out,\n float scale, int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n float alpha = 1.0f / (1.0f + expf(-logits[b * T + t]));\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\ntorch::Tensor get_amax(torch::Tensor x) {\n auto result = torch::zeros({1}, x.options());\n int64_t n = x.numel();\n int blocks = std::min(1024, (int)((n + 255) / 256));\n simple_amax_kernel<<<blocks, 256>>>(x.data_ptr<float>(), result.data_ptr<float>(), n);\n return result.clamp(1e-8);\n}\n\ntorch::Tensor do_quant_blend(torch::Tensor x, torch::Tensor logits, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n int blocks = (total + 255) / 256;\n quant_blend_kernel<<<blocks, 256>>>(\n x.data_ptr<float>(), logits.data_ptr<float>(), out.data_ptr<float>(),\n scale, B, T, D\n );\n return out;\n}\n\"\"\"\n\ncpp_source = \"torch::Tensor get_amax(torch::Tensor x); torch::Tensor do_quant_blend(torch::Tensor x, torch::Tensor logits, float scale);\"\n\nfused_module = load_inline(\n name='qvla',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['get_amax', 'do_quant_blend'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n amax = fused_module.get_amax(x)\n scale = (amax / 127.0).item()\n mixed = fused_module.do_quant_blend(x, layout_logits, scale)\n return self.out_proj(mixed)" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'qvla'
turn 488.3s turn · 6.1s LLM · 82.1s tools · tokens in=6,479 · out=520 · total=6,999
reasoning
Still failing. The verbose flag is true but we're not getting the actual error message. Let me try using the with_cuda=True flag and also see if there's a specific issue with the code. Maybe I need to check the extension loading more carefully. Let me try a minimal CUDA kernel first to make sure the build system works.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Minimal test kernel\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n\n__global__ void add_kernel(float* a, float* b, float* c, int64_t n) {\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {\n c[i] = a[i] + b[i];\n }\n}\n\ntorch::Tensor test_add(torch::Tensor a, torch::Tensor b) {\n auto c = torch::empty_like(a);\n int64_t n = a.numel();\n int blocks = (n + 255) / 256;\n add_kernel<<<blocks, 256>>>(a.data_ptr<float>(), b.data_ptr<float>(), c.data_ptr<float>(), n);\n return c;\n}\n\"\"\"\n\ncpp_source = \"torch::Tensor test_add(torch::Tensor a, torch::Tensor b);\"\n\ntest_module = load_inline(\n name='test_add',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['test_add'],\n verbose=True,\n extra_cuda_cflags=['-O3']\n)\n\nprint(\"Module loaded successfully!\")\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 # Placeholder - just use PyTorch for now to test compilation\n alpha = torch.sigmoid(layout_logits).unsqueeze(-1)\n with torch.no_grad():\n amax = x.detach().abs().max().clamp(min=1e-8)\n scale = amax / 127.0\n q = torch.clamp(torch.round(x / scale), -127.0, 127.0)\n x_q = q * scale\n mixed = alpha * x_q + (1.0 - alpha) * x\n return self.out_proj(mixed)" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 5 · 1 tool call(s) · 101.6s turn · 15.3s LLM · tokens in=6,945 · out=1,414 · total=8,359 · 6,229 chars (click to expand)
turn 5101.6s turn · 15.3s LLM · 86.3s tools · tokens in=6,945 · out=1,414 · total=8,359
reasoning
Good, compilation works. Now let me build up the full kernel piece by piece. Let me start with a kernel that computes amax correctly.
assistantGood, compilation works! Now let me build the full kernel with proper handling:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Fused sigmoid + fake quant + blend\n__global__ void quant_blend_kernel(\n const float* __restrict__ x,\n const float* __restrict__ logits,\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t d = i % D;\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Sigmoid\n float alpha = 1.0f / (1.0f + expf(-logits[b * T + t]));\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend(torch::Tensor x, torch::Tensor logits, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n logits.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor quant_blend(torch::Tensor x, torch::Tensor logits, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_full',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'quant_blend'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Fused quant + blend\n mixed = fused_module.quant_blend(x, layout_logits, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 6 · 1 tool call(s) · 87.0s turn · 11.0s LLM · tokens in=8,343 · out=1,381 · total=9,724 · 6,091 chars (click to expand)
turn 687.0s turn · 11.0s LLM · 76.0s tools · tokens in=8,343 · out=1,381 · total=9,724
reasoning
Good, it compiled. Now let me check correctness.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Fused sigmoid + fake quant + blend\n__global__ void quant_blend_kernel(\n const float* __restrict__ x,\n const float* __restrict__ logits,\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t d = i % D;\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Sigmoid\n float alpha = 1.0f / (1.0f + expf(-logits[b * T + t]));\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend(torch::Tensor x, torch::Tensor logits, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n logits.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor quant_blend(torch::Tensor x, torch::Tensor logits, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_full',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'quant_blend'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Fused quant + blend\n mixed = fused_module.quant_blend(x, layout_logits, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=3.38e-08 max_rel_err=3.23e-02
turn 7 · 1 tool call(s) · 102.4s turn · 17.3s LLM · tokens in=9,770 · out=1,756 · total=11,526 · 7,693 chars (click to expand)
turn 7102.4s turn · 17.3s LLM · 85.0s tools · tokens in=9,770 · out=1,756 · total=11,526
reasoning
The correctness passed. Now let me optimize further. The linear projection can also be fused into a custom CUDA kernel with matmul. Let me try to optimize the quant_blend kernel for better performance. Key optimizations to try: 1. Use larger thread blocks (e.g., 512 or 1024 threads) 2. Use vectorized loads/stores 3. Precompute alpha in a separate kernel to avoid redundant sigmoid computations 4. Fuse the linear projection (matmul + bias add) Let me first try optimizing the main kernel and see the timing.
assistantExcellent! Correctness passes! Now let me optimize the kernel. I'll try: 1. Better memory access patterns 2. Vectorized loads 3. Precompute alphas to avoid redundant sigmoid
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Precompute alphas = sigmoid(logits)\n__global__ void sigmoid_kernel(const float* __restrict__ logits, float* __restrict__ alphas, int64_t n) {\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {\n alphas[i] = 1.0f / (1.0f + expf(-logits[i]));\n }\n}\n\n// Kernel 4: Fused fake quant + blend using precomputed alphas\n__global__ void quant_blend_kernel_opt(\n const float* __restrict__ x,\n const float* __restrict__ alphas, // Precomputed sigmoid\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Get precomputed alpha\n float alpha = alphas[b * T + t];\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: compute sigmoid\ntorch::Tensor compute_sigmoid(torch::Tensor logits) {\n auto alphas = torch::empty_like(logits);\n int64_t n = logits.numel();\n int block_size = 256;\n int num_blocks = (n + block_size - 1) / block_size;\n \n sigmoid_kernel<<<num_blocks, block_size>>>(\n logits.data_ptr<float>(),\n alphas.data_ptr<float>(),\n n\n );\n \n return alphas;\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel_opt<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n alphas.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor compute_sigmoid(torch::Tensor logits);\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_opt',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'compute_sigmoid', 'quant_blend_opt'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Precompute alphas\n alphas = fused_module.compute_sigmoid(layout_logits)\n \n # Fused quant + blend\n mixed = fused_module.quant_blend_opt(x, alphas, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 8 · 1 tool call(s) · 14.3s turn · 14.3s LLM · tokens in=11,427 · out=1,618 · total=13,045 · 7,104 chars (click to expand)
turn 814.3s turn · 14.3s LLM · 0.0s tools · tokens in=11,427 · out=1,618 · total=13,045
reasoning
Good, let's test correctness and then think about more optimizations.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Precompute alphas = sigmoid(logits)\n__global__ void sigmoid_kernel(const float* __restrict__ logits, float* __restrict__ alphas, int64_t n) {\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {\n alphas[i] = 1.0f / (1.0f + expf(-logits[i]));\n }\n}\n\n// Kernel 4: Fused fake quant + blend using precomputed alphas\n__global__ void quant_blend_kernel_opt(\n const float* __restrict__ x,\n const float* __restrict__ alphas, // Precomputed sigmoid\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Get precomputed alpha\n float alpha = alphas[b * T + t];\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: compute sigmoid\ntorch::Tensor compute_sigmoid(torch::Tensor logits) {\n auto alphas = torch::empty_like(logits);\n int64_t n = logits.numel();\n int block_size = 256;\n int num_blocks = (n + block_size - 1) / block_size;\n \n sigmoid_kernel<<<num_blocks, block_size>>>(\n logits.data_ptr<float>(),\n alphas.data_ptr<float>(),\n n\n );\n \n return alphas;\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel_opt<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n alphas.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor compute_sigmoid(torch::Tensor logits);\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_opt',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'compute_sigmoid', 'quant_blend_opt'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Precompute alphas\n alphas = fused_module.compute_sigmoid(layout_logits)\n \n # Fused quant + blend\n mixed = fused_module.quant_blend_opt(x, alphas, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=3.38e-08 max_rel_err=3.23e-02
turn 9 · 1 tool call(s) · 17.3s turn · 17.3s LLM · tokens in=13,121 · out=1,725 · total=14,846 · 7,560 chars (click to expand)
turn 917.3s turn · 17.3s LLM · 0.0s tools · tokens in=13,121 · out=1,725 · total=14,846
reasoning
The user is suggesting I should submit my kernel now if it's correct and working. Let me check: 1. The kernel compiles ✓ 2. The kernel passes correctness tests (5/5 trials) ✓ 3. The kernel is numerically equivalent to the reference ✓ The kernel is optimized with: - Separate kernels for amax reduction, sigmoid computation, and quant blend - Precomputed alphas to avoid redundant sigmoid calculations - Grid-stride loops for efficient processing I should submit this kernel now as suggested.
assistantLet me verify the kernel is ready to submit with a static check:
call → static_check
callstatic_check { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Precompute alphas = sigmoid(logits)\n__global__ void sigmoid_kernel(const float* __restrict__ logits, float* __restrict__ alphas, int64_t n) {\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {\n alphas[i] = 1.0f / (1.0f + expf(-logits[i]));\n }\n}\n\n// Kernel 4: Fused fake quant + blend using precomputed alphas\n__global__ void quant_blend_kernel_opt(\n const float* __restrict__ x,\n const float* __restrict__ alphas, // Precomputed sigmoid\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Get precomputed alpha\n float alpha = alphas[b * T + t];\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: compute sigmoid\ntorch::Tensor compute_sigmoid(torch::Tensor logits) {\n auto alphas = torch::empty_like(logits);\n int64_t n = logits.numel();\n int block_size = 256;\n int num_blocks = (n + block_size - 1) / block_size;\n \n sigmoid_kernel<<<num_blocks, block_size>>>(\n logits.data_ptr<float>(),\n alphas.data_ptr<float>(),\n n\n );\n \n return alphas;\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel_opt<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n alphas.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor compute_sigmoid(torch::Tensor logits);\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_opt',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'compute_sigmoid', 'quant_blend_opt'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Precompute alphas\n alphas = fused_module.compute_sigmoid(layout_logits)\n \n # Fused quant + blend\n mixed = fused_module.quant_blend_opt(x, alphas, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 10 · FINAL · 1 tool call(s) · 198.9s turn · 16.3s LLM · tokens in=14,785 · out=1,671 · total=16,456 · 7,477 chars (click to expand)
turn 10198.9s turn · 16.3s LLM · 182.5s tools · tokens in=14,785 · out=1,671 · total=16,456 · FINAL
reasoning
The kernel has passed: 1. Compilation check - PASSED 2. Correctness check - PASSED (5/5 trials, max_abs_err=4.77e-07, within tolerance) 3. Static check - PASSED (no violations) The kernel is correct and ready to submit. Let me submit it now.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n\n// Kernel 1: Compute global max of |x| using grid-level reduction\n__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n int bid = blockIdx.x;\n \n float local_max = 0.0f;\n \n // Grid-stride loop\n for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {\n float v = fabsf(x[i]);\n if (v > local_max) local_max = v;\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n // Block reduction\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n block_max[bid] = smem[0];\n }\n}\n\n// Kernel 2: Final reduction to get global max\n__global__ void reduce_final(float* block_max, float* global_max, int n) {\n __shared__ float smem[256];\n int tid = threadIdx.x;\n \n float local_max = 0.0f;\n for (int i = tid; i < n; i += blockDim.x) {\n if (block_max[i] > local_max) local_max = block_max[i];\n }\n \n smem[tid] = local_max;\n __syncthreads();\n \n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s && smem[tid + s] > smem[tid]) {\n smem[tid] = smem[tid + s];\n }\n __syncthreads();\n }\n \n if (tid == 0) {\n global_max[0] = smem[0];\n }\n}\n\n// Kernel 3: Precompute alphas = sigmoid(logits)\n__global__ void sigmoid_kernel(const float* __restrict__ logits, float* __restrict__ alphas, int64_t n) {\n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {\n alphas[i] = 1.0f / (1.0f + expf(-logits[i]));\n }\n}\n\n// Kernel 4: Fused fake quant + blend using precomputed alphas\n__global__ void quant_blend_kernel_opt(\n const float* __restrict__ x,\n const float* __restrict__ alphas, // Precomputed sigmoid\n float* __restrict__ out,\n float scale,\n int64_t B, int64_t T, int64_t D\n) {\n int64_t total = B * T * D;\n \n for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {\n // Compute indices\n int64_t t = (i / D) % T;\n int64_t b = i / (T * D);\n \n // Get precomputed alpha\n float alpha = alphas[b * T + t];\n \n // Fake quant\n float xv = x[i];\n float q = roundf(xv / scale);\n q = fmaxf(-127.0f, fminf(127.0f, q));\n float xq = q * scale;\n \n // Blend\n out[i] = alpha * xq + (1.0f - alpha) * xv;\n }\n}\n\n// Host function: compute amax\ntorch::Tensor compute_amax(torch::Tensor x) {\n int64_t n = x.numel();\n int block_size = 256;\n int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));\n \n // Storage for partial results\n auto block_max = torch::empty({num_blocks}, x.options());\n auto global_max = torch::empty({1}, x.options());\n \n // Launch first kernel\n amax_kernel<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n block_max.data_ptr<float>(),\n n\n );\n \n // Launch final reduction\n reduce_final<<<1, block_size>>>(\n block_max.data_ptr<float>(),\n global_max.data_ptr<float>(),\n num_blocks\n );\n \n // Clamp to minimum\n return global_max.clamp(1e-8);\n}\n\n// Host function: compute sigmoid\ntorch::Tensor compute_sigmoid(torch::Tensor logits) {\n auto alphas = torch::empty_like(logits);\n int64_t n = logits.numel();\n int block_size = 256;\n int num_blocks = (n + block_size - 1) / block_size;\n \n sigmoid_kernel<<<num_blocks, block_size>>>(\n logits.data_ptr<float>(),\n alphas.data_ptr<float>(),\n n\n );\n \n return alphas;\n}\n\n// Host function: quant blend\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale) {\n auto out = torch::empty_like(x);\n int64_t B = x.size(0), T = x.size(1), D = x.size(2);\n int64_t total = B * T * D;\n \n int block_size = 256;\n int num_blocks = (total + block_size - 1) / block_size;\n \n quant_blend_kernel_opt<<<num_blocks, block_size>>>(\n x.data_ptr<float>(),\n alphas.data_ptr<float>(),\n out.data_ptr<float>(),\n scale,\n B, T, D\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor compute_amax(torch::Tensor x);\ntorch::Tensor compute_sigmoid(torch::Tensor logits);\ntorch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale);\n\"\"\"\n\nfused_module = load_inline(\n name='qvla_opt',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['compute_amax', 'compute_sigmoid', 'quant_blend_opt'],\n verbose=True,\n extra_cuda_cflags=['-O3']\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 x = x.contiguous()\n layout_logits = layout_logits.contiguous()\n \n # Compute amax using custom kernel\n amax = fused_module.compute_amax(x)\n scale = (amax / 127.0).item()\n \n # Precompute alphas\n alphas = fused_module.compute_sigmoid(layout_logits)\n \n # Fused quant + blend\n mixed = fused_module.quant_blend_opt(x, alphas, scale)\n \n # Linear projection\n return self.out_proj(mixed)" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.13 μs Runtime stats: mean=0.13μs median=?μs std=0.27μs Numerical precision: max_abs_err=4.77e-07 mean_abs_err=3.38e-08 max_rel_err=3.23e-02 Memory: 33.88 MB peak (ref: 34.38 MB, ratio: 0.9854x) Kernel launches: 18 (ref: 32, fusion ratio: 1.7778) SOL score: 0.2642
final submitted kernel (201 lines, 5,685 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

cuda_source = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>

// Kernel 1: Compute global max of |x| using grid-level reduction
__global__ void amax_kernel(const float* __restrict__ x, float* __restrict__ block_max, int64_t n) {
    __shared__ float smem[256];
    int tid = threadIdx.x;
    int bid = blockIdx.x;
    
    float local_max = 0.0f;
    
    // Grid-stride loop
    for (int64_t i = bid * blockDim.x + tid; i < n; i += blockDim.x * gridDim.x) {
        float v = fabsf(x[i]);
        if (v > local_max) local_max = v;
    }
    
    smem[tid] = local_max;
    __syncthreads();
    
    // Block reduction
    for (int s = blockDim.x >> 1; s > 0; s >>= 1) {
        if (tid < s && smem[tid + s] > smem[tid]) {
            smem[tid] = smem[tid + s];
        }
        __syncthreads();
    }
    
    if (tid == 0) {
        block_max[bid] = smem[0];
    }
}

// Kernel 2: Final reduction to get global max
__global__ void reduce_final(float* block_max, float* global_max, int n) {
    __shared__ float smem[256];
    int tid = threadIdx.x;
    
    float local_max = 0.0f;
    for (int i = tid; i < n; i += blockDim.x) {
        if (block_max[i] > local_max) local_max = block_max[i];
    }
    
    smem[tid] = local_max;
    __syncthreads();
    
    for (int s = blockDim.x >> 1; s > 0; s >>= 1) {
        if (tid < s && smem[tid + s] > smem[tid]) {
            smem[tid] = smem[tid + s];
        }
        __syncthreads();
    }
    
    if (tid == 0) {
        global_max[0] = smem[0];
    }
}

// Kernel 3: Precompute alphas = sigmoid(logits)
__global__ void sigmoid_kernel(const float* __restrict__ logits, float* __restrict__ alphas, int64_t n) {
    for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < n; i += blockDim.x * gridDim.x) {
        alphas[i] = 1.0f / (1.0f + expf(-logits[i]));
    }
}

// Kernel 4: Fused fake quant + blend using precomputed alphas
__global__ void quant_blend_kernel_opt(
    const float* __restrict__ x,
    const float* __restrict__ alphas,  // Precomputed sigmoid
    float* __restrict__ out,
    float scale,
    int64_t B, int64_t T, int64_t D
) {
    int64_t total = B * T * D;
    
    for (int64_t i = blockIdx.x * blockDim.x + threadIdx.x; i < total; i += blockDim.x * gridDim.x) {
        // Compute indices
        int64_t t = (i / D) % T;
        int64_t b = i / (T * D);
        
        // Get precomputed alpha
        float alpha = alphas[b * T + t];
        
        // Fake quant
        float xv = x[i];
        float q = roundf(xv / scale);
        q = fmaxf(-127.0f, fminf(127.0f, q));
        float xq = q * scale;
        
        // Blend
        out[i] = alpha * xq + (1.0f - alpha) * xv;
    }
}

// Host function: compute amax
torch::Tensor compute_amax(torch::Tensor x) {
    int64_t n = x.numel();
    int block_size = 256;
    int num_blocks = std::min(1024, (int)((n + block_size - 1) / block_size));
    
    // Storage for partial results
    auto block_max = torch::empty({num_blocks}, x.options());
    auto global_max = torch::empty({1}, x.options());
    
    // Launch first kernel
    amax_kernel<<<num_blocks, block_size>>>(
        x.data_ptr<float>(),
        block_max.data_ptr<float>(),
        n
    );
    
    // Launch final reduction
    reduce_final<<<1, block_size>>>(
        block_max.data_ptr<float>(),
        global_max.data_ptr<float>(),
        num_blocks
    );
    
    // Clamp to minimum
    return global_max.clamp(1e-8);
}

// Host function: compute sigmoid
torch::Tensor compute_sigmoid(torch::Tensor logits) {
    auto alphas = torch::empty_like(logits);
    int64_t n = logits.numel();
    int block_size = 256;
    int num_blocks = (n + block_size - 1) / block_size;
    
    sigmoid_kernel<<<num_blocks, block_size>>>(
        logits.data_ptr<float>(),
        alphas.data_ptr<float>(),
        n
    );
    
    return alphas;
}

// Host function: quant blend
torch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale) {
    auto out = torch::empty_like(x);
    int64_t B = x.size(0), T = x.size(1), D = x.size(2);
    int64_t total = B * T * D;
    
    int block_size = 256;
    int num_blocks = (total + block_size - 1) / block_size;
    
    quant_blend_kernel_opt<<<num_blocks, block_size>>>(
        x.data_ptr<float>(),
        alphas.data_ptr<float>(),
        out.data_ptr<float>(),
        scale,
        B, T, D
    );
    
    return out;
}
"""

cpp_source = """
torch::Tensor compute_amax(torch::Tensor x);
torch::Tensor compute_sigmoid(torch::Tensor logits);
torch::Tensor quant_blend_opt(torch::Tensor x, torch::Tensor alphas, float scale);
"""

fused_module = load_inline(
    name='qvla_opt',
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=['compute_amax', 'compute_sigmoid', 'quant_blend_opt'],
    verbose=True,
    extra_cuda_cflags=['-O3']
)

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:
        x = x.contiguous()
        layout_logits = layout_logits.contiguous()
        
        # Compute amax using custom kernel
        amax = fused_module.compute_amax(x)
        scale = (amax / 127.0).item()
        
        # Precompute alphas
        alphas = fused_module.compute_sigmoid(layout_logits)
        
        # Fused quant + blend
        mixed = fused_module.quant_blend_opt(x, alphas, scale)
        
        # Linear projection
        return self.out_proj(mixed)