mlx-bun 0.2.0 → 0.4.0
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 +71 -588
- package/docs/README.md +94 -0
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/archive/investigations/openjarvis-fit.md +198 -0
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
- package/docs/design/batching.md +1841 -0
- package/docs/design/decode-speed-program.md +2346 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +655 -334
- package/docs/design/kv-cache.md +824 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1990 -0
- package/docs/design/turboquant.md +2212 -0
- package/docs/design/unified-engine-frontier-plan.md +1833 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +50 -1
- package/docs/planning/release-notes-v0.4.0.md +45 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +3613 -0
- package/docs/reference/cli.md +434 -160
- package/docs/reference/distribution.md +328 -182
- package/docs/reference/environment.md +398 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +566 -168
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +113 -6
- package/docs/reference/server-api.md +944 -429
- package/docs/reference/server-config.md +740 -338
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +158 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/assistant-target.ts +46 -0
- package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1790 -0
- package/src/backends/mlx/cache-attachment.ts +67 -0
- package/src/backends/mlx/cache-layout.ts +31 -0
- package/src/backends/mlx/checkpoint-state.ts +53 -0
- package/src/backends/mlx/continuation-persistence.ts +106 -0
- package/src/backends/mlx/continuation-request.ts +43 -0
- package/src/backends/mlx/continuation.ts +77 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +32 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/full-kv-row-append.ts +32 -0
- package/src/backends/mlx/full-kv-row-donor.ts +54 -0
- package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
- package/src/backends/mlx/gateway-binding.ts +130 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/kv-codec.ts +9 -0
- package/src/backends/mlx/kv-maintenance.ts +133 -0
- package/src/backends/mlx/kv-tensor-rows.ts +212 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill-cohort.ts +89 -0
- package/src/backends/mlx/prefill-rows.ts +200 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/projected-context-rows.ts +72 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/request-state-policy.ts +41 -0
- package/src/backends/mlx/rollback.ts +89 -0
- package/src/backends/mlx/row-sampling.ts +49 -0
- package/src/backends/mlx/serial-executor.ts +242 -0
- package/src/backends/mlx/speculative-group.ts +359 -0
- package/src/backends/mlx/speculative-round.ts +161 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-rows.ts +104 -0
- package/src/backends/mlx/state-views.ts +46 -0
- package/src/backends/mlx/target-layout-capability.ts +35 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
- package/src/cli.ts +66 -58
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +60 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/prefix-cache.ts +23 -0
- package/src/contracts/resources.ts +25 -0
- package/src/contracts/sampling.ts +23 -0
- package/src/contracts/scheduling.ts +45 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +53 -0
- package/src/engine/resources.ts +53 -0
- package/src/engine/scheduler.ts +72 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +236 -3
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +8 -96
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +30 -16
- package/src/generate.ts +709 -417
- package/src/grammar.ts +12 -7
- package/src/harness-pi.ts +14 -33
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +7 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/draft-acceptance.ts +41 -0
- package/src/inference/draft-output.ts +49 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +12 -12
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-scheme.ts +70 -12
- package/src/kv-store.ts +177 -63
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
- package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
- package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +1 -1
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +30 -169
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +1 -3
- package/src/mlx/array.ts +11 -11
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +58 -11
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +33 -13
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/artifact-identity.ts +73 -0
- package/src/model/batched-kv.ts +235 -0
- package/src/model/batched-mask.ts +20 -6
- package/src/model/batched-quant.ts +9 -3
- package/src/model/batched-quantized-kv.ts +144 -0
- package/src/model/batched-rotating-quant.ts +78 -17
- package/src/model/batched-rotating-state.ts +76 -0
- package/src/model/batched-rotating.ts +65 -23
- package/src/model/batched-row-storage.ts +52 -0
- package/src/model/batched-ssm.ts +52 -0
- package/src/model/batched-turboquant-kv.ts +93 -0
- package/src/model/compiled-decode.ts +8 -2
- package/src/model/decoded-kv-donor.ts +12 -0
- package/src/model/delayed-quantized-kv.ts +72 -0
- package/src/model/delayed-rotating-quantized-kv.ts +93 -0
- package/src/model/delayed-turboquant-kv.ts +55 -0
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +76 -33
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/full-prefill-padding.ts +56 -0
- package/src/model/full-prefill-row.ts +105 -0
- package/src/model/gemma4-base.ts +179 -80
- package/src/model/gemma4.ts +40 -32
- package/src/model/generated/gemma4-12b.ts +6 -3
- package/src/model/generated/gemma4-26b.ts +6 -3
- package/src/model/generated/gemma4-e4b.ts +6 -3
- package/src/model/glm52-cache.ts +80 -4
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/glm52-mla.ts +12 -6
- package/src/model/glm52.ts +19 -40
- package/src/model/implementation.ts +69 -0
- package/src/model/kv-attention-view.ts +67 -0
- package/src/model/minicpm5.ts +17 -15
- package/src/model/profile.ts +12 -2
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3-delta-state.ts +74 -0
- package/src/model/qwen3-delta.ts +59 -36
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +202 -78
- package/src/model/rotating-kv-donor.ts +35 -0
- package/src/model/rotating-kv-layout.ts +262 -0
- package/src/model/rotating-row-transaction.ts +35 -0
- package/src/model/speculative-rotating-kv.ts +101 -0
- package/src/model/ssm-prefill-padding.ts +39 -0
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/turboquant-codec.ts +83 -0
- package/src/model/universal/dense.ts +15 -14
- package/src/model/universal/modules.ts +8 -1
- package/src/native-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/preflight.ts +31 -15
- package/src/prompt-cache.ts +110 -69
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/config-writer.ts +10 -3
- package/src/quantize/rotate.ts +4 -4
- package/src/quantize/trellis.ts +586 -0
- package/src/responses.ts +28 -1
- package/src/runtime-config.ts +18 -4
- package/src/sampler.ts +40 -29
- package/src/serve/batch-scheduler.ts +8 -1671
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +15 -7
- package/src/serve/discovery-routes.ts +12 -13
- package/src/serve/generation-gateway.ts +183 -213
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/lab-routes.ts +3 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +7 -5
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +511 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/request-plan.ts +23 -18
- package/src/serve/request-prep.ts +344 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +335 -2711
- package/src/spec/assistant-rows.ts +92 -0
- package/src/spec/assistant-source.ts +31 -55
- package/src/spec/cache-identity.ts +22 -0
- package/src/spec/deepspec-rows.ts +29 -0
- package/src/spec/deepspec-source.ts +16 -14
- package/src/spec/dflash-source.ts +36 -12
- package/src/spec/drafter.ts +153 -142
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +97 -122
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +129 -172
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-graph.ts +29 -0
- package/src/spec/glm52-mtp-rows.ts +132 -0
- package/src/spec/glm52-mtp-source.ts +54 -137
- package/src/spec/glm52-mtp-state.ts +33 -0
- package/src/spec/ngram-source.ts +93 -21
- package/src/spec/projected-draft-rows.ts +73 -0
- package/src/spec/qwen-mtp-module.ts +171 -0
- package/src/spec/qwen-mtp-rows.ts +219 -0
- package/src/spec/qwen-mtp-source.ts +147 -195
- package/src/spec/qwen-mtp-state.ts +30 -0
- package/src/spec/serve-loop.ts +201 -201
- package/src/spec/source.ts +110 -13
- package/src/spec/two-model-rows.ts +61 -0
- package/src/spec/two-model.ts +44 -102
- package/src/ssd-cache.ts +99 -19
- package/src/ssd-durability.ts +36 -20
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +2 -2
- package/src/train/forward.ts +6 -0
- package/src/train/loss.ts +1 -1
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +5 -3
- package/src/train/trainer.ts +6 -6
- package/src/vision/prompt.ts +1 -1
- package/src/vision/qwen3vl-tower.ts +52 -10
- package/src/web/app.html +1 -1
- package/src/web/app.js +62 -60
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +4 -4
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +55 -9
- package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/archive/investigations/hlg-ab.html +0 -34
- package/docs/archive/investigations/hlg-explorer.html +0 -238
- package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
- package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/archive/investigations/hlg-report.html +0 -262
- package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -318
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -231
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -415
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/turboquant-weights.md +0 -467
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -101
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -11
- /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
- /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
- /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
- /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
- /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
- /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -17,6 +17,7 @@ import { MlxArray } from "../../mlx/array";
|
|
|
17
17
|
import { Dtype } from "../../mlx/ffi";
|
|
18
18
|
import * as ops from "../../mlx/ops";
|
|
19
19
|
import type { Gemma4Model } from "../../model/gemma4";
|
|
20
|
+
import type { DraftProjection } from "../source";
|
|
20
21
|
import { loadAdapterTensors } from "../../lora";
|
|
21
22
|
import { writeShardedSafetensors, type NamedTensor } from "../../quantize/safetensors-writer";
|
|
22
23
|
import { processLogits, sampleToken, KeyStream, type DSparkSampleConfig } from "./sample";
|
|
@@ -25,7 +26,7 @@ import { join } from "node:path";
|
|
|
25
26
|
|
|
26
27
|
/** STS calibration (§3.2.1) — per-position confidence thresholds fit on real
|
|
27
28
|
* (confidence, accepted) verify outcomes (src/spec/dspark/calibration.ts,
|
|
28
|
-
* scripts/dspark
|
|
29
|
+
* scripts/dspark.ts calibrate). Consumed by the confidence-scheduled
|
|
29
30
|
* draft-length pruning (Alg 1, single-user form) in forwardInfer. Stored
|
|
30
31
|
* inside DflashConfig so it round-trips through dspark.json for free.
|
|
31
32
|
* ABSENT ⟹ no pruning — an uncalibrated checkpoint drafts exactly as before. */
|
|
@@ -73,6 +74,10 @@ export interface DflashTrainOut { draftLogits: MlxArray; conf: MlxArray }
|
|
|
73
74
|
* positions — ABSENT when the caller passed collectLogits:false (the loop
|
|
74
75
|
* never materialized/concatenated the per-position logits). */
|
|
75
76
|
export interface DflashDraftBlock { tokens: number[]; conf: number[]; draftLogits?: MlxArray }
|
|
77
|
+
export interface DflashDraftRows { tokens: number[][]; conf: number[][]; draftLogits?: MlxArray; }
|
|
78
|
+
export interface DflashContextAttention {
|
|
79
|
+
attend(layer: number, query: MlxArray, keys: MlxArray, values: MlxArray, scale: number): MlxArray;
|
|
80
|
+
}
|
|
76
81
|
export interface DflashDraftOpts {
|
|
77
82
|
sample?: DSparkSampleConfig;
|
|
78
83
|
keys?: KeyStream;
|
|
@@ -91,6 +96,8 @@ export interface DflashDraftOpts {
|
|
|
91
96
|
* path runs its own verify lm-head and never reads it — pass false there
|
|
92
97
|
* to skip the dead concat + a host-unrelated GPU alloc every round. */
|
|
93
98
|
collectLogits?: boolean;
|
|
99
|
+
/** Return confidence telemetry; pruning still computes it when needed. */
|
|
100
|
+
collectConfidence?: boolean;
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
const CDT = Dtype.float32;
|
|
@@ -244,7 +251,7 @@ export class DflashDrafter {
|
|
|
244
251
|
}
|
|
245
252
|
|
|
246
253
|
// --- Eq 3: one KV-injection layer. H_ctx read-only; H_d is queries+updated ---
|
|
247
|
-
#layer(i: number, H_d: MlxArray, H_ctx: MlxArray, maskBias: MlxArray | null, A: number, Lctx: number): MlxArray {
|
|
254
|
+
#layer(i: number, H_d: MlxArray, H_ctx: MlxArray, maskBias: MlxArray | null, A: number, Lctx: number, context?: DflashContextAttention): MlxArray {
|
|
248
255
|
const { dDraft, nHeads, gamma } = this.cfg;
|
|
249
256
|
const hd = dDraft / nHeads;
|
|
250
257
|
const eps = this.dims.eps;
|
|
@@ -252,24 +259,34 @@ export class DflashDrafter {
|
|
|
252
259
|
|
|
253
260
|
const residual = H_d;
|
|
254
261
|
const nd = ops.rmsNorm(H_d, this.get(`bb.${i}.attn_norm`), eps);
|
|
255
|
-
const nc = ops.rmsNorm(H_ctx, this.get(`bb.${i}.attn_norm`), eps); // SAME norm as block
|
|
262
|
+
const nc = context ? null : ops.rmsNorm(H_ctx, this.get(`bb.${i}.attn_norm`), eps); // SAME norm as block
|
|
256
263
|
|
|
257
264
|
// Q from block only
|
|
258
265
|
let q = ops.matmul(nd, this.get(`bb.${i}.q`)); // [A,γ,d]
|
|
259
266
|
q = disposing(q, ops.reshape(q, [A, gamma, nHeads, hd]));
|
|
260
267
|
q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3])); // [A,nHeads,γ,hd]
|
|
261
268
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
const kd = ops.matmul(nd, wk), vd = ops.matmul(nd, wv); nd.dispose();
|
|
270
|
+
let attn: MlxArray;
|
|
271
|
+
if (context) {
|
|
272
|
+
const shape = (array: MlxArray) => {
|
|
273
|
+
using rows = ops.reshape(array, [A, gamma, nHeads, hd]);
|
|
274
|
+
return ops.transposeAxes(rows, [0, 2, 1, 3]);
|
|
275
|
+
};
|
|
276
|
+
using keys = shape(kd), values = shape(vd); kd.dispose(); vd.dispose();
|
|
277
|
+
attn = context.attend(i, q, keys, values, Math.pow(hd, -0.5));
|
|
278
|
+
} else {
|
|
279
|
+
const kc = ops.matmul(nc!, wk), vc = ops.matmul(nc!, wv); nc!.dispose();
|
|
280
|
+
const shape = (array: MlxArray) => {
|
|
281
|
+
using rows = ops.reshape(array, [A, Lctx + gamma, nHeads, hd]);
|
|
282
|
+
return ops.transposeAxes(rows, [0, 2, 1, 3]);
|
|
283
|
+
};
|
|
284
|
+
using k = ops.concatAxis([kc, kd], 1), v = ops.concatAxis([vc, vd], 1);
|
|
285
|
+
kc.dispose(); kd.dispose(); vc.dispose(); vd.dispose();
|
|
286
|
+
using keys = shape(k), values = shape(v);
|
|
287
|
+
attn = ops.sdpa(q, keys, values, Math.pow(hd, -0.5), maskBias ? "array" : "", maskBias);
|
|
288
|
+
}
|
|
289
|
+
q.dispose();
|
|
273
290
|
attn = disposing(attn, ops.transposeAxes(attn, [0, 2, 1, 3])); // [A,γ,nHeads,hd]
|
|
274
291
|
attn = disposing(attn, ops.reshape(attn, [A, gamma, dDraft]));
|
|
275
292
|
attn = disposing(attn, ops.matmul(attn, this.get(`bb.${i}.o`)));
|
|
@@ -289,18 +306,36 @@ export class DflashDrafter {
|
|
|
289
306
|
}
|
|
290
307
|
|
|
291
308
|
/** hCtx [A,Lctx,m*H], anchorEmb [A,H], ctxMask [A,Lctx]|null → block [A,γ,d]. */
|
|
292
|
-
#backbone(hCtx: MlxArray, anchorEmb: MlxArray, ctxMask: MlxArray | null, A: number): MlxArray {
|
|
293
|
-
const Lctx = hCtx
|
|
294
|
-
const H_ctx = this.#buildContext(hCtx);
|
|
309
|
+
#backbone(hCtx: MlxArray | null, anchorEmb: MlxArray, ctxMask: MlxArray | null, A: number, context?: DflashContextAttention): MlxArray {
|
|
310
|
+
const Lctx = hCtx?.shape[1] ?? 0;
|
|
311
|
+
const H_ctx = context ? null : this.#buildContext(hCtx!);
|
|
295
312
|
let H_d = this.#buildBlock(anchorEmb, A);
|
|
296
313
|
const maskBias = this.#maskBias(ctxMask, A, Lctx);
|
|
297
|
-
for (let i = 0; i < this.cfg.nLayers; i++) H_d = disposing(H_d, this.#layer(i, H_d, H_ctx
|
|
298
|
-
H_ctx
|
|
314
|
+
for (let i = 0; i < this.cfg.nLayers; i++) H_d = disposing(H_d, this.#layer(i, H_d, H_ctx!, maskBias, A, Lctx, context));
|
|
315
|
+
H_ctx?.dispose(); maskBias?.dispose();
|
|
299
316
|
H_d = disposing(H_d, ops.rmsNorm(H_d, this.get("out_norm"), this.dims.eps));
|
|
300
317
|
return H_d;
|
|
301
318
|
}
|
|
302
319
|
|
|
303
|
-
|
|
320
|
+
/** Context projection is independent of the block and can be retained. */
|
|
321
|
+
projectContextRows(hidden: MlxArray): { k: MlxArray; v: MlxArray }[] {
|
|
322
|
+
const { nHeads, dDraft } = this.cfg, B = hidden.shape[0]!, N = hidden.shape[1]!;
|
|
323
|
+
using projected = this.#buildContext(hidden);
|
|
324
|
+
using pending = new DisposableStack();
|
|
325
|
+
const pairs = Array.from({ length: this.cfg.nLayers }, (_, layer) => {
|
|
326
|
+
using normalized = ops.rmsNorm(projected, this.get(`bb.${layer}.attn_norm`), this.dims.eps);
|
|
327
|
+
const plane = (name: string) => {
|
|
328
|
+
using flat = ops.matmul(normalized, this.get(name));
|
|
329
|
+
using rows = ops.reshape(flat, [B, N, nHeads, dDraft / nHeads]);
|
|
330
|
+
return pending.use(ops.transposeAxes(rows, [0, 2, 1, 3]));
|
|
331
|
+
};
|
|
332
|
+
return { k: plane(`bb.${layer}.k`), v: plane(`bb.${layer}.v`) };
|
|
333
|
+
});
|
|
334
|
+
pending.move();
|
|
335
|
+
return pairs;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#baseLogits(model: DraftProjection, block: MlxArray): MlxArray {
|
|
304
339
|
const hOut = ops.matmul(block, this.get("out_proj")); // [A,γ,H]
|
|
305
340
|
const hBf = hOut.astype(model.embed.scales.dtype); hOut.dispose();
|
|
306
341
|
const logits = model.logitsFromHidden(hBf); hBf.dispose();
|
|
@@ -400,167 +435,89 @@ export class DflashDrafter {
|
|
|
400
435
|
}
|
|
401
436
|
}
|
|
402
437
|
|
|
403
|
-
/**
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
* argmax result [1] uint32 feeds directly into the next position's
|
|
409
|
-
* takeAxis, no itemUint32 in the loop. Per-position token arrays are
|
|
410
|
-
* collected and resolved to host numbers with exactly ONE concat +
|
|
411
|
-
* toIntTokens() after the loop. Confidence is the one read the pruning
|
|
412
|
-
* ALGORITHM inherently needs per position (Alg 1 must decide whether to
|
|
413
|
-
* stop NOW) — so it stays per-position whenever thresholds/minConf are
|
|
414
|
-
* actually active; when pruning is inactive there is no such need, so
|
|
415
|
-
* confidence is deferred the same way (collect [1] arrays, one concat +
|
|
416
|
-
* one toFloat32 after the loop). The sampling path already forces a host
|
|
417
|
-
* read every position (sampleToken draws from a device RNG key) — that
|
|
418
|
-
* path is unchanged. */
|
|
419
|
-
forwardInfer(model: Gemma4Model, hCtx: MlxArray, anchorTok: number, gamma: number, opts: DflashDraftOpts = {}): DflashDraftBlock {
|
|
420
|
-
const { dDraft, markovRank: r } = this.cfg;
|
|
421
|
-
const V = this.dims.vocabSize;
|
|
422
|
-
const sample = opts.sample && opts.sample.temperature > 0 ? opts.sample : null;
|
|
423
|
-
const keys = opts.keys ?? new KeyStream(opts.sample?.seed ?? 0);
|
|
424
|
-
const collectLogits = opts.collectLogits ?? true;
|
|
425
|
-
const pruningActive = opts.thresholds !== undefined || opts.minConf !== undefined;
|
|
426
|
-
|
|
427
|
-
const ids = ops.fromInt32([anchorTok], [1, 1]);
|
|
428
|
-
const ae3 = model.embed.encode(ids); ids.dispose();
|
|
429
|
-
const anchorEmb = ops.reshape(ae3, [1, this.dims.hiddenSize]); ae3.dispose();
|
|
430
|
-
const block = this.#backbone(hCtx, anchorEmb, null, 1); // [1,γ,d]
|
|
431
|
-
anchorEmb.dispose();
|
|
432
|
-
const U = this.#baseLogits(model, block);
|
|
433
|
-
const Uf = U.astype(CDT); U.dispose();
|
|
438
|
+
/** Single-request callers use the same graph and proposal head at B1. */
|
|
439
|
+
forwardInfer(model: DraftProjection, hCtx: MlxArray, anchor: number, gamma: number, opts: DflashDraftOpts = {}): DflashDraftBlock {
|
|
440
|
+
const result = this.forwardRows(model, hCtx, [anchor], gamma, opts);
|
|
441
|
+
return { tokens: result.tokens[0]!, conf: result.conf[0]!, draftLogits: result.draftLogits };
|
|
442
|
+
}
|
|
434
443
|
|
|
435
|
-
|
|
444
|
+
forwardRows(model: DraftProjection, hCtx: MlxArray | null, anchors: readonly number[], gamma: number,
|
|
445
|
+
opts: DflashDraftOpts = {}, context?: DflashContextAttention): DflashDraftRows {
|
|
446
|
+
const B = anchors.length, { dDraft, markovRank: r } = this.cfg, V = this.dims.vocabSize;
|
|
447
|
+
const sample = opts.sample && opts.sample.temperature > 0 ? opts.sample : null;
|
|
448
|
+
const keys = sample ? anchors.map((_, row) => row === 0 && opts.keys ? opts.keys : new KeyStream(opts.sample?.seed ?? 0)) : [];
|
|
449
|
+
const collect = opts.collectLogits ?? true, pruning = opts.thresholds !== undefined || opts.minConf !== undefined;
|
|
450
|
+
using ids = ops.fromInt32([...anchors], [B, 1]);
|
|
451
|
+
using embeddings = model.embed.encode(ids);
|
|
452
|
+
using anchorEmb = ops.reshape(embeddings, [B, this.dims.hiddenSize]);
|
|
453
|
+
using block = this.#backbone(hCtx, anchorEmb, null, B, context);
|
|
454
|
+
using raw = this.#baseLogits(model, block);
|
|
455
|
+
using base = raw.astype(CDT);
|
|
436
456
|
const isRnn = this.cfg.seqHead === "rnn";
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
const tokArrs: MlxArray[] = []; // per-position [1] device token ids, greedy path only
|
|
444
|
-
const confArrs: MlxArray[] = []; // per-position [1] device confidences, deferred (no pruning) only
|
|
445
|
-
let tokens: number[] = [];
|
|
446
|
-
let prevIdx: MlxArray = ops.fromInt32([anchorTok], [1]); // device token id fed to takeAxis
|
|
447
|
-
let ownPrevIdx = true; // false once prevIdx aliases a tokArrs/argmax entry we must not double-dispose
|
|
448
|
-
// Iteration-local temps register here at creation so the catch can reach
|
|
449
|
-
// them on a mid-flight throw; drained (length=0) at the bottom of each
|
|
450
|
-
// iteration once everything in it was disposed on the normal path.
|
|
451
|
-
// dispose() idempotence makes catch-side re-disposal of the already-freed
|
|
452
|
-
// ones inert.
|
|
453
|
-
const pending: MlxArray[] = [];
|
|
457
|
+
let state: MlxArray | null = isRnn ? zerosArray([B, r]) : null;
|
|
458
|
+
const tokens: MlxArray[] = [], confidence: MlxArray[] = [], logits: MlxArray[] = [];
|
|
459
|
+
const lengths: Array<number | undefined> = anchors.map(() => undefined);
|
|
460
|
+
const hostConfidence: number[][] = [];
|
|
461
|
+
const needConfidence = pruning || opts.collectConfidence !== false;
|
|
462
|
+
using first = ops.fromInt32([...anchors], [B]); let previous = first;
|
|
454
463
|
try {
|
|
455
|
-
for (let
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (ownPrevIdx) { prevIdx.dispose(); ownPrevIdx = false; } // consumed; prevIdx reassigned below
|
|
461
|
-
let Bk: MlxArray;
|
|
464
|
+
for (let step = 0; step < gamma; step++) {
|
|
465
|
+
using row = base.slice([0, step, 0], [B, step + 1, V]);
|
|
466
|
+
using flat = ops.reshape(row, [B, V]);
|
|
467
|
+
using e1 = ops.takeAxis(this.get("markov.w1"), previous, 0);
|
|
468
|
+
let bias: MlxArray;
|
|
462
469
|
if (isRnn) {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
Bk = ops.matmul(e1, w2); pending.push(Bk);
|
|
473
|
-
}
|
|
474
|
-
const logitsK = ops.add(Uk, Bk); pending.push(logitsK);
|
|
475
|
-
Uk.dispose(); Bk.dispose();
|
|
476
|
-
// prevIdx becomes the SINGLE tracked owner of the next token id the
|
|
477
|
-
// moment it exists — no separate local for the catch to miss.
|
|
470
|
+
using recurrent = ops.matmul(state!, this.get("rnn.wH"));
|
|
471
|
+
using sum = ops.add(recurrent, e1);
|
|
472
|
+
using shifted = ops.add(sum, this.get("rnn.bH"));
|
|
473
|
+
const next = ops.tanh(shifted); state!.dispose(); state = next;
|
|
474
|
+
bias = ops.matmul(state, this.get("rnn.wO"));
|
|
475
|
+
} else bias = ops.matmul(e1, this.get("markov.w2"));
|
|
476
|
+
using correction = bias;
|
|
477
|
+
using scores = ops.add(flat, correction);
|
|
478
|
+
let token: MlxArray;
|
|
478
479
|
if (sample) {
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
// return ≥1 token). Pruning inherently needs the confidence value
|
|
504
|
-
// THIS position, on the host, to decide whether to stop — no way
|
|
505
|
-
// around that read when active. When inactive, defer it (device
|
|
506
|
-
// array, resolved once after the loop) since nothing this iteration
|
|
507
|
-
// depends on its value.
|
|
508
|
-
const thr = opts.thresholds?.[k] ?? opts.minConf;
|
|
509
|
-
if (pruningActive) {
|
|
510
|
-
const cVal = cz.toFloat32()[0]!; cz.dispose();
|
|
511
|
-
if (thr !== undefined && k > 0 && cVal < thr) {
|
|
512
|
-
// Drop position k SYMMETRICALLY on both paths so tokens/conf/
|
|
513
|
-
// draftLogits stay aligned (the DflashDraftBlock contract —
|
|
514
|
-
// verifySampling slices draftLogits per token). Greedy: pop the
|
|
515
|
-
// device array (prevIdx aliases it — one dispose via the owning
|
|
516
|
-
// collection). Sample: pop the host token + free the standalone
|
|
517
|
-
// fromInt32.
|
|
518
|
-
if (!sample) tokArrs.pop()!.dispose(); // also frees prevIdx (same array)
|
|
519
|
-
else { prevIdx.dispose(); tokens.pop(); }
|
|
520
|
-
ownPrevIdx = false; // dead either way — post-loop/catch must not re-dispose
|
|
521
|
-
if (collectLogits) perPos.pop()!.dispose(); // logits row for the dropped position
|
|
522
|
-
break;
|
|
480
|
+
const sampled = anchors.map((_, index) => {
|
|
481
|
+
if (lengths[index] !== undefined) return 0;
|
|
482
|
+
using one = scores.slice([index, 0], [index + 1, V]);
|
|
483
|
+
using processed = processLogits(one, sample);
|
|
484
|
+
return sampleToken(processed, keys[index]!.next());
|
|
485
|
+
});
|
|
486
|
+
token = ops.fromInt32(sampled, [B]);
|
|
487
|
+
} else token = ops.argmaxAxis(scores, -1);
|
|
488
|
+
tokens.push(token); previous = token;
|
|
489
|
+
if (collect) logits.push(ops.reshape(scores, [B, 1, V]));
|
|
490
|
+
if (needConfidence) {
|
|
491
|
+
using h = block.slice([0, step, 0], [B, step + 1, dDraft]);
|
|
492
|
+
using hFlat = ops.reshape(h, [B, dDraft]);
|
|
493
|
+
using joined = ops.concatAxis([hFlat, e1], 1);
|
|
494
|
+
using product = ops.matmul(joined, this.get("conf.w"));
|
|
495
|
+
using shifted = ops.add(product, this.get("conf.b"));
|
|
496
|
+
const conf = ops.sigmoid(shifted); confidence.push(conf);
|
|
497
|
+
if (pruning) {
|
|
498
|
+
const values = conf.toFloat32(), threshold = opts.thresholds?.[step] ?? opts.minConf;
|
|
499
|
+
hostConfidence.push(Array.from(values));
|
|
500
|
+
if (step > 0 && threshold !== undefined) values.forEach((value, row) => {
|
|
501
|
+
if (lengths[row] === undefined && value < threshold) lengths[row] = step;
|
|
502
|
+
});
|
|
503
|
+
if (lengths.every(length => length !== undefined)) break;
|
|
523
504
|
}
|
|
524
|
-
conf.push(cVal);
|
|
525
|
-
} else {
|
|
526
|
-
confArrs.push(cz);
|
|
527
505
|
}
|
|
528
|
-
pending.length = 0; // everything above was disposed (or handed to a collection)
|
|
529
506
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
tokens = allToks.toIntTokens(); allToks.dispose();
|
|
507
|
+
using packed = ops.concatAxis(tokens, 0); const values = packed.toIntTokens();
|
|
508
|
+
using packedConfidence = !pruning && confidence.length ? ops.concatAxis(confidence, 0) : null;
|
|
509
|
+
const conf = packedConfidence?.toFloat32();
|
|
510
|
+
const sizes = lengths.map(length => length ?? tokens.length);
|
|
511
|
+
let draftLogits: MlxArray | undefined;
|
|
512
|
+
if (collect) {
|
|
513
|
+
using full = ops.concatAxis(logits, 1);
|
|
514
|
+
draftLogits = full.slice([0, 0, 0], [B, Math.max(...sizes), V]);
|
|
539
515
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
const draftLogits = collectLogits ? ops.concatAxis(perPos, 1) : undefined;
|
|
547
|
-
if (collectLogits) for (const a of perPos) a.dispose();
|
|
548
|
-
return { tokens, conf, draftLogits };
|
|
549
|
-
} catch (err) {
|
|
550
|
-
// Cleanup on a mid-flight throw — the collections, the carried state,
|
|
551
|
-
// AND the current iteration's registered temps (`pending`). dispose()
|
|
552
|
-
// is idempotent (array.ts #disposed guard) so re-disposing an array the
|
|
553
|
-
// try block already freed (or that aliases one of these collections,
|
|
554
|
-
// e.g. prevIdx === tokArrs[k]) is inert, never a double-free bug.
|
|
555
|
-
for (const a of pending) a.dispose();
|
|
556
|
-
if (ownPrevIdx) prevIdx.dispose();
|
|
557
|
-
for (const a of tokArrs) a.dispose();
|
|
558
|
-
for (const a of confArrs) a.dispose();
|
|
559
|
-
for (const a of perPos) a.dispose();
|
|
560
|
-
s?.dispose();
|
|
561
|
-
Uf.dispose(); block.dispose();
|
|
562
|
-
throw err;
|
|
563
|
-
}
|
|
516
|
+
return {
|
|
517
|
+
tokens: sizes.map((length, row) => Array.from({ length }, (_, step) => values[step * B + row]!)),
|
|
518
|
+
conf: sizes.map((length, row) => opts.collectConfidence === false ? [] : Array.from({ length }, (_, step) => pruning ? hostConfidence[step]![row]! : conf![step * B + row]!)), draftLogits
|
|
519
|
+
};
|
|
520
|
+
} finally { state?.dispose(); for (const array of [...tokens, ...confidence, ...logits]) array.dispose(); }
|
|
564
521
|
}
|
|
565
522
|
|
|
566
523
|
save(dir: string): void {
|
|
@@ -31,6 +31,7 @@ import { MlxArray } from "../../mlx/array";
|
|
|
31
31
|
import { Dtype } from "../../mlx/ffi";
|
|
32
32
|
import * as ops from "../../mlx/ops";
|
|
33
33
|
import type { Gemma4Model } from "../../model/gemma4";
|
|
34
|
+
import type { DraftProjection } from "../source";
|
|
34
35
|
import { loadAdapterTensors } from "../../lora";
|
|
35
36
|
import { writeShardedSafetensors, type NamedTensor } from "../../quantize/safetensors-writer";
|
|
36
37
|
import { processLogits, sampleToken, KeyStream, type DSparkSampleConfig } from "./sample";
|
|
@@ -343,7 +344,7 @@ export class DSparkDrafter {
|
|
|
343
344
|
|
|
344
345
|
/** Base logits U from the SHARED frozen LM head over the backbone block
|
|
345
346
|
* hidden. [A,γ,V] (model dtype). */
|
|
346
|
-
#baseLogits(model:
|
|
347
|
+
#baseLogits(model: DraftProjection, block: MlxArray): MlxArray {
|
|
347
348
|
const hOut = ops.matmul(block, this.get("out_proj")); // [A,γ,H] (f32)
|
|
348
349
|
const hBf = hOut.astype(model.embed.scales.dtype); // head's activation dtype
|
|
349
350
|
hOut.dispose();
|
|
@@ -404,7 +405,7 @@ export class DSparkDrafter {
|
|
|
404
405
|
* reconstructs (so q is consistent). hCtx [1,H], anchorTok the bonus token.
|
|
405
406
|
* Returns the raw per-position logits so the verifier can recover q.
|
|
406
407
|
*/
|
|
407
|
-
forwardInfer(model:
|
|
408
|
+
forwardInfer(model: DraftProjection, hCtx: MlxArray, anchorTok: number, gamma: number, opts: DSparkDraftOpts = {}): DSparkDraftBlock {
|
|
408
409
|
const { dDraft, markovRank: r } = this.cfg;
|
|
409
410
|
const V = this.dims.vocabSize;
|
|
410
411
|
const A = 1;
|
|
@@ -537,4 +538,3 @@ function buildNames(cfg: DSparkConfig): string[] {
|
|
|
537
538
|
"markov.w1", "markov.w2", "conf.w", "conf.b");
|
|
538
539
|
return names;
|
|
539
540
|
}
|
|
540
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Quantize a DeepSpec-format drafter checkpoint (Phase 1a of the DSpark
|
|
2
|
-
// serving program, docs/design/
|
|
2
|
+
// serving program, docs/design/speculative-decoding.md).
|
|
3
3
|
//
|
|
4
4
|
// Thin policy layer over the house quantizer (src/quantize): the generic
|
|
5
5
|
// shape-eligibility rule already captures every 2-D matmul weight — the
|
package/src/spec/generate.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// with stock only on tie-free prompts (where batched == per-position).
|
|
12
12
|
// An earlier version verified per-position to stay bit-exact to STOCK —
|
|
13
13
|
// that matched no real oracle and cost an extra γ× read of the lm-head
|
|
14
|
-
// weight per step; superseded. See docs/design/
|
|
14
|
+
// weight per step; superseded. See docs/design/speculative-decoding.md.
|
|
15
15
|
//
|
|
16
16
|
// Limitation (same as the reference): partial-accept rollback requires
|
|
17
17
|
// trimmable caches; RotatingKVCache loses trimability once its ring
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MlxArray } from "../mlx/array";
|
|
2
|
+
import * as ops from "../mlx/ops";
|
|
3
|
+
import type { Glm52DecoderLayer, Glm52Model } from "../model/glm52";
|
|
4
|
+
import type { MLACache } from "../model/glm52-cache";
|
|
5
|
+
import { rmsNormF32Mlx } from "../model/glm52-mla";
|
|
6
|
+
|
|
7
|
+
/** Native MTP numerical graph. Tokens, anchor hidden and compressed state may
|
|
8
|
+
* have one or several rows; sampling and state retention belong to callers. */
|
|
9
|
+
export class Glm52MtpGraph {
|
|
10
|
+
constructor(readonly model: Glm52Model, readonly layer: Glm52DecoderLayer) {}
|
|
11
|
+
|
|
12
|
+
async forward(ids: MlxArray, hidden: MlxArray, cache: MLACache): Promise<MlxArray> {
|
|
13
|
+
const { glmConfig: config, weights } = this.model;
|
|
14
|
+
const prefix = `model.layers.${config.numHiddenLayers}`;
|
|
15
|
+
using embedded = weights.embedding(ids, "model.embed_tokens.weight", config.vocabSize, config.hiddenSize);
|
|
16
|
+
using embeddedNorm = rmsNormF32Mlx(embedded, weights.tensor(`${prefix}.enorm.weight`), config.rmsNormEps);
|
|
17
|
+
using hiddenNorm = rmsNormF32Mlx(hidden, weights.tensor(`${prefix}.hnorm.weight`), config.rmsNormEps);
|
|
18
|
+
using joined = ops.concatAxis([embeddedNorm, hiddenNorm], 2);
|
|
19
|
+
using projected = weights.linear(joined, `${prefix}.eh_proj.weight`, config.hiddenSize, 2 * config.hiddenSize);
|
|
20
|
+
return await this.layer.forwardAsync(projected, cache, null);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
project(hidden: MlxArray): MlxArray {
|
|
24
|
+
const { glmConfig: config, weights } = this.model;
|
|
25
|
+
using normalized = rmsNormF32Mlx(hidden,
|
|
26
|
+
weights.tensor(`model.layers.${config.numHiddenLayers}.shared_head.norm.weight`), config.rmsNormEps);
|
|
27
|
+
return this.model.logitsFromHidden(normalized);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { MlxArray } from "../mlx/array";
|
|
2
|
+
import * as ops from "../mlx/ops";
|
|
3
|
+
import { Dtype } from "../mlx/ffi";
|
|
4
|
+
import { materializeCopy } from "../mlx/materialize";
|
|
5
|
+
import { MLACache } from "../model/glm52-cache";
|
|
6
|
+
import { toLogprobs } from "../sampler";
|
|
7
|
+
import { applyStateChanges, disposeResources } from "../engine/resources";
|
|
8
|
+
import type { PreparedStateChange } from "../contracts/resources";
|
|
9
|
+
import type { DraftRowSampling } from "./source";
|
|
10
|
+
import type { Glm52MtpGraph } from "./glm52-mtp-graph";
|
|
11
|
+
|
|
12
|
+
export interface Glm52MtpRowState {
|
|
13
|
+
readonly cache: MLACache;
|
|
14
|
+
readonly hidden: MlxArray;
|
|
15
|
+
readonly processedTokens: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Native Colibri draft history starts empty, independently of target prompt
|
|
19
|
+
* length. Accepted draft rows are rebuilt from true target hidden states. */
|
|
20
|
+
export class Glm52MtpRows {
|
|
21
|
+
#cache: MLACache;
|
|
22
|
+
#hidden: MlxArray | null = null;
|
|
23
|
+
#processed: number[] = [];
|
|
24
|
+
#drafts: number[][] = [];
|
|
25
|
+
#depth = 0;
|
|
26
|
+
|
|
27
|
+
constructor(readonly graph: Glm52MtpGraph, readonly sampling: DraftRowSampling | null) {
|
|
28
|
+
this.#cache = this.makeCache();
|
|
29
|
+
}
|
|
30
|
+
makeCache(): MLACache {
|
|
31
|
+
const c = this.graph.model.glmConfig;
|
|
32
|
+
return new MLACache({ kvLoraRank: c.kvLoraRank, ropeHeadDim: c.qkRopeHeadDim,
|
|
33
|
+
maxTokens: c.maxPositionEmbeddings, role: "mtp" });
|
|
34
|
+
}
|
|
35
|
+
get rowCount(): number { return this.#processed.length; }
|
|
36
|
+
append(states: readonly (Glm52MtpRowState | null)[]): void {
|
|
37
|
+
applyStateChanges([() => this.prepareAppend(states)]);
|
|
38
|
+
}
|
|
39
|
+
prepareAppend(states: readonly (Glm52MtpRowState | null)[]): PreparedStateChange {
|
|
40
|
+
if (!states.length) return { commit() {}, dispose() {} };
|
|
41
|
+
let cache: MLACache | null = this.makeCache(), hidden: MlxArray | null = null;
|
|
42
|
+
const held: { dispose(): void }[] = [];
|
|
43
|
+
const processed = [...this.#processed, ...states.map(state => state?.processedTokens ?? 0)];
|
|
44
|
+
try {
|
|
45
|
+
cache.mergeRows([...(this.rowCount ? [this.#cache] : []), ...states.map(state => {
|
|
46
|
+
if (state) return state.cache;
|
|
47
|
+
const empty = this.makeCache(); held.push(empty); return empty;
|
|
48
|
+
})]);
|
|
49
|
+
hidden = ops.concatAxis([...(this.#hidden ? [this.#hidden] : []), ...states.map(state => {
|
|
50
|
+
if (state) return state.hidden;
|
|
51
|
+
const zero = ops.zeros([1, 1, this.graph.model.glmConfig.hiddenSize], Dtype.float32);
|
|
52
|
+
held.push(zero); return zero;
|
|
53
|
+
})], 0);
|
|
54
|
+
} catch (error) { cache.dispose(); hidden?.dispose(); throw error; }
|
|
55
|
+
finally { disposeResources(held); }
|
|
56
|
+
return {
|
|
57
|
+
commit: () => {
|
|
58
|
+
const priorCache = this.#cache, priorHidden = this.#hidden;
|
|
59
|
+
this.#cache = cache!; this.#hidden = hidden; this.#processed = processed;
|
|
60
|
+
cache = priorCache; hidden = priorHidden;
|
|
61
|
+
},
|
|
62
|
+
dispose: () => { cache?.dispose(); hidden?.dispose(); cache = null; hidden = null; },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
prefill(tokens: MlxArray, context: MlxArray): void {
|
|
66
|
+
const [batch, length] = tokens.shape as [number, number];
|
|
67
|
+
using tail = context.slice([0, length - 1, 0], [batch, length, context.shape[2]!]);
|
|
68
|
+
const hidden = materializeCopy(tail);
|
|
69
|
+
this.#hidden?.dispose(); this.#hidden = hidden;
|
|
70
|
+
this.#processed = this.#processed.map(count => count + length);
|
|
71
|
+
}
|
|
72
|
+
materialize(): void {
|
|
73
|
+
ops.evalAll([...this.#cache.state(), ...(this.#hidden ? [this.#hidden] : [])]);
|
|
74
|
+
}
|
|
75
|
+
filterRows(keep: readonly number[]): void {
|
|
76
|
+
if (!keep.length) { this.dispose(); return; }
|
|
77
|
+
using indices = ops.fromInt32([...keep], [keep.length]);
|
|
78
|
+
const hidden = ops.takeAxis(this.#hidden!, indices, 0);
|
|
79
|
+
try { this.#cache.filterRows(keep); } catch (error) { hidden.dispose(); throw error; }
|
|
80
|
+
this.#hidden!.dispose(); this.#hidden = hidden;
|
|
81
|
+
this.#processed = keep.map(row => this.#processed[row]!);
|
|
82
|
+
}
|
|
83
|
+
async draft(pending: readonly number[], depth: number, steps: readonly number[]): Promise<number[][]> {
|
|
84
|
+
const B = pending.length, tokens: MlxArray[] = [];
|
|
85
|
+
let ids: MlxArray | null = ops.fromInt32([...pending], [B, 1]), chained: MlxArray | null = null;
|
|
86
|
+
this.#cache.specRoundBegin();
|
|
87
|
+
try {
|
|
88
|
+
for (let position = 0; position < depth; position++) {
|
|
89
|
+
const hidden = await this.graph.forward(ids!, chained ?? this.#hidden!, this.#cache);
|
|
90
|
+
chained?.dispose(); chained = hidden;
|
|
91
|
+
using logits = this.graph.project(hidden);
|
|
92
|
+
using flat = ops.reshape(logits, [B, logits.shape.at(-1)!]);
|
|
93
|
+
using logprobs = toLogprobs(flat);
|
|
94
|
+
const next = this.sampling!.sample(logprobs, steps.map(step => step + position));
|
|
95
|
+
tokens.push(next); ids!.dispose(); ids = ops.reshape(next, [B, 1]);
|
|
96
|
+
}
|
|
97
|
+
using packed = depth ? ops.concatAxis(tokens, 0) : null;
|
|
98
|
+
const read = packed?.toIntTokens() ?? [];
|
|
99
|
+
this.#drafts = Array.from({ length: B }, (_, row) =>
|
|
100
|
+
Array.from({ length: depth }, (_, position) => read[position * B + row]!));
|
|
101
|
+
this.#depth = depth; return this.#drafts;
|
|
102
|
+
} finally { ids?.dispose(); chained?.dispose(); disposeResources(tokens); }
|
|
103
|
+
}
|
|
104
|
+
async commit(accepted: readonly number[], context: MlxArray): Promise<void> {
|
|
105
|
+
const B = accepted.length, width = Math.max(...accepted);
|
|
106
|
+
if (this.#depth) this.#cache.specRoundRollback(1);
|
|
107
|
+
else this.#cache.specRoundCommit();
|
|
108
|
+
if (width) {
|
|
109
|
+
using ids = ops.fromInt32(this.#drafts.flatMap(tokens => Array.from({ length: width }, (_, i) => tokens[i] ?? 0)), [B, width]);
|
|
110
|
+
using hidden = context.slice([0, 0, 0], [B, width, context.shape[2]!]);
|
|
111
|
+
this.#cache.specRoundBegin();
|
|
112
|
+
using output = await this.graph.forward(ids, hidden, this.#cache);
|
|
113
|
+
output.eval(); this.#cache.specRoundRollback(accepted);
|
|
114
|
+
}
|
|
115
|
+
using positions = ops.fromInt32([...accepted], [B, 1, 1]);
|
|
116
|
+
const hidden = ops.takeAlongAxis(context, positions, 1);
|
|
117
|
+
this.#hidden!.dispose(); this.#hidden = hidden;
|
|
118
|
+
this.#processed = this.#processed.map((count, row) => count + 1 + accepted[row]!);
|
|
119
|
+
this.#drafts = []; this.#depth = 0;
|
|
120
|
+
}
|
|
121
|
+
extractRow(row: number): Glm52MtpRowState {
|
|
122
|
+
const cache = this.#cache.extractRow(row);
|
|
123
|
+
try {
|
|
124
|
+
using hidden = this.#hidden!.slice([row, 0, 0], [row + 1, 1, this.#hidden!.shape[2]!]);
|
|
125
|
+
return { cache, hidden: materializeCopy(hidden), processedTokens: this.#processed[row]! };
|
|
126
|
+
} catch (error) { cache.dispose(); throw error; }
|
|
127
|
+
}
|
|
128
|
+
dispose(): void {
|
|
129
|
+
this.#cache.dispose(); this.#hidden?.dispose(); this.#hidden = null;
|
|
130
|
+
this.#processed = []; this.#drafts = []; this.#depth = 0;
|
|
131
|
+
}
|
|
132
|
+
}
|