Instructions to use khtsly/Kai-2.0-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use khtsly/Kai-2.0-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="khtsly/Kai-2.0-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("khtsly/Kai-2.0-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use khtsly/Kai-2.0-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "khtsly/Kai-2.0-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "khtsly/Kai-2.0-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/khtsly/Kai-2.0-Base
- SGLang
How to use khtsly/Kai-2.0-Base with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "khtsly/Kai-2.0-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "khtsly/Kai-2.0-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "khtsly/Kai-2.0-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "khtsly/Kai-2.0-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use khtsly/Kai-2.0-Base with Docker Model Runner:
docker model run hf.co/khtsly/Kai-2.0-Base
Download luau_kernels.py from khtsly/Kai-2.0-Base: direct link, hf CLI and curl.
- Browser
- Download file 50.4 kB
-
https://huggingface.co/khtsly/Kai-2.0-Base/resolve/main/luau_kernels.py
- Command line
-
hf download hf://khtsly/Kai-2.0-Base/luau_kernels.py
-
curl -L -o luau_kernels.py https://huggingface.co/khtsly/Kai-2.0-Base/resolve/main/luau_kernels.py
50.4 kB
| """Triton kernels for ``luau_infer`` (fused decoding of the LuauCoder HF port). | |
| Every kernel works on *rows*: one row per token of the call (``B`` rows when | |
| decoding, ``B * T`` for a prefill or a speculative verify), each with its own | |
| document position ``pos`` (RoPE, conv / value-shift masks), cache ``slot`` | |
| (where its K/V go) and ``start`` (the first valid key slot of its sequence: | |
| left padding). Nothing reads a Python scalar that changes between steps, so a | |
| decode step replays as a CUDA graph. | |
| * ``mix_norm`` Block AttnRes depth mix (a softmax over the sources, one tile) | |
| + RMSNorm, or the embedding gather + RMSNorm (layer 0). | |
| * ``gemv`` skinny ``x @ W.T`` (bf16 or rowwise-FP8 weights), epilogues: | |
| store, residual add, SwiGLU (gate|up rows), softcap logits. | |
| * ``qk_decode`` CCGQA conv + QK-mean + QK-norm + gains + RoPE + value shift, | |
| writes K/V to the cache and the conv latents to their ring. | |
| * ``attention`` GQA flash-decoding: each program reads a span of one KV | |
| head's keys once for all its query heads and all the | |
| sequence's rows (a speculative verify); the last span | |
| program merges and finishes DiffAttn V2 + XSA (+ gate). | |
| * ``qk_prefill`` ``qk_decode`` for prompts, in token tiles. | |
| * ``iha_mix`` IHA: pseudo-head mixes of the latent q / k / v, norm, temperature, | |
| RoPE at virtual positions, interleaved pseudo-K/V cache write; | |
| ``attention`` then runs over pseudo-rows with a sliding window and | |
| its finish collapses them (+ Gram-Schmidt XSA, gate). | |
| * ``head_gate`` the gated byte head's ``[h, sigmoid(u.h + b) P h]`` input. | |
| * ``sample`` repetition penalty / temperature / top-k / top-p / min-p + draw | |
| (or greedy), one row per program. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import sys | |
| from pathlib import Path | |
| import torch | |
| try: # (remote code: transformers only requires imports outside try blocks) | |
| import triton | |
| import triton.language as tl | |
| except ImportError as exc: # pragma: no cover | |
| raise ImportError("the fused LuauCoder decoding kernels need triton") from exc | |
| from .luau_gemv_tuned import TABLE as _TABLE | |
| LOG2E = 1.4426950408889634 | |
| # programmatic dependent launch (SM90+); LUAU_INFER_PDL=0 turns it off | |
| PDL = (torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 9 | |
| and os.environ.get("LUAU_INFER_PDL", "1") != "0") | |
| # L2 prefetch of the next GEMV's weights (SM90+); LUAU_INFER_PREFETCH=0 turns it off | |
| BULK = torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 9 | |
| PREFETCH = BULK and os.environ.get("LUAU_INFER_PREFETCH", "1") != "0" | |
| def _pf(pf) -> dict: | |
| """Launch kwargs of an optional prefetch target ``pf`` (a tensor).""" | |
| if pf is None or not PREFETCH: | |
| return dict(pf_ptr=None, pf_bytes=0, PF=False, BULK=False) | |
| return dict(pf_ptr=pf, pf_bytes=pf.numel() * pf.element_size(), PF=True, BULK=BULK) | |
| def _pdl(ON: tl.constexpr): | |
| """Wait for the previous kernel's writes, then let the next kernel launch.""" | |
| if ON: | |
| tl.extra.cuda.gdc_wait() | |
| tl.extra.cuda.gdc_launch_dependents() | |
| def _prefetch(ptr, nbytes, PF: tl.constexpr, BULK: tl.constexpr): | |
| """Fire-and-forget L2 prefetch of ``nbytes`` at ``ptr``, split over the kernel's programs.""" | |
| if PF: | |
| pid = tl.program_id(0) + tl.num_programs(0) * (tl.program_id(1) + tl.num_programs(1) * tl.program_id(2)) | |
| npg = tl.num_programs(0) * tl.num_programs(1) * tl.num_programs(2) | |
| CH: tl.constexpr = 4096 if BULK else 128 | |
| n = tl.cdiv(nbytes, CH) | |
| per = tl.cdiv(n, npg) | |
| lo = pid * per | |
| hi = tl.minimum(n, lo + per) | |
| base = ptr.to(tl.pointer_type(tl.int8)) | |
| for i0 in range(lo, hi, 256): | |
| i = i0 + tl.arange(0, 256) | |
| m = (i < hi).to(tl.int32) | |
| a = base + i.to(tl.int64) * CH | |
| if BULK: | |
| sz = tl.minimum(nbytes - i.to(tl.int64) * CH, CH).to(tl.int32) | |
| tl.inline_asm_elementwise( | |
| "{ .reg .pred p; setp.ne.b32 p, $3, 0; @p cp.async.bulk.prefetch.L2.global [$1], $2; " | |
| "mov.u32 $0, 0; }", "=r,l,r,r", [a, sz, m], dtype=tl.int32, is_pure=False, pack=1) | |
| else: | |
| tl.inline_asm_elementwise( | |
| "{ .reg .pred p; setp.ne.b32 p, $2, 0; @p prefetch.global.L2 [$1]; mov.u32 $0, 0; }", | |
| "=r,l,r", [a, m], dtype=tl.int32, is_pure=False, pack=1) | |
| def _mix_norm_kernel(s_ptr, s_row, s_ent, ids_ptr, emb_ptr, w_ptr, g_ptr, out_ptr, o_row, eps, D, | |
| NE: tl.constexpr, NE_PAD: tl.constexpr, MODE: tl.constexpr, BLOCK: tl.constexpr, | |
| ADD: tl.constexpr = 0, PART: tl.constexpr = 1, PDL: tl.constexpr = False, pf_ptr=None, pf_bytes=0, PF: tl.constexpr = False, BULK: tl.constexpr = False): | |
| """MODE 0: h = S[r, 0]; 1: embedding gather; 2: AttnRes mix; 3: sum of entries. out = rmsnorm(h) * g.""" | |
| r = tl.program_id(0).to(tl.int64) | |
| offs = tl.arange(0, BLOCK) | |
| msk = offs < D | |
| g = tl.load(g_ptr + offs, mask=msk, other=0.0).to(tl.float32) | |
| if MODE == 2: | |
| w = tl.load(w_ptr + offs, mask=msk, other=0.0) | |
| _prefetch(pf_ptr, pf_bytes, PF, BULK) | |
| _pdl(PDL) | |
| if MODE == 1: | |
| tok = tl.load(ids_ptr + r).to(tl.int64) | |
| hb = tl.load(emb_ptr + tok * D + offs, mask=msk, other=0.0) | |
| tl.store(s_ptr + r * s_row + offs, hb, mask=msk) | |
| h = hb.to(tl.float32) | |
| elif MODE == 0: | |
| h = tl.load(s_ptr + r * s_row + offs, mask=msk, other=0.0).to(tl.float32) | |
| else: | |
| j = tl.arange(0, NE_PAD) | |
| jm = j < NE | |
| v = tl.load(s_ptr + r * s_row + j[:, None] * s_ent + offs[None, :], mask=jm[:, None] & msk[None, :], | |
| other=0.0).to(tl.float32) | |
| if MODE == 3: | |
| h = tl.sum(v, 0) | |
| else: | |
| sc = tl.sum(v * w[None, :], 1) * tl.rsqrt(tl.sum(v * v, 1) / D + eps) | |
| sc = tl.where(j < NE - 1 + PART, sc, float("-inf")) | |
| e = tl.exp(sc - tl.max(sc, 0)) | |
| p = e / tl.sum(e, 0) | |
| h = tl.sum((p + ADD)[:, None] * v, 0) | |
| h = h.to(out_ptr.dtype.element_ty).to(tl.float32) # the mix output is bf16 | |
| y = h * tl.rsqrt(tl.sum(h * h, 0) / D + eps) * g | |
| tl.store(out_ptr + r * o_row + offs, y.to(out_ptr.dtype.element_ty), mask=msk) | |
| def mix_norm(S: torch.Tensor, n_ent: int, mode: int, out: torch.Tensor, g: torch.Tensor, eps: float, | |
| w: torch.Tensor | None = None, ids: torch.Tensor | None = None, | |
| emb: torch.Tensor | None = None, add: bool = False, partial: bool = True, pf=None) -> None: | |
| """``S`` ``(R, NS, D)`` sources (row-major per row), ``out`` ``(R, D)``.""" | |
| R, _, D = S.shape | |
| block = triton.next_power_of_2(D) | |
| ne_pad = triton.next_power_of_2(n_ent) if mode >= 2 else 1 | |
| warps = max(4, min(16, ne_pad * block // 1024)) | |
| _mix_norm_kernel[(R,)](S, S.stride(0), S.stride(1), ids if ids is not None else S, | |
| emb if emb is not None else S, w if w is not None else g, g, out, | |
| out.stride(0), eps, D, NE=n_ent, NE_PAD=ne_pad, MODE=mode, BLOCK=block, | |
| ADD=int(add), PART=int(partial), num_warps=warps, PDL=PDL, launch_pdl=PDL, **_pf(pf)) | |
| _TUNED_PATH = Path(__file__).with_name("luau_gemv_tuned.py") | |
| _TUNED: dict | None = None | |
| def _tuned() -> dict: | |
| """Pinned GEMV configs for this GPU (``benchmark/tune_gemv.py``), else {}.""" | |
| global _TUNED | |
| if _TUNED is None: | |
| name = torch.cuda.get_device_name() | |
| p = torch.cuda.get_device_properties(0) | |
| arch = [p.major, p.minor, p.multi_processor_count] | |
| hit = _TABLE.get(name) or next((e for e in _TABLE.values() if e.get("arch") == arch), None) | |
| _TUNED = dict(hit["gemv"]) if hit else {} | |
| return _TUNED | |
| def gemv_key(m_pad: int, n: int, k: int, fp8: bool, epi: int) -> str: | |
| return f"{m_pad},{n},{k},{int(fp8)},{int(epi == 2)}" | |
| def gemv_config(m_pad: int, n: int, k: int, fp8: bool, epi: int) -> tuple[int, int, int, int, int]: | |
| """``(BLOCK_N, BLOCK_K, num_warps, num_stages, DOT)``: pinned, else a default.""" | |
| hit = _tuned().get(gemv_key(m_pad, n, k, fp8, epi)) | |
| if hit: | |
| return tuple(hit) + (0,) * (5 - len(hit)) | |
| if m_pad >= 4: | |
| return 32, 128, 4, 3, 1 | |
| bk = 512 if fp8 else 256 | |
| bn = max(1, min(16, 2048 // (bk * m_pad) * 4)) | |
| return bn, bk, 4, 2, 0 | |
| def _gemv_tile(x_ptr, x_row, w_ptr, w_row, rm, mm, rn, nm, K, M_PAD: tl.constexpr, BLOCK_N: tl.constexpr, | |
| BLOCK_K: tl.constexpr, DOT: tl.constexpr): | |
| if DOT: | |
| acc = tl.zeros([M_PAD, BLOCK_N], dtype=tl.float32) | |
| for k0 in range(0, K, BLOCK_K): | |
| rk = k0 + tl.arange(0, BLOCK_K) | |
| km = rk < K | |
| x = tl.load(x_ptr + rm[:, None] * x_row + rk[None, :], mask=mm[:, None] & km[None, :], other=0.0) | |
| w = tl.load(w_ptr + rn[:, None] * w_row + rk[None, :], mask=nm[:, None] & km[None, :], other=0.0) | |
| acc = tl.dot(x.to(tl.bfloat16), tl.trans(w.to(tl.bfloat16)), acc) | |
| return acc | |
| acc3 = tl.zeros([M_PAD, BLOCK_N, BLOCK_K], dtype=tl.float32) | |
| for k0 in range(0, K, BLOCK_K): | |
| rk = k0 + tl.arange(0, BLOCK_K) | |
| km = rk < K | |
| x = tl.load(x_ptr + rm[:, None] * x_row + rk[None, :], mask=mm[:, None] & km[None, :], other=0.0) | |
| w = tl.load(w_ptr + rn[:, None] * w_row + rk[None, :], mask=nm[:, None] & km[None, :], other=0.0) | |
| acc3 += x.to(tl.float32)[:, None, :] * w.to(tl.float32)[None, :, :] | |
| return tl.sum(acc3, 2) | |
| def _gemv_kernel(x_ptr, x_row, w_ptr, w_row, ws_ptr, y_ptr, y_row, M, N, K, up_off, cap, | |
| M_PAD: tl.constexpr, EPI: tl.constexpr, FP8: tl.constexpr, | |
| BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr, DOT: tl.constexpr = False, | |
| PDL: tl.constexpr = False, pf_ptr=None, pf_bytes=0, PF: tl.constexpr = False, BULK: tl.constexpr = False): | |
| """y[m, n] = x[m] . W[n]. EPI 0: store; 1: residual add; 2: SwiGLU; 3: softcapped fp32 logits.""" | |
| _prefetch(pf_ptr, pf_bytes, PF, BULK) | |
| _pdl(PDL) | |
| pid = tl.program_id(0) | |
| rn = pid * BLOCK_N + tl.arange(0, BLOCK_N) | |
| nm = rn < N | |
| rm = tl.arange(0, M_PAD) | |
| mm = rm < M | |
| acc = _gemv_tile(x_ptr, x_row, w_ptr, w_row, rm, mm, rn, nm, K, M_PAD, BLOCK_N, BLOCK_K, DOT) | |
| if FP8: | |
| acc = acc * tl.load(ws_ptr + rn, mask=nm, other=0.0)[None, :] | |
| ym = mm[:, None] & nm[None, :] | |
| yp = y_ptr + rm[:, None] * y_row + rn[None, :] | |
| if EPI == 2: | |
| up = _gemv_tile(x_ptr, x_row, w_ptr, w_row, rm, mm, rn + up_off, nm, K, M_PAD, BLOCK_N, BLOCK_K, DOT) | |
| if FP8: | |
| up = up * tl.load(ws_ptr + up_off + rn, mask=nm, other=0.0)[None, :] | |
| gate = acc.to(tl.bfloat16).to(tl.float32) | |
| up = up.to(tl.bfloat16).to(tl.float32) | |
| tl.store(yp, (gate * tl.sigmoid(gate) * up).to(y_ptr.dtype.element_ty), mask=ym) | |
| elif EPI == 1: | |
| res = tl.load(yp, mask=ym, other=0.0).to(tl.float32) | |
| tl.store(yp, (acc.to(tl.bfloat16).to(tl.float32) + res).to(y_ptr.dtype.element_ty), mask=ym) | |
| elif EPI == 3: | |
| z = acc.to(tl.bfloat16).to(tl.float32) | |
| if cap > 0: | |
| t = z / cap | |
| e = tl.exp(-2.0 * tl.abs(t)) | |
| th = (1.0 - e) / (1.0 + e) | |
| z = cap * tl.where(t < 0, -th, th) | |
| tl.store(yp, z, mask=ym) | |
| else: | |
| tl.store(yp, acc.to(y_ptr.dtype.element_ty), mask=ym) | |
| def gemv(x: torch.Tensor, w: torch.Tensor, y: torch.Tensor, epi: int = 0, scale: torch.Tensor | None = None, | |
| n: int | None = None, up_off: int = 0, cap: float = 0.0, config: tuple | None = None, pf=None) -> None: | |
| """``x`` ``(M, K)`` (row stride free), ``w`` ``(N_w, K)``, ``y`` ``(M, n)``; ``n`` output | |
| columns (SwiGLU: the hidden size, ``up_off`` = its up rows' offset).""" | |
| M, K = x.shape | |
| N = n if n is not None else w.shape[0] | |
| m_pad = max(1, triton.next_power_of_2(M)) | |
| fp8 = scale is not None | |
| cfg = tuple(config or gemv_config(m_pad, N, K, fp8, epi)) | |
| bn, bk, warps, stages, dot = cfg + (0,) * (5 - len(cfg)) | |
| _gemv_kernel[(triton.cdiv(N, bn),)](x, x.stride(0), w, w.stride(0), scale if fp8 else w, y, y.stride(0), | |
| M, N, K, up_off, float(cap), M_PAD=max(16, m_pad) if dot else m_pad, | |
| EPI=epi, FP8=fp8, BLOCK_N=bn, BLOCK_K=bk, DOT=bool(dot), | |
| num_warps=warps, num_stages=stages, PDL=PDL, launch_pdl=PDL, **_pf(pf)) | |
| # CCGQA conv-latent / value-shift ring slots; a verify of up to RING - 3 drafts never overwrites | |
| RING: tl.constexpr = tl.constexpr(32) | |
| def _lat(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, r, t, b, slot, pos, col, cidx, LAG: tl.constexpr): | |
| """The pre-conv latent of the row's token ``LAG`` back (zero across a document start).""" | |
| if LAG == 0: | |
| v = tl.load(qkv_ptr + r * qkv_row + col + cidx).to(tl.float32) | |
| elif t >= LAG: | |
| v = tl.load(qkv_ptr + (r - LAG) * qkv_row + col + cidx, mask=pos >= LAG, other=0.0).to(tl.float32) | |
| else: | |
| v = tl.load(lat_ptr + b * lat_b + ((slot - LAG) % RING) * lat_l + col + cidx, mask=pos >= LAG, | |
| other=0.0).to(tl.float32) | |
| return tl.where(pos >= LAG, v, 0.0) | |
| def _conv(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, cs_ptr, csb_ptr, ch_ptr, chb_ptr, h, r, t, b, slot, pos, col, | |
| HD: tl.constexpr, KS: tl.constexpr, KC: tl.constexpr): | |
| """Virtual head ``h``'s causal conv.""" | |
| d = tl.arange(0, HD) | |
| b1 = tl.load(csb_ptr + h * HD + d).to(tl.float32) | |
| acc = tl.load(chb_ptr + h * HD + d).to(tl.float32) | |
| for j in tl.static_range(KC): | |
| u = b1 | |
| for i in tl.static_range(KS): | |
| a = tl.load(cs_ptr + (h * HD + d) * KS + i).to(tl.float32) | |
| u += a * _lat(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, r, t, b, slot, pos, col, d, i + j) | |
| w2 = tl.load(ch_ptr + ((h * KC + j) * HD + d[:, None]) * HD + d[None, :]).to(tl.float32) | |
| acc += tl.sum(w2 * u[:, None], 0) | |
| return acc | |
| def _conv_pre(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, b1, acc, a0, a1, w0, w1, r, t, b, slot, pos, col, | |
| HD: tl.constexpr, KS: tl.constexpr, KC: tl.constexpr): | |
| """``_conv`` (``KS``, ``KC`` <= 2) on taps already in registers (loaded before the PDL wait).""" | |
| d = tl.arange(0, HD) | |
| for j in tl.static_range(KC): | |
| u = b1 | |
| for i in tl.static_range(KS): | |
| a = a0 if i == 0 else a1 | |
| u += a * _lat(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, r, t, b, slot, pos, col, d, i + j) | |
| w2 = w0 if j == 0 else w1 | |
| acc += tl.sum(w2 * u[:, None], 0) | |
| return acc | |
| def _qk_decode_kernel(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, vh_ptr, vh_b, vh_l, | |
| pos_ptr, slot_ptr, cos_ptr, sin_ptr, cs_ptr, csb_ptr, ch_ptr, chb_ptr, qg_ptr, kg_ptr, | |
| q_ptr, q_row, kc_ptr, vc_ptr, kc_b, kc_h, T, eps, | |
| NQ: tl.constexpr, NKV: tl.constexpr, NXQ: tl.constexpr, HD: tl.constexpr, | |
| V_OFF: tl.constexpr, KS: tl.constexpr, KC: tl.constexpr, CCGQA: tl.constexpr, | |
| QK_MEAN: tl.constexpr, VSHIFT: tl.constexpr, ROPE: tl.constexpr, | |
| PDL: tl.constexpr = False, pf_ptr=None, pf_bytes=0, PF: tl.constexpr = False, BULK: tl.constexpr = False): | |
| """One (row, virtual head): queries go to ``q``, keys / values to the caches.""" | |
| h = tl.program_id(1) | |
| PRE: tl.constexpr = CCGQA and KS <= 2 and KC <= 2 | |
| if PRE: | |
| dd = tl.arange(0, HD) | |
| cb1 = tl.load(csb_ptr + h * HD + dd).to(tl.float32) | |
| cacc = tl.load(chb_ptr + h * HD + dd).to(tl.float32) | |
| ca0 = tl.load(cs_ptr + (h * HD + dd) * KS).to(tl.float32) | |
| ca1 = tl.load(cs_ptr + (h * HD + dd) * KS + (KS - 1)).to(tl.float32) | |
| cw0 = tl.load(ch_ptr + ((h * KC) * HD + dd[:, None]) * HD + dd[None, :]).to(tl.float32) | |
| cw1 = tl.load(ch_ptr + ((h * KC + (KC - 1)) * HD + dd[:, None]) * HD + dd[None, :]).to(tl.float32) | |
| r = tl.program_id(0).to(tl.int64) | |
| b = r // T | |
| t = r % T | |
| pos = tl.load(pos_ptr + r).to(tl.int64) | |
| slot = tl.load(slot_ptr + r).to(tl.int64) | |
| _prefetch(pf_ptr, pf_bytes, PF, BULK) | |
| _pdl(PDL) | |
| HALF: tl.constexpr = HD // 2 | |
| G: tl.constexpr = NQ // NKV | |
| d = tl.arange(0, HD) | |
| is_k = h >= NQ | |
| g = h - NQ | |
| ph = tl.where(is_k, NXQ + g, h % NXQ) | |
| col = ph * HD | |
| base = qkv_ptr + r * qkv_row | |
| keep = t + RING >= T # only a call's last RING tokens go to the rings (no write races) | |
| if CCGQA: | |
| if PRE: | |
| x = _conv_pre(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, cb1, cacc, ca0, ca1, cw0, cw1, r, t, b, slot, | |
| pos, col, HD, KS, KC) | |
| else: | |
| x = _conv(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, cs_ptr, csb_ptr, ch_ptr, chb_ptr, h, r, t, b, slot, | |
| pos, col, HD, KS, KC) | |
| if QK_MEAN: | |
| if is_k: | |
| qm = tl.zeros([HD], dtype=tl.float32) | |
| for jh in tl.static_range(G): | |
| qm += tl.load(base + ((g * G + jh) % NXQ) * HD + d).to(tl.float32) | |
| x += 0.5 * (qm / G + tl.load(base + col + d).to(tl.float32)) | |
| else: | |
| x += 0.5 * (tl.load(base + col + d).to(tl.float32) | |
| + tl.load(base + (NXQ + h // G) * HD + d).to(tl.float32)) | |
| else: | |
| x = tl.load(base + col + d).to(tl.float32) | |
| gain = tl.load(tl.where(is_k, kg_ptr + g * HD, qg_ptr) + d) | |
| x = x * tl.rsqrt(tl.sum(x * x, 0) / HD + eps) * gain | |
| if not CCGQA: # plain QK-norm rounds to bf16 before RoPE | |
| x = x.to(tl.bfloat16).to(tl.float32) | |
| lo, hi = tl.split(tl.permute(tl.reshape(x, [2, HALF]), (1, 0))) | |
| if ROPE: | |
| i2 = tl.arange(0, HALF) | |
| c = tl.load(cos_ptr + pos * HALF + i2) | |
| s = tl.load(sin_ptr + pos * HALF + i2) | |
| lo, hi = lo * c - hi * s, hi * c + lo * s | |
| lo_i = tl.arange(0, HALF) | |
| if is_k: | |
| dst = kc_ptr + b * kc_b + g * kc_h + slot * HD | |
| else: | |
| dst = q_ptr + r * q_row + h * HD | |
| tl.store(dst + lo_i, lo.to(q_ptr.dtype.element_ty)) | |
| tl.store(dst + HALF + lo_i, hi.to(q_ptr.dtype.element_ty)) | |
| if is_k: | |
| ch = g * HD + d | |
| own = tl.load(base + V_OFF + ch) | |
| v = own | |
| if VSHIFT: | |
| VH: tl.constexpr = NKV * HD // 2 | |
| upper = ch >= VH | |
| if t >= 1: | |
| prev = tl.load(base - qkv_row + V_OFF + ch, mask=upper, other=0.0) | |
| else: | |
| prev = tl.load(vh_ptr + b * vh_b + ((slot - 1) % RING) * vh_l + ch - VH, | |
| mask=upper & (slot >= 1), other=0.0) | |
| v = tl.where(upper, tl.where(pos > 0, prev, 0.0), own) | |
| tl.store(vh_ptr + b * vh_b + (slot % RING) * vh_l + ch - VH, own, mask=upper & keep) | |
| tl.store(vc_ptr + b * kc_b + g * kc_h + slot * HD + d, v.to(vc_ptr.dtype.element_ty)) | |
| if CCGQA: | |
| if ((h < NXQ) | is_k) & keep: | |
| tl.store(lat_ptr + b * lat_b + (slot % RING) * lat_l + col + d, tl.load(base + col + d)) | |
| def qk_decode(qkv, lat, vh, pos, slot, cos, sin, conv, qg, kg, q, kc, vc, T: int, eps: float, *, nq, nkv, | |
| nxq, hd, v_off, ks, kc_taps, ccgqa, qk_mean, vshift, rope, pf=None) -> None: | |
| R = qkv.shape[0] | |
| cs, csb, ch, chb = conv if conv is not None else (qkv,) * 4 | |
| _qk_decode_kernel[(R, nq + nkv)]( | |
| qkv, qkv.stride(0), lat if lat is not None else qkv, lat.stride(0) if lat is not None else 0, | |
| lat.stride(1) if lat is not None else 0, vh if vh is not None else qkv, | |
| vh.stride(0) if vh is not None else 0, vh.stride(1) if vh is not None else 0, | |
| pos, slot, cos, sin, cs, csb, ch, chb, qg, kg, q, q.stride(0), kc, vc, kc.stride(0), kc.stride(1), | |
| T, eps, NQ=nq, NKV=nkv, NXQ=nxq, HD=hd, V_OFF=v_off, KS=ks, KC=kc_taps, CCGQA=ccgqa, | |
| QK_MEAN=qk_mean, VSHIFT=vshift, ROPE=rope, num_warps=8, PDL=PDL, launch_pdl=PDL, **_pf(pf)) | |
| def _tile_lat(qkv_ptr, qkv_row, r0, t, tm, pos, col, d, T, LAG: tl.constexpr): | |
| """``[BT, HD]`` pre-conv latents ``LAG`` tokens back of a prompt tile.""" | |
| ok = tm & (pos >= LAG) & (t >= LAG) | |
| return tl.load(qkv_ptr + (r0 + t - LAG)[:, None] * qkv_row + col + d[None, :], mask=ok[:, None], | |
| other=0.0).to(tl.float32) | |
| def _qk_prefill_kernel(qkv_ptr, qkv_row, lat_ptr, lat_b, lat_l, vh_ptr, vh_b, vh_l, pos_ptr, cos_ptr, sin_ptr, | |
| cs_ptr, csb_ptr, ch_ptr, chb_ptr, qg_ptr, kg_ptr, q_ptr, q_row, kc_ptr, vc_ptr, kc_b, kc_h, | |
| T, eps, NQ: tl.constexpr, NKV: tl.constexpr, NXQ: tl.constexpr, HD: tl.constexpr, | |
| V_OFF: tl.constexpr, KS: tl.constexpr, KC: tl.constexpr, QK_MEAN: tl.constexpr, | |
| VSHIFT: tl.constexpr, ROPE: tl.constexpr, BT: tl.constexpr): | |
| """``qk_decode`` for a prompt, ``BT`` tokens of one virtual head per program (taps on tensor cores).""" | |
| tt = tl.program_id(0) | |
| h = tl.program_id(1) | |
| b = tl.program_id(2).to(tl.int64) | |
| HALF: tl.constexpr = HD // 2 | |
| G: tl.constexpr = NQ // NKV | |
| t = tt * BT + tl.arange(0, BT) | |
| tm = t < T | |
| r0 = b * T | |
| rows = r0 + t | |
| pos = tl.load(pos_ptr + rows, mask=tm, other=0).to(tl.int64) | |
| d = tl.arange(0, HD) | |
| is_k = h >= NQ | |
| g = h - NQ | |
| ph = tl.where(is_k, NXQ + g, h % NXQ) | |
| col = ph * HD | |
| b1 = tl.load(csb_ptr + h * HD + d).to(tl.float32) | |
| x = tl.zeros([BT, HD], dtype=tl.float32) + tl.load(chb_ptr + h * HD + d).to(tl.float32)[None, :] | |
| for j in tl.static_range(KC): | |
| u = tl.zeros([BT, HD], dtype=tl.float32) + b1[None, :] | |
| for i in tl.static_range(KS): | |
| a = tl.load(cs_ptr + (h * HD + d) * KS + i).to(tl.float32) | |
| u += a[None, :] * _tile_lat(qkv_ptr, qkv_row, r0, t, tm, pos, col, d, T, i + j) | |
| w2 = tl.load(ch_ptr + ((h * KC + j) * HD + d[:, None]) * HD + d[None, :]).to(tl.bfloat16) | |
| u_hi = u.to(tl.bfloat16) | |
| x = tl.dot(u_hi, w2, x) | |
| x = tl.dot((u - u_hi.to(tl.float32)).to(tl.bfloat16), w2, x) | |
| base = qkv_ptr + rows[:, None] * qkv_row | |
| if QK_MEAN: | |
| if is_k: | |
| qm = tl.zeros([BT, HD], dtype=tl.float32) | |
| for jh in tl.static_range(G): | |
| qm += tl.load(base + ((g * G + jh) % NXQ) * HD + d[None, :], mask=tm[:, None], other=0.0).to( | |
| tl.float32) | |
| x += 0.5 * (qm / G + tl.load(base + col + d[None, :], mask=tm[:, None], other=0.0).to(tl.float32)) | |
| else: | |
| x += 0.5 * (tl.load(base + col + d[None, :], mask=tm[:, None], other=0.0).to(tl.float32) | |
| + tl.load(base + (NXQ + h // G) * HD + d[None, :], mask=tm[:, None], other=0.0).to( | |
| tl.float32)) | |
| gain = tl.load(tl.where(is_k, kg_ptr + g * HD, qg_ptr) + d) | |
| x = x * tl.rsqrt(tl.sum(x * x, 1) / HD + eps)[:, None] * gain[None, :] | |
| lo, hi = tl.split(tl.permute(tl.reshape(x, [BT, 2, HALF]), (0, 2, 1))) | |
| i2 = tl.arange(0, HALF) | |
| if ROPE: | |
| c = tl.load(cos_ptr + pos[:, None] * HALF + i2[None, :]) | |
| sn = tl.load(sin_ptr + pos[:, None] * HALF + i2[None, :]) | |
| lo, hi = lo * c - hi * sn, hi * c + lo * sn | |
| if is_k: | |
| dst = kc_ptr + b * kc_b + g * kc_h + t[:, None] * HD | |
| else: | |
| dst = q_ptr + rows[:, None] * q_row + h * HD | |
| tl.store(dst + i2[None, :], lo.to(q_ptr.dtype.element_ty), mask=tm[:, None]) | |
| tl.store(dst + HALF + i2[None, :], hi.to(q_ptr.dtype.element_ty), mask=tm[:, None]) | |
| keep = tm & (t + RING >= T) | |
| if is_k: | |
| ch = g * HD + d | |
| own = tl.load(base + V_OFF + ch[None, :], mask=tm[:, None], other=0.0) | |
| v = own | |
| if VSHIFT: | |
| VH: tl.constexpr = NKV * HD // 2 | |
| upper = (ch >= VH)[None, :] | |
| prev = tl.load(base - qkv_row + V_OFF + ch[None, :], mask=tm[:, None] & upper & (t >= 1)[:, None], | |
| other=0.0) | |
| v = tl.where(upper, tl.where((pos > 0)[:, None], prev, 0.0), own) | |
| tl.store(vh_ptr + b * vh_b + (t % RING)[:, None] * vh_l + ch[None, :] - VH, own, | |
| mask=keep[:, None] & upper) | |
| tl.store(vc_ptr + b * kc_b + g * kc_h + t[:, None] * HD + d[None, :], v.to(vc_ptr.dtype.element_ty), | |
| mask=tm[:, None]) | |
| if (h < NXQ) | is_k: | |
| tl.store(lat_ptr + b * lat_b + (t % RING)[:, None] * lat_l + col + d[None, :], | |
| tl.load(base + col + d[None, :], mask=tm[:, None], other=0.0), mask=keep[:, None]) | |
| def qk_prefill(qkv, lat, vh, pos, cos, sin, conv, qg, kg, q, kc, vc, T: int, eps: float, *, nq, nkv, nxq, hd, | |
| v_off, ks, kc_taps, qk_mean, vshift, rope) -> None: | |
| """CCGQA ``qk_decode`` for ``B`` prompts of ``T`` tokens starting at slot 0.""" | |
| B = qkv.shape[0] // T | |
| cs, csb, ch, chb = conv | |
| bt = 32 if hd <= 128 else 16 # 64-token tiles spill | |
| _qk_prefill_kernel[(triton.cdiv(T, bt), nq + nkv, B)]( | |
| qkv, qkv.stride(0), lat, lat.stride(0), lat.stride(1), vh if vh is not None else qkv, | |
| vh.stride(0) if vh is not None else 0, vh.stride(1) if vh is not None else 0, pos, cos, sin, | |
| cs, csb, ch, chb, qg, kg, q, q.stride(0), kc, vc, kc.stride(0), kc.stride(1), T, eps, NQ=nq, NKV=nkv, | |
| NXQ=nxq, HD=hd, V_OFF=v_off, KS=ks, KC=kc_taps, QK_MEAN=qk_mean, VSHIFT=vshift, ROPE=rope, BT=bt, | |
| num_warps=4) | |
| # grid (span, KV head, sequence); the last span program merges the partials and finishes the rows | |
| def _spans(start, slot, NSPL: tl.constexpr, BL: tl.constexpr, MINB: tl.constexpr = 1): | |
| """``(span, n_spans)`` for keys ``[start, slot]``, sized on the device.""" | |
| n = slot + 1 - start | |
| span = tl.maximum(tl.cdiv(tl.cdiv(n, NSPL), BL), MINB) * BL | |
| return span, tl.where(n > 0, tl.cdiv(n, span), 0) | |
| def _merge(ml_ptr, acc_ptr, base0, n_sp, hrow, HD: tl.constexpr, G_PAD: tl.constexpr, GH_PAD: tl.constexpr, | |
| NSPL: tl.constexpr, CH: tl.constexpr): | |
| """Merge the span partials of the query heads ``hrow`` -> bf16-rounded output.""" | |
| d = tl.arange(0, HD) | |
| si = tl.arange(0, NSPL) | |
| m = tl.load(ml_ptr + (base0 + si)[:, None] * 2 * G_PAD + hrow[None, :], mask=(si < n_sp)[:, None], | |
| other=float("-inf")) | |
| l = tl.load(ml_ptr + (base0 + si)[:, None] * 2 * G_PAD + G_PAD + hrow[None, :], mask=(si < n_sp)[:, None], | |
| other=0.0) | |
| mg = tl.max(m, 0) | |
| mg = tl.where(mg == float("-inf"), 0.0, mg) | |
| lsum = tl.sum(tl.exp2(m - mg[None, :]) * l, 0) | |
| o = tl.zeros([GH_PAD, HD], dtype=tl.float32) | |
| for c0 in range(0, n_sp, CH): | |
| cs = c0 + tl.arange(0, CH) | |
| cm = cs < n_sp | |
| mc = tl.load(ml_ptr + (base0 + cs)[:, None] * 2 * G_PAD + hrow[None, :], mask=cm[:, None], | |
| other=float("-inf")) | |
| a = tl.load(acc_ptr + ((base0 + cs)[:, None, None] * G_PAD + hrow[None, :, None]) * HD | |
| + d[None, None, :], mask=cm[:, None, None], other=0.0) | |
| o += tl.sum(tl.exp2(mc - mg[None, :])[:, :, None] * a, 0) | |
| o = o / tl.maximum(lsum, 1e-30)[:, None] | |
| return o.to(tl.bfloat16).to(tl.float32) | |
| def _finish(ml_ptr, acc_ptr, r, g, b, n_sp, slot, qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, y_row, | |
| lam_off, gate_off, NKV: tl.constexpr, NSPL: tl.constexpr, G: tl.constexpr, G_PAD: tl.constexpr, | |
| HD: tl.constexpr, CH: tl.constexpr, DIFF: tl.constexpr, XSA: tl.constexpr, GATE: tl.constexpr): | |
| """Merge row ``r``'s spans for KV head ``g`` and finish DiffAttn V2 + XSA (+ gate) into ``y``.""" | |
| base0 = (r * NKV + g) * NSPL | |
| d = tl.arange(0, HD) | |
| if DIFF: | |
| GH: tl.constexpr = G // 2 | |
| GH_PAD: tl.constexpr = G_PAD // 2 | |
| i = tl.arange(0, GH_PAD) | |
| im = i < GH | |
| y0 = _merge(ml_ptr, acc_ptr, base0, n_sp, 2 * i, HD, G_PAD, GH_PAD, NSPL, CH) | |
| y1 = _merge(ml_ptr, acc_ptr, base0, n_sp, 2 * i + 1, HD, G_PAD, GH_PAD, NSPL, CH) | |
| lam = tl.load(qkv_ptr + r * qkv_row + lam_off + g * GH + i, mask=im, other=0.0).to(tl.float32) | |
| y = y0 - tl.sigmoid(lam)[:, None] * y1 | |
| else: | |
| GH: tl.constexpr = G | |
| GH_PAD: tl.constexpr = G_PAD | |
| i = tl.arange(0, GH_PAD) | |
| im = i < GH | |
| y = _merge(ml_ptr, acc_ptr, base0, n_sp, i, HD, G_PAD, GH_PAD, NSPL, CH) | |
| if XSA: | |
| v = tl.load(vc_ptr + b * kc_b + g * kc_h + slot * HD + d).to(tl.float32) | |
| vn = v / tl.maximum(tl.sqrt(tl.sum(v * v, 0)), 1e-12) | |
| y = y - tl.sum(y * vn[None, :], 1)[:, None] * vn[None, :] | |
| oh = g * GH + i | |
| if GATE == 1: # per channel | |
| gt = tl.load(qkv_ptr + r * qkv_row + gate_off + oh[:, None] * HD + d[None, :], mask=im[:, None], | |
| other=0.0).to(tl.float32) | |
| y = y * tl.sigmoid(gt) | |
| elif GATE == 2: # per head | |
| gt = tl.load(qkv_ptr + r * qkv_row + gate_off + oh, mask=im, other=0.0).to(tl.float32) | |
| y = y * tl.sigmoid(gt)[:, None] | |
| tl.store(y_ptr + r * y_row + oh[:, None] * HD + d[None, :], y.to(y_ptr.dtype.element_ty), mask=im[:, None]) | |
| def _fence(): | |
| """``fence.acq_rel.gpu`` in every thread (CUDA's ``__threadfence``).""" | |
| tl.inline_asm_elementwise("fence.acq_rel.gpu; mov.u32 $0, 0;", "=r", [], dtype=tl.int32, is_pure=False, | |
| pack=1) | |
| def _seq_keys(start_ptr, slot_ptr, r0, T, win, WIN: tl.constexpr): | |
| """A sequence's key range ``[start, last]``.""" | |
| start = tl.load(start_ptr + r0) | |
| if WIN: | |
| start = tl.maximum(start, tl.load(slot_ptr + r0) - win + 1) | |
| return start, tl.load(slot_ptr + r0 + T - 1) | |
| def _unit(x, tol): | |
| """``x / |x|``; 0 where ``|x| <= tol`` (the port's ``_unit``).""" | |
| n = tl.sqrt(tl.sum(x * x, 0)) | |
| return tl.where(n > tol, x / tl.maximum(n, tol), 0.0) | |
| def _iha_finish(ml_ptr, acc_ptr, rt, g, b, n_sp, vs0, r_ptr, qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, | |
| y_row, gate_off, P: tl.constexpr, NKV: tl.constexpr, NSPL: tl.constexpr, G: tl.constexpr, | |
| G_PAD: tl.constexpr, HD: tl.constexpr, CH: tl.constexpr, XSA: tl.constexpr, GATE: tl.constexpr): | |
| """IHA finish: merge, collapse with ``R``, Gram-Schmidt XSA and the gate for one token row.""" | |
| d = tl.arange(0, HD) | |
| i = tl.arange(0, G_PAD) | |
| im = i < G | |
| oh = g * G + i | |
| y = tl.zeros([G_PAD, HD], dtype=tl.float32) | |
| for p in tl.static_range(P): | |
| yp = _merge(ml_ptr, acc_ptr, ((rt * P + p) * NKV + g) * NSPL, n_sp, i, HD, G_PAD, G_PAD, NSPL, CH) | |
| rr = tl.load(r_ptr + oh * P + p, mask=im, other=0.0).to(tl.float32) | |
| y += rr[:, None] * yp | |
| y = y.to(tl.bfloat16).to(tl.float32) | |
| if XSA: | |
| vb = vc_ptr + b * kc_b + g * kc_h + vs0 * HD | |
| e0 = tl.zeros([HD], dtype=tl.float32) | |
| e1 = tl.zeros([HD], dtype=tl.float32) | |
| e2 = tl.zeros([HD], dtype=tl.float32) | |
| for p in tl.static_range(P): | |
| w = _unit(tl.load(vb + p * HD + d).to(tl.float32), 1e-12) | |
| w = w - tl.sum(w * e0, 0) * e0 | |
| w = w - tl.sum(w * e1, 0) * e1 | |
| w = w - tl.sum(w * e2, 0) * e2 | |
| e = _unit(w, 1e-2) | |
| y = y - tl.sum(y * e[None, :], 1)[:, None] * e[None, :] | |
| if p == 0: | |
| e0 = e | |
| elif p == 1: | |
| e1 = e | |
| elif p == 2: | |
| e2 = e | |
| if GATE == 1: | |
| gt = tl.load(qkv_ptr + rt * qkv_row + gate_off + oh[:, None] * HD + d[None, :], mask=im[:, None], | |
| other=0.0).to(tl.float32) | |
| y = y * tl.sigmoid(gt) | |
| elif GATE == 2: | |
| gt = tl.load(qkv_ptr + rt * qkv_row + gate_off + oh, mask=im, other=0.0).to(tl.float32) | |
| y = y * tl.sigmoid(gt)[:, None] | |
| tl.store(y_ptr + rt * y_row + oh[:, None] * HD + d[None, :], y.to(y_ptr.dtype.element_ty), mask=im[:, None]) | |
| def _attn_kernel(q_ptr, q_row, kc_ptr, vc_ptr, kc_b, kc_h, slot_ptr, start_ptr, ml_ptr, acc_ptr, cnt_ptr, | |
| qkv_ptr, qkv_row, y_ptr, y_row, T, qk_scale, lam_off, gate_off, win, r_ptr, | |
| NKV: tl.constexpr, NSPL: tl.constexpr, G: tl.constexpr, G_PAD: tl.constexpr, QR: tl.constexpr, | |
| HD: tl.constexpr, BL: tl.constexpr, CH: tl.constexpr, DIFF: tl.constexpr, XSA: tl.constexpr, | |
| GATE: tl.constexpr, FINISH: tl.constexpr, WIN: tl.constexpr = False, IHA: tl.constexpr = 0, | |
| MINB: tl.constexpr = 1, PDL: tl.constexpr = False, pf_ptr=None, pf_bytes=0, PF: tl.constexpr = False, BULK: tl.constexpr = False): | |
| """Flash-decoding attention; ``FINISH``: the last span program finishes the row.""" | |
| sp = tl.program_id(0) | |
| g = tl.program_id(1) | |
| b = tl.program_id(2).to(tl.int64) | |
| r0 = b * T | |
| start, last = _seq_keys(start_ptr, slot_ptr, r0, T, win, WIN) | |
| span, n_sp = _spans(start, last, NSPL, BL, MINB) | |
| lo = start + sp * span | |
| hi = tl.minimum(last + 1, lo + span) | |
| qi = tl.arange(0, QR) | |
| t = qi // G | |
| j = qi % G | |
| qm = t < T | |
| lim = tl.load(slot_ptr + r0 + t, mask=qm, other=-1) | |
| _prefetch(pf_ptr, pf_bytes, PF, BULK) | |
| _pdl(PDL) | |
| if lo < hi: | |
| d = tl.arange(0, HD) | |
| q = tl.load(q_ptr + (r0 + t)[:, None] * q_row + (g * G + j)[:, None] * HD + d[None, :], | |
| mask=qm[:, None], other=0.0) | |
| m_i = tl.full([QR], float("-inf"), tl.float32) | |
| l_i = tl.zeros([QR], dtype=tl.float32) | |
| acc = tl.zeros([QR, HD], dtype=tl.float32) | |
| kbase = b * kc_b + g * kc_h | |
| for k0 in range(lo, hi, BL): | |
| kk = k0 + tl.arange(0, BL) | |
| km = kk < hi | |
| k = tl.load(kc_ptr + kbase + kk[:, None] * HD + d[None, :], mask=km[:, None], other=0.0) | |
| s = tl.dot(q, tl.trans(k)) * qk_scale # base-2 logits | |
| ok = km[None, :] & (kk[None, :] <= lim[:, None]) | |
| if WIN: | |
| ok = ok & (kk[None, :] > lim[:, None] - win) | |
| s = tl.where(ok, s, float("-inf")) | |
| m_new = tl.maximum(m_i, tl.max(s, 1)) | |
| m_ok = tl.where(m_new == float("-inf"), 0.0, m_new) # a row with no key yet | |
| alpha = tl.exp2(m_i - m_ok) | |
| p = tl.exp2(s - m_ok[:, None]) | |
| l_i = l_i * alpha + tl.sum(p, 1) | |
| v = tl.load(vc_ptr + kbase + kk[:, None] * HD + d[None, :], mask=km[:, None], other=0.0) | |
| acc = acc * alpha[:, None] + tl.dot(p.to(v.dtype), v) | |
| m_i = m_new | |
| base = ((r0 + t) * NKV + g) * NSPL + sp | |
| tl.store(ml_ptr + base * 2 * G_PAD + j, m_i, mask=qm) | |
| tl.store(ml_ptr + base * 2 * G_PAD + G_PAD + j, l_i, mask=qm) | |
| tl.store(acc_ptr + (base * G_PAD + j)[:, None] * HD + d[None, :], acc, mask=qm[:, None]) | |
| if FINISH: | |
| _fence() | |
| tl.debug_barrier() | |
| old = tl.atomic_add(cnt_ptr + b * NKV + g, 1, sem="acq_rel", scope="gpu") | |
| if old == n_sp - 1: | |
| _fence() | |
| tl.atomic_xchg(cnt_ptr + b * NKV + g, 0, sem="relaxed", scope="gpu") | |
| if IHA: | |
| _iha_finish(ml_ptr, acc_ptr, b, g, b, n_sp, tl.load(slot_ptr + r0), r_ptr, qkv_ptr, qkv_row, | |
| vc_ptr, kc_b, kc_h, y_ptr, y_row, gate_off, IHA, NKV, NSPL, G, G_PAD, HD, CH, | |
| XSA, GATE) | |
| else: | |
| _finish(ml_ptr, acc_ptr, r0, g, b, n_sp, last, qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, | |
| y_row, lam_off, gate_off, NKV, NSPL, G, G_PAD, HD, CH, DIFF, XSA, GATE) | |
| def _finish_kernel(ml_ptr, slot_ptr, start_ptr, acc_ptr, qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, y_row, T, | |
| lam_off, gate_off, NKV: tl.constexpr, NSPL: tl.constexpr, G: tl.constexpr, G_PAD: tl.constexpr, | |
| HD: tl.constexpr, BL: tl.constexpr, CH: tl.constexpr, DIFF: tl.constexpr, XSA: tl.constexpr, | |
| GATE: tl.constexpr, MINB: tl.constexpr = 1, PDL: tl.constexpr = False): | |
| """The finish of a multi-row (verify / short prompt) attention, a program per (row, KV head).""" | |
| _pdl(PDL) | |
| r = tl.program_id(0).to(tl.int64) | |
| g = tl.program_id(1) | |
| b = r // T | |
| _, n_sp = _spans(tl.load(start_ptr + b * T), tl.load(slot_ptr + b * T + T - 1), NSPL, BL, MINB) | |
| _finish(ml_ptr, acc_ptr, r, g, b, n_sp, tl.load(slot_ptr + r), qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, | |
| y_row, lam_off, gate_off, NKV, NSPL, G, G_PAD, HD, CH, DIFF, XSA, GATE) | |
| def _iha_finish_kernel(ml_ptr, slot_ptr, start_ptr, acc_ptr, qkv_ptr, qkv_row, vc_ptr, kc_b, kc_h, y_ptr, y_row, | |
| Tt, win, r_ptr, gate_off, P: tl.constexpr, NKV: tl.constexpr, NSPL: tl.constexpr, | |
| G: tl.constexpr, G_PAD: tl.constexpr, HD: tl.constexpr, BL: tl.constexpr, CH: tl.constexpr, | |
| XSA: tl.constexpr, GATE: tl.constexpr, WIN: tl.constexpr, MINB: tl.constexpr = 1, | |
| PDL: tl.constexpr = False): | |
| """IHA's finish of a multi-token call, a program per (token row, KV head).""" | |
| _pdl(PDL) | |
| rt = tl.program_id(0).to(tl.int64) | |
| g = tl.program_id(1) | |
| b = rt // Tt | |
| start, last = _seq_keys(start_ptr, slot_ptr, b * Tt * P, Tt * P, win, WIN) | |
| _, n_sp = _spans(start, last, NSPL, BL, MINB) | |
| _iha_finish(ml_ptr, acc_ptr, rt, g, b, n_sp, tl.load(slot_ptr + rt * P), r_ptr, qkv_ptr, qkv_row, vc_ptr, | |
| kc_b, kc_h, y_ptr, y_row, gate_off, P, NKV, NSPL, G, G_PAD, HD, CH, XSA, GATE) | |
| # tests set 32 / False so a 1-row step and a verify match bitwise | |
| QR_MIN = 16 | |
| FUSED_FINISH = True | |
| # smallest span, in 64-key blocks | |
| ATTN_MINB = 1 | |
| def attention(q, kc, vc, slot, start, qkv, y, ml, acc, cnt, T: int, *, nq, nkv, hd, nspl, lam_off, | |
| gate_off, diff, xsa, gate, win: int = 0, iha_p: int = 0, iha_r=None, pf=None, bl: int = 64, | |
| warps: int | None = None) -> None: | |
| """Flash-decoding attention for ``R = B * T`` rows (``win``: sliding window; ``iha_p``: pseudo-rows).""" | |
| if iha_p: | |
| assert not diff, "IHA with DiffAttn V2: no fused finish" | |
| T = T * iha_p | |
| R = q.shape[0] | |
| G = nq // nkv | |
| g_pad = max(16, triton.next_power_of_2(G)) | |
| qr = max(QR_MIN, triton.next_power_of_2(T * G)) | |
| ch = 8 if g_pad <= 16 else 4 | |
| _attn_kernel[(nspl, nkv, R // T)](q, q.stride(0), kc, vc, kc.stride(0), kc.stride(1), slot, start, ml, acc, | |
| cnt, qkv, qkv.stride(0), y, y.stride(0), T, hd ** -0.5 * LOG2E, lam_off, | |
| gate_off, int(win), iha_r if iha_p else q, | |
| NKV=nkv, NSPL=nspl, G=G, G_PAD=g_pad, QR=qr, HD=hd, BL=bl, | |
| CH=ch, DIFF=diff, XSA=xsa, GATE=gate, | |
| FINISH=T == max(iha_p, 1) and FUSED_FINISH, WIN=win > 0, IHA=iha_p, | |
| MINB=ATTN_MINB, | |
| num_warps=warps or (4 if qr <= 32 else 8), num_stages=2, PDL=PDL, launch_pdl=PDL, | |
| **_pf(pf)) | |
| if iha_p: | |
| if T > iha_p or not FUSED_FINISH: | |
| _iha_finish_kernel[(R // iha_p, nkv)](ml, slot, start, acc, qkv, qkv.stride(0), vc, kc.stride(0), | |
| kc.stride(1), y, y.stride(0), T // iha_p, int(win), iha_r, | |
| gate_off, P=iha_p, NKV=nkv, NSPL=nspl, G=G, G_PAD=g_pad, | |
| HD=hd, BL=bl, CH=ch, XSA=xsa, GATE=gate, WIN=win > 0, MINB=ATTN_MINB, | |
| num_warps=4, PDL=PDL, launch_pdl=PDL) | |
| return | |
| if T > 1 or not FUSED_FINISH: | |
| _finish_kernel[(R, nkv)](ml, slot, start, acc, qkv, qkv.stride(0), vc, kc.stride(0), kc.stride(1), y, | |
| y.stride(0), T, lam_off, gate_off, NKV=nkv, NSPL=nspl, G=G, G_PAD=g_pad, HD=hd, | |
| BL=bl, CH=ch, DIFF=diff, XSA=xsa, GATE=gate, MINB=ATTN_MINB, num_warps=4, PDL=PDL, | |
| launch_pdl=PDL) | |
| def _iha_mix_kernel(q_ptr, q_row, kl_ptr, vl_ptr, kl_b, kl_h, aq_ptr, ak_ptr, av_ptr, qg_ptr, kg_ptr, temp_ptr, | |
| pos_ptr, slot_ptr, cos_ptr, sin_ptr, qv_ptr, qv_row, kc_ptr, vc_ptr, kc_b, kc_h, T, eps, | |
| P: tl.constexpr, NQ: tl.constexpr, NQ_PAD: tl.constexpr, NKV: tl.constexpr, HD: tl.constexpr, | |
| ROPE: tl.constexpr, PDL: tl.constexpr = False, pf_ptr=None, pf_bytes=0, PF: tl.constexpr = False, BULK: tl.constexpr = False): | |
| """One (row, pseudo-head p): IHA mixes, norm, temperature and RoPE, then cache / ``qv`` writes.""" | |
| r = tl.program_id(0).to(tl.int64) | |
| p = tl.program_id(1) | |
| b = r // T | |
| HALF: tl.constexpr = HD // 2 | |
| rslot = tl.load(slot_ptr + r).to(tl.int64) | |
| pos = tl.load(pos_ptr + r).to(tl.int64) * P + p | |
| slot = rslot * P + p | |
| d = tl.arange(0, HD) | |
| i2 = tl.arange(0, HALF) | |
| h = tl.arange(0, NQ_PAD) | |
| hm = h < NQ | |
| at = tl.load(aq_ptr + (h[None, :] * NQ + h[:, None]) * P + p, mask=hm[:, None] & hm[None, :], other=0.0) | |
| qgain = tl.load(qg_ptr + d) | |
| kgain = tl.load(kg_ptr + d) | |
| if ROPE: | |
| c = tl.load(cos_ptr + pos * HALF + i2) | |
| s = tl.load(sin_ptr + pos * HALF + i2) | |
| _prefetch(pf_ptr, pf_bytes, PF, BULK) | |
| _pdl(PDL) | |
| # queries: one tensor-core tile | |
| q = tl.load(q_ptr + r * q_row + h[:, None] * HD + d[None, :], mask=hm[:, None], other=0.0) | |
| x = tl.dot(at.to(tl.bfloat16), q.to(tl.bfloat16)).to(tl.bfloat16).to(tl.float32) # at[h, m] | |
| x = x * tl.rsqrt(tl.sum(x * x, 1) / HD + eps)[:, None] * qgain[None, :] | |
| x = x.to(tl.bfloat16).to(tl.float32) | |
| lo, hi = tl.split(tl.permute(tl.reshape(x, [NQ_PAD, 2, HALF]), (0, 2, 1))) | |
| if ROPE: | |
| lo, hi = lo * c[None, :] - hi * s[None, :], hi * c[None, :] + lo * s[None, :] | |
| dst = qv_ptr + (r * P + p) * qv_row + h[:, None] * HD + i2[None, :] | |
| tl.store(dst, lo.to(qv_ptr.dtype.element_ty), mask=hm[:, None]) | |
| tl.store(dst + HALF, hi.to(qv_ptr.dtype.element_ty), mask=hm[:, None]) | |
| # keys / values: CUDA-core sums | |
| src = b * kl_b + rslot * HD | |
| for g in tl.static_range(NKV): | |
| k = tl.zeros([HD], dtype=tl.float32) | |
| v = tl.zeros([HD], dtype=tl.float32) | |
| for m in tl.static_range(NKV): | |
| ak = tl.load(ak_ptr + (m * NKV + g) * P + p).to(tl.float32) | |
| av = tl.load(av_ptr + (m * NKV + g) * P + p).to(tl.float32) | |
| k += ak * tl.load(kl_ptr + src + m * kl_h + d).to(tl.float32) | |
| v += av * tl.load(vl_ptr + src + m * kl_h + d).to(tl.float32) | |
| k = k.to(tl.bfloat16).to(tl.float32) | |
| k = (k * tl.rsqrt(tl.sum(k * k, 0) / HD + eps) * kgain).to(tl.bfloat16).to(tl.float32) | |
| k = (k * tl.load(temp_ptr + g)).to(tl.bfloat16).to(tl.float32) | |
| klo, khi = tl.split(tl.permute(tl.reshape(k, [2, HALF]), (1, 0))) | |
| if ROPE: | |
| klo, khi = klo * c - khi * s, khi * c + klo * s | |
| kd = kc_ptr + b * kc_b + g * kc_h + slot * HD | |
| tl.store(kd + i2, klo.to(kc_ptr.dtype.element_ty)) | |
| tl.store(kd + HALF + i2, khi.to(kc_ptr.dtype.element_ty)) | |
| tl.store(vc_ptr + b * kc_b + g * kc_h + slot * HD + d, v.to(vc_ptr.dtype.element_ty)) | |
| def iha_mix(q, kl, vl, aq, ak, av, qg, kg, temp, pos, slot, cos, sin, qv, kc, vc, T: int, eps: float, *, | |
| P: int, nq: int, nkv: int, hd: int, rope: bool, pf=None) -> None: | |
| """``q`` ``(R, nq, hd)`` latent queries, ``kl`` / ``vl`` ``(B, nkv, L, hd)`` latent keys / values at the | |
| rows' slots, mixes ``(H, H, P)`` bf16, ``qv`` ``(R * P, nq, hd)``, caches ``(B, nkv, L * P, hd)``.""" | |
| R = q.shape[0] | |
| _iha_mix_kernel[(R, P)](q, q.stride(0), kl, vl, kl.stride(0), kl.stride(1), aq, ak, av, qg, kg, temp, pos, | |
| slot, cos, sin, qv, qv.stride(0), kc, vc, kc.stride(0), kc.stride(1), T, eps, | |
| P=P, NQ=nq, NQ_PAD=max(16, triton.next_power_of_2(nq)), NKV=nkv, HD=hd, ROPE=rope, | |
| num_warps=4, PDL=PDL, launch_pdl=PDL, **_pf(pf)) | |
| def _head_gate_kernel(y_ptr, y_row, b_ptr, h_ptr, h_row, D, RK: tl.constexpr, BLOCK: tl.constexpr, | |
| PDL: tl.constexpr = False): | |
| """Gated byte head input ``[h, sigmoid(u . h + b) * P h]``.""" | |
| _pdl(PDL) | |
| r = tl.program_id(0).to(tl.int64) | |
| j = tl.arange(0, BLOCK) | |
| jm = j < RK | |
| a = tl.load(y_ptr + r * y_row + RK).to(tl.float32) + tl.load(b_ptr).to(tl.float32) | |
| gt = tl.sigmoid(a.to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16).to(tl.float32) | |
| yp = tl.load(y_ptr + r * y_row + j, mask=jm, other=0.0).to(tl.float32) | |
| tl.store(h_ptr + r * h_row + D + j, (gt * yp).to(h_ptr.dtype.element_ty), mask=jm) | |
| def head_gate(y, bias, h, D: int, rank: int) -> None: | |
| _head_gate_kernel[(y.shape[0],)](y, y.stride(0), bias, h, h.stride(0), D, RK=rank, | |
| BLOCK=triton.next_power_of_2(rank), num_warps=4, PDL=PDL, launch_pdl=PDL) | |
| def _sample_kernel(x_ptr, x_row, V, inv_temp, top_k, top_p, min_p, seed_ptr, excl_ptr, y_ptr, pd_ptr, u_ptr, | |
| pres_ptr, pres_row, ids_ptr, penalty, T, | |
| TOP_K: tl.constexpr, TOP_P: tl.constexpr, MIN_P: tl.constexpr, EXCL: tl.constexpr, | |
| REP: tl.constexpr, GREEDY: tl.constexpr, T_MAX: tl.constexpr, BLOCK: tl.constexpr, | |
| ITERS: tl.constexpr): | |
| """One row: repetition penalty, temperature, top-k, top-p, min-p (thresholds by bisection), then a | |
| draw.""" | |
| r = tl.program_id(0).to(tl.int64) | |
| offs = tl.arange(0, BLOCK) | |
| msk = offs < V | |
| x = tl.load(x_ptr + r * x_row + offs, mask=msk, other=float("-inf")) | |
| if REP: | |
| b = r // T | |
| t = r % T | |
| seen = tl.load(pres_ptr + b * pres_row + offs, mask=msk, other=0) != 0 | |
| for i in tl.static_range(1, T_MAX): | |
| if i <= t: | |
| seen = seen | (offs == tl.load(ids_ptr + b * T + i)) | |
| x = tl.where(seen, tl.where(x < 0, x * penalty, x / penalty), x) | |
| if GREEDY: | |
| tl.store(y_ptr + r, tl.argmax(x, 0).to(tl.int64)) | |
| else: | |
| x = x * inv_temp | |
| if TOP_K: | |
| lo = tl.min(tl.where(msk, x, float("inf")), 0) | |
| hi = tl.max(x, 0) | |
| for _ in range(ITERS): # count(x >= lo) >= k > count(x >= hi) | |
| mid = lo + (hi - lo) * 0.5 | |
| ok = tl.sum((x >= mid).to(tl.int32), 0) >= top_k | |
| lo = tl.where(ok, mid, lo) | |
| hi = tl.where(ok, hi, mid) | |
| kth = tl.min(tl.where(x >= lo, x, float("inf")), 0) | |
| x = tl.where(x >= kth, x, float("-inf")) | |
| m = tl.max(x, 0) | |
| p = tl.exp(x - m) # max 1 | |
| z = tl.sum(p, 0) | |
| if TOP_P: | |
| lo = tl.zeros([], dtype=tl.float32) | |
| hi = tl.full([], 1.0, tl.float32) # mass(p >= lo) >= top_p * z > mass(p >= hi) (or hi = 1) | |
| goal = top_p * z | |
| for _ in range(ITERS): | |
| mid = lo + (hi - lo) * 0.5 | |
| ok = tl.sum(tl.where(p >= mid, p, 0.0), 0) >= goal | |
| lo = tl.where(ok, mid, lo) | |
| hi = tl.where(ok, hi, mid) | |
| tau = tl.min(tl.where(p >= lo, p, float("inf")), 0) | |
| p = tl.where(p >= tau, p, 0.0) | |
| if MIN_P: | |
| p = tl.where(p >= min_p, p, 0.0) # max is 1: min_p * max = min_p | |
| seed = tl.load(seed_ptr) | |
| if EXCL: | |
| e = tl.load(excl_ptr + r) | |
| pd = tl.sum(tl.where(offs == e, p, 0.0), 0) / tl.sum(p, 0) | |
| tl.store(pd_ptr + r, pd) | |
| tl.store(u_ptr + r, tl.rand(seed + 7919, r.to(tl.int32))) | |
| p = tl.where(offs == e, 0.0, p) | |
| cdf = tl.cumsum(p, 0) | |
| u = tl.rand(seed, r.to(tl.int32)) * tl.max(cdf, 0) | |
| tok = tl.min(tl.where((cdf > u) & (p > 0), offs, BLOCK), 0) | |
| tl.store(y_ptr + r, tl.where(tok < V, tok, tl.argmax(p, 0)).to(tl.int64)) | |
| def sample(x: torch.Tensor, seed: torch.Tensor, y: torch.Tensor, *, temperature: float, top_k: int, top_p: float, | |
| min_p: float, excl: torch.Tensor | None = None, pd: torch.Tensor | None = None, | |
| u: torch.Tensor | None = None, greedy: bool = False, penalty: float = 1.0, | |
| pres: torch.Tensor | None = None, ids: torch.Tensor | None = None, T: int = 1) -> None: | |
| """Draw ``y`` ``(R,)`` from fp32 logits ``x`` ``(R, V)``.""" | |
| R, V = x.shape | |
| block = triton.next_power_of_2(V) | |
| rep = penalty != 1.0 | |
| _sample_kernel[(R,)](x, x.stride(0), V, 1.0 / temperature, int(top_k), float(top_p), float(min_p), seed, | |
| excl if excl is not None else y, y, pd if pd is not None else x, | |
| u if u is not None else x, pres.view(torch.uint8) if rep else y, | |
| pres.stride(0) if rep else 0, ids if rep else y, float(penalty), T, | |
| TOP_K=bool(top_k) and top_k < V, TOP_P=top_p < 1.0, MIN_P=bool(min_p), | |
| EXCL=excl is not None, REP=rep, GREEDY=greedy, T_MAX=T, BLOCK=block, ITERS=40, | |
| num_warps=32 if block >= 16384 else 8) | |
| kernels = sys.modules[__name__] # ``from .luau_kernels import kernels as K``: transformers' | |
| # remote code only follows ``from .module import ...`` lines | |