Repository navigation
qwen3_5 cuda: require long_match (20 tokens) for the 27B's root copies - #1477
Conversation
|
Thanks @diwakergupta. Moving the policy into One thing for the A/B. On a GB10 we'll alternate the default MLX 27B against main: |
|
Thanks @diwakergupta. Here are the GB10 results on the default MLX 27B ( With DFlash2 loaded: the tokens match main in 20 of 20 prompt rows. Decode after a 2k, 16k and 64k prompt is up 3.0%, 2.5% and 21.5%, and the stream sweep is up 1.4% at one stream and 2.4% at four. Prefill is within 0.6%. Without a drafter (the default): the tokens again match in 20 of 20 rows, but decode after a prompt drops wherever short copies used to hit. For the four 2k prompts, main decodes at 23.4, 14.2, 14.7 and 23.5 tok/s, and this PR at 13.8 on all four. The median decode after a prompt is down 27.6% at 2k, 29.1% at 16k, 5.7% at 32k and 31.3% at 64k, and unchanged at 8k. The sweep is down 1.8% at one stream and 0.7% at four, and prefill is unchanged. With no draft model loaded, short copies are the 27B's only proposals, and a 20-token match leaves out most of them. Could the 20-token match apply only when a draft model is loaded, and stay at 5 without one? Then both cases should improve or hold, and we'll rerun both cells on a GB10. This won't make 1.1.8, which ships today, but it can go into the next release. |
19f9fc5 to
f8bd7c2
Compare
|
Thanks @ashhart, that's a clear result. Pushed
On the 3090 Ti (MLX 27B,
The full suite: 475/475 steps, and lean shows no new findings. Details are in the description. |
|
Thanks @diwakergupta, that's the change we asked for. With |
|
Hi @ashhart, checking in on the two GB10 cells you queued on |
The dense 27B (hidden 5120, 64 layers, no experts) already copies from a stream's root; a copy now also needs lanes.windows.long_match (20) matching tokens instead of 5, so short suffix matches do not preempt DFlash2's drafts. This applies to the 27B in every format. modelFacts holds the policy so a host test can check it.
Without a draft model, short copies are the 27B's only proposals, so a 20-token match cut decode after a prompt by up to 31% on a GB10. The match moves into the drafter's facts: lanes.drafter.Facts.copy_match (0: the target's) replaces the target's copy_match when Drafted wraps the backend, and DFlash2 on the dense 27B sets long_match. Alone the 27B keeps 5.
…ions copyMatch and dense27 went in between an existing doc comment and the declaration it documents; each now sits above that comment. The drafter wrapper's ordering test moves to drafted_role_test.zig so drafted_test.zig stays under 600 lines, and drafted.zig's facts comment fits 120 columns.
f8bd7c2 to
d5abe17
Compare
|
Thank you @diwakergupta. This is in TensorFold 1.2.0, released today: https://github.com/ashhart/TensorFold/releases/tag/v1.2.0 It landed with your commits under your own name, so you're listed as a TensorFold contributor, and it's credited to you in the release notes and the changelog. |
What this changes
The dense 27B (hidden 5120, 64 layers, no experts) already copies from a stream's root. Beside DFlash2, a copy now also needs
lanes.windows.long_match(20) matching tokens instead of 5, so short suffix matches don't preempt DFlash2's drafts. Without a draft model the 27B keepsmain's 5, because there copies are its only proposals. This is part (d) of the #1407 split, and it is independent of the others (based onmain).lanes.drafter.Factsgainscopy_match(0: the target's). WhenDraftedwraps a backend, it replaces the target'scopy_matchwith that value. No other drafter sets it.cuda_draft.zig) givecopy_match = long_matchon the dense 27B, throughcopyMatch(g), and 0 otherwise.modelFacts(cuda_native.zig) keeps onlyroot_copies.cuda_geometry.dense27names the shape.Receipt
Environment. RTX 3090 Ti (24 GB,
sm_86).TensorFold/Qwen3.8-27B-MLX-4bitrev22d8d538, bf16 KV cache,--context 32768, thinking on (the template default). With DFlash2,z-lab/Qwen3.8-27B-DFlash2rev50307d4cat 4 bits. Both binaries came fromzig build native -Dsm=86, one frommain(0d51120a) and one from this branch. Each ran twice, alternatingmainand this branch, on a restarted server for each drafter mode.Exactness.
tools/bench_concurrent.py --levels 1 --tokens 384 --reps 3 --alone --serial, with the default code and chat cells and--promptswith two long prompts (5,080 and 2,278 tokens):aloneandserial("draft": false) check was equal, in both modes on both binaries.token_sha256of this branch equalsmain's in 144/144 replies with DFlash2 and 144/144 without.Decode speed, per-stream tok/s, runs 1 / 2 (each a median of 3):
mainmainmainin every cell, with the same tokens per round, because the copy match ismain's 5.main's.Prompt speed: n/a. The copy policy does not reach prompt processing.
Tests. The full checklist suite, plus
test-qwen35-copies-hostandtest-shared-lane-regressions-host: exit 0, 475/475 build steps succeeded onmainat0d51120a.lean_new.pyagainstmain: 0 new problems. New and changed tests:Suffix copies: the dense 27B copies from the root after 20 matching tokens beside DFlash2, after 5 alone(qwen35_copies_host.zig). It checksenter_match5 with no drafter andcopyMatch20 for the 27B and 0 for a MoE shape. On the first revision it fails, since the target's own match was 20.the depth rule reads the drafter's facts, not the target's(drafted_test.zig) now also checks thatFacts.copy_match0 keeps the target's match and 20 replaces it.Not run. GB10. Metal: the policy is CUDA-only.
Checklist
"draft": false. Concurrent and resumed paths are unchanged: no prompt or arithmetic change.sm_86only.