Repository navigation
Conversation
…32 probabilities window_rows.cu: decode by 256-key chunks and a merge in chunk order, prompt tiles over 128-dim slices; Window.p32 keeps P to 2^-16 as two bf16 halves (Metal's rounding points), promptRows takes each row's last key. window_attention.cu and its callers are unchanged. core/attention_range.zig: float64 at the rounding points and the range fp32 allows.
…ttention window_rows.cu at head dim 512: decode partials with K and V tiles in shared memory, a block for 4 query heads and a warp for each key run, merged in chunk order as at 256; prompt tiles as at 256. No window over a linear cache to 262144 keys, GQA 8 and 16.
|
Thanks @jschmied for keeping the 512 work behind the same - Synthema, Ash's AI Assistant. |
|
Please refuse both at 512 for now. Gemma 4 is the only user of the 512 path, and its global layers are causal over the whole context with no window: the ring is the context length, and image rows see each other only on the sliding layers (head dim 256). Our 31B image branch (#1186) uses the same split, so neither case is reachable today. A refusal by name is better than an untested path; if a model needs either later, it can come with its own cases. Not in the middle of a change here. |
…im 512, the 17-row decode count back - Contract entries at head dim 512 with 10 query heads over 2 (GQA 5): decode, prompt rows with P32 and with P as bf16, and the 512 merge control, so each key head's second block of four heads holds one (window_rows512.cuh's partial group) and the odd-ratio prompt mapping runs; the device tests gain the same decode and prompt cases. - decode1 runs 1, 3, 17 and c.rows rows again (those under c.rows), so the 256 decode cases check 17 rows as #1123 did, and the 512 cases with 4 or 17 rows keep their counts.
|
Thanks @jschmied. Head dim 512 over a linear cache for global attention is on - Synthema, Ash's AI Assistant. |
|
This shipped in TensorFold 1.1.4: https://github.com/ashhart/TensorFold/releases/tag/v1.1.4 Thank you @jschmied for the contribution. - Synthema, Ash's AI Assistant. |
What this changes
Stacked on #1123 (
window_attentionat head dim 256); this is its second commit. It includescore/bf16_round.zigwith #1056's sign fix through that PR.Step 6 of #1048, the global attention. As agreed there, it is not a new operator:
window_attentionruns with no window over a linear cache (win = 0,ringthe cache length) at head dim 512, with key-tile splits and a merge for long caches. Nothing calls it yet.window_rows.cu, with any number of query heads per key head up to 16 (Gemma 4: 8 for the 31B, 16 for the 12B). Linear caches are served to 262,144 keys and beyond: positions are int32, and a cache of more than 2^31 rows is refused.cp.async. A block takes 4 query heads, and each of its 8 warps takes a key run: keysw, w + 8, ...of every tile. The scores have the same arithmetic as at 256: each lane's fma chain over its 16 dims, then a xor tree. The runs'oare added in run order. The arithmetic doesn't depend on the batch, the slot or the cache length, so neither do a row's bits; chunks past a row's keys are skipped exactly.p32and the per-row last key as at 256.Why one operator holds: the current callers' kernels are not touched.
window_attention.cuand its fatbin are byte-identical tomain's, and Kolibri-1's timings don't move (receipt below). The new head dims are new instantiations behind the sameWindowandWindowAttention.decodeandprompt. The current head-128 kernels were not folded into the new ones: that would change Kolibri-1's bytes (bf16 P and its own sum orders), which #1048 rules out.Receipt
Environment: TensorFold
d1018b31(1.1.1) plus cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123 and this commit; one DGX Spark (GB10, sm_121, CUDA 13.0, nvcc 13.0.88). No checkpoint needed. Shapes come fromfamilies/gemma4/config.zig, and value ranges followmlx-community/gemma-4-12B-it-4bit's global layers: q at RMS 0.95 to 1.05, k at 0.06 to 0.07 (inputs drawn from 0.06 to 0.13), v at unit RMS, with peaked keys mixed in.Exactness,
tf-cuda-test window-rows(cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123's cases, plus):In all: 4,848,501 outputs bit-equal to float64's value at the rounding points and 14,566,539 within their range. Smaller decode calls' bits equal the widest call's, the 20,000-key cache declared 16x longer gives the same bits, and a prompt chunk split in two gives every row's bits.
Decode speed, new shapes (
tf-cuda-test window-bench gemma, GPU µs, median of 25, at positions 1k / 8k / 32k / 128k; caches from DRAM):At 128k, a 12B row reads 256 MiB (185 GB/s), 4 rows read 1 GiB (203 GB/s), and a 31B row 1 GiB (219 GB/s).
Prompt speed, new shapes (512-row chunk ending at the context):
The prompt tiles run at about 23 TFLOPS of useful work (cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123's kernel at 512); a deeper key pipeline is the next lever.
Current callers' speed: unchanged. Kolibri-1, ABBA x2 against
main(the bench added), GPU µs, medians of 4:tf_window_decode_tc, 1 rowwattn_kernel<128,8,4,8>, 2,048 rowsKernel contract,
tf-cuda-test kernel-contract(built-Dnvcc, ReleaseFast) on the GB10:SUMMARY 91 kernels: 91 pass gates 1-4, 0 fail, 0 known findings; 14 controls: 14 red as planted, 0 missed; 1533 limit problems(cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123: 88 and 13;
main:SUMMARY 85 kernels: 85 pass gates 1-4, 0 fail, 0 known findings; 7 controls: 7 red as planted, 0 missed; 1533 limit problems).exp(m_c - M), red at gate 3. cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123's six still go red.tf_wrows_part_512at 64 KiB dynamic shared memory, opt-in;tf_wrows_merge_512;tf_wrows_prompt_512and_p32at 80 KiB). All 8 window_rows records are current on sm_80, 86, 89, 120 and 121. The run over every image reports 877 problems, asmain's does.Default path unchanged: every fatbin but
window_rowsandcontract_controlsis byte-identical tomain's on all five SMs.glm_quantdiffers in bytes, not in SASS, exactly as in cuda window_attention: head dim 256, any GQA, a row's last key and fp32 probabilities #1123's build.window_attention's SASS: 25 of 25. The existing controls' SASS: 35 of 35.tf-cuda-test windowpasses.Tests run:
zig build testfrom an empty cache: 213/213 steps, 2,964 of 2,978 tests passed, 14 skipped (main: 211/211 steps, 2,959 of 2,973 tests passed, 14 skipped).zig fmt --checkis clean.lean_check.py: 444 findings, as onmain.Not run, and why: Metal (no Metal change). sm_80, 86, 89 and 120 only through their recorded compiles. No model calls it yet (step 8 of Proposal: Gemma 4 on CUDA, built on the shared CUDA operators (shared extensions first) #1048).
Overlap with #798
The same as #1123's: no change to
window_attention.cuorwindow_split.cuh. A test merge onto the #746/#798 scratch conflicts only in the registration lists (registry.zig's record line;build/cuda.zigandcontract_tests.zigalready conflict between that scratch and 1.1.1).Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (No serving path changes; a row's bits are its own.)SUMMARYline is in the receipt.