@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,433 @@
|
|
|
1
|
+
import type { MlxCacheLayer, MlxMixedRange, MlxSequenceRange } from "../../contracts/mlx/graph";
|
|
2
|
+
// Concrete model graph for Qwen3.5 hybrid models (e.g. Qwen3.6-27B-OptiQ-4bit).
|
|
3
|
+
// Port target: mlx_lm.models.qwen3_5 (+ qwen3_next Attention/MLP/RMSNormGated,
|
|
4
|
+
// gated_delta recurrence). The architecture is a 64-layer stack where every
|
|
5
|
+
// `fullAttentionInterval`-th layer is standard softmax attention and the rest
|
|
6
|
+
// are gated-DeltaNet linear-attention layers. Weights carry a
|
|
7
|
+
// `language_model.` prefix. The blocks live in `blocks.ts`; this graph composes
|
|
8
|
+
// them and hands every block the phase its caller names.
|
|
9
|
+
//
|
|
10
|
+
// Parity bars: bf16 KV → bit-exact vs mlx-lm; mixed-precision KV → bit-exact vs
|
|
11
|
+
// mlx-optiq (the 16 full-attention layers quantized per kv_config.json, via the
|
|
12
|
+
// shared maybeQuantizeKv path).
|
|
13
|
+
|
|
14
|
+
import type { ModelConfig } from "../../artifacts/config";
|
|
15
|
+
import type { Weights } from "../../artifacts/weights";
|
|
16
|
+
|
|
17
|
+
import { mapPackedTokens } from "../../input/token-groups";
|
|
18
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
19
|
+
|
|
20
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
21
|
+
import { qwenAppendChunkSize } from "../../layers/qwen-append";
|
|
22
|
+
import { disposing } from "../../layers/helpers";
|
|
23
|
+
import { LoraState } from "../../layers/lora";
|
|
24
|
+
import { QuantizedEmbedding } from "../../layers/quantized-embedding";
|
|
25
|
+
import { QuantizedLinear, QuantizedLinearPlain, QuantizedLinearRows } from "../../layers/quantized-linear";
|
|
26
|
+
import { RMSNorm } from "../../layers/normalization";
|
|
27
|
+
import { type Cache } from "../../contracts/mlx/cache";
|
|
28
|
+
import { qwen35WeightsView } from "./checkpoint";
|
|
29
|
+
import type { GraphDeclaration } from "../../contracts/portable/graph";
|
|
30
|
+
import type { MlxCapturingForward, MlxDeclaredGraph, MlxHeadForward, MlxKnownSpans, MlxLayerCapture, MlxPromptRange, MlxTokenPhases, MlxVerifyForward, MlxRowTable } from "../../contracts/mlx/graph";
|
|
31
|
+
import type { TargetView } from "../../contracts/mlx/draft-target";
|
|
32
|
+
import type { MediaEncoders, MlxPromptInput, Vision } from "../../contracts/mlx/media";
|
|
33
|
+
import { declareGraph } from "../capabilities";
|
|
34
|
+
import { DEFAULT_PHASE_ROWS, rowTableFrom, type ReadPhase } from "../graph";
|
|
35
|
+
import { bindQwenMediaInput, qwenDraftTarget, qwenMediaEncoders } from "./media-input";
|
|
36
|
+
import { mropeInvFreq } from "../../layers/qwen-mrope";
|
|
37
|
+
import type { MropeForwardState } from "../../contracts/mlx/positions";
|
|
38
|
+
import { Qwen3Layer, QwenAttentionLayer, QwenDeltaLayer, QwenGatedDeltaNet, Qwen3TextAttention, Qwen3MediaAttention, type QwenMlp } from "./blocks";
|
|
39
|
+
import { Dtype, deviceArchitecture } from "@mlx-bun/mlx/ffi";
|
|
40
|
+
import { fusedGateUpEligible, type TrellisLinear } from "../../layers/trellis-linear";
|
|
41
|
+
import { TrellisFusedMLP, TrellisUnfusedMLP, TrellisReducePrompt, TrellisScatterPrompt, TrellisWidePrompt, TrellisTiledPrompt, TrellisSplitKPrompt, TrellisExpandReducePrompt, TrellisExpandScatterPrompt, type RowProjection } from "../../layers/trellis-prompt";
|
|
42
|
+
import { qualifiedRepresentations, wideTrellisPrefillEligible, tiledTrellisPrefillEligible, splitKTrellisPrefillEligible } from "../../kernels/trellis/index";
|
|
43
|
+
|
|
44
|
+
const PREFIX = "language_model";
|
|
45
|
+
|
|
46
|
+
// The generic graph binds device and artifact choices once at construction.
|
|
47
|
+
// Its forwards call the resulting operations without inspecting the device.
|
|
48
|
+
type FixedLayer = QwenDeltaLayer | QwenAttentionLayer;
|
|
49
|
+
interface FixedRange { readonly from: number; readonly to: number; readonly layers: readonly FixedLayer[]; readonly media: readonly FixedLayer[] }
|
|
50
|
+
function packedProjection(base: TrellisLinear): RowProjection {
|
|
51
|
+
return base.geometry.axis === 1 ? new TrellisReducePrompt(base) : new TrellisScatterPrompt(base);
|
|
52
|
+
}
|
|
53
|
+
function expandedProjection(base: TrellisLinear): RowProjection {
|
|
54
|
+
return base.geometry.axis === 1 ? new TrellisExpandReducePrompt(base) : new TrellisExpandScatterPrompt(base);
|
|
55
|
+
}
|
|
56
|
+
function affineMlp(base: Extract<QwenMlp, {kind: "affine"}>): RowProjection {
|
|
57
|
+
return new TrellisUnfusedMLP(new QuantizedLinearPlain(base.gate), new QuantizedLinearPlain(base.up), new QuantizedLinearPlain(base.down));
|
|
58
|
+
}
|
|
59
|
+
/** Main's committed-span qualification, evaluated from loaded projections at construction. */
|
|
60
|
+
export function qwen35KnownSpansEligible(config: ModelConfig, layers: readonly Qwen3Layer[], device: string): boolean {
|
|
61
|
+
const t = config.text;
|
|
62
|
+
if (t.hiddenSize !== 5120 || t.intermediateSize !== 17408 || layers.length !== 64 ||
|
|
63
|
+
t.headDim !== 256 || t.numAttentionHeads !== 24 || t.numKeyValueHeads !== 4 || device !== "applegpu_g16s")
|
|
64
|
+
return false;
|
|
65
|
+
const qualified = (linear: QuantizedLinear) => linear.spec.mode === "affine" &&
|
|
66
|
+
[2, 3, 4, 6, 8].includes(linear.spec.bits) && [32, 64, 128].includes(linear.spec.groupSize);
|
|
67
|
+
return layers.every(layer => {
|
|
68
|
+
const a = layer.linearAttn, s = layer.selfAttn;
|
|
69
|
+
const attention = a ? [a.inProjQkv, a.inProjZ, a.inProjB, a.inProjA, a.outProj]
|
|
70
|
+
: [s!.qProj, s!.kProj, s!.vProj, s!.oProj];
|
|
71
|
+
const mlp = layer.mlp.kind === "affine" ? [layer.mlp.gate, layer.mlp.up, layer.mlp.down] : [];
|
|
72
|
+
return attention.every(qualified) && mlp.every(qualified);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class Qwen35Model implements MlxDeclaredGraph, MlxTokenPhases {
|
|
77
|
+
readonly config: ModelConfig;
|
|
78
|
+
readonly weightsBytes: number;
|
|
79
|
+
/** Base path for LoRA target keys (weights carry the language_model prefix). */
|
|
80
|
+
readonly prefixBase = "language_model.model";
|
|
81
|
+
readonly loraState = new LoraState();
|
|
82
|
+
/** Prepared image and video embeddings with request-owned mRoPE positions,
|
|
83
|
+
* layer taps for drafts. Its few full-attention layers materialize their
|
|
84
|
+
* scores at long context, so prefill chunks shrink to bound that workspace. */
|
|
85
|
+
get graphCapabilities(): GraphDeclaration {
|
|
86
|
+
return declareGraph({
|
|
87
|
+
media: { input: "embeddings+positions", video: true }, hiddenLayerTaps: true,
|
|
88
|
+
prefill: { boundedWorkspace: true },
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
bindMediaInput(input: Vision): MlxPromptInput { return bindQwenMediaInput(this, input.embeddings, input.mrope!); }
|
|
92
|
+
mediaEncoders(modelDir: string): Promise<MediaEncoders> { return qwenMediaEncoders(this, modelDir); }
|
|
93
|
+
draftTarget(_caches: Cache[]): TargetView { return qwenDraftTarget(this); }
|
|
94
|
+
readonly embed: QuantizedEmbedding;
|
|
95
|
+
readonly layers: Qwen3Layer[];
|
|
96
|
+
readonly finalNorm: RMSNorm;
|
|
97
|
+
/** null when tied: the output head reuses embed_tokens (embed.asLinear). */
|
|
98
|
+
readonly lmHead: QuantizedLinear | null;
|
|
99
|
+
readonly tied: boolean;
|
|
100
|
+
readonly faIdx: number;
|
|
101
|
+
readonly #ranges: readonly FixedRange[];
|
|
102
|
+
readonly #adapterOperations: TrellisFusedMLP[] = [];
|
|
103
|
+
readonly #head: (hidden: MlxArray) => MlxArray;
|
|
104
|
+
|
|
105
|
+
constructor(weights: Weights, config: ModelConfig, maxPhaseRows = DEFAULT_PHASE_ROWS, device = deviceArchitecture()) {
|
|
106
|
+
const representations = qualifiedRepresentations(device);
|
|
107
|
+
// Checkpoint-generation normalization BEFORE the first tensor() call: the
|
|
108
|
+
// 5.8-family export names the trunk `model.language_model.*` with a
|
|
109
|
+
// top-level `lm_head`, ships `mtp.*` in-repo, and stores RMSNorm gains as
|
|
110
|
+
// γ−1 with HF-layout conv1d. The view maps all of that onto the names and
|
|
111
|
+
// values this graph reads (mlx-lm's post-sanitize space). No-op — nothing
|
|
112
|
+
// installed at all — for artifacts already in that space.
|
|
113
|
+
const view = qwen35WeightsView(weights);
|
|
114
|
+
if (view) weights.setView(view);
|
|
115
|
+
this.config = config;
|
|
116
|
+
this.tied = config.text.tieWordEmbeddings;
|
|
117
|
+
this.weightsBytes = [...weights.shards.files.values()]
|
|
118
|
+
.reduce((a, f) => a + f.mmap.size, 0);
|
|
119
|
+
this.embed = QuantizedEmbedding.load(weights, `${PREFIX}.model.embed_tokens`, config);
|
|
120
|
+
this.layers = Array.from(
|
|
121
|
+
{ length: config.text.numHiddenLayers },
|
|
122
|
+
(_, i) => new Qwen3Layer(weights, config, i, representations),
|
|
123
|
+
);
|
|
124
|
+
this.finalNorm = new RMSNorm(weights.tensor(`${PREFIX}.model.norm.weight`), config.text.rmsNormEps);
|
|
125
|
+
// Tied models (e.g. Qwen3.5-4B) ship no lm_head; the reference uses
|
|
126
|
+
// embed_tokens.as_linear (mlx-lm qwen3_5 TextModel.__call__).
|
|
127
|
+
this.lmHead = this.tied ? null : QuantizedLinear.load(weights, `${PREFIX}.lm_head`, config);
|
|
128
|
+
this.faIdx = config.text.fullAttentionInterval - 1;
|
|
129
|
+
const head = this.lmHead ? new QuantizedLinearPlain(this.lmHead) : null;
|
|
130
|
+
this.#head = head ? hidden => head.forward(hidden) : hidden => this.embed.asLinear(hidden);
|
|
131
|
+
const narrow = (base: QwenMlp): RowProjection => {
|
|
132
|
+
if (base.kind === "affine") return affineMlp(base);
|
|
133
|
+
const down = packedProjection(base.down);
|
|
134
|
+
if (fusedGateUpEligible(base.gate, base.up)) {
|
|
135
|
+
const operation = new TrellisFusedMLP(base.gate, base.up, down, this.loraState);
|
|
136
|
+
this.#adapterOperations.push(operation); return operation;
|
|
137
|
+
}
|
|
138
|
+
return new TrellisUnfusedMLP(packedProjection(base.gate), packedProjection(base.up), down);
|
|
139
|
+
};
|
|
140
|
+
const windowGate = (base: TrellisLinear): RowProjection =>
|
|
141
|
+
wideTrellisPrefillEligible(base.geometry, 5, Dtype.bfloat16, representations.widePrefill) ? new TrellisWidePrompt(base)
|
|
142
|
+
: tiledTrellisPrefillEligible(base.geometry, 5, Dtype.bfloat16, representations.widePrefill) ? new TrellisTiledPrompt(base) : expandedProjection(base);
|
|
143
|
+
const tiledGate = (base: TrellisLinear): RowProjection =>
|
|
144
|
+
tiledTrellisPrefillEligible(base.geometry, 16, Dtype.bfloat16, representations.widePrefill) ? new TrellisTiledPrompt(base) : expandedProjection(base);
|
|
145
|
+
const splitDown = (base: TrellisLinear): RowProjection =>
|
|
146
|
+
splitKTrellisPrefillEligible(base.geometry, 5, Dtype.bfloat16) ? new TrellisSplitKPrompt(base) : expandedProjection(base);
|
|
147
|
+
const five = (base: QwenMlp) => base.kind === "affine" ? affineMlp(base)
|
|
148
|
+
: new TrellisUnfusedMLP(windowGate(base.gate), windowGate(base.up), splitDown(base.down));
|
|
149
|
+
const nine = (base: QwenMlp) => base.kind === "affine" ? affineMlp(base)
|
|
150
|
+
: new TrellisUnfusedMLP(windowGate(base.gate), windowGate(base.up), expandedProjection(base.down));
|
|
151
|
+
const sixteen = (base: QwenMlp) => base.kind === "affine" ? affineMlp(base)
|
|
152
|
+
: new TrellisUnfusedMLP(tiledGate(base.gate), tiledGate(base.up), expandedProjection(base.down));
|
|
153
|
+
const expanded = (base: QwenMlp) => base.kind === "affine" ? affineMlp(base)
|
|
154
|
+
: new TrellisUnfusedMLP(expandedProjection(base.gate), expandedProjection(base.up), expandedProjection(base.down));
|
|
155
|
+
const bind = (from: number, to: number, mlp: (base: QwenMlp) => RowProjection): FixedRange => {
|
|
156
|
+
const operations = this.layers.map(layer => mlp(layer.mlp));
|
|
157
|
+
return { from, to, layers: this.layers.map((layer, index) => this.#layerView(weights, config, layer, index, operations[index]!, false)),
|
|
158
|
+
media: this.layers.map((layer, index) => this.#layerView(weights, config, layer, index, operations[index]!, true)) };
|
|
159
|
+
};
|
|
160
|
+
const unfusedNarrow=bind(1,4,base=>base.kind==="affine" ? affineMlp(base)
|
|
161
|
+
: new TrellisUnfusedMLP(packedProjection(base.gate),packedProjection(base.up),packedProjection(base.down)));
|
|
162
|
+
this.#ranges = [bind(1, 4, narrow), bind(5, 8, five), bind(9, 15, nine), bind(16, 32, sixteen), bind(33, Infinity, expanded)];
|
|
163
|
+
this.knownSpans = qwen35KnownSpansEligible(config, this.layers, device)
|
|
164
|
+
? Object.freeze({ maxChunkSize: (state: readonly Cache[]) => qwenAppendChunkSize(state[0]!.offset) }) : undefined;
|
|
165
|
+
const forward = (range: FixedRange, phase: ReadPhase, bounded: boolean): MlxCapturingForward => (ids, state, capture) =>
|
|
166
|
+
this.#captured(this.forwardLayers(this.embed.encode(ids), state, phase, undefined, capture, range.layers, bounded), capture);
|
|
167
|
+
const exact = <Op>(build: (range: FixedRange) => Op): MlxRowTable<Op> => {
|
|
168
|
+
const ranges = this.#ranges.map(range => ({ ...range, operation: build(range) }));
|
|
169
|
+
const defaultOperation = ranges.at(-1)!.operation;
|
|
170
|
+
// Admission caps do not remove the component's distinct 1–32 row forms.
|
|
171
|
+
return Object.freeze({ ...rowTableFrom(rows => ranges.find(range => rows >= range.from && rows <= range.to)!.operation, Math.max(32, maxPhaseRows)),
|
|
172
|
+
default: defaultOperation });
|
|
173
|
+
};
|
|
174
|
+
this.decode = exact(range => forward(range, "decode", false));
|
|
175
|
+
this.verify = exact(range => forward(range, "window", false));
|
|
176
|
+
this.appendKnown = this.knownSpans ? this.#committedKnownOperations(weights, config)
|
|
177
|
+
: this.#ranges.map(range => ({ from: range.from, to: range.to, operation: (ids, state) =>
|
|
178
|
+
this.forwardLayers(this.embed.encode(ids), state, "window", undefined, null, range.layers, false) }));
|
|
179
|
+
this.prompt = this.#ranges.map(range => ({ from: range.from, to: range.to, operation: forward(range, "window", range.from > 4) }));
|
|
180
|
+
this.multiSequencePrompt = this.prompt;
|
|
181
|
+
// Main's whole chunks use independent projections even at 1–4 actual
|
|
182
|
+
// rows and materialize each layer and its recurrent state.
|
|
183
|
+
this.promptChunk = [unfusedNarrow, ...this.#ranges.slice(1)].map(range => ({
|
|
184
|
+
from: range.from, to: range.to, operation: forward(range, "window", true) }));
|
|
185
|
+
this.multiSequencePromptChunk = this.promptChunk;
|
|
186
|
+
this.logits = Object.freeze({ default: (hidden: MlxArray) => this.logitsFromHidden(hidden) });
|
|
187
|
+
this.sequence = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
188
|
+
operation: (ids, cache) => this.forwardLayers(this.embed.encode(ids), cache, "window", undefined, null, range.layers, range.from > 4) }));
|
|
189
|
+
this.mediaPrefill = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
190
|
+
operation: (embeds, cache, positions) => this.forwardLayers(ops.contiguous(embeds), cache, "window", positions, null, range.media, range.from > 4) }));
|
|
191
|
+
this.mediaPrompt = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
192
|
+
operation: (ids, cache, positions) => this.forwardLayers(this.embed.encode(ids), cache, "window", positions, null, range.media, range.from > 4) }));
|
|
193
|
+
this.mediaDecode = exact(range => (ids, cache, positions) => this.forwardLayers(this.embed.encode(ids), cache, "decode", positions, null, range.media, false));
|
|
194
|
+
this.embeddingPrompt = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
195
|
+
operation: (embeds, cache) => this.forwardLayers(ops.contiguous(embeds), cache, "window", undefined, null, range.layers, range.from > 4) }));
|
|
196
|
+
this.mixed = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
197
|
+
operation: groups => this.#mixedForward(groups, range.layers) }));
|
|
198
|
+
const packedWithVerification: import("../../contracts/mlx/graph").MlxMixedRange[] = this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
199
|
+
totalTo: range.from === 1 ? 4 : undefined,
|
|
200
|
+
operation: (groups: readonly import("../../contracts/mlx/graph").MlxPhaseGroup[]) => this.#mixedForward(groups, range.layers) }));
|
|
201
|
+
packedWithVerification.push({ from: 1, to: 4, totalFrom: 5,
|
|
202
|
+
operation: groups => this.#mixedForward(groups, unfusedNarrow.layers) });
|
|
203
|
+
const separated = (phase: ReadPhase) => this.#ranges.map(range => ({ from: range.from, to: range.to,
|
|
204
|
+
operation: (group: import("../../contracts/mlx/graph").MlxPhaseGroup) => this.#captured(this.forwardLayers(this.embed.encode(group.ids), group.state, phase,
|
|
205
|
+
undefined, group.capture, range.layers, group.phase === "window" && range.from > 4), group.capture) }));
|
|
206
|
+
this.mixedSeparate = { packed: packedWithVerification, decode: separated("decode"), window: separated("window"), verify: separated("window") };
|
|
207
|
+
|
|
208
|
+
this.cacheLayers = this.layers.map(layer => layer.isLinear ? {kind:"recurrent" as const} : {kind:"full" as const,turboQuant:"dense" as const});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#layerView(weights: Weights, config: ModelConfig, base: Qwen3Layer, index: number, mlp: RowProjection, media: boolean): FixedLayer {
|
|
212
|
+
const prefix = `${PREFIX}.model.layers.${index}`;
|
|
213
|
+
if (base.linearAttn) {
|
|
214
|
+
const b = base.linearAttn;
|
|
215
|
+
return new QwenDeltaLayer(weights, config, prefix, new QwenGatedDeltaNet(weights, config, `${prefix}.linear_attn`, {
|
|
216
|
+
inProjQkv: new QuantizedLinearPlain(b.inProjQkv), inProjZ: new QuantizedLinearPlain(b.inProjZ),
|
|
217
|
+
inProjB: new QuantizedLinearPlain(b.inProjB), inProjA: new QuantizedLinearPlain(b.inProjA), outProj: new QuantizedLinearPlain(b.outProj) }), mlp);
|
|
218
|
+
}
|
|
219
|
+
const b = base.selfAttn!;
|
|
220
|
+
const projections = { qProj: new QuantizedLinearPlain(b.qProj), kProj: new QuantizedLinearPlain(b.kProj),
|
|
221
|
+
vProj: new QuantizedLinearPlain(b.vProj), oProj: new QuantizedLinearPlain(b.oProj) };
|
|
222
|
+
const mixer = media ? new Qwen3MediaAttention(weights, config, `${prefix}.self_attn`, projections)
|
|
223
|
+
: new Qwen3TextAttention(weights, config, `${prefix}.self_attn`, projections);
|
|
224
|
+
return new QwenAttentionLayer(weights, config, prefix, mixer, mlp);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** The committed graph binds independent affine rows before any forward.
|
|
228
|
+
* Trellis projections retain the same fixed prompt ranges as this graph. */
|
|
229
|
+
#committedKnownOperations(weights: Weights, config: ModelConfig): import("../../contracts/mlx/graph").MlxKnownOperations {
|
|
230
|
+
const affine = (base: Extract<QwenMlp, {kind:"affine"}>): RowProjection => new TrellisUnfusedMLP(
|
|
231
|
+
new QuantizedLinearRows(base.gate), new QuantizedLinearRows(base.up), new QuantizedLinearRows(base.down));
|
|
232
|
+
return this.#ranges.map(range => {
|
|
233
|
+
const layers = this.layers.map((base, index): FixedLayer => {
|
|
234
|
+
const prefix = `${PREFIX}.model.layers.${index}`;
|
|
235
|
+
const mlp = base.mlp.kind === "affine" ? affine(base.mlp) : range.layers[index]!.mlp;
|
|
236
|
+
if (base.linearAttn) {
|
|
237
|
+
const b = base.linearAttn;
|
|
238
|
+
return new QwenDeltaLayer(weights, config, prefix, new QwenGatedDeltaNet(weights, config, `${prefix}.linear_attn`, {
|
|
239
|
+
inProjQkv: new QuantizedLinearRows(b.inProjQkv), inProjZ: new QuantizedLinearRows(b.inProjZ),
|
|
240
|
+
inProjB: new QuantizedLinearRows(b.inProjB), inProjA: new QuantizedLinearRows(b.inProjA), outProj: new QuantizedLinearRows(b.outProj),
|
|
241
|
+
}), mlp);
|
|
242
|
+
}
|
|
243
|
+
const b = base.selfAttn!;
|
|
244
|
+
return new QwenAttentionLayer(weights, config, prefix, new Qwen3TextAttention(weights, config, `${prefix}.self_attn`, {
|
|
245
|
+
qProj: new QuantizedLinearRows(b.qProj), kProj: new QuantizedLinearRows(b.kProj),
|
|
246
|
+
vProj: new QuantizedLinearRows(b.vProj), oProj: new QuantizedLinearRows(b.oProj),
|
|
247
|
+
}), mlp);
|
|
248
|
+
});
|
|
249
|
+
return { from: range.from, to: range.to, operation: (ids, state) =>
|
|
250
|
+
this.forwardLayers(this.embed.encode(ids), state, "committed", undefined, null, layers, false) };
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
loraTargets(): Map<string, QuantizedLinear | TrellisLinear> {
|
|
255
|
+
const out = new Map<string, QuantizedLinear | TrellisLinear>();
|
|
256
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
257
|
+
const l = this.layers[i]!;
|
|
258
|
+
const p = `${PREFIX}.model.layers.${i}`;
|
|
259
|
+
if (l.selfAttn) {
|
|
260
|
+
out.set(`${p}.self_attn.q_proj`, l.selfAttn.qProj);
|
|
261
|
+
out.set(`${p}.self_attn.k_proj`, l.selfAttn.kProj);
|
|
262
|
+
out.set(`${p}.self_attn.v_proj`, l.selfAttn.vProj);
|
|
263
|
+
out.set(`${p}.self_attn.o_proj`, l.selfAttn.oProj);
|
|
264
|
+
} else if (l.linearAttn) {
|
|
265
|
+
out.set(`${p}.linear_attn.in_proj_qkv`, l.linearAttn.inProjQkv);
|
|
266
|
+
out.set(`${p}.linear_attn.in_proj_z`, l.linearAttn.inProjZ);
|
|
267
|
+
out.set(`${p}.linear_attn.in_proj_b`, l.linearAttn.inProjB);
|
|
268
|
+
out.set(`${p}.linear_attn.in_proj_a`, l.linearAttn.inProjA);
|
|
269
|
+
out.set(`${p}.linear_attn.out_proj`, l.linearAttn.outProj);
|
|
270
|
+
}
|
|
271
|
+
out.set(`${p}.mlp.gate_proj`, l.mlp.gate);
|
|
272
|
+
out.set(`${p}.mlp.up_proj`, l.mlp.up);
|
|
273
|
+
out.set(`${p}.mlp.down_proj`, l.mlp.down);
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Releases the mRoPE frequencies a vision forward built; the weights are its owner's. */
|
|
279
|
+
dispose(): void {
|
|
280
|
+
for (const operation of this.#adapterOperations) operation.dispose();
|
|
281
|
+
this.#mropeInvFreq?.dispose();
|
|
282
|
+
this.#mropeInvFreq = null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** One cache per layer, the full-attention caches sharing one mask memo:
|
|
286
|
+
* the cache the composition's KV scheme names for each attention layer
|
|
287
|
+
* (`composedFullAttentionCache`). Their TurboQuant read is dense
|
|
288
|
+
* (`denseTurboQuantKernels`): the read decodes keys and values, then runs the
|
|
289
|
+
* fused SDPA. */
|
|
290
|
+
readonly cacheLayers: readonly MlxCacheLayer[];
|
|
291
|
+
readonly sequence: readonly MlxSequenceRange[];
|
|
292
|
+
readonly mediaPrefill: readonly import("../../contracts/mlx/media").MlxPositionedEmbeddingsRange[];
|
|
293
|
+
readonly mediaPrompt: readonly import("../../contracts/mlx/media").MlxPositionedRange[];
|
|
294
|
+
readonly mediaDecode: import("../../contracts/mlx/graph").MlxRowTable<import("../../contracts/mlx/media").MlxPositionedForward>;
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
/** One whole chunk of a prompt; rows are sequences times the chunk size, and
|
|
298
|
+
* each layer's output and recurrent state is evaluated before the next. The
|
|
299
|
+
* GPU is this graph's one unit. */
|
|
300
|
+
readonly prompt: readonly MlxPromptRange[];
|
|
301
|
+
readonly multiSequencePrompt: readonly MlxPromptRange[];
|
|
302
|
+
readonly promptChunk: readonly MlxPromptRange[];
|
|
303
|
+
readonly multiSequencePromptChunk: readonly MlxPromptRange[];
|
|
304
|
+
|
|
305
|
+
/** One new token per sequence: `ids` [sequences, 1], so rows are sequences. */
|
|
306
|
+
readonly decode: MlxRowTable<MlxCapturingForward>;
|
|
307
|
+
|
|
308
|
+
/** A speculative window: each sequence's last accepted token and its drafted
|
|
309
|
+
* tokens, right-padded by the caller to the round's depth, `ids`
|
|
310
|
+
* [sequences, depth + 1], so rows are sequences times (depth + 1). The graph
|
|
311
|
+
* appends all depth + 1 positions; dropping the rejected suffix is the
|
|
312
|
+
* caller's speculative transaction, begun before this call. */
|
|
313
|
+
readonly verify: MlxRowTable<MlxVerifyForward>;
|
|
314
|
+
|
|
315
|
+
/** Main's qualified committed spans, bound once when the generic graph loads. */
|
|
316
|
+
readonly knownSpans: MlxKnownSpans | undefined;
|
|
317
|
+
/** Known tokens: the committed read under `knownSpans`, the window read otherwise. */
|
|
318
|
+
readonly appendKnown: import("../../contracts/mlx/graph").MlxKnownOperations;
|
|
319
|
+
|
|
320
|
+
/** The same output head at every declared numeric row. */
|
|
321
|
+
readonly logits: MlxRowTable<MlxHeadForward>;
|
|
322
|
+
|
|
323
|
+
/** Hands `capture` the post-final-norm output after its layers, and returns it. */
|
|
324
|
+
#captured(hidden: MlxArray, capture: MlxLayerCapture | null): MlxArray {
|
|
325
|
+
capture?.(this.layers.length, hidden);
|
|
326
|
+
return hidden;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Each group's attention reads its own caches and phase. Declared packed
|
|
330
|
+
* operations share the nonverify MLP rows; verification keeps its own geometry.
|
|
331
|
+
* Prompt groups above four rows evaluate each layer and recurrent state. */
|
|
332
|
+
readonly mixed: readonly MlxMixedRange[];
|
|
333
|
+
readonly mixedSeparate: import("../../contracts/mlx/graph").MlxSeparateMixed;
|
|
334
|
+
#mixedForward(groups: readonly import("../../contracts/mlx/graph").MlxPhaseGroup[], layers: readonly FixedLayer[]): MlxArray[] {
|
|
335
|
+
const hidden: MlxArray[] = [];
|
|
336
|
+
const results: MlxArray[] = [];
|
|
337
|
+
const bounded = groups.some(group => group.phase === "window" && group.rows > 4);
|
|
338
|
+
try {
|
|
339
|
+
for (const group of groups) hidden.push(this.embed.encode(group.ids));
|
|
340
|
+
for (const [i, layer] of layers.entries()) {
|
|
341
|
+
const mids: MlxArray[] = [];
|
|
342
|
+
try {
|
|
343
|
+
for (const [row, group] of groups.entries())
|
|
344
|
+
mids.push(layer.forwardAttn(hidden[row]!, group.state[i]!, group.phase === "decode" ? "decode" : "window"));
|
|
345
|
+
const outputs = mapPackedTokens(mids, h => layer.forwardMlp(h));
|
|
346
|
+
for (const row of groups.keys()) { hidden[row]!.dispose(); hidden[row] = outputs[row]!; }
|
|
347
|
+
// Materialize every layer's recurrent tail as well as the residual.
|
|
348
|
+
// It is not a dependency of h and otherwise pins prefill buffers.
|
|
349
|
+
if (bounded) {
|
|
350
|
+
const caches = groups.map(group => group.state[i]!);
|
|
351
|
+
const state = caches.map(cache => cache.state());
|
|
352
|
+
try { ops.evalAll([...hidden, ...state.flat()]); }
|
|
353
|
+
finally { for (const [row, cache] of caches.entries())
|
|
354
|
+
if (cache.stateNeedsDispose) for (const value of state[row]!) value.dispose(); }
|
|
355
|
+
}
|
|
356
|
+
for (const [row, group] of groups.entries()) group.capture?.(i, hidden[row]!);
|
|
357
|
+
} finally { for (const mid of mids) mid.dispose(); }
|
|
358
|
+
}
|
|
359
|
+
for (const [row, group] of groups.entries()) {
|
|
360
|
+
const out = this.finalNorm.forward(hidden[row]!); results.push(out);
|
|
361
|
+
group.capture?.(this.layers.length, out);
|
|
362
|
+
}
|
|
363
|
+
return results;
|
|
364
|
+
} catch (error) { for (const result of results) result.dispose(); throw error; }
|
|
365
|
+
finally { for (const h of hidden) h.dispose(); }
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** The interleaved-mRoPE inverse frequencies, built by the first forward a
|
|
369
|
+
* media request hands its positions; a text forward keeps the fast rope. */
|
|
370
|
+
#mropeInvFreq: MlxArray | null = null;
|
|
371
|
+
|
|
372
|
+
readonly embeddingPrompt: readonly import("../../contracts/mlx/media").MlxEmbeddingsRange[];
|
|
373
|
+
|
|
374
|
+
/** The decoder over `h0` (consumed), every block reading its cache for
|
|
375
|
+
* `phase`, on the fixed layer view the calling operation names.
|
|
376
|
+
* `bounded` evaluates each layer's output and
|
|
377
|
+
* recurrent state before the next. `capture` receives each layer's residual
|
|
378
|
+
* output after the layer runs; the caller hands it the final hidden. */
|
|
379
|
+
protected forwardLayers(h0: MlxArray, cache: Cache[], phase: ReadPhase,
|
|
380
|
+
positions: MlxArray | undefined, capture: MlxLayerCapture | null, layers: readonly FixedLayer[], bounded: boolean): MlxArray {
|
|
381
|
+
const L = h0.shape[1]!;
|
|
382
|
+
// Vision requests: one interleaved-mRoPE cos/sin table per forward,
|
|
383
|
+
// shared by all 12 full-attention layers (positions are layer-invariant).
|
|
384
|
+
let mropeFwd: MropeForwardState | null = null;
|
|
385
|
+
if (positions) {
|
|
386
|
+
const t = this.config.text;
|
|
387
|
+
const ropeDims = Math.trunc(t.headDim * t.partialRotaryFactor);
|
|
388
|
+
const base = t.ropeParameters.full_attention?.ropeTheta ?? 10000;
|
|
389
|
+
this.#mropeInvFreq ??= mropeInvFreq(ropeDims, base);
|
|
390
|
+
mropeFwd = { posIds: positions, invFreq: this.#mropeInvFreq, rotaryDims: ropeDims };
|
|
391
|
+
}
|
|
392
|
+
let h: MlxArray | null = h0;
|
|
393
|
+
const prof = (globalThis as Record<string, unknown>).__deltaProf as
|
|
394
|
+
Record<string, number>
|
|
395
|
+
| undefined;
|
|
396
|
+
try {
|
|
397
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
398
|
+
const tl = prof ? performance.now() : 0;
|
|
399
|
+
const next: MlxArray = layers[i]!.forward(h!, cache[i]!, phase, mropeFwd);
|
|
400
|
+
h!.dispose();
|
|
401
|
+
h = next;
|
|
402
|
+
if (bounded) {
|
|
403
|
+
// Affine prefills also need bounded evaluation: a retained prefix
|
|
404
|
+
// history can leave too little room for the entire deferred graph.
|
|
405
|
+
// Materialize the cache outputs too. In particular, the tiny
|
|
406
|
+
// copied conv tail is not a dependency of `h`; leaving it lazy
|
|
407
|
+
// pins the whole prefill conv buffer until the chunk ends.
|
|
408
|
+
const state = cache[i]!.state();
|
|
409
|
+
try { ops.evalAll([h, ...state]); }
|
|
410
|
+
finally { if (cache[i]!.stateNeedsDispose) for (const a of state) a.dispose(); }
|
|
411
|
+
}
|
|
412
|
+
if (prof) {
|
|
413
|
+
ops.evalAll([h]);
|
|
414
|
+
const key = this.layers[i]!.isLinear ? "layerLin" : "layerFull";
|
|
415
|
+
prof[key] = (prof[key] ?? 0) + performance.now() - tl;
|
|
416
|
+
}
|
|
417
|
+
capture?.(i, h);
|
|
418
|
+
}
|
|
419
|
+
const out = disposing(h, this.finalNorm.forward(h));
|
|
420
|
+
h = null; // consumed — the finally must not double-free
|
|
421
|
+
return out;
|
|
422
|
+
} finally {
|
|
423
|
+
if (mropeFwd && !positions) mropeFwd.posIds.dispose();
|
|
424
|
+
// A mid-loop layer throw must not strand the in-flight [1,L,H]
|
|
425
|
+
// residual (2026-08-18 review).
|
|
426
|
+
h?.dispose();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
logitsFromHidden(h: MlxArray): MlxArray {
|
|
431
|
+
return this.#head(h);
|
|
432
|
+
}
|
|
433
|
+
}
|