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,235 @@
|
|
|
1
|
+
# TurboQuant KV — design (Phase 13)
|
|
2
|
+
|
|
3
|
+
Status: v1 wired end-to-end (2026-07-06): codec + `TurboQuantKVCache` +
|
|
4
|
+
`--kv-quant turbo[:k<bits>v<bits>]` (cli.ts, serve/generate/bench) +
|
|
5
|
+
`maybeQuantizeKv` conversion + `GenerationGateway` solo-only refusal +
|
|
6
|
+
`kv-store.ts` persistence + `scripts/eval-turboquant-curve.ts` (KL/ppl curve
|
|
7
|
+
script; not yet RUN against a real model — that's the next stage's gate).
|
|
8
|
+
Owner seam: L2 cache format, L1-unmodified attention (dequantize-on-fetch),
|
|
9
|
+
eval-gated. Opt-in only — naked default stays L1.
|
|
10
|
+
|
|
11
|
+
## What it is
|
|
12
|
+
|
|
13
|
+
Rotation-based KV-cache quantization: signed int8 affine keys + FWHT-rotated
|
|
14
|
+
3-bit Lloyd-Max values, per-32-group fp16 scales. More usable context at the
|
|
15
|
+
same memory (2.56× KV compression at the k8/v3 default, head_dim 128), NOT a
|
|
16
|
+
weight quantizer. Composes with (is orthogonal to) the per-layer mixed-KV
|
|
17
|
+
allocation axis — TurboQuant is the QUANTIZER axis (frontier plan §7.2).
|
|
18
|
+
|
|
19
|
+
## Oracle chain (decided 2026-07-06 from the research fan-out)
|
|
20
|
+
|
|
21
|
+
Two unrelated implementations share the name; do not conflate:
|
|
22
|
+
|
|
23
|
+
- **The paper** (arXiv:2504.19874, Google): dense QR random rotation, no
|
|
24
|
+
groups, no K/V asymmetry, optional QJL residual stage. It anchors the WHY
|
|
25
|
+
(rotate→Gaussian marginal→Lloyd-Max optimal; 4^-b distortion law) but not
|
|
26
|
+
the layout.
|
|
27
|
+
- **vllm-metal** (`vllm-project/vllm-metal`, `vllm_metal/attention/caches/
|
|
28
|
+
turboquant.py` + `kernels_v2/turboquant.metal`): the engineering variant.
|
|
29
|
+
optiq's `runtime/mtp/turboquant.py` config layer is lifted verbatim from it
|
|
30
|
+
(byte-identical `CENTROIDS_3BIT`, matching op signatures in optiq
|
|
31
|
+
`cache_state.py`). **This is our oracle** — "the oracle is whoever ships
|
|
32
|
+
it." Its Python reference functions are pure MLX; we vendor them and
|
|
33
|
+
generate bit-exact goldens with the oracle venv.
|
|
34
|
+
- mlx-vlm's 6.3k-line module is a THIRD design (whole-vector norms, MSE/Prod
|
|
35
|
+
codecs, keys rotated too) — noted, not our target. Its numeric test oracles
|
|
36
|
+
(MSE≈{0.36, 0.117, 0.03} at bits {1,2,3} on unit vectors) are still useful
|
|
37
|
+
sanity anchors for the rotation+Lloyd-Max math.
|
|
38
|
+
- vllm-metal's rendered docs page contradicts its own source (claims keys are
|
|
39
|
+
rotated; the code never rotates keys). Trust the source.
|
|
40
|
+
|
|
41
|
+
## Algorithm (vllm-metal reference semantics, exact)
|
|
42
|
+
|
|
43
|
+
Per token, per kv-head, groups of 32 along head_dim (head_dim ∈ {64,128,256,
|
|
44
|
+
512}, must divide by 32):
|
|
45
|
+
|
|
46
|
+
**Keys — NO rotation, asymmetric affine, per-32-group:**
|
|
47
|
+
- signed (q8_0/int8, bits=8): `max_val=127; scale=(max−min)/(2·max_val);
|
|
48
|
+
zero=round((max+min)/(2·scale)); idx=clip(round(x/scale − zero), −127, 127)`
|
|
49
|
+
stored as int8, one byte per element (no packing at 8 bits).
|
|
50
|
+
- unsigned (q5_0/q4_0/int2…): `max_val=2^bits−1; scale=(max−min)/max_val;
|
|
51
|
+
zero=round(min/scale); idx=clip(round(x/scale − zero), 0, max_val)`, packed.
|
|
52
|
+
- Dequant (both): `x̂=(idx+zero)·scale`. scale/zero fp16, one pair per group.
|
|
53
|
+
- Reference routes intermediates through fp16 (and deliberately drops the
|
|
54
|
+
+1e-8 scale epsilon because it underflows in fp16) — match the Python
|
|
55
|
+
reference's ACTUAL behavior, verified by goldens, not its comments.
|
|
56
|
+
|
|
57
|
+
**Values — FWHT + Lloyd-Max, per-32-group RMS scale:**
|
|
58
|
+
- `y = FWHT(x · signs)` where `signs ∈ {±1}^d` from `mx.random.randint(0,2,
|
|
59
|
+
(d,), key=mx.random.key(42))`, and FWHT normalizes by 1/√d.
|
|
60
|
+
- `scale = sqrt(mean(y²))` per 32-group (RMS, not min/max); `y_n = y/(scale+1e-8)`.
|
|
61
|
+
- `idx = searchsorted(BOUNDARIES, y_n)` — nearest centroid. 3-bit table:
|
|
62
|
+
centroids ±{0.24509, 0.75601, 1.34391, 2.15195}, boundaries ±{0.50055,
|
|
63
|
+
1.04996, 1.74793}, 0. Other bit-widths (2/4/5/8): iterative Lloyd-Max on a
|
|
64
|
+
unit normal — we generate those tables ONCE from the vendored reference and
|
|
65
|
+
hardcode them (parity by construction; no runtime iteration).
|
|
66
|
+
- Pack: flat little-endian bitstream, element i at bits [i·b, i·b+b), values
|
|
67
|
+
may straddle two bytes (3-bit: 8 values → 3 bytes).
|
|
68
|
+
- Dequant: `x̂ = InvFWHT(centroids[idx] · scale · signs⁻¹)` (inverse = apply
|
|
69
|
+
FWHT then multiply signs; Hadamard is an involution up to normalization).
|
|
70
|
+
|
|
71
|
+
**Per-token-per-head bytes (k8v3, d=128):** 128 (K int8) + 8+8 (K scale/zero)
|
|
72
|
+
+ 48 (V packed) + 8 (V scale) = 200 vs 512 bf16 → 2.56×. The centroid table is
|
|
73
|
+
a shared constant, not per-token. This reproduces optiq's `compression_ratio`.
|
|
74
|
+
|
|
75
|
+
**Sign vectors are hardcoded constants per head_dim** (64/128/256/512),
|
|
76
|
+
generated from the reference's key(42) — exactly what vllm-metal does in its
|
|
77
|
+
.metal source. Deterministic across machines and spill/restore.
|
|
78
|
+
|
|
79
|
+
## v1 architecture in mlx-bun
|
|
80
|
+
|
|
81
|
+
Dequantize-on-fetch: `TurboQuantKVCache implements Cache` (does NOT subclass
|
|
82
|
+
KVCache — that keeps it auto-excluded from batching), `updateAndFetch(k,v)`
|
|
83
|
+
quantizes the new tokens into packed storage and returns the dequantized bf16
|
|
84
|
+
active window, so the standard `ops.sdpa` path runs unmodified — the same
|
|
85
|
+
pattern optiq's `runtime/kv/rotating.py` uses for its v1. No generated-file
|
|
86
|
+
changes: a novel cache class fails every `#matches()` guard and falls back to
|
|
87
|
+
the monolith by design. Quantization groups run along head_dim only —
|
|
88
|
+
token-axis slicing stays byte-safe (standing invariant).
|
|
89
|
+
|
|
90
|
+
Files (from the codebase-map seams):
|
|
91
|
+
- `src/mlx/turboquant-ops.ts` — NEW: fwht (bind `mlx_hadamard_transform`,
|
|
92
|
+
confirmed exported by libmlxc), encode/decode keys + values, pack/unpack.
|
|
93
|
+
- `src/mlx/turboquant-tables.ts` — NEW, GENERATED by regen script: sign
|
|
94
|
+
vectors per head_dim + Lloyd-Max centroid/boundary tables per bit-width.
|
|
95
|
+
- `src/model/gemma4-base.ts` — NEW `TurboQuantKVCache` (full-attention only in
|
|
96
|
+
v1; rotating/sliding-window layers stay bf16 — documented limitation).
|
|
97
|
+
- `src/generate.ts` `maybeQuantizeKv()` — the single conversion chokepoint
|
|
98
|
+
(serve serial lane + generate + eval all flow through it); keep the
|
|
99
|
+
`offset===0` skip and `quantizedKvStart` semantics.
|
|
100
|
+
- `src/cli.ts` — `--kv-quant turbo[:k<bits>v<bits>]` (default k8v3).
|
|
101
|
+
- `src/serve/generation-gateway.ts` — explicit solo-only refusal (belt +
|
|
102
|
+
braces on top of the automatic instanceof exclusion).
|
|
103
|
+
- `src/kv-store.ts` — new `CacheKind "turboquant"`, branches in
|
|
104
|
+
snapshotCache/loadKvCache/cloneKvCaches; header carries kBits/vBits.
|
|
105
|
+
- `src/model/fingerprint.ts` — NOT touched, by design symmetry: uniform
|
|
106
|
+
`--kv-quant 4|8` is a CLI-only runtime lever that never feeds
|
|
107
|
+
`configFingerprint()` either (only the per-layer `kv_config.json` scheme
|
|
108
|
+
does); TurboQuant is the same class of lever, so it gets the same
|
|
109
|
+
non-treatment. The SSD-cache compat key (`server.ts`'s `schemeKey`) DOES
|
|
110
|
+
fold in the TurboQuant scheme directly (`turbo-k<bits>v<bits>`), same as it
|
|
111
|
+
already does for uniform bits — that's the actual anti-collision mechanism
|
|
112
|
+
for this class of scheme, not the fingerprint.
|
|
113
|
+
- Docs same-commit: server-config.md, cli.md, features-matrix.md.
|
|
114
|
+
- Tests: `tests/turboquant-ops.test.ts` (golden bit-exactness vs vendored
|
|
115
|
+
reference + model-free math props), `tests/turboquant-cache.test.ts` (cache
|
|
116
|
+
invariants, growth/trim, persistence roundtrip — synthetic arrays, no
|
|
117
|
+
model/golden dependency), `scripts/regen-turboquant-goldens.ts`.
|
|
118
|
+
- `scripts/eval-turboquant-curve.ts` — the Gate 3 quality-vs-bpw curve script:
|
|
119
|
+
bf16 baseline + {k8v8,k8v4,k8v3,k8v2,k4v3,k4v2} sequentially, reusing
|
|
120
|
+
`src/eval/kl.ts`'s `evaluateKlKvArm` (teacher-forced serving-decode KL,
|
|
121
|
+
real `TurboQuantKVCache.fromKVCache` conversion) and
|
|
122
|
+
`src/eval/perplexity.ts`'s `evalPpl` (bf16-forward anchor column).
|
|
123
|
+
Typechecks + `--help`/arg-parsing verified; not yet RUN against a real
|
|
124
|
+
model — that run (and reading the resulting curve against the paper's law)
|
|
125
|
+
is the next stage's job.
|
|
126
|
+
- Vendored reference: `lab/repro/vllm-metal-turboquant/` (their Python file +
|
|
127
|
+
provenance note), driven only by the regen script via the oracle venv.
|
|
128
|
+
|
|
129
|
+
## Gates — ALL PASSED 2026-07-06 (M1 Max 32 GB)
|
|
130
|
+
|
|
131
|
+
Gate 3 measured curve (MiniCPM5-1B, `scripts/eval-turboquant-curve.ts`,
|
|
132
|
+
teacher-forced serving-decode KL vs bf16, 8 prompts × 128 tokens, 32 decode
|
|
133
|
+
steps; affine baselines via the same `evaluateKlKvArm` harness):
|
|
134
|
+
|
|
135
|
+
| scheme | effective KV bits | mean KL vs bf16 |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| bf16 | 16.00 | 0 (control) |
|
|
138
|
+
| uniform kv8 (affine g64) | 8.50 | 0.00246 |
|
|
139
|
+
| turbo k8v8 | 8.75 | 0.00214 |
|
|
140
|
+
| turbo k8v4 | 6.75 | 0.00936 |
|
|
141
|
+
| **turbo k8v3 (default)** | **6.25** | **0.0325** |
|
|
142
|
+
| turbo k8v2 | 5.75 | 0.175 |
|
|
143
|
+
| uniform kv4 (affine g64) | 4.50 | 0.0516 |
|
|
144
|
+
| turbo k4v3 | 4.25 | 0.0622 |
|
|
145
|
+
| turbo k4v2 | 3.75 | 0.205 |
|
|
146
|
+
|
|
147
|
+
Shape reproduces the paper's law: value bits dominate, ~4^-b decay, cliff at
|
|
148
|
+
v2. Headline: turbo adds operating points between affine kv8/kv4 — the k8v3
|
|
149
|
+
default (2.56× KV compression) beats uniform kv4's KL with room to spare.
|
|
150
|
+
Live smokes: cpm5 + e4b generation coherent under turbo:k8v3 (e4b emits the
|
|
151
|
+
one-time rotating-layers-stay-bf16 warning). The paper's own LongBench
|
|
152
|
+
numbers were NOT rerun (different benchmark harness) — the reproduction is
|
|
153
|
+
shape-level plus the codec-level D_mse≈0.03 anchor, which our 3-bit
|
|
154
|
+
roundtrip test hits.
|
|
155
|
+
|
|
156
|
+
1. **Quantizer parity (bit-exact, the hard gate):** our encode indices,
|
|
157
|
+
scales, zeros, packed bytes, and dequant outputs match the vendored
|
|
158
|
+
vllm-metal Python reference on golden vectors (head_dim 64/128; configs
|
|
159
|
+
k8v3/k4v3/k4v2/k8v4/k2v5/k5v8 — spanning every kBits/vBits value the CLI
|
|
160
|
+
accepts, per the 2026-07-06 integration review). This is an oracle-backed
|
|
161
|
+
scheme at the codec level.
|
|
162
|
+
2. **Math sanity (model-free):** FWHT involution/orthogonality; roundtrip MSE
|
|
163
|
+
at 3-bit on unit-normal data ≈ paper's D_mse≈0.03 band.
|
|
164
|
+
3. **Quality-vs-bpw curve (Phase 13 exit criterion):** teacher-forced KL
|
|
165
|
+
(src/eval/kl.ts) + perplexity vs bf16 KV on MiniCPM5-1B (head_dim 128,
|
|
166
|
+
pure full-attention) across {k8v8, k8v4, k8v3, k8v2, k4v3, k4v2}; curve
|
|
167
|
+
shape must match the paper's law (≈quality-neutral ≥3.5 effective bits,
|
|
168
|
+
marginal degradation at 2.5, cliff below). e4b spot check second. Model
|
|
169
|
+
runs SEQUENTIAL (32 GB box rule).
|
|
170
|
+
4. Whole-repo `tsc --noEmit` = 0; fast suite green; no batching regression
|
|
171
|
+
(turbo requests route serial with a clear reason).
|
|
172
|
+
|
|
173
|
+
## Deferred inverse FWHT (LANDED 2026-07-06, post-v1, Josh-directed)
|
|
174
|
+
|
|
175
|
+
Attention is linear in V, so `InvFWHT(Σᵢ wᵢ·v̂ᵢ) = Σᵢ wᵢ·InvFWHT(v̂ᵢ)`:
|
|
176
|
+
`updateAndFetchDeferredV` returns the V window still in the rotated domain
|
|
177
|
+
and the attention site un-rotates the OUTPUT once per query row
|
|
178
|
+
(`tq.unrotateValues`) — O(q·d log d) per step instead of O(T·d log d).
|
|
179
|
+
Opt-in per attention site via `SharedKv.vRotated` (monolith gemma4.ts —
|
|
180
|
+
KV-shared consumer layers inherit the flag through sharedIn — and
|
|
181
|
+
minicpm5.ts); every other consumer keeps calling `updateAndFetch` (eager)
|
|
182
|
+
and stays correct. Not bit-identical to eager (bf16 rounding in the rotated
|
|
183
|
+
domain before the transform); measured k8v3 KL 0.0338 vs eager 0.0325 —
|
|
184
|
+
same quality. Paired fetch-path A/B on a LOADED M1 Max: never slower,
|
|
185
|
+
~10-20% off fetch cost at 4k ctx, noise-level at 8k (dequant gather
|
|
186
|
+
dominates both paths) — no speed claim until a quiet-machine benchmark.sh
|
|
187
|
+
run; the win is removing the O(T) transform, which matters more once the
|
|
188
|
+
gather itself is fused.
|
|
189
|
+
|
|
190
|
+
## Future: rotation-based WEIGHT quantization (noted 2026-07-06, Josh)
|
|
191
|
+
|
|
192
|
+
The same rotate-then-quantize mechanism applies to weights, and we already
|
|
193
|
+
ship a quantization tool (`convert`/`fuse` verbs) to hang it on — as a
|
|
194
|
+
further optimization of quantization itself, the quantizer leg of the §7.1
|
|
195
|
+
mixed-precision program (allocation × quantizer, same orthogonality as KV):
|
|
196
|
+
|
|
197
|
+
- Rotation smears outlier channels so a low-bit codebook covers the signal
|
|
198
|
+
mass — the QuaRot/SpinQuant family (both cited by the TurboQuant paper).
|
|
199
|
+
- Weights beat KV on one axis: the rotation FOLDS into adjacent weight
|
|
200
|
+
matrices offline (R into one layer, Rᵀ into the next) → zero runtime
|
|
201
|
+
cost, no online transform at all.
|
|
202
|
+
- Weights lose on the other: they're static, so calibration-aware methods
|
|
203
|
+
(GPTQ/AWQ/imatrix, optiq sensitivity maps) are admissible and set a
|
|
204
|
+
higher baseline than any calibration-free scheme — the win to chase is
|
|
205
|
+
rotation COMPOSED WITH calibration/allocation, not instead of it.
|
|
206
|
+
- A Lloyd-Max weight FORMAT needs custom quantized-matmul kernels — the
|
|
207
|
+
26B gather-qmv shelving (dispatch fixed-cost ate the prize) is the
|
|
208
|
+
cautionary precedent. Rotation-folding into mlx's EXISTING affine format
|
|
209
|
+
needs no new kernels and is the cheap first experiment.
|
|
210
|
+
- Activations (W4A4/QuaRot act-quant): more involved (online rotation,
|
|
211
|
+
fused kernels) and mispriced for this hardware — no int4 tensor cores,
|
|
212
|
+
decode is weight-bandwidth-bound. See w4a16-compute-precision-spike.md.
|
|
213
|
+
Not queued.
|
|
214
|
+
|
|
215
|
+
Gate when picked up: perplexity + frozen 6-task eval at equal bpw vs the
|
|
216
|
+
plain affine convert output (the §7.1 gate, eval DB rows).
|
|
217
|
+
|
|
218
|
+
## Non-goals for v1 (recorded so they don't creep)
|
|
219
|
+
|
|
220
|
+
- Fused quantized-SDPA Metal kernel (the remaining fetch cost is the
|
|
221
|
+
unpack+gather; deferred InvFWHT — see above — already landed).
|
|
222
|
+
- Rotating/sliding-window TurboQuant cache; batched TurboQuant; QJL residual
|
|
223
|
+
stage (Q_prod); entropy coding (paper explicitly declined it too).
|
|
224
|
+
- TurboQuant on the speculative lane: `--kv-quant turbo` + `--draft-model`
|
|
225
|
+
keeps the KV scheme — those requests decode serially WITHOUT speculation
|
|
226
|
+
(the spec loop is bf16-KV-only; excluded in the server's spec-eligibility
|
|
227
|
+
gate with a startup warning, 2026-07-07 review fix — turbo was previously
|
|
228
|
+
routed into the spec lane and silently dropped).
|
|
229
|
+
- Head dims beyond {64,128,256,512}: REFUSED AT SERVER START (2026-07-07
|
|
230
|
+
review fix — validation was lazy on the first cache append, so an
|
|
231
|
+
unsupported model 500'd every request mid-prefill; createServer now
|
|
232
|
+
checks the config's full-attention head dim against
|
|
233
|
+
TURBOQUANT_HEAD_DIMS, and the cache-level check stays as the backstop).
|
|
234
|
+
- Speed claims of any kind — v1 dequant-on-fetch is expected slower per-step
|
|
235
|
+
at long context; this ships as a memory/context feature like uniform KV.
|