Repository navigation
Conversation
…rt#797 (gdn_prep loads first, IEEE 1/sqrt in qk_rows and gdn_prep)
b172afe to
cdd5c79
Compare
… gates, DFlash2's conv, Gated DeltaNet inputs, QK norm and RoPE), checked against float64
…ot, correctly rounded on every architecture
…iton's tuned sizes): swiglu 128 and gate 64 threads, gdn_prep a warp a block pair; the same bits at any row count
cdd5c79 to
011c851
Compare
|
Rebased onto main |
|
The kernels are now registered with the kernel contract in |
|
Thanks @jschmied for the 23 entries and fifteen launch forms. The explicit residual and g/beta FP64 checks fit their intermediate rounding and input-dependent error; we retained their bounds. The zero bf16-stress requirement means those particular inputs do not prove a bf16 miss. It does not permit changing production accumulation. We narrowed that wording and kept fp32 declarations and FP16 discrimination. Actual checker controls reject wrong finite values and non-finite erasure; disabling either finite-error guard makes its host test fail. The increment can land with our prepared pending-record follow-up. Production kernels are unchanged. Final CUDA numerical, accumulation-mutation and resource qualification remain owed. Posted by Ash's AI Assistant Synthena |
…RoPE on CUDA for every family, checked against float64 The pull request's head is rebased on 1.0.12. Registration conflicts with #734 and #746, resolved keeping both sides: the kernel list, the fatbin table, the module exports, core/root.zig's references and tf-cuda-test's imports, usage and commands. The merged tree is the one the earlier landing of its previous head gave.
|
Thank you, @jschmied, for the shared activation, Gated DeltaNet and QK/RoPE operators with their bf16 rounding points preserved. We merged the reviewed head Your newer registration increment NVIDIA GB10/RTX PRO 6000 release contracts passed 55/55 with five controls red; these operator checks do not establish family adoption. Posted by Ash's AI Assistant Synthena |
|
Thanks @jschmied for #797's registration follow-up. 1.1.1 includes activation, DeltaNet and Q/K numerical coverage for fifteen launch forms. The explicit FP64 residual and gating bounds remain intact. This increment adds contract coverage without changing production arithmetic; limited bf16 stress discrimination does not permit lower-precision sums. Posted by Ash's AI Assistant Synthena |
…rm and RoPE on CUDA for every family, checked against float64 The pull request's head is rebased on 1.0.12. Registration conflicts with ashhart#734 and ashhart#746, resolved keeping both sides: the kernel list, the fatbin table, the module exports, core/root.zig's references and tf-cuda-test's imports, usage and commands. The merged tree is the one the earlier landing of its previous head gave.
… states, and a platform layer for Windows (ashhart#734, ashhart#746, ashhart#797, ashhart#798, ashhart#836, ashhart#849, ashhart#852, ashhart#853, ashhart#859, ashhart#885, ashhart#886, ashhart#888)
What this changes
Next to
normsandembed_rows(#736), the per-row kernels a hybrid attention/DeltaNet family needs between itsprojections, as shared modules, operator-only (no model calls them yet), in the shape of #746:
zig/kernels/cuda/act_rows.cu,zig/src/cuda/act_rows.zig: SwiGLU from[gate | up]rows, the sigmoid outputgate (
o * sigmoid(g)from[q | gate]heads), 64-value group sums of the stored bf16 outputs (for an FP8/NVFP4activation scale downstream), and DFlash2's two-tap dynamic conv over block segments, with an optional residual.
zig/kernels/cuda/gdn_prep.cu,zig/src/cuda/gdn_prep.zig: Gated DeltaNet inputs per row: the causal conv windowover the kept rows plus the new ones (up to 8 taps), SiLU, q/k L2 norms, v,
g = exp(-exp(A_log) softplus(a))andbeta = sigmoid(b); key dims 64, 128, 256.zig/kernels/cuda/qk_rows.cu,zig/src/cuda/qk_rows.zig: QK RMS norm (fp32 or bf16 weights), RoPE (rotate-half,full or partial, from a cos/sin table or from
inv_freqin fp32), and the K/V cache write, from packed or stridedsources (
[q | gate]rows, padded k), packed or head-major outputs.zig/src/core/gdn_prep_ref.zig,zig/src/core/qk_ref.zig, andswiglu/dconvincore/act_ref.zig: the float64references.
Every kernel sums a row in one fixed order, so a row's bits do not depend on how many rows run beside it.
Users we know of: the Qwen3.8-27B family in #608 (its target's MLP, attention output gate, GDN layers and q/k, and
its DFlash2 drafter's conv), and any CUDA family with GDN layers or gated attention.
Receipt
46a08c18(1.0.12) plus this commit; one DGX Spark (GB10, sm_121, CUDA 13). No checkpoint.tf-cuda-test act-rows: SwiGLU at 17,408 and 192, output gate 24x256 and 3x64, group sums, dconv (5,120 ingroups of 16, segments 16 and 7, with and without residual): worst 0.996 of the tolerance.
tf-cuda-test gdn-prep: 16/48 heads at 128 (the 27B), 2/3 at 64, 1/2 at 256: worst 0.995.tf-cuda-test qk-rows: 48/4x128 full rotation, 48/4x128 none, 8/2x64 partial, 16/2x128 without norm, 24/4x256rotary 64 (the 27B), strided sources and head-major outputs bit-equal to the packed call: worst 0.988. The worst
elements are the float64 value correctly rounded to bf16 just above a power of two; every element above 0.8 of
the tolerance equals
bf16_rn(want).reading across a segment start (1,804x), softplus switching to
xabove 2 instead of 20 (14,503x), the QK normdividing by
dim - 1(1.43x; 1.95x in the dim-128 warp form), the conv window one tap short, and RoPE's rotate-halfsign flipped.
serial replies equal 0.6.6's except two at bf16 near-ties, drafted == serial,
bench_concurrent --alone --serial12/12 cells exact; teacher-forced on 4,092 rows: NLL +0.0011 against the Triton set, argmax agreement 99.12 %,
KL 0.00071. On an RTX 5090 (sm_120) every
tf-cuda-testof these modules passed, mutations included(BobClawblaw, Qwen3.8-27B on CUDA: the qwen27 family's engine for NVIDIA GPUs, every stream drafted #608).
docs/kernel-contract.md),zig build kernel-contract -Dnvcc=/usr/local/cuda/bin/nvccon the GB10(sm_121), exit 0:
SUMMARY 35 kernels: 35 pass gates 1-4, 0 fail, 0 known findings; 5 controls: 5 red as planted, 0 missed; 0 limit problems; gates 44467 ms, limits 1 mszig/tests/cuda/contract_act.zig,contract_gdn.zig,contract_qk.zig): SwiGLU and the outputgate, each with its 64-value sums of the stored outputs as their own entries; group sums; dconv with and without
residual;
tf_gdn_prep_64/128/256each as q/k, v, and g/beta;tf_qk_rows_win four forms (norm with table orinv_freqrotation, norm without rotation, no norm) andtf_qk_rowsin three (dim 256 rotary 64 with table orinv_freq, dim 64 rotary 32 without norm).q/k rotary 64; DFlash2's 5,120-channel conv in segments of 16; Kolibri's 48/4x128 q/k; at 1 row and 40 to 300
rows, with the row edges at 16 (the decode block size switch), the 2,048-value block edges and head-dim edges.
core/act_ref.zig,gdn_prep_ref.zig,qk_ref.zig) through the contract's bound,fp32 sums with their real depth (8 + 3 for group sums, 2 for the conv, the conv taps for GDN), the fp32 op counts
after them, and the bf16 rounding of the GDN conv before the norm (
mids2). Two entries keep the PR's own float64bound as a stated check, because the contract's fixed op count cannot carry them: dconv with residual (the conv is
rounded to bf16 before the add, an error of the conv's size, not the output's) and GDN's g and beta
(
g = exp(-y)carriesytimesy's relative error).the conv's own bf16 rounding (q/k norms, GDN q/k and v), a bf16 sum stays within about an output ulp, so those
specs state it (
sums.bf16 = 0, with the reason), as the existing RMS-norm entry does.registry.zig(the 256/128/64-thread formslaunch.rowThreadspicks,tf_qk_rowsat dim64 and 256,
tf_qk_rows_w), recorded fromtf-cuda-test kernel-contract-limitsover fatbins built for sm_80, 86,89, 120 and 121: every record current, 0 problems. Only sm_121 ran on a GPU.
dim - 1(tf_qk_rowsshapes andsums), dconv reading across a segment start (both dconv entries), softplus switching at 2 instead of 20 (all three
g/beta entries).
zig build test(84/84 steps, 1,378 of 1,385 tests, 7 skipped) andzig build test-cuda-host(39/39steps, 729 of 729).
tf-cuda-test norm-rowsstill passes on the shared rig.zig fmt --checkclean.lean_check.py: 517findings, as on
main.SUMMARY); sm_80, 86, 89 and 120 only through theirrecorded compiles (gate 5), not on a GPU; no model on
mainuses it.norm_rows_tests.zigexports its test rig (pub) soact_rows_tests.zigshares it instead of copying it.Decode block sizes, and the arithmetic we keep
launch.rowThreadsgives decode-sized calls (16 rows or fewer) the block sizes Triton's tuned glue uses for the27B:
swiglu128 threads, the output gate 64,gdn_prep64 (a warp a head either way). Prompt rows keep 256 and128. A value's arithmetic and its group sums stay on the same lanes, so the bits are the same at every row count,
which the tests check (1 and 3 rows take the small blocks, 17 and 64 the large ones).
What is left is a choice, not a shape. On a GB10, one decode row, a call:
swiglugdn_prepAt the same shape the difference is the sigmoid's division.
swigluover 17,408 values in a CUDA graph: exactlyrounded
__fdiv_rnwithexpf1.16 µs, with__expf1.15 µs, Triton'sdiv.fullandex2.approx(
__fdividef,__expf) 0.86 µs;__frcp_rngives__fdiv_rn(1, x)'s bits on all 65,536 bf16 inputs but 1.21 µs.These kernels keep the exactly rounded division, so a value has the same bits on every GPU, at about 0.3-0.5 µs a
call (on an RTX 5090, about 1 % of a 4.8k-context decode).
qk_rowskeeps its 256-thread block, whose reductionorder the shape sets.
Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (Noserving path changes.)
SUMMARYline is in the receipt.