Add in-Space offgrid/local mode (ZeroGPU H200 + in-process referee)
Browse files- referee/chains.py +181 -0
referee/chains.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generative fusion-chain grammar: [+residual] -> {rms|layer}norm -> ×w(+b) -> epilogue.
|
| 2 |
+
|
| 3 |
+
The widest sweep of the reduction->epilogue region (where the compiler under-fuses and the 2B
|
| 4 |
+
wins). References are COMPOSED; teacher kernels are TEMPLATE-GENERATED (scalar-reduce +
|
| 5 |
+
whole-row variants). Everything is harness-filtered downstream — nothing here is trusted.
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
import torch
|
| 9 |
+
|
| 10 |
+
_C = 0.7978845608028654 # sqrt(2/pi)
|
| 11 |
+
|
| 12 |
+
# epilogue: (torch fn on fp32 tensor, triton expression in fp32 var `n`)
|
| 13 |
+
ACTS = {
|
| 14 |
+
"gelu": (lambda t: 0.5 * t * (1.0 + torch.tanh(_C * (t + 0.044715 * t * t * t))),
|
| 15 |
+
"(0.5 * n * (1.0 + (2.0 * tl.sigmoid(2.0 * (0.7978845608028654 * (n + 0.044715 * n * n * n))) - 1.0)))"),
|
| 16 |
+
"silu": (lambda t: t * torch.sigmoid(t), "(n * tl.sigmoid(n))"),
|
| 17 |
+
"relu2": (lambda t: torch.relu(t) * torch.relu(t), "(tl.maximum(n, 0.0) * tl.maximum(n, 0.0))"),
|
| 18 |
+
# --- expanded grammar (each torch fn EXACTLY matches its triton expr; no approximation) ---
|
| 19 |
+
"tanh": (lambda t: torch.tanh(t), "(2.0 * tl.sigmoid(2.0 * n) - 1.0)"), # identity tanh(x)=2σ(2x)-1
|
| 20 |
+
"sigmoid": (lambda t: torch.sigmoid(t), "tl.sigmoid(n)"),
|
| 21 |
+
"relu": (lambda t: torch.relu(t), "tl.maximum(n, 0.0)"),
|
| 22 |
+
"square": (lambda t: t * t, "(n * n)"),
|
| 23 |
+
# --- 2c round 2: more real activations (each torch fn EXACTLY matches its triton expr) ---
|
| 24 |
+
"abs": (lambda t: torch.abs(t), "tl.abs(n)"),
|
| 25 |
+
"softsign": (lambda t: t / (1.0 + torch.abs(t)), "(n / (1.0 + tl.abs(n)))"),
|
| 26 |
+
"hardsigmoid": (lambda t: torch.clamp(t + 3.0, 0.0, 6.0) / 6.0,
|
| 27 |
+
"(tl.minimum(tl.maximum(n + 3.0, 0.0), 6.0) / 6.0)"), # F.hardsigmoid
|
| 28 |
+
"hardswish": (lambda t: t * torch.clamp(t + 3.0, 0.0, 6.0) / 6.0,
|
| 29 |
+
"(n * tl.minimum(tl.maximum(n + 3.0, 0.0), 6.0) / 6.0)"), # F.hardswish
|
| 30 |
+
# --- V2 round 3: 8 more real, numerically-safe activations. Same exactness rule: the
|
| 31 |
+
# torch lambda IS the triton expression (tanh via the 2*sigmoid(2x)-1 identity;
|
| 32 |
+
# softplus uses F.softplus's threshold=20 guard so exp never overflows). -----------
|
| 33 |
+
"leaky_relu": (lambda t: torch.where(t > 0, t, 0.01 * t),
|
| 34 |
+
"tl.where(n > 0.0, n, 0.01 * n)"),
|
| 35 |
+
"relu6": (lambda t: torch.clamp(t, 0.0, 6.0),
|
| 36 |
+
"tl.minimum(tl.maximum(n, 0.0), 6.0)"),
|
| 37 |
+
"hardtanh": (lambda t: torch.clamp(t, -1.0, 1.0),
|
| 38 |
+
"tl.minimum(tl.maximum(n, -1.0), 1.0)"),
|
| 39 |
+
"elu": (lambda t: torch.where(t > 0, t, torch.exp(torch.clamp(t, max=0.0)) - 1.0),
|
| 40 |
+
"tl.where(n > 0.0, n, tl.exp(tl.minimum(n, 0.0)) - 1.0)"),
|
| 41 |
+
"selu": (lambda t: 1.0507009873554805 * torch.where(
|
| 42 |
+
t > 0, t, 1.6732632423543772 * (torch.exp(torch.clamp(t, max=0.0)) - 1.0)),
|
| 43 |
+
"(1.0507009873554805 * tl.where(n > 0.0, n, "
|
| 44 |
+
"1.6732632423543772 * (tl.exp(tl.minimum(n, 0.0)) - 1.0)))"),
|
| 45 |
+
"softplus": (lambda t: torch.where(t > 20.0, t, torch.log(1.0 + torch.exp(torch.clamp(t, max=20.0)))),
|
| 46 |
+
"tl.where(n > 20.0, n, tl.log(1.0 + tl.exp(tl.minimum(n, 20.0))))"),
|
| 47 |
+
"mish": (lambda t: t * torch.tanh(torch.where(
|
| 48 |
+
t > 20.0, t, torch.log(1.0 + torch.exp(torch.clamp(t, max=20.0))))),
|
| 49 |
+
"(n * (2.0 * tl.sigmoid(2.0 * tl.where(n > 20.0, n, "
|
| 50 |
+
"tl.log(1.0 + tl.exp(tl.minimum(n, 20.0))))) - 1.0))"),
|
| 51 |
+
"gelu_erf": (lambda t: 0.5 * t * (1.0 + torch.erf(t * 0.7071067811865476)),
|
| 52 |
+
"(0.5 * n * (1.0 + tl.erf(n * 0.7071067811865476)))"), # EXACT gelu
|
| 53 |
+
}
|
| 54 |
+
NORMS = ["rms", "layer"]
|
| 55 |
+
RESID = [False, True]
|
| 56 |
+
ACTNAMES = ["gelu", "silu", "relu2", "tanh", "sigmoid", "relu", "square",
|
| 57 |
+
"abs", "softsign", "hardsigmoid", "hardswish",
|
| 58 |
+
"leaky_relu", "relu6", "hardtanh", "elu", "selu", "softplus", "mish", "gelu_erf"]
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def chain_name(norm, residual, act):
|
| 62 |
+
return ("add_" if residual else "") + ("rmsnorm" if norm == "rms" else "layernorm") + "_" + act
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def chain_kind(norm, residual):
|
| 66 |
+
return ("add_" if residual else "") + ("rms" if norm == "rms" else "ln") # -> input signature
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def chain_reference(norm, residual, act, eps=None):
|
| 70 |
+
eps = eps if eps is not None else (1e-6 if norm == "rms" else 1e-5)
|
| 71 |
+
fn = ACTS[act][0]
|
| 72 |
+
def ref(*args):
|
| 73 |
+
if residual and norm == "rms":
|
| 74 |
+
x, r, w = args; h = x.float() + r.float(); b = None
|
| 75 |
+
elif residual:
|
| 76 |
+
x, r, w, b = args; h = x.float() + r.float()
|
| 77 |
+
elif norm == "rms":
|
| 78 |
+
x, w = args; h = x.float(); b = None
|
| 79 |
+
else:
|
| 80 |
+
x, w, b = args; h = x.float()
|
| 81 |
+
if norm == "rms":
|
| 82 |
+
n = h * torch.rsqrt(h.pow(2).mean(-1, keepdim=True) + eps) * w.float()
|
| 83 |
+
else:
|
| 84 |
+
mu = h.mean(-1, keepdim=True); hc = h - mu
|
| 85 |
+
n = hc * torch.rsqrt((hc * hc).mean(-1, keepdim=True) + eps) * w.float() + b.float()
|
| 86 |
+
return fn(n).to(args[0].dtype)
|
| 87 |
+
return ref
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
# ---- teacher-kernel templates -----------------------------------------------------------
|
| 91 |
+
def _kernel(norm, residual, act_expr, eps, variant):
|
| 92 |
+
"""variant: 'scalar' (loop+scalar accumulator) or 'whole' (single block per row)."""
|
| 93 |
+
ptrs = "x_ptr, " + ("r_ptr, " if residual else "") + "w_ptr, " + ("b_ptr, " if norm == "layer" else "") + "y_ptr"
|
| 94 |
+
sig = "x, " + ("residual, " if residual else "") + "w" + (", b" if norm == "layer" else "")
|
| 95 |
+
launch = "x, " + ("residual, " if residual else "") + "w" + (", b" if norm == "layer" else "") + ", y"
|
| 96 |
+
radv = " r_ptr += row * stride;" if residual else ""
|
| 97 |
+
hload = ("tl.load(x_ptr + cols, mask=MM, other=0.0).to(tl.float32)"
|
| 98 |
+
+ (" + tl.load(r_ptr + cols, mask=MM, other=0.0).to(tl.float32)" if residual else ""))
|
| 99 |
+
# bias load indent differs: scalar variant loads it INSIDE the apply for-loop (8 spaces),
|
| 100 |
+
# whole-row loads it flat (4 spaces). Wrong indent -> IndentationError.
|
| 101 |
+
bload8 = " b = tl.load(b_ptr + cols, mask=MM, other=0.0).to(tl.float32)\n" if norm == "layer" else ""
|
| 102 |
+
bload4 = " b = tl.load(b_ptr + cols, mask=MM, other=0.0).to(tl.float32)\n" if norm == "layer" else ""
|
| 103 |
+
if norm == "rms":
|
| 104 |
+
normed = "h * rr * w"
|
| 105 |
+
else:
|
| 106 |
+
normed = "(h - mu) * rr * w + b"
|
| 107 |
+
|
| 108 |
+
if variant == "scalar":
|
| 109 |
+
if norm == "rms":
|
| 110 |
+
reduce_block = f''' s = 0.0
|
| 111 |
+
for off in range(0, N, BLOCK):
|
| 112 |
+
cols = off + tl.arange(0, BLOCK); MM = cols < N
|
| 113 |
+
h = {hload}
|
| 114 |
+
s += tl.sum(h * h)
|
| 115 |
+
rr = tl.rsqrt(s / N + eps)'''
|
| 116 |
+
else:
|
| 117 |
+
reduce_block = f''' s = 0.0
|
| 118 |
+
for off in range(0, N, BLOCK):
|
| 119 |
+
cols = off + tl.arange(0, BLOCK); MM = cols < N
|
| 120 |
+
s += tl.sum({hload})
|
| 121 |
+
mu = s / N
|
| 122 |
+
v = 0.0
|
| 123 |
+
for off in range(0, N, BLOCK):
|
| 124 |
+
cols = off + tl.arange(0, BLOCK); MM = cols < N
|
| 125 |
+
d = tl.where(MM, ({hload}) - mu, 0.0); v += tl.sum(d * d)
|
| 126 |
+
rr = tl.rsqrt(v / N + eps)'''
|
| 127 |
+
body = f'''@triton.jit
|
| 128 |
+
def _k({ptrs}, stride, N, eps, BLOCK: tl.constexpr):
|
| 129 |
+
row = tl.program_id(0); x_ptr += row * stride;{radv} y_ptr += row * stride
|
| 130 |
+
{reduce_block}
|
| 131 |
+
for off in range(0, N, BLOCK):
|
| 132 |
+
cols = off + tl.arange(0, BLOCK); MM = cols < N
|
| 133 |
+
h = {hload}
|
| 134 |
+
w = tl.load(w_ptr + cols, mask=MM, other=0.0).to(tl.float32)
|
| 135 |
+
{bload8} n = {normed}
|
| 136 |
+
tl.store(y_ptr + cols, {act_expr}, mask=MM)
|
| 137 |
+
def run({sig}):
|
| 138 |
+
M, N = x.shape; y = torch.empty_like(x)
|
| 139 |
+
_k[(M,)]({launch}, x.stride(0), N, {eps}, BLOCK=1024)
|
| 140 |
+
return y
|
| 141 |
+
'''
|
| 142 |
+
else: # whole-row single block
|
| 143 |
+
if norm == "rms":
|
| 144 |
+
stat = " rr = tl.rsqrt(tl.sum(h * h) / N + eps)"
|
| 145 |
+
else:
|
| 146 |
+
stat = (" mu = tl.sum(h) / N\n hc = tl.where(MM, h - mu, 0.0)\n"
|
| 147 |
+
" rr = tl.rsqrt(tl.sum(hc * hc) / N + eps)")
|
| 148 |
+
normed = "hc * rr * w + b"
|
| 149 |
+
body = f'''@triton.jit
|
| 150 |
+
def _k({ptrs}, stride, N, eps, BLOCK: tl.constexpr):
|
| 151 |
+
row = tl.program_id(0); x_ptr += row * stride;{radv} y_ptr += row * stride
|
| 152 |
+
cols = tl.arange(0, BLOCK); MM = cols < N
|
| 153 |
+
h = {hload}
|
| 154 |
+
{stat}
|
| 155 |
+
w = tl.load(w_ptr + cols, mask=MM, other=0.0).to(tl.float32)
|
| 156 |
+
{bload4} n = {normed}
|
| 157 |
+
tl.store(y_ptr + cols, {act_expr}, mask=MM)
|
| 158 |
+
def run({sig}):
|
| 159 |
+
M, N = x.shape; y = torch.empty_like(x)
|
| 160 |
+
_k[(M,)]({launch}, x.stride(0), N, {eps}, BLOCK=triton.next_power_of_2(N))
|
| 161 |
+
return y
|
| 162 |
+
'''
|
| 163 |
+
return body
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def chain_structures(norm, residual, act):
|
| 167 |
+
eps = 1e-6 if norm == "rms" else 1e-5
|
| 168 |
+
expr = ACTS[act][1]
|
| 169 |
+
return [_kernel(norm, residual, expr, eps, "scalar"), _kernel(norm, residual, expr, eps, "whole")]
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def all_chains():
|
| 173 |
+
"""[(name, kind, reference_fn, [kernel_src, ...]), ...] for the full grammar."""
|
| 174 |
+
out = []
|
| 175 |
+
for norm in NORMS:
|
| 176 |
+
for residual in RESID:
|
| 177 |
+
for act in ACTNAMES:
|
| 178 |
+
name = chain_name(norm, residual, act)
|
| 179 |
+
out.append((name, chain_kind(norm, residual), chain_reference(norm, residual, act),
|
| 180 |
+
chain_structures(norm, residual, act)))
|
| 181 |
+
return out
|