Repository navigation
qwen3_5 cuda: a prompt chunk's last layer runs q, attention, o and the MLP over the kept row's tile - #2229
Conversation
d20b34a to
77c3f9d
Compare
|
Thanks @jschmied. Keeping k and v over the whole chunk while only the kept row's tile runs the rest is a clean cut, and the planted uncounted-keys control plus 18 servers of bit-equal last-row logits per model make it easy to trust. We'll add the changelog line, crediting @jungjipdo for |
…shhart#2146 landed, ashhart#2229 without the branch name
|
Our GB10 run, main against this head, Qwen3.8-27B: verdict GREEN. 32K prompts are 1.6% to 2.0% faster (about 1,284 to 1,306 tok/s), decode after them is level, and the 1- and 4-stream chat and code sweeps are within 0.1%. No token differences across runs in the 20 prompt rows I checked. A small gain with nothing lost, and exact. Thanks @jschmied: it's queued for after the 1.2.3 cut. |
77c3f9d to
f1f22d3
Compare
…e MLP over the kept row's tile (ashhart#2165) A prompt chunk keeps one row's logits. Past the last layer's keys and values, its queries' attention, gate, o projection and MLP reach nothing but that row, so they run over the last 128 rows only; k and v still cover every row. 128 rows keep q, o and the MLP on the prompt GEMMs (rows > 16) at the same per-row bits. - cuda_prompt.runFrom: the prompt attention from a chunk row on, each row over its own keys (len + from). - core/prompt_tail.zig: the decision any family can share. A chunk past one tile, in one part, whose last layer fits a row range and has no other readers, takes the tail from total - 128. - qwen3_5/cuda_prompt_tail.zig: Qwen 3.5's facts for it. Hidden reads, learner hooks, pockets, int8, images and a tapped last layer (MTP taps it) are readers; odd head groups and a non-attention last layer do not fit. - The dense and routed MLPs both take the tail; glue launches pass no device row count for it. - Contract: qwen35 pages checks runFrom's rows against the whole chunk's, with a planted control (the start's keys not counted) that must move them. Host test: each refusing fact, planted, refuses the tail. Ports two cudafast-qwen38-27b pieces by intent: our last-layer tail tile, and jungjipdo's kept-row tail (the attention from the kept row's own query). Credit to jungjipdo.
f1f22d3 to
017fd8e
Compare
|
Thank you @jschmied. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
…shhart#2146 landed, ashhart#2229 without the branch name
…shhart#2146 landed, ashhart#2229 without the branch name
Step: test-qwen-serving-host. Old pins: e166f3f. New base: 063d881 (origin/main). Sets the five kernel hashes (experts.cu, experts_pack.cu, experts_prefill.cu, qmm_group.cu, qmm_prefill.cu), the qmm_group prefix and the launch-sequence hash to 063d881's bytes. The prefix is now group[0..16095]: line 1 lost 37 bytes and the rest is byte-equal, so it covers the same text e166f3f's group[0..16132] did. No code changes; 2/2 tests pass. Recorded, as merged and reviewed: - #2229 (3d4f6aa): a prompt chunk's last layer runs q, attention, gate, o and the MLP over its last 128 rows (the launch-sequence pin). - efdf28f, fcb1529, f3bcb78, ecef17d, 2ebc3c2, 42d3461 (lean, no PR number in the history): line-1 comments of the five kernel files only.
|
Thanks @jschmied! This is in TensorFold 1.2.4, out now: https://github.com/ashhart/TensorFold/releases/tag/v1.2.4 |
|
Thanks @jungjipdo! This is in TensorFold 1.2.4, out now: https://github.com/ashhart/TensorFold/releases/tag/v1.2.4 |
What this changes
A prompt chunk keeps one row's logits. Every layer's keys, values and recurrences are still written for every row. Past the last layer's keys and values, though, its queries' attention, gate, o projection and MLP feed nothing but that row. So in the last layer, k and v still run over the whole chunk, and q, attention,
attn_gate, o and the MLP run over the last 128 rows only.128 rows, not one. At 128 rows, q, o and the MLP stay on the prompt GEMMs (rows > 16), and each row keeps its own per-row bits. One row would drop to the decode kernels.
cuda_prompt.runFromruns the prompt attention from one chunk row onward: each row over its own keys (len + from), with the same key tiles.runis nowrunFrom(.., 0, rows), paged and whole.Dense and routed MLPs both take the tail. The glue launches (
attn_gate,mlp_act, routing) get no device row count for the tail, because their rows come from their own pointers.The decision lives in
core/prompt_tail.zig, so any family can share it: a chunk past one tile, in one part, whose last layer fits a row range and has no other readers, takes the tail fromtotal - 128. Its host tests cover the short chunk, a cut chunk, readers and a layer that doesn't fit.Qwen 3.5's facts,
qwen3_5/cuda_prompt_tail.zig: hidden reads, learner hooks, pockets, int8, images and a tapped last layer are readers; odd head groups and a last layer that is not attention don't fit. MTP taps the last layer, so a 35B served with its MTP head keeps the full layer. DFlash2's taps (5..61) do not refuse it. A host test plants each fact and checks that each one refuses the tail.Issue: Fixes qwen3_5 CUDA: the prompt's last layer computes q/o/MLP only for the kept row's tile, logits bit-equal #2165.
Stacked on: main
981fe201d, one commit.atc overlap --json: no conflicts against open pull requests (qwen35: dense BF16 loading and native prompt logprobs #2020 and CUDA: #1764's BF16 prompt tile for Qwen ModelOpt, Nemotron and Dory, plus two exact Qwen prompt kernels (#1762) #2008 share files and merge cleanly).Checks on this head
77c3f9de0.zig build testRC 0, 0 errors; the no-GPU CI set (test-kernel-contract test-golden test-server-security test-pull-security) RC 0;git diff --checkclean.tf-cuda-test qwen-pageson a GB10 (sm_121): every paged == contiguous case passes, bf16 and fp8, including therunFromrows, and its controls are red as planted (swapped table, planted row, uncounted tail keys).Receipt
981fe201d+ this commit; Zig 0.17.0, nvcc 13.0; GB10 (sm_121), clock capped at 2,300 MHz, page cache dropped before every server start;TensorFold/Qwen3.8-27B-MLX-4bitwith its DFlash2 drafter, and Qwen3.6-35B-A3B MLX 4-bit without a drafter.runFromrows against the whole chunk's, paged and whole, bf16 and fp8. Its planted control (the start's keys left uncounted) must move those rows.TTFT on a GB10, clock capped at 2,300 MHz, page cache dropped per start. Six ABBA rounds of fresh servers, each with A (main 981fe20), A' (a copy of main's binary) and B (this head):
Decode cells (2K, 16K, four streams) stay within ±0.2 % on both models.
Co-credit to jungjipdo: their kept-row prompt tail in the cudafast Qwen3.8 27B challenge contributed the attention from the kept row's own query (
runFrom). The 128-row q/o/MLP tile is from our entry in the same challenge.