mlx-bun 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -21
- package/THIRD_PARTY_LICENSES.md +1 -0
- package/docs/archive/mlx-bun-lab-report.html +275 -0
- package/docs/archive/wwdc-mlx-bun.html +848 -0
- package/docs/design/audio-input-plan.md +356 -0
- package/docs/design/batching-perf-path.md +58 -35
- package/docs/design/batching-v2-plan.md +23 -9
- package/docs/design/bucketing-stage.md +2 -1
- package/docs/design/compat-cli-surface-design.md +4 -3
- package/docs/design/decode-speed-program.md +172 -0
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +371 -0
- package/docs/design/dspark-speculative-decoding.md +167 -5
- package/docs/design/faithful-l1-consolidation.md +310 -0
- package/docs/design/generic-model-support.md +8 -5
- package/docs/design/grammar-spec-batching-integration.md +301 -0
- package/docs/design/minicpm5-decode-megakernel.md +16 -11
- package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
- package/docs/design/omlx-adoption-map.md +14 -6
- package/docs/design/orpo-training.md +34 -30
- package/docs/design/paged-kv-cache.md +214 -0
- package/docs/design/parallel-slots.md +82 -49
- package/docs/design/parity-tier-dag.md +43 -33
- package/docs/design/repo-cleanup-plan.md +189 -0
- package/docs/design/runtime-isolation.md +19 -3
- package/docs/design/segmented-backward-training.md +3 -2
- package/docs/design/ssd-kv-cold-tier.md +130 -0
- package/docs/design/structured-output.md +484 -0
- package/docs/design/the-dreaming-master-plan.md +2 -3
- package/docs/design/turboquant-kv.md +235 -0
- package/docs/design/unified-engine-frontier-plan.md +774 -0
- package/docs/design/web-chat-beat-matrix.md +315 -0
- package/docs/design/web-chat-redesign.md +1112 -0
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/lab-build-journal.md +2 -2
- package/docs/investigations/openwiki-evaluation.md +249 -0
- package/docs/planning/IDEAS.md +14 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -3
- package/docs/planning/chat-ui-vision-memory-first.md +199 -0
- package/docs/planning/chat-ui-vision.md +50 -0
- package/docs/planning/memory-docs-and-dag-plan.md +15 -6
- package/docs/planning/release-notes-v0.0.11.md +239 -0
- package/docs/reference/cli.md +35 -16
- package/docs/reference/distribution.md +13 -6
- package/docs/reference/embedding.md +35 -14
- package/docs/reference/features-matrix.md +97 -0
- package/docs/reference/library-api.md +30 -9
- package/docs/reference/memory.md +26 -6
- package/docs/reference/models.md +11 -1
- package/docs/reference/orpo-quickstart.md +3 -4
- package/docs/reference/server-api.md +634 -22
- package/docs/reference/server-config.md +250 -121
- package/docs/reference/training.md +14 -15
- package/package.json +5 -3
- package/src/anthropic.ts +13 -0
- package/src/audio/conformer.ts +647 -0
- package/src/audio/decode.ts +133 -0
- package/src/audio/features.ts +202 -0
- package/src/audio/transcode.ts +67 -0
- package/src/cli.ts +356 -105
- package/src/config.ts +49 -2
- package/src/download.ts +40 -0
- package/src/eval/README.md +7 -6
- package/src/eval/kl.ts +59 -3
- package/src/eval/quality-db.ts +2 -2
- package/src/eval/runner.ts +3 -3
- package/src/expert-offload.ts +15 -2
- package/src/flags.ts +13 -0
- package/src/generate.ts +330 -24
- package/src/grammar.ts +585 -0
- package/src/hub-rest.ts +242 -0
- package/src/kv-store.ts +442 -88
- package/src/lora.ts +8 -0
- package/src/md-modules.d.ts +42 -0
- package/src/media-fetch.ts +284 -0
- package/src/memory/rest.ts +245 -0
- package/src/memory/vault.ts +74 -0
- package/src/mlx/array.ts +106 -19
- package/src/mlx/autograd.ts +2 -2
- package/src/mlx/ffi.ts +27 -3
- package/src/mlx/metal-kernel.ts +7 -4
- package/src/mlx/ops.ts +153 -23
- package/src/mlx/turboquant-ops.ts +831 -0
- package/src/mlx/turboquant-tables.ts +237 -0
- package/src/model/batched-mask.ts +62 -1
- package/src/model/batched-quant.ts +206 -0
- package/src/model/batched-rotating-quant.ts +346 -0
- package/src/model/batched-rotating.ts +46 -1
- package/src/model/compiled-decode.ts +4 -15
- package/src/model/factory.ts +10 -4
- package/src/model/gemma4-base.ts +363 -39
- package/src/model/gemma4.ts +122 -33
- package/src/model/generated/gemma4-12b.ts +9 -13
- package/src/model/generated/gemma4-26b.ts +10 -5
- package/src/model/generated/gemma4-e4b.ts +14 -9
- package/src/model/minicpm5.ts +58 -102
- package/src/model/paged-kv.ts +253 -0
- package/src/model/qwen3-delta.ts +76 -15
- package/src/model/qwen3-moe.ts +404 -0
- package/src/model/qwen3.ts +9 -8
- package/src/model/qwen3_5.ts +88 -23
- package/src/model/support.ts +12 -1
- package/src/model/universal/dense.ts +40 -5
- package/src/model/universal/rope.ts +36 -21
- package/src/pi-web.ts +1299 -82
- package/src/preflight.ts +27 -8
- package/src/prompt-cache.ts +293 -33
- package/src/quantize/quantizer.ts +16 -1
- package/src/registry.ts +57 -2
- package/src/serve/batch-scheduler.ts +965 -72
- package/src/serve/generation-gateway.ts +214 -11
- package/src/serve/isolate.ts +417 -0
- package/src/serve/lane-registry.ts +44 -0
- package/src/serve/session-search.ts +326 -0
- package/src/server.ts +1380 -135
- package/src/spec/assistant-source.ts +150 -0
- package/src/spec/deepspec-source.ts +143 -0
- package/src/spec/dflash-source.ts +124 -0
- package/src/spec/dspark/ab-stats.ts +136 -0
- package/src/spec/dspark/calibration.ts +112 -0
- package/src/spec/dspark/deepspec-module.ts +801 -0
- package/src/spec/dspark/generate-dflash.ts +72 -20
- package/src/spec/dspark/loader.ts +23 -0
- package/src/spec/dspark/module-dflash.ts +278 -36
- package/src/spec/dspark/quantize-drafter.ts +91 -0
- package/src/spec/generate.ts +59 -25
- package/src/spec/ngram-source.ts +132 -0
- package/src/spec/serve-loop.ts +536 -0
- package/src/spec/source.ts +93 -0
- package/src/spec/two-model.ts +171 -0
- package/src/ssd-cache.ts +107 -35
- package/src/tokenizer.ts +288 -2
- package/src/tool-approvals.ts +131 -0
- package/src/tool-call.ts +408 -20
- package/src/train/flash-cce.ts +2 -2
- package/src/train/job.ts +0 -2
- package/src/train/trainer.ts +1 -4
- package/src/vision/prompt.ts +217 -48
- package/src/web/app.html +1184 -1789
- package/src/web/app.js +5667 -0
- package/src/web/icon.svg +13 -0
- package/src/web/manifest.webmanifest +24 -0
- package/src/web/src/adapters-panel.ts +288 -0
- package/src/web/src/api.ts +57 -0
- package/src/web/src/assistant.ts +485 -0
- package/src/web/src/chat.ts +1050 -0
- package/src/web/src/composer.ts +959 -0
- package/src/web/src/dataset.ts +132 -0
- package/src/web/src/finetune.ts +267 -0
- package/src/web/src/hub.ts +428 -0
- package/src/web/src/main.ts +98 -0
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +572 -0
- package/src/web/src/model-picker.ts +159 -0
- package/src/web/src/palette.ts +346 -0
- package/src/web/src/protocol.ts +62 -0
- package/src/web/src/quantize.ts +167 -0
- package/src/web/src/rag.ts +274 -0
- package/src/web/src/sessions.ts +469 -0
- package/src/web/src/shell.ts +804 -0
- package/src/web/src/status.ts +252 -0
- package/src/web/src/ui-catalog.ts +92 -0
- package/src/web/sw.js +71 -0
- package/src/web/vendor/README.md +61 -0
- package/src/web/vendor/hljs-LICENSE +29 -0
- package/src/web/vendor/hljs-theme.css +59 -0
- package/src/web/vendor/hljs.js +26 -0
- package/src/model/fused-decode-kernel.ts +0 -312
- package/src/model/fused-geglu-kernel.ts +0 -198
- package/src/model/fused-mlp-kernel.ts +0 -169
- package/src/model/fused-swiglu-kernel.ts +0 -240
- package/src/model/steel-linear-kernel.ts +0 -96
- package/src/status-page.html +0 -497
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Decode-speed program — the ranked path to faster tokens
|
|
2
|
+
|
|
3
|
+
Status: PLANNED (2026-07-04). The single-stream decode roadmap, written
|
|
4
|
+
down after the mode-matrix benchmark (scripts/bench-modes.ts) confirmed
|
|
5
|
+
what the roofline work predicted: **the baseline decode path has no waste
|
|
6
|
+
left** — e4b/cpm5/12B sit at the memory-bandwidth wall in every tier, so
|
|
7
|
+
tier levers can't buy short-context decode speed. Faster means one of
|
|
8
|
+
four physical moves. Each lever below has evidence, an expected win, and
|
|
9
|
+
a trigger; pick them up in order.
|
|
10
|
+
|
|
11
|
+
**LANDED 2026-07-04 (correcting "no waste left" for CPM5):** CPM5 decode
|
|
12
|
+
carried one real, non-physics waste — an UNFUSED swiglu (`sigmoid`+`mul`+`mul`
|
|
13
|
+
= 3 kernels/layer × 24). Porting mlx-lm's `@partial(mx.compile) swiglu`
|
|
14
|
+
(activations.py → `compiledSwiglu` in minicpm5.ts, M=1 decode, kill-switch
|
|
15
|
+
`MLX_BUN_COMPILED_SWIGLU=0`) fused it to one `CV2ISigmoid…` kernel and moved
|
|
16
|
+
CPM5 **250.5 → 264.4 tok/s (+5.5%), to parity/ahead of mlx-lm (260.3)** —
|
|
17
|
+
bit-identical tokens. The win was per-dispatch host+encode tax (48 ops/token),
|
|
18
|
+
NOT the ~0.9% elementwise GPU time the Xcode capture showed; that's also why
|
|
19
|
+
CompiledDecode was 0% (it replays the same unfused graph). See §4 and
|
|
20
|
+
[[cpm5-decode-parity-investigation]]. The bandwidth-wall framing holds for the
|
|
21
|
+
*matmul* path; small-elementwise fusion is the exception it missed.
|
|
22
|
+
|
|
23
|
+
The physics: decode tok/s ≈ bandwidth ÷ bytes-touched-per-token
|
|
24
|
+
(M4 Pro ~273 GB/s). To go faster: read the bytes ONCE for several tokens
|
|
25
|
+
(speculation, batching), read FEWER bytes (quantization), SKIP reads
|
|
26
|
+
(caching), or shave the non-GPU residue (host overhead). TTFT/throughput
|
|
27
|
+
are already leadership territory (caches 16×/8.7× second-turn TTFT,
|
|
28
|
+
batching 12× TTFT + 2.1× aggregate under load, 2–5× startup vs the
|
|
29
|
+
Python stacks) — this program is about the decode number itself.
|
|
30
|
+
|
|
31
|
+
## The levers, ranked
|
|
32
|
+
|
|
33
|
+
### 1. Speculative decoding — the only wall-breaker [expected 1.1–3×]
|
|
34
|
+
|
|
35
|
+
One target forward verifies γ drafts + a bonus: the weight read amortizes
|
|
36
|
+
over up-to-γ+1 tokens. The serve loop, verify math (L1: 48/48 vs mlx-lm),
|
|
37
|
+
grammar composition, and `usage.speculation` telemetry ALL landed
|
|
38
|
+
2026-07-03; what remains is drafters worth running:
|
|
39
|
+
|
|
40
|
+
- **1a. AssistantSource (build next)** — wrap the optiq KV-borrowing
|
|
41
|
+
gemma assistant drafter (`src/spec/drafter.ts`, bit-exact vs optiq's
|
|
42
|
+
spec_generate) as a `DraftSource` behind the SAME `--draft-model` flag
|
|
43
|
+
(parity-plan §7.9 dispatch-by-artifact). Artifacts downloaded for e4b +
|
|
44
|
+
12B. Measured today: **12B γ=1 ≈ 1.09×** with this deliberately heavy
|
|
45
|
+
drafter (docs/design/spec-decode-larger-targets.md). L2 oracle exists.
|
|
46
|
+
- **1b. Cheaper drafter head** — the 262k tied-embedding argmax every
|
|
47
|
+
draft step dominates γ≥2 cost; capping/approximating it extends the win
|
|
48
|
+
past γ=1 (same doc, "remaining levers").
|
|
49
|
+
- **1d. Grammar-aware speculation (Josh's insight, 2026-07-04)** — the
|
|
50
|
+
grammar mask collapses the drafting problem on structured output:
|
|
51
|
+
(i) **jump-forward** — when the mask admits exactly ONE token
|
|
52
|
+
(structural JSON runs), emit it with NO forward at all and fold it into
|
|
53
|
+
the next verify window as a pre-accepted draft (zero-cost tokens,
|
|
54
|
+
20–40% of dense-schema output); (ii) **constrained drafting** — mask
|
|
55
|
+
the drafter too (matcher `rollBack` on rejection, the flagged
|
|
56
|
+
MLX_BUN_SPEC_GRAMMAR_DRAFT lever): our own matrix measured acceptance
|
|
57
|
+
DROP 51%→29% under grammar with a blind drafter — constrained drafting
|
|
58
|
+
flips that to ~1.0 on structural spans; (iii) **grammar-pruned draft
|
|
59
|
+
TREES** — a DSpark token tree's branching factor collapses under a
|
|
60
|
+
tight mask, concentrating the budget on content positions
|
|
61
|
+
(XGrammar-2's `traverse_draft_tree`, the U2 trigger in
|
|
62
|
+
structured-output.md). Agent output is majority-structural: this turns
|
|
63
|
+
speculation near-deterministic exactly where agents spend tokens.
|
|
64
|
+
- **1c. DSpark (THE goal drafter)** — DFlash KV-injection, architecture
|
|
65
|
+
verified (overfit τ=3.24, paper-range). Blockers are research, not
|
|
66
|
+
serve wiring: 27B/12B retarget (regen+train, Josh's shell), data scale
|
|
67
|
+
(thousands of on-distribution generations vs 160), draft-loop
|
|
68
|
+
tightening. At τ≈3 on the 27B agent workload: **~15 → ~35–45 tok/s**
|
|
69
|
+
(docs/investigations/dspark-handoff.md). Slots in as `DflashSource`,
|
|
70
|
+
no-oracle/KL-gated (a Lab item).
|
|
71
|
+
|
|
72
|
+
### 2. mlx bump — narrow 26B / spec-decode wins, NOT a general decode lever [main-only, from-source]
|
|
73
|
+
|
|
74
|
+
Pinned at mlx 0.31.2 — still the newest *released* mlx (and newest on
|
|
75
|
+
PyPI). All the decode-relevant work is UNRELEASED on mlx `main`; there is
|
|
76
|
+
no nightly wheel, so a bump means building mlx + mlx-c from source AND
|
|
77
|
+
running the oracle (mlx-lm / optiq — no released version targets mlx >
|
|
78
|
+
0.31.2) on an unvalidated combination. That oracle validity is the real
|
|
79
|
+
cost, NOT golden regen (regenerating goldens is the verification, not a
|
|
80
|
+
gate). Upstream refs below are all in `ml-explore/mlx`, full-URL'd — a bare
|
|
81
|
+
`#NNNN` in this repo resolves to our own tracker (a 404), not theirs.
|
|
82
|
+
|
|
83
|
+
What `main` actually has (confirmed against the PR pages):
|
|
84
|
+
- [ml-explore/mlx#3485](https://github.com/ml-explore/mlx/pull/3485)
|
|
85
|
+
`GatherQMM::output_shapes` — merged 2026-05-29, zero numeric change. THE
|
|
86
|
+
prize: resolves the `src/generate.ts` blocker that keeps 26B MoE decode
|
|
87
|
+
uncompiled → unblocks CompiledDecode over the MoE (attacks the 26B host
|
|
88
|
+
term).
|
|
89
|
+
- [ml-explore/mlx#3764](https://github.com/ml-explore/mlx/pull/3764)
|
|
90
|
+
`qmv_wide` — merged 2026-06-26. Small-M (≈2–8) quant matvec; helps
|
|
91
|
+
SPEC-DECODE verify + batching, NOT single-stream M=1 and NOT the gather /
|
|
92
|
+
MoE path. Becomes the default for M≈2–8 → re-baseline batched goldens.
|
|
93
|
+
This is why the bump pairs with lever 1, not standalone.
|
|
94
|
+
|
|
95
|
+
What `main` does NOT have (corrects the prior note):
|
|
96
|
+
[ml-explore/mlx#3553](https://github.com/ml-explore/mlx/issues/3553) is an
|
|
97
|
+
OPEN issue (the problem report), NOT a merged fix, and `qmv_wide` is not
|
|
98
|
+
wired into the gather path. There is NO `gather_qmm` M=1 qmv-class fast
|
|
99
|
+
path upstream — the 26B M=1 compute-bound gap (~4 ms/step) is ours to close
|
|
100
|
+
(the shelved moe-qmv-kernel; roofline #2). Probable no-op:
|
|
101
|
+
[ml-explore/mlx#3120](https://github.com/ml-explore/mlx/pull/3120) (split-K
|
|
102
|
+
small-M quant matmul) was in mlx HEAD 2026-03-21, before the 0.31.2 tag —
|
|
103
|
+
likely already ours; confirm before counting it.
|
|
104
|
+
|
|
105
|
+
Sequence: land this WITH lever 1 (speculation), where #3485 + #3764 both
|
|
106
|
+
pay off — not as a standalone "faster decode" move it isn't.
|
|
107
|
+
|
|
108
|
+
### 3. Quantization quality-per-bit — fewer bytes IS more tok/s [expected ~10–15%]
|
|
109
|
+
|
|
110
|
+
Decode scales ~linearly with weight bytes. oQ-style sensitivity-driven
|
|
111
|
+
quant in `convert` (adoption map #4, eval-gated) and TurboQuant (Phase 13)
|
|
112
|
+
are decode-speed programs wearing quality clothes: 4.0 → ~3.5 effective
|
|
113
|
+
bpw at equal KL ≈ +10–15% decode with zero kernel work. Gate: perplexity
|
|
114
|
+
+ 6-task eval vs the existing knapsack at equal bpw.
|
|
115
|
+
|
|
116
|
+
### 4. Host-side residuals [expected 2–8% on affected models]
|
|
117
|
+
|
|
118
|
+
- **CPM5 unfused swiglu — LANDED (+5.5% decode, 2026-07-04).** `compiledSwiglu`
|
|
119
|
+
(minicpm5.ts) `mx.compile`s `silu(gate)*up` → one kernel at decode (M=1),
|
|
120
|
+
cutting 48 dispatches/token. Proof the ~5% residual was dispatch tax, not GPU
|
|
121
|
+
time. The exact-copy `FaithfulMiniCPM5` fuses it for ALL shapes like mlx-lm's
|
|
122
|
+
non-M-gated `@mx.compile` (autograd-safe, Vjp maxDiff==0), which makes its
|
|
123
|
+
per-token kernel SET byte-identical to mlx-lm's (24==24, verified via parseable
|
|
124
|
+
**xctrace shader-list diff**); the M=1 gate leaves prefill unfused (extra
|
|
125
|
+
`vn_Sigmoid`+`vvn_Multiply`, ~0.7% there). Whether to widen production's gate
|
|
126
|
+
was deferred until the FaithfulMiniCPM5 A/B landed a verdict (it did — see the
|
|
127
|
+
retired note below). The same
|
|
128
|
+
standalone `sigmoid/silu + mul` pattern likely costs ~5% on other models' MLPs
|
|
129
|
+
(gemma/qwen) — audit and give each an `mx.compile` helper.
|
|
130
|
+
- **e4b ~5% per-step host overhead** (Phase 7 residual; dispatch count) —
|
|
131
|
+
now a prime suspect for the SAME unfused-elementwise cause; try the
|
|
132
|
+
compiledSwiglu treatment on its MLP.
|
|
133
|
+
- **FaithfulMiniCPM5 exact-copy backend — BUILT (2026-07-04; retired
|
|
134
|
+
2026-07-05 — the default IS the faithful path; file deleted along with
|
|
135
|
+
`MLX_BUN_CPM5_FAITHFUL`, unified-engine-frontier-plan.md §6).** Was
|
|
136
|
+
`src/model/minicpm5-faithful.ts`: an op-for-op copy of mlx-lm's llama.py +
|
|
137
|
+
activations.py, swappable against our optimized `MiniCPM5Model` through the
|
|
138
|
+
same generate()/eval path. Bit-exact to the golden, dispatched-kernel set
|
|
139
|
+
verified identical to mlx-lm's. The A/B reference — prove identical, THEN
|
|
140
|
+
compare performance, THEN optimize. Debranching alone buys ~0% (host JS
|
|
141
|
+
conditionals hidden by the GPU-bound pipeline); its analysis produced the
|
|
142
|
+
matmul-fusion non-lever below.
|
|
143
|
+
- **P4 device-side step chaining** — depth-k chained step graphs, one
|
|
144
|
+
host sync per k tokens (batching-perf-path P4; the oMLX burst-decode
|
|
145
|
+
REFUTATION does not apply — this attacks OUR FFI/readback cost, a
|
|
146
|
+
different mechanism).
|
|
147
|
+
- ~~**Perf-kernel default flip**~~ — OBSOLETE: the perf kernel was DELETED
|
|
148
|
+
2026-07-05 (regressed e4b 0.62–0.93× in the paired A/B; only win 12B@16k
|
|
149
|
+
+6% with a KL WARN — unified-engine-frontier-plan.md §6).
|
|
150
|
+
|
|
151
|
+
### Non-levers (measured, don't re-litigate without new evidence)
|
|
152
|
+
|
|
153
|
+
Megakernels at M=1 (bandwidth floor: ceiling ~1.78× CPM5, achieved 0.94×
|
|
154
|
+
— multi-token amortization is required, which is levers 1/batching);
|
|
155
|
+
oMLX-style burst decode (refuted for Bun); fused-decode activeN (refuted
|
|
156
|
+
end-to-end on 12B, reverted); host graph-build overlap (already hidden by
|
|
157
|
+
the pipelined loop — spin-injection proof in decode-roofline-lookagain);
|
|
158
|
+
**QKV / gate-up matmul fusion at M=1** (CPM5 2026-07-04: q/k/v blocked by
|
|
159
|
+
OptiQ mixed precision — v_proj 8-bit vs q/k 4-bit; gate/up fusible in 18/24
|
|
160
|
+
layers but the speed-ceiling version is ~2% SLOWER — matmul dispatches are
|
|
161
|
+
bandwidth-hidden, and a concatenated `[2I]` qmv is less efficient at M=1
|
|
162
|
+
than two `[I]`. Contrast the swiglu win: that fuses ELEMENTWISE ops, which
|
|
163
|
+
are dispatch-bound. Don't re-litigate matmul fusion for single-stream).
|
|
164
|
+
|
|
165
|
+
## Sequence
|
|
166
|
+
|
|
167
|
+
**1a AssistantSource → 2 mlx bump + re-bench → 3 oQ spike → 1b cheaper
|
|
168
|
+
head → 1c DSpark** (as its training milestones land, Josh-gated runs),
|
|
169
|
+
with §4 host residuals as filler between blocks. Re-run
|
|
170
|
+
`scripts/bench-modes.ts` (e4b + 12B, short/2k/4k) after each lever lands —
|
|
171
|
+
it is this program's scoreboard; promote clean-machine rows to
|
|
172
|
+
benchmarks/RESULTS.md.
|
|
@@ -12,7 +12,7 @@ and need a test run, so deferred to their own pass). Authored 2026-06-14.
|
|
|
12
12
|
- P1 #5 — **DONE**: `STATUS.md` exists at root.
|
|
13
13
|
- P1 #6 — **DONE**: `docs/planning/` exists with `IDEAS.md`, `PRODUCT_ROADMAP.md`, `ResearchTopics.md`, `journal.md`.
|
|
14
14
|
- P1 #7 — open (optimization_plan.md still lives in docs/design/ as a standalone).
|
|
15
|
-
- P1 #8 — **RESOLVED (2026-07-01)**: the duplicate `archive/pi-builtin-investigation.html` is already gone; `archive/` deliberately keeps 2 small demo artifacts (`mlx-bun-lab-report.html`, `wwdc-mlx-bun.html`, 76K total), tracked.
|
|
15
|
+
- P1 #8 — **RESOLVED (2026-07-01)**: the duplicate `archive/pi-builtin-investigation.html` is already gone; `docs/archive/` deliberately keeps 2 small demo artifacts (`mlx-bun-lab-report.html`, `wwdc-mlx-bun.html`, 76K total), tracked.
|
|
16
16
|
- P2 #9 — **NOT DONE**: `harness-pi.ts`, `pi-provider.ts`, `pi-terminal.ts`, `pi-web.ts` still live flat in `src/` root (no `src/pi/` subdirectory).
|
|
17
17
|
- P2 #10 — **PARTIALLY DONE**: ~57 one-off research/debug scripts moved to `scripts/experiments/`; production + tooling + bench-* + regen-* + parity-* + gen-model + eval/serve remain at `scripts/` root (the full bench/regen/build split was not applied).
|
|
18
18
|
- P2 #11 — **DONE**: CLI vocabulary reconciled.
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# DSpark serving program — flip spec wall-clock positive + design the product surface
|
|
2
|
+
|
|
3
|
+
Status: **PLANNED** (2026-07-07). Trigger for Josh's pickup: TurboQuant merge —
|
|
4
|
+
but only Phase 5 actually depends on it; Phases 0–4 are start-anytime.
|
|
5
|
+
Owner: decode / spec. Predecessors: PR #19 (DSpark paper code-complete +
|
|
6
|
+
serve-integrated + DeepSpec oracle), the first-live-run findings in
|
|
7
|
+
[dspark-handoff.md](../investigations/dspark-handoff.md) "FIRST LIVE RUN".
|
|
8
|
+
|
|
9
|
+
## The problem, in numbers (2026-07-07 first live run, loaded machine)
|
|
10
|
+
|
|
11
|
+
`gemma-4-12B-it-OptiQ-4bit` + `deepseek-ai/dspark_gemma4_12b_block7` (γ=7):
|
|
12
|
+
|
|
13
|
+
- **τ ≈ 2.8** committed tokens per target forward (2.7× fewer target calls) —
|
|
14
|
+
the algorithm WORKS, at 26–33% per-token acceptance (the predicted
|
|
15
|
+
OptiQ-4bit-target degradation vs their bf16 training).
|
|
16
|
+
- **Wall-clock LOST ~3.4×** (spec 14.6 vs serial 49.8 agg tok/s). The tax is
|
|
17
|
+
the drafter itself: 6.9 GB bf16 → ~3 GB of weight reads per draft round
|
|
18
|
+
(2 GB untied lm_head + 7 × 134 MB markov_w2 + layers), ~14 host syncs per
|
|
19
|
+
round in the transcription-faithful `draftBlock`, tapped verifies falling
|
|
20
|
+
back to the unoptimized monolith, and ~14 GB of two-model weights
|
|
21
|
+
squeezing the 24 GB box.
|
|
22
|
+
- The 20 s bench TTFT was conc-4 queueing on the serial-forced spec lane
|
|
23
|
+
(documented routing), not prefill — but per-request slowdown is real.
|
|
24
|
+
|
|
25
|
+
**Goal:** spec ≥ 1.3× serial decode on 12B at the best config, clean-machine
|
|
26
|
+
paired A/B — then (and only then) design when it's on by default. Every phase
|
|
27
|
+
has its own gate; the drafter-quantization thesis
|
|
28
|
+
([[drafter-quantization-thesis]]) makes the risky-looking phase (aggressive
|
|
29
|
+
quant) the SAFEST: drafter numerics only move acceptance, never correctness,
|
|
30
|
+
so the entire quality gate is one acceptance A/B.
|
|
31
|
+
|
|
32
|
+
**THE OBJECTIVE, stated right (Josh, 2026-07-07): 26–33% acceptance with the
|
|
33
|
+
bf16 drafter is the WORKABLE BASELINE — τ≈2.8 already pays. The question
|
|
34
|
+
quantization must answer is PRESERVATION: do we still get that number at
|
|
35
|
+
4-bit?** The point of quantizing (and of mixed precision specifically) is
|
|
36
|
+
never compression for its own sake — it's cutting the drafter's cost 4×
|
|
37
|
+
WITHOUT making it terrible at predicting tokens.
|
|
38
|
+
|
|
39
|
+
**Sensitivity is MEASURED, never guessed — and THE TOOL ALREADY EXISTS
|
|
40
|
+
(Josh): optiq's sensitivity method** (mlx-optiq.com/docs/sensitivity —
|
|
41
|
+
per-group simulate-quant → KL vs reference on a curated calibration mix →
|
|
42
|
+
greedy knapsack allocation to target BPW, emitted as a quant predicate).
|
|
43
|
+
Phase 1e adopts it for the drafter rather than inventing anything; the
|
|
44
|
+
drafter's target-hiddens-in forward even makes it cheaper (cached hiddens →
|
|
45
|
+
no 12B in the sweep loop). Allocation comes from the measured table;
|
|
46
|
+
hypotheses (lm_head argmax-proximal, chain compounding, buffered layers)
|
|
47
|
+
are recorded for falsification only. Phase 1.5 (fine-tune) is an OPTIONAL
|
|
48
|
+
UPSIDE lever on top of the workable baseline, not a premise that acceptance
|
|
49
|
+
is broken.
|
|
50
|
+
|
|
51
|
+
**And TurboQuant's role, stated right (Josh): TQ is the better-quant-at-
|
|
52
|
+
EQUAL-bits instrument — the preservation tool, not a compression ladder.**
|
|
53
|
+
Mechanism: distribute the weight vectors Gaussian, then place the
|
|
54
|
+
quantization levels non-uniformly with FINER step sizes around the peak
|
|
55
|
+
where the mass lives — affine 4-bit spends half its levels on tails TQ
|
|
56
|
+
barely pays for. Expected: TQ-4bit preserves acceptance better than
|
|
57
|
+
affine-4bit at the same size; the Phase-5 headline comparison is TQ-4 vs
|
|
58
|
+
affine-4 AT EQUAL BPW, with lower-bpw rungs only after that's won.
|
|
59
|
+
|
|
60
|
+
## Phase 0 — baseline + attribution (no code; Josh's shell for GPU runs)
|
|
61
|
+
|
|
62
|
+
The scoreboard everything else is measured against. All directional runs
|
|
63
|
+
fine on a loaded box; the FINAL pre/post pair must be clean-machine.
|
|
64
|
+
|
|
65
|
+
- [ ] **0a. Oracle gate the bf16 port ONCE** (before any optimization, so
|
|
66
|
+
later acceptance deltas are attributable to quant/tuning, not port bugs):
|
|
67
|
+
torch venv + DeepSpec install (header of
|
|
68
|
+
`scripts/oracle-dspark-deepspec.py` documents setup), dump the temp-0
|
|
69
|
+
trace (threshold 0 and 0.5 arms), run
|
|
70
|
+
`scripts/dspark-deepspec-compare.ts` — target vs their reference on the
|
|
71
|
+
**bf16 HF 12B** (`--target` the bf16 snapshot; the OptiQ-4bit arm is
|
|
72
|
+
`--acceptance-only`, a measurement not a bit gate). Fixture per
|
|
73
|
+
goldens/README.md conventions. Exit: round-for-round PASS, or a filed
|
|
74
|
+
divergence with the first-divergent round attached.
|
|
75
|
+
- [ ] **0b. γ sweep, conc 1** (no code): serve with `--num-draft-tokens`
|
|
76
|
+
∈ {2, 3, 5, 7} × `bench-feature-matrix.ts --concurrency 1 --cells
|
|
77
|
+
serial,spec`. Record per-request tok/s + acceptance + TTFT per γ. Exit: a
|
|
78
|
+
table; the best-γ config is the Phase 1 comparison base.
|
|
79
|
+
- [ ] **0c. Time attribution**: xctrace (or coarse: MLX_BUN_LANE_DEBUG +
|
|
80
|
+
timers around `source.draft` / verify forward / commit in a scratch
|
|
81
|
+
branch) on ~20 rounds. Split: draft-block GPU, draft host syncs, verify
|
|
82
|
+
forward, tap/commit overhead. Plus the paging check: RSS + `vm_stat`
|
|
83
|
+
pageouts during a run (is the 14 GB pairing thrashing?). Exit: a
|
|
84
|
+
percentage breakdown — it ORDERS phases 1–3 by measured value, replacing
|
|
85
|
+
the estimates below.
|
|
86
|
+
|
|
87
|
+
## Phase 1 — quantize the drafter (uniform 4-bit baseline; NOT TurboQuant yet)
|
|
88
|
+
|
|
89
|
+
The expected big lever: 6.9 GB → ~1.8 GB kills bandwidth AND memory pressure.
|
|
90
|
+
mlx-native group quantization, no research dependency.
|
|
91
|
+
|
|
92
|
+
- [x] **1a. `scripts/dspark-quantize-drafter.ts`** *(DONE 2026-07-07 — thin
|
|
93
|
+
driver over the house quantizer: `src/spec/dspark/quantize-drafter.ts`
|
|
94
|
+
adds a `quantizePredicate` overlay (confidence_head kept bf16, recorded
|
|
95
|
+
as the mlx `false` convention); load smoke = DeepspecDrafter reload +
|
|
96
|
+
one quantized fc forward)* — reads a DeepSpec-format
|
|
97
|
+
checkpoint dir, writes a quantized sibling (same config.json + arch stamp,
|
|
98
|
+
plus the house `quantization: {bits, group_size}` block). Per-tensor
|
|
99
|
+
policy:
|
|
100
|
+
- QUANTIZE (group-64, 4-bit default, flag-tunable): every 2-D matmul
|
|
101
|
+
weight — `layers.*.self_attn.{q,k,o}_proj`, `layers.*.mlp.{gate,up,
|
|
102
|
+
down}_proj`, `fc`, `lm_head`, `markov_head.markov_w2`, and
|
|
103
|
+
`embed_tokens` + `markov_head.markov_w1` as quantized-gather lookups
|
|
104
|
+
(mlx QuantizedEmbedding semantics — mlx-lm quantizes embeddings; ours
|
|
105
|
+
must match its gather-dequant numerics).
|
|
106
|
+
- KEEP bf16: all norms, `layers.*.layer_scalar`, `confidence_head.proj.*`
|
|
107
|
+
(tiny), biases.
|
|
108
|
+
- Output verified loadable before exit (load smoke).
|
|
109
|
+
- [x] **1b. Quantized forward in `src/spec/dspark/deepspec-module.ts`**
|
|
110
|
+
*(DONE 2026-07-07 — MatW/TableW weight representation: `.scales` sibling
|
|
111
|
+
detection, quantized_matmul transpose=true for every Linear, mlx
|
|
112
|
+
QuantizedEmbedding gather-dequant for embed_tokens/markov_w1; bf16 path
|
|
113
|
+
keeps the lazy transpose views untouched; synthetic quantized-checkpoint
|
|
114
|
+
describe block added — 8-bit tracks bf16 token-for-token)*:
|
|
115
|
+
detect quantization at load (scales/biases sibling keys — the house
|
|
116
|
+
detection pattern), route matmuls through `quantized_matmul` and lookups
|
|
117
|
+
through the quantized-gather path; bf16 path untouched (both formats load
|
|
118
|
+
through the same class — kind detection unchanged). Synthetic-format test
|
|
119
|
+
extended with a tiny quantized checkpoint (same file, new describe block).
|
|
120
|
+
- [x] **1c. The acceptance A/B harness** *(DONE 2026-07-07 — runner drives
|
|
121
|
+
`specServeRun` per arm (target loaded once, drafters sequential); spec
|
|
122
|
+
telemetry extended with per-position draftedByPos/acceptedByPos; the
|
|
123
|
+
stats/verdict math is model-free in `src/spec/dspark/ab-stats.ts`,
|
|
124
|
+
unit-tested in tests/dspark-ab-stats.test.ts; chat-template rendering
|
|
125
|
+
pins enable_thinking OFF)* — `scripts/dspark-drafter-ab.ts`:
|
|
126
|
+
same target, same prompt set (≥32 prompts, temp 0), drafter A vs drafter
|
|
127
|
+
B; reports per-position acceptance, τ, tok/s, and a paired verdict. This
|
|
128
|
+
is THE gate for every quantization experiment from here on (Phase 5
|
|
129
|
+
reuses it unchanged). Model-free logic unit-tested; the run itself is
|
|
130
|
+
GPU/Josh.
|
|
131
|
+
- [ ] **1d. Run it**: 4-bit vs bf16 drafter at best-γ from 0b. Exit criteria:
|
|
132
|
+
acceptance drop ≤ 3 points absolute AND wall-clock strictly improves;
|
|
133
|
+
record both. If 4-bit alone flips spec past serial — say so loudly in the
|
|
134
|
+
handoff, that's the headline.
|
|
135
|
+
- [ ] **1e. The MEASURED sensitivity map — ADOPT OPTIQ'S METHOD, don't
|
|
136
|
+
invent** (mlx-optiq.com/docs/sensitivity; source readable in the oracle
|
|
137
|
+
venv's `site-packages/optiq`). Their loop, verbatim: reference logits on
|
|
138
|
+
calibration data → simulate-quantize ONE group (quantize→dequantize
|
|
139
|
+
round-trip) → KL divergence on the full output distribution → restore →
|
|
140
|
+
next (group, bits); then their greedy knapsack (max KL-reduction per
|
|
141
|
+
extra bit) allocates to a target BPW. **Applied to the drafter it gets
|
|
142
|
+
CHEAPER than optiq's own runs**: the drafter isn't mlx_lm-loadable
|
|
143
|
+
(its forward needs target hiddens), so `optiq convert` can't run on it
|
|
144
|
+
directly — but that same fact removes the 12B from the loop entirely.
|
|
145
|
+
Cache tapped hiddens ONCE over an optiq-style 6-domain calibration mix
|
|
146
|
+
(our PATH-B shard format stores exactly this), then the whole sweep is
|
|
147
|
+
drafter-forward-only KL: 3B × ~10 groups × candidate bits = minutes.
|
|
148
|
+
The knapsack's output config gets ONE end-to-end acceptance A/B (1c
|
|
149
|
+
harness) as confirmation — KL is the search signal, acceptance is the
|
|
150
|
+
ship gate. Their protected-tensor defaults (lm_head/embed highest bits,
|
|
151
|
+
first/last blocks) are noted as the static prior their own exact method
|
|
152
|
+
exists to replace — we run the exact method; the drafter is small.
|
|
153
|
+
|
|
154
|
+
## Phase 1.5 — acceptance upside (OPTIONAL; the baseline is already workable)
|
|
155
|
+
|
|
156
|
+
26–33% (τ≈2.8) with the bf16 drafter pays as-is — this phase is the
|
|
157
|
+
opportunistic numerator work on top, NOT a precondition: the gap vs their
|
|
158
|
+
bf16-target numbers is distribution shift with a known mechanism, and every
|
|
159
|
+
point recovered multiplies the cost work. Run it if Phase 1's preserved
|
|
160
|
+
acceptance + cost win lands short of the ≥1.3× goal, or whenever the upside
|
|
161
|
+
is worth the run.
|
|
162
|
+
|
|
163
|
+
- [ ] **1.5a. Adaptation fine-tune on OUR target's hiddens** — their
|
|
164
|
+
checkpoint as init (the expensive pretraining is done; this is short
|
|
165
|
+
distribution adaptation, not their 10-epoch/38 TB run). The data comes
|
|
166
|
+
from OUR stack by construction: tap `[5,17,29,41,46]` hidden dumps from
|
|
167
|
+
the OptiQ-4bit 12B over on-distribution generations (the PATH-B regen
|
|
168
|
+
tooling extracts exactly this). OPEN DESIGN (resolve first): where the
|
|
169
|
+
gradient runs — (a) export our tapped-hidden shards into DeepSpec's
|
|
170
|
+
torch trainer format and fine-tune with THEIR code (MIT; least new code,
|
|
171
|
+
needs a torch box/venv and a shard-format bridge), vs (b) a training
|
|
172
|
+
path for the deepspec module in our stack (autograd through the port —
|
|
173
|
+
more work, fully local). Gate: acceptance A/B (1c harness) pre/post
|
|
174
|
+
fine-tune on held-out prompts; expected: a large chunk of the
|
|
175
|
+
bf16-vs-OptiQ gap closes.
|
|
176
|
+
- [ ] **1.5b. Confidence-threshold activation** — at 26% acceptance the
|
|
177
|
+
scheduler is finally in its design regime: sweep the raw threshold
|
|
178
|
+
(their knob) and/or our calibrated thresholds; objective =
|
|
179
|
+
tokens-per-second, not τ (pruning doomed positions trades a little τ
|
|
180
|
+
for less wasted draft+verify work). Free: no code, the machinery
|
|
181
|
+
shipped in PR #19.
|
|
182
|
+
- [ ] **1.5c. Quantify the target-fidelity axis** (measurement, not a
|
|
183
|
+
build): acceptance vs target quant — e.g. the same drafter against a
|
|
184
|
+
higher-fidelity 12B variant if one fits (mixed/8-bit tap-layer
|
|
185
|
+
experiments), to split "drafter needs adapting" from "target hiddens
|
|
186
|
+
are too degraded". Informs whether 1.5a alone suffices.
|
|
187
|
+
|
|
188
|
+
## Phase 2 — tighten `draftBlock` (replay the proven tightening)
|
|
189
|
+
|
|
190
|
+
`Gemma4DSparkModel.draftBlock` kept the reference's per-position structure
|
|
191
|
+
(transcription fidelity): 7 argmax `itemUint32` syncs + 7 confidence
|
|
192
|
+
`toFloat32` syncs per round. We already solved this exact shape once
|
|
193
|
+
(module-dflash.ts, 2026-07-06 — bit-identity-pinned).
|
|
194
|
+
|
|
195
|
+
- [ ] **2a. On-device token chaining**: the sequential Markov loop keeps the
|
|
196
|
+
argmax result as a device `[1]` index feeding the next position's
|
|
197
|
+
`takeAxis(markov_w1, ·)`; ONE concat + ONE host read after the loop.
|
|
198
|
+
(Post-1b the bias matmul is quantized too.)
|
|
199
|
+
- [ ] **2b. Confidence: compute NOTHING at threshold ≤ 0** (their default —
|
|
200
|
+
today we compute + sync 7 confidences that are then unused); when a
|
|
201
|
+
threshold IS set, per-position reads are inherent to the truncation
|
|
202
|
+
decision (same reasoning as the dflash loop — document it).
|
|
203
|
+
- [ ] **2c. `collectLogits`-style skip** for `baseLogits` if the serve path
|
|
204
|
+
still materializes anything it discards (audit `DeepspecSource.draft` —
|
|
205
|
+
it disposes `block.baseLogits` unread; make the module skip building it,
|
|
206
|
+
mirroring `DflashDraftOpts.collectLogits`).
|
|
207
|
+
- [ ] **Gate**: bit-identity — pinned tokens on the deterministic synthetic
|
|
208
|
+
checkpoint pre/post rewrite (the tests/dspark-infer-loop.test.ts
|
|
209
|
+
pattern), plus real-checkpoint determinism (same prompt twice → same
|
|
210
|
+
drafts). Tightening is a pure optimization; any token change is a bug.
|
|
211
|
+
|
|
212
|
+
## Phase 3 — `captureLayer` in the generated gemma forwards
|
|
213
|
+
|
|
214
|
+
Tapped spec forwards (prefill + EVERY verify round) currently fall back to
|
|
215
|
+
the monolith (the 2026-07-07 guard fix — correct-but-unspecialized). The
|
|
216
|
+
verify forward is the spec path's biggest single GPU cost; give it back the
|
|
217
|
+
generated fast path. Independent of Phases 1–2; parallelizable.
|
|
218
|
+
|
|
219
|
+
- [ ] **3a. `scripts/gen-model.ts`**: emit the tap exactly as the monolith
|
|
220
|
+
does — `captureLayer(i, h)` after each layer's residual
|
|
221
|
+
(gemma4.ts:970 semantics) + the post-finalNorm sentinel
|
|
222
|
+
(index = nLayers, gemma4.ts:989) — and REMOVE `this.hiddenTap !== null`
|
|
223
|
+
from the emitted fallback guard.
|
|
224
|
+
- [ ] **3b. Regenerate all three** (12b / 26b / e4b; regen commands in each
|
|
225
|
+
file's header) — the hand-patched guards are superseded by generator
|
|
226
|
+
output.
|
|
227
|
+
- [ ] **Gate**: (i) generated-parity suite green (untapped behavior
|
|
228
|
+
untouched); (ii) NEW tap-parity check — tapped rows bit-equal
|
|
229
|
+
monolith-vs-generated on the same input (model-gated test, e4b);
|
|
230
|
+
(iii) spec bench pre/post for the verify-round win.
|
|
231
|
+
|
|
232
|
+
## Phase 4 — serving UX: flags, defaults, composition (the product pass)
|
|
233
|
+
|
|
234
|
+
Decisions, made on Phase 0–3 DATA, then implemented. The doctrine rails:
|
|
235
|
+
drop-in-replacement (a lone request must never get slower because a flag
|
|
236
|
+
exists), dont-delete-optionality (losing configs stay documented
|
|
237
|
+
default-off), spec = opt-in until it WINS a clean-machine paired A/B.
|
|
238
|
+
|
|
239
|
+
- [ ] **4a. γ default per drafter kind**: the checkpoint's trained γ is the
|
|
240
|
+
cap, not necessarily the default — if 0b says γ=3 beats γ=7 at our
|
|
241
|
+
acceptance, `numDraftTokens` defaults to the measured-best (per-kind
|
|
242
|
+
table in code, overridable), and the handoff documents why.
|
|
243
|
+
- [ ] **4b. Quantized-drafter UX**: `mlx-bun get` the bf16 →
|
|
244
|
+
`scripts/dspark-quantize-drafter.ts` is a manual step today; decide
|
|
245
|
+
whether `serve --draft-model <bf16-dir>` should offer/auto-run the
|
|
246
|
+
4-bit conversion (like the starter-model flow) or just print the
|
|
247
|
+
command. Also: registry listing shows drafters distinctly (they are not
|
|
248
|
+
servable models — `/v1/models` must NOT list them; verify).
|
|
249
|
+
- [ ] **4c. Spec × prompt-cache composition** (parity-plan §7.6 — currently
|
|
250
|
+
BYPASSED on the spec path, v1 note in serve-loop.ts): multi-turn agents
|
|
251
|
+
re-prefill every turn when a draft is mounted. Scope it here or
|
|
252
|
+
explicitly re-defer with the measured cost (12B multi-turn TTFT with
|
|
253
|
+
spec on). At minimum: the boundary-snapshot machinery must not regress
|
|
254
|
+
when spec is mounted.
|
|
255
|
+
- [ ] **4d. Surface audit**: `--draft-kind` (keep), `--num-draft-tokens`
|
|
256
|
+
semantics doc, `/stats` shows mounted drafter + kind + γ, `usage.
|
|
257
|
+
speculation` already ships. server-config.md gets a "speculative
|
|
258
|
+
serving" section consolidating the four kinds + the when-does-it-pay
|
|
259
|
+
table (from Phase 0/1 data). features-matrix + cli.md + README rows.
|
|
260
|
+
- [ ] **4e. The default decision, written down**: for each (model, drafter)
|
|
261
|
+
pair measured, spec default on/off per the clean-machine A/B — recorded
|
|
262
|
+
in RESULTS.md "composition" + the features matrix. (Prediction to test:
|
|
263
|
+
ON for 12B+quantized drafter, OFF for e4b anything.)
|
|
264
|
+
|
|
265
|
+
## Phase 5 — TurboQuant application (the trigger event)
|
|
266
|
+
|
|
267
|
+
Trigger, precisely: **TQ WEIGHT quantization** in the convert tooling — PR
|
|
268
|
+
#20 (2026-07-07) landed TurboQuant for KV; the rotation-based weight-side
|
|
269
|
+
is the noted follow-up (turboquant-kv.md), and it's what the drafter
|
|
270
|
+
needs. The drafter is its lowest-risk first customer — one-number gate,
|
|
271
|
+
no KL/eval battery. **TQ's HYPOTHESIS here is PRESERVATION AT EQUAL BITS**
|
|
272
|
+
(Gaussian-distributed vectors + finer step sizes around the peak, where
|
|
273
|
+
affine spends half its levels on tails) — a hypothesis 5b MEASURES, never
|
|
274
|
+
a default: TurboQuant earns its place the same way everything in this
|
|
275
|
+
repo does.
|
|
276
|
+
|
|
277
|
+
- [ ] **5a.** Extend `dspark-quantize-drafter.ts` with the TurboQuant
|
|
278
|
+
scheme.
|
|
279
|
+
- [ ] **5b. THE HEADLINE: TQ-4bit vs affine-4bit AT EQUAL BPW** through the
|
|
280
|
+
Phase-1c harness — same size, whose acceptance is closer to bf16? If
|
|
281
|
+
affine-4 bled in 1d, this is the expected fix; if affine-4 held, TQ's
|
|
282
|
+
margin becomes headroom for lower rungs. Only AFTER TQ-4 ≥ affine-4:
|
|
283
|
+
the lower-bpw ladder (3.5 / 3.0 / 2.5) → acceptance-per-byte curve,
|
|
284
|
+
knee adopted (dont-delete-optionality for the rest).
|
|
285
|
+
- [ ] **5b″. TQ IS HOW, SENSITIVITY-AWARE IS WHAT (Josh)** — two orthogonal
|
|
286
|
+
axes, never mixed: TQ vs affine is a METHOD question (decided by 5b's
|
|
287
|
+
equal-bpw measurement — a method that wins at equal bits wins for every
|
|
288
|
+
tensor, so there is no reason to mix METHODS within an artifact);
|
|
289
|
+
sensitivity is the bit ALLOCATION question (the 1e knapsack, whatever
|
|
290
|
+
the method — candidate set {method-2, method-3, method-4, method-8} per
|
|
291
|
+
group, measured KL cost each, greedy to target BPW). IF 5b confirms TQ,
|
|
292
|
+
the artifact is TQ-uniform at knapsack-allocated bits; if it doesn't,
|
|
293
|
+
affine-uniform at knapsack-allocated bits — either way the OUTCOME of
|
|
294
|
+
the measurement, not a premise. Nothing here is "on by default";
|
|
295
|
+
defaults are Phase 4e/6 decisions made on clean-machine numbers.
|
|
296
|
+
- [ ] **5b′. PER-TENSOR MIXED PRECISION rungs** (Josh, 2026-07-07). The
|
|
297
|
+
intuition "only 5 layers = few knobs" undercounts: the drafter's mass is
|
|
298
|
+
~10 TENSOR GROUPS, and two of them are 58% of the bytes — `lm_head`
|
|
299
|
+
(~2 GB, read FULLY every round: the bandwidth whale) and `embed_tokens`
|
|
300
|
+
(~2 GB, gather-only: ~free to read, pure resident-memory win), plus
|
|
301
|
+
`markov_w2` (134 MB read ×7/round ≈ 940 MB). Both whales only shape the
|
|
302
|
+
DRAFT distribution → acceptance-only risk. Mixed rungs to sweep: 3-bit
|
|
303
|
+
lm_head + 3-bit markov_w2 + 4-bit layers; 2-bit embed variants; k_proj
|
|
304
|
+
(2 M params) 8-bit for free. The ~10-group space is small enough for a
|
|
305
|
+
near-exhaustive sweep through the SAME one-number harness — unlike
|
|
306
|
+
sensitivity search on a full model. **Allocation objective (the point):
|
|
307
|
+
PRESERVE the bf16 acceptance at the smallest cost, not minimize bytes —
|
|
308
|
+
and allocation follows the MEASURED sensitivity table from 1e, never a
|
|
309
|
+
prior.** The mixed rungs are built FROM the table: give the measured-
|
|
310
|
+
sensitive groups more bits (or TQ them, post-Phase-5), squeeze the
|
|
311
|
+
measured-insensitive ones. The "only 5 layers" worry dissolves either
|
|
312
|
+
way — the tensor-group space (~10 knobs, two of them 58% of the bytes)
|
|
313
|
+
is the real granularity, and 1e prices every knob empirically.
|
|
314
|
+
- [ ] **5c.** If TurboQuant wins: fold the recipe into 4b's UX (the
|
|
315
|
+
conversion the server offers is the TurboQuant one).
|
|
316
|
+
|
|
317
|
+
## Phase 6 — quotable results + promotion
|
|
318
|
+
|
|
319
|
+
- [ ] Clean-machine protocol (reboot + `sudo purge`), then: bench-feature-
|
|
320
|
+
matrix conc-1 AND agg×4, serial vs best-spec-config, on 12B (and e4b as
|
|
321
|
+
the expected-negative control). Promote to `benchmarks/RESULTS.md`
|
|
322
|
+
"composition"; update decode-speed-program.md (lever 1c: measured),
|
|
323
|
+
STATUS, and the handoff's FIRST LIVE RUN section with the closing
|
|
324
|
+
numbers.
|
|
325
|
+
- [ ] Loose ends carried from PR #19, closed or re-deferred with reasons:
|
|
326
|
+
the paper-faithful gated RNN head (seqHead:"gru", currently variant-
|
|
327
|
+
documented), paper-Alg-1/STS survival-product scheduler (Lab item),
|
|
328
|
+
per-slot spec under batching (unified-engine frontier row — NOT this
|
|
329
|
+
program).
|
|
330
|
+
|
|
331
|
+
## Dependency graph + who does what
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
0a (oracle gate, Josh: venv+GPU) ──┐
|
|
335
|
+
0b (γ sweep, Josh: GPU) ──────────┼─→ 1a→1b→1c→1d (quant baseline; 1d Josh GPU)
|
|
336
|
+
0c (attribution, Josh: GPU) ───────┘ │
|
|
337
|
+
├─→ 1.5 (OPTIONAL acceptance
|
|
338
|
+
│ upside: fine-tune on our
|
|
339
|
+
│ target's hiddens + threshold
|
|
340
|
+
│ sweep; run if 1's preserved
|
|
341
|
+
│ acceptance falls short)
|
|
342
|
+
├─→ 2a-2c (tightening; CPU-gated)
|
|
343
|
+
3a-3b (generator tap; parallel anytime) ────┤
|
|
344
|
+
└─→ 4 (UX, needs 0–3 data)
|
|
345
|
+
TurboQuant merge ─→ 5a-5c (reuses 1c harness) ─→ 6 (clean machine, Josh)
|
|
346
|
+
```
|
|
347
|
+
Priority note: Phase 1's PRESERVATION question ("do we keep 26–33% at
|
|
348
|
+
4-bit?") is the program's hinge — one A/B answers it; if affine-4 bleeds,
|
|
349
|
+
the answers are MEASURED (1e sensitivity table → mixed allocation) and
|
|
350
|
+
ENGINEERED (Phase 5: TQ-4 at equal bpw — the better quant is the designed
|
|
351
|
+
fix, not a fallback).
|
|
352
|
+
|
|
353
|
+
Code phases (1a/1b/2/3/4-impl) are agent-runnable sessions; every GPU
|
|
354
|
+
measurement is Josh's shell. Nothing except Phase 5 waits on TurboQuant —
|
|
355
|
+
Phases 0–4 can land first so TurboQuant drops into a finished harness.
|
|
356
|
+
|
|
357
|
+
## Exit criteria for the whole program
|
|
358
|
+
|
|
359
|
+
1. Spec wall-clock ≥ 1.3× serial on 12B at the recommended config,
|
|
360
|
+
clean-machine paired — or a written verdict that it can't be reached and
|
|
361
|
+
why (with the config left as a characterized default-off lever).
|
|
362
|
+
2. **Acceptance PRESERVED and understood**: the quantized drafter holds the
|
|
363
|
+
bf16 baseline's 26–33% (or the mixed rung that does is adopted, or the
|
|
364
|
+
loss is measured and accepted with numbers); the optional 1.5 upside
|
|
365
|
+
levers are run-or-explicitly-deferred — the drafter predicts tokens;
|
|
366
|
+
small was never the goal.
|
|
367
|
+
3. The acceptance-per-byte curve exists (TurboQuant vs 4-bit vs mixed vs
|
|
368
|
+
bf16), with acceptance-at-fixed-budget allocation swept (5b′).
|
|
369
|
+
4. The serving surface is documented, defaults decided per-pair and
|
|
370
|
+
recorded, and a fresh `mlx-bun get` → serve → speedup flow works without
|
|
371
|
+
reading any design doc.
|