Repository navigation
llama: a smaller Llama drafting for the served one (--drafter), replies unchanged (builds on #1415, #1416) - #1417
BobClawblaw wants to merge 9 commits into
Conversation
|
Drafted equals plain per the receipts, and there's no lane-core change or new kernel. That's good. Two things:
|
f7c7562 to
5d4a3af
Compare
|
Thanks. Pushed 5d4a3af (one commit, on #1416's new head):
Shared rounds. Both of your options, in turn:
One correction to the old receipt: the 87-117 tok/s single-stream figures from Also: the 3B is admitted as a drafter only ( On these commits over main a1e6d34: |
|
Thanks @BobClawblaw. The drafter's default now reads the published 4-bit layout, or bf16 with an explicit width of 0 ( Three asks:
|
A new `llama` family for the native Metal engine: dense Llama-architecture checkpoints (heads of 128, default RoPE, no biases, an untied head) in bf16, read in place from the shards with nothing converted. It keeps HF modeling_llama's rounding points (a bf16 residual, LlamaRMSNorm, RoPE with bf16 cos and sin, SiLU), runs prompt chunks on gemm_nax's tensor-unit GEMM and decode windows on a simdgroup-a-row matvec, decode attention on sdpa_vector lanes at absolute positions, and sampled draws on tf_sample_full. tf-llama-run checks greedy tokens, every position's logits, and that windows and one-row steps agree bit for bit. Measured on an M5 Ultra against HF's bf16 run of the release: 1,500 positions teacher-forced at mean KL 0.0015 and top-1 99.1%; decode 16.4 tokens/s a stream and 28-32 with two; cold prompts 1.3k tokens/s at 8k tokens and 563 at 131k. docs/recipes/nanbeige-4.3-33b-metal.md has the rest.
The family's Metal kernels through gates 1-5 (zig/tests/contract/metal_llama*.zig, the roll call and sources in contracts.zig): the glue (embedding, the norms at HF's rounding points, the residual add, RoPE with bf16 cos and sin, the SiLU gate, the decode attention's partials and their merge, the argmax draw by its stated NaN rule), the six row-projection forms, the four GEMM forms and the prompt attention at both served geometries, each with its float64 reference, served shapes and tiles, launched as forward.zig launches it; gate 5 reads the pipelines on this GPU. tf-kernel-contract --only llama on the M5 Ultra: 21 kernels, 21 pass gates 1-4, 0 fail, 0 known findings, 0 limit problems.
…out tensor units by name; the teacher-forced misses and the licence in the doc tf-llama-run takes exact's window width as an argument and loses its environment switches (LLAMA_LAYERS, LLAMA_WINDOW).
…hecks a planted row is reported
… near-tie, a float64 reference, the doc's misses and a one-process receipt
…eside the bf16 default
The family reads an MLX affine checkpoint as mlx_lm writes it: each projection
its own {u32 words, bf16 scales, bf16 biases} triple in groups of 64 at 4 or 8
bits, the embedding and head quantized, the norms bf16, and config.json's
uniform quantization table. Nothing is converted, by us or at load. Decode
windows run the core's row kernels, prompt chunks its tensor-unit affine
matmul; the embedding's rows come from a new family kernel, ll_embed_affine,
MLX's dequantize bf16(bf16(scale * q) + bias), registered with the contract.
affine_mm's 8-bit groups-of-64 form is registered too. capabilities lists
bf16, mlx-q4g64 and mlx-q8g64. The sums scratch is allocated only for
quantized checkpoints, so the bf16 path is as before.
Nanbeige4.3-33B on an M5 Ultra, two published quants pinned
(pratikgx/Nanbeige4.3-33B-MLX-4bit, fcmeyer/Nanbeige4.3-33B-MLX-8bit),
against HF's bf16 run of the release over 1,500 positions: 8-bit mean KL
0.00234, top-1 98.7% (MLX on the same files: 0.00272); 4-bit 0.0849, 91.1%
(MLX: 0.0851). Windows and one-row steps agree bit for bit on both; the
release's logits are bit-identical to before. The recipe doc has the tables;
the quants are lossy and the release stays the default.
…wo paths and a float64 pass, and a one-process receipt
…rafts verified by the model's windows Nanbeige4.1-3B shares Nanbeige4.3-33B's tokenizer, so the family admits it as a drafter only (config.zig's qualified list has a role; serving the 3B on its own is refused by name). drafter.zig is the lane host's priced copy proposer: one cache a stream synced to the context by longest common prefix (made and grown in 4,096-row steps), greedy steps chained on the GPU through token slots, and a depth from measured rates (the stream's acceptance, a chained step's time, a line fitted to the round's time by its window's rows). While more than one stream holds a drafter cache it proposes nothing, so shared rounds decode as undrafted. The model's window keeps the drafts its own draws agree with, so replies keep its bits. --drafter-bits 4 (the default) serves an MLX 4-bit drafter as published (mlx_lm's layout, read as the served model's quants are), 0 its bf16 release. Model.loadOn puts the drafter on the served model's queue and residency set; budget.longestWith counts its caches. M5 Ultra, the bf16 33B with mlx-community/Nanbeige4.1-3B-4bit: drafted greedy tokens equal plain greedy tokens on nine prompts in tf-llama-run's new draft mode (the bf16 drafter on two of them too), 23.2-46.4 tok/s against 16.0-16.3; served with --parallel 1, one stream 99.5-116.8 tok/s on the harness's ruler (16.4 undrafted) and every quick-plan check passes. With --parallel 2 two streams decode together at the undrafted rate less the lane core's copy drafts (code 31.5 against 34.4), so the recipe doc recommends the drafter with --parallel 1.
…ound priced and drafted, a failed warm-up frees the drafter
5d4a3af to
b652456
Compare
|
Thanks. Pushed b652456 (one commit on #1416's new head): 1. One memory budget. The backend's admission now runs on one ledger ( 2. Shared rounds are priced, and drafting stays on.
3. Warm-up failure. The harness's quick plan on the drafted The doc's drafter section is rewritten for the budget and the priced rounds. CI on these commits over main 03d08f1 (the pushed heads are rebased onto d0c9dc9, which adds only a CI workflow time limit): on #1417's head, which carries all three, |
What
--drafterfor thellamafamily: a smaller Llama on the same tokenizer proposes a stream's next tokens, and the served model verifies them in its windows, so replies keep the model's bits (builds on #1415 and #1416). It was brought up with Nanbeige/Nanbeige4.1-3B drafting for Nanbeige4.3-33B. The two share the tokenizer exactly (166,100 ids, merges, added tokens, bos and eos); only theirvocab_sizes pad differently. The 3B is admitted as a drafter only: serving it on its own is refused by name.How
zig/src/families/llama/drafter.zigis the lane host's priced copy proposer (LaneHost.proposers). A round asks it for up to 15 tokens after the stream's context. The window verifies them row by row and keeps the prefix the model's own draws agree with, as it keeps any copy draft. There is no lane-core change and no new kernel: the drafter runs the family's own forward on the served model's queue (Model.loadOn) and in its residency set.budget.Ledger) holds the streams' caches and the drafter's: when a stream is admitted, its drafter cache is made or grown to the stream's capacity (a growth's copy counted while it lives), and the stream waits if the two don't fit beside what is held. A freed slot keeps its tokens for the next request that shares its prefix, counted too, and gives way first when a stream needs the room.pricing.depthShared: every stream's 1 + p + ... + p^k tokens for a window of all their rows and every stream's chained steps, against the round undrafted); a stream drafts nothing only in a round where that costs more than it lands.--drafter-bits 4(the default) serves an MLX 4-bit drafter as published, inmlx_lm's layout, read as llama: published MLX affine quants (8-bit and 4-bit) read in place, beside the bf16 default (builds on #1415) #1416 reads the served model's quants:mlx-community/Nanbeige4.1-3B-4bit@ 4d6c41d88f1416777bbda005aad92798e56e5ba9.--drafter-bits 0serves the bf16 release @ 9c4555c37921c0982af8fffeee1e0a6e6b953c4f. The drafter's weights change no reply. Both are Apache-2.0.tf-llama-run <model> <tokens> draft <drafter>,<n>decodes greedily through the drafter's windows and prints the tokens with the rounds and drafts kept, for the identity check below.Measured (M5 Ultra, the bf16 33B)
Identity. On eight chat prompts (128 tokens, thinking on and off, English and Chinese) and after a 1,500-token prompt (256 tokens), the drafted greedy tokens equal the plain greedy tokens exactly with the published 4-bit drafter. The bf16 drafter gives the same tokens on two of the prompts. The drafted rates on those nine:
Served with
--parallel 1(the recipe's drafted setting). The harness's quick plan passes in full with the drafter on this branch's build (28 Oct 2026; its ruler, with no other model loaded, 113.5 / 110.7 / 109.2 / 101.8 tok/s), as it did on the first build: structured 18/18 with drafted == plain 12/12, tools 5/5, seeded sampling 9/9 equal on repeat and undrafted, turns resumed in 0.35 s, soak 60/60, concurrent 12/12, streaming, multi-turn, stop, thinking, max_tokens.--parallel 2)--parallel 1)bench_concurrent.py's code / chat, one stream, fresh server (128 tokens)The ruler's texts repeat, and the drafter continues them almost whole. Ordinary prompts gain 1.4-2.9x on the nine check prompts and 1.5-1.6x on
bench_concurrent.py's. A sampled stream at temperature 0.7 gains less, because greedy drafts land less often against sampled draws: 19.1 and 24.5 tok/s against 16.2.Two streams. With
--parallel 2and the drafter, every stream drafts in shared rounds. On fresh servers, eight new prompts sent two at a time (greedy, 256 tokens): 34.4-42.4 tok/s together (38.4 on average) against 26.6-30.0 (29.0) without--drafter, every reply's token ids equal. Streams joining, leaving, queued, refused (HTTP 400) and cancelled each return the ids of their plain solo run; in rounds shared from the first token to the last, 189 drafts were offered and 127 kept.Receipt
--context 131072 --parallel 2 --prompt-cache-gib 8andLLAMA_LOAD_LIMIT_GB=150, with--draftermlx-community/Nanbeige4.1-3B-4bit @ 4d6c41d88f1416777bbda005aad92798e56e5ba9 (--drafter-bits 4) or Nanbeige/Nanbeige4.1-3B @ 9c4555c37921c0982af8fffeee1e0a6e6b953c4f (--drafter-bits 0). An idle server of another model was loaded beside it for the first build's measurements; the 28 Oct streams and speed runs, and the harness's ruler, ran with no other model loaded.tools/bench_concurrent.py --levels 1,2 --tokens 128 --temperatures 0,0.7 --alone --serialwith each drafter: every reply equals its request alone and with"draft": false(alone 12/12, serial 12/12, failed 0, for each).tools/bench_openai.py --tokens 256 --reps 3, before → after with the 4-bit drafter:tools/bench_cache.py --require-cold, a 9,000-token prompt cold: 6.92 s with the drafter. The drafter reads the prompt after the model's own pass. Repeated raw-token prompts reportcached_tokens0, as in llama: Nanbeige4.3-33B on Metal, the bf16 release served as published, every kernel in the contract #1415: the family's prompt cache resumes chat turns, and the harness's turns check resumes 5,493 of 5,649 tokens in 0.35 s against 4.39 s cold.zig build test,test-kernel-contract,test-golden,fuzz-cortheon,dev-tools,test-server-securityandtest-pull-securityall exit 0, and on llama: Nanbeige4.3-33B on Metal, the bf16 release served as published, every kernel in the contract #1415's and llama: published MLX affine quants (8-bit and 4-bit) read in place, beside the bf16 default (builds on #1415) #1416's headszig build testandtest-kernel-contractexit 0;zig fmt --checkis clean and the lean check finds 0 new problems (428 on main and on each head);llama_teacher_judge_test.pypasses;tf-kernel-contract --only llamaon the M5 Ultra:SUMMARY 23 kernels: 23 pass gates 1-4, 0 fail, 0 known findings; 0 controls: 0 red as planted, 0 missed; 0 limit problems(21 kernels on llama: Nanbeige4.3-33B on Metal, the bf16 release served as published, every kernel in the contract #1415's head). Rebuilt on the rebased heads, the bf16 release's 1,500-position logits are bit-identical to the judged run on all three, both quants' to theirs, and a drafted greedy chat (128 tokens) equals the plain one. The pushed heads differ from the ones CI ran on only in comments and docstrings (the lean check's one-line rule); fmt, lean, the judge's tests, the build andzig build testwere rerun on them.Checks
zig build testcovers the depth rule and its shared-round pricing, the cost fit, the acceptance history, the drafter role, the roll call, the one budget (two drafted 240,000-token requests that each fit a 100 GiB budget alone are refused together), a slot's growth bytes and a failed warm-up freeing the drafter. Without--drafter, the served path is unchanged: t1500 and t64 logits and a greedy chat are bit-identical to #1415's measured build.