KernelBench mega · RTX PRO 6000

Kimi-Linear Decode GLM-5.2

11.14×geomean speedup across shapes

manually audited: clean

RTX PRO 6000 GLM-5.2 cell (11.14x), the strongest non-Anthropic mega result. Genuine Triton fused int4 dequant-GEMV + persistent-buffer/CUDA-graph decode path using data_ptr identity to decide rebind-vs-continue. Forbidden-scan passed; template_mutated=False; correctness clean.

harnesszai-claude
Kernel source (redacted)
"""Fused W4A16 dequant-GEMV solution for the Kimi-Linear hybrid decode unit.

Beats baseline.py three ways:

1. **Fused int4 dequant-GEMV** (Triton, split-K + fp32 atomic reduction). The int4
   weights are streamed once; the per-group asymmetric dequant is fused into the
   dot so the bf16 weight is never materialized. Two kernels: ``w4_gemv`` for the
   M=1 attention projections and ``w4_gemv_batched`` for the MoE experts (indexes
   the full expert table directly, no weight gather).

2. **MLA weight absorption.** q is projected into the 512-d latent and attention
   runs against the compressed ``c_kv`` cache directly, so the [ctx, 8192] KV
   tensor is never materialized -- the dominant win at long context.

3. **CUDA Graph capture/replay.** Batch-1 decode is dispatch-bound (~90 tiny
   kernels/step, ~4 us launch each). The whole step is captured into a graph and
   replayed as one launch. To make the step shape-stable (graphs need fixed
   shapes/addresses) the MLA KV cache is a *padded* buffer with a length mask and
   in-place append instead of a growing ``cat``, and all recurrent state is
   updated in-place on static buffers.

Module / buffer names are identical to reference.py so the reference state_dict
loads with strict=True.
"""
from __future__ import annotations

from dataclasses import dataclass, field

import torch
import torch.nn as nn
import torch.nn.functional as F
import triton
import triton.language as tl

EPS = 1.0e-6
GROUP_SIZE = 128
OP_TYPE = "kimi_linear_w4a16_decode"


@dataclass(frozen=True)
class Config:
    hidden: int = 2304
    kda_heads: int = 32
    kda_head_dim: int = 128
    short_conv: int = 4
    mla_heads: int = 32
    kv_lora: int = 512
    qk_nope: int = 128
    qk_rope: int = 64
    v_head: int = 128
    rope_theta: float = 10000.0
    n_experts: int = 64
    n_active: int = 8
    n_shared: int = 1
    moe_inter: int = 1024
    routed_scaling: float = 2.446
    group: int = 128
    pattern: tuple = ("K", "K", "K", "M")
    dtype: torch.dtype = field(default=torch.bfloat16)


def build_config(shape: dict) -> Config:
    return Config(n_experts=int(shape.get("n_experts", 64)))


# --------------------------------------------------------------------------- #
# Triton kernels -- fused int4 dequant-GEMV (tl.dot / tensor-core, split-K).
# Each program owns BLOCK_N output features and strides through K in GROUP-sized
# chunks; the int4 nibbles are unpacked, per-group dequantized, and dotted with
# the activation in-register -- the bf16 weight is never materialized. Split-K
# (round-robin over KS) multiplies block count for batch-1 parallelism; partials
# reduce via fp32 atomics. tl.dot keeps the issue slots free for memory traffic.
# --------------------------------------------------------------------------- #
@triton.jit
def _w4_gemv_kernel(x_ptr, wq_ptr, s_ptr, z_ptr, y_ptr, K, N,
                    GROUP: tl.constexpr, PAIRS: tl.constexpr,
                    BLOCK_N: tl.constexpr, KS: tl.constexpr, TM: tl.constexpr):
    pid_n = tl.program_id(0)
    pid_k = tl.program_id(1)
    cols = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
    ngroups = K // GROUP
    acc = tl.zeros([TM, BLOCK_N], dtype=tl.float32)
    rm = tl.arange(0, TM)
    pair_ar = tl.arange(0, PAIRS)
    for g in range(pid_k, ngroups, KS):
        k_base = g * GROUP
        x_even = tl.load(x_ptr + k_base + pair_ar * 2)
        x_odd = tl.load(x_ptr + k_base + pair_ar * 2 + 1)
        x_even = tl.where(rm[:, None] < 1, x_even[None, :], 0.0).to(tl.bfloat16)
        x_odd = tl.where(rm[:, None] < 1, x_odd[None, :], 0.0).to(tl.bfloat16)
        row_off = (k_base // 2 + pair_ar)[:, None]
        wq = tl.load(wq_ptr + row_off * N + cols[None, :])      # [PAIRS, BLOCK_N] uint8
        lo = (wq & 0xF).to(tl.float32)
        hi = ((wq >> 4) & 0xF).to(tl.float32)
        s = tl.load(s_ptr + g * N + cols).to(tl.float32)
        z = tl.load(z_ptr + g * N + cols).to(tl.float32)
        lo = (lo - z[None, :]) * s[None, :]
        hi = (hi - z[None, :]) * s[None, :]
        acc += tl.dot(x_even, lo.to(tl.bfloat16))
        acc += tl.dot(x_odd, hi.to(tl.bfloat16))
    tl.atomic_add(y_ptr + cols, tl.sum(acc, axis=0))


def _pick_ks(K: int, group: int = GROUP_SIZE) -> int:
    ng = K // group
    return max(1, min(8, ng))


def w4_gemv(x: torch.Tensor, w_q: torch.Tensor, scales: torch.Tensor,
            zeros: torch.Tensor, K: int, N: int, group: int = GROUP_SIZE,
            block_n: int = 64) -> torch.Tensor:
    """y = x @ dequant(w_q); x is [K] bf16, returns [N] bf16."""
    ks = _pick_ks(K, group)
    y = torch.zeros(N, dtype=torch.float32, device=x.device)
    grid = (triton.cdiv(N, block_n), ks)
    _w4_gemv_kernel[grid](x, w_q, scales, zeros, y, K, N,
                          GROUP=group, PAIRS=group // 2, BLOCK_N=block_n, KS=ks, TM=16,
                          num_warps=4, num_stages=3)
    return y.to(torch.bfloat16)


@triton.jit
def _w4_gemv_batch_kernel(x_ptr, wq_ptr, s_ptr, z_ptr, idx_ptr, y_ptr,
                          K, N, stride_xe, stride_ye,
                          GROUP: tl.constexpr, PAIRS: tl.constexpr,
                          BLOCK_N: tl.constexpr, KS: tl.constexpr, TM: tl.constexpr):
    pid_n = tl.program_id(0)
    pid_k = tl.program_id(1)
    pid_e = tl.program_id(2)
    e = tl.load(idx_ptr + pid_e).to(tl.int64)
    cols = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
    ngroups = K // GROUP
    acc = tl.zeros([TM, BLOCK_N], dtype=tl.float32)
    rm = tl.arange(0, TM)
    pair_ar = tl.arange(0, PAIRS)
    xbase = x_ptr + pid_e * stride_xe
    wq_base = wq_ptr + e * (K // 2) * N
    s_base = s_ptr + e * ngroups * N
    z_base = z_ptr + e * ngroups * N
    for g in range(pid_k, ngroups, KS):
        k_base = g * GROUP
        x_even = tl.load(xbase + k_base + pair_ar * 2)
        x_odd = tl.load(xbase + k_base + pair_ar * 2 + 1)
        x_even = tl.where(rm[:, None] < 1, x_even[None, :], 0.0).to(tl.bfloat16)
        x_odd = tl.where(rm[:, None] < 1, x_odd[None, :], 0.0).to(tl.bfloat16)
        row_off = (k_base // 2 + pair_ar)[:, None]
        wq = tl.load(wq_base + row_off * N + cols[None, :])
        lo = (wq & 0xF).to(tl.float32)
        hi = ((wq >> 4) & 0xF).to(tl.float32)
        s = tl.load(s_base + g * N + cols).to(tl.float32)
        z = tl.load(z_base + g * N + cols).to(tl.float32)
        lo = (lo - z[None, :]) * s[None, :]
        hi = (hi - z[None, :]) * s[None, :]
        acc += tl.dot(x_even, lo.to(tl.bfloat16))
        acc += tl.dot(x_odd, hi.to(tl.bfloat16))
    tl.atomic_add((y_ptr + pid_e * stride_ye + cols), tl.sum(acc, axis=0))


def w4_gemv_batched(x: torch.Tensor, w_q: torch.Tensor, scales: torch.Tensor,
                    zeros: torch.Tensor, idx: torch.Tensor, K: int, N: int,
                    group: int = GROUP_SIZE, block_n: int = 64) -> torch.Tensor:
    """Batched expert GEMV. x is [K] (shared across selected experts) or
    [n_sel, K] (per-expert). idx selects experts from the full table (no copy).
    Returns [n_sel, N] bf16."""
    n_sel = idx.numel()
    ks = max(1, min(8, (K // group)))
    y = torch.zeros((n_sel, N), dtype=torch.float32, device=x.device)
    stride_xe = 0 if x.dim() == 1 else x.stride(0)
    grid = (triton.cdiv(N, block_n), ks, n_sel)
    _w4_gemv_batch_kernel[grid](x, w_q, scales, zeros, idx, y, K, N,
                                stride_xe, N,
                                GROUP=group, PAIRS=group // 2, BLOCK_N=block_n, KS=ks, TM=16,
                                num_warps=4, num_stages=3)
    return y.to(torch.bfloat16)


# --------------------------------------------------------------------------- #
# quantized layers (same buffer names as reference.py)
# --------------------------------------------------------------------------- #
class QuantLinear(nn.Module):
    def __init__(self, in_f: int, out_f: int, group: int = GROUP_SIZE):
        super().__init__()
        self.in_f, self.out_f, self.group = in_f, out_f, group
        ng = in_f // group
        self.register_buffer("w_q", torch.zeros(in_f // 2, out_f, dtype=torch.uint8))
        self.register_buffer("scales", torch.zeros(ng, out_f, dtype=torch.bfloat16))
        self.register_buffer("zeros", torch.zeros(ng, out_f, dtype=torch.bfloat16))

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return w4_gemv(x, self.w_q, self.scales, self.zeros, self.in_f, self.out_f, self.group)


class QuantExperts(nn.Module):
    def __init__(self, n: int, in_f: int, out_f: int, group: int = GROUP_SIZE):
        super().__init__()
        self.n, self.in_f, self.out_f, self.group = n, in_f, out_f, group
        ng = in_f // group
        self.register_buffer("w_q", torch.zeros(n, in_f // 2, out_f, dtype=torch.uint8))
        self.register_buffer("scales", torch.zeros(n, ng, out_f, dtype=torch.bfloat16))
        self.register_buffer("zeros", torch.zeros(n, ng, out_f, dtype=torch.bfloat16))

    def forward_idx(self, x: torch.Tensor, idx: torch.Tensor) -> torch.Tensor:
        return w4_gemv_batched(x, self.w_q, self.scales, self.zeros, idx,
                               self.in_f, self.out_f, self.group)


# --------------------------------------------------------------------------- #
# helpers
# --------------------------------------------------------------------------- #
@triton.jit
def _rmsnorm_kernel(x_ptr, w_ptr, o_ptr, N, EPS: tl.constexpr, BLOCK: tl.constexpr):
    offs = tl.arange(0, BLOCK)
    mask = offs < N
    x = tl.load(x_ptr + offs, mask=mask, other=0.0).to(tl.float32)
    var = tl.sum(x * x, axis=0) / N
    inv = tl.rsqrt(var + EPS)
    w = tl.load(w_ptr + offs, mask=mask, other=0.0).to(tl.float32)
    out = (x * inv * w).to(tl.bfloat16)
    tl.store(o_ptr + offs, out, mask=mask)


def _rmsnorm(x: torch.Tensor, w: torch.Tensor) -> torch.Tensor:
    n = x.numel()
    o = torch.empty(n, dtype=torch.bfloat16, device=x.device)
    _rmsnorm_kernel[(1,)](x, w, o, n, EPS=EPS, BLOCK=triton.next_power_of_2(n), num_warps=8)
    return o


@triton.jit
def _kda_recur_kernel(S_ptr, q_ptr, k_ptr, v_ptr, g_ptr, beta_ptr, o_ptr,
                      H: tl.constexpr, DK: tl.constexpr, BJ: tl.constexpr):
    pid_h = tl.program_id(0)
    pid_j = tl.program_id(1)
    iar = tl.arange(0, DK)
    js = pid_j * BJ + tl.arange(0, BJ)
    base = pid_h * DK
    krow = tl.load(k_ptr + base + iar)              # [DK] f32
    qrow = tl.load(q_ptr + base + iar)
    gval = tl.load(g_ptr + base + iar).to(tl.float32)
    ge = tl.sigmoid(-gval)                            # = exp(-softplus(g))
    beta = tl.load(beta_ptr + pid_h)
    soff = pid_h * DK * DK + iar[:, None] * DK + js[None, :]   # [DK, BJ]
    st = tl.load(S_ptr + soff)                        # [DK, BJ] f32
    st = st * ge[:, None]
    pred = tl.sum(st * krow[:, None], axis=0)         # [BJ]
    vrow = tl.load(v_ptr + base + js)
    st = st + beta * krow[:, None] * (vrow - pred)[None, :]
    oj = tl.sum(st * qrow[:, None], axis=0)           # [BJ]
    tl.store(S_ptr + soff, st)
    tl.store(o_ptr + base + js, oj)


def _kda_recur(S, q, k, v, g, beta, H, Dk):
    """Fused gated-delta recurrence: update S in-place, return o [H*Dk] f32.
    q,k,v,g are [H*Dk] (g raw pre-softplus); beta is [H]."""
    o = torch.empty(H * Dk, dtype=torch.float32, device=S.device)
    BJ = 32
    _kda_recur_kernel[(H, Dk // BJ)](S, q, k, v, g, beta, o, H=H, DK=Dk, BJ=BJ, num_warps=4)
    return o


@triton.jit
def _short_conv_kernel(val_ptr, prev_ptr, cw_ptr, out_ptr, prev_out_ptr, C: tl.constexpr,
                       K: tl.constexpr, BLOCK_C: tl.constexpr):
    pid = tl.program_id(0)
    cs = pid * BLOCK_C + tl.arange(0, BLOCK_C)
    # window rows 0..K-1: rows 0..K-2 from prev, row K-1 = val
    acc = tl.zeros([BLOCK_C], dtype=tl.float32)
    for t in range(K):
        if t < K - 1:
            w = tl.load(prev_ptr + t * C + cs)
        else:
            w = tl.load(val_ptr + cs)
        cw = tl.load(cw_ptr + cs * K + t).to(tl.float32)
        acc += w.to(tl.float32) * cw
    out = tl.sigmoid(acc) * acc                       # silu
    tl.store(out_ptr + cs, out.to(tl.bfloat16))
    # roll prev: new_prev[t] = old prev[t+1] for t in 0..K-3, new_prev[K-2] = val
    for t in range(K - 1):
        if t < K - 2:
            v = tl.load(prev_ptr + (t + 1) * C + cs)
        else:
            v = tl.load(val_ptr + cs)
        tl.store(prev_out_ptr + t * C + cs, v)


def _short_conv_fused(val, prev_buf, conv_w_idx, C, K=4):
    """val [C] bf16, prev_buf [K-1, C] bf16 (updated in place via prev_out),
    conv_w_idx [C, K] fp32. Returns silu(conv) [C] bf16."""
    out = torch.empty(C, dtype=torch.bfloat16, device=val.device)
    BLOCK_C = 256
    _short_conv_kernel[(triton.cdiv(C, BLOCK_C),)](
        val, prev_buf, conv_w_idx, out, prev_buf, C=C, K=K, BLOCK_C=BLOCK_C, num_warps=4)
    return out


@triton.jit
def _silu_mul_kernel(g_ptr, u_ptr, o_ptr, D, BD: tl.constexpr):
    pid_m = tl.program_id(0)
    pid_d = tl.program_id(1)
    offs = pid_d * BD + tl.arange(0, BD)
    base = pid_m * D + offs
    g = tl.load(g_ptr + base).to(tl.float32)
    u = tl.load(u_ptr + base).to(tl.float32)
    r = (g * tl.sigmoid(g)) * u
    tl.store(o_ptr + base, r.to(tl.bfloat16))


def silu_mul(g: torch.Tensor, u: torch.Tensor) -> torch.Tensor:
    """out[k,m] = silu(g)*u, bf16. Inputs bf16 [k,m]."""
    k, m = g.shape
    o = torch.empty_like(g)
    BD = 256
    _silu_mul_kernel[(k, triton.cdiv(m, BD))](g, u, o, m, BD=BD, num_warps=4)
    return o


@triton.jit
def _wsum_kernel(d_ptr, w_ptr, o_ptr, D, K: tl.constexpr, BD: tl.constexpr):
    pid = tl.program_id(0)
    offs = pid * BD + tl.arange(0, BD)
    acc = tl.zeros([BD], dtype=tl.float32)
    for k in range(K):
        dk = tl.load(d_ptr + k * D + offs).to(tl.float32)
        wk = tl.load(w_ptr + k)
        acc += wk * dk
    tl.store(o_ptr + offs, acc.to(tl.bfloat16))


def weighted_sum(d_r: torch.Tensor, w: torch.Tensor) -> torch.Tensor:
    """out[d] = sum_k w[k]*d_r[k,d]. d_r bf16 [k,d], w fp32 [k]."""
    k, d = d_r.shape
    o = torch.empty(d, dtype=torch.bfloat16, device=d_r.device)
    BD = 256
    _wsum_kernel[(triton.cdiv(d, BD),)](d_r, w, o, d, K=k, BD=BD, num_warps=4)
    return o


@triton.jit
def _rope_kernel(x_ptr, cos_ptr, sin_ptr, o_ptr, NPAIRS,
                 HALF: tl.constexpr, BP: tl.constexpr):
    pid = tl.program_id(0)
    pids = pid * BP + tl.arange(0, BP)
    mask = pids < NPAIRS
    row = pids // HALF
    loc = pids % HALF
    e0 = row * (2 * HALF) + 2 * loc
    e1 = e0 + 1
    x0 = tl.load(x_ptr + e0, mask=mask, other=0.0).to(tl.float32)
    x1 = tl.load(x_ptr + e1, mask=mask, other=0.0).to(tl.float32)
    c = tl.load(cos_ptr + loc, mask=mask, other=0.0)
    s = tl.load(sin_ptr + loc, mask=mask, other=0.0)
    tl.store(o_ptr + e0, (x0 * c - x1 * s).to(tl.bfloat16), mask=mask)
    tl.store(o_ptr + e1, (x1 * c + x0 * s).to(tl.bfloat16), mask=mask)


def apply_rope_fused(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
    """Fused RoPE on x [..., D] (D = qk_rope). Returns bf16."""
    D = x.shape[-1]
    half = D // 2
    npairs = x.numel() // 2
    o = torch.empty_like(x)
    BP = 128
    _rope_kernel[(triton.cdiv(npairs, BP),)](x, cos, sin, o, npairs, HALF=half, BP=BP, num_warps=2)
    return o


def _rmsnorm_eager(x: torch.Tensor, w: torch.Tensor) -> torch.Tensor:
    xf = x.float()
    xf = xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + EPS)
    return (xf * w.float()).to(x.dtype)


def _rope_cossin(pos, dim: int, theta: float, device):
    inv = 1.0 / (theta ** (torch.arange(0, dim, 2, device=device, dtype=torch.float32) / dim))
    ang = pos * inv
    return torch.cos(ang), torch.sin(ang)


def _apply_rope(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
    xf = x.float()
    even, odd = xf[..., [REDACTED: IP]], xf[..., [REDACTED: IP]]
    out = torch.empty_like(xf)
    out[..., [REDACTED: IP]] = even * cos - odd * sin
    out[..., [REDACTED: IP]] = odd * cos + even * sin
    return out.to(x.dtype)


def _dequant_full(ql: QuantLinear) -> torch.Tensor:
    """Materialize full bf16 weight (only used for the small kv_b)."""
    K = ql.in_f
    wu = torch.empty((K, ql.out_f), dtype=torch.uint8, device=ql.w_q.device)
    wu[[REDACTED: IP]] = ql.w_q & 0xF
    wu[[REDACTED: IP]] = (ql.w_q >> 4) & 0xF
    s = ql.scales.repeat_interleave(ql.group, dim=0)
    z = ql.zeros.repeat_interleave(ql.group, dim=0)
    return (wu.to(torch.bfloat16) - z) * s


# --------------------------------------------------------------------------- #
# layers
# --------------------------------------------------------------------------- #
class KDA(nn.Module):
    def __init__(self, cfg: Config):
        super().__init__()
        self.cfg = cfg
        H, Dk, d = cfg.kda_heads, cfg.kda_head_dim, cfg.hidden
        self.q_proj = QuantLinear(d, H * Dk, cfg.group)
        self.k_proj = QuantLinear(d, H * Dk, cfg.group)
        self.v_proj = QuantLinear(d, H * Dk, cfg.group)
        self.g_proj = QuantLinear(d, H * Dk, cfg.group)
        self.beta_proj = nn.Linear(d, H, bias=False, dtype=cfg.dtype)
        self.conv_w = nn.Parameter(torch.empty(3, H * Dk, cfg.short_conv, dtype=cfg.dtype))
        self.o_proj = QuantLinear(H * Dk, d, cfg.group)
        self.scale = Dk ** -0.5
        self._qkvg = None       # fused q/k/v/g weight table (lazy, post-load)
        self._qkvg_idx = None

    def _fuse_qkvg(self):
        if self._qkvg is None or self._qkvg[0].device != self.q_proj.w_q.device:
            wq = torch.stack([self.q_proj.w_q, self.k_proj.w_q,
                              self.v_proj.w_q, self.g_proj.w_q], dim=0).contiguous()
            s = torch.stack([self.q_proj.scales, self.k_proj.scales,
                             self.v_proj.scales, self.g_proj.scales], dim=0).contiguous()
            z = torch.stack([self.q_proj.zeros, self.k_proj.zeros,
                             self.v_proj.zeros, self.g_proj.zeros], dim=0).contiguous()
            self._qkvg = (wq, s, z)
            self._qkvg_idx = torch.arange(4, device=wq.device)
        return self._qkvg

    def _short_conv_ip(self, val, prev_buf, idx):
        # in-place rolling conv window (graph-safe: prev_buf updated via copy_)
        win = torch.cat([prev_buf, val[None]], dim=0)
        w = self.conv_w[idx].float().transpose(0, 1)
        out = F.silu((win.float() * w).sum(0)).to(val.dtype)
        prev_buf.copy_(win[1:])
        return out

    def step_static(self, x, b):
        H, Dk = self.cfg.kda_heads, self.cfg.kda_head_dim
        d = self.cfg.hidden
        C = H * Dk
        wq, s, z = self._fuse_qkvg()
        qkvg = w4_gemv_batched(x, wq, s, z, self._qkvg_idx, d, C)        # [4, C] bf16
        q = _short_conv_fused(qkvg[0], b["cq"], self.conv_w[0], C)
        k = _short_conv_fused(qkvg[1], b["ck"], self.conv_w[1], C)
        v = _short_conv_fused(qkvg[2], b["cv"], self.conv_w[2], C)
        qf = (q.view(H, Dk).float() * self.scale).reshape(-1)
        kf = k.view(H, Dk).float().reshape(-1)
        vf = v.view(H, Dk).float().reshape(-1)
        beta = torch.sigmoid(self.beta_proj(x).float())                  # [H]
        o = _kda_recur(b["S"], qf, kf, vf, qkvg[3].reshape(-1), beta, H, Dk)
        return self.o_proj(o.reshape(H * Dk).to(torch.bfloat16))

    # eager path (kept for safety / non-graph use)
    def step(self, x, st):
        H, Dk = self.cfg.kda_heads, self.cfg.kda_head_dim
        q = self.q_proj(x)
        k = self.k_proj(x)
        v = self.v_proj(x)
        q, st["cq"] = self._short_conv_ip(q, st["cq"].clone(), 0)
        k, st["ck"] = self._short_conv_ip(k, st["ck"].clone(), 1)
        v, st["cv"] = self._short_conv_ip(v, st["cv"].clone(), 2)
        q = q.view(H, Dk).float() * self.scale
        k = k.view(H, Dk).float()
        v = v.view(H, Dk).float()
        g = (-F.softplus(self.g_proj(x).float())).view(H, Dk)
        beta = torch.sigmoid(self.beta_proj(x).float())
        S = st["S"].clone() * g.exp()[:, :, None]
        pred = (S * k[:, :, None]).sum(1)
        S = S + beta[:, None, None] * k[:, :, None] * (v - pred)[:, None, :]
        o = (S * q[:, :, None]).sum(1)
        st["S"] = S
        return self.o_proj(o.reshape(H * Dk).to(torch.bfloat16))


class MLA(nn.Module):
    def __init__(self, cfg: Config):
        super().__init__()
        self.cfg = cfg
        H, d = cfg.mla_heads, cfg.hidden
        self.q_proj = QuantLinear(d, H * (cfg.qk_nope + cfg.qk_rope), cfg.group)
        self.kv_a = QuantLinear(d, cfg.kv_lora + cfg.qk_rope, cfg.group)
        self.kv_b = QuantLinear(cfg.kv_lora, H * (cfg.qk_nope + cfg.v_head), cfg.group)
        self.o_proj = QuantLinear(H * cfg.v_head, d, cfg.group)
        self.scale = (cfg.qk_nope + cfg.qk_rope) ** -0.5
        self._kv_b_bf = None
        self._W_nope = None
        self._W_v = None
        self._arange = None

    def _kv_b_split(self):
        if self._W_nope is None or self._W_nope.device != self.kv_b.w_q.device:
            Wkv = _dequant_full(self.kv_b).float().view(self.cfg.kv_lora, self.cfg.mla_heads,
                                                        self.cfg.qk_nope + self.cfg.v_head)
            self._W_nope = Wkv[:, :, :self.cfg.qk_nope].contiguous()
            self._W_v = Wkv[:, :, self.cfg.qk_nope:].contiguous()
        return self._W_nope, self._W_v

    def step_static(self, x, b):
        cfg = self.cfg
        H = cfg.mla_heads
        pad = b["c_kv"]          # [CAP, 512] bf16, padded
        krop = b["k_rope"]       # [CAP, 64]
        seq = b["seq"]           # [1] int64, current length = new token position
        pos = seq[0]
        q = self.q_proj(x).view(H, cfg.qk_nope + cfg.qk_rope)
        q_nope = q[:, :cfg.qk_nope].float()
        q_rope = q[:, cfg.qk_nope:]
        kv = self.kv_a(x)
        c_new = kv[:cfg.kv_lora]
        kr_new = kv[cfg.kv_lora:]
        cos, sin = _rope_cossin(pos, cfg.qk_rope, cfg.rope_theta, x.device)
        q_rope = apply_rope_fused(q_rope, cos, sin).float()
        kr_new = apply_rope_fused(kr_new, cos, sin)
        # in-place append into padded cache
        pad.index_copy_(0, seq, c_new[None])
        krop.index_copy_(0, seq, kr_new[None])
        seq.add_(1)

        W_nope, W_v = self._kv_b_split()
        ckv = pad.float()                                   # [CAP, 512]
        qabs = torch.einsum("hd,ihd->hi", q_nope, W_nope)   # [H, 512]
        # scores laid out [H, CAP] so softmax reduces along the contiguous dim
        score_nope = torch.einsum("hi,ci->hc", qabs, ckv)   # [H, CAP]
        score_rope = torch.einsum("hd,cd->hc", q_rope, krop.float())
        scores = (score_nope + score_rope) * self.scale
        if self._arange is None or self._arange.shape[0] != pad.shape[0]:
            self._arange = torch.arange(pad.shape[0], device=x.device)
        valid = (self._arange < seq)                        # [CAP]
        scores = scores.masked_fill(~valid[None, :], float("-inf"))
        p = torch.softmax(scores, dim=1)                    # [H, CAP]
        u = torch.einsum("hc,ci->hi", p, ckv)              # [H, 512]
        o = torch.einsum("hi,ihd->hd", u, W_v)             # [H, 128]
        return self.o_proj(o.reshape(H * cfg.v_head).to(torch.bfloat16))

    def step(self, x, st):
        # eager fallback (non-padded), kept for safety
        cfg = self.cfg
        H = cfg.mla_heads
        pos = st["c_kv"].shape[0]
        q = self.q_proj(x).view(H, cfg.qk_nope + cfg.qk_rope)
        q_nope = q[:, :cfg.qk_nope].float()
        q_rope = q[:, cfg.qk_nope:]
        kv = self.kv_a(x)
        c_kv = kv[:cfg.kv_lora]
        k_rope = kv[cfg.kv_lora:]
        cos, sin = _rope_cossin(pos, cfg.qk_rope, cfg.rope_theta, x.device)
        q_rope = _apply_rope(q_rope, cos, sin).float()
        k_rope = _apply_rope(k_rope, cos, sin)
        st["c_kv"] = torch.cat([st["c_kv"], c_kv[None]], 0)
        st["k_rope"] = torch.cat([st["k_rope"], k_rope[None]], 0)
        W_nope, W_v = self._kv_b_split()
        ckv = st["c_kv"].float()
        qabs = torch.einsum("hd,ihd->hi", q_nope, W_nope)
        score_nope = torch.einsum("lc,hc->lh", ckv, qabs)
        score_rope = torch.einsum("hd,ld->lh", q_rope, st["k_rope"].float())
        scores = (score_nope + score_rope) * self.scale
        p = torch.softmax(scores, dim=0)
        u = torch.einsum("lh,li->hi", p, ckv)
        o = torch.einsum("hi,ihd->hd", u, W_v)
        return self.o_proj(o.reshape(H * cfg.v_head).to(torch.bfloat16))


class MoE(nn.Module):
    def __init__(self, cfg: Config):
        super().__init__()
        self.cfg = cfg
        d, m, E = cfg.hidden, cfg.moe_inter, cfg.n_experts
        self.router = nn.Linear(d, E, bias=False, dtype=cfg.dtype)
        self.gate = QuantExperts(E, d, m, cfg.group)
        self.up = QuantExperts(E, d, m, cfg.group)
        self.down = QuantExperts(E, m, d, cfg.group)
        self.s_gate = QuantExperts(cfg.n_shared, d, m, cfg.group)
        self.s_up = QuantExperts(cfg.n_shared, d, m, cfg.group)
        self.s_down = QuantExperts(cfg.n_shared, m, d, cfg.group)
        self._sidx = None
        self._gu = None           # fused routed gate+up table [2E, ...]
        self._sgu = None          # fused shared gate+up table [2*n_shared, ...]

    def _fuse(self):
        if self._gu is None or self._gu[0].device != self.gate.w_q.device:
            self._gu = (torch.cat([self.gate.w_q, self.up.w_q], 0).contiguous(),
                        torch.cat([self.gate.scales, self.up.scales], 0).contiguous(),
                        torch.cat([self.gate.zeros, self.up.zeros], 0).contiguous())
            self._sgu = (torch.cat([self.s_gate.w_q, self.s_up.w_q], 0).contiguous(),
                         torch.cat([self.s_gate.scales, self.s_up.scales], 0).contiguous(),
                         torch.cat([self.s_gate.zeros, self.s_up.zeros], 0).contiguous())
            self._sidx = torch.arange(self.cfg.n_shared, device=self.gate.w_q.device)
        return self._gu

    def step(self, x):
        cfg = self.cfg
        d, m, E = cfg.hidden, cfg.moe_inter, cfg.n_experts
        gu_wq, gu_s, gu_z = self._fuse()
        probs = torch.softmax(self.router(x).float(), dim=-1)
        w, idx = torch.topk(probs, cfg.n_active)
        w = w / (w.sum() + 1e-9) * cfg.routed_scaling
        k = cfg.n_active
        # routed: fused gate+up (shared activation x)
        idx_gu = torch.cat([idx, idx + E], 0)
        gu = w4_gemv_batched(x, gu_wq, gu_s, gu_z, idx_gu, d, m)   # [2k, m] bf16
        hh = silu_mul(gu[:k], gu[k:])                              # [k, m] bf16
        d_r = self.down.forward_idx(hh, idx)                       # [k, d] bf16
        out = weighted_sum(d_r, w)                                 # [d] bf16
        # shared expert (fused gate+up)
        sgu_wq, sgu_s, sgu_z = self._sgu
        sidx_gu = torch.cat([self._sidx, self._sidx + cfg.n_shared], 0)
        sgu = w4_gemv_batched(x, sgu_wq, sgu_s, sgu_z, sidx_gu, d, m)  # [2*ns, m]
        sh = silu_mul(sgu[:cfg.n_shared], sgu[cfg.n_shared:])
        sd = self.s_down.forward_idx(sh, self._sidx)               # [ns, d]
        out = out + sd.sum(0)
        return out


class Block(nn.Module):
    def __init__(self, cfg: Config, kind: str):
        super().__init__()
        self.kind = kind
        self.attn_norm = nn.Parameter(torch.ones(cfg.hidden, dtype=cfg.dtype))
        self.moe_norm = nn.Parameter(torch.ones(cfg.hidden, dtype=cfg.dtype))
        self.attn = KDA(cfg) if kind == "K" else MLA(cfg)
        self.moe = MoE(cfg)

    def step_static(self, x, b):
        h = x + self.attn.step_static(_rmsnorm(x, self.attn_norm), b)
        return h + self.moe.step(_rmsnorm(h, self.moe_norm))

    def step(self, x, st):
        h = x + self.attn.step(_rmsnorm(x, self.attn_norm), st)
        return h + self.moe.step(_rmsnorm(h, self.moe_norm))


class Model(nn.Module):
    def __init__(self, cfg: Config):
        super().__init__()
        self.cfg = cfg
        self.blocks = nn.ModuleList(Block(cfg, k) for k in cfg.pattern)
        self._mla_idx = cfg.pattern.index("M")
        self._MARGIN = 128
        # graph / static-buffer state (lazy)
        self._h = None
        self._bufs = None
        self._cap = None
        self._graph = None
        self._py_seq = 0

    # -- static buffer management ------------------------------------------- #
    def _dev(self):
        return self.blocks[0].attn_norm.device

    def _alloc_kda(self):
        dev = self._dev()
        cfg = self.cfg
        H, Dk, C = cfg.kda_heads, cfg.kda_head_dim, cfg.kda_heads * cfg.kda_head_dim
        bufs = []
        for kind in cfg.pattern:
            if kind == "K":
                bufs.append({
                    "S": torch.zeros(H, Dk, Dk, device=dev, dtype=torch.float32),
                    "cq": torch.zeros(cfg.short_conv - 1, C, device=dev, dtype=cfg.dtype),
                    "ck": torch.zeros(cfg.short_conv - 1, C, device=dev, dtype=cfg.dtype),
                    "cv": torch.zeros(cfg.short_conv - 1, C, device=dev, dtype=cfg.dtype),
                })
            else:
                bufs.append(None)   # MLA allocated when ctx is known
        return bufs

    def _prime(self, hidden, state):
        dev = self._dev()
        cfg = self.cfg
        mla = self._mla_idx
        ctx = state[mla]["c_kv"].shape[0]
        need_cap = ctx + self._MARGIN
        if self._h is None or self._h.device != dev:
            self._h = torch.zeros(cfg.hidden, device=dev, dtype=cfg.dtype)
        if self._bufs is None:
            self._bufs = self._alloc_kda()
        if self._cap is None or need_cap > self._cap:
            self._cap = need_cap
            cap = self._cap
            self._bufs[mla] = {
                "c_kv": torch.zeros(cap, cfg.kv_lora, device=dev, dtype=cfg.dtype),
                "k_rope": torch.zeros(cap, cfg.qk_rope, device=dev, dtype=cfg.dtype),
                "seq": torch.zeros(1, device=dev, dtype=torch.int64),
            }
            self._graph = None   # shape changed -> recapture
        # copy hidden + KDA state
        self._h.copy_(hidden)
        for i, kind in enumerate(cfg.pattern):
            if kind == "K":
                self._bufs[i]["S"].copy_(state[i]["S"].to(torch.float32))
                self._bufs[i]["cq"].copy_(state[i]["cq"])
                self._bufs[i]["ck"].copy_(state[i]["ck"])
                self._bufs[i]["cv"].copy_(state[i]["cv"])
        # copy MLA cache into padded buffer
        mbuf = self._bufs[mla]
        cap = self._cap
        mbuf["c_kv"][:ctx].copy_(state[mla]["c_kv"])
        mbuf["c_kv"][ctx:cap].zero_()
        mbuf["k_rope"][:ctx].copy_(state[mla]["k_rope"])
        mbuf["k_rope"][ctx:cap].zero_()
        mbuf["seq"].fill_(ctx)
        self._py_seq = ctx

    def _step_static(self):
        h = self._h
        for i, blk in enumerate(self.blocks):
            h = blk.step_static(h, self._bufs[i])
        self._h.copy_(h)

    def _capture(self):
        s = torch.cuda.Stream()
        s.wait_stream(torch.cuda.current_stream())
        with torch.cuda.stream(s):
            for _ in range(3):
                self._step_static()
        torch.cuda.current_stream().wait_stream(s)
        g = torch.cuda.CUDAGraph()
        with torch.cuda.graph(g):
            self._step_static()
        self._graph = g

    def _is_mine(self, state):
        try:
            return state[self._mla_idx]["c_kv"].data_ptr() == self._bufs[self._mla_idx]["c_kv"].data_ptr()
        except Exception:
            return False

    def step(self, hidden, state):
        mine = self._bufs is not None and self._is_mine(state) and hidden.data_ptr() == self._h.data_ptr()
        if not mine:
            self._prime(hidden, state)
            if self._graph is None:
                self._prime(hidden, state)   # reset after warmup mutation
                self._capture()
                self._prime(hidden, state)   # restore initial state for first real replay
        self._graph.replay()
        self._py_seq += 1
        return self._h, self._make_state()

    def _make_state(self):
        out = []
        for i, kind in enumerate(self.cfg.pattern):
            if kind == "K":
                b = self._bufs[i]
                out.append({"S": b["S"], "cq": b["cq"], "ck": b["ck"], "cv": b["cv"]})
            else:
                b = self._bufs[i]
                n = self._py_seq
                out.append({"c_kv": b["c_kv"][:n], "k_rope": b["k_rope"][:n]})
        return out


def init_state(cfg: Config, context_len: int, seed: int) -> list:
    dev = torch.device("cuda:0")
    g = torch.Generator(device=dev).manual_seed(seed)
    H, Dk = cfg.kda_heads, cfg.kda_head_dim
    C = H * Dk
    state = []
    for kind in cfg.pattern:
        if kind == "K":
            state.append({
                "S": torch.randn(H, Dk, Dk, device=dev, generator=g) * 0.05,
                "cq": torch.randn(cfg.short_conv - 1, C, device=dev, generator=g, dtype=cfg.dtype) * 0.1,
                "ck": torch.randn(cfg.short_conv - 1, C, device=dev, generator=g, dtype=cfg.dtype) * 0.1,
                "cv": torch.randn(cfg.short_conv - 1, C, device=dev, generator=g, dtype=cfg.dtype) * 0.1,
            })
        else:
            state.append({
                "c_kv": torch.randn(context_len, cfg.kv_lora, device=dev, generator=g, dtype=cfg.dtype) * 0.1,
                "k_rope": torch.randn(context_len, cfg.qk_rope, device=dev, generator=g, dtype=cfg.dtype) * 0.1,
            })
    return state


def init_token(cfg: Config, seed: int) -> torch.Tensor:
    dev = torch.device("cuda:0")
    g = torch.Generator(device=dev).manual_seed(seed + 1)
    return torch.randn(cfg.hidden, device=dev, generator=g, dtype=cfg.dtype) * 0.25

20260619_084649_zai-claude_glm-5.2_02_kimi_linear_decode