mlx-bun 0.0.9 → 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 +255 -0
- 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 +98 -0
- 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 +18 -2
- package/docs/design/ssd-kv-cold-tier.md +288 -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/decode-roofline-lookagain.md +92 -6
- package/docs/investigations/dspark-handoff.md +182 -16
- package/docs/investigations/kernel-perf-review-2026-07.md +105 -26
- 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.10.md +57 -0
- 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 +251 -119
- package/docs/reference/training.md +20 -16
- 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 +402 -107
- 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 -16
- package/src/grammar.ts +585 -0
- package/src/hub-rest.ts +242 -0
- package/src/kv-store.ts +618 -122
- 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 +127 -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 +179 -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 +391 -34
- 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 +123 -15
- package/src/model/qwen3-moe.ts +404 -0
- package/src/model/qwen3.ts +9 -8
- package/src/model/qwen3_5.ts +99 -25
- 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 +338 -32
- package/src/quantize/quantizer.ts +16 -1
- package/src/registry.ts +61 -3
- package/src/serve/batch-scheduler.ts +1001 -76
- package/src/serve/generation-gateway.ts +292 -30
- 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 +1460 -105
- 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 +285 -0
- 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 +29 -26
- package/src/train/job.ts +0 -2
- package/src/train/loss.ts +53 -11
- package/src/train/prefix-shared.ts +30 -7
- package/src/train/segmented.ts +150 -46
- package/src/train/trainer.ts +22 -15
- 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
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Decode perf "look again" — adversarial re-exam of the M=1 floor claim (2026-07-01)
|
|
2
2
|
|
|
3
|
+
> **2026-07-02 CORRECTION — the host-graph-tax claim is itself overturned; see
|
|
4
|
+
> §7.** The fix-plan items 1a–1d were built on "host graph build is serial with
|
|
5
|
+
> the GPU"; the overlap spike (decode-overlap-probe.ts) shows the pipelined loop
|
|
6
|
+
> ALREADY hides the build. The §3 wall times and %-of-roofline stand; the
|
|
7
|
+
> §4(b)/(c) decomposition does not — the whole gap is GPU-side.
|
|
8
|
+
|
|
3
9
|
**Machine:** Apple M1 Max, 32 GB (MacBookPro18,2), `sysctl` verified. All eval-DB
|
|
4
10
|
rows are also M1 Max — same box. **All numbers below are directional (session,
|
|
5
11
|
loaded-machine caveat); quotable numbers remain benchmark.sh-gated.** GPU idle
|
|
@@ -225,12 +231,33 @@ is suspect, profile on the other laptop before building anything.**
|
|
|
225
231
|
1d. **12B short-context: compile the concat phase too** (or accept 1b as
|
|
226
232
|
the fix). The current segmented form compiles nothing below the 1024
|
|
227
233
|
window and never compiles the 8 full-attention layers. ~+9% @600.
|
|
228
|
-
2. **26B GPU overhead (~4 ms/tok over floor):** profile gather-qmm expert
|
|
229
|
-
reads (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
2. **26B GPU overhead (~4 ms/tok over floor):** ~~profile gather-qmm expert
|
|
235
|
+
reads~~ **PROFILED 2026-07-02** (moe-expert-read-profile.ts, exact 26B
|
|
236
|
+
shapes; real decode @600 re-measured 21.0–22.6 ms/tok ✓). The gap is real
|
|
237
|
+
and located, but BOTH cheap candidates are refuted: expert-contiguous
|
|
238
|
+
layout does nothing (a chain with ONE expert repeated ×8 — 1/8 the unique
|
|
239
|
+
bytes — runs at the same speed: not bandwidth/locality-bound), and merging
|
|
240
|
+
gate+up stacks to cut dispatches is SLOWER (9.6 vs 8.1 ms). Root cause:
|
|
241
|
+
**mx.gather_qmm at M=1 is compute-bound** (~99 GB/s effective vs the qmv
|
|
242
|
+
kernel's ~180 on identical bytes; upstream python mlx 0.31.2 reproduces
|
|
243
|
+
6.18 vs 4.01 ms) — it lacks a qmv-class fast path, so each per-expert
|
|
244
|
+
[1,2816]→[704] product runs on mostly-idle GEMM tiles. The router chain
|
|
245
|
+
adds a secondary ~1.6–2.6 ms of tiny-op dispatches.
|
|
246
|
+
**Custom-kernel attempt (same day): built, correct, SHELVED.** A gather-qmv
|
|
247
|
+
Metal kernel (scripts/experiments/moe-qmv-kernel.ts + moe-qmv-parity.ts)
|
|
248
|
+
passes bounded-divergence on all three 26B dispatch patterns, but five
|
|
249
|
+
structural variants (occupancy/staging/bank-conflict/mask-trick sweeps —
|
|
250
|
+
post-mortem table in the kernel header) all measure SLOWER than gather_qmm
|
|
251
|
+
(best 12.5 vs 8–10 ms on the 30-layer chain), and the killer measurement is
|
|
252
|
+
structural: **mx.fast.metal_kernel dispatches cost ~60–95 µs each in a
|
|
253
|
+
dependent chain, nearly independent of the work inside** — at 3
|
|
254
|
+
dispatches/layer × 30 layers that fixed cost alone eats the entire ~4 ms
|
|
255
|
+
prize. Remaining routes, in order: (a) UPSTREAM — give mlx's gather_qmm an
|
|
256
|
+
M=1 qmv-class path in C++ (no dispatch overhead; natural companion to the
|
|
257
|
+
quantized_matmul M=2/3 bug report), (b) a fused whole-MLP kernel (gate+up+
|
|
258
|
+
gelu in one dispatch, down in a second → 60 dispatches/step) with a
|
|
259
|
+
qmv-class body — a dedicated fused-decode-v2-style session starting from
|
|
260
|
+
the post-mortem map.
|
|
234
261
|
3. **e4b GPU overhead (1.8–3.7 ms):** dispatch-count reduction on the
|
|
235
262
|
per-layer-input machinery (the ~1–2 MiB gate/proj GEMVs and altup
|
|
236
263
|
elementwise chains; batch the 42 per-layer gate GEMVs into one [42·width]
|
|
@@ -247,7 +274,66 @@ is suspect, profile on the other laptop before building anything.**
|
|
|
247
274
|
bandwidth wall (weight read shared across K tokens) — unchanged priority,
|
|
248
275
|
now with the roofline to prove why nothing else can.
|
|
249
276
|
|
|
277
|
+
## 7. The overlap spike (2026-07-02) — fix 1b REFUTED; §4(c) decomposition corrected
|
|
278
|
+
|
|
279
|
+
Fix 1b asked: can the host graph build hide under the GPU (build-two-ahead /
|
|
280
|
+
off-thread dispatch)? `decode-overlap-probe.ts` answers two ways — the
|
|
281
|
+
decisive one is DIRECT REMOVAL: take the per-step host build out of the loop
|
|
282
|
+
entirely (pre-build all N step graphs up front, chained through the lazy
|
|
283
|
+
argmax outputs — identical graph structure to production — then run
|
|
284
|
+
dispatch+read with zero interleaved build) and see if decode gets faster.
|
|
285
|
+
|
|
286
|
+
M1 Max, greedy, uncompiled, all arms token-IDENTICAL to baseline:
|
|
287
|
+
|
|
288
|
+
| arm | CPM5 @132 (spin 2 ms) | e4b @600 (spin 4 ms) |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| baseline (pipelined) | 4.05 ms/tok (graph 0.86, dispatch 3.13) | 19.02→18.06 across passes (graph ~3.3–3.6, dispatch ~14) |
|
|
291
|
+
| **prebuilt (host build REMOVED)** | **4.11 (+0.07)** | **19.03 (+0.01)** |
|
|
292
|
+
| prebuilt-1buf (also no per-step dispatch boundaries) | 4.33 | 19.73 |
|
|
293
|
+
| serial (evalAll, no pipeline) | **+1.75 ms** | **+3.36 ms** |
|
|
294
|
+
| spin-build / spin-pre / spin-post (+W injected host work) | **+0.4 ms** (not +2) | **+1.0–1.4 ms** (not +4) |
|
|
295
|
+
| chain-2 / chain-3 (deeper pipeline) | ±0.01 ms | +0.02 / −0.96 (== pass drift) |
|
|
296
|
+
|
|
297
|
+
- **Removing the work gains nothing**: with the entire 0.9 ms (CPM5) /
|
|
298
|
+
3.6 ms (e4b) per-token build lifted out of the loop, decode speed is
|
|
299
|
+
unchanged (+0.07 / +0.01 ms, inside pass-to-pass drift). Even the one-buffer
|
|
300
|
+
floor — no host work AND no per-step dispatch boundaries — is no faster.
|
|
301
|
+
**The build already overlaps; wall = GPU step time.**
|
|
302
|
+
- The injection arms agree from the other direction: extra host work is
|
|
303
|
+
ABSORBED (dispatch shrinks 3.13→1.6 exactly as `gpu − host` predicts) — the
|
|
304
|
+
GPU is busy with step n while the host builds step n+1.
|
|
305
|
+
- The serial anchor costs MORE than the build itself (CPM5 +1.75 vs 0.86;
|
|
306
|
+
e4b +3.36 vs 3.6): the pipelined loop hides the build AND the per-step
|
|
307
|
+
launch gap. The loop shape is already right; mlx-lm's identical shape gets
|
|
308
|
+
the identical hiding.
|
|
309
|
+
- Deeper pipelining (chain-2/3) buys exactly nothing — there is no residual
|
|
310
|
+
host term to hide.
|
|
311
|
+
|
|
312
|
+
**Corrections to this doc:**
|
|
313
|
+
- §4(c) "host JS loop — the single biggest NON-physics term" is WRONG as an
|
|
314
|
+
additive claim. The "host graph ms" column was measured as time-in-JS-calls,
|
|
315
|
+
but that window runs concurrently with the GPU; "GPU ms" (= the dispatch
|
|
316
|
+
wait) is `gpu − graph`, so summing them reconstructs the wall without any
|
|
317
|
+
recoverable host term. The true GPU step time ≈ the measured wall itself.
|
|
318
|
+
- §6.1a (CPM5 CompiledDecode "+20–25%"): premise gone. Any compiled-decode win
|
|
319
|
+
is GPU-side (fewer/denser dispatches from C++ replay), not host removal —
|
|
320
|
+
re-bill as profile-first, expected small. This also re-explains §4(d):
|
|
321
|
+
e4b @600 compiled wall 18.9→18.1 means compiled made the GPU ~0.8 ms faster
|
|
322
|
+
(net of concat tax), not "host −2.4, GPU +1.7".
|
|
323
|
+
- §6.1b (this spike): answered, REFUTED — nothing to build.
|
|
324
|
+
- §6.1c/1d (SharedKv segmented-compile plumbing ~L effort, 12B concat-phase
|
|
325
|
+
compile): the host-tax share of their billing is gone; only GPU-side effects
|
|
326
|
+
remain. De-prioritize pending a GPU-side profile.
|
|
327
|
+
- §6 items 2 (26B expert reads), 3 (e4b dispatch count), 4 (backlog #4
|
|
328
|
+
contiguity), 5 (CPM5 KV-path), 6 (spec decode) are UNAFFECTED — they were
|
|
329
|
+
always GPU-side, and they are now the entire recoverable gap.
|
|
330
|
+
- 12B/26B not re-probed (structurally the same loop; 12B was at-wall under
|
|
331
|
+
either reading; 26B's 3.7 ms graph ≪ its ~18 ms step has the same slack).
|
|
332
|
+
|
|
250
333
|
## Probes added (scripts/experiments/, tsc-clean)
|
|
334
|
+
- `decode-overlap-probe.ts` — direct-removal (prebuilt / prebuilt-1buf) +
|
|
335
|
+
spin-injection + serial-anchor + chain-depth arms for the overlap question
|
|
336
|
+
(§7).
|
|
251
337
|
- `decode-roofline-bw.ts` — machine bandwidth: raw read, decode-shaped qmv
|
|
252
338
|
GEMV (multi-copy, one-eval chaining), bf16 GEMV, dispatch chain.
|
|
253
339
|
- `decode-roofline-step.ts` — factory-generic pipelined decode split
|
|
@@ -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
|
|
|
@@ -12,7 +12,7 @@ area reviews + full mechanisms): `reports/kernel-perf-review-2026-07-01.json`
|
|
|
12
12
|
vendored MLX steel machinery, exact-by-default backward with autograd + FD
|
|
13
13
|
parity — marred by decision drift: the PLAN-decided 1.35× filter win was
|
|
14
14
|
never landed and the in-code comments argued three contradictory positions
|
|
15
|
-
(comments fixed 2026-07-01; the FLIP
|
|
15
|
+
(comments fixed 2026-07-01; the FLIP LANDED 2026-07-02 — see backlog #1).
|
|
16
16
|
- **Training flash-attention kernel**: faithful port with exemplary post-bug
|
|
17
17
|
discipline, correctly opt-in — but it copies a naive oracle (~30× slower)
|
|
18
18
|
and its tests covered none of the production configs (extended 2026-07-01:
|
|
@@ -47,35 +47,109 @@ evalSftLoss error swallowing · tokens_per_sec metric · inverted comments
|
|
|
47
47
|
(gemma4.ts:298, flash-cce filter trio) · silent steel fallback (now warns;
|
|
48
48
|
H%128 throw narrowed) · flash-attn test blindness.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
tile loop at trace-time N — q-cat adapters grow N per step under shapeless
|
|
52
|
-
replay, so the newest KV rows
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
FIXED 2026-07-02: **FUSED_DECODE=1 inside whole-graph compiled decode** baked
|
|
51
|
+
the tile loop at trace-time N — q-cat adapters grow N per step under shapeless
|
|
52
|
+
replay, so the newest KV rows were silently never attended. REPRODUCED on e4b
|
|
53
|
+
(42 layers traced tile=true at N=17; diverges within 3 tokens then
|
|
54
|
+
repetition-loops). The 12B was never affected — its segmented form runs concat
|
|
55
|
+
layers as uncompiled js layers. Fix: generate() refuses to compile under
|
|
56
|
+
MLX_BUN_FUSED_DECODE=1 (explicit opt-in wins, like LoRA/MoE) + quantizedSdpa
|
|
57
|
+
throws if the tiled path is ever selected inside a trace (lands in the
|
|
58
|
+
transactional fallback, never silent). Regression in
|
|
59
|
+
tests/compiled-decode.test.ts, whose e4b block also now uses the dynamic
|
|
60
|
+
snapshot resolver — the old hard-coded hash silently skipped it on this
|
|
61
|
+
machine, which is how the combo went unexercised.
|
|
62
|
+
|
|
63
|
+
NEW BUG (found 2026-07-02 by the backlog-#8 gate test; FIXED in mlx-bun,
|
|
64
|
+
UPSTREAM in mlx): **mx.quantized_matmul(transpose=false) returns wrong values
|
|
65
|
+
at row count 2 or 3** — relnorm ~0.33-0.39 on our dylib, ~0.98-1.14 on stock
|
|
66
|
+
mlx 0.31.2 (oracle venv repro); M=1 and M>=4 exact, transpose=true exact at
|
|
67
|
+
every M. mlx's autograd computes dh for a transpose=true head qmm via an
|
|
68
|
+
internal transpose=false call at the cotangent's row count, so EVERY training
|
|
69
|
+
head silently produced wrong dh for 2-3-token responses, 2-3-token tail
|
|
70
|
+
chunks, and tiny prompt spans (f32 ground truth: dh relnorm up to 0.99 at the
|
|
71
|
+
affected positions, cos ~0.2). Serving/decode unaffected (transpose=true).
|
|
72
|
+
Fix: (a) loss.ts `logitsFromHiddenPadM` pads differentiated head spans to 4
|
|
73
|
+
rows (pad cotangents are exactly zero) — applied at all seven head sites;
|
|
74
|
+
(b) ops.quantizedMatmul pads direct transpose=false calls (the fused head's
|
|
75
|
+
analytic backward). Verified vs f32-dequant ground truth (chunk-4 dh
|
|
76
|
+
0.47→0.006) + M-sweeps. Worth filing upstream with the 10-line python repro.
|
|
55
77
|
|
|
56
78
|
## The ranked optimization backlog (task #12)
|
|
57
79
|
|
|
58
|
-
1.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
E4B=1
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
1. ~~**[S] Land the coeff filter at eps~1e-5**~~ **LANDED 2026-07-02** — BOTH
|
|
81
|
+
skips default 1e-5 (coeff filter + blockMax block skip; env=0 restores exact).
|
|
82
|
+
All gates run on the M1 Max with real chunk-ORPO data
|
|
83
|
+
(flash-cce-filter-realdata.ts, extended: E4B=1 + blockEps sweep + Vjp
|
|
84
|
+
full-logits fidelity): filter CPM5 0.343%/1.41×, e4b 0.158%/1.70×; blockMax
|
|
85
|
+
skip ~lossless (≤0.004%) and real text DOES go cold (the synthetic probe was
|
|
86
|
+
the artifact) — **combined 1.71× (CPM5) / 3.16× (e4b)**; teacher-forced
|
|
87
|
+
fidelity cosine ≥0.99993, filter adds ≤0.07% over the eps=0 reassociation
|
|
88
|
+
floor (standing test in tests/train-orpo-fused-ce.test.ts). The "eps=0
|
|
89
|
+
byte-identical" gate resolved structurally: eps=0 compiles the identical
|
|
90
|
+
pre-flip kernel, but run-to-run dh is never byte-stable (atomic-add
|
|
91
|
+
reassociation) — byte-replay was the wrong spelling of that gate.
|
|
92
|
+
2. ~~**[M] planSegments full-attention isolation**~~ **REFUTED BY MEASUREMENT
|
|
93
|
+
2026-07-02** — built, A/B'd @8K on real chunk rows: ZERO peak win (18.09 vs
|
|
94
|
+
18.02 GB; scripts/experiments/seg-isolation-smoke.ts + MLX_BUN_SEG_MEM_LOG
|
|
95
|
+
phase probes). The §5 cost-model premise is false: mlx's sdpa BACKWARD
|
|
96
|
+
materializes O(L²) scores for EVERY layer (~3.5 GB/layer @8K e4b — the
|
|
97
|
+
sliding window is just an additive mask; sliding pair +7.1 GB ≈ full+sliding
|
|
98
|
+
+7.15). Worst segment = layer count alone, so **segment_size is the whole
|
|
99
|
+
knob: seg1 measures 14.59 GB @8K (+3% step time, loss identical) — which
|
|
100
|
+
DOES fit the 24 GB M4 Pro today, no code needed.** Inter-segment clearCache
|
|
101
|
+
also measured no-effect (watermark is live memory). Real next levers: the
|
|
102
|
+
head vjp's ~3 GB [M,V] spike (backlog #8) and an O(L)-memory attention
|
|
103
|
+
backward (the flash-attention track).
|
|
104
|
+
3. ~~**[S] Auto-dispatch the training head by M**~~ **LANDED 2026-07-02** —
|
|
105
|
+
fusedRespLogpMean routes requested-flash batches with M <
|
|
106
|
+
MLX_BUN_FLASH_MIN_M (default 1024) to the exact fused head. Fresh crossover
|
|
107
|
+
sweep (head-dispatch-sweep.ts, M1 Max — the review's 1.9× @M=512 was
|
|
108
|
+
pre-filter-flip): fused wins e4b M=64 1.6× / M=512 1.13×, tie @1024; the
|
|
109
|
+
#1-flip made flash FASTER at long M too (e4b ≥2048; 8K 10.7 vs 13.2 s) on
|
|
110
|
+
top of its memory win. CPM5: fused faster at every M — flash stays a pure
|
|
111
|
+
memory lever there (≥1024 honors the caller's intent). Dispatch proven by
|
|
112
|
+
bit-identical-to-fused loss in tests/train-orpo-fused-ce.test.ts.
|
|
113
|
+
4. ~~**[S] Fused decode full-capacity KV buffers + activeN**~~ **REFUTED BY
|
|
114
|
+
MEASUREMENT 2026-07-02** — the variant was built (an int32 activeN input,
|
|
115
|
+
capacity-strided rows, fetch attaches full buffers), gated BYTE-IDENTICAL
|
|
116
|
+
on all three recorded dispatch shapes and perf-oracle-green — and then
|
|
117
|
+
measured SLOWER end-to-end: interleaved in-process A/B on the 12B uniform
|
|
118
|
+
kv4 (tokens identical across arms, M1 Max) gave 24.64 vs 26.18 tok/s @8k
|
|
119
|
+
(0.94) and 23.07 vs 23.83 @22k (0.97) — the "~4× at 32k" scaling is
|
|
120
|
+
refuted too. Two holes in the estimate: the 12B's full-attention dispatch
|
|
121
|
+
shape is KV=1 (H16 D512), where the fetch view is a CONTIGUOUS PREFIX and
|
|
122
|
+
the six-copies model never applied; and kernel-only micro-A/Bs proved
|
|
123
|
+
unstable (±50% run-to-run) — the numbers behind "1-3%" were never
|
|
124
|
+
end-to-end. REVERTED; evidence + re-application recipe:
|
|
125
|
+
scripts/experiments/fused-decode-activen-ab.ts.
|
|
69
126
|
5. **[M] Collapse per-token host syncs in the spec/DSpark loop** — ~2γ+1
|
|
70
127
|
round-trips → ~2 per verify cycle; directly attacks DSpark's fixed draft
|
|
71
128
|
overhead.
|
|
72
129
|
6. **[M] Pipeline the batched decode loop + clearCache cadence** — folded into
|
|
73
130
|
the batching-v2 wave (docs/design/batching-v2-plan.md).
|
|
74
131
|
7. **[S] Enable the 26B perf kernel** (open PLAN Phase E box; oracle frozen).
|
|
75
|
-
8.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
132
|
+
8. ~~**[S] Bound the SFT segmented head**~~ **LANDED 2026-07-02** — both SFT
|
|
133
|
+
segmented classes now use boundedSftCe (token-chunked Checkpoint head, the
|
|
134
|
+
proven ORPO plumbing; MLX_BUN_SEG_HEAD/MLX_BUN_SEG_HEAD_CHUNK knobs).
|
|
135
|
+
Head-only A/B at e4b M=6000: whole-vocab head 16.60 GB peak vs bounded
|
|
136
|
+
6.60 GB (**~10 GB head-vjp transient eliminated**), loss identical, dh
|
|
137
|
+
relnorm 0.00000; head time +45% (Checkpoint recompute, small share of a
|
|
138
|
+
step). The @8K smoke's short responses were never head-bound (peak set by
|
|
139
|
+
the per-layer sdpa backward — see #2), so its wall peak moved little; the
|
|
140
|
+
win is exactly the long-response regime the review named. Gate test:
|
|
141
|
+
tests/train-orpo-fused-ce.test.ts "bounded SFT head".
|
|
142
|
+
**Landing this exposed a NEW upstream mlx bug (see ledger below).**
|
|
143
|
+
9. ~~**[S] Segmented-step overhead pass**~~ **LANDED 2026-07-02** — all three
|
|
144
|
+
fixes: MlxArray.detachCopy (ONE mlx→mlx copy; the old rawBytes+
|
|
145
|
+
fromBytesCopy route was two copies via the JS heap), detachLeaves (ONE
|
|
146
|
+
evalAll barrier per segment's whole vjp set, applied in all six segmented
|
|
147
|
+
backward loops), and a step-shared block-sparse-mask memo for the CPM5
|
|
148
|
+
prefix classes (prefixSharedCaches — makeMask hands out slice views).
|
|
149
|
+
Gate: loss + grads BYTE-IDENTICAL on CPM5-SFT / CPM5-ORPO-prefix / e4b-SFT
|
|
150
|
+
fixed steps. Step time (short-seq fixtures, M1 Max): CPM5 ORPO-prefix
|
|
151
|
+
238→158 ms (−34%), e4b SFT 2065→1272 ms (−38%); e4b @8K flat (GPU-bound,
|
|
152
|
+
as predicted) with peak unchanged (14.49 GB).
|
|
79
153
|
10. **[M] e4b prefill gap** — profile-first; NOTE: the decode look-again could
|
|
80
154
|
NOT reproduce RESULTS.md's 304-vs-373 row on the M1 Max (no eval-DB
|
|
81
155
|
backing) — re-bench on the M4 Pro before building anything.
|
|
@@ -85,8 +159,13 @@ or make the tile loop trace-safe).
|
|
|
85
159
|
The review's framing assumed the megakernel post-mortem's "M=1 decode is at
|
|
86
160
|
the floor". The follow-up investigation (docs/investigations/
|
|
87
161
|
decode-roofline-lookagain.md) OVERTURNED that: only the 12B is at the wall
|
|
88
|
-
(~92-93% of measured roofline); CPM5 58-64%, e4b 64-70%, 26B 60-62
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
162
|
+
(~92-93% of measured roofline); CPM5 58-64%, e4b 64-70%, 26B 60-62%.
|
|
163
|
+
**2026-07-02 second correction (lookagain §7):** the "host JS graph build =
|
|
164
|
+
#1 recoverable term" part of that verdict was itself wrong — the overlap
|
|
165
|
+
spike (decode-overlap-probe.ts, spin-injection + serial anchor) proved the
|
|
166
|
+
pipelined loop ALREADY hides the build; wall = GPU step time. The lookagain's
|
|
167
|
+
host-side fixes (1a–1d: CPM5 compiled-decode port, build-ahead spike, SharedKv
|
|
168
|
+
segmented-compile, 12B concat-phase compile) are refuted or de-prioritized;
|
|
169
|
+
its GPU-side fixes (26B gather-qmm bandwidth, e4b dispatch batching, CPM5
|
|
170
|
+
KV-path, backlog #4 contiguity, spec decode) are now the ENTIRE recoverable
|
|
171
|
+
gap and still compose with the backlog above.
|
|
@@ -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
|