@mlx-bun/inference 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +1475 -2
- package/THIRD_PARTY_NOTICES.md +3404 -0
- package/dist/native/libmlx_bun_ane.dylib +0 -0
- package/dist/native/libmlx_bun_expert_io.dylib +0 -0
- package/dist/native/mlx-bun-frame-extract +0 -0
- package/examples/fit-model.ts +25 -0
- package/examples/qwen3-forward.ts +42 -0
- package/examples/qwen3-generate.ts +28 -0
- package/examples/trellis-expand.ts +23 -0
- package/package.json +129 -4
- package/src/adapters/available.ts +110 -0
- package/src/adapters/index.ts +3 -0
- package/src/adapters/manager.ts +316 -0
- package/src/artifacts/auxiliary-files.ts +45 -0
- package/src/artifacts/config-dialects.ts +94 -0
- package/src/artifacts/config.ts +341 -0
- package/src/artifacts/draft-vocabulary.ts +30 -0
- package/src/artifacts/expert-offload-build.ts +75 -0
- package/src/artifacts/expert-offload.ts +89 -0
- package/src/artifacts/experts/index.ts +3 -0
- package/src/artifacts/experts/io.ts +386 -0
- package/src/artifacts/experts/residency.ts +1134 -0
- package/src/artifacts/experts/usage.ts +415 -0
- package/src/artifacts/fingerprint.ts +44 -0
- package/src/artifacts/glm52/container.ts +305 -0
- package/src/artifacts/glm52/expert-layout.ts +249 -0
- package/src/artifacts/glm52/index.ts +7 -0
- package/src/artifacts/glm52/kernel-layout.ts +124 -0
- package/src/artifacts/glm52/layout.ts +152 -0
- package/src/artifacts/glm52/memory.ts +500 -0
- package/src/artifacts/glm52/resident-weights.ts +135 -0
- package/src/artifacts/glm52/weights.ts +503 -0
- package/src/artifacts/glm52-config.ts +262 -0
- package/src/artifacts/identity.ts +94 -0
- package/src/artifacts/index.ts +15 -0
- package/src/artifacts/mmap.ts +90 -0
- package/src/artifacts/safetensors-writer.ts +249 -0
- package/src/artifacts/safetensors.ts +164 -0
- package/src/artifacts/turboquant-fold.ts +42 -0
- package/src/artifacts/weight-audit.ts +43 -0
- package/src/artifacts/weights.ts +255 -0
- package/src/contracts/index.ts +2 -0
- package/src/contracts/mlx/attention.ts +8 -0
- package/src/contracts/mlx/cache.ts +510 -0
- package/src/contracts/mlx/checkpoint.ts +10 -0
- package/src/contracts/mlx/draft-checkpoint.ts +14 -0
- package/src/contracts/mlx/draft-projection.ts +27 -0
- package/src/contracts/mlx/draft-target.ts +84 -0
- package/src/contracts/mlx/drafter.ts +176 -0
- package/src/contracts/mlx/forward-work.ts +23 -0
- package/src/contracts/mlx/glm52-weights.ts +25 -0
- package/src/contracts/mlx/graph.ts +309 -0
- package/src/contracts/mlx/head.ts +6 -0
- package/src/contracts/mlx/index.ts +15 -0
- package/src/contracts/mlx/kv-codec.ts +9 -0
- package/src/contracts/mlx/media.ts +113 -0
- package/src/contracts/mlx/positions.ts +16 -0
- package/src/contracts/mlx/row-table.ts +2 -0
- package/src/contracts/mlx/trainable.ts +103 -0
- package/src/contracts/mlx/whisper.ts +96 -0
- package/src/contracts/portable/composition.ts +106 -0
- package/src/contracts/portable/denoising.ts +17 -0
- package/src/contracts/portable/execution.ts +79 -0
- package/src/contracts/portable/generation.ts +103 -0
- package/src/contracts/portable/graph.ts +80 -0
- package/src/contracts/portable/index.ts +15 -0
- package/src/contracts/portable/memory-plan.ts +26 -0
- package/src/contracts/portable/object-cache.ts +8 -0
- package/src/contracts/portable/prefill.ts +63 -0
- package/src/contracts/portable/prefix-cache.ts +33 -0
- package/src/contracts/portable/prompt.ts +2 -0
- package/src/contracts/portable/resources.ts +25 -0
- package/src/contracts/portable/rollback.ts +7 -0
- package/src/contracts/portable/sampling.ts +44 -0
- package/src/contracts/portable/scheduling.ts +54 -0
- package/src/contracts/portable/token-delivery.ts +4 -0
- package/src/contracts/portable/tsconfig.json +14 -0
- package/src/embeddings/index.ts +1 -0
- package/src/embeddings/text.ts +85 -0
- package/src/execution/admission.ts +59 -0
- package/src/execution/batch-group.ts +1240 -0
- package/src/execution/batch-types.ts +225 -0
- package/src/execution/cancellation.ts +38 -0
- package/src/execution/continuation-request.ts +45 -0
- package/src/execution/continuation-types.ts +10 -0
- package/src/execution/coordinator.ts +70 -0
- package/src/execution/denoising-group.ts +180 -0
- package/src/execution/engine.ts +56 -0
- package/src/execution/fill-group.ts +505 -0
- package/src/execution/fit.ts +184 -0
- package/src/execution/gateway-binding.ts +178 -0
- package/src/execution/grammar-group.ts +224 -0
- package/src/execution/index.ts +18 -0
- package/src/execution/methods.ts +75 -0
- package/src/execution/mixed-iteration.ts +96 -0
- package/src/execution/plan.ts +65 -0
- package/src/execution/prefill-cohort.ts +100 -0
- package/src/execution/prefill-rows.ts +263 -0
- package/src/execution/request-policy.ts +19 -0
- package/src/execution/row-sampling.ts +49 -0
- package/src/execution/scheduler.ts +92 -0
- package/src/execution/session.ts +247 -0
- package/src/execution/speculative-group.ts +797 -0
- package/src/execution/tasks.ts +44 -0
- package/src/generation/autoregressive.ts +840 -0
- package/src/generation/bindings/autoregressive.ts +104 -0
- package/src/generation/bindings/denoising.ts +60 -0
- package/src/generation/bindings/prefill-policy.ts +36 -0
- package/src/generation/checkpoint-identity.ts +60 -0
- package/src/generation/denoising.ts +85 -0
- package/src/generation/diffusion.ts +583 -0
- package/src/generation/fill/echo-index.ts +188 -0
- package/src/generation/fill/index.ts +3 -0
- package/src/generation/fill/proposal.ts +69 -0
- package/src/generation/fill/schema-rows.ts +506 -0
- package/src/generation/fill/session.ts +464 -0
- package/src/generation/fill/tool-boundary.ts +103 -0
- package/src/generation/fill-append.ts +58 -0
- package/src/generation/generate.ts +44 -0
- package/src/generation/grammar-step.ts +39 -0
- package/src/generation/index.ts +14 -0
- package/src/generation/phase-dispatch.ts +115 -0
- package/src/generation/prefill.ts +33 -0
- package/src/generation/result.ts +49 -0
- package/src/generation/scopes.ts +157 -0
- package/src/generation/speculative/acceptance.ts +41 -0
- package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
- package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
- package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
- package/src/generation/speculative/bindings/binding.ts +106 -0
- package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
- package/src/generation/speculative/bindings/draft-target.ts +10 -0
- package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
- package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
- package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
- package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
- package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
- package/src/generation/speculative/cache-identity.ts +16 -0
- package/src/generation/speculative/draft-kind.ts +149 -0
- package/src/generation/speculative/draft-policy.ts +41 -0
- package/src/generation/speculative/draft-registry.ts +118 -0
- package/src/generation/speculative/draft-vocab.ts +110 -0
- package/src/generation/speculative/index.ts +17 -0
- package/src/generation/speculative/output.ts +49 -0
- package/src/generation/speculative/round.ts +307 -0
- package/src/generation/speculative/source.ts +144 -0
- package/src/generation/speculative/sources/assistant-source.ts +64 -0
- package/src/generation/speculative/sources/deepspec-source.ts +70 -0
- package/src/generation/speculative/sources/dflash-source.ts +84 -0
- package/src/generation/speculative/sources/dflash2-source.ts +86 -0
- package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
- package/src/generation/speculative/sources/ngram-source.ts +165 -0
- package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
- package/src/generation/speculative/sources/two-model.ts +75 -0
- package/src/generation/types.ts +194 -0
- package/src/index.ts +20 -0
- package/src/input/audio/audiotoolbox.ts +112 -0
- package/src/input/audio/decode.ts +133 -0
- package/src/input/audio/features.ts +202 -0
- package/src/input/audio/index.ts +6 -0
- package/src/input/audio/transcode.ts +67 -0
- package/src/input/audio/whisper-mel.ts +185 -0
- package/src/input/audio/whisper-tokenizer.ts +238 -0
- package/src/input/chat-template.ts +389 -0
- package/src/input/index.ts +6 -0
- package/src/input/media-fetch.ts +439 -0
- package/src/input/packed-mixed.ts +43 -0
- package/src/input/special-tokens.ts +75 -0
- package/src/input/token-groups.ts +49 -0
- package/src/input/tokenizer.ts +336 -0
- package/src/input/tool-call.ts +689 -0
- package/src/input/vision/index.ts +3 -0
- package/src/input/vision/preprocess.ts +247 -0
- package/src/input/vision/prompt.ts +398 -0
- package/src/input/vision/qwen3vl-preprocess.ts +409 -0
- package/src/input/vision/qwen3vl-prompt.ts +237 -0
- package/src/input/vision/video-frames.ts +100 -0
- package/src/kernels/ane/fill.ts +101 -0
- package/src/kernels/ane/linear.ts +416 -0
- package/src/kernels/attention/flash.ts +694 -0
- package/src/kernels/attention/kvq4-decode.ts +155 -0
- package/src/kernels/attention/masks.ts +40 -0
- package/src/kernels/attention/multi-query.ts +193 -0
- package/src/kernels/attention/paged.ts +130 -0
- package/src/kernels/delta/gated.ts +306 -0
- package/src/kernels/delta/index.ts +3 -0
- package/src/kernels/delta/silu-rms-heads.ts +69 -0
- package/src/kernels/delta/state.ts +74 -0
- package/src/kernels/gated-rms-norm.ts +64 -0
- package/src/kernels/glm52/layout.ts +37 -0
- package/src/kernels/glm52/streamed-experts.ts +360 -0
- package/src/kernels/logits.ts +38 -0
- package/src/kernels/quantization/affine-row.ts +154 -0
- package/src/kernels/quantization/affine-rows.ts +36 -0
- package/src/kernels/quantization/affine-split-mma.ts +144 -0
- package/src/kernels/quantization/affine3-mma.ts +117 -0
- package/src/kernels/quantization/affine3-rows.ts +103 -0
- package/src/kernels/quantization/affine4-mma.ts +113 -0
- package/src/kernels/quantization/affine4-rows.ts +102 -0
- package/src/kernels/residual-rms-norm.ts +65 -0
- package/src/kernels/sampling/index.ts +2 -0
- package/src/kernels/sampling/normalized-argmax.ts +116 -0
- package/src/kernels/sampling/token-bitmask.ts +52 -0
- package/src/kernels/softcap.ts +35 -0
- package/src/kernels/trellis/codebook.ts +123 -0
- package/src/kernels/trellis/down-codebook.ts +184 -0
- package/src/kernels/trellis/down-factored.ts +180 -0
- package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
- package/src/kernels/trellis/down-mma-wide.ts +195 -0
- package/src/kernels/trellis/down-mma.ts +145 -0
- package/src/kernels/trellis/expand.ts +42 -0
- package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
- package/src/kernels/trellis/gate-up-codebook.ts +137 -0
- package/src/kernels/trellis/gate-up-factored.ts +197 -0
- package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
- package/src/kernels/trellis/gate-up-mma.ts +148 -0
- package/src/kernels/trellis/gate-up.ts +248 -0
- package/src/kernels/trellis/geometry.ts +22 -0
- package/src/kernels/trellis/index.ts +103 -0
- package/src/kernels/trellis/launch.ts +12 -0
- package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
- package/src/kernels/trellis/mixed-gate-up.ts +146 -0
- package/src/kernels/trellis/qualified.ts +34 -0
- package/src/kernels/trellis/reduce.ts +150 -0
- package/src/kernels/trellis/scatter.ts +407 -0
- package/src/kernels/trellis/splitk-prefill.ts +152 -0
- package/src/kernels/trellis/tiled-prefill.ts +131 -0
- package/src/kernels/trellis/vector-expand.ts +58 -0
- package/src/kernels/trellis/wide-prefill.ts +89 -0
- package/src/kernels/turboquant/decode.ts +82 -0
- package/src/kernels/turboquant/index.ts +5 -0
- package/src/kernels/turboquant/inverse.ts +122 -0
- package/src/kernels/turboquant/ops.ts +860 -0
- package/src/kernels/turboquant/signs.ts +130 -0
- package/src/kernels/turboquant/tables.ts +124 -0
- package/src/layers/affine-verify-linear.ts +75 -0
- package/src/layers/ane-prefill-split.ts +283 -0
- package/src/layers/compiled-normalization.ts +41 -0
- package/src/layers/delta-heads.ts +23 -0
- package/src/layers/dense-embedding.ts +29 -0
- package/src/layers/dense-linear.ts +32 -0
- package/src/layers/dequantized-linear.ts +72 -0
- package/src/layers/folded-attention.ts +42 -0
- package/src/layers/geglu.ts +130 -0
- package/src/layers/helpers.ts +7 -0
- package/src/layers/index.ts +36 -0
- package/src/layers/kv4-decode-attention.ts +15 -0
- package/src/layers/layer-norm.ts +24 -0
- package/src/layers/loading.ts +92 -0
- package/src/layers/lora.ts +150 -0
- package/src/layers/normalization.ts +9 -0
- package/src/layers/prefix-layout.ts +33 -0
- package/src/layers/quantized-append-attention.ts +32 -0
- package/src/layers/quantized-attention.ts +353 -0
- package/src/layers/quantized-embedding.ts +39 -0
- package/src/layers/quantized-linear.ts +137 -0
- package/src/layers/quantized-switch-linear.ts +37 -0
- package/src/layers/qwen-append.ts +12 -0
- package/src/layers/qwen-mrope.ts +238 -0
- package/src/layers/rope-2d.ts +110 -0
- package/src/layers/rope.ts +389 -0
- package/src/layers/swiglu.ts +23 -0
- package/src/layers/trellis-codebook-down.ts +52 -0
- package/src/layers/trellis-codebook-gate-up.ts +42 -0
- package/src/layers/trellis-down.ts +117 -0
- package/src/layers/trellis-gate-up.ts +71 -0
- package/src/layers/trellis-linear.ts +211 -0
- package/src/layers/trellis-prompt.ts +102 -0
- package/src/layers/trellis-reduce-gate-up.ts +73 -0
- package/src/layers/trellis-scatter-down.ts +98 -0
- package/src/models/ane-install.ts +74 -0
- package/src/models/audio/conformer.ts +656 -0
- package/src/models/cache-composition.ts +44 -0
- package/src/models/capabilities.ts +89 -0
- package/src/models/chat-template.ts +10 -0
- package/src/models/composition.ts +107 -0
- package/src/models/diffusion-gemma/experts.ts +59 -0
- package/src/models/diffusion-gemma/family.ts +21 -0
- package/src/models/diffusion-gemma/model.ts +900 -0
- package/src/models/diffusion-gemma/vision.ts +549 -0
- package/src/models/drafter-loaders.ts +49 -0
- package/src/models/drafters.ts +39 -0
- package/src/models/factory.ts +351 -0
- package/src/models/families.ts +70 -0
- package/src/models/family.ts +125 -0
- package/src/models/gemma4/assistant-target.ts +46 -0
- package/src/models/gemma4/assistant.ts +327 -0
- package/src/models/gemma4/blocks.ts +755 -0
- package/src/models/gemma4/compiled-decode.ts +452 -0
- package/src/models/gemma4/family.ts +39 -0
- package/src/models/gemma4/gemma4-12b.ts +677 -0
- package/src/models/gemma4/gemma4-26b.ts +544 -0
- package/src/models/gemma4/gemma4-e4b.ts +599 -0
- package/src/models/gemma4/graphs.ts +147 -0
- package/src/models/gemma4/media.ts +88 -0
- package/src/models/gemma4/model.ts +860 -0
- package/src/models/gemma4/serving-blocks.ts +72 -0
- package/src/models/gemma4/trainable.ts +186 -0
- package/src/models/gemma4/written-blocks.ts +232 -0
- package/src/models/gemma4/written-forward.ts +159 -0
- package/src/models/gemma4/written-input.ts +29 -0
- package/src/models/glm52/atlas.ts +507 -0
- package/src/models/glm52/coupling.ts +388 -0
- package/src/models/glm52/dsa.ts +601 -0
- package/src/models/glm52/family.ts +20 -0
- package/src/models/glm52/mla.ts +812 -0
- package/src/models/glm52/model.ts +1127 -0
- package/src/models/glm52/moe.ts +223 -0
- package/src/models/glm52/mtp.ts +60 -0
- package/src/models/glm52/pilot.ts +537 -0
- package/src/models/glm52/reference.ts +445 -0
- package/src/models/glm52/residency.ts +557 -0
- package/src/models/glm52/streamed-experts.ts +447 -0
- package/src/models/graph.ts +59 -0
- package/src/models/implementation.ts +230 -0
- package/src/models/index.ts +15 -0
- package/src/models/media-input.ts +15 -0
- package/src/models/memory-plan.ts +39 -0
- package/src/models/minicpm5/family.ts +29 -0
- package/src/models/minicpm5/model.ts +394 -0
- package/src/models/minicpm5/trainable.ts +90 -0
- package/src/models/profile.ts +337 -0
- package/src/models/qwen/blocks.ts +658 -0
- package/src/models/qwen/checkpoint.ts +190 -0
- package/src/models/qwen/families.ts +57 -0
- package/src/models/qwen/media-input.ts +161 -0
- package/src/models/qwen/mtp.ts +101 -0
- package/src/models/qwen/qwen3-moe.ts +355 -0
- package/src/models/qwen/qwen3.ts +323 -0
- package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
- package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
- package/src/models/qwen/qwen3_5.ts +433 -0
- package/src/models/qwen/written-layers.ts +285 -0
- package/src/models/row-table.ts +1 -0
- package/src/models/runtime.ts +73 -0
- package/src/models/speculative/deepspec-artifact.ts +10 -0
- package/src/models/speculative/deepspec.ts +744 -0
- package/src/models/speculative/dflash.ts +553 -0
- package/src/models/speculative/dflash2-artifact.ts +9 -0
- package/src/models/speculative/dflash2-operations.ts +1 -0
- package/src/models/speculative/dflash2.ts +576 -0
- package/src/models/speculative/loader.ts +29 -0
- package/src/models/support.ts +79 -0
- package/src/models/universal/archs.ts +365 -0
- package/src/models/universal/blocks.ts +479 -0
- package/src/models/universal/dense.ts +255 -0
- package/src/models/universal/family.ts +17 -0
- package/src/models/vision/qwen3vl.ts +566 -0
- package/src/models/vision/siglip.ts +520 -0
- package/src/models/vision/unified.ts +176 -0
- package/src/models/whisper/family.ts +19 -0
- package/src/models/whisper/fast.ts +734 -0
- package/src/models/whisper/model.ts +430 -0
- package/src/runtime/compiled-trace.ts +16 -0
- package/src/runtime/config.ts +77 -0
- package/src/runtime/expert-trace.ts +71 -0
- package/src/runtime/graph-forward.ts +65 -0
- package/src/runtime/integers.ts +6 -0
- package/src/runtime/native.ts +16 -0
- package/src/runtime/resources.ts +53 -0
- package/src/runtime/row-operations.ts +42 -0
- package/src/runtime/trace.ts +161 -0
- package/src/sampling/curve.ts +122 -0
- package/src/sampling/draft.ts +55 -0
- package/src/sampling/extras.ts +45 -0
- package/src/sampling/filters.ts +134 -0
- package/src/sampling/grammar.ts +630 -0
- package/src/sampling/hlg.ts +290 -0
- package/src/sampling/index.ts +9 -0
- package/src/sampling/processors.ts +142 -0
- package/src/sampling/sampler.ts +120 -0
- package/src/sampling/step.ts +343 -0
- package/src/sampling/types.ts +161 -0
- package/src/sampling/window-filters.ts +46 -0
- package/src/scoring/decisions.ts +96 -0
- package/src/scoring/full-sequence.ts +103 -0
- package/src/scoring/index.ts +9 -0
- package/src/scoring/kl.ts +29 -0
- package/src/scoring/perplexity.ts +165 -0
- package/src/scoring/response-logps.ts +65 -0
- package/src/state/affine-attention.ts +180 -0
- package/src/state/attachment.ts +68 -0
- package/src/state/attention-read.ts +215 -0
- package/src/state/batched-kv.ts +294 -0
- package/src/state/batched-mask.ts +445 -0
- package/src/state/batched-quant.ts +389 -0
- package/src/state/batched-quantized-kv.ts +209 -0
- package/src/state/batched-rotating-quant.ts +457 -0
- package/src/state/batched-rotating-state.ts +149 -0
- package/src/state/batched-rotating.ts +430 -0
- package/src/state/batched-row-storage.ts +179 -0
- package/src/state/batched-ssm.ts +54 -0
- package/src/state/batched-turboquant-kv.ts +144 -0
- package/src/state/bf16-first-kv.ts +663 -0
- package/src/state/cache-service.ts +592 -0
- package/src/state/capabilities.ts +65 -0
- package/src/state/checkpoint.ts +46 -0
- package/src/state/continuation-persistence.ts +126 -0
- package/src/state/decode-step-inputs.ts +31 -0
- package/src/state/decoded-kv-donor.ts +12 -0
- package/src/state/delayed-quantized-kv.ts +141 -0
- package/src/state/delayed-rotating-quantized-kv.ts +178 -0
- package/src/state/delayed-turboquant-kv.ts +123 -0
- package/src/state/durability.ts +214 -0
- package/src/state/encoder-cache.ts +26 -0
- package/src/state/full-kv-row-append.ts +33 -0
- package/src/state/full-kv-row-donor.ts +54 -0
- package/src/state/full-prefill-padding.ts +56 -0
- package/src/state/full-prefill-row.ts +112 -0
- package/src/state/full-transitioning-kv-rows.ts +70 -0
- package/src/state/glm52-cache.ts +783 -0
- package/src/state/grouped-heads-kv4-cache.ts +26 -0
- package/src/state/index.ts +38 -0
- package/src/state/kv-attention-view.ts +77 -0
- package/src/state/kv-budget.ts +14 -0
- package/src/state/kv-scheme.ts +315 -0
- package/src/state/kv-storage.ts +57 -0
- package/src/state/kv-tensor-rows.ts +212 -0
- package/src/state/kv.ts +324 -0
- package/src/state/kv4-head256-cache.ts +46 -0
- package/src/state/latent-legos.ts +895 -0
- package/src/state/layout.ts +277 -0
- package/src/state/leases.ts +26 -0
- package/src/state/paged/cache.ts +689 -0
- package/src/state/paged/codec.ts +36 -0
- package/src/state/paged/rows.ts +223 -0
- package/src/state/persistence-types.ts +173 -0
- package/src/state/persistence-worker.ts +83 -0
- package/src/state/persistence.ts +1036 -0
- package/src/state/persistence.worker.d.ts +3 -0
- package/src/state/persistence.worker.js +264 -0
- package/src/state/prefix-cache.ts +685 -0
- package/src/state/quantized-kv.ts +369 -0
- package/src/state/quantized-tensor.ts +26 -0
- package/src/state/request-policy.ts +48 -0
- package/src/state/retention-policy.ts +37 -0
- package/src/state/rollback.ts +131 -0
- package/src/state/rotating-kv-donor.ts +35 -0
- package/src/state/rotating-kv-layout.ts +341 -0
- package/src/state/rotating-kv.ts +529 -0
- package/src/state/rotating-quantized-kv.ts +616 -0
- package/src/state/rotating-row-transaction.ts +35 -0
- package/src/state/rows.ts +104 -0
- package/src/state/softcap-attention.ts +118 -0
- package/src/state/speculative/glm52-mtp-state.ts +38 -0
- package/src/state/speculative/qwen-mtp-state.ts +34 -0
- package/src/state/speculative-rotating-kv.ts +113 -0
- package/src/state/ssd-cache.ts +434 -0
- package/src/state/ssm-prefill-padding.ts +39 -0
- package/src/state/ssm.ts +422 -0
- package/src/state/target-layout.ts +7 -0
- package/src/state/tiered-prefix-cache.ts +45 -0
- package/src/state/training-cache.ts +300 -0
- package/src/state/transitioning-kv-rows.ts +267 -0
- package/src/state/turboquant-attention.ts +97 -0
- package/src/state/turboquant-codec.ts +90 -0
- package/src/state/turboquant-kv.ts +442 -0
- package/src/state/views.ts +26 -0
- package/src/transcription/index.ts +3 -0
- package/src/transcription/silero-vad.ts +379 -0
- package/src/transcription/whisper/decode.ts +773 -0
- package/src/transcription/whisper/format.ts +74 -0
- package/src/transcription/whisper/index.ts +4 -0
- package/src/transcription/whisper/timing.ts +274 -0
- package/src/transcription/whisper/transcribe.ts +394 -0
- package/src/transcription/whisper/types.ts +22 -0
|
@@ -0,0 +1,190 @@
|
|
|
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-bun/mlx/array";
|
|
35
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
36
|
+
import { quantFor, type ModelConfig } from "../../artifacts/config";
|
|
37
|
+
import type { Weights, WeightsView } from "../../artifacts/weights";
|
|
38
|
+
|
|
39
|
+
/** Header-level facts about one stored tensor (no bytes are read). */
|
|
40
|
+
export interface CheckpointTensor {
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly shape: readonly number[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface Qwen35Sanitized {
|
|
46
|
+
/** canonical (graph) name → the name the artifact actually stores. */
|
|
47
|
+
readonly names: Map<string, string>;
|
|
48
|
+
/** Canonical names stored as γ−1: a +1.0 is due at load. */
|
|
49
|
+
readonly normShift: Set<string>;
|
|
50
|
+
/** Canonical names in HF conv layout: a moveaxis(2, 1) is due at load. */
|
|
51
|
+
readonly convMoveaxis: Set<string>;
|
|
52
|
+
/** True when the artifact already IS our canonical layout — no view needed
|
|
53
|
+
* and the pre-existing load path runs untouched. */
|
|
54
|
+
readonly identity: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** mlx-lm `TextModel.sanitize` norm_keys, verbatim and in order. */
|
|
58
|
+
const NORM_KEYS = [
|
|
59
|
+
".input_layernorm.weight",
|
|
60
|
+
".post_attention_layernorm.weight",
|
|
61
|
+
"model.norm.weight",
|
|
62
|
+
".q_norm.weight",
|
|
63
|
+
".k_norm.weight",
|
|
64
|
+
] as const;
|
|
65
|
+
|
|
66
|
+
/** mlx-lm `Model.sanitize`: drop vision, fold every naming onto
|
|
67
|
+
* `language_model.…`. Returns null for a dropped tensor. */
|
|
68
|
+
function canonicalName(key: string): string | null {
|
|
69
|
+
if (key.startsWith("vision_tower") || key.startsWith("model.visual")) return null;
|
|
70
|
+
if (key.startsWith("model.language_model"))
|
|
71
|
+
return "language_model.model" + key.slice("model.language_model".length);
|
|
72
|
+
if (key.startsWith("language_model.")) return key;
|
|
73
|
+
return "language_model." + key;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Port of mlx_lm.models.qwen3_5 `Model.sanitize` ∘ `TextModel.sanitize`,
|
|
78
|
+
* name/shape half. Pure: takes header facts, returns the load plan.
|
|
79
|
+
*/
|
|
80
|
+
export function sanitizeQwen35Checkpoint(
|
|
81
|
+
tensors: Iterable<CheckpointTensor>,
|
|
82
|
+
): Qwen35Sanitized {
|
|
83
|
+
// Pass 1 — rename (vision dropped), exactly as Model.sanitize.
|
|
84
|
+
const renamed: { canonical: string; source: string; shape: readonly number[] }[] = [];
|
|
85
|
+
let sawForeignName = false;
|
|
86
|
+
for (const t of tensors) {
|
|
87
|
+
const canonical = canonicalName(t.name);
|
|
88
|
+
if (canonical === null) {
|
|
89
|
+
sawForeignName ||= t.name.startsWith("model.visual");
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (canonical !== t.name) sawForeignName = true;
|
|
93
|
+
renamed.push({ canonical, source: t.name, shape: t.shape });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Pass 2 — TextModel.sanitize's two flags, over the renamed map BEFORE the
|
|
97
|
+
// mtp drop (the oracle computes them first, then filters).
|
|
98
|
+
const hasMtpWeights = renamed.some((t) => t.canonical.includes("mtp."));
|
|
99
|
+
const hasUnsanitizedConv1d = renamed.some(
|
|
100
|
+
(t) => t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1,
|
|
101
|
+
);
|
|
102
|
+
const shouldShiftNormWeights = hasMtpWeights || hasUnsanitizedConv1d;
|
|
103
|
+
|
|
104
|
+
const names = new Map<string, string>();
|
|
105
|
+
const normShift = new Set<string>();
|
|
106
|
+
const convMoveaxis = new Set<string>();
|
|
107
|
+
for (const t of renamed) {
|
|
108
|
+
if (t.canonical.includes("mtp.")) continue; // oracle drops these outright
|
|
109
|
+
names.set(t.canonical, t.source);
|
|
110
|
+
if (t.canonical.includes("conv1d.weight") && t.shape[t.shape.length - 1] !== 1)
|
|
111
|
+
convMoveaxis.add(t.canonical);
|
|
112
|
+
if (
|
|
113
|
+
shouldShiftNormWeights &&
|
|
114
|
+
NORM_KEYS.some((sfx) => t.canonical.endsWith(sfx)) &&
|
|
115
|
+
t.shape.length === 1
|
|
116
|
+
)
|
|
117
|
+
normShift.add(t.canonical);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
names,
|
|
122
|
+
normShift,
|
|
123
|
+
convMoveaxis,
|
|
124
|
+
identity: !sawForeignName && !hasMtpWeights && !shouldShiftNormWeights &&
|
|
125
|
+
convMoveaxis.size === 0,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The {@link WeightsView} for a qwen3.5 artifact, or null when the artifact is
|
|
131
|
+
* already canonical (then nothing is installed and the load path is bit-for-bit
|
|
132
|
+
* what it was before this seam existed).
|
|
133
|
+
*/
|
|
134
|
+
export function qwen35WeightsView(weights: Weights): WeightsView | null {
|
|
135
|
+
const plan = sanitizeQwen35Checkpoint(
|
|
136
|
+
weights.tensorNames.map((name) => ({ name, shape: weights.info(name).shape })),
|
|
137
|
+
);
|
|
138
|
+
if (plan.identity) return null;
|
|
139
|
+
return {
|
|
140
|
+
names: plan.names,
|
|
141
|
+
fixup(canonical: string, arr: MlxArray): MlxArray | null {
|
|
142
|
+
// Oracle order: moveaxis first, then the γ shift (disjoint sets — a
|
|
143
|
+
// conv1d weight is 3-D and never a norm gain).
|
|
144
|
+
if (plan.convMoveaxis.has(canonical)) {
|
|
145
|
+
// `v.moveaxis(2, 1)` on [C, 1, K] → [C, K, 1]. Materialized: the
|
|
146
|
+
// conv1d kernel consumes it every forward, and the transposed view
|
|
147
|
+
// would otherwise pin the source shard buffer.
|
|
148
|
+
const moved = ops.transposeAxes(arr, [0, 2, 1]);
|
|
149
|
+
const out = ops.contiguous(moved);
|
|
150
|
+
moved.dispose();
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
if (plan.normShift.has(canonical)) {
|
|
154
|
+
// `v + 1.0` — a weak python scalar, so the add happens at the gain's
|
|
155
|
+
// own dtype (bf16 here); scalarLike builds the constant host-side at
|
|
156
|
+
// that dtype for the same single-kernel add the reference dispatches.
|
|
157
|
+
const one = ops.scalarLike(1, arr);
|
|
158
|
+
const out = ops.add(arr, one);
|
|
159
|
+
one.dispose();
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The graph fingerprint the `qwen3.5` graph table keys its written graphs on: architecture plus the complete
|
|
168
|
+
* language-model quantization table (every layer's projections, the head and the embedding). Two artifacts share
|
|
169
|
+
* a fingerprint only if every tensor has the same codec. Reads the config only. */
|
|
170
|
+
export function qwen35GraphFingerprint(config: ModelConfig): string {
|
|
171
|
+
const t = config.text;
|
|
172
|
+
const q = config.quantization as unknown as { bits?: number; groupSize?: number; mode?: string; overrides?: Record<string, unknown> } | null;
|
|
173
|
+
const roles = ["linear_attn.in_proj_qkv", "linear_attn.in_proj_z", "linear_attn.in_proj_a", "linear_attn.in_proj_b",
|
|
174
|
+
"linear_attn.out_proj", "self_attn.q_proj", "self_attn.k_proj", "self_attn.v_proj", "self_attn.o_proj",
|
|
175
|
+
"mlp.gate_proj", "mlp.up_proj", "mlp.down_proj"];
|
|
176
|
+
const table: unknown[] = [];
|
|
177
|
+
for (let layer = 0; layer < t.numHiddenLayers; layer++)
|
|
178
|
+
for (const role of roles) table.push(quantFor(config.quantization, `language_model.model.layers.${layer}.${role}`));
|
|
179
|
+
table.push(quantFor(config.quantization, "language_model.lm_head"), quantFor(config.quantization, "language_model.model.embed_tokens"));
|
|
180
|
+
const payload = JSON.stringify({
|
|
181
|
+
modelType: config.modelType, hiddenSize: t.hiddenSize, intermediateSize: t.intermediateSize,
|
|
182
|
+
layers: t.numHiddenLayers, fullAttentionInterval: t.fullAttentionInterval,
|
|
183
|
+
heads: t.numAttentionHeads, kvHeads: t.numKeyValueHeads, headDim: t.headDim,
|
|
184
|
+
linear: [t.linearNumKeyHeads, t.linearNumValueHeads, t.linearKeyHeadDim, t.linearValueHeadDim, t.linearConvKernelDim],
|
|
185
|
+
vocabSize: t.vocabSize, tied: t.tieWordEmbeddings, defaults: q ? [q.bits, q.groupSize, q.mode] : null, table,
|
|
186
|
+
});
|
|
187
|
+
const hash = new Bun.CryptoHasher("sha256");
|
|
188
|
+
hash.update(payload);
|
|
189
|
+
return hash.digest("hex").slice(0, 16);
|
|
190
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { L1, defineFamily } from "../family";
|
|
2
|
+
|
|
3
|
+
/** Qwen3.5 hybrid gated-DeltaNet family (model_type qwen3_5 / qwen3_5_text).
|
|
4
|
+
* Dense MLP only for now: the MoE variant (qwen3_5_moe) is deferred. */
|
|
5
|
+
export const QWEN35_FAMILY = defineFamily({
|
|
6
|
+
graph: "qwen3.5",
|
|
7
|
+
accepts: config => (config.modelType === "qwen3_5" || config.modelType === "qwen3_5_text") &&
|
|
8
|
+
!config.text.enableMoeBlock &&
|
|
9
|
+
config.text.numExperts === 0 &&
|
|
10
|
+
config.text.linearNumValueHeads > 0 &&
|
|
11
|
+
config.text.fullAttentionInterval > 0,
|
|
12
|
+
hasModelType: modelType => modelType === "qwen3_5" || modelType === "qwen3_5_text",
|
|
13
|
+
tier: "targeted",
|
|
14
|
+
label: "qwen3_5",
|
|
15
|
+
loader: "safetensors",
|
|
16
|
+
loop: "autoregressive",
|
|
17
|
+
fidelity: L1,
|
|
18
|
+
specialization: "dedicated",
|
|
19
|
+
profileId: "qwen3.5-dedicated",
|
|
20
|
+
capabilities: ["qwen3.5-graph", "recurrent-state"],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/** Plain Qwen3 (model_type `qwen3`, Qwen3ForCausalLM): a standard dense decoder
|
|
24
|
+
* with per-head q/k norm and tied embeddings. Also the text-embedding backbone
|
|
25
|
+
* (mlx-community Qwen3-Embedding-*). Distinct from the qwen3_5 hybrid. */
|
|
26
|
+
export const QWEN3_FAMILY = defineFamily({
|
|
27
|
+
graph: "qwen3",
|
|
28
|
+
accepts: config => config.modelType === "qwen3",
|
|
29
|
+
hasModelType: modelType => modelType === "qwen3",
|
|
30
|
+
tier: "targeted",
|
|
31
|
+
label: "qwen3",
|
|
32
|
+
loader: "safetensors",
|
|
33
|
+
loop: "autoregressive",
|
|
34
|
+
fidelity: L1,
|
|
35
|
+
specialization: "dedicated",
|
|
36
|
+
profileId: "qwen3-dedicated",
|
|
37
|
+
capabilities: ["qwen3-graph"],
|
|
38
|
+
embedding: { terminator: "<|endoftext|>" },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/** Qwen3-MoE (model_type `qwen3_moe`): plain-qwen3 attention with a sparse MoE
|
|
42
|
+
* FFN (gate Linear, precise softmax, top-k, renormalize, SwitchGLU experts with
|
|
43
|
+
* compiled swiglu). Distinct from the qwen3 embedding backbone and the
|
|
44
|
+
* qwen3_5 gated-DeltaNet hybrid. */
|
|
45
|
+
export const QWEN3_MOE_FAMILY = defineFamily({
|
|
46
|
+
graph: "qwen3-moe",
|
|
47
|
+
accepts: config => config.modelType === "qwen3_moe",
|
|
48
|
+
hasModelType: modelType => modelType === "qwen3_moe",
|
|
49
|
+
tier: "targeted",
|
|
50
|
+
label: "qwen3_moe",
|
|
51
|
+
loader: "safetensors",
|
|
52
|
+
loop: "autoregressive",
|
|
53
|
+
fidelity: L1,
|
|
54
|
+
specialization: "dedicated",
|
|
55
|
+
profileId: "qwen3-moe-dedicated",
|
|
56
|
+
capabilities: ["qwen3-moe-graph"],
|
|
57
|
+
});
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { rowOperationFor } from "../../runtime/row-operations";
|
|
2
|
+
import type { ModelConfig } from "../../artifacts/config";
|
|
3
|
+
import { TURBOQUANT_FOLD_FILE, readTurboQuantFold } from "../../artifacts/turboquant-fold";
|
|
4
|
+
import type { QuantizedEmbedding } from "../../layers/quantized-embedding";
|
|
5
|
+
import { QuantizedLinear } from "../../layers/quantized-linear";
|
|
6
|
+
import { readDraftVocabulary } from "../../artifacts/draft-vocabulary";
|
|
7
|
+
import type { DraftProjection } from "../../contracts/mlx/draft-projection";
|
|
8
|
+
import { mropePositionIds } from "../../layers/qwen-mrope";
|
|
9
|
+
import { type MropeRequestState } from "../../contracts/mlx/positions";
|
|
10
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
11
|
+
import type { Cache } from "../../contracts/mlx/cache";
|
|
12
|
+
import type { MediaEncoders, MlxDecodeState, MlxPromptInput, VisionEncoder, MlxPositionedEmbeddingsRange, MlxPositionedRange, MlxPositionedForward } from "../../contracts/mlx/media";
|
|
13
|
+
import type { MlxHeadForward, MlxRowTable } from "../../contracts/mlx/graph";
|
|
14
|
+
import type { DraftProjectionKernels, ResidualBasis, TargetView } from "../../contracts/mlx/draft-target";
|
|
15
|
+
import type { DraftHeadOperations } from "../../contracts/mlx/draft-projection";
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
19
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
20
|
+
import { bindEmbeddingsInput } from "../media-input";
|
|
21
|
+
|
|
22
|
+
/** What the Qwen graph's media and draft ports read from it. */
|
|
23
|
+
export interface QwenMediaGraph {
|
|
24
|
+
readonly config: ModelConfig;
|
|
25
|
+
readonly embed: QuantizedEmbedding;
|
|
26
|
+
readonly lmHead: QuantizedLinear | null;
|
|
27
|
+
/** The full-attention layer whose cache supplies logical positions. */
|
|
28
|
+
readonly faIdx: number;
|
|
29
|
+
/** The vision prefill phase: a prompt's prepared embeddings (borrowed) at request positions. */
|
|
30
|
+
prefillEmbeddingsAtPositions?(embeddings: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
|
|
31
|
+
/** A prompt's token ids after a reused prefix, at request positions. */
|
|
32
|
+
prefillAtPositions?(ids: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
|
|
33
|
+
/** One new token per row at request positions. */
|
|
34
|
+
decodeAtPositions?(ids: MlxArray, caches: Cache[], positions: MlxArray, width: number): MlxArray;
|
|
35
|
+
readonly mediaPrefill?: readonly MlxPositionedEmbeddingsRange[];
|
|
36
|
+
readonly mediaPrompt?: readonly MlxPositionedRange[];
|
|
37
|
+
readonly mediaDecode?: MlxRowTable<MlxPositionedForward>;
|
|
38
|
+
readonly logits: MlxRowTable<MlxHeadForward>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class QwenMediaDecodeState implements MlxDecodeState {
|
|
42
|
+
readonly key = "qwen-interleaved-mrope";
|
|
43
|
+
constructor(readonly model: QwenMediaGraph, readonly delta: number) {}
|
|
44
|
+
|
|
45
|
+
decode(ids: MlxArray, caches: Cache[], rows: readonly MlxDecodeState[], width: number): MlxArray {
|
|
46
|
+
const B = rows.length, L = ids.shape[1]!;
|
|
47
|
+
const cache = caches[this.model.faIdx]!;
|
|
48
|
+
// The cache supplies logical positions, including left padding, on device.
|
|
49
|
+
// No offset readback or request-global position mutation is needed.
|
|
50
|
+
const offsets = (cache as Cache & { ropeOffsetArr?: MlxArray }).ropeOffsetArr;
|
|
51
|
+
using deltas = ops.fromInt32(rows.map(row => (row as QwenMediaDecodeState).delta), [B]);
|
|
52
|
+
using scalar = offsets ? null : ops.fromInt32([cache.offset], []);
|
|
53
|
+
using starts = ops.add(offsets ?? scalar!, deltas);
|
|
54
|
+
using startRows = ops.reshape(starts, [B, 1]);
|
|
55
|
+
using indices = ops.arange(0, L, 1, Dtype.int32);
|
|
56
|
+
using positions = ops.add(startRows, indices);
|
|
57
|
+
using axis = ops.reshape(positions, [1, B, L]);
|
|
58
|
+
using grid = ops.concatAxis([axis, axis, axis], 0);
|
|
59
|
+
return this.model.mediaDecode ? rowOperationFor(this.model.mediaDecode, width)(ids, caches, grid)
|
|
60
|
+
: this.model.decodeAtPositions!(ids, caches, grid, width);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The prompt owns its grid; only its continuation delta survives into decode. */
|
|
65
|
+
export function bindQwenMediaInput(model: QwenMediaGraph, embeddings: MlxArray,
|
|
66
|
+
state: MropeRequestState): MlxPromptInput {
|
|
67
|
+
const input = bindEmbeddingsInput((ids, caches, start, phase, width) => {
|
|
68
|
+
using positions = mropePositionIds(state, start, ids.shape[1]!);
|
|
69
|
+
if (start === 0) return model.mediaPrefill
|
|
70
|
+
? model.mediaPrefill.find(range => width >= range.from && width <= range.to)!.operation(embeddings, caches, positions)
|
|
71
|
+
: model.prefillEmbeddingsAtPositions!(embeddings, caches, positions, width);
|
|
72
|
+
if (phase === "decode") return model.mediaDecode ? rowOperationFor(model.mediaDecode, width)(ids, caches, positions)
|
|
73
|
+
: model.decodeAtPositions!(ids, caches, positions, width);
|
|
74
|
+
return model.mediaPrompt
|
|
75
|
+
? model.mediaPrompt.find(range => width >= range.from && width <= range.to)!.operation(ids, caches, positions)
|
|
76
|
+
: model.prefillAtPositions!(ids, caches, positions, width);
|
|
77
|
+
});
|
|
78
|
+
return { ...input, decodeState: new QwenMediaDecodeState(model, state.delta) };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Tower weights arrive either as the OptiQ-convention sidecar or in the main
|
|
82
|
+
* shards (mlx-vlm convention); the tower loader handles both. The encoder is a
|
|
83
|
+
* Qwen3VLVisionTower riding the shared lazy slot; the Qwen media route is its
|
|
84
|
+
* only consumer and reads it through the structural contract it defines. */
|
|
85
|
+
export async function qwenMediaEncoders(model: QwenMediaGraph, modelDir: string): Promise<MediaEncoders> {
|
|
86
|
+
const hasSidecar = existsSync(`${modelDir}/optiq/optiq_vision.safetensors`);
|
|
87
|
+
if (!hasSidecar && model.config.raw.vision_config === undefined) return { vision: null, audio: null };
|
|
88
|
+
const { Qwen3VLVisionTower } = await import("../vision/qwen3vl");
|
|
89
|
+
return { vision: () => Qwen3VLVisionTower.load(modelDir) as unknown as VisionEncoder, audio: null };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The residual basis a rotated Qwen artifact declares in its fold record
|
|
93
|
+
* (`turboquant_fold.json`), for its graph's constructor to read once. A record
|
|
94
|
+
* whose stream carries no R1 rotation declares none. A missing record, or one
|
|
95
|
+
* without `final_gain`, declares none either: DFlash 2 then drafts in its
|
|
96
|
+
* trained basis (output exact, acceptance collapsed), and one line names the
|
|
97
|
+
* file to update. */
|
|
98
|
+
export function qwenResidualBasis(graph: string, modelDir: string): ResidualBasis | undefined {
|
|
99
|
+
const fold = readTurboQuantFold(modelDir);
|
|
100
|
+
if (fold && !fold.r1) return undefined;
|
|
101
|
+
if (fold?.finalGain) return Object.freeze({ r1Seed: fold.seed, finalGain: fold.finalGain });
|
|
102
|
+
console.error(`[graph] ${graph}: ${join(modelDir, TURBOQUANT_FOLD_FILE)} ${fold ? "records no final_gain" : "is missing"}; ` +
|
|
103
|
+
"DFlash 2 drafts unrotated (output exact, acceptance collapses) until it records the final-norm gain the fold moved into lm_head");
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Ports draft sources read from this graph: its embedding, head, layer taps,
|
|
108
|
+
* the MTP geometry a checkpoint-native draft head needs, from a graph whose
|
|
109
|
+
* residual stream carries a rotation fold that basis, and from a graph whose
|
|
110
|
+
* composition measured them the kernels of a drafter's own projections (each the
|
|
111
|
+
* same object on every view) and the head over its draft vocabulary (`vocabulary`,
|
|
112
|
+
* read when a drafter first reads the projection's). */
|
|
113
|
+
export function qwenDraftTarget(model: QwenMediaGraph, residualBasis?: ResidualBasis,
|
|
114
|
+
draftProjections?: DraftProjectionKernels, vocabulary?: () => DraftProjection["vocabulary"]): TargetView {
|
|
115
|
+
const projection: DraftProjection = { embed: model.embed, logits: model.logits };
|
|
116
|
+
// The vocabulary's rows are gathered when a drafter first reads them, not for drafters that never do.
|
|
117
|
+
if (vocabulary) Object.defineProperty(projection, "vocabulary", { get: vocabulary, enumerable: true });
|
|
118
|
+
return Object.freeze({ identity: model, ...(residualBasis ? { residualBasis } : {}), ...(draftProjections ? { draftProjections } : {}),
|
|
119
|
+
hiddenLayerTaps: Object.freeze({
|
|
120
|
+
layerCount: model.config.text.numHiddenLayers,
|
|
121
|
+
projection: Object.freeze(projection),
|
|
122
|
+
}), recurrentMtp: Object.freeze({
|
|
123
|
+
hiddenSize: model.config.text.hiddenSize, layerCount: model.config.text.numHiddenLayers,
|
|
124
|
+
embed: model.embed.encode.bind(model.embed), logits: model.logits,
|
|
125
|
+
vocabularyHead: model.lmHead ? Object.freeze({ w: model.lmHead.w, scales: model.lmHead.scales,
|
|
126
|
+
biases: model.lmHead.biases, spec: model.lmHead.spec, vocabSize: model.config.text.vocabSize }) : undefined,
|
|
127
|
+
}) });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** The head's rows of the artifact's frequency-ranked draft vocabulary (`file`, a path inside the artifact) and their
|
|
131
|
+
* projection operations on `kernels` (the head's own layers over those rows), for a graph whose composition
|
|
132
|
+
* measured a drafter selecting over them. A row gather of an affine head is exact: the rows' logits are the full
|
|
133
|
+
* head's arithmetic per row. The gathered arrays go to `owned`, which the graph frees. */
|
|
134
|
+
export function qwenDraftVocabulary(head: QuantizedLinear, modelDir: string, file: string, vocabSize: number,
|
|
135
|
+
kernels: (rows: QuantizedLinear) => DraftHeadOperations,
|
|
136
|
+
owned: { dispose(): void }[]): NonNullable<DraftProjection["vocabulary"]> {
|
|
137
|
+
const listed = readDraftVocabulary(join(modelDir, file), vocabSize);
|
|
138
|
+
using index = ops.fromInt32([...listed], [listed.length]);
|
|
139
|
+
const ids = index.astype(Dtype.uint32);
|
|
140
|
+
owned.push(ids);
|
|
141
|
+
const gather = (array: MlxArray) => {
|
|
142
|
+
using rows = ops.takeAxis(array, index, 0);
|
|
143
|
+
const copy = ops.contiguous(rows);
|
|
144
|
+
owned.push(copy);
|
|
145
|
+
return copy;
|
|
146
|
+
};
|
|
147
|
+
const rows = new QuantizedLinear(gather(head.w), gather(head.scales), head.biases ? gather(head.biases) : null, head.spec);
|
|
148
|
+
ops.evalAll([ids, rows.w, rows.scales, ...(rows.biases ? [rows.biases] : [])]);
|
|
149
|
+
return Object.freeze({ ids, logits: kernels(rows) });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
/** Gather a draft vocabulary only when a source first reads it, then retain
|
|
154
|
+
* the same port and owned weights for every target view. The graph supplies
|
|
155
|
+
* the concrete projection operations over the gathered rows. */
|
|
156
|
+
export function qwenDraftVocabularyMemo(head: QuantizedLinear, modelDir: string, file: string, vocabSize: number,
|
|
157
|
+
kernels: (rows: QuantizedLinear) => DraftHeadOperations,
|
|
158
|
+
owned: { dispose(): void }[]): () => NonNullable<DraftProjection["vocabulary"]> {
|
|
159
|
+
let vocabulary: NonNullable<DraftProjection["vocabulary"]> | undefined;
|
|
160
|
+
return () => vocabulary ??= qwenDraftVocabulary(head, modelDir, file, vocabSize, kernels, owned);
|
|
161
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Qwen MTP numerical graph. Request state, sampling and checkpoint retention
|
|
2
|
+
// belong to its callers; the cache supplies positions and attention storage.
|
|
3
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
4
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
5
|
+
import type { ModelConfig } from "../../artifacts/config";
|
|
6
|
+
import type { Weights } from "../../artifacts/weights";
|
|
7
|
+
import { disposing } from "../../layers/helpers";
|
|
8
|
+
import { QuantizedLinear } from "../../layers/quantized-linear";
|
|
9
|
+
import { RMSNorm } from "../../layers/normalization";
|
|
10
|
+
import { type Cache } from "../../contracts/mlx/cache";
|
|
11
|
+
import type { RecurrentMtpForward, RecurrentMtpModule } from "../../contracts/mlx/drafter";
|
|
12
|
+
import type { MlxRowTable } from "../../contracts/mlx/graph";
|
|
13
|
+
import { DenseLinear } from "../../layers/dense-linear";
|
|
14
|
+
import { compiledSwiglu } from "../../layers/swiglu";
|
|
15
|
+
import { Qwen3Attention } from "./blocks";
|
|
16
|
+
import { rowTable } from "../graph";
|
|
17
|
+
|
|
18
|
+
type MtpLinear = DenseLinear | QuantizedLinear;
|
|
19
|
+
|
|
20
|
+
/** Projection tensors belong to Weights; dense transpose views belong to
|
|
21
|
+
* the provider's resource stack. Quantized heads keep no dense copy. */
|
|
22
|
+
function loadMtpLinear(
|
|
23
|
+
weights: Weights, path: string, config: ModelConfig, resources: DisposableStack,
|
|
24
|
+
): MtpLinear {
|
|
25
|
+
if (weights.has(`${path}.scales`)) return QuantizedLinear.load(weights, path, config);
|
|
26
|
+
const layer = new DenseLinear(weights.tensor(`${path}.weight`), null);
|
|
27
|
+
resources.use(layer.wT);
|
|
28
|
+
return layer;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The one MTP decoder block: fc-merge → attention → swiglu MLP → norm. */
|
|
32
|
+
export class MtpModule implements RecurrentMtpModule {
|
|
33
|
+
readonly fc: MtpLinear;
|
|
34
|
+
readonly preFcNormEmbedding: RMSNorm;
|
|
35
|
+
readonly preFcNormHidden: RMSNorm;
|
|
36
|
+
readonly attn: Qwen3Attention<MtpLinear>;
|
|
37
|
+
readonly mlpGate: MtpLinear;
|
|
38
|
+
readonly mlpUp: MtpLinear;
|
|
39
|
+
readonly mlpDown: MtpLinear;
|
|
40
|
+
readonly inputNorm: RMSNorm;
|
|
41
|
+
readonly postAttnNorm: RMSNorm;
|
|
42
|
+
readonly finalNorm: RMSNorm;
|
|
43
|
+
|
|
44
|
+
constructor(weights: Weights, config: ModelConfig, resources: DisposableStack) {
|
|
45
|
+
const eps = config.text.rmsNormEps;
|
|
46
|
+
this.fc = loadMtpLinear(weights, "fc", config, resources);
|
|
47
|
+
this.preFcNormEmbedding = new RMSNorm(weights.tensor("pre_fc_norm_embedding.weight"), eps);
|
|
48
|
+
this.preFcNormHidden = new RMSNorm(weights.tensor("pre_fc_norm_hidden.weight"), eps);
|
|
49
|
+
// The target's attention block (blocks.ts) with the companion's dense or quantized heads.
|
|
50
|
+
this.attn = new Qwen3Attention<MtpLinear>(weights, config, "layers.0.self_attn",
|
|
51
|
+
(w, path, c) => loadMtpLinear(w, path, c, resources));
|
|
52
|
+
this.mlpGate = loadMtpLinear(weights, "layers.0.mlp.gate_proj", config, resources);
|
|
53
|
+
this.mlpUp = loadMtpLinear(weights, "layers.0.mlp.up_proj", config, resources);
|
|
54
|
+
this.mlpDown = loadMtpLinear(weights, "layers.0.mlp.down_proj", config, resources);
|
|
55
|
+
this.inputNorm = new RMSNorm(weights.tensor("layers.0.input_layernorm.weight"), eps);
|
|
56
|
+
this.postAttnNorm = new RMSNorm(weights.tensor("layers.0.post_attention_layernorm.weight"), eps);
|
|
57
|
+
this.finalNorm = new RMSNorm(weights.tensor("norm.weight"), eps);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** One position per row; the module has one draft kernel set, at every width. */
|
|
61
|
+
readonly decode: MlxRowTable<RecurrentMtpForward> = rowTable<RecurrentMtpForward>(
|
|
62
|
+
(tokenEmbeds, hiddens, cache) => this.#block(tokenEmbeds, hiddens, cache, "decode"));
|
|
63
|
+
/** Several positions per row. */
|
|
64
|
+
readonly window: RecurrentMtpForward = (tokenEmbeds, hiddens, cache) => this.#block(tokenEmbeds, hiddens, cache, "window");
|
|
65
|
+
|
|
66
|
+
/** One block forward over [B,S,·]: token embeddings ([B,S,H], target
|
|
67
|
+
* embed_tokens output) paired with hiddens ([B,S,H], target pre-final-norm
|
|
68
|
+
* or the module's own chained output), the attention reading its cache for
|
|
69
|
+
* `phase`. Appends S rows to `cache`; returns the module output [B,S,H]
|
|
70
|
+
* (post final norm — what the target lm_head consumes AND what chains into
|
|
71
|
+
* the next step's `hidden`). */
|
|
72
|
+
#block(tokenEmbeds: MlxArray, hiddens: MlxArray, cache: Cache, phase: "decode" | "window"): MlxArray {
|
|
73
|
+
const embNorm = this.preFcNormEmbedding.forward(tokenEmbeds);
|
|
74
|
+
const hidNorm = this.preFcNormHidden.forward(hiddens);
|
|
75
|
+
const joined = ops.concatAxis([embNorm, hidNorm], 2);
|
|
76
|
+
embNorm.dispose();
|
|
77
|
+
hidNorm.dispose();
|
|
78
|
+
const x = this.fc.forward(joined);
|
|
79
|
+
joined.dispose();
|
|
80
|
+
|
|
81
|
+
// Decoder layer (Qwen3Layer.forward shape).
|
|
82
|
+
const xn = this.inputNorm.forward(x);
|
|
83
|
+
const r = this.attn.forward(xn, cache, phase);
|
|
84
|
+
xn.dispose();
|
|
85
|
+
const h = ops.add(x, r);
|
|
86
|
+
x.dispose();
|
|
87
|
+
r.dispose();
|
|
88
|
+
const hn = this.postAttnNorm.forward(h);
|
|
89
|
+
const g = this.mlpGate.forward(hn);
|
|
90
|
+
const u = this.mlpUp.forward(hn);
|
|
91
|
+
hn.dispose();
|
|
92
|
+
const act = compiledSwiglu(g, u);
|
|
93
|
+
g.dispose(); u.dispose();
|
|
94
|
+
const m = this.mlpDown.forward(act);
|
|
95
|
+
act.dispose();
|
|
96
|
+
const out = ops.add(h, m);
|
|
97
|
+
h.dispose();
|
|
98
|
+
m.dispose();
|
|
99
|
+
return disposing(out, this.finalNorm.forward(out));
|
|
100
|
+
}
|
|
101
|
+
}
|