Repository navigation
Conversation
8 tasks done
jschmied
added a commit
to jschmied/TensorFold
that referenced
this pull request
Oct 13, 2026
…rt#797 (gdn_prep loads first, IEEE 1/sqrt in qk_rows and gdn_prep)
… 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
jschmied
force-pushed
the
cuda-glue-rows
branch
from
October 14, 2026 09:13
b172afe to
cdd5c79
Compare
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
c36b536d(1.0.9) 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).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).
zig build testandzig build test-cuda-host(27/27 steps, 323/323 tests).zig fmt --checkclean.lean_check.py: 538 findings, as onmain.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.)