gpt-5.5-priority · popcorn · l12_default_gpt
error 3_FusedCrossAttentionRoPEDropout.py
model
gpt-5.5-priority
turns / max
2 / 10
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
—
ref runtime
0.00 μs
speedup
—
started
2026-05-02T21:42:51Z
reference PyTorch source (the prompt the agent sees)
import math

import torch
import torch.nn as nn
import torch.nn.functional as F

# Default ModelNew is PyTorch-only. run_and_check: use check_kernel=False with backend=cuda
# until the candidate file contains a real CUDA kernel (see kernel_static_checker).

class Model(nn.Module):
    """
    Single-layer multi-head cross-attention with RoPE on Q and K, attention
    dropout, and output projection—intended as a fusion target for robotics
    stacks (e.g. proprio / action queries attending to vision or memory).

    Pipeline (conceptually one fused kernel): linear Q from query stream,
    linear K/V from key–value stream → reshape heads → apply RoPE separately
    along query positions (T_q) and key positions (T_k) → scaled dot-product,
    softmax, dropout on weights → aggregate values → output projection.
    """

    def __init__(
        self,
        dim: int,
        num_heads: int,
        dropout: float = 0.0,
        rope_base: float = 10000.0,
    ):
        super().__init__()
        assert dim % num_heads == 0
        self.dim = dim
        self.num_heads = num_heads
        self.head_dim = dim // num_heads
        assert self.head_dim % 2 == 0, "RoPE requires an even head dimension"

        self.q_proj = nn.Linear(dim, dim, bias=False)
        self.k_proj = nn.Linear(dim, dim, bias=False)
        self.v_proj = nn.Linear(dim, dim, bias=False)
        self.out_proj = nn.Linear(dim, dim, bias=False)
        self.dropout = nn.Dropout(dropout)
        self.scale = 1.0 / math.sqrt(self.head_dim)

        inv_freq = 1.0 / (
            rope_base ** (torch.arange(0, self.head_dim, 2).float() / self.head_dim)
        )
        self.register_buffer("inv_freq", inv_freq, persistent=False)

    @staticmethod
    def _rotate_half(x: torch.Tensor) -> torch.Tensor:
        x1, x2 = x.chunk(2, dim=-1)
        return torch.cat([-x2, x1], dim=-1)

    def _rope(self, x: torch.Tensor, seq_len: int) -> torch.Tensor:
        """Apply RoPE along the sequence dimension (last-but-one after head). x: (B, H, L, d)."""
        t = torch.arange(seq_len, device=x.device, dtype=self.inv_freq.dtype)
        freqs = torch.outer(t, self.inv_freq)
        emb = torch.cat([freqs, freqs], dim=-1)
        cos = emb.cos().view(1, 1, seq_len, self.head_dim)
        sin = emb.sin().view(1, 1, seq_len, self.head_dim)
        return x * cos + self._rotate_half(x) * sin

    def forward(self, x_query: torch.Tensor, x_kv: torch.Tensor) -> torch.Tensor:
        """
        Args:
            x_query: (B, T_q, dim) — e.g. robot or decoder tokens
            x_kv:    (B, T_k, dim) — e.g. encoder / memory tokens
        Returns:
            (B, T_q, dim)
        """
        B, T_q, _ = x_query.shape
        _, T_k, _ = x_kv.shape
        h, d = self.num_heads, self.head_dim

        q = self.q_proj(x_query).view(B, T_q, h, d).transpose(1, 2)
        k = self.k_proj(x_kv).view(B, T_k, h, d).transpose(1, 2)
        v = self.v_proj(x_kv).view(B, T_k, h, d).transpose(1, 2)

        q = self._rope(q, T_q)
        k = self._rope(k, T_k)

        attn = torch.matmul(q, k.transpose(-2, -1)) * self.scale
        attn = F.softmax(attn, dim=-1)
        attn = self.dropout(attn)
        out = torch.matmul(attn, v)
        out = out.transpose(1, 2).contiguous().view(B, T_q, self.dim)
        return self.out_proj(out)


class ModelNew(nn.Module):
    """
    KernelBench candidate entry point (`eval_kernel_against_ref` / `run_and_check`).
    Replace this class with a fused CUDA/Triton (etc.) implementation; the default
    delegates to `Model` so you can smoke-test the harness with the same file for
    both `ref_arch_src_path` and `kernel_src_path`.
    """

    def __init__(
        self,
        dim: int,
        num_heads: int,
        dropout: float = 0.0,
        rope_base: float = 10000.0,
    ):
        super().__init__()
        self._impl = Model(dim, num_heads, dropout, rope_base)

    def forward(self, x_query: torch.Tensor, x_kv: torch.Tensor) -> torch.Tensor:
        return self._impl(x_query, x_kv)


batch_size = 4
seq_len_q = 64
seq_len_kv = 128
dim = 256
num_heads = 8
# Use 0.0 so `run_and_check` / multi-trial correctness matches: the harness does not
# re-seed RNG between the reference forward and `ModelNew` forward, so attention
# dropout > 0 would make outputs differ even for identical math.
dropout_p = 0.0


def get_inputs():
    p = popcorn_pri
    bs = p.jitter_int(batch_size)
    tq = p.jitter_int(seq_len_q)
    tk = p.jitter_int(seq_len_kv)
    x_query = torch.randn(bs, tq, dim)
    x_kv = torch.randn(bs, tk, dim)
    return [x_query, x_kv]


def get_init_inputs():
    return [dim, num_heads, dropout_p]
turn 010.7s turn · 10.7s LLM · 0.0s tools
reasoning
**Planning a Python Implementation** I need to create a Python file that implements a full attention mechanism. It's crucial to ensure the weights match the reference model, which has components like q_proj. I think the harness will need to copy the state_dict from the reference model to the new one, and I'll define the same module parameters. For projections, I might consider using torch.mm for faster performance and explore whether to implement a custom CUDA kernel. I'll ensure the structure supports the necessary shapes while considering PyTorch functionalities. **Analyzing Attention Mechanism Flops** In calculating the flops: (256x256)*B*Tq gives about 16M, with K/V totalling around 33M, leading to roughly 98M overall. The attention calculation for each head also factors in as 32M. I realize that PyTorch's overhead with rope and softmax might slow things down, so fusing attention could improve speed. I’m contemplating whether custom projections are needed, but using torch linear for GEMM seems preferable. I’ll need to ensure that outputs have a contiguous shape, and considering how to process scores with reduced max/sum calculations will be crucial! **Optimizing Thread Computation** I'm thinking about how each thread could compute the score for one key, and then we could reduce those scores across the keys for the output dimensions. Keeping it simple, I’m considering setting up a block with 128 threads. This would involve shared score arrays with a size of 128, possibly along with qrope set to 32. I want to make sure this approach is efficient while maintaining the accuracy of the scores for the outputs.
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 17189.3s turn · 7189.3s LLM · 0.0s tools
feedbackLLM call failed: _WorkItemTimeout: work item exceeded soft timeout budget