mlx-bun 0.4.0 → 1.0.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 +1453 -88
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +10 -8
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +12 -10
- package/src/{serve → server}/chat-stage.ts +27 -22
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +42 -42
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +42 -83
- package/src/server/generated-token-history.ts +57 -0
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +8 -8
- package/src/{serve → server}/request-prep.ts +82 -68
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -94
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -1841
- package/docs/design/decode-speed-program.md +0 -2349
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -705
- package/docs/design/kv-cache.md +0 -824
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -1990
- package/docs/design/turboquant.md +0 -2212
- package/docs/design/unified-engine-frontier-plan.md +0 -1880
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -594
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/release-notes-v0.4.0.md +0 -45
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3613
- package/docs/reference/cli.md +0 -585
- package/docs/reference/distribution.md +0 -355
- package/docs/reference/environment.md +0 -398
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -674
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -334
- package/docs/reference/server-api.md +0 -1775
- package/docs/reference/server-config.md +0 -846
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/conformer.ts +0 -647
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/transcode.ts +0 -67
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -108
- package/src/backends/mlx/batch-group.ts +0 -1790
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -106
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -45
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -130
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -133
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/model-prompt.ts +0 -164
- package/src/backends/mlx/model-serving.ts +0 -79
- package/src/backends/mlx/prefill-cohort.ts +0 -89
- package/src/backends/mlx/prefill-rows.ts +0 -200
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -41
- package/src/backends/mlx/rollback.ts +0 -89
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -242
- package/src/backends/mlx/speculative-group.ts +0 -359
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -114
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3168
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -60
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -259
- package/src/contracts/prefix-cache.ts +0 -23
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -45
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -53
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -72
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -452
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1346
- package/src/grammar.ts +0 -591
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -39
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -257
- package/src/kv-store.ts +0 -1099
- package/src/lab/README.md +0 -18
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
- package/src/lab/paged-kv/paged-kv.ts +0 -270
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -49
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -388
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -512
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/ops.ts +0 -1021
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -93
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -55
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -189
- package/src/model/fingerprint.ts +0 -33
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2351
- package/src/model/gemma4.ts +0 -1315
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -67
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -443
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -252
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -819
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -102
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -83
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native-pack.ts +0 -162
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1932
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -460
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -81
- package/src/safetensors.ts +0 -158
- package/src/sampler.ts +0 -1011
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -496
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -43
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -147
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/server.ts +0 -1314
- package/src/spec/assistant-rows.ts +0 -92
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -317
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -204
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -219
- package/src/spec/qwen-mtp-source.ts +0 -383
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -585
- package/src/spec/source.ts +0 -215
- package/src/spec/two-model-rows.ts +0 -61
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -372
- package/src/ssd-durability.ts +0 -211
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -168
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -373
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -196
- package/src/vision/qwen3vl-tower.ts +0 -555
- package/src/vision/siglip.ts +0 -599
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2143
- package/src/web/app.js +0 -5703
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1057
- package/src/web/src/composer.ts +0 -959
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
package/src/model/qwen3-moe.ts
DELETED
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
// Concrete model graph for Qwen3-MoE (model_type `qwen3_moe`,
|
|
2
|
-
// Qwen3MoeForCausalLM). A STRAIGHT op-for-op transcription of the oracle
|
|
3
|
-
// (`/Users/joshrossi/Code/mlx-lm/.venv/.../mlx_lm/models/qwen3_moe.py` +
|
|
4
|
-
// switch_layers.py SwitchGLU + activations.py swiglu). Each op below carries
|
|
5
|
-
// the exact oracle line it copies — no abstraction, no reorder, no
|
|
6
|
-
// "optimization". The ONLY intentional deviation from a naive transcription is
|
|
7
|
-
// that the expert swiglu is mx.compile-COMPILED (like the oracle's
|
|
8
|
-
// activations.py `@partial(mx.compile) def swiglu`), matching both the greedy
|
|
9
|
-
// token stream AND the dispatched Metal kernel set.
|
|
10
|
-
//
|
|
11
|
-
// Attention is identical to plain qwen3 (per-head q/k RMSNorm over head_dim
|
|
12
|
-
// before RoPE, full-head RoPE, GQA, SDPA). The MoE block is
|
|
13
|
-
// Qwen3MoeSparseMoeBlock: gate Linear -> precise softmax over ALL experts ->
|
|
14
|
-
// argpartition top-k -> take_along_axis -> renormalize (norm_topk_prob) ->
|
|
15
|
-
// SwitchGLU(swiglu) experts -> weighted sum. Per decoder_sparse_step /
|
|
16
|
-
// mlp_only_layers a layer may instead be a dense MLP (MLP class); both are
|
|
17
|
-
// handled faithfully. Weights are untied (separate lm_head). Config: 48 layers,
|
|
18
|
-
// hidden 2048, 128 experts, top-8, moe_intermediate 768, rope_theta 1e7.
|
|
19
|
-
|
|
20
|
-
import type { ModelConfig } from "../config";
|
|
21
|
-
import type { Weights } from "../weights";
|
|
22
|
-
import { MlxArray } from "../mlx/array";
|
|
23
|
-
import * as ops from "../mlx/ops";
|
|
24
|
-
import { CompiledFunction } from "../mlx/compile";
|
|
25
|
-
import {
|
|
26
|
-
argmaxLastPosition,
|
|
27
|
-
disposing,
|
|
28
|
-
isCompiledTrace,
|
|
29
|
-
KVCache,
|
|
30
|
-
LoraState,
|
|
31
|
-
QuantizedEmbedding,
|
|
32
|
-
QuantizedLinear,
|
|
33
|
-
QuantizedSwitchLinear,
|
|
34
|
-
RMSNorm,
|
|
35
|
-
type Cache,
|
|
36
|
-
type Mask,
|
|
37
|
-
} from "./gemma4-base";
|
|
38
|
-
|
|
39
|
-
// ── activations.py swiglu (mx.compile) ───────────────────────────────────────
|
|
40
|
-
// `@partial(mx.compile, shapeless=True) def swiglu(gate, x): return nn.silu(gate) * x`
|
|
41
|
-
// nn.silu(g) == g * sigmoid(g); mx.compile fuses sigmoid + mul + mul into ONE
|
|
42
|
-
// kernel. Traced once (shapeless), replayed thereafter. Autograd-safe (mx.compile
|
|
43
|
-
// threads the VJP through the traced graph). Exported so the parity test can
|
|
44
|
-
// assert the closure exists and the expert path actually uses it.
|
|
45
|
-
let _swigluClosure: CompiledFunction | null = null;
|
|
46
|
-
export function compiledSwiglu(gate: MlxArray, up: MlxArray): MlxArray {
|
|
47
|
-
if (!_swigluClosure) {
|
|
48
|
-
_swigluClosure = new CompiledFunction((inputs) => {
|
|
49
|
-
const g = inputs[0]!, u = inputs[1]!; // nn.silu(gate) * x
|
|
50
|
-
const sig = ops.sigmoid(g);
|
|
51
|
-
const silu = ops.mul(g, sig); sig.dispose();
|
|
52
|
-
const out = ops.mul(silu, u); silu.dispose();
|
|
53
|
-
return [out];
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
return _swigluClosure.apply([gate, up])[0]!;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ── qwen3_moe.py Attention (== plain qwen3) ──────────────────────────────────
|
|
60
|
-
class Attention {
|
|
61
|
-
readonly qProj: QuantizedLinear;
|
|
62
|
-
readonly kProj: QuantizedLinear;
|
|
63
|
-
readonly vProj: QuantizedLinear;
|
|
64
|
-
readonly oProj: QuantizedLinear;
|
|
65
|
-
readonly qNorm: RMSNorm;
|
|
66
|
-
readonly kNorm: RMSNorm;
|
|
67
|
-
readonly nHeads: number;
|
|
68
|
-
readonly nKvHeads: number;
|
|
69
|
-
readonly headDim: number;
|
|
70
|
-
readonly scale: number;
|
|
71
|
-
readonly ropeBase: number;
|
|
72
|
-
|
|
73
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
74
|
-
const t = config.text;
|
|
75
|
-
this.nHeads = t.numAttentionHeads; // self.n_heads
|
|
76
|
-
this.nKvHeads = t.numKeyValueHeads; // self.n_kv_heads
|
|
77
|
-
this.headDim = t.headDim; // head_dim
|
|
78
|
-
this.scale = Math.pow(this.headDim, -0.5); // self.scale = head_dim**-0.5
|
|
79
|
-
this.ropeBase = t.ropeParameters.full_attention?.ropeTheta ?? 10000000; // args.rope_theta
|
|
80
|
-
this.qProj = QuantizedLinear.load(weights, `${prefix}.q_proj`, config); // nn.Linear(dim, n_heads*head_dim, bias=False)
|
|
81
|
-
this.kProj = QuantizedLinear.load(weights, `${prefix}.k_proj`, config);
|
|
82
|
-
this.vProj = QuantizedLinear.load(weights, `${prefix}.v_proj`, config);
|
|
83
|
-
this.oProj = QuantizedLinear.load(weights, `${prefix}.o_proj`, config);
|
|
84
|
-
this.qNorm = new RMSNorm(weights.tensor(`${prefix}.q_norm.weight`), t.rmsNormEps); // nn.RMSNorm(head_dim)
|
|
85
|
-
this.kNorm = new RMSNorm(weights.tensor(`${prefix}.k_norm.weight`), t.rmsNormEps);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
forward(x: MlxArray, mask: Mask, cache: Cache): MlxArray {
|
|
89
|
-
const [B, L] = x.shape as [number, number, number]; // B, L, D = x.shape
|
|
90
|
-
let q = this.qProj.forward(x); // queries = self.q_proj(x)
|
|
91
|
-
let k = this.kProj.forward(x); // keys = self.k_proj(x)
|
|
92
|
-
let v = this.vProj.forward(x); // values = self.v_proj(x)
|
|
93
|
-
// queries = self.q_norm(queries.reshape(B,L,n_heads,-1)).transpose(0,2,1,3)
|
|
94
|
-
q = disposing(q, ops.reshape(q, [B, L, this.nHeads, this.headDim]));
|
|
95
|
-
k = disposing(k, ops.reshape(k, [B, L, this.nKvHeads, this.headDim]));
|
|
96
|
-
v = disposing(v, ops.reshape(v, [B, L, this.nKvHeads, this.headDim]));
|
|
97
|
-
q = disposing(q, this.qNorm.forward(q)); // self.q_norm(...)
|
|
98
|
-
k = disposing(k, this.kNorm.forward(k)); // self.k_norm(...)
|
|
99
|
-
q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3])); // .transpose(0,2,1,3)
|
|
100
|
-
k = disposing(k, ops.transposeAxes(k, [0, 2, 1, 3]));
|
|
101
|
-
v = disposing(v, ops.transposeAxes(v, [0, 2, 1, 3])); // values.reshape(...).transpose(0,2,1,3)
|
|
102
|
-
q = disposing(q, ops.rope(q, this.headDim, this.ropeBase, cache.offset, null)); // self.rope(queries, offset=cache.offset)
|
|
103
|
-
k = disposing(k, ops.rope(k, this.headDim, this.ropeBase, cache.offset, null)); // self.rope(keys, offset=cache.offset)
|
|
104
|
-
const [keys, values] = cache.updateAndFetch(k, v); // cache.update_and_fetch(keys, values)
|
|
105
|
-
k.dispose(); v.dispose();
|
|
106
|
-
let out = ops.sdpa(q, keys, values, this.scale, mask.mode, mask.arr); // scaled_dot_product_attention(...)
|
|
107
|
-
q.dispose(); keys.dispose(); values.dispose();
|
|
108
|
-
out = disposing(out, ops.transposeAxes(out, [0, 2, 1, 3])); // output.transpose(0,2,1,3)
|
|
109
|
-
out = disposing(out, ops.reshape(out, [B, L, -1])); // .reshape(B, L, -1)
|
|
110
|
-
const y = this.oProj.forward(out); out.dispose(); // self.o_proj(output)
|
|
111
|
-
return y;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ── qwen3_moe.py MLP (dense-layer FFN) ───────────────────────────────────────
|
|
116
|
-
// def __call__(self, x): return self.down_proj(swiglu(self.gate_proj(x), self.up_proj(x)))
|
|
117
|
-
class MLP {
|
|
118
|
-
readonly gateProj: QuantizedLinear;
|
|
119
|
-
readonly upProj: QuantizedLinear;
|
|
120
|
-
readonly downProj: QuantizedLinear;
|
|
121
|
-
|
|
122
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
123
|
-
this.gateProj = QuantizedLinear.load(weights, `${prefix}.gate_proj`, config); // nn.Linear(dim, hidden_dim, bias=False)
|
|
124
|
-
this.upProj = QuantizedLinear.load(weights, `${prefix}.up_proj`, config);
|
|
125
|
-
this.downProj = QuantizedLinear.load(weights, `${prefix}.down_proj`, config);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
forward(x: MlxArray): MlxArray {
|
|
129
|
-
const g = this.gateProj.forward(x); // self.gate_proj(x)
|
|
130
|
-
const u = this.upProj.forward(x); // self.up_proj(x)
|
|
131
|
-
const s = compiledSwiglu(g, u); // swiglu(gate, x) (mx.compile)
|
|
132
|
-
g.dispose(); u.dispose();
|
|
133
|
-
const y = this.downProj.forward(s); s.dispose(); // self.down_proj(...)
|
|
134
|
-
return y;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ── switch_layers.py SwitchGLU (swiglu activation, quantized experts) ─────────
|
|
139
|
-
// The three per-expert projections are the stacked switch_mlp.{gate,up,down}_proj
|
|
140
|
-
// tensors; the activation is the SAME @mx.compile swiglu as activations.py.
|
|
141
|
-
class SwitchGLU {
|
|
142
|
-
readonly gateProj: QuantizedSwitchLinear;
|
|
143
|
-
readonly upProj: QuantizedSwitchLinear;
|
|
144
|
-
readonly downProj: QuantizedSwitchLinear;
|
|
145
|
-
|
|
146
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
147
|
-
this.gateProj = QuantizedSwitchLinear.load(weights, `${prefix}.gate_proj`, config);
|
|
148
|
-
this.upProj = QuantizedSwitchLinear.load(weights, `${prefix}.up_proj`, config);
|
|
149
|
-
this.downProj = QuantizedSwitchLinear.load(weights, `${prefix}.down_proj`, config);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** x [B, L, H], indices [B, L, k] → [B, L, k, H]. */
|
|
153
|
-
forward(x: MlxArray, indices: MlxArray): MlxArray {
|
|
154
|
-
// x = mx.expand_dims(x, (-2, -3)) → [B, L, 1, 1, H]
|
|
155
|
-
let h = ops.expandDims(x, -2);
|
|
156
|
-
h = disposing(h, ops.expandDims(h, -3));
|
|
157
|
-
|
|
158
|
-
// do_sort = indices.size >= 64
|
|
159
|
-
const doSort = indices.size >= 64;
|
|
160
|
-
let idx = indices;
|
|
161
|
-
let invOrder: MlxArray | null = null;
|
|
162
|
-
let order: MlxArray | null = null;
|
|
163
|
-
if (doSort) {
|
|
164
|
-
// _gather_sort(x, indices): flatten indices, argsort → order, argsort(order) →
|
|
165
|
-
// inv_order, gather rows by order // M (M = k = last dim of indices).
|
|
166
|
-
const M = indices.shape[indices.ndim - 1]!; // *_, M = indices.shape
|
|
167
|
-
const idxFlat = ops.reshape(indices, [indices.size]); // indices.flatten()
|
|
168
|
-
order = ops.argsortAxis(idxFlat, 0); // order = mx.argsort(indices)
|
|
169
|
-
invOrder = ops.argsortAxis(order, 0); // inv_order = mx.argsort(order)
|
|
170
|
-
const mScalar = ops.scalarLike(M, order);
|
|
171
|
-
const rowIdx = ops.floorDivide(order, mScalar); // order // M
|
|
172
|
-
mScalar.dispose();
|
|
173
|
-
const [, , , , H] = h.shape as number[];
|
|
174
|
-
const flat = ops.reshape(h, [-1, 1, H!]); // x.flatten(0, -3)
|
|
175
|
-
h.dispose();
|
|
176
|
-
h = ops.takeAxis(flat, rowIdx, 0); // x.flatten(0,-3)[order // M]
|
|
177
|
-
flat.dispose(); rowIdx.dispose();
|
|
178
|
-
idx = ops.takeAxis(idxFlat, order, 0); // indices[order]
|
|
179
|
-
idxFlat.dispose();
|
|
180
|
-
}
|
|
181
|
-
// (self.training path — mx.stop_gradient(idx) — is inference-irrelevant here)
|
|
182
|
-
const xUp = this.upProj.forward(h, idx, doSort); // x_up = self.up_proj(x, idx, sorted_indices=do_sort)
|
|
183
|
-
const xGate = this.gateProj.forward(h, idx, doSort); // x_gate = self.gate_proj(x, idx, sorted_indices=do_sort)
|
|
184
|
-
h.dispose();
|
|
185
|
-
// self.activation(x_up, x_gate) == SwiGLU()(x_up, x_gate) == swiglu(x_gate, x_up)
|
|
186
|
-
// (SwiGLU.__call__(self, x, gate) returns swiglu(gate, x); called (x_up, x_gate)).
|
|
187
|
-
const mid = compiledSwiglu(xGate, xUp); // swiglu(gate=x_gate, x=x_up) (mx.compile)
|
|
188
|
-
xGate.dispose(); xUp.dispose();
|
|
189
|
-
let y = this.downProj.forward(mid, idx, doSort); // x = self.down_proj(activation, idx, sorted_indices=do_sort)
|
|
190
|
-
mid.dispose();
|
|
191
|
-
if (idx !== indices) idx.dispose();
|
|
192
|
-
|
|
193
|
-
if (doSort) {
|
|
194
|
-
// _scatter_unsort(x, inv_order, indices.shape): x[inv_order], unflatten to
|
|
195
|
-
// indices.shape (+ the trailing [1, H] the squeeze(-2) below removes).
|
|
196
|
-
y = disposing(y, ops.takeAxis(y, invOrder!, 0)); // x = x[inv_order]
|
|
197
|
-
invOrder!.dispose(); order!.dispose();
|
|
198
|
-
const [B, L, k] = indices.shape as number[];
|
|
199
|
-
const H = y.shape[y.ndim - 1]!;
|
|
200
|
-
y = disposing(y, ops.reshape(y, [B!, L!, k!, 1, H])); // mx.unflatten(x, 0, shape)
|
|
201
|
-
}
|
|
202
|
-
// return x.squeeze(-2)
|
|
203
|
-
const shape = y.shape;
|
|
204
|
-
shape.splice(shape.length - 2, 1);
|
|
205
|
-
return disposing(y, ops.reshape(y, shape));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// ── qwen3_moe.py Qwen3MoeSparseMoeBlock ──────────────────────────────────────
|
|
210
|
-
class Qwen3MoeSparseMoeBlock {
|
|
211
|
-
readonly gate: QuantizedLinear;
|
|
212
|
-
readonly switchMlp: SwitchGLU;
|
|
213
|
-
readonly numExperts: number;
|
|
214
|
-
readonly topK: number;
|
|
215
|
-
readonly normTopkProb: boolean;
|
|
216
|
-
|
|
217
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
218
|
-
const t = config.text;
|
|
219
|
-
this.numExperts = t.numExperts; // self.num_experts
|
|
220
|
-
this.topK = t.topKExperts; // self.top_k
|
|
221
|
-
this.normTopkProb = t.normTopkProb; // self.norm_topk_prob
|
|
222
|
-
this.gate = QuantizedLinear.load(weights, `${prefix}.gate`, config); // nn.Linear(dim, num_experts, bias=False)
|
|
223
|
-
this.switchMlp = new SwitchGLU(weights, config, `${prefix}.switch_mlp`); // SwitchGLU(dim, moe_inter, num_experts)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
forward(x: MlxArray): MlxArray {
|
|
227
|
-
let gates = this.gate.forward(x); // gates = self.gate(x)
|
|
228
|
-
gates = disposing(gates, ops.softmaxAxis(gates, -1, true)); // gates = mx.softmax(gates, axis=-1, precise=True)
|
|
229
|
-
|
|
230
|
-
const k = this.topK;
|
|
231
|
-
const [B, L] = gates.shape as [number, number, number];
|
|
232
|
-
// inds = mx.argpartition(gates, kth=-k, axis=-1)[..., -k:]
|
|
233
|
-
const part = ops.argpartitionAxis(gates, this.numExperts - k, -1); // argpartition(..., kth=-k)
|
|
234
|
-
let inds: MlxArray;
|
|
235
|
-
if (isCompiledTrace()) {
|
|
236
|
-
const start = ops.fromInt32([this.numExperts - k], [1]);
|
|
237
|
-
inds = ops.sliceDynamic(part, start, [2], [B, L, k]);
|
|
238
|
-
start.dispose();
|
|
239
|
-
} else {
|
|
240
|
-
inds = part.slice([0, 0, this.numExperts - k], [B, L, this.numExperts]); // [..., -k:]
|
|
241
|
-
}
|
|
242
|
-
part.dispose();
|
|
243
|
-
|
|
244
|
-
let scores = ops.takeAlongAxis(gates, inds, -1); // scores = mx.take_along_axis(gates, inds, axis=-1)
|
|
245
|
-
gates.dispose();
|
|
246
|
-
if (this.normTopkProb) {
|
|
247
|
-
const denom = ops.sumAxis(scores, -1, true); // mx.sum(scores, axis=-1, keepdims=True)
|
|
248
|
-
scores = disposing(scores, ops.div(scores, denom)); // scores /= ...
|
|
249
|
-
denom.dispose();
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const y = this.switchMlp.forward(x, inds); // y = self.switch_mlp(x, inds)
|
|
253
|
-
inds.dispose();
|
|
254
|
-
// y = (y * scores[..., None]).sum(axis=-2)
|
|
255
|
-
const sExp = ops.expandDims(scores, -1); // scores[..., None]
|
|
256
|
-
scores.dispose();
|
|
257
|
-
const wy = ops.mul(y, sExp); // y * scores[..., None]
|
|
258
|
-
y.dispose(); sExp.dispose();
|
|
259
|
-
return disposing(wy, ops.sumAxis(wy, -2, false)); // .sum(axis=-2)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// ── qwen3_moe.py Qwen3MoeDecoderLayer ────────────────────────────────────────
|
|
264
|
-
class Qwen3MoeDecoderLayer {
|
|
265
|
-
readonly selfAttn: Attention;
|
|
266
|
-
readonly mlp: Qwen3MoeSparseMoeBlock | MLP;
|
|
267
|
-
readonly inputLayernorm: RMSNorm;
|
|
268
|
-
readonly postAttentionLayernorm: RMSNorm;
|
|
269
|
-
|
|
270
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string, layerIdx: number) {
|
|
271
|
-
const t = config.text;
|
|
272
|
-
this.selfAttn = new Attention(weights, config, `${prefix}.self_attn`);
|
|
273
|
-
this.inputLayernorm = new RMSNorm(weights.tensor(`${prefix}.input_layernorm.weight`), t.rmsNormEps);
|
|
274
|
-
this.postAttentionLayernorm = new RMSNorm(weights.tensor(`${prefix}.post_attention_layernorm.weight`), t.rmsNormEps);
|
|
275
|
-
// if (layer_idx not in mlp_only_layers) and (num_experts > 0 and
|
|
276
|
-
// (layer_idx + 1) % decoder_sparse_step == 0): Qwen3MoeSparseMoeBlock else MLP
|
|
277
|
-
const isMoe =
|
|
278
|
-
!t.mlpOnlyLayers.includes(layerIdx) &&
|
|
279
|
-
t.numExperts > 0 &&
|
|
280
|
-
(layerIdx + 1) % t.decoderSparseStep === 0;
|
|
281
|
-
this.mlp = isMoe
|
|
282
|
-
? new Qwen3MoeSparseMoeBlock(weights, config, `${prefix}.mlp`)
|
|
283
|
-
: new MLP(weights, config, `${prefix}.mlp`);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
forward(x: MlxArray, mask: Mask, cache: Cache): MlxArray {
|
|
287
|
-
const xn = this.inputLayernorm.forward(x); // self.input_layernorm(x)
|
|
288
|
-
const r1 = this.selfAttn.forward(xn, mask, cache); // r = self.self_attn(..., mask, cache)
|
|
289
|
-
xn.dispose();
|
|
290
|
-
const h = ops.add(x, r1); r1.dispose(); // h = x + r
|
|
291
|
-
const hn = this.postAttentionLayernorm.forward(h); // self.post_attention_layernorm(h)
|
|
292
|
-
const r2 = this.mlp.forward(hn); hn.dispose(); // r = self.mlp(...)
|
|
293
|
-
const out = ops.add(h, r2); h.dispose(); r2.dispose(); // out = h + r
|
|
294
|
-
return out;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// ── qwen3_moe.py Qwen3MoeModel + Model ───────────────────────────────────────
|
|
299
|
-
export class Qwen3MoeModel {
|
|
300
|
-
readonly config: ModelConfig;
|
|
301
|
-
readonly weightsBytes: number;
|
|
302
|
-
readonly prefixBase = "model";
|
|
303
|
-
readonly loraState = new LoraState();
|
|
304
|
-
readonly embed: QuantizedEmbedding;
|
|
305
|
-
readonly layers: Qwen3MoeDecoderLayer[];
|
|
306
|
-
readonly finalNorm: RMSNorm;
|
|
307
|
-
/** Untied lm_head (tie_word_embeddings=false for this family). */
|
|
308
|
-
readonly lmHead: QuantizedLinear | null;
|
|
309
|
-
|
|
310
|
-
constructor(weights: Weights, config: ModelConfig) {
|
|
311
|
-
this.config = config;
|
|
312
|
-
this.weightsBytes = [...weights.shards.files.values()]
|
|
313
|
-
.reduce((a, f) => a + f.mmap.size, 0);
|
|
314
|
-
this.embed = QuantizedEmbedding.load(weights, "model.embed_tokens", config); // nn.Embedding
|
|
315
|
-
this.layers = Array.from(
|
|
316
|
-
{ length: config.text.numHiddenLayers },
|
|
317
|
-
(_, i) => new Qwen3MoeDecoderLayer(weights, config, `model.layers.${i}`, i),
|
|
318
|
-
);
|
|
319
|
-
this.finalNorm = new RMSNorm(weights.tensor("model.norm.weight"), config.text.rmsNormEps); // self.norm
|
|
320
|
-
this.lmHead = config.text.tieWordEmbeddings
|
|
321
|
-
? null
|
|
322
|
-
: QuantizedLinear.load(weights, "lm_head", config); // self.lm_head
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
loraTargets(): Map<string, QuantizedLinear> {
|
|
326
|
-
const out = new Map<string, QuantizedLinear>();
|
|
327
|
-
for (let i = 0; i < this.layers.length; i++) {
|
|
328
|
-
const l = this.layers[i]!;
|
|
329
|
-
const p = `model.layers.${i}`;
|
|
330
|
-
out.set(`${p}.self_attn.q_proj`, l.selfAttn.qProj);
|
|
331
|
-
out.set(`${p}.self_attn.k_proj`, l.selfAttn.kProj);
|
|
332
|
-
out.set(`${p}.self_attn.v_proj`, l.selfAttn.vProj);
|
|
333
|
-
out.set(`${p}.self_attn.o_proj`, l.selfAttn.oProj);
|
|
334
|
-
if (l.mlp instanceof MLP) {
|
|
335
|
-
out.set(`${p}.mlp.gate_proj`, l.mlp.gateProj);
|
|
336
|
-
out.set(`${p}.mlp.up_proj`, l.mlp.upProj);
|
|
337
|
-
out.set(`${p}.mlp.down_proj`, l.mlp.downProj);
|
|
338
|
-
}
|
|
339
|
-
// MoE switch_mlp / gate are QuantizedSwitchLinear (stacked experts) — not
|
|
340
|
-
// LoRA targets under our per-linear adapter machinery.
|
|
341
|
-
}
|
|
342
|
-
return out;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
makeCache(): Cache[] {
|
|
346
|
-
return this.layers.map(() => new KVCache());
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
forwardHidden(ids: MlxArray, cache: Cache[]): MlxArray {
|
|
350
|
-
const h = this.embed.encode(ids); // self.embed_tokens(inputs)
|
|
351
|
-
return this.forwardLayers(h, cache);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
forwardEmbeddings(_embeds: MlxArray, _cache: Cache[], _bidir: MlxArray | null): MlxArray {
|
|
355
|
-
throw new Error("qwen3_moe input-embedding path is not supported");
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
protected forwardLayers(h0: MlxArray, cache: Cache[]): MlxArray {
|
|
359
|
-
const L = h0.shape[1]!;
|
|
360
|
-
const mask = cache[0]!.makeMask(L, null); // create_attention_mask(h, cache[0])
|
|
361
|
-
let cur = h0;
|
|
362
|
-
for (let i = 0; i < this.layers.length; i++) { // for layer, c in zip(self.layers, cache)
|
|
363
|
-
const next = this.layers[i]!.forward(cur, mask, cache[i]!); // h = layer(h, mask, c)
|
|
364
|
-
cur.dispose();
|
|
365
|
-
cur = next;
|
|
366
|
-
}
|
|
367
|
-
mask.arr?.dispose();
|
|
368
|
-
return disposing(cur, this.finalNorm.forward(cur)); // return self.norm(h)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
logitsFromHidden(h: MlxArray): MlxArray {
|
|
372
|
-
return this.lmHead ? this.lmHead.forward(h) : this.embed.asLinear(h); // self.lm_head(out)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
forward(tokens: number[] | MlxArray, cache: Cache[]): MlxArray {
|
|
376
|
-
const ids = Array.isArray(tokens)
|
|
377
|
-
? ops.fromInt32(tokens, [1, tokens.length])
|
|
378
|
-
: tokens;
|
|
379
|
-
const h = this.forwardHidden(ids, cache);
|
|
380
|
-
if (Array.isArray(tokens)) ids.dispose();
|
|
381
|
-
const logits = this.logitsFromHidden(h);
|
|
382
|
-
h.dispose();
|
|
383
|
-
return logits;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
generate(promptTokens: number[], maxTokens: number, eosIds: number[] = []): number[] {
|
|
387
|
-
const cache = this.makeCache();
|
|
388
|
-
const out: number[] = [];
|
|
389
|
-
try {
|
|
390
|
-
let tokens = promptTokens;
|
|
391
|
-
for (let step = 0; step < maxTokens; step++) {
|
|
392
|
-
const logits = this.forward(tokens, cache);
|
|
393
|
-
const next = argmaxLastPosition(logits);
|
|
394
|
-
logits.dispose();
|
|
395
|
-
if (eosIds.includes(next)) break;
|
|
396
|
-
out.push(next);
|
|
397
|
-
tokens = [next];
|
|
398
|
-
}
|
|
399
|
-
} finally {
|
|
400
|
-
for (const c of cache) c.dispose();
|
|
401
|
-
}
|
|
402
|
-
return out;
|
|
403
|
-
}
|
|
404
|
-
}
|
package/src/model/qwen3-mrope.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
// Qwen3.5/3.8 multimodal RoPE (mRoPE) — the language-side position machinery
|
|
2
|
-
// for vision requests (PLAN 14v), port of mlx-vlm's qwen3_5 language rope:
|
|
3
|
-
// MRoPERotaryEmbedding (style "interleaved", mrope_section [11,11,10]) +
|
|
4
|
-
// get_rope_index + the rope_deltas decode continuation.
|
|
5
|
-
//
|
|
6
|
-
// TEXT-ONLY EQUIVALENCE: with all three position streams equal, interleaved
|
|
7
|
-
// selection collapses to plain partial RoPE — which is why the text path's
|
|
8
|
-
// ops.rope stays bit-exact untouched. This module only activates for
|
|
9
|
-
// requests whose prompt contains vision spans; while active, EVERY
|
|
10
|
-
// full-attention rope in the request (prefill AND decode) goes through the
|
|
11
|
-
// manual interleaved path, mirroring the reference (which never uses the
|
|
12
|
-
// fused fast-rope kernel when position_ids are supplied).
|
|
13
|
-
//
|
|
14
|
-
// Position semantics (get_rope_index, B=1 serial): text tokens advance all
|
|
15
|
-
// three streams together; an image span of grid (t, h/merge, w/merge) gets
|
|
16
|
-
// t/h/w grid positions offset by the current base; text after an image
|
|
17
|
-
// resumes at max+1. delta = (max position + 1) - sequence length; decode
|
|
18
|
-
// positions are offset + delta on all three streams.
|
|
19
|
-
|
|
20
|
-
import { MlxArray } from "../mlx/array";
|
|
21
|
-
import { Dtype } from "../mlx/ffi";
|
|
22
|
-
import * as ops from "../mlx/ops";
|
|
23
|
-
import { MetalKernel } from "../mlx/metal-kernel";
|
|
24
|
-
|
|
25
|
-
export interface MropeRequestState {
|
|
26
|
-
/** Full-grid positions for the prompt, one Int32Array per t/h/w stream. */
|
|
27
|
-
positions: [Int32Array, Int32Array, Int32Array];
|
|
28
|
-
/** (max position + 1) - promptLength; decode positions = offset + delta. */
|
|
29
|
-
delta: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface MropeForwardState {
|
|
33
|
-
/** Effective positions [3, 1, L] int32 for the CURRENT forward window. */
|
|
34
|
-
posIds: MlxArray;
|
|
35
|
-
/** Borrowed model-owned f32 inv_freq (mropeInvFreq) — not disposed here. */
|
|
36
|
-
invFreq: MlxArray;
|
|
37
|
-
rotaryDims: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Active per-forward mRoPE cos/sin, read by Qwen3Attention.forward. Null on
|
|
41
|
-
* the text-only path (serial lane only — vision requests never batch). */
|
|
42
|
-
export let activeMrope: MropeForwardState | null = null;
|
|
43
|
-
export function setActiveMrope(s: MropeForwardState | null): void {
|
|
44
|
-
activeMrope = s;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const MROPE_SECTION = [11, 11, 10] as const;
|
|
48
|
-
|
|
49
|
-
/** Interleaved frequency→stream selector (rope_utils
|
|
50
|
-
* _interleaved_position_selector): default t(0); indices 1,4,7,… take
|
|
51
|
-
* h(1) while < section[1]*3; indices 2,5,8,… take w(2) while < section[2]*3. */
|
|
52
|
-
export function interleavedSelector(freqDim: number): Int32Array {
|
|
53
|
-
const sel = new Int32Array(freqDim);
|
|
54
|
-
for (let dim = 1; dim <= 2; dim++) {
|
|
55
|
-
const offset = dim; // h starts at 1, w at 2
|
|
56
|
-
for (let i = offset; i < Math.min(MROPE_SECTION[dim]! * 3, freqDim); i += 3)
|
|
57
|
-
sel[i] = dim;
|
|
58
|
-
}
|
|
59
|
-
return sel;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** inv_freq for the language rope — computed on-device exactly like
|
|
63
|
-
* compute_inv_freq (Metal powf is not correctly rounded; a JS emulation
|
|
64
|
-
* drifts by 1 ulp on some entries). Returned as a live f32 device array
|
|
65
|
-
* (the apply kernel reads it directly). */
|
|
66
|
-
export function mropeInvFreq(rotaryDims: number, base: number): MlxArray {
|
|
67
|
-
const ar = ops.arange(0, rotaryDims, 2, Dtype.float32);
|
|
68
|
-
const ex = ops.mulScalar(ar, 1 / rotaryDims);
|
|
69
|
-
ar.dispose();
|
|
70
|
-
const theta = MlxArray.fromFloat32(Float32Array.from([base]), [1]);
|
|
71
|
-
const p = ops.pow(theta, ex);
|
|
72
|
-
theta.dispose();
|
|
73
|
-
ex.dispose();
|
|
74
|
-
const one = MlxArray.fromFloat32(Float32Array.from([1]), [1]);
|
|
75
|
-
const invA = ops.div(one, p);
|
|
76
|
-
one.dispose();
|
|
77
|
-
p.dispose();
|
|
78
|
-
return invA;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Effective positions [3,1,L] int32 for window [offset, offset+L) —
|
|
82
|
-
* prompt-grid positions while inside the prompt, offset+delta beyond it
|
|
83
|
-
* (the reference's rope_deltas continuation). */
|
|
84
|
-
export function buildMropePositions(
|
|
85
|
-
state: MropeRequestState, offset: number, L: number,
|
|
86
|
-
invFreq: MlxArray, rotaryDims: number,
|
|
87
|
-
): MropeForwardState {
|
|
88
|
-
const P = state.positions;
|
|
89
|
-
const promptLen = P[0].length;
|
|
90
|
-
const joint = new Int32Array(3 * L);
|
|
91
|
-
for (let axis = 0; axis < 3; axis++) {
|
|
92
|
-
for (let l = 0; l < L; l++) {
|
|
93
|
-
const idx = offset + l;
|
|
94
|
-
joint[axis * L + l] = idx < promptLen ? P[axis]![idx]! : idx + state.delta;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return { posIds: MlxArray.fromInt32(joint, [3, 1, L]), invFreq, rotaryDims };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// The reference language-side apply is a CUSTOM METAL KERNEL (rope_utils
|
|
101
|
-
// _mrope_apply_kernel, pairing "half_split", position_ndim 3): per rotated
|
|
102
|
-
// pair it computes angle = pos * inv_freq in f32, cos/sin in-kernel, and
|
|
103
|
-
// writes x*c − x_pair*s / x_pair*c + x*s with ONE rounding to the tensor
|
|
104
|
-
// dtype. A bf16 cos/sin manual path is ~0.4% off per rotation and moved
|
|
105
|
-
// step-0 logits by ~1.0 — this verbatim port is the oracle's arithmetic.
|
|
106
|
-
const kernelCache = new Map<number, MetalKernel>();
|
|
107
|
-
function mropeKernel(rotaryDims: number): MetalKernel {
|
|
108
|
-
let k = kernelCache.get(rotaryDims);
|
|
109
|
-
if (k) return k;
|
|
110
|
-
const half = rotaryDims / 2;
|
|
111
|
-
const source = `
|
|
112
|
-
uint elem = thread_position_in_grid.x;
|
|
113
|
-
|
|
114
|
-
const int half_dim = ${half};
|
|
115
|
-
const int q_bsz = x_shape[0];
|
|
116
|
-
const int q_heads = x_shape[1];
|
|
117
|
-
const int q_len = x_shape[2];
|
|
118
|
-
const int q_dim = x_shape[3];
|
|
119
|
-
const int slots = half_dim + q_dim - ${rotaryDims};
|
|
120
|
-
const int work_size = q_bsz * q_heads * q_len * slots;
|
|
121
|
-
|
|
122
|
-
if (elem >= uint(work_size)) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
int local = int(elem);
|
|
127
|
-
int slot = local % slots;
|
|
128
|
-
int tmp = local / slots;
|
|
129
|
-
int t = tmp % q_len;
|
|
130
|
-
tmp = tmp / q_len;
|
|
131
|
-
int h = tmp % q_heads;
|
|
132
|
-
int b = tmp / q_heads;
|
|
133
|
-
int base = ((b * q_heads + h) * q_len + t) * q_dim;
|
|
134
|
-
|
|
135
|
-
if (slot >= half_dim) {
|
|
136
|
-
int pass_d = ${rotaryDims} + slot - half_dim;
|
|
137
|
-
int pass_idx = base + pass_d;
|
|
138
|
-
x_out[pass_idx] = x[pass_idx];
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
int freq_idx = slot;
|
|
143
|
-
int d = freq_idx;
|
|
144
|
-
int pair_d = d + half_dim;
|
|
145
|
-
int axis = int(position_selector[freq_idx]);
|
|
146
|
-
float pos = static_cast<float>(position_ids[(axis * q_bsz + b) * q_len + t]);
|
|
147
|
-
float angle = pos * static_cast<float>(inv_freq[freq_idx]);
|
|
148
|
-
float c = metal::cos(angle);
|
|
149
|
-
float s = metal::sin(angle);
|
|
150
|
-
|
|
151
|
-
int idx = base + d;
|
|
152
|
-
float xv = static_cast<float>(x[idx]);
|
|
153
|
-
float xp = static_cast<float>(x[base + pair_d]);
|
|
154
|
-
x_out[idx] = static_cast<T>(xv * c - xp * s);
|
|
155
|
-
x_out[base + pair_d] = static_cast<T>(xp * c + xv * s);
|
|
156
|
-
`;
|
|
157
|
-
k = new MetalKernel({
|
|
158
|
-
name: `mrope_apply_half_split_${rotaryDims}_3d`,
|
|
159
|
-
inputNames: ["x", "position_ids", "inv_freq", "position_selector"],
|
|
160
|
-
outputNames: ["x_out"],
|
|
161
|
-
source,
|
|
162
|
-
ensureRowContiguous: true,
|
|
163
|
-
});
|
|
164
|
-
kernelCache.set(rotaryDims, k);
|
|
165
|
-
return k;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const selectorCache = new Map<number, MlxArray>();
|
|
169
|
-
function selectorArr(half: number): MlxArray {
|
|
170
|
-
let s = selectorCache.get(half);
|
|
171
|
-
if (!s) {
|
|
172
|
-
s = MlxArray.fromInt32(interleavedSelector(half), [half]);
|
|
173
|
-
selectorCache.set(half, s);
|
|
174
|
-
}
|
|
175
|
-
return s;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** Apply interleaved mRoPE to one [B, heads, L, headDim] tensor via the
|
|
179
|
-
* reference's exact Metal kernel. `invFreq` is the f32 device array from
|
|
180
|
-
* mropeInvFreq. */
|
|
181
|
-
export function applyInterleavedRope(
|
|
182
|
-
x: MlxArray, fwd: MropeForwardState,
|
|
183
|
-
): MlxArray {
|
|
184
|
-
const rotaryDims = fwd.rotaryDims;
|
|
185
|
-
const [B, H, L, D] = x.shape as [number, number, number, number];
|
|
186
|
-
const half = rotaryDims / 2;
|
|
187
|
-
const slots = half + D - rotaryDims;
|
|
188
|
-
const work = B * H * L * slots;
|
|
189
|
-
const [out] = mropeKernel(rotaryDims).apply(
|
|
190
|
-
[x, fwd.posIds, fwd.invFreq, selectorArr(half)],
|
|
191
|
-
{
|
|
192
|
-
outputs: [{ shape: [B, H, L, D], dtype: x.dtype }],
|
|
193
|
-
grid: [work, 1, 1],
|
|
194
|
-
threadGroup: [256, 1, 1],
|
|
195
|
-
templateDtypes: { T: x.dtype },
|
|
196
|
-
},
|
|
197
|
-
);
|
|
198
|
-
return out!;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** get_rope_index port (B=1, no attention mask): positions per stream + the
|
|
202
|
-
* decode delta for a prompt with vision spans. `grids` are the per-image
|
|
203
|
-
* (t, h, w) grids in PATCH units and must appear in prompt order. */
|
|
204
|
-
export function qwenRopeIndex(
|
|
205
|
-
ids: readonly number[],
|
|
206
|
-
grids: readonly [number, number, number][],
|
|
207
|
-
mergeSize: number,
|
|
208
|
-
imageTokenId: number,
|
|
209
|
-
videoTokenId: number,
|
|
210
|
-
): MropeRequestState {
|
|
211
|
-
const L = ids.length;
|
|
212
|
-
const P: [Int32Array, Int32Array, Int32Array] =
|
|
213
|
-
[new Int32Array(L), new Int32Array(L), new Int32Array(L)];
|
|
214
|
-
let write = 0; // next output index (== st in the reference walk)
|
|
215
|
-
let base = 0; // st_idx: next position after everything placed so far
|
|
216
|
-
let gi = 0;
|
|
217
|
-
let i = 0;
|
|
218
|
-
while (i < L) {
|
|
219
|
-
const tok = ids[i]!;
|
|
220
|
-
if ((tok === imageTokenId || tok === videoTokenId) && gi < grids.length) {
|
|
221
|
-
const [t, h, w] = grids[gi]!;
|
|
222
|
-
gi++;
|
|
223
|
-
const gh = Math.trunc(h / mergeSize);
|
|
224
|
-
const gw = Math.trunc(w / mergeSize);
|
|
225
|
-
const span = t * gh * gw;
|
|
226
|
-
for (let k = 0; k < span; k++) {
|
|
227
|
-
const tt = Math.trunc(k / (gh * gw));
|
|
228
|
-
const rem = k % (gh * gw);
|
|
229
|
-
const hh = Math.trunc(rem / gw);
|
|
230
|
-
const ww = rem % gw;
|
|
231
|
-
P[0][write + k] = base + tt;
|
|
232
|
-
P[1][write + k] = base + hh;
|
|
233
|
-
P[2][write + k] = base + ww;
|
|
234
|
-
}
|
|
235
|
-
// Reference: next base = max position in the span + 1 = base +
|
|
236
|
-
// max(t, gh, gw) … computed as llm_pos_ids.max()+1.
|
|
237
|
-
base = base + Math.max(t, gh, gw);
|
|
238
|
-
write += span;
|
|
239
|
-
i += span;
|
|
240
|
-
} else {
|
|
241
|
-
P[0][write] = base;
|
|
242
|
-
P[1][write] = base;
|
|
243
|
-
P[2][write] = base;
|
|
244
|
-
base++;
|
|
245
|
-
write++;
|
|
246
|
-
i++;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
if (write !== L)
|
|
250
|
-
throw new Error(`qwenRopeIndex covered ${write} of ${L} tokens (grids misaligned?)`);
|
|
251
|
-
return { positions: P, delta: base - L };
|
|
252
|
-
}
|