mlx-bun 0.0.10 → 0.0.12
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 +107 -32
- package/THIRD_PARTY_LICENSES.md +10 -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/colibri-glm52-port.md +1479 -0
- 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/pre-colibri-stabilization.md +329 -0
- 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/colibri-oracle-pin.md +1284 -0
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/indexshare-performance-spike.md +357 -0
- 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/planning/release-notes-v0.0.12.md +80 -0
- package/docs/reference/cli.md +63 -18
- package/docs/reference/distribution.md +37 -6
- package/docs/reference/embedding.md +40 -16
- package/docs/reference/features-matrix.md +99 -0
- package/docs/reference/library-api.md +69 -20
- package/docs/reference/memory.md +26 -6
- package/docs/reference/models.md +60 -3
- package/docs/reference/orpo-quickstart.md +3 -4
- package/docs/reference/server-api.md +717 -24
- package/docs/reference/server-config.md +265 -129
- package/docs/reference/training.md +24 -16
- package/package.json +5 -3
- package/src/anthropic.ts +67 -44
- 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/chat-template.ts +155 -10
- package/src/cli.ts +483 -113
- package/src/config.ts +116 -24
- package/src/diffusion/diffusion-generate.ts +14 -8
- package/src/download.ts +143 -12
- package/src/eval/README.md +7 -6
- package/src/eval/ifeval.ts +63 -120
- package/src/eval/kl.ts +59 -3
- package/src/eval/quality-db.ts +2 -2
- package/src/eval/runner.ts +17 -8
- package/src/eval/tasks/ifeval.ts +167 -31
- package/src/expert-io.ts +391 -0
- package/src/expert-offload.ts +15 -2
- package/src/expert-residency.ts +1134 -0
- package/src/expert-usage.ts +415 -0
- package/src/flags.ts +13 -0
- package/src/generate.ts +438 -35
- package/src/grammar.ts +585 -0
- package/src/hf-push.ts +1 -1
- package/src/hub-rest.ts +242 -0
- package/src/index.ts +14 -2
- package/src/jobs/runner.ts +37 -18
- package/src/kv-store.ts +586 -93
- package/src/lora.ts +85 -14
- package/src/md-modules.d.ts +42 -0
- package/src/media-fetch.ts +426 -0
- package/src/memory/rest.ts +245 -0
- package/src/memory/vault.ts +74 -0
- package/src/mlx/array.ts +149 -19
- package/src/mlx/autograd.ts +53 -16
- package/src/mlx/checkpoint.ts +46 -13
- package/src/mlx/custom-vjp.ts +83 -35
- 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 +103 -6
- package/src/model/gemma4-base.ts +395 -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/glm52-atlas.ts +511 -0
- package/src/model/glm52-cache.ts +706 -0
- package/src/model/glm52-config.ts +262 -0
- package/src/model/glm52-container.ts +305 -0
- package/src/model/glm52-coupling.ts +388 -0
- package/src/model/glm52-dsa.ts +602 -0
- package/src/model/glm52-expert-layout.ts +253 -0
- package/src/model/glm52-layout.ts +152 -0
- package/src/model/glm52-memory.ts +473 -0
- package/src/model/glm52-mla.ts +786 -0
- package/src/model/glm52-moe.ts +223 -0
- package/src/model/glm52-pilot.ts +537 -0
- package/src/model/glm52-reference.ts +445 -0
- package/src/model/glm52-residency.ts +557 -0
- package/src/model/glm52-resident-weights.ts +135 -0
- package/src/model/glm52-streamed-experts.ts +453 -0
- package/src/model/glm52-streamed-metal.ts +610 -0
- package/src/model/glm52-weights.ts +503 -0
- package/src/model/glm52.ts +1153 -0
- 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 +19 -1
- package/src/model/universal/dense.ts +40 -5
- package/src/model/universal/rope.ts +36 -21
- package/src/native/expert_io.c +523 -0
- package/src/native-pack.ts +6 -4
- 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/responses.ts +62 -49
- package/src/serve/batch-scheduler.ts +1050 -78
- package/src/serve/generation-gateway.ts +252 -24
- 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 +1701 -175
- 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/glm52-mtp-source.ts +392 -0
- package/src/spec/ngram-source.ts +132 -0
- package/src/spec/serve-loop.ts +617 -0
- package/src/spec/source.ts +118 -0
- package/src/spec/two-model.ts +171 -0
- package/src/ssd-cache.ts +111 -35
- package/src/tokenizer.ts +288 -2
- package/src/tool-approvals.ts +131 -0
- package/src/tool-call.ts +438 -22
- package/src/train/flash-cce.ts +2 -2
- package/src/train/job.ts +0 -12
- package/src/train/lora-params.ts +17 -6
- package/src/train/trainer.ts +60 -30
- package/src/vision/prompt.ts +217 -48
- package/src/web/app.html +1197 -1791
- package/src/web/app.js +5694 -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 +300 -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/web-tools.ts +54 -2
- package/src/weights.ts +82 -19
- 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
|
@@ -1,11 +1,176 @@
|
|
|
1
1
|
# DSpark — handoff
|
|
2
2
|
|
|
3
|
-
**State
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
**State (2026-07-06): the DSpark paper is CODE-COMPLETE and serve-integrated.**
|
|
4
|
+
Architecture proven correct (overfit τ=3.24, paper-range); serve-integrated
|
|
5
|
+
behind `--draft-model` (Phase 1 — the `DraftSource` seam is KV-borrowing-ready;
|
|
6
|
+
sibling AssistantSource verified bit-lossless on real weights,
|
|
7
|
+
`tests/spec-serve-assistant.test.ts`); and every remaining paper component
|
|
8
|
+
landed in Phase 2 the same day: Alg-1 confidence-scheduled draft-length pruning
|
|
9
|
+
(checkpoint-driven, zero change for uncalibrated checkpoints), STS calibration
|
|
10
|
+
(§3.2.1, `calibration.ts` + `scripts/dspark-calibrate.ts`), the RNN sequential
|
|
11
|
+
head (Eq 6, `--seq-head rnn`, init-equivalent to Markov), the tightened draft
|
|
12
|
+
loop (on-device token chaining + deferred conf reads + `collectLogits:false`
|
|
13
|
+
on serve — bit-identity pinned), and the `dspark` variant rename + central
|
|
14
|
+
loader. Suites: smoke 21/21 · dspark tests 17/17 · adjacent server suites
|
|
15
|
+
green. **What remains is exactly the GPU work below** — data scale + 12B
|
|
16
|
+
retarget + train + calibrate + measure; e4b not netting a speedup is a
|
|
17
|
+
data/target-speed problem, not architecture. Full design:
|
|
7
18
|
[docs/design/dspark-speculative-decoding.md](../design/dspark-speculative-decoding.md).
|
|
8
19
|
|
|
20
|
+
## PATH A (preferred, no training) — DeepSeek's published 12B drafter
|
|
21
|
+
|
|
22
|
+
DeepSeek released a TRAINED drafter for our exact target:
|
|
23
|
+
`deepseek-ai/dspark_gemma4_12b_block7` (6.86 GB bf16, γ=7; DeepSpec repo is
|
|
24
|
+
the MIT reference impl + the oracle — see the "DeepSpec ground truth" section
|
|
25
|
+
of the design doc). Once the deepspec-variant port lands:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
# 1. download the trained drafter (~6.9 GB)
|
|
29
|
+
mlx-bun get deepseek-ai/dspark_gemma4_12b_block7
|
|
30
|
+
# 2. oracle gate: dump their reference trace (temp 0 = RNG-free deterministic)
|
|
31
|
+
# in a torch venv, then compare ours round-for-round (scripts staged)
|
|
32
|
+
# 3. measure + serve (auto-detected via config.json architectures field)
|
|
33
|
+
mlx-bun serve --model gemma-4-12B-it-OptiQ-4bit --draft-model <snapshot-of-dspark_gemma4_12b_block7>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Oracle protocol (step 2, expanded)
|
|
37
|
+
|
|
38
|
+
Two staged scripts implement the temp-0 deterministic trace protocol against
|
|
39
|
+
DeepSpec's own reference implementation (github.com/deepseek-ai/DeepSpec, MIT).
|
|
40
|
+
At temperature 0 their leaky-rejection verify degenerates to exact argmax
|
|
41
|
+
token-match — the whole round trace is RNG-free and reproducible, so a
|
|
42
|
+
plain round-for-round diff is a real bit-exact gate (same discipline as the
|
|
43
|
+
D2 diffusion oracle, minus RNG parity entirely — see the design doc's
|
|
44
|
+
"DeepSpec ground truth" section).
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
# a. dump the reference trace — needs its OWN torch venv (NOT the mlx-lm
|
|
48
|
+
# oracle venv at /Users/joshrossi/Code/mlx-lm/.venv, which has no
|
|
49
|
+
# torch/deepspec and shouldn't); see the script header for the exact
|
|
50
|
+
# venv-setup + pip install steps.
|
|
51
|
+
.venv-deepspec/bin/python scripts/oracle-dspark-deepspec.py \
|
|
52
|
+
--target <snapshot-dir-of-google/gemma-4-12B-it> \
|
|
53
|
+
--drafter <snapshot-of-dspark_gemma4_12b_block7> \
|
|
54
|
+
--data prompts.jsonl --n 8 --max-new-tokens 128 \
|
|
55
|
+
--temperature 0 --confidence-threshold 0 \
|
|
56
|
+
--out goldens/dspark-deepspec/trace-thr0.jsonl
|
|
57
|
+
|
|
58
|
+
# b. compare our port round-for-round
|
|
59
|
+
bun scripts/dspark-deepspec-compare.ts \
|
|
60
|
+
--fixture goldens/dspark-deepspec/trace-thr0.jsonl \
|
|
61
|
+
--target gemma-4-12B-it-bf16 --drafter <snapshot-of-dspark_gemma4_12b_block7>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Run the pair twice — once at `--confidence-threshold 0` (no pruning), once at
|
|
65
|
+
`0.5` — to gate both the base draft loop and the confidence-truncation path.
|
|
66
|
+
|
|
67
|
+
Fixture location: `goldens/dspark-deepspec/*.jsonl` follows the house
|
|
68
|
+
manifest convention (goldens/README.md) — these are machine-independent
|
|
69
|
+
**JSON manifests** (prompts + token-id traces, no tensor blobs), so they are
|
|
70
|
+
the **tracked** kind, not the `.bin` machine-specific kind. Regenerate by
|
|
71
|
+
rerunning step (a); there is no `scripts/regen-*` wrapper for this family yet
|
|
72
|
+
since the oracle run needs its own GPU-hosting torch venv, not the mlx-lm
|
|
73
|
+
oracle venv this repo otherwise standardizes on.
|
|
74
|
+
|
|
75
|
+
**The OptiQ-4bit caveat is load-bearing, not a footnote**: the fixture above
|
|
76
|
+
is generated against the bf16 HF target. A `dspark-deepspec-compare.ts` run
|
|
77
|
+
with `--target` pointing at our bf16 12B is the TRUE bit-exact gate. A run
|
|
78
|
+
with `--target` pointing at the OptiQ-4bit-quantized 12B we actually serve is
|
|
79
|
+
a **separate acceptance-rate measurement** — tapped hiddens differ
|
|
80
|
+
numerically at 4-bit, so round-for-round divergence there is expected, not a
|
|
81
|
+
bug; pass `--acceptance-only` on that arm so the script reports an aggregate
|
|
82
|
+
accept-length reading instead of a PASS/FAIL assert.
|
|
83
|
+
|
|
84
|
+
Caveat: trained against the bf16 HF target; our serving 12B is OptiQ-4bit —
|
|
85
|
+
tapped hiddens differ numerically, so measure acceptance rather than assuming
|
|
86
|
+
their 60–85%.
|
|
87
|
+
|
|
88
|
+
**FIRST LIVE RUN (2026-07-07, loaded machine — directional only):** τ ≈ 2.8
|
|
89
|
+
committed/target-forward (200 tok / 72 verify rounds; per-token acceptance
|
|
90
|
+
26–33% — the predicted OptiQ-4bit degradation), output coherent, losslessness
|
|
91
|
+
holding. **But wall-clock LOST ~3.4×** (spec 14.6 vs serial 49.8 agg tok/s;
|
|
92
|
+
the 20 s bench TTFT is conc-4 queueing on the serial-forced spec lane, not
|
|
93
|
+
prefill). The tax is the drafter itself. **The full step-by-step program for
|
|
94
|
+
the next pass is
|
|
95
|
+
[docs/design/dspark-serving-program.md](../design/dspark-serving-program.md)**
|
|
96
|
+
(phases, gates, dependency graph; pickup at TurboQuant merge, only its
|
|
97
|
+
Phase 5 waits for it). Lever summary:
|
|
98
|
+
1. **Quantize the drafter** — the big one, and the ideal quantization target
|
|
99
|
+
PERIOD: drafter numerics only move ACCEPTANCE, never correctness
|
|
100
|
+
(losslessness is structural), so aggressive bpw is safe and the gate is a
|
|
101
|
+
single acceptance A/B. 6.9 GB bf16 → ~1.8 GB @4-bit kills both the
|
|
102
|
+
~3 GB/round bandwidth tax (2 GB lm_head + 7×134 MB markov_w2 reads) and
|
|
103
|
+
the 14 GB two-model memory pressure on 24 GB. Uniform 4-bit (mlx-native)
|
|
104
|
+
first as the baseline; **TurboQuant (Phase 13), when it lands, competes
|
|
105
|
+
on acceptance-per-byte against that baseline** — the drafter is its
|
|
106
|
+
lowest-risk first customer. Enabler either way: quantized-weight support
|
|
107
|
+
in deepspec-module's forward (quantized_matmul, the house pattern).
|
|
108
|
+
2. **Tighten deepspec draftBlock** — ~14 host syncs/round (7 argmax + 7
|
|
109
|
+
confidence reads); replay the on-device chaining + deferred-conf
|
|
110
|
+
tightening already done for our own module (threshold=0 needs NO conf
|
|
111
|
+
reads).
|
|
112
|
+
3. **captureLayer in the GENERATED gemma forwards** — tapped verifies
|
|
113
|
+
currently fall back to the monolith (correct-but-unspecialized); teach
|
|
114
|
+
scripts/gen-model.ts to emit the tap so spec verifies keep the fast path.
|
|
115
|
+
4. **γ sweep** — γ=7 at ~30% acceptance wastes drafts;
|
|
116
|
+
`--num-draft-tokens 2..3` may net better wall-clock free of any code.
|
|
117
|
+
|
|
118
|
+
## PATH B — train our own module (custom targets / research)
|
|
119
|
+
|
|
120
|
+
The payoff target is **12B** (27B is memory-infeasible to train on 24 GB; the
|
|
121
|
+
pipeline stays dim-generic so 27B remains a future recipe). All three scripts
|
|
122
|
+
take `--model` and (new, 2026-07-06) `--tap-layers` — the retarget is now a
|
|
123
|
+
pure parameterization, no code edits. **`--tap-layers` MUST be identical across
|
|
124
|
+
regen and train** (the shard feature dim is `m*H`, `m = tapLayers.length`).
|
|
125
|
+
|
|
126
|
+
12B tap set: use **`5,17,29,41,46`** — DeepSeek's actual trained
|
|
127
|
+
`target_layer_ids` for this model (their layer-output convention matches our
|
|
128
|
+
tapLayers indexing; audited 2026-07-06). Our earlier `24,37,47,48` guess is
|
|
129
|
+
superseded.
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
# 0. one-time: cache the 12B target + a prompt/topic corpus (thousands of
|
|
133
|
+
# on-distribution topics — the data-scale lever; 160 only reached per-pos ~0.17).
|
|
134
|
+
mlx-bun get mlx-community/gemma-4-12B-it-OptiQ-4bit
|
|
135
|
+
# (12B target may need the serve process stopped to free memory for regen.)
|
|
136
|
+
|
|
137
|
+
# 1. regen multi-layer training shards from the 12B target's own generations
|
|
138
|
+
bun scripts/dspark-regen-dflash.ts \
|
|
139
|
+
--model gemma-4-12B-it-OptiQ-4bit --tap-layers 5,17,29,41,46 \
|
|
140
|
+
--topics <thousands-of-topics.txt> --out data/dspark-12b --max-resp 320
|
|
141
|
+
|
|
142
|
+
# 2. train the drafter against the 12B (warm-start survivable via --resume;
|
|
143
|
+
# GPU runs kept getting killed ~step 5000 pre-resume). Optional A/B:
|
|
144
|
+
# --seq-head rnn trains the Eq-6 RNN head instead of Markov (Eq 5).
|
|
145
|
+
bun scripts/dspark-train-dflash.ts \
|
|
146
|
+
--model gemma-4-12B-it-OptiQ-4bit --tap-layers 5,17,29,41,46 \
|
|
147
|
+
--data data/dspark-12b --out ckpt/dspark-12b \
|
|
148
|
+
--iters 8000 --batch 8 [--seq-head rnn] [--ddraft 2560] [--resume ckpt/dspark-12b]
|
|
149
|
+
|
|
150
|
+
# 3. STS-calibrate (§3.2.1): fit per-position confidence thresholds on real
|
|
151
|
+
# verify outcomes and stamp them into dspark.json — this ACTIVATES the
|
|
152
|
+
# Alg-1 confidence scheduler at decode (uncalibrated = fixed-γ, no change).
|
|
153
|
+
bun scripts/dspark-calibrate.ts \
|
|
154
|
+
--model gemma-4-12B-it-OptiQ-4bit \
|
|
155
|
+
--drafter ckpt/dspark-12b --data <prompts.jsonl> [--target 0.5]
|
|
156
|
+
|
|
157
|
+
# 4. measure live τ + tok/s vs vanilla 12B decode (clean machine — dirty
|
|
158
|
+
# numbers are garbage). Run BOTH pre- and post-calibration for the
|
|
159
|
+
# scheduler's own A/B (MLX_BUN_DSPARK_MINCONF=<c> = manual uniform knob).
|
|
160
|
+
bun scripts/dspark-measure-dflash.ts \
|
|
161
|
+
--model gemma-4-12B-it-OptiQ-4bit \
|
|
162
|
+
--drafter ckpt/dspark-12b --data <prompts.jsonl>
|
|
163
|
+
|
|
164
|
+
# 5. serve it (auto-detected as kind=dspark via dspark.json; γ pinned to cfg.gamma)
|
|
165
|
+
mlx-bun serve --model gemma-4-12B-it-OptiQ-4bit --draft-model ckpt/dspark-12b
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Decision gate (write it down, RESULTS.md only if clean-machine): does 12B live
|
|
169
|
+
τ net a wall-clock win? If the draft loop dominates, do the loop-tightening
|
|
170
|
+
(per-position host syncs + double 262K LM-head) first — see the open items in
|
|
171
|
+
the design doc. Memory guard (`server.ts`) caps context to fit; a client
|
|
172
|
+
sending huge `max_tokens` trips admission — lower it.
|
|
173
|
+
|
|
9
174
|
## What happened (short version)
|
|
10
175
|
- Built v1 first as a single-vector shortcut — it dropped the paper's core KV
|
|
11
176
|
injection and was never really DSpark. Chunk (τ≈1.26) and article (τ≈1.16)
|
|
@@ -31,20 +196,21 @@ architecture problem. Full design + measured numbers:
|
|
|
31
196
|
- Training `--resume` (warm-start from checkpoint) — the GPU runs kept getting killed ~step 5000; resume survives that.
|
|
32
197
|
|
|
33
198
|
## Next (in priority order)
|
|
34
|
-
1. **Retarget to
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
3.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
199
|
+
1. **Retarget to 12B + scale data + train + calibrate + measure** — the GPU
|
|
200
|
+
recipe above is the complete remaining work. (27B stays a future recipe:
|
|
201
|
+
memory-infeasible to train on the 24 GB M4 Pro.)
|
|
202
|
+
2. ~~Tighten the draft inference loop~~ **DONE 2026-07-06** (on-device token
|
|
203
|
+
chaining, deferred conf reads, `collectLogits:false`; bit-identity pinned).
|
|
204
|
+
3. ~~Finish the paper~~ **DONE 2026-07-06**: RNN head (Eq 6, `--seq-head rnn`),
|
|
205
|
+
STS calibration (§3.2.1), Alg-1 confidence-scheduled draft-length pruning
|
|
206
|
+
(single-user form). ⚠ Eq 6 + §3.2.1 shapes are design-doc-faithful readings
|
|
207
|
+
(paper PDF absent) — verify against the paper when available.
|
|
208
|
+
4. ~~Rename `dflash`→`dspark`~~ **DONE 2026-07-06** (canonical variant +
|
|
209
|
+
central loader `src/spec/dspark/loader.ts`; legacy stamps still load).
|
|
45
210
|
|
|
46
211
|
## Key files
|
|
47
|
-
`src/spec/dspark/{module,data,generate}-dflash.ts`, `{loss,sample}.ts`;
|
|
212
|
+
`src/spec/dspark/{module,data,generate}-dflash.ts`, `{loss,sample,calibration,loader}.ts`;
|
|
213
|
+
`src/spec/{source,serve-loop,dflash-source,assistant-source}.ts` (the serve seam);
|
|
48
214
|
`src/model/gemma4.ts` (hiddenTap), `gemma4-base.ts` (trim bypass);
|
|
49
215
|
`scripts/dspark-{regen,train,measure}-dflash.ts`, `dspark-dflash-smoke.ts`.
|
|
50
216
|
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# IndexShare / IndexCache performance spike
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-16
|
|
4
|
+
**Status:** accepted research spike; paper/code audit complete; implementation and
|
|
5
|
+
full-model measurement not started
|
|
6
|
+
**Target:** GLM-5.2 DSA on the M1 Max 32 GB Colibri path
|
|
7
|
+
|
|
8
|
+
## Recommendation
|
|
9
|
+
|
|
10
|
+
Run the spike, but do not treat it as a new model feature. The GLM-5.2 path
|
|
11
|
+
already implements the checkpoint's cross-layer IndexShare schedule: retained
|
|
12
|
+
`full` layers run the DSA indexer and intervening `shared` layers reuse the most
|
|
13
|
+
recent selection. The useful work is to make that correctness path production
|
|
14
|
+
shaped, prove long-context parity, and measure whether the saved indexer work is
|
|
15
|
+
visible behind expert I/O on Apple Silicon.
|
|
16
|
+
|
|
17
|
+
The first prerequisite is the exact stock indexer overlay. The pinned public
|
|
18
|
+
Colibri artifact has no `out-idx-*` files, so every full-model result recorded
|
|
19
|
+
to date is DSA-off. The second prerequisite is a scalable indexer path: current
|
|
20
|
+
code materializes a large `[heads, context, head_dim]` product, copies every
|
|
21
|
+
score to the host, sorts the full score vector in JavaScript, and supports
|
|
22
|
+
sparse DSA only for single-token decode. Those choices are good correctness
|
|
23
|
+
scaffolding but cannot test the paper's long-prefill result.
|
|
24
|
+
|
|
25
|
+
This spike must not change the trained `full`/`shared` pattern or expose it as a
|
|
26
|
+
normal user knob. GLM-5.2 ships IndexShare as checkpoint architecture, not as an
|
|
27
|
+
optional quality/performance preset.
|
|
28
|
+
|
|
29
|
+
## Naming and source claims
|
|
30
|
+
|
|
31
|
+
The linked paper calls the method **IndexCache**. The GLM-5.2 model card calls
|
|
32
|
+
the deployed architecture **IndexShare**. They use the same core mechanism:
|
|
33
|
+
cache the top-k positions produced by a retained DSA indexer and reuse them in
|
|
34
|
+
subsequent shared layers.
|
|
35
|
+
|
|
36
|
+
Primary sources:
|
|
37
|
+
|
|
38
|
+
- [IndexCache paper, arXiv:2603.12201v1](https://arxiv.org/abs/2603.12201v1)
|
|
39
|
+
- [authors' SGLang/vLLM reference patches](https://github.com/THUDM/IndexCache)
|
|
40
|
+
- [pinned GLM-5.2 model card](https://huggingface.co/zai-org/GLM-5.2/blob/f6142f127a14b58dc602592e996cd7d8ff139351/README.md)
|
|
41
|
+
- [pinned GLM-5.2 configuration](https://huggingface.co/zai-org/GLM-5.2/blob/f6142f127a14b58dc602592e996cd7d8ff139351/config.json)
|
|
42
|
+
|
|
43
|
+
The sources establish three different claims that must not be blended:
|
|
44
|
+
|
|
45
|
+
| Claim | Published evidence | What mlx-bun may say before local measurement |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| Cross-layer reuse | F layers compute top-k; S layers reuse the nearest preceding F layer | Implemented semantics, once parity is gated |
|
|
48
|
+
| IndexCache speed | On a 30B DSA model on an 8x H100 node, 1/4 retention reached up to 1.82x prefill and 1.48x per-request decode at 200K context | Paper result only; not a Mac prediction |
|
|
49
|
+
| GLM-5.2 IndexShare | The model card says one retained indexer per four sparse-attention layers reduces per-token FLOPs by 2.9x at 1M context | Vendor FLOP claim only; not end-to-end speed |
|
|
50
|
+
|
|
51
|
+
The paper also reports that uniform 1/4 retention hurts a frozen 30B model's
|
|
52
|
+
long-context average (50.2 to 43.0), while a loss-searched pattern recovers it
|
|
53
|
+
to 49.9. Training-aware IndexCache makes uniform interleaving viable. Therefore
|
|
54
|
+
mlx-bun must preserve GLM-5.2's trained schedule rather than search a new one
|
|
55
|
+
during this spike.
|
|
56
|
+
|
|
57
|
+
## GLM-5.2 schedule
|
|
58
|
+
|
|
59
|
+
The pinned GLM-5.2 config has 78 layers, `index_topk=2048`,
|
|
60
|
+
`index_topk_freq=4`, and `index_skip_topk_offset=3`. Its explicit schedule has
|
|
61
|
+
21 full and 57 shared layers:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
FFFSSSFSSSFSSSF...FSSS
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Relative to an all-full counterfactual, the checkpoint omits 57/78 = 73.1% of
|
|
68
|
+
layer indexer invocations. It does not ship the missing shared-layer indexer
|
|
69
|
+
weights, so a true same-checkpoint `IndexShare off` A/B is impossible. Any
|
|
70
|
+
estimated all-full number must be labeled a component counterfactual, not an
|
|
71
|
+
end-to-end model benchmark.
|
|
72
|
+
|
|
73
|
+
`index_share_for_mtp_iteration` is a second, orthogonal optimization: reuse
|
|
74
|
+
indices across speculative draft iterations. mlx-bun parses that field but does
|
|
75
|
+
not currently consume it in the MTP runtime. Keep its measurement separate so
|
|
76
|
+
cross-layer IndexShare and MTP-iteration sharing each receive an attributable
|
|
77
|
+
result.
|
|
78
|
+
|
|
79
|
+
## Current mlx-bun state
|
|
80
|
+
|
|
81
|
+
Already present:
|
|
82
|
+
|
|
83
|
+
- [`src/model/glm52-config.ts`](../../src/model/glm52-config.ts) parses explicit
|
|
84
|
+
`indexer_types` and the frequency/offset fallback.
|
|
85
|
+
- [`src/model/glm52.ts`](../../src/model/glm52.ts) constructs DSA indexers only
|
|
86
|
+
for full layers and passes one request-local selection state through the
|
|
87
|
+
decoder stack.
|
|
88
|
+
- [`src/model/glm52-dsa.ts`](../../src/model/glm52-dsa.ts) records a full
|
|
89
|
+
layer's exact dense/sparse selection and serves it to shared layers.
|
|
90
|
+
- [`tests/glm52-config-container.test.ts`](../../tests/glm52-config-container.test.ts)
|
|
91
|
+
and [`tests/glm52-dsa.test.ts`](../../tests/glm52-dsa.test.ts) cover schedule
|
|
92
|
+
parsing, missing-owner refusal, context consistency, and exact reuse.
|
|
93
|
+
|
|
94
|
+
Known blockers and likely bottlenecks:
|
|
95
|
+
|
|
96
|
+
1. **No production DSA overlay.** The public Colibri artifact deliberately
|
|
97
|
+
disables DSA because every full-layer indexer tensor is absent. Producing the
|
|
98
|
+
exact overlay requires selective reads from 20 pinned source shards (about
|
|
99
|
+
99.90 GiB input, about 197 MB output). This is a Josh-run acquisition step,
|
|
100
|
+
not an agent-session download.
|
|
101
|
+
2. **No sparse long prefill.** `Glm52DsaIndexer.projectAndSelect()` rejects a
|
|
102
|
+
multi-token prefill once context exceeds `index_topk`. The paper's prefill
|
|
103
|
+
headline is therefore out of scope until chunked/sparse DSA prefill exists.
|
|
104
|
+
3. **Quadratic transient shape.** `glm52DsaScoresMlx()` forms the broadcast
|
|
105
|
+
product before reduction. At production geometry this scales as
|
|
106
|
+
`32 * context * 128` float elements rather than streaming/tiled score
|
|
107
|
+
accumulation.
|
|
108
|
+
4. **GPU-to-host top-k.** The full score vector crosses to a `Float32Array`,
|
|
109
|
+
then `selectDsaThresholdTiesF32()` clones and sorts all positions. This is
|
|
110
|
+
`O(context log context)` host work in each full layer, unlike the production
|
|
111
|
+
GPU top-k assumed by the paper.
|
|
112
|
+
5. **Shared-index copies.** Shared layers clone the 2,048-element JavaScript
|
|
113
|
+
positions list, and absorbed MLA uploads it again before each gather. The
|
|
114
|
+
paper's temporary index tensor is reused in place. Measure this separately;
|
|
115
|
+
remove copies only after ownership and asynchronous lifetime are gated.
|
|
116
|
+
6. **The current short-context bottleneck is elsewhere.** At 128 tokens the
|
|
117
|
+
full model is limited by streamed expert delivery, and DSA cannot prune a
|
|
118
|
+
prefix smaller than 2,048. No short-context speedup should be expected.
|
|
119
|
+
|
|
120
|
+
## Hypotheses
|
|
121
|
+
|
|
122
|
+
- **H1 - component cost:** at the longest context that fits the 32 GB contract,
|
|
123
|
+
retained-indexer time is material and grows roughly linearly per decode token
|
|
124
|
+
with context length.
|
|
125
|
+
- **H2 - sharing value:** avoiding 57 of 78 indexer invocations removes a
|
|
126
|
+
measurable amount of counterfactual work even after a tiled score/top-k
|
|
127
|
+
kernel is used.
|
|
128
|
+
- **H3 - product value:** DSA plus the shipped IndexShare schedule improves
|
|
129
|
+
end-to-end long-context decode over DSA-off full attention, without token
|
|
130
|
+
drift from the official DSA runtime. This comparison measures the combined
|
|
131
|
+
sparse-attention product, not IndexShare in isolation.
|
|
132
|
+
- **H4 - MTP interaction:** any win remains a win with native MTP enabled. A
|
|
133
|
+
decode-only win that disappears under the product MTP path is not a default
|
|
134
|
+
performance claim.
|
|
135
|
+
|
|
136
|
+
## Bounded experiment
|
|
137
|
+
|
|
138
|
+
### Stage 0 - artifact and parity gate
|
|
139
|
+
|
|
140
|
+
1. Generate the immutable `out-idx-*` overlay from the pinned
|
|
141
|
+
`zai-org/GLM-5.2-FP8` revision. Record source revision, selected shard list,
|
|
142
|
+
tensor inventory, byte count, and SHA-256 values. Do not mutate the 357 GiB
|
|
143
|
+
serving snapshot.
|
|
144
|
+
2. Header-validate exactly the 21 full-layer indexers required by the shipped
|
|
145
|
+
schedule and prove that shared-layer indexers are neither required nor
|
|
146
|
+
silently loaded.
|
|
147
|
+
3. Add an official-runtime oracle at contexts above 2,048. Gate selected
|
|
148
|
+
positions, logits on tie-free rows, and greedy token IDs before taking any
|
|
149
|
+
performance number.
|
|
150
|
+
|
|
151
|
+
#### Stage 0 result — pass (2026-08-17)
|
|
152
|
+
|
|
153
|
+
The stock overlay was generated outside mlx-bun from
|
|
154
|
+
`zai-org/GLM-5.2-FP8@ba978f7d347eaf65d22f1a86833408afdb953541`
|
|
155
|
+
with `colibri@ecade075cfc2eae684097ea7de5570c3786ce199`. It contains 20
|
|
156
|
+
`out-idx-*` files totaling 197,202,400 bytes. The existing header validator
|
|
157
|
+
finds 118,646 tensors, 59,066 quantized tensors, 19,456 routed experts,
|
|
158
|
+
complete DSA and MTP families, all 21 required full-layer indexers, and no
|
|
159
|
+
shared-layer indexer requirement.
|
|
160
|
+
|
|
161
|
+
The first-sparse gate prefills exactly 2,048 deterministic tokens, then sends
|
|
162
|
+
one greedy token at context 2,049 with MTP off. The mlx-bun probe observes the
|
|
163
|
+
21 configured full layers and exactly 2,048 selected positions per layer. A
|
|
164
|
+
detached pinned Colibri build captures each official score row, selection,
|
|
165
|
+
float32 logit vector, and token trajectory. Replaying the captured scores with
|
|
166
|
+
`Glm52DsaSelectionState` gives:
|
|
167
|
+
|
|
168
|
+
- 21/21 exact ordered position vectors;
|
|
169
|
+
- 21/21 exact float32 thresholds;
|
|
170
|
+
- 21/21 tie-free boundaries, minimum boundary gap 0.025123596;
|
|
171
|
+
- exact greedy trajectory `[264, 264]` and the same sparse-step top-1 token;
|
|
172
|
+
- 154,880-logit cosine 0.997645, RMSE 0.200109, maximum absolute drift
|
|
173
|
+
0.947218, with wide top-1 margins in both runtimes (9.571914 / 9.567580).
|
|
174
|
+
|
|
175
|
+
The direct full-runtime selections are 10/21 ordered-exact and 14/21
|
|
176
|
+
set-exact. Each of the seven set differences swaps only the single excluded
|
|
177
|
+
position at this top-2,048-of-2,049 boundary. This is upstream numerical drift
|
|
178
|
+
from the runtimes' different quantized-matmul accumulation before DSA, not a
|
|
179
|
+
selector mismatch; replaying identical official scores proves the isolated
|
|
180
|
+
DSA threshold/tie contract exactly. No performance claim is made from either
|
|
181
|
+
correctness run.
|
|
182
|
+
|
|
183
|
+
Reproduction is split between
|
|
184
|
+
`scripts/probe-colibri-glm52-dsa-long.ts` and
|
|
185
|
+
`scripts/check-colibri-glm52-dsa-long.ts`. The raw capture, external Colibri
|
|
186
|
+
instrumentation patch, and SHA-256 inventory are machine-local at
|
|
187
|
+
`~/.cache/mlx-bun/evidence/glm52-dsa-stage0-2026-08-17/`; manifest SHA-256 is
|
|
188
|
+
`6ecb88d944b055146dd700a1714af97b61845d4218527282fcbea009663fe3b4`.
|
|
189
|
+
|
|
190
|
+
### Stage 1 - production-shaped indexer kernel
|
|
191
|
+
|
|
192
|
+
Build a model-free benchmark at exact geometry (`32` heads, head dimension
|
|
193
|
+
`128`, top-k `2048`) for contexts `2,048`, `8,192`, and `32,768`:
|
|
194
|
+
|
|
195
|
+
- tiled score accumulation that never materializes `[H,L,D]`;
|
|
196
|
+
- on-device/native deterministic top-k with the current threshold and
|
|
197
|
+
lower-position tie contract;
|
|
198
|
+
- one compact index buffer retained across F -> S layers;
|
|
199
|
+
- direct gather consumption without a score-vector host copy or per-shared-
|
|
200
|
+
layer index re-upload.
|
|
201
|
+
|
|
202
|
+
Compare the candidate against the existing reference composition for exact
|
|
203
|
+
selected positions on random, tied, all-equal, and production-captured rows.
|
|
204
|
+
Record kernel time, synchronization time, peak MLX allocation, process
|
|
205
|
+
footprint, and bytes copied to/from the host. Negative results count.
|
|
206
|
+
|
|
207
|
+
#### Stage 1 result — pass (2026-08-17)
|
|
208
|
+
|
|
209
|
+
The production path now computes `[H,D] @ [D,L] -> [H,L]` and never forms the
|
|
210
|
+
old `[H,L,D]` broadcast product. Deterministic device selection encodes the
|
|
211
|
+
lexicographic `(score descending, position ascending)` rank into `uint64`, uses
|
|
212
|
+
MLX `argpartition`, and then restores Colibri's observable two-scan ordering
|
|
213
|
+
(strictly above threshold first, threshold ties second). A FULL layer retains
|
|
214
|
+
only the resulting 2,048-entry, 8 KiB index buffer; SHARED layers borrow that
|
|
215
|
+
same device array and MLA gathers from it directly. Normal inference performs
|
|
216
|
+
no score/index host readback or per-SHARED-layer upload. The probe observer is
|
|
217
|
+
the explicit diagnostic exception.
|
|
218
|
+
|
|
219
|
+
Correctness gates pass for deterministic random rows, threshold ties,
|
|
220
|
+
all-equal rows, the exact 2,049/2,048 boundary, borrowed MLA consumption, and
|
|
221
|
+
all 21 production-captured Colibri score rows. The latter reproduce exact
|
|
222
|
+
ordered positions and float32 thresholds on device. A fresh full-model run
|
|
223
|
+
also reproduced all 21 prior mlx-bun position vectors and both greedy tokens;
|
|
224
|
+
its complete 154,880-float decode-logit payload is byte-identical (SHA-256
|
|
225
|
+
`d1f62be2de4877d2fc8ae8feab88e522958210252b50ef96eb786cb22581ba18`).
|
|
226
|
+
Tiled accumulation moved nine diagnostic thresholds by at most
|
|
227
|
+
`3.0517578125e-5`, but no selection boundary moved.
|
|
228
|
+
|
|
229
|
+
The exact-geometry, warm synchronized component benchmark (seven repeats) is:
|
|
230
|
+
|
|
231
|
+
| Context | Production behavior | Score median | Score + top-k median | Timed host copies | MLX peak |
|
|
232
|
+
|---:|---|---:|---:|---:|---:|
|
|
233
|
+
| 2,048 | dense boundary; production skips score/top-k | 0.448 ms (diagnostic only) | — | 0 B | 1.27 MiB |
|
|
234
|
+
| 8,192 | sparse | 0.473 ms | 0.929 ms | 0 B | 5.41 MiB |
|
|
235
|
+
| 32,768 | sparse | 0.748 ms | 1.269 ms | 0 B | 21.35 MiB |
|
|
236
|
+
|
|
237
|
+
At those contexts the removed broadcast product would have been 32, 128, and
|
|
238
|
+
512 MiB respectively; the tiled dot output is 0.25, 1, and 4 MiB. These are
|
|
239
|
+
model-free component measurements, not end-to-end inference claims. The
|
|
240
|
+
benchmark is `scripts/bench-glm52-dsa-indexer.ts`. Machine-local evidence is
|
|
241
|
+
under `~/.cache/mlx-bun/evidence/glm52-dsa-stage1-2026-08-17/`; manifest
|
|
242
|
+
SHA-256 is
|
|
243
|
+
`600ec92c41d4c66735e1834a678a09f2ae55ecdddfab31c3dd1bf31ee9709fef`.
|
|
244
|
+
|
|
245
|
+
### Stage 2 - decode matrix
|
|
246
|
+
|
|
247
|
+
Use direct library inference, not a server. Run separate fresh processes and
|
|
248
|
+
the standard quiet-machine preflight.
|
|
249
|
+
|
|
250
|
+
| Axis | Cells |
|
|
251
|
+
|---|---|
|
|
252
|
+
| Context | 2,048; 8,192; 32,768; 64K only if the exact planner remains inside the 25 GiB process ceiling |
|
|
253
|
+
| DSA | off/full attention; on with the checkpoint's 21F/57S schedule |
|
|
254
|
+
| MTP | off to isolate DSA; on for the product decision |
|
|
255
|
+
| Residency | the same fixed expert policy and seed profile in every paired arm |
|
|
256
|
+
| Repeats | three fresh processes per default-eligible cell; cold and warm turn in each process |
|
|
257
|
+
|
|
258
|
+
For each turn record TTFT, prefill wall time, decode tok/s, total wall time,
|
|
259
|
+
DSA projection/score/top-k/gather time, MLA time, expert disk service/wait,
|
|
260
|
+
target forwards, MTP acceptance, physical footprint, compression, swap, and
|
|
261
|
+
exact token IDs.
|
|
262
|
+
|
|
263
|
+
The DSA-off versus DSA-on result combines sparse core attention with
|
|
264
|
+
IndexShare. To estimate IndexShare's isolated contribution, report the measured
|
|
265
|
+
retained-indexer total and a clearly labeled all-full component counterfactual
|
|
266
|
+
derived from the same per-layer exact-geometry benchmark. Do not present that
|
|
267
|
+
counterfactual as a runnable checkpoint.
|
|
268
|
+
|
|
269
|
+
#### Stage 2 result — pass, negative product-performance decision (2026-08-17)
|
|
270
|
+
|
|
271
|
+
The fresh-process runner planned 36 cells. Twenty-four were eligible under the
|
|
272
|
+
G5 25 GiB process ceiling and completed: contexts 2,048 and 8,192, four DSA/MTP
|
|
273
|
+
arms, and three repeats. Every process ran cold and warm turns. Cold/warm,
|
|
274
|
+
cross-repeat, and MTP-off/on greedy token vectors were exact; all emitted
|
|
275
|
+
sixteen token IDs equal to `264`. The twelve 32K combinations were not run:
|
|
276
|
+
the exact planner reports 29,334,150,784 bytes (27.320 GiB) MTP-off and
|
|
277
|
+
30,644,281,216 bytes (28.540 GiB) MTP-on, both above the unchanged 25 GiB
|
|
278
|
+
process limit. The initial refusal is retained in the evidence as an attempt
|
|
279
|
+
record. This is contract ineligibility, not an allocation crash.
|
|
280
|
+
|
|
281
|
+
Long prompts use an explicitly bounded benchmark seam: dense batched prompt
|
|
282
|
+
construction ends at the exact prompt boundary, and every subsequent decode or
|
|
283
|
+
MTP verification row uses exact DSA. These numbers characterize decode and
|
|
284
|
+
whole-turn wall time only. They are not sparse-prefill measurements.
|
|
285
|
+
|
|
286
|
+
Warm medians across three fresh processes are:
|
|
287
|
+
|
|
288
|
+
| Context | DSA | MTP | Decode tok/s | Total wall |
|
|
289
|
+
|---:|---|---|---:|---:|
|
|
290
|
+
| 2,048 | off | off | 0.1363 | 260.9 s |
|
|
291
|
+
| 2,048 | on | off | 0.1318 | 271.5 s |
|
|
292
|
+
| 2,048 | off | on | 0.1312 | 281.7 s |
|
|
293
|
+
| 2,048 | on | on | 0.0880 | 338.7 s |
|
|
294
|
+
| 8,192 | off | off | 0.1292 | 722.1 s |
|
|
295
|
+
| 8,192 | on | off | 0.1420 | 711.8 s |
|
|
296
|
+
| 8,192 | off | on | 0.1587 | 711.8 s |
|
|
297
|
+
| 8,192 | on | on | 0.1042 | 770.1 s |
|
|
298
|
+
|
|
299
|
+
At 8K without MTP, the paired median DSA delta is +12.38% decode throughput
|
|
300
|
+
and -1.89% total wall time. Expert I/O and prompt work hide most of the decode
|
|
301
|
+
gain, leaving the whole-turn result below the required 5%. With MTP enabled,
|
|
302
|
+
the paired median delta reverses to -34.33% decode throughput and +8.19% total
|
|
303
|
+
wall time. The exact MTP trace explains part of the product result: DSA-off
|
|
304
|
+
accepted ten drafts in five rounds (3.2 tokens/target forward, six target
|
|
305
|
+
calls), whereas DSA-on accepted eight drafts in seven rounds (2.286
|
|
306
|
+
tokens/target forward, eight target calls). Small verify batches now keep
|
|
307
|
+
residual/MLP/expert work batched, but exact causal sparse attention still runs
|
|
308
|
+
per verification row. Two of the three 8K DSA+MTP cells observed net swap
|
|
309
|
+
growth, so the memory side of the win gate also does not close.
|
|
310
|
+
|
|
311
|
+
The immutable external overlay retains 197,202,400 bytes of indexers. As a
|
|
312
|
+
clearly labeled non-runnable component counterfactual, Stage 1's 8K
|
|
313
|
+
score+top-k median implies 19.51 ms for the shipped 21 FULL layers versus
|
|
314
|
+
72.48 ms for hypothetical 78 FULL layers, so IndexShare avoids about 52.97 ms
|
|
315
|
+
of selection work per target row. At 32K the corresponding component-only
|
|
316
|
+
figures are 26.64 ms, 98.95 ms, and 72.31 ms avoided. The checkpoint lacks the
|
|
317
|
+
57 missing indexers, and these sums exclude the rest of model execution.
|
|
318
|
+
|
|
319
|
+
The product decision is negative: retain the exact 21F/57S implementation as
|
|
320
|
+
model semantics and land its correctness/scalability work, but make no local
|
|
321
|
+
end-to-end speed claim. Decode is conclusive, so Stage 3 remains a separate
|
|
322
|
+
deferred prefill experiment rather than a G6R exit requirement. Evidence is
|
|
323
|
+
under `~/.cache/mlx-bun/evidence/glm52-dsa-stage2-2026-08-17/`; manifest
|
|
324
|
+
SHA-256 is
|
|
325
|
+
`90b3fe4ed53714604b7a747991b3bb1b87aedbf57a139915065f5b4be42cda38`.
|
|
326
|
+
|
|
327
|
+
### Stage 3 - deferred prefill follow-up
|
|
328
|
+
|
|
329
|
+
Only after decode is characterized, implement chunked sparse prefill with exact
|
|
330
|
+
causal selection semantics and run the same context ladder. This is the stage
|
|
331
|
+
that can test whether the paper's growing prefill benefit translates to MLX;
|
|
332
|
+
the existing single-token path cannot support that claim.
|
|
333
|
+
|
|
334
|
+
## Decision rules
|
|
335
|
+
|
|
336
|
+
- Preserve the shipped 21F/57S schedule regardless of outcome; it is model
|
|
337
|
+
semantics.
|
|
338
|
+
- Call the work a local performance win only when three fresh MTP-on processes
|
|
339
|
+
are token-identical and the paired median end-to-end wall time improves by at
|
|
340
|
+
least 5% at a context that fits the 32 GB contract, without new swap or a
|
|
341
|
+
footprint regression outside the existing G5 bounds.
|
|
342
|
+
- If the kernel saves DSA time but expert I/O hides the wall win, land only the
|
|
343
|
+
correctness/scalability work and record the negative end-to-end result.
|
|
344
|
+
- Do not quote the paper's H100 speedups or GLM-5.2's 1M-token FLOP reduction as
|
|
345
|
+
mlx-bun speed. Curated claims require this machine's `benchmark.sh`-quality
|
|
346
|
+
evidence and belong in `benchmarks/RESULTS.md` only after the gate passes.
|
|
347
|
+
- Evaluate MTP-iteration index sharing as a separate follow-up with its own
|
|
348
|
+
on/off control and acceptance trace.
|
|
349
|
+
|
|
350
|
+
## Exit
|
|
351
|
+
|
|
352
|
+
The spike closes when the DSA overlay is provenance-pinned, long-context
|
|
353
|
+
IndexShare matches an official runtime, the production-shaped score/top-k path
|
|
354
|
+
has exact model-free gates, and the paired MTP-off/on decode matrix has a
|
|
355
|
+
written decision. Prefill may remain a separately tracked follow-up only if the
|
|
356
|
+
decode result is already conclusive; otherwise sparse long prefill is required
|
|
357
|
+
before closure.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Build journal — mlx-bun Lab (web UI + native quantize/train/dataset + pi web chat)
|
|
2
2
|
|
|
3
3
|
*Branch `web-ui-and-native-lab`, 2026-06-13/14. Visual summary:
|
|
4
|
-
[archive/mlx-bun-lab-report.html](../../archive/mlx-bun-lab-report.html). Evidence
|
|
4
|
+
[archive/mlx-bun-lab-report.html](../../docs/archive/mlx-bun-lab-report.html). Evidence
|
|
5
5
|
artifact: `benchmarks/lab-verification.json` (regenerable, gitignored — produced by
|
|
6
6
|
`scripts/verify-lab.ts`).*
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ page. Compute is **native Bun/MLX (no Python)** per Josh's decision.
|
|
|
22
22
|
|
|
23
23
|
2. **Gate the riskiest unknown first.** Native LoRA needs autograd across the
|
|
24
24
|
FFI boundary. Rather than discover mid-build that it's infeasible, the first
|
|
25
|
-
thing built was `spikes/phase-train-vag.ts`: a tiny LoRA-shaped loss
|
|
25
|
+
thing built was `lab/spikes/phase-train-vag.ts`: a tiny LoRA-shaped loss
|
|
26
26
|
(`mean((x + (x@A)@B − y)²)`) differentiated by `mlx_value_and_grad` through a
|
|
27
27
|
`bun:ffi` JSCallback closure, checked against central finite differences.
|
|
28
28
|
**PASS (<1e-2), exactly 2 grads returned (base frozen).** Only then was the
|