YMRohit's picture
Add in-Space offgrid/local mode (ZeroGPU H200 + in-process referee)
0118c5e verified
Raw
History Blame Contribute Delete
52.1 kB
"""OUROBOROS op suite — the SPECS the proposer writes kernels for.
Mirror of `sec_sqli/discovery_specialist`'s environment definition (`OBJ`/`PARAM`/
`ENVS`), but the "environment" here is a fusion op whose ground truth is a PyTorch
reference and whose grounded reward is a measured wall-clock speedup.
Each `OpSpec` is the immutable problem statement for one op:
- `reference(*inputs) -> Tensor` : the PyTorch ground truth (correctness oracle).
- `make_inputs(rng) -> tuple` : ADVERSARIAL randomized inputs — shape, dtype AND
magnitude vary, so a kernel that is only correct on
benign N(0,1) inputs (e.g. softmax with no
max-subtraction) FAILS. This is the GPU analog of
dvwa_oracle's benign-baseline / anti-pattern-match
negative controls.
- `tol(dtype)` : rtol/atol DERIVED from fp accumulation, never
hand-tuned to make a kernel pass.
- `signature_hint` : goes into the proposer prompt.
- The honest baselines (eager + torch.compile) are built by the harness, not stored
here, so the same `reference` defines both ground truth and the bar.
Scope is deliberately HARD-narrowed to FUSION wins (ops where eager launches several
kernels and Triton can fuse them). We do NOT try to beat cuBLAS at dense GEMM — that is
the losing-the-window trap called out in the brief.
A candidate KERNEL is a Python source string that, when exec'd in a namespace already
holding {torch, triton, tl}, defines a callable `run(*inputs) -> Tensor` matching the
op's reference signature. The harness is the only thing that ever runs it.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Callable
import torch
# ----------------------------------------------------------------------------------------
# Tolerances DERIVED from dtype accumulation behaviour (not tuned to pass).
# A reduction over D elements accumulates ~sqrt(D) * eps_machine relative error; we give a
# comfortable but principled envelope per storage dtype. Internals always accumulate in fp32.
# ----------------------------------------------------------------------------------------
_TOL = {
torch.float32: (2e-4, 2e-5),
torch.float16: (2e-2, 2e-3),
torch.bfloat16: (3e-2, 8e-3),
}
def tol_for(dtype: torch.dtype) -> tuple[float, float]:
return _TOL.get(dtype, (2e-2, 2e-3))
# ----------------------------------------------------------------------------------------
# Randomized regimes. `make_inputs` must sweep these so correctness is ADVERSARIAL: a
# kernel has to survive large magnitudes and low-precision dtypes, not just the easy case.
# ----------------------------------------------------------------------------------------
_DTYPES = [torch.float16, torch.bfloat16, torch.float32]
_SCALES = [1.0, 8.0, 64.0] # magnitude sweep — exposes overflow / missing max-sub
_ROWLEN = [128, 512, 1024, 4096, 4097, 8192] # incl. non-power-of-2 (masking correctness)
_NROWS = [8, 64, 1000, 4096]
def _pick(rng, xs):
return xs[rng.randrange(len(xs))]
def _randn(rng, shape, dtype, scale, dev="cuda"):
g = torch.Generator(device=dev).manual_seed(rng.randrange(2**31))
return (torch.randn(shape, generator=g, device=dev, dtype=torch.float32) * scale).to(dtype)
# ----------------------------------------------------------------------------------------
# References (ground truth). Each upcasts to fp32 for the numerically-sensitive reduction
# exactly as a correct kernel must — so allclose tests the FUSION, not a dtype mismatch.
# ----------------------------------------------------------------------------------------
def _rmsnorm_ref(x, w, eps: float = 1e-6):
xf = x.float()
rms = torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps)
return (xf * rms).to(x.dtype) * w
def _softmax_ref(x):
return torch.softmax(x.float(), dim=-1).to(x.dtype)
def _swiglu_ref(gate, up):
# the FFN activation fusion: SiLU(gate) * up (elementwise, multi-launch in eager)
return (torch.nn.functional.silu(gate.float()) * up.float()).to(gate.dtype)
def _add_rmsnorm_ref(x, residual, w, eps: float = 1e-6):
h = (x.float() + residual.float())
rms = torch.rsqrt(h.pow(2).mean(-1, keepdim=True) + eps)
return (h * rms).to(x.dtype) * w
def _rope_ref(x, cos, sin):
# LLaMA "rotate_half" RoPE: out = x*cos + rotate_half(x)*sin,
# rotate_half(x) = cat(-x[D/2:], x[:D/2]). Eager: a cat (alloc) + 2 muls + add (multi-launch).
D = x.shape[-1]; h = D // 2
xf = x.float()
rot = torch.cat([-xf[..., h:], xf[..., :h]], dim=-1)
return (xf * cos.float() + rot * sin.float()).to(x.dtype)
def _layernorm_ref(x, w, b, eps: float = 1e-5):
# full LayerNorm: subtract mean, divide by std, affine. Two reductions (mean then var) +
# affine — eager launches several kernels. Distinct from RMSNorm (mean-subtraction + bias).
xf = x.float()
mu = xf.mean(-1, keepdim=True)
xc = xf - mu
var = (xc * xc).mean(-1, keepdim=True)
return (xc * torch.rsqrt(var + eps) * w.float() + b.float()).to(x.dtype)
def _add_layernorm_ref(x, residual, w, b, eps: float = 1e-5):
h = x.float() + residual.float()
mu = h.mean(-1, keepdim=True)
hc = h - mu
var = (hc * hc).mean(-1, keepdim=True)
return (hc * torch.rsqrt(var + eps) * w.float() + b.float()).to(x.dtype)
_GELU_C = 0.7978845608028654 # sqrt(2/pi)
def _geglu_ref(gate, up):
# GeGLU: gelu_tanh(gate) * up (the FFN gate with GELU instead of SiLU). tanh approximation.
g = gate.float()
gelu = 0.5 * g * (1.0 + torch.tanh(_GELU_C * (g + 0.044715 * g * g * g)))
return (gelu * up.float()).to(gate.dtype)
def _qknorm_rope_ref(x, w, cos, sin, eps: float = 1e-6):
# FUSION CHAIN (reduction -> gather): per-head RMSNorm then RoPE — the Qwen-style QK-norm.
# The composed reference; max-autotune fuses the chain too, so beating it means the model
# found a schedule inductor's search missed (keeping the rms scale in-register, no
# intermediate materialized).
xf = x.float()
rms = torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps)
n = xf * rms * w.float()
D = x.shape[-1]; h = D // 2
rot = torch.cat([-n[..., h:], n[..., :h]], dim=-1)
return (n * cos.float() + rot * sin.float()).to(x.dtype)
# ---- comprehensive suite: activations, reductions, softmax family, chains, quant ----------
def _gelu_ref(x):
g = x.float()
return (0.5 * g * (1.0 + torch.tanh(_GELU_C * (g + 0.044715 * g * g * g)))).to(x.dtype)
def _silu_ref(x):
g = x.float()
return (g * torch.sigmoid(g)).to(x.dtype)
def _relu2_ref(x):
g = torch.relu(x.float())
return (g * g).to(x.dtype)
def _bias_gelu_ref(x, bias):
g = x.float() + bias.float()
return (0.5 * g * (1.0 + torch.tanh(_GELU_C * (g + 0.044715 * g * g * g)))).to(x.dtype)
def _reglu_ref(gate, up):
return (torch.relu(gate.float()) * up.float()).to(gate.dtype)
def _l2norm_ref(x, eps: float = 1e-6):
xf = x.float()
return (xf * torch.rsqrt(xf.pow(2).sum(-1, keepdim=True) + eps)).to(x.dtype)
def _log_softmax_ref(x):
return torch.log_softmax(x.float(), dim=-1).to(x.dtype)
def _softmax_scale_ref(x, scale):
return torch.softmax(x.float() * scale.float(), dim=-1).to(x.dtype)
def _layernorm_gelu_ref(x, w, b, eps: float = 1e-5):
xf = x.float()
mu = xf.mean(-1, keepdim=True)
xc = xf - mu
var = (xc * xc).mean(-1, keepdim=True)
ln = xc * torch.rsqrt(var + eps) * w.float() + b.float()
return (0.5 * ln * (1.0 + torch.tanh(_GELU_C * (ln + 0.044715 * ln * ln * ln)))).to(x.dtype)
def _add_rmsnorm_rope_ref(x, residual, w, cos, sin, eps: float = 1e-6):
h = x.float() + residual.float()
n = h * torch.rsqrt(h.pow(2).mean(-1, keepdim=True) + eps) * w.float()
D = x.shape[-1]; hd = D // 2
rot = torch.cat([-n[..., hd:], n[..., :hd]], dim=-1)
return (n * cos.float() + rot * sin.float()).to(x.dtype)
def _dequant_int8_ref(q, scale):
# per-row int8 weight dequantization: out = q * scale (memory-bound, NON-GEMM)
return (q.float() * scale.float()).to(torch.float16)
# ---- V2 standalone additions: real LLM ops beyond the chain grammar ----------------------
_SOFTCAP = 30.0
def _softcap_softmax_ref(x):
# Gemma2-style logit softcapping then softmax: softmax(cap * tanh(x / cap)).
t = _SOFTCAP * torch.tanh(x.float() / _SOFTCAP)
return torch.softmax(t, dim=-1).to(x.dtype)
def _rmsnorm_gemma_ref(x, w, eps: float = 1e-6):
# Gemma-style RMSNorm: scale by (1 + w), not w. The +1 is the classic silent-wrongness trap.
xf = x.float()
rms = torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps)
return (xf * rms * (1.0 + w.float())).to(x.dtype)
def _glu_ref(gate, up):
# the ORIGINAL gated linear unit: sigmoid(gate) * up
return (torch.sigmoid(gate.float()) * up.float()).to(gate.dtype)
def _rope_interleaved_ref(x, cos, sin):
# GPT-J / interleaved RoPE: pairs (x[2i], x[2i+1]) rotated by (cos[i], sin[i]).
xf = x.float()
x1, x2 = xf[..., 0::2], xf[..., 1::2]
c, s = cos.float(), sin.float()
out = torch.empty_like(xf)
out[..., 0::2] = x1 * c - x2 * s
out[..., 1::2] = x2 * c + x1 * s
return out.to(x.dtype)
def _cross_entropy_ref(x, tgt):
# fused per-row cross-entropy (the Liger flagship fusion): -log_softmax(x)[tgt], no reduction.
return torch.nn.functional.cross_entropy(x.float(), tgt, reduction="none").to(x.dtype)
# ---- INVENTION suite (V2.7): problem classes the model was never trained on --------------
def _cumsum_ref(x):
# row-wise inclusive prefix sum — a SCAN, not a reduction: a different parallel
# algorithm class (carry propagation across blocks) from everything in the suite.
return torch.cumsum(x.float(), dim=-1).to(x.dtype)
def _entropy_ref(x):
# per-row Shannon entropy of softmax(x), fused from logits: H = lse(x) - sum(x*p).
xf = x.float()
lse = torch.logsumexp(xf, dim=-1, keepdim=True)
p = torch.exp(xf - lse)
return (lse.squeeze(-1) - (xf * p).sum(-1)).to(x.dtype)
def _kl_div_ref(x, y):
# per-row KL(softmax(x) || softmax(y)) from raw logits — the distillation op.
# DOUBLE logsumexp fusion; both must be max-subtracted.
xf, yf = x.float(), y.float()
lx = xf - torch.logsumexp(xf, dim=-1, keepdim=True)
ly = yf - torch.logsumexp(yf, dim=-1, keepdim=True)
return (torch.exp(lx) * (lx - ly)).sum(-1).to(x.dtype)
# ----------------------------------------------------------------------------------------
@dataclass
class OpSpec:
name: str
reference: Callable
make_inputs: Callable # rng -> tuple[Tensor, ...] (ADVERSARIAL random, for correctness)
bench_inputs: Callable # () -> tuple[Tensor, ...] (FIXED large fp16, for timing)
stress_inputs: Callable # () -> list[tuple] GUARANTEED killer cases (high-scale fp16/bf16,
# odd N). Run on EVERY eval so a wrong kernel is
# caught deterministically, never by seed luck.
signature_hint: str
notes: str = ""
extra: dict = field(default_factory=dict)
# Per-op tolerance override — DERIVED from the op's numerics (documented at the spec),
# never tuned to make a kernel pass. Needed where the global elementwise envelope is
# the wrong yardstick (e.g. scans: error tracks the running-path magnitude; entropy:
# the REFERENCE itself carries catastrophic cancellation).
tol_override: dict = field(default_factory=dict)
def tol(self, dtype: torch.dtype) -> tuple[float, float]:
return self.tol_override.get(dtype, tol_for(dtype))
# Guaranteed-hard cases: large magnitude (overflow trap), low precision, NON-power-of-2 row
# length (masking trap), small odd row count. These are run on every correctness check so the
# negative controls (no max-subtract / no rsqrt) fail DETERMINISTICALLY, not probabilistically.
def _stress_1tensor(N=4097, M=37):
return [(_fixed((M, N), torch.float16, 64.0, seed=91),),
(_fixed((M, N), torch.bfloat16, 64.0, seed=92),),
(_fixed((3, 8192), torch.float16, 32.0, seed=93),)]
def _stress_rmsnorm(N=4097, M=37):
return [(_fixed((M, N), torch.float16, 64.0, 91), _fixed((N,), torch.float16, 1.0, 94)),
(_fixed((M, N), torch.bfloat16, 64.0, 92), _fixed((N,), torch.bfloat16, 1.0, 95)),
(_fixed((3, 8192), torch.float16, 32.0, 93), _fixed((8192,), torch.float16, 1.0, 96))]
def _stress_swiglu(N=4097, M=37):
return [(_fixed((M, N), torch.float16, 64.0, 91), _fixed((M, N), torch.float16, 8.0, 94)),
(_fixed((M, N), torch.bfloat16, 64.0, 92), _fixed((M, N), torch.bfloat16, 8.0, 95))]
def _stress_add_rmsnorm(N=4097, M=37):
return [(_fixed((M, N), torch.float16, 64.0, 91), _fixed((M, N), torch.float16, 64.0, 94),
_fixed((N,), torch.float16, 1.0, 97)),
(_fixed((M, N), torch.bfloat16, 64.0, 92), _fixed((M, N), torch.bfloat16, 64.0, 95),
_fixed((N,), torch.bfloat16, 1.0, 98))]
# A single FIXED, realistic LLM-regime shape so a candidate's speedup is COMPARABLE across
# the whole search (apples-to-apples), and the bench input is identical for kernel + both
# baselines. fp16, deterministic seed.
_BENCH_M, _BENCH_N = 8192, 4096
def _fixed(shape, dtype=torch.float16, scale=1.0, seed=1234, dev="cuda"):
g = torch.Generator(device=dev).manual_seed(seed)
return (torch.randn(shape, generator=g, device=dev, dtype=torch.float32) * scale).to(dtype)
def _bench_rmsnorm():
return (_fixed((_BENCH_M, _BENCH_N), seed=1), _fixed((_BENCH_N,), seed=2))
def _bench_softmax():
return (_fixed((_BENCH_M, _BENCH_N), seed=3),)
def _bench_swiglu():
return (_fixed((_BENCH_M, _BENCH_N), seed=4), _fixed((_BENCH_M, _BENCH_N), seed=5))
def _bench_add_rmsnorm():
return (_fixed((_BENCH_M, _BENCH_N), seed=6), _fixed((_BENCH_M, _BENCH_N), seed=7),
_fixed((_BENCH_N,), seed=8))
def _rope_costab(M, D, seed, dtype=torch.float16, dev="cuda"):
g = torch.Generator(device=dev).manual_seed(seed)
ang = torch.randn((M, D // 2), generator=g, device=dev, dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
return torch.cat([c, c], -1).to(dtype), torch.cat([s, s], -1).to(dtype)
def _bench_rope():
M, D = 32768, 128
cos, sin = _rope_costab(M, D, 21)
return (_fixed((M, D), seed=20), cos, sin)
def _bench_layernorm():
return (_fixed((_BENCH_M, _BENCH_N), seed=30), _fixed((_BENCH_N,), seed=31), _fixed((_BENCH_N,), seed=32))
def _bench_add_layernorm():
return (_fixed((_BENCH_M, _BENCH_N), seed=33), _fixed((_BENCH_M, _BENCH_N), seed=34),
_fixed((_BENCH_N,), seed=35), _fixed((_BENCH_N,), seed=36))
def _bench_geglu():
return (_fixed((_BENCH_M, _BENCH_N), seed=37), _fixed((_BENCH_M, _BENCH_N), seed=38))
def _bench_qknorm_rope():
M, D = 32768, 128
cos, sin = _rope_costab(M, D, 41)
return (_fixed((M, D), seed=40), _fixed((D,), seed=42), cos, sin)
# ---- input generators (adversarial) ----------------------------------------------------
def _mk_rmsnorm(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
x = _randn(rng, (M, N), dt, sc)
w = _randn(rng, (N,), dt, 1.0)
return (x, w)
def _mk_softmax(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc),)
def _mk_swiglu(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, 1.0))
def _mk_add_rmsnorm(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, sc), _randn(rng, (N,), dt, 1.0))
_HEADDIM = [64, 128, 256] # even head dims (RoPE)
def _mk_rope(rng):
M, D, dt, sc = _pick(rng, _NROWS), _pick(rng, _HEADDIM), _pick(rng, _DTYPES), _pick(rng, _SCALES)
g = torch.Generator(device="cuda").manual_seed(rng.randrange(2**31))
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
cos = torch.cat([c, c], -1).to(dt); sin = torch.cat([s, s], -1).to(dt)
return (_randn(rng, (M, D), dt, sc), cos, sin)
def _stress_rope():
out = []
for D, dt in [(128, torch.float16), (256, torch.bfloat16), (64, torch.float16)]:
g = torch.Generator(device="cuda").manual_seed(700 + D)
ang = torch.randn((37, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
out.append((_fixed((37, D), dt, 64.0, 700 + D),
torch.cat([c, c], -1).to(dt), torch.cat([s, s], -1).to(dt)))
return out
def _mk_layernorm(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (N,), dt, 1.0), _randn(rng, (N,), dt, 1.0))
def _mk_add_layernorm(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, sc),
_randn(rng, (N,), dt, 1.0), _randn(rng, (N,), dt, 1.0))
def _mk_geglu(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, 1.0))
def _stress_layernorm():
return [(_fixed((37, 4097), torch.float16, 64.0, 91), _fixed((4097,), torch.float16, 1.0, 94),
_fixed((4097,), torch.float16, 1.0, 95)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 92), _fixed((4097,), torch.bfloat16, 1.0, 96),
_fixed((4097,), torch.bfloat16, 1.0, 97))]
def _stress_add_layernorm():
return [(_fixed((37, 4097), torch.float16, 64.0, 91), _fixed((37, 4097), torch.float16, 64.0, 92),
_fixed((4097,), torch.float16, 1.0, 94), _fixed((4097,), torch.float16, 1.0, 95)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 96), _fixed((37, 4097), torch.bfloat16, 64.0, 97),
_fixed((4097,), torch.bfloat16, 1.0, 98), _fixed((4097,), torch.bfloat16, 1.0, 99))]
def _stress_geglu():
return [(_fixed((37, 4097), torch.float16, 64.0, 91), _fixed((37, 4097), torch.float16, 8.0, 94)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 92), _fixed((37, 4097), torch.bfloat16, 8.0, 95))]
def _mk_qknorm_rope(rng):
M, D, dt, sc = _pick(rng, _NROWS), _pick(rng, _HEADDIM), _pick(rng, _DTYPES), _pick(rng, _SCALES)
g = torch.Generator(device="cuda").manual_seed(rng.randrange(2**31))
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
cos = torch.cat([c, c], -1).to(dt); sin = torch.cat([s, s], -1).to(dt)
return (_randn(rng, (M, D), dt, sc), _randn(rng, (D,), dt, 1.0), cos, sin)
def _stress_qknorm_rope():
out = []
for D, dt in [(128, torch.float16), (256, torch.bfloat16), (64, torch.float16)]:
g = torch.Generator(device="cuda").manual_seed(800 + D)
ang = torch.randn((37, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
out.append((_fixed((37, D), dt, 64.0, 800 + D), _fixed((D,), dt, 1.0, 810 + D),
torch.cat([c, c], -1).to(dt), torch.cat([s, s], -1).to(dt)))
return out
# ---------- comprehensive suite: input generators ----------------------------------------
def _mk_x(rng): # plain elementwise (M,N)
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc),)
def _mk_x_bias(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (N,), dt, 1.0))
def _mk_gate_up(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, 1.0))
def _mk_softmax_scale(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
scl = torch.tensor([0.05 + rng.random() * 1.5], device="cuda", dtype=dt)
return (_randn(rng, (M, N), dt, sc), scl)
def _mk_layernorm_gelu(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (N,), dt, 1.0), _randn(rng, (N,), dt, 1.0))
def _mk_add_rmsnorm_rope(rng):
M, D, dt, sc = _pick(rng, _NROWS), _pick(rng, _HEADDIM), _pick(rng, _DTYPES), _pick(rng, _SCALES)
g = torch.Generator(device="cuda").manual_seed(rng.randrange(2**31))
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
return (_randn(rng, (M, D), dt, sc), _randn(rng, (M, D), dt, sc), _randn(rng, (D,), dt, 1.0),
torch.cat([c, c], -1).to(dt), torch.cat([s, s], -1).to(dt))
def _int8(rng, shape, dev="cuda"):
g = torch.Generator(device=dev).manual_seed(rng.randrange(2**31))
return torch.randint(-127, 127, shape, generator=g, device=dev, dtype=torch.int8)
def _mk_dequant_int8(rng):
M, N = _pick(rng, _NROWS), _pick(rng, _ROWLEN)
q = _int8(rng, (M, N))
g = torch.Generator(device="cuda").manual_seed(rng.randrange(2**31))
scale = (torch.rand((M, 1), generator=g, device="cuda") * 0.05 + 0.005).to(torch.float16)
return (q, scale)
# bench inputs (fixed large)
def _bench_x(seed): return (_fixed((_BENCH_M, _BENCH_N), seed=seed),)
def _bench_gelu(): return _bench_x(50)
def _bench_silu(): return _bench_x(51)
def _bench_relu2(): return _bench_x(52)
def _bench_bias_gelu(): return (_fixed((_BENCH_M, _BENCH_N), seed=53), _fixed((_BENCH_N,), seed=54))
def _bench_reglu(): return (_fixed((_BENCH_M, _BENCH_N), seed=55), _fixed((_BENCH_M, _BENCH_N), seed=56))
def _bench_l2norm(): return _bench_x(57)
def _bench_log_softmax(): return _bench_x(58)
def _bench_softmax_scale(): return (_fixed((_BENCH_M, _BENCH_N), seed=59),
torch.tensor([0.125], device="cuda", dtype=torch.float16))
def _bench_layernorm_gelu(): return (_fixed((_BENCH_M, _BENCH_N), seed=60),
_fixed((_BENCH_N,), seed=61), _fixed((_BENCH_N,), seed=62))
def _bench_add_rmsnorm_rope():
M, D = 32768, 128; cos, sin = _rope_costab(M, D, 63)
return (_fixed((M, D), seed=64), _fixed((M, D), seed=65), _fixed((D,), seed=66), cos, sin)
_TALL_M = [4, 8, 16, 32]
_WIDE_N = [16384, 32768, 65536, 131072]
def _mk_rmsnorm_wide(rng):
M, N, dt, sc = _pick(rng, _TALL_M), _pick(rng, _WIDE_N), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (N,), dt, 1.0))
def _bench_rmsnorm_wide(): return (_fixed((8, 131072), seed=90), _fixed((131072,), seed=91))
def _stress_rmsnorm_wide():
return [(_fixed((8, 131072), torch.float16, 64.0, 90), _fixed((131072,), torch.float16, 1.0, 91)),
(_fixed((5, 65537), torch.bfloat16, 32.0, 92), _fixed((65537,), torch.bfloat16, 1.0, 93)),
(_fixed((16, 40000), torch.float16, 16.0, 94), _fixed((40000,), torch.float16, 1.0, 95))]
def _bench_dequant_int8():
g = torch.Generator(device="cuda").manual_seed(67)
q = torch.randint(-127, 127, (_BENCH_M, _BENCH_N), generator=g, device="cuda", dtype=torch.int8)
g2 = torch.Generator(device="cuda").manual_seed(68)
scale = (torch.rand((_BENCH_M, 1), generator=g2, device="cuda") * 0.05 + 0.005).to(torch.float16)
return (q, scale)
# stress (guaranteed hard) — high magnitude / low precision / odd N
def _stress_x():
return [(_fixed((37, 4097), torch.float16, 64.0, 71),), (_fixed((37, 4097), torch.bfloat16, 64.0, 72),),
(_fixed((3, 8192), torch.float16, 32.0, 73),)]
def _stress_x_bias():
return [(_fixed((37, 4097), torch.float16, 64.0, 71), _fixed((4097,), torch.float16, 4.0, 74)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 72), _fixed((4097,), torch.bfloat16, 4.0, 75))]
def _stress_gate_up():
return [(_fixed((37, 4097), torch.float16, 64.0, 71), _fixed((37, 4097), torch.float16, 8.0, 74)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 72), _fixed((37, 4097), torch.bfloat16, 8.0, 75))]
def _stress_softmax_scale():
return [(_fixed((37, 4097), torch.float16, 64.0, 71), torch.tensor([1.5], device="cuda", dtype=torch.float16)),
(_fixed((37, 4097), torch.bfloat16, 32.0, 72), torch.tensor([0.5], device="cuda", dtype=torch.bfloat16))]
def _stress_layernorm_gelu():
return [(_fixed((37, 4097), torch.float16, 64.0, 71), _fixed((4097,), torch.float16, 1.0, 74),
_fixed((4097,), torch.float16, 1.0, 75)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 72), _fixed((4097,), torch.bfloat16, 1.0, 76),
_fixed((4097,), torch.bfloat16, 1.0, 77))]
def _stress_add_rmsnorm_rope():
out = []
for D, dt in [(128, torch.float16), (256, torch.bfloat16)]:
g = torch.Generator(device="cuda").manual_seed(820 + D)
ang = torch.randn((37, D // 2), generator=g, device="cuda", dtype=torch.float32)
c = torch.cos(ang); s = torch.sin(ang)
out.append((_fixed((37, D), dt, 64.0, 820 + D), _fixed((37, D), dt, 64.0, 830 + D),
_fixed((D,), dt, 1.0, 840 + D), torch.cat([c, c], -1).to(dt), torch.cat([s, s], -1).to(dt)))
return out
def _stress_dequant_int8():
out = []
for M, N, sd in [(37, 4097, 71), (3, 8192, 72)]:
g = torch.Generator(device="cuda").manual_seed(sd)
q = torch.randint(-127, 127, (M, N), generator=g, device="cuda", dtype=torch.int8)
g2 = torch.Generator(device="cuda").manual_seed(sd + 1)
scale = (torch.rand((M, 1), generator=g2, device="cuda") * 0.1 + 0.005).to(torch.float16)
out.append((q, scale))
return out
# ---- V2 standalone ops: generators / bench / stress --------------------------------------
def _mk_rope_inter(rng):
M, D, dt, sc = _pick(rng, _NROWS), _pick(rng, _HEADDIM), _pick(rng, _DTYPES), _pick(rng, _SCALES)
g = torch.Generator(device="cuda").manual_seed(rng.randrange(2**31))
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
return (_randn(rng, (M, D), dt, sc), torch.cos(ang).to(dt), torch.sin(ang).to(dt))
def _bench_rope_inter():
M, D = 32768, 128
g = torch.Generator(device="cuda").manual_seed(140)
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
return (_fixed((M, D), seed=141), torch.cos(ang).to(torch.float16), torch.sin(ang).to(torch.float16))
def _stress_rope_inter():
out = []
for D, dt in [(128, torch.float16), (256, torch.bfloat16), (64, torch.float16)]:
g = torch.Generator(device="cuda").manual_seed(850 + D)
ang = torch.randn((37, D // 2), generator=g, device="cuda", dtype=torch.float32)
out.append((_fixed((37, D), dt, 64.0, 850 + D), torch.cos(ang).to(dt), torch.sin(ang).to(dt)))
return out
def _tgt(M, N, seed):
g = torch.Generator(device="cuda").manual_seed(seed)
return torch.randint(0, N, (M,), generator=g, device="cuda", dtype=torch.int64)
def _mk_cross_entropy(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _tgt(M, N, rng.randrange(2**31)))
def _bench_cross_entropy():
return (_fixed((_BENCH_M, _BENCH_N), seed=150), _tgt(_BENCH_M, _BENCH_N, 151))
def _stress_cross_entropy():
return [(_fixed((37, 4097), torch.float16, 64.0, 152), _tgt(37, 4097, 153)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 154), _tgt(37, 4097, 155)),
(_fixed((3, 8192), torch.float16, 32.0, 156), _tgt(3, 8192, 157))]
def _bench_glu(): return (_fixed((_BENCH_M, _BENCH_N), seed=160), _fixed((_BENCH_M, _BENCH_N), seed=161))
def _bench_softcap_softmax(): return _bench_x(162)
def _bench_rmsnorm_gemma(): return (_fixed((_BENCH_M, _BENCH_N), seed=163), _fixed((_BENCH_N,), seed=164))
# ---- invention suite: generators / bench / stress ----------------------------------------
def _mk_xy(rng):
M, N, dt, sc = _pick(rng, _NROWS), _pick(rng, _ROWLEN), _pick(rng, _DTYPES), _pick(rng, _SCALES)
return (_randn(rng, (M, N), dt, sc), _randn(rng, (M, N), dt, sc))
def _stress_xy():
return [(_fixed((37, 4097), torch.float16, 64.0, 171), _fixed((37, 4097), torch.float16, 64.0, 172)),
(_fixed((37, 4097), torch.bfloat16, 64.0, 173), _fixed((37, 4097), torch.bfloat16, 64.0, 174)),
(_fixed((3, 8192), torch.float16, 32.0, 175), _fixed((3, 8192), torch.float16, 32.0, 176))]
def _bench_cumsum(): return _bench_x(170)
def _bench_entropy(): return _bench_x(177)
def _bench_kl_div(): return (_fixed((_BENCH_M, _BENCH_N), seed=178), _fixed((_BENCH_M, _BENCH_N), seed=179))
SPECS: dict[str, OpSpec] = {
"rmsnorm": OpSpec(
name="rmsnorm",
reference=_rmsnorm_ref,
make_inputs=_mk_rmsnorm,
bench_inputs=_bench_rmsnorm,
stress_inputs=_stress_rmsnorm,
signature_hint=(
"def run(x, w): # x:(M,N) w:(N,) -> (M,N)\n"
" # y[i] = x[i] * rsqrt(mean(x[i]^2) + 1e-6) * w (RMSNorm, accumulate in fp32)"),
notes="row-wise normalise + per-channel scale; eager does square/mean/rsqrt/mul as separate launches.",
extra={"eps": 1e-6},
),
"softmax": OpSpec(
name="softmax",
reference=_softmax_ref,
make_inputs=_mk_softmax,
bench_inputs=_bench_softmax,
stress_inputs=_stress_1tensor,
signature_hint=(
"def run(x): # x:(M,N) -> (M,N)\n"
" # row-wise softmax. MUST subtract row-max before exp (numerical stability)."),
notes="classic online/row softmax; the max-subtraction is the correctness trap large scales expose.",
),
"swiglu": OpSpec(
name="swiglu",
reference=_swiglu_ref,
make_inputs=_mk_swiglu,
bench_inputs=_bench_swiglu,
stress_inputs=_stress_swiglu,
signature_hint=(
"def run(gate, up): # both (M,N) -> (M,N)\n"
" # SiLU(gate) * up where SiLU(z) = z * sigmoid(z) (FFN gate fusion)"),
notes="elementwise activation fusion; eager launches silu + mul separately.",
),
"add_rmsnorm": OpSpec(
name="add_rmsnorm",
reference=_add_rmsnorm_ref,
make_inputs=_mk_add_rmsnorm,
bench_inputs=_bench_add_rmsnorm,
stress_inputs=_stress_add_rmsnorm,
signature_hint=(
"def run(x, residual, w): # x,residual:(M,N) w:(N,) -> (M,N)\n"
" # h = x + residual; then RMSNorm(h) * w (fused residual-add + norm)"),
notes="the transformer block's add-then-norm; eager does add then a separate norm pass.",
extra={"eps": 1e-6},
),
"rope": OpSpec(
name="rope",
reference=_rope_ref,
make_inputs=_mk_rope,
bench_inputs=_bench_rope,
stress_inputs=_stress_rope,
signature_hint=(
"def run(x, cos, sin): # x,cos,sin all (M,D), D even -> (M,D)\n"
" # LLaMA rotate_half RoPE: out = x*cos + rotate_half(x)*sin,\n"
" # rotate_half(x) = concat(-x[:, D/2:], x[:, :D/2]). Accumulate in fp32."),
notes="fused rotary embedding; eager does a cat (alloc) + 2 muls + add as separate launches.",
),
"layernorm": OpSpec(
name="layernorm",
reference=_layernorm_ref,
make_inputs=_mk_layernorm,
bench_inputs=_bench_layernorm,
stress_inputs=_stress_layernorm,
signature_hint=(
"def run(x, w, b): # x:(M,N) w,b:(N,) -> (M,N)\n"
" # LayerNorm: y = (x-mean)/sqrt(var+1e-5)*w + b, over the last dim. fp32 reductions."),
notes="full layernorm (mean+var+affine); eager launches mean/var/normalize/affine separately.",
extra={"eps": 1e-5},
),
"add_layernorm": OpSpec(
name="add_layernorm",
reference=_add_layernorm_ref,
make_inputs=_mk_add_layernorm,
bench_inputs=_bench_add_layernorm,
stress_inputs=_stress_add_layernorm,
signature_hint=(
"def run(x, residual, w, b): # x,residual:(M,N) w,b:(N,) -> (M,N)\n"
" # h = x + residual; then LayerNorm(h)*w + b (fused residual-add + layernorm)"),
notes="residual-add + full layernorm; the transformer block's add-then-LN.",
extra={"eps": 1e-5},
),
"geglu": OpSpec(
name="geglu",
reference=_geglu_ref,
make_inputs=_mk_geglu,
bench_inputs=_bench_geglu,
stress_inputs=_stress_geglu,
signature_hint=(
"def run(gate, up): # both (M,N) -> (M,N)\n"
" # GeGLU: gelu_tanh(gate) * up, gelu_tanh(z)=0.5*z*(1+tanh(0.7978845608*(z+0.044715*z^3)))"),
notes="GELU-gated FFN fusion (tanh-approx GELU); eager launches gelu then mul separately.",
),
"qknorm_rope": OpSpec(
name="qknorm_rope",
reference=_qknorm_rope_ref,
make_inputs=_mk_qknorm_rope,
bench_inputs=_bench_qknorm_rope,
stress_inputs=_stress_qknorm_rope,
signature_hint=(
"def run(x, w, cos, sin): # x,cos,sin:(M,D) w:(D,), D even -> (M,D)\n"
" # FUSED QK-norm+RoPE: n = rmsnorm(x)*w (over D); then rope(n): \n"
" # out = n*cos + rotate_half(n)*sin. Keep the rms scale in-register (no\n"
" # intermediate n in DRAM). Accumulate the reduction in fp32."),
notes="reduction->gather fusion chain (Qwen-style QK-norm then RoPE); the bigger-discovery probe.",
extra={"eps": 1e-6},
),
# ---- comprehensive suite -------------------------------------------------------------
"gelu": OpSpec("gelu", _gelu_ref, _mk_x, _bench_gelu, _stress_x,
"def run(x): # (M,N)->(M,N) gelu_tanh(x)=0.5*x*(1+tanh(0.7978845608*(x+0.044715*x^3)))",
notes="GELU activation (tanh approx)."),
"silu": OpSpec("silu", _silu_ref, _mk_x, _bench_silu, _stress_x,
"def run(x): # (M,N)->(M,N) silu(x)=x*sigmoid(x)", notes="SiLU/Swish activation."),
"relu2": OpSpec("relu2", _relu2_ref, _mk_x, _bench_relu2, _stress_x,
"def run(x): # (M,N)->(M,N) relu(x)^2", notes="squared-ReLU activation (used in some FFNs)."),
"bias_gelu": OpSpec("bias_gelu", _bias_gelu_ref, _mk_x_bias, _bench_bias_gelu, _stress_x_bias,
"def run(x, bias): # x:(M,N) bias:(N,) -> (M,N) gelu_tanh(x + bias)",
notes="fused bias-add + GELU (the FFN up-proj epilogue)."),
"reglu": OpSpec("reglu", _reglu_ref, _mk_gate_up, _bench_reglu, _stress_gate_up,
"def run(gate, up): # both (M,N) -> (M,N) relu(gate) * up",
notes="ReGLU gated FFN fusion."),
"l2norm": OpSpec("l2norm", _l2norm_ref, _mk_x, _bench_l2norm, _stress_x,
"def run(x): # (M,N)->(M,N) x * rsqrt(sum(x^2) + 1e-6) (L2 normalize over last dim)",
notes="L2 normalization (reduction); fp32 accumulate.", extra={"eps": 1e-6}),
"log_softmax": OpSpec("log_softmax", _log_softmax_ref, _mk_x, _bench_log_softmax, _stress_x,
"def run(x): # (M,N)->(M,N) x - logsumexp(x); MUST subtract row-max for stability",
notes="row-wise log-softmax (reduction); max-subtraction required."),
"softmax_scale": OpSpec("softmax_scale", _softmax_scale_ref, _mk_softmax_scale, _bench_softmax_scale,
_stress_softmax_scale,
"def run(x, scale): # x:(M,N) scale:(1,) -> (M,N) softmax(x*scale[0]); subtract row-max",
notes="fused scale + softmax (attention prelude); reduction."),
"layernorm_gelu": OpSpec("layernorm_gelu", _layernorm_gelu_ref, _mk_layernorm_gelu, _bench_layernorm_gelu,
_stress_layernorm_gelu,
"def run(x, w, b): # x:(M,N) w,b:(N,) -> (M,N) gelu(LayerNorm(x)*w + b)",
notes="FUSION CHAIN: layernorm (reduction) -> GELU epilogue.", extra={"eps": 1e-5}),
"add_rmsnorm_rope": OpSpec("add_rmsnorm_rope", _add_rmsnorm_rope_ref, _mk_add_rmsnorm_rope,
_bench_add_rmsnorm_rope, _stress_add_rmsnorm_rope,
"def run(x, residual, w, cos, sin): # x,res,cos,sin:(M,D) w:(D,) -> (M,D)\n"
" # h=x+residual; n=rmsnorm(h)*w; out=n*cos+rotate_half(n)*sin (3-stage fusion chain)",
notes="THREE-stage fusion chain: residual-add -> RMSNorm (reduction) -> RoPE (gather).",
extra={"eps": 1e-6}),
"dequant_int8": OpSpec("dequant_int8", _dequant_int8_ref, _mk_dequant_int8, _bench_dequant_int8,
_stress_dequant_int8,
"def run(q, scale): # q:(M,N) int8, scale:(M,1) fp16 -> (M,N) fp16 out = q*scale (per-row dequant)",
notes="NON-GEMM int8 weight dequantization (memory-bound)."),
# ---- V2 standalone ops --------------------------------------------------------------
"softcap_softmax": OpSpec("softcap_softmax", _softcap_softmax_ref, _mk_softmax,
_bench_softcap_softmax, _stress_1tensor,
"def run(x): # (M,N)->(M,N) softmax(30*tanh(x/30)) row-wise (Gemma2 logit softcap).\n"
" # MUST apply the softcap BEFORE softmax and subtract the row-max before exp.",
notes="Gemma2-style softcapped softmax; the cap is what large-scale inputs expose."),
"rmsnorm_gemma": OpSpec("rmsnorm_gemma", _rmsnorm_gemma_ref, _mk_rmsnorm,
_bench_rmsnorm_gemma, _stress_rmsnorm,
"def run(x, w): # x:(M,N) w:(N,) -> (M,N)\n"
" # Gemma RMSNorm: y = x * rsqrt(mean(x^2)+1e-6) * (1 + w) — note the (1 + w)!",
notes="Gemma-style RMSNorm: scale by (1+w); dropping the +1 is the classic silent bug.",
extra={"eps": 1e-6}),
"glu": OpSpec("glu", _glu_ref, _mk_gate_up, _bench_glu, _stress_gate_up,
"def run(gate, up): # both (M,N) -> (M,N) sigmoid(gate) * up (the original GLU)",
notes="the original gated linear unit; eager launches sigmoid then mul separately."),
"rope_interleaved": OpSpec("rope_interleaved", _rope_interleaved_ref, _mk_rope_inter,
_bench_rope_inter, _stress_rope_inter,
"def run(x, cos, sin): # x:(M,D), cos,sin:(M,D/2), D even -> (M,D)\n"
" # GPT-J INTERLEAVED RoPE: out[2i]=x[2i]*cos[i]-x[2i+1]*sin[i];\n"
" # out[2i+1]=x[2i+1]*cos[i]+x[2i]*sin[i]. fp32 math.",
notes="interleaved-pair rotary (GPT-J/NeoX-style); strided pair access is the fusion win."),
"cross_entropy": OpSpec("cross_entropy", _cross_entropy_ref, _mk_cross_entropy,
_bench_cross_entropy, _stress_cross_entropy,
"def run(x, tgt): # x:(M,N) fp, tgt:(M,) int64 -> (M,)\n"
" # per-row cross-entropy: logsumexp(x) - x[tgt]. MUST subtract row-max inside\n"
" # the logsumexp (stability). Accumulate in fp32; output dtype = x.dtype.",
notes="fused cross-entropy (the Liger flagship): softmax+log+gather in one pass."),
# ---- INVENTION suite: never-trained problem classes ----------------------------------
"cumsum": OpSpec("cumsum", _cumsum_ref, _mk_x, _bench_cumsum, _stress_x,
"def run(x): # (M,N)->(M,N) row-wise INCLUSIVE prefix sum (cumsum along the last dim).\n"
" # This is a SCAN: each output depends on ALL previous elements in the row —\n"
" # a carry must propagate across blocks. Accumulate in fp32.",
notes="prefix-scan algorithm class (carry across blocks) — unlike every reduction op.",
# SCAN tolerance: rounding error tracks the RUNNING-SUM magnitude (scale*sqrt(j)),
# not the output element — fp32 envelope: eps*scale_max*sqrt(N_max) ≈ 1.2e-7*64*90
# ≈ 7e-4, ×~constants → 5e-3 atol. Wrong-kernel errors here are 1e3+, so the
# verification stays sharp. fp16/bf16 global atol already dominates this term.
tol_override={torch.float32: (2e-4, 5e-3)}),
"entropy": OpSpec("entropy", _entropy_ref, _mk_x, _bench_entropy, _stress_x,
"def run(x): # x:(M,N) -> (M,) Shannon entropy of softmax(x) per row:\n"
" # H = logsumexp(x) - sum(x * softmax(x)). MUST subtract the row max inside\n"
" # both the logsumexp and the softmax (stability). fp32 accumulation.",
notes="fused entropy-from-logits (sampling diagnostics): two coupled reductions.",
# H = lse - Σx·p subtracts two O(scale·|x|) quantities — the REFERENCE itself
# carries this cancellation, so elementwise agreement beyond eps*|x|_max*sqrt(N)
# ≈ 1.2e-7*300*64 ≈ 2e-3 is unattainable for ANY correct kernel. fp32 atol 2e-2
# against H ∈ [0, log N≈9]; the no-max-sub control still fails with nan/inf.
tol_override={torch.float32: (2e-4, 2e-2)}),
"kl_div": OpSpec("kl_div", _kl_div_ref, _mk_xy, _bench_kl_div, _stress_xy,
"def run(x, y): # both (M,N) logits -> (M,) KL(softmax(x) || softmax(y)) per row:\n"
" # lx = x - lse(x); ly = y - lse(y); out = sum(exp(lx) * (lx - ly)).\n"
" # BOTH logsumexps must be max-subtracted. fp32 accumulation.",
notes="fused distillation KL from raw logit pairs: double logsumexp + weighted sum."),
# ---- algorithm-discovery experiment: rmsnorm at a TALL-SKINNY shape where split-K wins ---
"rmsnorm_wide": OpSpec("rmsnorm_wide", _rmsnorm_ref, _mk_rmsnorm_wide, _bench_rmsnorm_wide,
_stress_rmsnorm_wide,
"def run(x, w): # x:(M,N) w:(N,) -> (M,N) RMSNorm; M is SMALL, N is HUGE (tall-skinny).\n"
" # one-program-per-row leaves the GPU idle; split the row's reduction across programs.",
notes="rmsnorm at tall-skinny (M<<#SMs, huge N) — the regime where split-K reduction wins.",
extra={"eps": 1e-6}),
}
def _build_chain_spec(norm: str, residual: bool, acts: list[str]) -> "OpSpec":
"""Dynamic spec for ANY block stack a user assembles: [+residual] -> {rms|layer}norm ->
act1 -> act2 -> ... The reference is composed from the SAME blocks, so any stack the user
invents is verifiable (that is the whole point — the blocks ARE the spec)."""
import chains
eps = 1e-6 if norm == "rms" else 1e-5
fns = [chains.ACTS[a][0] for a in acts] # torch fns, in order
def ref(*args):
if residual and norm == "rms":
x, r, w = args; h = x.float() + r.float(); b = None
elif residual:
x, r, w, b = args; h = x.float() + r.float()
elif norm == "rms":
x, w = args; h = x.float(); b = None
else:
x, w, b = args; h = x.float()
if norm == "rms":
n = h * torch.rsqrt(h.pow(2).mean(-1, keepdim=True) + eps) * w.float()
else:
mu = h.mean(-1, keepdim=True); hc = h - mu
n = hc * torch.rsqrt((hc * hc).mean(-1, keepdim=True) + eps) * w.float() + b.float()
for fn in fns:
n = fn(n)
return n.to(args[0].dtype)
kind = ("add_" if residual else "") + ("rms" if norm == "rms" else "ln")
mk = {"rms": _mk_rmsnorm, "add_rms": _mk_add_rmsnorm, "ln": _mk_layernorm,
"add_ln": _mk_add_layernorm}[kind]
bench = {"rms": _bench_rmsnorm, "add_rms": _bench_add_rmsnorm, "ln": _bench_layernorm,
"add_ln": _bench_add_layernorm}[kind]
stress = {"rms": _stress_rmsnorm, "add_rms": _stress_add_rmsnorm, "ln": _stress_layernorm,
"add_ln": _stress_add_layernorm}[kind]
sig = {"rms": "def run(x, w):", "add_rms": "def run(x, residual, w):",
"ln": "def run(x, w, b):", "add_ln": "def run(x, residual, w, b):"}[kind]
normname = "RMSNorm" if norm == "rms" else "LayerNorm"
chain_str = " then ".join(acts)
return OpSpec("custom_chain", ref, mk, bench, stress,
f"{sig} # fused custom chain: {'residual + ' if residual else ''}{normname} "
f"then {chain_str}; accumulate the reduction in fp32",
notes=f"custom block stack: {'+res ' if residual else ''}{norm}norm -> {chain_str}")
def get_spec(name: str) -> OpSpec:
# dynamic block-stack spec, encoded as "chain|<norm>|<0|1>|<act1,act2,...>"
if name.startswith("chain|"):
_, norm, res, acts = name.split("|", 3)
return _build_chain_spec(norm, res == "1", [a for a in acts.split(",") if a])
if name not in SPECS:
raise KeyError(f"unknown op {name!r}; have {sorted(SPECS)}")
return SPECS[name]
# ----------------------------------------------------------------------------------------
# SHAPE-GRID inputs (V2, purely ADDITIVE — references/tolerances/bench_inputs untouched).
# Builds inputs for any op at an arbitrary (M, N[, dtype]) so the harness can re-bench the
# same kernel across a grid of shapes. For rope-family ops N is the head dim D (must be
# even). Deterministic seeds derived from the shape so every grid cell is reproducible.
# ----------------------------------------------------------------------------------------
_ROPE_FAMILY = {"rope", "rope_interleaved", "qknorm_rope", "add_rmsnorm_rope"}
def _grid_kind(name: str) -> str:
"""Input-signature kind for an op (mirrors _register_chains's _IN map + explicit ops)."""
explicit = {
"softmax": "x", "log_softmax": "x", "gelu": "x", "silu": "x", "relu2": "x",
"l2norm": "x", "softcap_softmax": "x",
"rmsnorm": "rms", "rmsnorm_wide": "rms", "rmsnorm_gemma": "rms",
"layernorm": "ln", "layernorm_gelu": "ln",
"add_rmsnorm": "add_rms", "add_layernorm": "add_ln",
"swiglu": "gate_up", "geglu": "gate_up", "reglu": "gate_up", "glu": "gate_up",
"bias_gelu": "x_bias", "softmax_scale": "x_scale", "dequant_int8": "int8",
"cross_entropy": "ce", "rope": "rope", "rope_interleaved": "rope_inter",
"qknorm_rope": "qkr", "add_rmsnorm_rope": "arr",
"cumsum": "x", "entropy": "x", "kl_div": "gate_up",
}
if name in explicit:
return explicit[name]
if name.endswith("_short"):
return _grid_kind(name[: -len("_short")])
try:
import chains
for cname, kind, _ref, _s in chains.all_chains():
if cname == name:
return {"rms": "rms", "add_rms": "add_rms", "ln": "ln", "add_ln": "add_ln"}[kind]
except Exception:
pass
raise KeyError(f"no grid input builder for op {name!r}")
def grid_inputs(name: str, M: int, N: int, dtype=torch.float16) -> tuple:
kind = _grid_kind(name)
sd = (hash((name, M, N, str(dtype))) & 0x7FFFFFF) + 7
x = _fixed((M, N), dtype, 1.0, seed=sd)
if kind == "x":
return (x,)
if kind == "rms":
return (x, _fixed((N,), dtype, 1.0, seed=sd + 1))
if kind == "ln":
return (x, _fixed((N,), dtype, 1.0, seed=sd + 1), _fixed((N,), dtype, 1.0, seed=sd + 2))
if kind == "add_rms":
return (x, _fixed((M, N), dtype, 1.0, seed=sd + 3), _fixed((N,), dtype, 1.0, seed=sd + 1))
if kind == "add_ln":
return (x, _fixed((M, N), dtype, 1.0, seed=sd + 3),
_fixed((N,), dtype, 1.0, seed=sd + 1), _fixed((N,), dtype, 1.0, seed=sd + 2))
if kind == "gate_up":
return (x, _fixed((M, N), dtype, 1.0, seed=sd + 3))
if kind == "x_bias":
return (x, _fixed((N,), dtype, 1.0, seed=sd + 1))
if kind == "x_scale":
return (x, torch.tensor([0.125], device="cuda", dtype=dtype))
if kind == "ce":
g = torch.Generator(device="cuda").manual_seed(sd + 4)
return (x, torch.randint(0, N, (M,), generator=g, device="cuda", dtype=torch.int64))
if kind == "int8":
g = torch.Generator(device="cuda").manual_seed(sd)
q = torch.randint(-127, 127, (M, N), generator=g, device="cuda", dtype=torch.int8)
g2 = torch.Generator(device="cuda").manual_seed(sd + 1)
return (q, (torch.rand((M, 1), generator=g2, device="cuda") * 0.05 + 0.005).to(torch.float16))
# rope family: N is the head dim D (even)
D = N
if D % 2:
raise ValueError(f"{name}: head dim must be even, got {D}")
g = torch.Generator(device="cuda").manual_seed(sd + 5)
ang = torch.randn((M, D // 2), generator=g, device="cuda", dtype=torch.float32)
c, s = torch.cos(ang), torch.sin(ang)
if kind == "rope_inter":
return (x, c.to(dtype), s.to(dtype))
cos = torch.cat([c, c], -1).to(dtype)
sin = torch.cat([s, s], -1).to(dtype)
if kind == "rope":
return (x, cos, sin)
if kind == "qkr":
return (x, _fixed((D,), dtype, 1.0, seed=sd + 1), cos, sin)
if kind == "arr":
return (x, _fixed((M, D), dtype, 1.0, seed=sd + 3), _fixed((D,), dtype, 1.0, seed=sd + 1), cos, sin)
raise KeyError(kind)
# ---- SHORT-ROW regime variants (V2.7 invention targets) -----------------------------------
# The shape-grid characterized ONE loss region for the whole product: 16384x2048 (many short
# rows), where row-per-program schedules underuse the GPU and inductor wins. These variants
# are the SAME ops with the bench (and its correctness case) pinned INSIDE that region —
# the invention question is whether RL finds a schedule family (split-row / multi-row /
# persistent) that wins where its entire current style loses. Adversarial correctness sweep
# unchanged (same make_inputs/stress).
_SHORT_M, _SHORT_N = 16384, 2048
_SHORT_BASES = ["rmsnorm", "softmax", "layernorm_gelu", "add_layernorm_sigmoid",
# F1 falsification slate: the 10 worst remaining loss-cell ops — does the
# whole-row style TRANSFER from rl_adapter_invent without new ideas?
"add_layernorm_tanh", "add_layernorm_silu", "add_layernorm_gelu",
"layernorm_sigmoid", "layernorm_tanh", "rmsnorm_silu", "add_rmsnorm_silu",
"add_rmsnorm_sigmoid", "add_layernorm_square", "add_rmsnorm_gelu"]
def _register_short_variants():
for base in _SHORT_BASES:
b = SPECS[base]
name = base + "_short"
if name in SPECS:
continue
SPECS[name] = OpSpec(
name, b.reference, b.make_inputs,
(lambda base=base: grid_inputs(base, _SHORT_M, _SHORT_N)),
b.stress_inputs,
b.signature_hint + "\n # REGIME: M=16384 rows of only N=2048. One-program-per-row "
"underuses the GPU here;\n # consider processing MULTIPLE rows per program or "
"splitting work differently.",
notes=f"{base} pinned to the characterized loss regime (16384x2048) — schedule invention target.",
extra=dict(b.extra))
# ---- register the generative fusion-chain grammar (chains.py) ----------------------------
def _register_chains():
import chains
_IN = {"rms": (_mk_rmsnorm, _bench_rmsnorm, _stress_rmsnorm),
"add_rms": (_mk_add_rmsnorm, _bench_add_rmsnorm, _stress_add_rmsnorm),
"ln": (_mk_layernorm, _bench_layernorm, _stress_layernorm),
"add_ln": (_mk_add_layernorm, _bench_add_layernorm, _stress_add_layernorm)}
_SIG = {"rms": "def run(x, w):", "add_rms": "def run(x, residual, w):",
"ln": "def run(x, w, b):", "add_ln": "def run(x, residual, w, b):"}
for name, kind, ref, _structs in chains.all_chains():
if name in SPECS:
continue
mk, bench, stress = _IN[kind]
act = name.rsplit("_", 1)[-1]
SPECS[name] = OpSpec(name, ref, mk, bench, stress,
f"{_SIG[kind]} # fused {name}: {kind.replace('add_','residual+').replace('rms','RMSNorm').replace('ln','LayerNorm')} "
f"then {act} epilogue; accumulate the reduction in fp32",
notes=f"generative fusion chain (reduction->epilogue): {name}.")
_register_chains()
_register_short_variants()