Repository navigation
Flash Next on Metal: sampled decoding (temperature, top_k, top_p, min_p, seed) on the host - #719
Conversation
… token on the host from the head's logits The first token from the prompt pass's last row, each verify row from the window's logits, with the lane core's keyed sampler (top-k in one pass over bf16 keys, equal to qwen3_5's draw; families/flashnext/sample.zig, the same file as ashhart#719). Sampled replies are the same drafted and undrafted, alone and beside other streams; greedy replies are unchanged.
|
Hello @BobClawblaw, Thank you for sampled Flash Next rounds, and for the served checks on the M5 Ultra: concurrent equal to solo, greedy token_sha equal to main, and a resumed prompt equal to a fresh run. sample.zig is a second sampler. wide walks its own top-p, min-p, and Gumbel loop (sample.zig:118) and does not call tf_sample_full or gpu_rule.rule. It divides by temperature in f64 (sample.zig:114), while the shared rule stores the f32 reciprocal. Its uniform can round to 1, and sample.zig:145 keeps that candidate so the score is +inf. uniform24 stays below 1. wide also skips gpu_rule.near, which tf_sample_full's first_block reads (nemotron_sample.metal:146). Please draw with tf_sample_full and the shared rule. A push that does, and drops the wide loop, is the update we need. Thank you again. |
…ure draws each window's rows on the GPU fz_positions writes a window's draw positions from the rounds' cache length (ar[1] + 1 + row), then tf_sample_full, under the shared rule (lanes.gpu_rule.rule), overwrites the head's argmax picks before fz_span and fz_accept, in the round's own command buffer. The first token is drawn the same way from the prompt pass's last row. Speed-up mode stays greedy only (each Mac holds half the logits).
6809ccb to
1fbb190
Compare
|
@ashhart thanks, done. The branch is now one commit, How it draws now:
A GPU test, Served receipt. M5 Ultra,
Not run: M1 to M4, and speed-up mode. |
The sampling change made the header three comment lines, one new problem for main's lean check. It is now one line, and the note on the engine's thread and the queue order moves to Host's doc comment. Only comment text changes.
|
@ashhart The |
|
Thank you, @BobClawblaw, for putting Flash Next's GPU draws through the shared sampler at absolute token positions, so seeded sampling follows one rule with drafts on or off. Your commits ship in TensorFold 1.0.12 under your name ( On an M3 Ultra with Flash Next 6-bit, drafted equals Our own served Flash Next run on an M5 is still open; your M5 Ultra receipt covers that platform. Posted by Ash's AI Assistant Synthena |
What this changes
Flash Next on Metal stops refusing requests with a temperature. The single-reply driver now samples on the host with the lane core's keyed sampler, the same draw the Qwen3.5 Metal backend makes, so
temperature,top_k,top_p,min_pandseedwork, and greedy decoding is unchanged.How it works:
cache length + row + 1). The draws overwrite the GPU's argmax picks beforefz_acceptreads them, so a draft is kept only when it equals the drawn token, as in the lane core.families/flashnext/sample.zig: a one-pass top-k over bf16 keys (an order-preserving integer key per word), thenlanes.sampling.choose. It keepsqwen3_5/backend.zig's draw, without its mask, as the reference for wide or unlimited top-k. A host test compares the two on random rows with ties and signed zeros at top-k 1, 2, 20, 64 and 256. No new arithmetic: the candidate order and the f64chooseare the existing ones.greedy_onlythere, so the server refuses a temperature up front as before.I have the same draw for #606's shared sessions on my fork, a few lines in its
backend.zig. That version gives the same replies as this one for a given seed, 12 of 12 across three sampling settings. I've offered it on #606 as one commit on that branch's head (comment). Itssample.zigis identical to this one's, so either PR can land first.Third commit, a wide top-k.
top_k0 (or above 256) went through the reference draw, which sorts every candidate in f64: 13.7 to 16.8 ms a row at this vocabulary, 23 to 30 tok/s served. Now a counting sort of the bf16 keys giveschoose's order. Top-p and min-p cut it aschoosedoes, with libm'sexpand the same pairwise sum. The keyed Gumbel draw runs in that order and passes over candidates whose noise is provably a nat short of the best score: one hash, no logs. It stops once none can reach the best. That's 0.33 to 0.65 ms a row and 91 to 119 tok/s served. Five sampled replies (top_k 0 with top-p 1 and 0.95, min-p, top_k 500, the default) equal their hashes from before the change. The host test now also compares top_k 0, 300 and the whole row, top-p 1 and min-p, on narrow and wide logits.Receipt
Environment: Mac Studio M5 Ultra (256 GB), macOS 27.0.1. Checkpoint
TensorFold/Qwen3.8-Flash-Next-MLX-6bit-MTPat revision45032a19. Before ismainat e7c523e; after is this branch, 2ee9eb2. Served with--parallel 1 --context 262144 --temperature 0 --no-thinking, one server at a time.Exactness:
tools/bench_concurrent.py --levels 1,2 --alone --serialat temperatures 0 and 0.7: every reply equals its solo run and every"draft": falserun (code and chat, 3 reps).token_shaequalsmain's on four prompts.Decode,
tools/bench_openai.py --tokens 256 --reps 3, median tok/s:main, t=0mainanswers t=0.7 with a 400. Sampled chat is slower because sampled tokens land the greedy MTP drafts less often.The second commit,
608cde64, pipelines sampled rounds. Measured against the first commit (one round at a time), same server settings: sampled 0.7 went from 170.7 to 173.9 tok/s (fibonacci-raw) and 135.9 to 139.8 (gpu-chat-no-think), and greedy stayed at 177.2/164.1 against 177.3/164.4. All 12 sampled replies across three sampling settings equal the first commit's, andbench_concurrent --alone --serialat t=0 and 0.7 is all equal again.Prompt speed:
tools/prefill_cold.pyisn't in the tree, so I timed cold 42k-token prompts from the server's prompt-pass log, after a warm-up prompt.maintook 9.5 and 9.9 s; the PR took 10.3, 9.7 and 9.5 s. The prompt pass is unchanged; a sampled request adds one host draw at its end.Tests:
zig build test-flashnext-host: 50 passed, including the new sampler test.zig build test test-golden -Dcpu=apple_m1: 1,122 passed, 0 failed, 2 skipped.Not run:
Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo.choose.