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
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// GENERATED by scripts/regen-turboquant-goldens.ts — DO NOT EDIT.
|
|
2
|
+
// Regenerate: bun scripts/regen-turboquant-goldens.ts
|
|
3
|
+
//
|
|
4
|
+
// Source: lab/repro/vllm-metal-turboquant/turboquant_reference.py (vendored
|
|
5
|
+
// vllm-metal oracle, see PROVENANCE.md in that directory), executed under
|
|
6
|
+
// the oracle venv (mlx 0.31.2) via gen_goldens.py.
|
|
7
|
+
//
|
|
8
|
+
// - SIGN_VECTORS[headDim]: the fwht() sign table (±1), derived from
|
|
9
|
+
// mx.random.randint(0, 2, shape=(headDim,), key=mx.random.key(42)) —
|
|
10
|
+
// deterministic across machines and spill/restore by construction.
|
|
11
|
+
// - LLOYD_MAX[bits]: Lloyd-Max (centroids, boundaries) for value
|
|
12
|
+
// quantization at the given bit width. bits=3 is the vendored reference's
|
|
13
|
+
// hardcoded fast-path table (CENTROIDS_3BIT/BOUNDARIES_3BIT); other widths
|
|
14
|
+
// are the reference's own iterative Lloyd-Max fit on a unit-normal source
|
|
15
|
+
// (mx.random.normal(key=mx.random.key(0)), 500 iterations), computed once
|
|
16
|
+
// here and hardcoded — no runtime iteration in the TS port.
|
|
17
|
+
|
|
18
|
+
export const TURBOQUANT_HEAD_DIMS = [64, 128, 256, 512] as const;
|
|
19
|
+
export type TurboQuantHeadDim = (typeof TURBOQUANT_HEAD_DIMS)[number];
|
|
20
|
+
|
|
21
|
+
export const SIGN_VECTORS: Record<TurboQuantHeadDim, number[]> = {
|
|
22
|
+
64: [
|
|
23
|
+
1, -1, -1, -1, 1, 1, 1, -1, 1, 1,
|
|
24
|
+
-1, 1, -1, 1, -1, 1, -1, 1, 1, -1,
|
|
25
|
+
1, -1, -1, 1, -1, -1, -1, 1, -1, -1,
|
|
26
|
+
1, -1, 1, -1, 1, 1, 1, 1, 1, 1,
|
|
27
|
+
1, 1, 1, -1, 1, 1, -1, 1, 1, -1,
|
|
28
|
+
-1, -1, -1, 1, -1, -1, 1, -1, 1, 1,
|
|
29
|
+
1, -1, -1, 1,
|
|
30
|
+
],
|
|
31
|
+
128: [
|
|
32
|
+
-1, 1, -1, -1, 1, 1, 1, 1, -1, -1,
|
|
33
|
+
-1, -1, -1, 1, -1, -1, -1, 1, 1, -1,
|
|
34
|
+
-1, -1, 1, 1, 1, -1, 1, -1, 1, -1,
|
|
35
|
+
-1, 1, 1, 1, 1, 1, -1, 1, -1, 1,
|
|
36
|
+
1, -1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
37
|
+
-1, -1, -1, 1, 1, -1, 1, -1, 1, -1,
|
|
38
|
+
1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
|
|
39
|
+
-1, -1, -1, -1, -1, 1, -1, -1, 1, 1,
|
|
40
|
+
-1, -1, 1, 1, 1, 1, 1, -1, 1, -1,
|
|
41
|
+
1, -1, 1, 1, -1, 1, 1, -1, -1, -1,
|
|
42
|
+
-1, 1, -1, -1, -1, 1, 1, -1, -1, 1,
|
|
43
|
+
-1, 1, 1, 1, 1, 1, 1, -1, -1, 1,
|
|
44
|
+
1, 1, -1, 1, -1, 1, 1, 1,
|
|
45
|
+
],
|
|
46
|
+
256: [
|
|
47
|
+
1, -1, 1, 1, -1, 1, 1, 1, 1, 1,
|
|
48
|
+
1, 1, -1, -1, 1, 1, 1, -1, -1, 1,
|
|
49
|
+
1, -1, -1, -1, 1, -1, 1, 1, 1, -1,
|
|
50
|
+
-1, 1, -1, 1, 1, 1, -1, 1, 1, 1,
|
|
51
|
+
1, -1, 1, -1, 1, 1, -1, 1, -1, 1,
|
|
52
|
+
-1, -1, 1, 1, -1, -1, 1, 1, 1, 1,
|
|
53
|
+
-1, 1, 1, 1, -1, -1, -1, -1, 1, -1,
|
|
54
|
+
-1, 1, 1, 1, -1, 1, -1, 1, 1, 1,
|
|
55
|
+
-1, 1, -1, -1, 1, -1, -1, 1, -1, 1,
|
|
56
|
+
1, -1, 1, -1, 1, -1, -1, 1, 1, -1,
|
|
57
|
+
1, 1, -1, -1, 1, -1, -1, -1, -1, 1,
|
|
58
|
+
-1, 1, 1, 1, -1, -1, -1, 1, 1, -1,
|
|
59
|
+
-1, -1, 1, 1, -1, 1, -1, -1, -1, -1,
|
|
60
|
+
1, -1, -1, 1, 1, -1, 1, -1, 1, 1,
|
|
61
|
+
-1, -1, -1, -1, -1, -1, -1, -1, 1, -1,
|
|
62
|
+
1, 1, 1, -1, 1, -1, -1, -1, 1, 1,
|
|
63
|
+
-1, -1, 1, 1, -1, -1, -1, 1, -1, 1,
|
|
64
|
+
-1, -1, -1, 1, -1, 1, -1, -1, -1, 1,
|
|
65
|
+
1, -1, 1, 1, 1, -1, 1, 1, -1, -1,
|
|
66
|
+
1, -1, -1, -1, 1, -1, 1, -1, -1, 1,
|
|
67
|
+
-1, 1, 1, -1, -1, 1, -1, -1, 1, 1,
|
|
68
|
+
1, 1, -1, -1, 1, 1, -1, -1, -1, 1,
|
|
69
|
+
-1, 1, -1, 1, -1, -1, -1, 1, -1, 1,
|
|
70
|
+
-1, 1, -1, -1, 1, 1, 1, 1, -1, -1,
|
|
71
|
+
-1, -1, 1, -1, 1, 1, 1, -1, 1, -1,
|
|
72
|
+
-1, -1, -1, -1, -1, -1,
|
|
73
|
+
],
|
|
74
|
+
512: [
|
|
75
|
+
-1, 1, -1, -1, -1, -1, 1, -1, -1, -1,
|
|
76
|
+
1, -1, 1, 1, -1, 1, 1, -1, -1, 1,
|
|
77
|
+
-1, -1, 1, 1, 1, 1, 1, 1, -1, -1,
|
|
78
|
+
-1, 1, -1, 1, -1, -1, 1, 1, 1, 1,
|
|
79
|
+
-1, -1, 1, 1, 1, -1, -1, -1, -1, -1,
|
|
80
|
+
1, -1, -1, -1, -1, -1, 1, -1, 1, 1,
|
|
81
|
+
1, -1, -1, 1, -1, -1, 1, 1, 1, -1,
|
|
82
|
+
-1, 1, 1, 1, -1, 1, 1, -1, -1, -1,
|
|
83
|
+
-1, 1, 1, -1, -1, -1, 1, 1, 1, 1,
|
|
84
|
+
-1, 1, -1, 1, -1, -1, -1, 1, 1, 1,
|
|
85
|
+
1, -1, -1, 1, 1, -1, 1, 1, -1, 1,
|
|
86
|
+
-1, -1, 1, -1, 1, -1, 1, 1, -1, -1,
|
|
87
|
+
1, 1, -1, -1, -1, 1, -1, 1, -1, -1,
|
|
88
|
+
-1, -1, 1, 1, 1, -1, 1, 1, -1, -1,
|
|
89
|
+
-1, -1, -1, 1, -1, -1, -1, 1, 1, 1,
|
|
90
|
+
-1, 1, -1, -1, 1, -1, -1, 1, 1, -1,
|
|
91
|
+
-1, -1, 1, 1, 1, 1, -1, 1, 1, -1,
|
|
92
|
+
1, 1, -1, 1, 1, 1, -1, 1, -1, -1,
|
|
93
|
+
-1, 1, -1, -1, -1, 1, 1, -1, 1, -1,
|
|
94
|
+
-1, -1, 1, 1, 1, 1, -1, -1, 1, 1,
|
|
95
|
+
1, -1, -1, -1, -1, 1, -1, -1, 1, -1,
|
|
96
|
+
1, -1, 1, -1, 1, 1, 1, 1, -1, 1,
|
|
97
|
+
-1, 1, -1, 1, 1, -1, 1, -1, -1, -1,
|
|
98
|
+
1, -1, 1, -1, 1, -1, 1, 1, -1, -1,
|
|
99
|
+
1, -1, 1, -1, -1, -1, 1, -1, -1, -1,
|
|
100
|
+
-1, 1, -1, -1, -1, 1, 1, 1, -1, 1,
|
|
101
|
+
1, 1, 1, -1, 1, -1, -1, -1, -1, -1,
|
|
102
|
+
1, 1, -1, -1, -1, 1, 1, 1, 1, -1,
|
|
103
|
+
-1, 1, 1, 1, -1, 1, 1, 1, 1, 1,
|
|
104
|
+
1, -1, -1, 1, 1, 1, -1, 1, -1, 1,
|
|
105
|
+
-1, 1, 1, 1, 1, 1, -1, -1, 1, 1,
|
|
106
|
+
-1, 1, 1, -1, 1, -1, -1, 1, 1, -1,
|
|
107
|
+
-1, 1, -1, 1, 1, 1, -1, -1, -1, -1,
|
|
108
|
+
1, 1, 1, -1, 1, -1, 1, 1, -1, 1,
|
|
109
|
+
1, 1, 1, 1, 1, -1, 1, 1, -1, -1,
|
|
110
|
+
1, 1, -1, -1, -1, -1, -1, 1, 1, 1,
|
|
111
|
+
1, -1, 1, 1, -1, -1, -1, 1, -1, 1,
|
|
112
|
+
1, 1, 1, 1, 1, -1, -1, 1, -1, -1,
|
|
113
|
+
-1, 1, -1, 1, 1, -1, 1, 1, -1, 1,
|
|
114
|
+
-1, 1, 1, 1, -1, 1, -1, 1, 1, 1,
|
|
115
|
+
1, -1, 1, 1, 1, 1, 1, -1, 1, -1,
|
|
116
|
+
1, -1, 1, 1, 1, -1, 1, -1, 1, 1,
|
|
117
|
+
1, 1, -1, -1, -1, -1, 1, -1, -1, 1,
|
|
118
|
+
1, -1, -1, -1, -1, 1, 1, -1, 1, -1,
|
|
119
|
+
1, -1, -1, -1, 1, 1, 1, -1, -1, -1,
|
|
120
|
+
-1, -1, 1, -1, -1, -1, -1, -1, 1, -1,
|
|
121
|
+
1, 1, -1, 1, 1, -1, -1, -1, 1, 1,
|
|
122
|
+
1, 1, 1, -1, 1, 1, -1, 1, -1, 1,
|
|
123
|
+
-1, 1, -1, -1, 1, -1, -1, 1, -1, 1,
|
|
124
|
+
-1, -1, -1, 1, 1, -1, -1, -1, 1, -1,
|
|
125
|
+
1, -1, -1, 1, -1, 1, 1, -1, 1, -1,
|
|
126
|
+
1, 1,
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const TURBOQUANT_VALUE_BITS = [2, 3, 4, 5, 8] as const;
|
|
131
|
+
export type TurboQuantValueBits = (typeof TURBOQUANT_VALUE_BITS)[number];
|
|
132
|
+
|
|
133
|
+
export interface LloydMaxTable {
|
|
134
|
+
centroids: number[];
|
|
135
|
+
boundaries: number[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const LLOYD_MAX: Record<TurboQuantValueBits, LloydMaxTable> = {
|
|
139
|
+
2: {
|
|
140
|
+
centroids: [
|
|
141
|
+
-1.5144749879837036, -0.45822522044181824, 0.44863229990005493, 1.512152075767517,
|
|
142
|
+
],
|
|
143
|
+
boundaries: [
|
|
144
|
+
-0.9863501191139221, -0.004796460270881653, 0.9803922176361084,
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
3: {
|
|
148
|
+
centroids: [
|
|
149
|
+
-2.151949882507324, -1.3439099788665771, -0.7560099959373474, -0.24508999288082123, 0.24508999288082123, 0.7560099959373474, 1.3439099788665771, 2.151949882507324,
|
|
150
|
+
],
|
|
151
|
+
boundaries: [
|
|
152
|
+
-1.7479300498962402, -1.0499600172042847, -0.5005499720573425, 0, 0.5005499720573425, 1.0499600172042847, 1.7479300498962402,
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
4: {
|
|
156
|
+
centroids: [
|
|
157
|
+
-2.765662670135498, -2.0995230674743652, -1.6401931047439575, -1.27662992477417, -0.9602491855621338, -0.673130452632904, -0.4038185179233551, -0.14272712171077728, 0.11716290563344955, 0.3790881633758545,
|
|
158
|
+
0.6475776433944702, 0.9337777495384216, 1.2523075342178345, 1.6217625141143799, 2.0757482051849365, 2.7207279205322266,
|
|
159
|
+
],
|
|
160
|
+
boundaries: [
|
|
161
|
+
-2.4325928688049316, -1.8698580265045166, -1.458411455154419, -1.1184395551681519, -0.8166898488998413, -0.5384745001792908, -0.2732728123664856, -0.012782108038663864, 0.24812553822994232, 0.5133329033851624,
|
|
162
|
+
0.7906776666641235, 1.0930426120758057, 1.437035083770752, 1.8487553596496582, 2.398238182067871,
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
5: {
|
|
166
|
+
centroids: [
|
|
167
|
+
-3.3482043743133545, -2.7744688987731934, -2.3917815685272217, -2.0885653495788574, -1.8382762670516968, -1.6273508071899414, -1.436827301979065, -1.2599420547485352, -1.0958681106567383, -0.9411738514900208,
|
|
168
|
+
-0.7932286262512207, -0.6509044766426086, -0.5113211274147034, -0.37372007966041565, -0.23732160031795502, -0.10278966277837753, 0.031794287264347076, 0.16419854760169983, 0.3001006245613098, 0.4395425021648407,
|
|
169
|
+
0.5808256268501282, 0.7275802493095398, 0.8738965392112732, 1.029397964477539, 1.1942607164382935, 1.3728704452514648, 1.5676456689834595, 1.778881311416626, 2.0225136280059814, 2.3095157146453857,
|
|
170
|
+
2.666351556777954, 3.2329483032226562,
|
|
171
|
+
],
|
|
172
|
+
boundaries: [
|
|
173
|
+
-3.0613365173339844, -2.583125114440918, -2.24017333984375, -1.9634208679199219, -1.7328135967254639, -1.5320889949798584, -1.3483846187591553, -1.1779050827026367, -1.0185209512710571, -0.8672012090682983,
|
|
174
|
+
-0.7220665216445923, -0.581112802028656, -0.4425206184387207, -0.30552083253860474, -0.17005562782287598, -0.03549768775701523, 0.09799641370773315, 0.23214958608150482, 0.36982154846191406, 0.5101840496063232,
|
|
175
|
+
0.654202938079834, 0.8007383942604065, 0.9516472816467285, 1.1118292808532715, 1.2835655212402344, 1.4702579975128174, 1.6732635498046875, 1.9006974697113037, 2.1660146713256836, 2.48793363571167,
|
|
176
|
+
2.9496498107910156,
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
8: {
|
|
180
|
+
centroids: [
|
|
181
|
+
-4.505678653717041, -4.454618453979492, -4.436285972595215, -4.401589393615723, -4.363239765167236, -4.332197189331055, -4.2975006103515625, -4.26280403137207, -4.228107929229736, -4.193411827087402,
|
|
182
|
+
-4.15871524810791, -4.124018669128418, -4.094437599182129, -4.045758247375488, -4.002621173858643, -4.002171516418457, -3.942392110824585, -3.916801691055298, -3.8863255977630615, -3.8477535247802734,
|
|
183
|
+
-3.7988643646240234, -3.762794256210327, -3.7445151805877686, -3.706960439682007, -3.67462158203125, -3.6314854621887207, -3.5950119495391846, -3.580256938934326, -3.539952516555786, -3.5038421154022217,
|
|
184
|
+
-3.4671568870544434, -3.4281671047210693, -3.398128032684326, -3.363133192062378, -3.3274667263031006, -3.2919743061065674, -3.2577857971191406, -3.2200968265533447, -3.192981719970703, -3.157238006591797,
|
|
185
|
+
-3.111802577972412, -3.0821340084075928, -3.050640344619751, -3.0148110389709473, -2.980158805847168, -2.946451425552368, -2.9111905097961426, -2.8747212886810303, -2.8412270545959473, -2.8061022758483887,
|
|
186
|
+
-2.7716867923736572, -2.7376010417938232, -2.7029218673706055, -2.6634461879730225, -2.630377769470215, -2.5996179580688477, -2.560898780822754, -2.525275230407715, -2.4947545528411865, -2.461374044418335,
|
|
187
|
+
-2.424009323120117, -2.3877711296081543, -2.3505144119262695, -2.3163986206054688, -2.282374858856201, -2.243652820587158, -2.2097959518432617, -2.1770639419555664, -2.14471697807312, -2.1113693714141846,
|
|
188
|
+
-2.078673839569092, -2.044494390487671, -2.00639271736145, -1.969869613647461, -1.9300988912582397, -1.8931699991226196, -1.8589746952056885, -1.8212106227874756, -1.7848811149597168, -1.7465486526489258,
|
|
189
|
+
-1.7103406190872192, -1.6743196249008179, -1.6393754482269287, -1.6040517091751099, -1.5708216428756714, -1.5365480184555054, -1.5035663843154907, -1.469175100326538, -1.4350656270980835, -1.4022008180618286,
|
|
190
|
+
-1.3688998222351074, -1.3355891704559326, -1.3018449544906616, -1.2698367834091187, -1.235532283782959, -1.20119047164917, -1.1664694547653198, -1.1305049657821655, -1.0959333181381226, -1.0614327192306519,
|
|
191
|
+
-1.0274933576583862, -0.9940271377563477, -0.9609262347221375, -0.9273853898048401, -0.8929082751274109, -0.8593462705612183, -0.8261474967002869, -0.7937442660331726, -0.7588282823562622, -0.7230017185211182,
|
|
192
|
+
-0.6871297359466553, -0.6517745852470398, -0.6162516474723816, -0.5811514854431152, -0.5462668538093567, -0.5111281275749207, -0.4750610589981079, -0.4394458830356598, -0.404982328414917, -0.36981964111328125,
|
|
193
|
+
-0.334137886762619, -0.29919183254241943, -0.26465246081352234, -0.23168867826461792, -0.20013625919818878, -0.1672147512435913, -0.13413792848587036, -0.1003282368183136, -0.06571532040834427, -0.03132394701242447,
|
|
194
|
+
0.0043428270146250725, 0.04037246108055115, 0.07451506704092026, 0.1076153963804245, 0.14043505489826202, 0.17426857352256775, 0.20812825858592987, 0.2430444061756134, 0.27797263860702515, 0.31494686007499695,
|
|
195
|
+
0.35088568925857544, 0.38743987679481506, 0.4222983717918396, 0.4568648338317871, 0.49128350615501404, 0.5256633758544922, 0.5586227178573608, 0.5910427570343018, 0.6249552369117737, 0.6594945788383484,
|
|
196
|
+
0.6942835450172424, 0.7278474569320679, 0.7624561786651611, 0.7963849902153015, 0.8309887647628784, 0.8644483685493469, 0.8981063961982727, 0.9320245385169983, 0.96662437915802, 1.0006996393203735,
|
|
197
|
+
1.0343793630599976, 1.0680633783340454, 1.101860523223877, 1.135563611984253, 1.1707100868225098, 1.2038687467575073, 1.2388564348220825, 1.2744282484054565, 1.3102103471755981, 1.3441187143325806,
|
|
198
|
+
1.3769688606262207, 1.4091657400131226, 1.4424594640731812, 1.477047085762024, 1.5127589702606201, 1.5482075214385986, 1.58390474319458, 1.6193201541900635, 1.655400037765503, 1.6924738883972168,
|
|
199
|
+
1.7273176908493042, 1.7618744373321533, 1.7985631227493286, 1.8349602222442627, 1.871187686920166, 1.9062069654464722, 1.9427249431610107, 1.9807021617889404, 2.0164709091186523, 2.049800395965576,
|
|
200
|
+
2.083641529083252, 2.1192877292633057, 2.1556057929992676, 2.189804792404175, 2.2249133586883545, 2.257265329360962, 2.2943572998046875, 2.3308892250061035, 2.3646092414855957, 2.3981246948242188,
|
|
201
|
+
2.4336130619049072, 2.4672765731811523, 2.5033960342407227, 2.535766124725342, 2.5712199211120605, 2.606968879699707, 2.6403279304504395, 2.6730761528015137, 2.7094709873199463, 2.745285749435425,
|
|
202
|
+
2.7794594764709473, 2.8145666122436523, 2.851815938949585, 2.885251045227051, 2.919672727584839, 2.9549803733825684, 2.987560510635376, 3.021491289138794, 3.061659097671509, 3.102267026901245,
|
|
203
|
+
3.1455001831054688, 3.1724164485931396, 3.2052037715911865, 3.2377841472625732, 3.2674646377563477, 3.3014495372772217, 3.3345274925231934, 3.3695874214172363, 3.4068915843963623, 3.442040205001831,
|
|
204
|
+
3.4636645317077637, 3.5024828910827637, 3.5508108139038086, 3.5749337673187256, 3.604726791381836, 3.6401684284210205, 3.692674160003662, 3.7173542976379395, 3.7488019466400146, 3.7978620529174805,
|
|
205
|
+
3.8167099952697754, 3.856578826904297, 3.890836000442505, 3.9217264652252197, 3.974006175994873, 4.009003639221191, 4.029621601104736, 4.079561233520508, 4.099013805389404, 4.1337103843688965,
|
|
206
|
+
4.172705173492432, 4.198393821716309, 4.237799167633057, 4.272495746612549, 4.307192325592041, 4.341888427734375,
|
|
207
|
+
],
|
|
208
|
+
boundaries: [
|
|
209
|
+
-4.4801483154296875, -4.4454522132873535, -4.418937683105469, -4.382414817810059, -4.347718238830566, -4.314848899841309, -4.280152320861816, -4.245455741882324, -4.210760116577148, -4.176063537597656,
|
|
210
|
+
-4.141366958618164, -4.109228134155273, -4.070097923278809, -4.0241899490356445, -4.002396583557129, -3.9722819328308105, -3.9295969009399414, -3.9015636444091797, -3.867039680480957, -3.8233089447021484,
|
|
211
|
+
-3.780829429626465, -3.753654718399048, -3.7257378101348877, -3.690791130065918, -3.6530535221099854, -3.613248825073242, -3.587634563446045, -3.5601048469543457, -3.521897315979004, -3.485499382019043,
|
|
212
|
+
-3.447661876678467, -3.413147449493408, -3.3806304931640625, -3.3452999591827393, -3.309720516204834, -3.2748799324035645, -3.238941192626953, -3.2065391540527344, -3.17510986328125, -3.1345202922821045,
|
|
213
|
+
-3.096968173980713, -3.066387176513672, -3.0327258110046387, -2.9974849224090576, -2.9633049964904785, -2.928821086883545, -2.892955780029297, -2.857974052429199, -2.823664665222168, -2.7888946533203125,
|
|
214
|
+
-2.7546439170837402, -2.720261573791504, -2.6831841468811035, -2.646912097930908, -2.6149978637695312, -2.580258369445801, -2.5430870056152344, -2.5100150108337402, -2.4780642986297607, -2.4426918029785156,
|
|
215
|
+
-2.4058902263641357, -2.369142770767212, -2.333456516265869, -2.299386739730835, -2.2630138397216797, -2.22672438621521, -2.193429946899414, -2.160890579223633, -2.1280431747436523, -2.0950217247009277,
|
|
216
|
+
-2.061583995819092, -2.0254435539245605, -1.9881311655044556, -1.9499843120574951, -1.9116344451904297, -1.8760724067687988, -1.840092658996582, -1.8030458688735962, -1.7657148838043213, -1.7284445762634277,
|
|
217
|
+
-1.6923301219940186, -1.6568474769592285, -1.621713638305664, -1.5874366760253906, -1.5536848306655884, -1.520057201385498, -1.4863708019256592, -1.452120304107666, -1.418633222579956, -1.3855502605438232,
|
|
218
|
+
-1.35224449634552, -1.3187170028686523, -1.2858408689498901, -1.2526845932006836, -1.2183613777160645, -1.1838300228118896, -1.1484872102737427, -1.113219141960144, -1.0786830186843872, -1.044463038444519,
|
|
219
|
+
-1.0107603073120117, -0.9774767160415649, -0.9441558122634888, -0.9101468324661255, -0.8761272430419922, -0.8427468538284302, -0.8099458813667297, -0.776286244392395, -0.7409150004386902, -0.7050657272338867,
|
|
220
|
+
-0.6694521903991699, -0.6340131163597107, -0.5987015962600708, -0.5637091398239136, -0.5286974906921387, -0.4930945932865143, -0.45725345611572266, -0.4222140908241272, -0.3874009847640991, -0.35197877883911133,
|
|
221
|
+
-0.3166648745536804, -0.2819221615791321, -0.24817056953907013, -0.21591246128082275, -0.18367549777030945, -0.15067633986473083, -0.11723308265209198, -0.08302177488803864, -0.04851963371038437, -0.013490559533238411,
|
|
222
|
+
0.022357644513249397, 0.0574437640607357, 0.09106522798538208, 0.12402522563934326, 0.15735182166099548, 0.1911984086036682, 0.22558632493019104, 0.26050853729248047, 0.29645973443984985, 0.332916259765625,
|
|
223
|
+
0.36916279792785645, 0.4048691391944885, 0.43958160281181335, 0.47407418489456177, 0.5084734559059143, 0.5421430468559265, 0.5748327374458313, 0.6079989671707153, 0.642224907875061, 0.6768890619277954,
|
|
224
|
+
0.7110655307769775, 0.7451518177986145, 0.7794206142425537, 0.8136868476867676, 0.8477185964584351, 0.8812773823738098, 0.9150654673576355, 0.9493244886398315, 0.9836620092391968, 1.0175395011901855,
|
|
225
|
+
1.0512213706970215, 1.0849618911743164, 1.118712067604065, 1.1531368494033813, 1.1872894763946533, 1.221362590789795, 1.2566423416137695, 1.2923192977905273, 1.3271645307540894, 1.3605437278747559,
|
|
226
|
+
1.3930673599243164, 1.4258126020431519, 1.4597532749176025, 1.4949030876159668, 1.5304832458496094, 1.5660561323165894, 1.6016124486923218, 1.6373600959777832, 1.6739369630813599, 1.7098958492279053,
|
|
227
|
+
1.744596004486084, 1.7802188396453857, 1.8167617321014404, 1.8530739545822144, 1.8886973857879639, 1.9244658946990967, 1.9617135524749756, 1.9985865354537964, 2.0331356525421143, 2.066720962524414,
|
|
228
|
+
2.1014647483825684, 2.137446880340576, 2.1727051734924316, 2.2073590755462646, 2.241089344024658, 2.275811195373535, 2.3126232624053955, 2.3477492332458496, 2.3813669681549072, 2.4158687591552734,
|
|
229
|
+
2.4504446983337402, 2.4853363037109375, 2.5195810794830322, 2.553493022918701, 2.589094400405884, 2.6236484050750732, 2.6567020416259766, 2.6912736892700195, 2.7273783683776855, 2.7623724937438965,
|
|
230
|
+
2.7970130443573, 2.833191394805908, 2.8685336112976074, 2.9024620056152344, 2.937326431274414, 2.9712705612182617, 3.004525899887085, 3.0415751934051514, 3.081963062286377, 3.1238837242126465,
|
|
231
|
+
3.1589584350585938, 3.188810110092163, 3.22149395942688, 3.25262451171875, 3.284457206726074, 3.317988395690918, 3.352057456970215, 3.3882393836975098, 3.4244658946990967, 3.452852249145508,
|
|
232
|
+
3.4830737113952637, 3.526646852493286, 3.5628724098205566, 3.5898303985595703, 3.6224474906921387, 3.666421413421631, 3.705014228820801, 3.7330780029296875, 3.773332118988037, 3.807286024093628,
|
|
233
|
+
3.836644411087036, 3.8737072944641113, 3.9062812328338623, 3.947866439819336, 3.9915049076080322, 4.019312858581543, 4.054591178894043, 4.089287757873535, 4.11636209487915, 4.153207778930664,
|
|
234
|
+
4.185549736022949, 4.218096733093262, 4.255147457122803, 4.289844036102295, 4.324540138244629,
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
};
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { MlxArray } from "../mlx/array";
|
|
19
19
|
import * as ops from "../mlx/ops";
|
|
20
|
-
import { createCausalMask, type Cache, type Mask } from "./gemma4-base";
|
|
20
|
+
import { createCausalMask, KVCache, type Cache, type Mask } from "./gemma4-base";
|
|
21
21
|
|
|
22
22
|
/** Padding-aware key-validity mask for batched DECODE with left-padded rows.
|
|
23
23
|
*
|
|
@@ -190,6 +190,67 @@ export function mergeKVRows(
|
|
|
190
190
|
return { keys, values, leftPad, width };
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/** mlx-lm `BatchKVCache.extend`: append ONE new right-justified row to an
|
|
194
|
+
* existing batched [B,H,S,D] buffer WITHOUT re-extracting the running rows
|
|
195
|
+
* (the O(B·S) slice storm mergeKVRows pays on a join). Pad whichever side
|
|
196
|
+
* is narrower on the LEFT to the common width, then a single B-axis concat.
|
|
197
|
+
* Existing rows' left-pads grow by the batch-side pad (they never shrink —
|
|
198
|
+
* mlx-lm extend semantics; the decode mask covers pads either way).
|
|
199
|
+
* Caller owns the result; inputs are not disposed. */
|
|
200
|
+
export function extendKVRows(
|
|
201
|
+
keys: MlxArray, values: MlxArray, leftPad: number[],
|
|
202
|
+
row: { keys: MlxArray; values: MlxArray },
|
|
203
|
+
): { keys: MlxArray; values: MlxArray; leftPad: number[]; width: number } {
|
|
204
|
+
const S = keys.shape[2]!;
|
|
205
|
+
const Lr = row.keys.shape[2]!;
|
|
206
|
+
const width = Math.max(S, Lr);
|
|
207
|
+
const padTo = (a: MlxArray, pad: number): MlxArray => {
|
|
208
|
+
if (pad === 0) return a.slice([0, 0, 0, 0], a.shape as number[]); // fresh full view
|
|
209
|
+
const [B, H, , D] = a.shape as [number, number, number, number];
|
|
210
|
+
const z = ops.zeros([B, H, pad, D], a.dtype);
|
|
211
|
+
const out = ops.concatAxis([z, a], 2);
|
|
212
|
+
z.dispose();
|
|
213
|
+
return out;
|
|
214
|
+
};
|
|
215
|
+
const bk = padTo(keys, width - S);
|
|
216
|
+
const bv = padTo(values, width - S);
|
|
217
|
+
const rk = padTo(row.keys, width - Lr);
|
|
218
|
+
const rv = padTo(row.values, width - Lr);
|
|
219
|
+
const outK = ops.concatAxis([bk, rk], 0);
|
|
220
|
+
const outV = ops.concatAxis([bv, rv], 0);
|
|
221
|
+
for (const a of [bk, bv, rk, rv]) a.dispose();
|
|
222
|
+
return {
|
|
223
|
+
keys: outK,
|
|
224
|
+
values: outV,
|
|
225
|
+
leftPad: [...leftPad.map((p) => p + (width - S)), width - Lr],
|
|
226
|
+
width,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** mlx-lm `BatchKVCache.extract` (models/cache.py:1080): pull row `i` out of
|
|
231
|
+
* a batched full-attention cache into a fresh SERIAL KVCache — the row slice
|
|
232
|
+
* past its left padding, materialized as an OWNED contiguous copy (extraction
|
|
233
|
+
* outlives the batch; the source buffers are about to be filter()ed or
|
|
234
|
+
* disposed). `leftPad` is the scheduler's per-row padding for this row (full
|
|
235
|
+
* layers share one offset; the scheduler owns the pad list). Bit-exact vs a
|
|
236
|
+
* solo run by construction: merge/extend/filter are byte-preserving per row
|
|
237
|
+
* (tests/batched-decode-parity, tests/batched-extract) and this is a pure
|
|
238
|
+
* slice+copy of those bytes. Off the hot decode path. */
|
|
239
|
+
export function extractKVRow(cache: KVCache, leftPad: number, i: number): KVCache {
|
|
240
|
+
if (!cache.keys || !cache.values) throw new Error("extractKVRow: empty cache");
|
|
241
|
+
const S = cache.offset; // valid columns (buffer may be STEP-padded past it)
|
|
242
|
+
const cut = (a: MlxArray): MlxArray => {
|
|
243
|
+
const [, H, , D] = a.shape as [number, number, number, number];
|
|
244
|
+
const view = a.slice([i, 0, leftPad, 0], [i + 1, H, S, D]);
|
|
245
|
+
const own = ops.contiguous(view);
|
|
246
|
+
view.dispose();
|
|
247
|
+
return own;
|
|
248
|
+
};
|
|
249
|
+
const out = new KVCache();
|
|
250
|
+
out.restoreState(cut(cache.keys), cut(cache.values), S - leftPad);
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
|
|
193
254
|
/** mlx-lm `filter`: keep only `keep` (sorted row indices) along the batch
|
|
194
255
|
* axis — eviction of finished sequences from a batched [B,H,S,D] buffer.
|
|
195
256
|
* Caller owns the result; inputs are not disposed. */
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// Batched QUANTIZED KV for continuous batching (Phase 3.1 of
|
|
2
|
+
// docs/design/unified-engine-frontier-plan.md) — the quantized twins of
|
|
3
|
+
// batched-mask.ts's dynamic-B ops, over (packed, scales, biases) triples.
|
|
4
|
+
//
|
|
5
|
+
// Why this is safe surgery: mlx quantization packs along HEAD_DIM (the last
|
|
6
|
+
// axis; packed last-dim = D/(32/bits), scales/biases last-dim = D/groupSize),
|
|
7
|
+
// so the TOKEN axis (axis 2) stays token-granular in all three tensors —
|
|
8
|
+
// left-padding, concat, and row-filter at token granularity never touch a
|
|
9
|
+
// quantization group. Pad columns hold zeros; they are never attended (the
|
|
10
|
+
// padding mask covers them) and never dequantized into anything a real row
|
|
11
|
+
// reads. QuantizedKVCache.updateAndFetchQuantized already handles arbitrary
|
|
12
|
+
// starting widths (it trims to `offset` and regrows in STEP chunks), so a
|
|
13
|
+
// merged exact-width buffer needs no STEP alignment here.
|
|
14
|
+
//
|
|
15
|
+
// Composition contract (the L2 oracle binds per ROW): each joiner solo-
|
|
16
|
+
// prefills with the SAME per-layer conversion the serial path runs
|
|
17
|
+
// (maybeQuantizeKv at chunk boundaries — see BatchScheduler.#quantizeSolo),
|
|
18
|
+
// so a row's quantized bytes are bit-exact vs serial `--kv-quant config` by
|
|
19
|
+
// construction; this module only re-arranges those bytes across the batch
|
|
20
|
+
// axis. Gates: tests/batched-kv-quant-parity.test.ts.
|
|
21
|
+
|
|
22
|
+
import { MlxArray } from "../mlx/array";
|
|
23
|
+
import * as ops from "../mlx/ops";
|
|
24
|
+
import { QuantizedKVCache, type Mask } from "./gemma4-base";
|
|
25
|
+
import { buildBatchedDecodeMask } from "./batched-mask";
|
|
26
|
+
|
|
27
|
+
export interface QuantRow {
|
|
28
|
+
keys: ops.QuantizedTensor;
|
|
29
|
+
values: ops.QuantizedTensor;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const disposeTriple = (t: ops.QuantizedTensor): void => {
|
|
33
|
+
t.packed.dispose();
|
|
34
|
+
t.scales.dispose();
|
|
35
|
+
t.biases.dispose();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Apply an MlxArray op to each member of a triple. Each tensor keeps its
|
|
39
|
+
* OWN last-dim (packed vs scales/biases differ) — helpers must never share
|
|
40
|
+
* one `D` across the triple (recon hazard, 2026-07-05). */
|
|
41
|
+
const tripleMap = (
|
|
42
|
+
t: ops.QuantizedTensor, f: (a: MlxArray) => MlxArray,
|
|
43
|
+
): ops.QuantizedTensor => ({ packed: f(t.packed), scales: f(t.scales), biases: f(t.biases) });
|
|
44
|
+
|
|
45
|
+
/** Left-pad one tensor of a triple by `pad` tokens (axis 2) with zeros of
|
|
46
|
+
* its own dtype/last-dim. pad=0 returns a fresh full view (mirrors
|
|
47
|
+
* batched-mask.ts leftPadTo so ownership is uniform). */
|
|
48
|
+
const leftPadTo = (a: MlxArray, pad: number): MlxArray => {
|
|
49
|
+
if (pad === 0) return a.slice([0, 0, 0, 0], a.shape as number[]);
|
|
50
|
+
const [B, H, , D] = a.shape as [number, number, number, number];
|
|
51
|
+
const z = ops.zeros([B, H, pad, D], a.dtype);
|
|
52
|
+
const out = ops.concatAxis([z, a], 2);
|
|
53
|
+
z.dispose();
|
|
54
|
+
return out;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Quantized twin of mergeKVRows: stack N single-row quantized KV slices
|
|
58
|
+
* into one left-padded [B,H,Smax,*] triple pair. Caller owns the result;
|
|
59
|
+
* input rows are not disposed. */
|
|
60
|
+
export function mergeQuantRows(rows: QuantRow[]): {
|
|
61
|
+
keys: ops.QuantizedTensor; values: ops.QuantizedTensor; leftPad: number[]; width: number;
|
|
62
|
+
} {
|
|
63
|
+
const lens = rows.map((r) => r.keys.packed.shape[2]!);
|
|
64
|
+
const width = Math.max(...lens);
|
|
65
|
+
const leftPad = lens.map((l) => width - l);
|
|
66
|
+
const padded = rows.map((r, i) => ({
|
|
67
|
+
keys: tripleMap(r.keys, (a) => leftPadTo(a, leftPad[i]!)),
|
|
68
|
+
values: tripleMap(r.values, (a) => leftPadTo(a, leftPad[i]!)),
|
|
69
|
+
}));
|
|
70
|
+
const cat = (pick: (r: QuantRow) => ops.QuantizedTensor): ops.QuantizedTensor => ({
|
|
71
|
+
packed: ops.concatAxis(padded.map((r) => pick(r).packed), 0),
|
|
72
|
+
scales: ops.concatAxis(padded.map((r) => pick(r).scales), 0),
|
|
73
|
+
biases: ops.concatAxis(padded.map((r) => pick(r).biases), 0),
|
|
74
|
+
});
|
|
75
|
+
const keys = cat((r) => r.keys);
|
|
76
|
+
const values = cat((r) => r.values);
|
|
77
|
+
for (const r of padded) { disposeTriple(r.keys); disposeTriple(r.values); }
|
|
78
|
+
return { keys, values, leftPad, width };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Quantized twin of extendKVRows: append ONE right-justified quantized row
|
|
82
|
+
* to an existing batched triple pair in one pad + one B-axis concat.
|
|
83
|
+
* Existing pads grow, never shrink (mlx-lm extend semantics). Caller owns
|
|
84
|
+
* the result; inputs are not disposed. */
|
|
85
|
+
export function extendQuantRows(
|
|
86
|
+
keys: ops.QuantizedTensor, values: ops.QuantizedTensor, leftPad: number[], row: QuantRow,
|
|
87
|
+
): { keys: ops.QuantizedTensor; values: ops.QuantizedTensor; leftPad: number[]; width: number } {
|
|
88
|
+
const S = keys.packed.shape[2]!;
|
|
89
|
+
const Lr = row.keys.packed.shape[2]!;
|
|
90
|
+
const width = Math.max(S, Lr);
|
|
91
|
+
const bk = tripleMap(keys, (a) => leftPadTo(a, width - S));
|
|
92
|
+
const bv = tripleMap(values, (a) => leftPadTo(a, width - S));
|
|
93
|
+
const rk = tripleMap(row.keys, (a) => leftPadTo(a, width - Lr));
|
|
94
|
+
const rv = tripleMap(row.values, (a) => leftPadTo(a, width - Lr));
|
|
95
|
+
const cat = (b: ops.QuantizedTensor, r: ops.QuantizedTensor): ops.QuantizedTensor => ({
|
|
96
|
+
packed: ops.concatAxis([b.packed, r.packed], 0),
|
|
97
|
+
scales: ops.concatAxis([b.scales, r.scales], 0),
|
|
98
|
+
biases: ops.concatAxis([b.biases, r.biases], 0),
|
|
99
|
+
});
|
|
100
|
+
const outK = cat(bk, rk);
|
|
101
|
+
const outV = cat(bv, rv);
|
|
102
|
+
for (const t of [bk, bv, rk, rv]) disposeTriple(t);
|
|
103
|
+
return {
|
|
104
|
+
keys: outK, values: outV,
|
|
105
|
+
leftPad: [...leftPad.map((p) => p + (width - S)), width - Lr],
|
|
106
|
+
width,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Quantized twin of extractKVRow (mlx-lm BatchKVCache.extract,
|
|
111
|
+
* models/cache.py:1080, over triples): pull row `i` past its left padding
|
|
112
|
+
* into a fresh SERIAL QuantizedKVCache with OWNED contiguous copies.
|
|
113
|
+
* Token-axis slicing is byte-safe because quantization packs along
|
|
114
|
+
* HEAD_DIM (file header) — a row's quantized bytes come out exactly as
|
|
115
|
+
* the serial oracle wrote them. */
|
|
116
|
+
export function extractQuantRow(
|
|
117
|
+
cache: QuantizedKVCache, leftPad: number, i: number,
|
|
118
|
+
): QuantizedKVCache {
|
|
119
|
+
if (!cache.keys || !cache.values) throw new Error("extractQuantRow: empty cache");
|
|
120
|
+
const S = cache.offset;
|
|
121
|
+
const cut = (t: ops.QuantizedTensor): ops.QuantizedTensor =>
|
|
122
|
+
tripleMap(t, (a) => {
|
|
123
|
+
const [, H, , D] = a.shape as [number, number, number, number];
|
|
124
|
+
const view = a.slice([i, 0, leftPad, 0], [i + 1, H, S, D]);
|
|
125
|
+
const own = ops.contiguous(view);
|
|
126
|
+
view.dispose();
|
|
127
|
+
return own;
|
|
128
|
+
});
|
|
129
|
+
const out = new QuantizedKVCache(cache.groupSize, cache.bits);
|
|
130
|
+
out.restoreState(cut(cache.keys), cut(cache.values), S - leftPad);
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Quantized twin of filterKVRows: keep `keep` rows along the batch axis.
|
|
135
|
+
* Caller owns the result; inputs are not disposed. */
|
|
136
|
+
export function filterQuantRows(
|
|
137
|
+
keys: ops.QuantizedTensor, values: ops.QuantizedTensor, keep: number[],
|
|
138
|
+
): { keys: ops.QuantizedTensor; values: ops.QuantizedTensor } {
|
|
139
|
+
const idx = MlxArray.fromInt32(Int32Array.from(keep), [keep.length]);
|
|
140
|
+
const take = (t: ops.QuantizedTensor): ops.QuantizedTensor =>
|
|
141
|
+
tripleMap(t, (a) => ops.takeAxis(a, idx, 0));
|
|
142
|
+
const k = take(keys);
|
|
143
|
+
const v = take(values);
|
|
144
|
+
idx.dispose();
|
|
145
|
+
return { keys: k, values: v };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Per-step cache wrapper for batched QUANTIZED decode with left-padded
|
|
149
|
+
* rows — the quantized twin of BatchedDecodeMaskCache. Subclasses
|
|
150
|
+
* QuantizedKVCache so attention's `instanceof` dispatch routes to
|
|
151
|
+
* quantizedSdpa exactly as for a serial quantized cache; delegates KV
|
|
152
|
+
* storage to the persistent batched inner and overrides the two things a
|
|
153
|
+
* padded batch needs: the padding-aware decode mask and per-row RoPE
|
|
154
|
+
* positions. Ephemeral — the scheduler builds a fresh wrapper each step
|
|
155
|
+
* and calls releaseRopeArr() after (never dispose(), which would free the
|
|
156
|
+
* inner). Rope is captured ONCE per step before updateAndFetch (attention
|
|
157
|
+
* reads it pre-write; see minicpm5.ts LlamaAttention.forward), so an
|
|
158
|
+
* eagerly-built [B] position array is exact. */
|
|
159
|
+
export class BatchedQuantDecodeMaskCache extends QuantizedKVCache {
|
|
160
|
+
override readonly ropeOffsetArr: MlxArray;
|
|
161
|
+
|
|
162
|
+
constructor(
|
|
163
|
+
private readonly inner: QuantizedKVCache,
|
|
164
|
+
private readonly B: number,
|
|
165
|
+
private readonly leftPad: number[],
|
|
166
|
+
) {
|
|
167
|
+
super(inner.groupSize, inner.bits);
|
|
168
|
+
this.offset = inner.offset;
|
|
169
|
+
const data = new Int32Array(B);
|
|
170
|
+
for (let b = 0; b < B; b++) data[b] = inner.offset - leftPad[b]!;
|
|
171
|
+
this.ropeOffsetArr = MlxArray.fromInt32(data, [B]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
override updateAndFetchQuantized(k: MlxArray, v: MlxArray): [ops.QuantizedTensor, ops.QuantizedTensor] {
|
|
175
|
+
const r = this.inner.updateAndFetchQuantized(k, v);
|
|
176
|
+
this.offset = this.inner.offset;
|
|
177
|
+
return r;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override makeMask(N: number, _windowSize: number | null): Mask {
|
|
181
|
+
// Same convention as BatchedDecodeMaskCache: built pre-write, S spans
|
|
182
|
+
// offset + N; quantizedSdpaUnfused expands it for the 5-D GQA scores.
|
|
183
|
+
const S = this.inner.offset + N;
|
|
184
|
+
return { mode: "array", arr: buildBatchedDecodeMask(this.B, N, S, this.leftPad, null) };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Free the per-step RoPE array WITHOUT touching the persistent inner —
|
|
188
|
+
* name and signature must match the scheduler's structural
|
|
189
|
+
* `(c as { releaseRopeArr?: () => void })` cast. */
|
|
190
|
+
releaseRopeArr(): void {
|
|
191
|
+
this.ropeOffsetArr.dispose();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
override state(): MlxArray[] {
|
|
195
|
+
return this.inner.state();
|
|
196
|
+
}
|
|
197
|
+
override isTrimmable(): boolean {
|
|
198
|
+
return this.inner.isTrimmable();
|
|
199
|
+
}
|
|
200
|
+
override trim(n: number): void {
|
|
201
|
+
this.inner.trim(n);
|
|
202
|
+
}
|
|
203
|
+
override dispose(): void {
|
|
204
|
+
this.inner.dispose();
|
|
205
|
+
}
|
|
206
|
+
}
|