mlx-bun 0.2.0 → 0.3.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 +91 -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/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +394 -159
- package/docs/reference/distribution.md +321 -182
- package/docs/reference/environment.md +348 -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 +104 -6
- package/docs/reference/server-api.md +886 -425
- package/docs/reference/server-config.md +638 -330
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -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.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +58 -25
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -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/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -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 +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -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 +1 -1
- package/src/generate.ts +656 -268
- 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/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-store.ts +109 -49
- 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/{model → lab/paged-kv}/paged-kv.ts +9 -6
- 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 +9 -10
- 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/batched-mask.ts +8 -2
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +2 -2
- package/src/model/batched-rotating.ts +1 -1
- package/src/model/compiled-decode.ts +1 -1
- 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/gemma4-base.ts +26 -9
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +2 -2
- package/src/model/generated/gemma4-26b.ts +2 -2
- package/src/model/generated/gemma4-e4b.ts +2 -2
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +6 -8
- 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_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +140 -56
- 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/universal/dense.ts +1 -1
- 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/prompt-cache.ts +96 -53
- 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 +4 -4
- 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 +154 -193
- 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 +512 -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 +19 -15
- package/src/serve/request-prep.ts +346 -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 +317 -2649
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +8 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- 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 +4 -3
- 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-source.ts +1 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +166 -69
- package/src/spec/serve-loop.ts +154 -156
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +80 -12
- package/src/ssd-durability.ts +25 -13
- 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 +5 -3
- 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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ModelConfig } from "../config";
|
|
2
|
+
import {
|
|
3
|
+
assertResolvedModelProfile,
|
|
4
|
+
type GenerationLoop,
|
|
5
|
+
type ModelGraph,
|
|
6
|
+
type ModelLoader,
|
|
7
|
+
type ResolvedModelProfile,
|
|
8
|
+
} from "./profile";
|
|
9
|
+
|
|
10
|
+
/** Engine code implements this port. Source and Model remain backend-specific;
|
|
11
|
+
* selection introduces no tensor conversion or dispatch in the token loop.
|
|
12
|
+
* create borrows source; a failed construction must release its own resources. */
|
|
13
|
+
export interface ModelImplementation<Source, Model> {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly graph: ModelGraph;
|
|
16
|
+
readonly loader: ModelLoader;
|
|
17
|
+
readonly loop: GenerationLoop;
|
|
18
|
+
create(source: Source, config: ModelConfig, profile: ResolvedModelProfile): Model;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ModelImplementationProvider<Source, Model> {
|
|
22
|
+
/** Validate identity and composition, then return one compatible binding.
|
|
23
|
+
* A declared implementation must never silently fall back to another. */
|
|
24
|
+
select(config: ModelConfig, profile: ResolvedModelProfile): ModelImplementation<Source, Model>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Immutable composition, with identity matching delegated to model profiles.
|
|
28
|
+
* Exact declarations are requirements: absent/incompatible code is an error,
|
|
29
|
+
* never an invitation to retry with a different numerical implementation. */
|
|
30
|
+
export class ModelImplementationRegistry<Source, Model> implements ModelImplementationProvider<Source, Model> {
|
|
31
|
+
private readonly entries: ReadonlyMap<string, ModelImplementation<Source, Model>>;
|
|
32
|
+
|
|
33
|
+
constructor(implementations: readonly ModelImplementation<Source, Model>[]) {
|
|
34
|
+
const entries = new Map<string, ModelImplementation<Source, Model>>();
|
|
35
|
+
for (const implementation of implementations) {
|
|
36
|
+
if (!implementation.id.trim()) throw new Error("model implementation id must not be empty");
|
|
37
|
+
if (entries.has(implementation.id))
|
|
38
|
+
throw new Error(`duplicate model implementation ${implementation.id}`);
|
|
39
|
+
entries.set(implementation.id, Object.freeze({
|
|
40
|
+
id: implementation.id,
|
|
41
|
+
graph: implementation.graph,
|
|
42
|
+
loader: implementation.loader,
|
|
43
|
+
loop: implementation.loop,
|
|
44
|
+
create: implementation.create.bind(implementation),
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
this.entries = entries;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Return a new composition; active models retain their existing binding. */
|
|
51
|
+
with(...implementations: readonly ModelImplementation<Source, Model>[]): ModelImplementationRegistry<Source, Model> {
|
|
52
|
+
return new ModelImplementationRegistry([...this.entries.values(), ...implementations]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
select(config: ModelConfig, profile: ResolvedModelProfile): ModelImplementation<Source, Model> {
|
|
56
|
+
assertResolvedModelProfile(config, profile);
|
|
57
|
+
const execution = profile.profile.execution;
|
|
58
|
+
// These default IDs preserve the existing dedicated/generated/family choice.
|
|
59
|
+
const id = execution.implementation ?? (execution.specialization === "generated"
|
|
60
|
+
? `${execution.graph}-generated` : execution.graph);
|
|
61
|
+
const implementation = this.entries.get(id);
|
|
62
|
+
if (!implementation)
|
|
63
|
+
throw new Error(`model profile ${profile.profile.id} requires unavailable implementation ${id}; refusing to fall back`);
|
|
64
|
+
if (implementation.graph !== execution.graph || implementation.loader !== execution.loader ||
|
|
65
|
+
implementation.loop !== execution.loop)
|
|
66
|
+
throw new Error(`model implementation ${id} is incompatible with profile ${profile.profile.id}; refusing to fall back`);
|
|
67
|
+
return implementation;
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/model/minicpm5.ts
CHANGED
|
@@ -30,7 +30,7 @@ import { runtimeValue } from "../runtime-config";
|
|
|
30
30
|
* `@partial(mx.compile, shapeless=True) def swiglu(gate, x): return nn.silu(gate) * x`
|
|
31
31
|
* mx.compile fuses sigmoid + mul + mul into ONE kernel (mlx-lm's decode
|
|
32
32
|
* `CV2ISigmoid…Multiply`) instead of our three separate dispatches. Traced
|
|
33
|
-
* once, replayed thereafter
|
|
33
|
+
* once, replayed thereafter for decode and prefill. */
|
|
34
34
|
let _swigluClosure: CompiledFunction | null = null;
|
|
35
35
|
export function compiledSwiglu(gate: MlxArray, up: MlxArray): MlxArray {
|
|
36
36
|
if (!_swigluClosure) {
|
|
@@ -200,15 +200,13 @@ export class LlamaMLP {
|
|
|
200
200
|
|
|
201
201
|
/** MLP: returns mlp(x); the caller adds the residual when given. */
|
|
202
202
|
forward(x: MlxArray, residual?: MlxArray): MlxArray {
|
|
203
|
-
const H = x.shape[x.shape.length - 1]!;
|
|
204
|
-
const M = x.shape.reduce((a, b) => a * b, 1) / H;
|
|
205
203
|
const gate = this.gate.forward(x);
|
|
206
204
|
const up = this.up.forward(x);
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
// trace
|
|
205
|
+
// Match mlx_lm activations.py at every sequence length. Separate kernels
|
|
206
|
+
// differ numerically on MLX 0.32.2 at larger prefill shapes. An enclosing
|
|
207
|
+
// compiled trace owns fusion itself; the explicit opt-out stays available.
|
|
210
208
|
let hidden: MlxArray;
|
|
211
|
-
if (
|
|
209
|
+
if (!isCompiledTrace() && runtimeValue("MLX_BUN_COMPILED_SWIGLU") !== "0") {
|
|
212
210
|
hidden = compiledSwiglu(gate, up);
|
|
213
211
|
gate.dispose();
|
|
214
212
|
up.dispose();
|
|
@@ -321,7 +319,7 @@ export class MiniCPM5Model {
|
|
|
321
319
|
* NEVER disposed — the caller owns it (for segmented backward `h` is a leaf
|
|
322
320
|
* whose lifetime is managed by the autograd closure); intra-range
|
|
323
321
|
* intermediates ARE disposed. Building block for `forwardLayers` and the
|
|
324
|
-
* segmented-backward training path (docs/design/
|
|
322
|
+
* segmented-backward training path (docs/design/orpo-training.md).
|
|
325
323
|
* MiniCPM5 is plain full-attention with no KV-sharing, so each layer reads
|
|
326
324
|
* its own stateless `cache[i]` and a single causal mask. */
|
|
327
325
|
runLayerRange(h: MlxArray, aIdx: number, bIdx: number, cache: Cache[]): MlxArray {
|
package/src/model/profile.ts
CHANGED
|
@@ -58,6 +58,9 @@ export interface ModelExecutionComposition {
|
|
|
58
58
|
readonly graph: ModelGraph;
|
|
59
59
|
readonly loop: GenerationLoop;
|
|
60
60
|
readonly specialization: ModelSpecialization;
|
|
61
|
+
/** Engine-owned code registration. Model files never supply executable code.
|
|
62
|
+
* Omit to retain the existing graph implementation. */
|
|
63
|
+
readonly implementation?: string;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
/** A profile declares construction only. Request methods such as MTP, KV
|
|
@@ -323,6 +326,10 @@ function executionCapabilities(profile: ModelProfile): EngineCapability[] {
|
|
|
323
326
|
|
|
324
327
|
function validateProfile(profile: ModelProfile): void {
|
|
325
328
|
if (!profile.id) throw new Error("model profile id must not be empty");
|
|
329
|
+
if (profile.execution.implementation !== undefined &&
|
|
330
|
+
(!profile.execution.implementation.trim() || !profile.artifactFingerprint ||
|
|
331
|
+
profile.execution.specialization !== "artifact"))
|
|
332
|
+
throw new Error(`model profile ${profile.id} must bind a named implementation to an exact artifact`);
|
|
326
333
|
if ((profile.artifactFingerprint === undefined) !== (profile.configFingerprint === undefined))
|
|
327
334
|
throw new Error(
|
|
328
335
|
`model profile ${profile.id} must declare artifactFingerprint and configFingerprint together`,
|
|
@@ -413,6 +420,7 @@ export function assertResolvedModelProfile(
|
|
|
413
420
|
config: ModelConfig,
|
|
414
421
|
resolved: ResolvedModelProfile,
|
|
415
422
|
): void {
|
|
423
|
+
validateProfile(resolved.profile);
|
|
416
424
|
const fingerprint = configFingerprint(config);
|
|
417
425
|
if (resolved.artifact.configFingerprint !== fingerprint)
|
|
418
426
|
throw new Error(
|
|
@@ -424,8 +432,10 @@ export function assertResolvedModelProfile(
|
|
|
424
432
|
`model profile ${resolved.profile.id} selects ${resolved.profile.execution.graph}, ` +
|
|
425
433
|
`which is incompatible with ${config.modelType}`,
|
|
426
434
|
);
|
|
427
|
-
if (resolved.exactArtifact
|
|
428
|
-
resolved.
|
|
435
|
+
if (resolved.exactArtifact !== (resolved.profile.artifactFingerprint !== undefined) ||
|
|
436
|
+
(resolved.exactArtifact &&
|
|
437
|
+
(resolved.profile.artifactFingerprint !== resolved.artifact.fingerprint ||
|
|
438
|
+
resolved.profile.configFingerprint !== fingerprint)))
|
|
429
439
|
throw new Error(
|
|
430
440
|
`model profile ${resolved.profile.id} does not match artifact ` +
|
|
431
441
|
`${resolved.artifact.fingerprint ?? "<unidentified>"}`,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// MLX 0.32.2, mlx/backend/metal/scaled_dot_product_attention.cpp (MIT):
|
|
2
|
+
// https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/scaled_dot_product_attention.cpp
|
|
3
|
+
// For the qualified Qwen GQA-6/D256 graph on applegpu_g16s, one-pass/vector
|
|
4
|
+
// selection and two-pass block counts change after these inclusive KV lengths.
|
|
5
|
+
// A committed span must stay within one arithmetic regime to match M=1.
|
|
6
|
+
const ATTENTION_BOUNDARIES = [1023, 1024, 8192, 32768, 65536];
|
|
7
|
+
|
|
8
|
+
export function qwenAppendChunkSize(cacheTokens: number): number {
|
|
9
|
+
for (const end of ATTENTION_BOUNDARIES)
|
|
10
|
+
if (cacheTokens < end) return Math.min(4, end - cacheTokens);
|
|
11
|
+
return 4;
|
|
12
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Experimental Qwen GDN convolution. Its two outputs are evaluated together:
|
|
2
|
+
// consuming the activation also materializes the small, independently owned
|
|
3
|
+
// state tail, without keeping a concatenated prefill buffer alive for it.
|
|
4
|
+
// Arithmetic follows MLX 0.31.2 depthwise_conv_1d and unary sigmoid (MIT,
|
|
5
|
+
// Copyright Apple Inc.), preserving the bf16 intermediate rounding.
|
|
6
|
+
import type { MlxArray } from "../mlx/array";
|
|
7
|
+
import { Dtype } from "../mlx/ffi";
|
|
8
|
+
import { MetalKernel } from "../mlx/metal-kernel";
|
|
9
|
+
|
|
10
|
+
/** Borrow all inputs; return owned activation and an independent state tail. */
|
|
11
|
+
export type QwenConvolution = (x: MlxArray, state: MlxArray, weight: MlxArray) => [MlxArray, MlxArray];
|
|
12
|
+
|
|
13
|
+
let kernel: MetalKernel | null = null;
|
|
14
|
+
export const fusedQwenConvolution: QwenConvolution = (x, state, weight) => {
|
|
15
|
+
const [B, M, D] = x.shape as [number, number, number];
|
|
16
|
+
const K = weight.shape[1]!;
|
|
17
|
+
if (x.shape.length !== 3 || weight.shape.length !== 3 || weight.shape[0] !== D ||
|
|
18
|
+
weight.shape[2] !== 1 || K !== 4 || state.shape.join() !== [B, K - 1, D].join() ||
|
|
19
|
+
![Dtype.bfloat16, Dtype.float32].includes(x.dtype) || state.dtype !== x.dtype || weight.dtype !== x.dtype)
|
|
20
|
+
throw new Error("fused Qwen convolution requires matching bf16/f32 inputs, [B,M,D], [B,3,D], [D,4,1]");
|
|
21
|
+
kernel ??= new MetalKernel({ name: "qwen_causal_conv_silu_tail",
|
|
22
|
+
inputNames: ["state", "x", "w"], outputNames: ["out", "tail"],
|
|
23
|
+
source: String.raw`
|
|
24
|
+
const uint c = thread_position_in_grid.x;
|
|
25
|
+
const uint t = thread_position_in_grid.y;
|
|
26
|
+
const uint b = thread_position_in_grid.z;
|
|
27
|
+
if (c >= D) return;
|
|
28
|
+
if (t < M) {
|
|
29
|
+
float acc = 0.0f;
|
|
30
|
+
for (uint i = 0; i < K; ++i) {
|
|
31
|
+
const uint row = t + i;
|
|
32
|
+
const T value = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
|
|
33
|
+
acc += float(value) * float(w[c*K+i]);
|
|
34
|
+
}
|
|
35
|
+
const T conv = T(acc);
|
|
36
|
+
// Preserve the pinned MLX sigmoid's typed operations and bf16
|
|
37
|
+
// intermediate rounding. Promoting this expression to f32 differs.
|
|
38
|
+
const auto y = 1 / (1 + metal::exp(metal::abs(conv)));
|
|
39
|
+
const T sig = conv < 0 ? y : 1-y;
|
|
40
|
+
out[(b*M+t)*D+c] = conv * sig;
|
|
41
|
+
}
|
|
42
|
+
if (t < K-1) {
|
|
43
|
+
const uint row = M + t;
|
|
44
|
+
tail[(b*(K-1)+t)*D+c] = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
|
|
45
|
+
}
|
|
46
|
+
` });
|
|
47
|
+
return kernel.apply([state, x, weight], {
|
|
48
|
+
outputs: [{ shape: [B, M, D], dtype: x.dtype }, { shape: [B, K - 1, D], dtype: x.dtype }],
|
|
49
|
+
grid: [D, Math.max(M, K - 1), B], threadGroup: [256, 1, 1],
|
|
50
|
+
templateDtypes: { T: x.dtype }, templateInts: { D, M, K },
|
|
51
|
+
}) as [MlxArray, MlxArray];
|
|
52
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Qwen3.5 checkpoint-generation normalization — the load-seam port of
|
|
2
|
+
// mlx_lm.models.qwen3_5's `Model.sanitize` + `TextModel.sanitize`.
|
|
3
|
+
//
|
|
4
|
+
// Two checkpoint generations ship the same graph under different conventions:
|
|
5
|
+
//
|
|
6
|
+
// pre-5.8 (mlx-lm-converted) 5.8-family (transformers 5.8.0 export)
|
|
7
|
+
// ────────────────────────── ───────────────────────────────────────
|
|
8
|
+
// language_model.model.* model.language_model.*
|
|
9
|
+
// language_model.lm_head.* lm_head.* (top level)
|
|
10
|
+
// vision_tower.* model.visual.*
|
|
11
|
+
// (no mtp tensors in-repo) mtp.* (in-repo)
|
|
12
|
+
// conv1d.weight [C, K, 1] conv1d.weight [C, 1, K] (HF layout)
|
|
13
|
+
// RMSNorm gains stored as γ RMSNorm gains stored as γ−1
|
|
14
|
+
//
|
|
15
|
+
// Our graph speaks the FIRST column (`PREFIX = "language_model"` in
|
|
16
|
+
// qwen3_5.ts) — which is exactly mlx-lm's post-sanitize name space — so this
|
|
17
|
+
// module maps the artifact onto it instead of teaching every consumer two
|
|
18
|
+
// namings. The rules below are a line-for-line copy of the oracle; see
|
|
19
|
+
// mlx_lm/models/qwen3_5.py `Model.sanitize` (naming/drop) and
|
|
20
|
+
// `TextModel.sanitize` (γ shift, conv layout).
|
|
21
|
+
//
|
|
22
|
+
// The γ shift is the dangerous one: a spurious +1.0 silently corrupts an old
|
|
23
|
+
// artifact. The oracle's discriminator is NOT the naming — it is
|
|
24
|
+
// should_shift = any("mtp." in k) or any conv1d.weight with shape[-1] != 1
|
|
25
|
+
// evaluated over the whole (post-rename, pre-drop) weight map. Reproduced
|
|
26
|
+
// verbatim. Measured on the two artifacts in play (2026-09-01, M1 Max):
|
|
27
|
+
// • ~/.cache/…/models--mjriii--Qwen3.8-27B/snapshots/staged — no mtp.*,
|
|
28
|
+
// conv1d [10240,4,1] → no shift; layer-0 input_layernorm ≡ 1.0.
|
|
29
|
+
// • /Volumes/MLX-Models/models/mjriii/Qwen3.8-27B-{tqalloc-norot,rtn4-g64}
|
|
30
|
+
// — 31 mtp.* tensors, conv1d [10240,1,4] → shift; layer-0
|
|
31
|
+
// input_layernorm mean −0.0334 (= γ−1), byte-identical to the raw
|
|
32
|
+
// Qwen/Qwen3.8-27B 5.8 checkpoint (the quantizer copies norms verbatim).
|
|
33
|
+
|
|
34
|
+
import type { MlxArray } from "../mlx/array";
|
|
35
|
+
import * as ops from "../mlx/ops";
|
|
36
|
+
import type { Weights, WeightsView } from "../weights";
|
|
37
|
+
|
|
38
|
+
/** Header-level facts about one stored tensor (no bytes are read). */
|
|
39
|
+
export interface CheckpointTensor {
|
|
40
|
+
readonly name: string;
|
|
41
|
+
readonly shape: readonly number[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Qwen35Sanitized {
|
|
45
|
+
/** canonical (graph) name → the name the artifact actually stores. */
|
|
46
|
+
readonly names: Map<string, string>;
|
|
47
|
+
/** Canonical names stored as γ−1: a +1.0 is due at load. */
|
|
48
|
+
readonly normShift: Set<string>;
|
|
49
|
+
/** Canonical names in HF conv layout: a moveaxis(2, 1) is due at load. */
|
|
50
|
+
readonly convMoveaxis: Set<string>;
|
|
51
|
+
/** True when the artifact already IS our canonical layout — no view needed
|
|
52
|
+
* and the pre-existing load path runs untouched. */
|
|
53
|
+
readonly identity: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** mlx-lm `TextModel.sanitize` norm_keys, verbatim and in order. */
|
|
57
|
+
const NORM_KEYS = [
|
|
58
|
+
".input_layernorm.weight",
|
|
59
|
+
".post_attention_layernorm.weight",
|
|
60
|
+
"model.norm.weight",
|
|
61
|
+
".q_norm.weight",
|
|
62
|
+
".k_norm.weight",
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
/** mlx-lm `Model.sanitize`: drop vision, fold every naming onto
|
|
66
|
+
* `language_model.…`. Returns null for a dropped tensor. */
|
|
67
|
+
function canonicalName(key: string): string | null {
|
|
68
|
+
if (key.startsWith("vision_tower") || key.startsWith("model.visual")) return null;
|
|
69
|
+
if (key.startsWith("model.language_model"))
|
|
70
|
+
return "language_model.model" + key.slice("model.language_model".length);
|
|
71
|
+
if (key.startsWith("language_model.")) return key;
|
|
72
|
+
return "language_model." + key;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Port of mlx_lm.models.qwen3_5 `Model.sanitize` ∘ `TextModel.sanitize`,
|
|
77
|
+
* name/shape half. Pure: takes header facts, returns the load plan.
|
|
78
|
+
*/
|
|
79
|
+
export function sanitizeQwen35Checkpoint(
|
|
80
|
+
tensors: Iterable<CheckpointTensor>,
|
|
81
|
+
): Qwen35Sanitized {
|
|
82
|
+
// Pass 1 — rename (vision dropped), exactly as Model.sanitize.
|
|
83
|
+
const renamed: { canonical: string; source: string; shape: readonly number[] }[] = [];
|
|
84
|
+
let sawForeignName = false;
|
|
85
|
+
for (const t of tensors) {
|
|
86
|
+
const canonical = canonicalName(t.name);
|
|
87
|
+
if (canonical === null) {
|
|
88
|
+
sawForeignName ||= t.name.startsWith("model.visual");
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (canonical !== t.name) sawForeignName = true;
|
|
92
|
+
renamed.push({ canonical, source: t.name, shape: t.shape });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Pass 2 — TextModel.sanitize's two flags, over the renamed map BEFORE the
|
|
96
|
+
// mtp drop (the oracle computes them first, then filters).
|
|
97
|
+
const hasMtpWeights = renamed.some((t) => t.canonical.includes("mtp."));
|
|
98
|
+
const hasUnsanitizedConv1d = renamed.some(
|
|
99
|
+
(t) => t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1,
|
|
100
|
+
);
|
|
101
|
+
const shouldShiftNormWeights = hasMtpWeights || hasUnsanitizedConv1d;
|
|
102
|
+
|
|
103
|
+
const names = new Map<string, string>();
|
|
104
|
+
const normShift = new Set<string>();
|
|
105
|
+
const convMoveaxis = new Set<string>();
|
|
106
|
+
for (const t of renamed) {
|
|
107
|
+
if (t.canonical.includes("mtp.")) continue; // oracle drops these outright
|
|
108
|
+
names.set(t.canonical, t.source);
|
|
109
|
+
if (t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1)
|
|
110
|
+
convMoveaxis.add(t.canonical);
|
|
111
|
+
if (
|
|
112
|
+
shouldShiftNormWeights &&
|
|
113
|
+
NORM_KEYS.some((sfx) => t.canonical.endsWith(sfx)) &&
|
|
114
|
+
t.shape.length === 1
|
|
115
|
+
)
|
|
116
|
+
normShift.add(t.canonical);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
names,
|
|
121
|
+
normShift,
|
|
122
|
+
convMoveaxis,
|
|
123
|
+
identity: !sawForeignName && !hasMtpWeights && !shouldShiftNormWeights &&
|
|
124
|
+
convMoveaxis.size === 0,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The {@link WeightsView} for a qwen3.5 artifact, or null when the artifact is
|
|
130
|
+
* already canonical (then nothing is installed and the load path is bit-for-bit
|
|
131
|
+
* what it was before this seam existed).
|
|
132
|
+
*/
|
|
133
|
+
export function qwen35WeightsView(weights: Weights): WeightsView | null {
|
|
134
|
+
const plan = sanitizeQwen35Checkpoint(
|
|
135
|
+
weights.tensorNames.map((name) => ({ name, shape: weights.info(name).shape })),
|
|
136
|
+
);
|
|
137
|
+
if (plan.identity) return null;
|
|
138
|
+
return {
|
|
139
|
+
names: plan.names,
|
|
140
|
+
fixup(canonical: string, arr: MlxArray): MlxArray | null {
|
|
141
|
+
// Oracle order: moveaxis first, then the γ shift (disjoint sets — a
|
|
142
|
+
// conv1d weight is 3-D and never a norm gain).
|
|
143
|
+
if (plan.convMoveaxis.has(canonical)) {
|
|
144
|
+
// `v.moveaxis(2, 1)` on [C, 1, K] → [C, K, 1]. Materialized: the
|
|
145
|
+
// conv1d kernel consumes it every forward, and the transposed view
|
|
146
|
+
// would otherwise pin the source shard buffer.
|
|
147
|
+
const moved = ops.transposeAxes(arr, [0, 2, 1]);
|
|
148
|
+
const out = ops.contiguous(moved);
|
|
149
|
+
moved.dispose();
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
if (plan.normShift.has(canonical)) {
|
|
153
|
+
// `v + 1.0` — a weak python scalar, so the add happens at the gain's
|
|
154
|
+
// own dtype (bf16 here); scalarLike builds the constant host-side at
|
|
155
|
+
// that dtype for the same single-kernel add the reference dispatches.
|
|
156
|
+
const one = ops.scalarLike(1, arr);
|
|
157
|
+
const out = ops.add(arr, one);
|
|
158
|
+
one.dispose();
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|