@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,1127 @@
|
|
|
1
|
+
import { bindGraphCaches } from "../cache-composition";
|
|
2
|
+
import type { MlxCacheLayer } from "../../contracts/mlx/graph";
|
|
3
|
+
// Dedicated GLM-5.2 correctness graph over the direct Colibri artifact.
|
|
4
|
+
//
|
|
5
|
+
// G2 deliberately favors an auditable dequantize->f32 path. Routed experts are
|
|
6
|
+
// resolved by their exact tensor names and composed in route order. G3 swaps
|
|
7
|
+
// that expert resolver for bounded slabs/LRU without changing this graph.
|
|
8
|
+
|
|
9
|
+
import { gpuStream,MlxArray } from "@mlx-bun/mlx/array";
|
|
10
|
+
import { synchronize } from "@mlx-bun/mlx/ffi";
|
|
11
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
12
|
+
import type { ModelConfig } from "../../artifacts/config";
|
|
13
|
+
import { loadModelConfig } from "../../artifacts/config";
|
|
14
|
+
import {
|
|
15
|
+
loadGlm52Config,
|
|
16
|
+
type Glm52Config,
|
|
17
|
+
} from "../../artifacts/glm52-config";
|
|
18
|
+
import { validateGlm52ContainerLayout } from "../../artifacts/glm52/layout";
|
|
19
|
+
import { ColibriGlm52ResidentWeights } from "../../artifacts/glm52/resident-weights";
|
|
20
|
+
import { ColibriGlm52Weights } from "../../artifacts/glm52/weights";
|
|
21
|
+
import { type Cache, type LatentAttentionCache } from "../../contracts/mlx/cache";
|
|
22
|
+
import { LoraState } from "../../layers/lora";
|
|
23
|
+
import type { GraphDeclaration } from "../../contracts/portable/graph";
|
|
24
|
+
import type { MlxRowTable, MlxCapturingForward, MlxDeclaredGraph, MlxHeadForward, MlxKnownOperations, MlxPromptRange, MlxTokenPhases } from "../../contracts/mlx/graph";
|
|
25
|
+
import { declareGraph } from "../capabilities";
|
|
26
|
+
import { type QuantizedLinear } from "../../layers/quantized-linear";
|
|
27
|
+
import type { CacheCodecProvider } from "../../state/persistence-types";
|
|
28
|
+
import { BF16_KV, type KvStorageScheme } from "../../contracts/portable/composition";
|
|
29
|
+
import {
|
|
30
|
+
glm52DsaScoresMlx,
|
|
31
|
+
Glm52DsaSelectionState,
|
|
32
|
+
type Glm52DsaSelectionObserver,
|
|
33
|
+
} from "./dsa";
|
|
34
|
+
import { Glm52MtpGraph } from "./mtp";
|
|
35
|
+
import { Glm52Mla,partialInterleavedRopeMlx,rmsNormF32Mlx,type Glm52MlaBatchedSelection,GLM52_PHASE_READS,type Glm52PhaseReads } from "./mla";
|
|
36
|
+
import {
|
|
37
|
+
composeGlm52MoeOutputsMlx,
|
|
38
|
+
planGlm52MoeBatchF32,
|
|
39
|
+
routeGlm52MoeF32,
|
|
40
|
+
type Glm52RoutedExpertOutput,
|
|
41
|
+
} from "./moe";
|
|
42
|
+
import { Glm52PilotTracker } from "./pilot";
|
|
43
|
+
import {
|
|
44
|
+
Glm52ExpertRuntime,
|
|
45
|
+
type Glm52ExpertRuntimeOptions,
|
|
46
|
+
} from "./residency";
|
|
47
|
+
import type { Glm52ExpertExecutionBackend } from "./streamed-experts";
|
|
48
|
+
import { NATIVE_MTP_DRAFT } from "../drafters";
|
|
49
|
+
|
|
50
|
+
export interface Glm52ModelCapabilities {
|
|
51
|
+
readonly dsa: boolean;
|
|
52
|
+
/** The artifact contains the complete native MTP metadata/tensor family. */
|
|
53
|
+
readonly mtpMetadata: boolean;
|
|
54
|
+
/** The native MTP weights/tier are loaded for this model instance. */
|
|
55
|
+
readonly mtpEnabled?: boolean;
|
|
56
|
+
/** Draft tokens per round the loaded MTP tier was planned for. */
|
|
57
|
+
readonly mtpDraftTokens?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The composition's KV scheme and paging, which a GLM-5.2 graph's latent
|
|
61
|
+
* caches compose (`composedLatentCache`): the latent, RoPE key and DSA index
|
|
62
|
+
* key stored as the scheme names, in pages under paging. */
|
|
63
|
+
export interface Glm52LatentCaches {
|
|
64
|
+
readonly kv: KvStorageScheme;
|
|
65
|
+
readonly pagedKv: { readonly blockSize: number } | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** f32 latent state, unpaged: the checkpoint-native storage (`MLACache`). */
|
|
69
|
+
export const GLM52_F32_CACHES: Glm52LatentCaches = Object.freeze({ kv: BF16_KV, pagedKv: null });
|
|
70
|
+
|
|
71
|
+
export interface Glm52StreamedOpenOptions
|
|
72
|
+
extends Omit<Glm52ExpertRuntimeOptions, "fixedBytes"> {
|
|
73
|
+
/** The latent caches' scheme and paging (default f32, unpaged). */
|
|
74
|
+
readonly caches?: Glm52LatentCaches;
|
|
75
|
+
/** KV/transient/allocator/Bun/OS reserve, excluding resident weights. */
|
|
76
|
+
readonly reserveBytes: number;
|
|
77
|
+
/** Internal counterfactual control; indexer weights remain resident. */
|
|
78
|
+
readonly enableDsa?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Stage-2 benchmark seam: build long contexts with dense batched prefill,
|
|
81
|
+
* then exercise exact DSA on one-token decode. Normal serving stays exact.
|
|
82
|
+
*/
|
|
83
|
+
readonly dsaPrefillMode?: "exact" | "dense-benchmark";
|
|
84
|
+
/** Exact prompt length covered by `dense-benchmark`; required in that mode. */
|
|
85
|
+
readonly dsaBenchmarkPrefillTokens?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface DsaStep {
|
|
89
|
+
readonly key: MlxArray;
|
|
90
|
+
/** Borrowed from the request-local selection state; do not dispose here. */
|
|
91
|
+
readonly selectedPositions: MlxArray | Glm52MlaBatchedSelection | null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Native MTP verifies at most gamma+1 rows under the 64-slot expert union. */
|
|
95
|
+
const GLM52_DSA_SPARSE_DECODE_BATCH_MAX = 8;
|
|
96
|
+
|
|
97
|
+
function swiglu(
|
|
98
|
+
source: Glm52WeightSource,
|
|
99
|
+
input: MlxArray,
|
|
100
|
+
prefix: string,
|
|
101
|
+
intermediate: number,
|
|
102
|
+
hidden: number,
|
|
103
|
+
): MlxArray {
|
|
104
|
+
const gate = source.linear(
|
|
105
|
+
input,
|
|
106
|
+
`${prefix}.gate_proj.weight`,
|
|
107
|
+
intermediate,
|
|
108
|
+
hidden,
|
|
109
|
+
);
|
|
110
|
+
const up = source.linear(
|
|
111
|
+
input,
|
|
112
|
+
`${prefix}.up_proj.weight`,
|
|
113
|
+
intermediate,
|
|
114
|
+
hidden,
|
|
115
|
+
);
|
|
116
|
+
const activated = ops.silu(gate);
|
|
117
|
+
const product = ops.mul(activated, up);
|
|
118
|
+
gate.dispose();
|
|
119
|
+
up.dispose();
|
|
120
|
+
activated.dispose();
|
|
121
|
+
const output = source.linear(
|
|
122
|
+
product,
|
|
123
|
+
`${prefix}.down_proj.weight`,
|
|
124
|
+
hidden,
|
|
125
|
+
intermediate,
|
|
126
|
+
);
|
|
127
|
+
product.dispose();
|
|
128
|
+
return output;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
class Glm52DsaIndexer {
|
|
132
|
+
readonly prefix: string;
|
|
133
|
+
|
|
134
|
+
constructor(
|
|
135
|
+
readonly config: Glm52Config,
|
|
136
|
+
readonly weights: Glm52WeightSource,
|
|
137
|
+
readonly layer: number,
|
|
138
|
+
) {
|
|
139
|
+
this.prefix = `model.layers.${layer}.self_attn.indexer`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
projectAndSelect(
|
|
143
|
+
input: MlxArray,
|
|
144
|
+
cache: LatentAttentionCache,
|
|
145
|
+
state: Glm52DsaSelectionState,
|
|
146
|
+
forceDense = false,
|
|
147
|
+
): DsaStep {
|
|
148
|
+
const [batch, tokens, hidden] = input.shape;
|
|
149
|
+
if (hidden !== this.config.hiddenSize)
|
|
150
|
+
throw new Error(`DSA hidden width ${hidden} != ${this.config.hiddenSize}`);
|
|
151
|
+
|
|
152
|
+
const positionOffset = batch! > 1
|
|
153
|
+
? (cache.rowOffsets.length
|
|
154
|
+
? cache.rowOffsets
|
|
155
|
+
: new Array(batch!).fill(0) as number[])
|
|
156
|
+
: cache.offset;
|
|
157
|
+
const qA = this.weights.linear(
|
|
158
|
+
input,
|
|
159
|
+
`model.layers.${this.layer}.self_attn.q_a_proj.weight`,
|
|
160
|
+
this.config.qLoraRank,
|
|
161
|
+
this.config.hiddenSize,
|
|
162
|
+
);
|
|
163
|
+
const qNorm = rmsNormF32Mlx(
|
|
164
|
+
qA,
|
|
165
|
+
this.weights.tensor(
|
|
166
|
+
`model.layers.${this.layer}.self_attn.q_a_layernorm.weight`,
|
|
167
|
+
),
|
|
168
|
+
this.config.rmsNormEps,
|
|
169
|
+
);
|
|
170
|
+
qA.dispose();
|
|
171
|
+
const queryFlat = this.weights.linear(
|
|
172
|
+
qNorm,
|
|
173
|
+
`${this.prefix}.wq_b.weight`,
|
|
174
|
+
this.config.indexNumHeads * this.config.indexHeadDim,
|
|
175
|
+
this.config.qLoraRank,
|
|
176
|
+
);
|
|
177
|
+
qNorm.dispose();
|
|
178
|
+
const queryRaw = ops.reshape(queryFlat, [
|
|
179
|
+
batch!,
|
|
180
|
+
tokens!,
|
|
181
|
+
this.config.indexNumHeads,
|
|
182
|
+
this.config.indexHeadDim,
|
|
183
|
+
]);
|
|
184
|
+
queryFlat.dispose();
|
|
185
|
+
const query = partialInterleavedRopeMlx(
|
|
186
|
+
queryRaw,
|
|
187
|
+
positionOffset,
|
|
188
|
+
this.config.qkRopeHeadDim,
|
|
189
|
+
this.config.ropeTheta,
|
|
190
|
+
1,
|
|
191
|
+
);
|
|
192
|
+
queryRaw.dispose();
|
|
193
|
+
|
|
194
|
+
const keyRaw = this.weights.linear(
|
|
195
|
+
input,
|
|
196
|
+
`${this.prefix}.wk.weight`,
|
|
197
|
+
this.config.indexHeadDim,
|
|
198
|
+
this.config.hiddenSize,
|
|
199
|
+
);
|
|
200
|
+
const keyNorm = ops.layerNorm(
|
|
201
|
+
keyRaw,
|
|
202
|
+
this.weights.tensor(`${this.prefix}.k_norm.weight`),
|
|
203
|
+
this.weights.tensor(`${this.prefix}.k_norm.bias`),
|
|
204
|
+
1e-6,
|
|
205
|
+
);
|
|
206
|
+
keyRaw.dispose();
|
|
207
|
+
const key = partialInterleavedRopeMlx(
|
|
208
|
+
keyNorm,
|
|
209
|
+
positionOffset,
|
|
210
|
+
this.config.qkRopeHeadDim,
|
|
211
|
+
this.config.ropeTheta,
|
|
212
|
+
1,
|
|
213
|
+
);
|
|
214
|
+
keyNorm.dispose();
|
|
215
|
+
|
|
216
|
+
const headWeights = this.weights.linear(
|
|
217
|
+
input,
|
|
218
|
+
`${this.prefix}.weights_proj.weight`,
|
|
219
|
+
this.config.indexNumHeads,
|
|
220
|
+
this.config.hiddenSize,
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
let allKeys = key;
|
|
224
|
+
const prior = cache.storedIndexKeys();
|
|
225
|
+
if (prior) {
|
|
226
|
+
allKeys = ops.concatAxis([prior, key], 1);
|
|
227
|
+
prior.dispose();
|
|
228
|
+
}
|
|
229
|
+
const contextLength = allKeys.shape[1]!;
|
|
230
|
+
let selectedPositions: MlxArray | Glm52MlaBatchedSelection | null;
|
|
231
|
+
if (forceDense || contextLength <= this.config.indexTopk) {
|
|
232
|
+
state.selectFullDense(this.layer, contextLength);
|
|
233
|
+
selectedPositions = null;
|
|
234
|
+
} else if (batch! > 1) {
|
|
235
|
+
const rowSelections: Array<MlxArray | null> = [];
|
|
236
|
+
for (let row = 0; row < batch!; row++) {
|
|
237
|
+
const rowContext = (cache.rowOffsets[row] ?? 0) + tokens!;
|
|
238
|
+
if (rowContext <= this.config.indexTopk) {
|
|
239
|
+
rowSelections.push(null);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const pad = contextLength - rowContext;
|
|
243
|
+
const queryRow = query.slice(
|
|
244
|
+
[row, 0, 0, 0],
|
|
245
|
+
[row + 1, 1, this.config.indexNumHeads, this.config.indexHeadDim],
|
|
246
|
+
);
|
|
247
|
+
const query2d = ops.reshape(queryRow, [
|
|
248
|
+
this.config.indexNumHeads,
|
|
249
|
+
this.config.indexHeadDim,
|
|
250
|
+
]);
|
|
251
|
+
queryRow.dispose();
|
|
252
|
+
const keysRow = allKeys.slice(
|
|
253
|
+
[row, pad, 0],
|
|
254
|
+
[row + 1, contextLength, this.config.indexHeadDim],
|
|
255
|
+
);
|
|
256
|
+
const keys2d = ops.reshape(keysRow, [
|
|
257
|
+
rowContext,
|
|
258
|
+
this.config.indexHeadDim,
|
|
259
|
+
]);
|
|
260
|
+
keysRow.dispose();
|
|
261
|
+
const weightsRow = headWeights.slice(
|
|
262
|
+
[row, 0, 0],
|
|
263
|
+
[row + 1, 1, this.config.indexNumHeads],
|
|
264
|
+
);
|
|
265
|
+
const weights1d = ops.reshape(weightsRow, [this.config.indexNumHeads]);
|
|
266
|
+
weightsRow.dispose();
|
|
267
|
+
const scores = glm52DsaScoresMlx(query2d, keys2d, weights1d);
|
|
268
|
+
rowSelections.push(state.selectFullDevice(this.layer, scores, row));
|
|
269
|
+
query2d.dispose();
|
|
270
|
+
keys2d.dispose();
|
|
271
|
+
weights1d.dispose();
|
|
272
|
+
scores.dispose();
|
|
273
|
+
}
|
|
274
|
+
selectedPositions = { rows: rowSelections };
|
|
275
|
+
} else {
|
|
276
|
+
if (tokens !== 1) {
|
|
277
|
+
if (allKeys !== key) allKeys.dispose();
|
|
278
|
+
query.dispose();
|
|
279
|
+
headWeights.dispose();
|
|
280
|
+
key.dispose();
|
|
281
|
+
throw new Error(
|
|
282
|
+
"G2 DSA sparse prefill beyond index_topk is not yet supported; " +
|
|
283
|
+
"use serial decode or a shorter prefill",
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const query2d = ops.reshape(query, [
|
|
287
|
+
this.config.indexNumHeads,
|
|
288
|
+
this.config.indexHeadDim,
|
|
289
|
+
]);
|
|
290
|
+
const keys2d = ops.reshape(allKeys, [
|
|
291
|
+
contextLength,
|
|
292
|
+
this.config.indexHeadDim,
|
|
293
|
+
]);
|
|
294
|
+
const weights1d = ops.reshape(headWeights, [
|
|
295
|
+
this.config.indexNumHeads,
|
|
296
|
+
]);
|
|
297
|
+
const scores = glm52DsaScoresMlx(query2d, keys2d, weights1d);
|
|
298
|
+
selectedPositions = state.selectFullDevice(this.layer, scores);
|
|
299
|
+
query2d.dispose();
|
|
300
|
+
keys2d.dispose();
|
|
301
|
+
weights1d.dispose();
|
|
302
|
+
scores.dispose();
|
|
303
|
+
}
|
|
304
|
+
if (allKeys !== key) allKeys.dispose();
|
|
305
|
+
query.dispose();
|
|
306
|
+
headWeights.dispose();
|
|
307
|
+
return { key, selectedPositions };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
class Glm52Mlp {
|
|
312
|
+
constructor(
|
|
313
|
+
readonly config: Glm52Config,
|
|
314
|
+
readonly weights: Glm52WeightSource,
|
|
315
|
+
readonly layer: number,
|
|
316
|
+
readonly expertBackend: Glm52ExpertExecutionBackend | null = null,
|
|
317
|
+
readonly pilot: Glm52PilotTracker | null = null,
|
|
318
|
+
) {}
|
|
319
|
+
|
|
320
|
+
forward(input: MlxArray): MlxArray {
|
|
321
|
+
const prefix = `model.layers.${this.layer}.mlp`;
|
|
322
|
+
if (this.layer < this.config.firstKDenseReplace) {
|
|
323
|
+
return swiglu(
|
|
324
|
+
this.weights,
|
|
325
|
+
input,
|
|
326
|
+
prefix,
|
|
327
|
+
this.config.intermediateSize,
|
|
328
|
+
this.config.hiddenSize,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
if (this.expertBackend)
|
|
332
|
+
throw new Error("streamed GLM routed experts require forwardAsync()");
|
|
333
|
+
|
|
334
|
+
const router = this.weights.tensor(`${prefix}.gate.weight`);
|
|
335
|
+
const routerTranspose = ops.transposeAxes(router, [1, 0]);
|
|
336
|
+
const logits = ops.matmul(input, routerTranspose);
|
|
337
|
+
routerTranspose.dispose();
|
|
338
|
+
const logitsHost = logits.toFloat32();
|
|
339
|
+
logits.dispose();
|
|
340
|
+
const correctionBias = this.weights
|
|
341
|
+
.tensor(`${prefix}.gate.e_score_correction_bias`)
|
|
342
|
+
.toFloat32();
|
|
343
|
+
const [batch, tokens] = input.shape;
|
|
344
|
+
|
|
345
|
+
const sharedIntermediate =
|
|
346
|
+
this.config.moeIntermediateSize * this.config.numSharedExperts;
|
|
347
|
+
const shared = sharedIntermediate > 0
|
|
348
|
+
? swiglu(
|
|
349
|
+
this.weights,
|
|
350
|
+
input,
|
|
351
|
+
`${prefix}.shared_experts`,
|
|
352
|
+
sharedIntermediate,
|
|
353
|
+
this.config.hiddenSize,
|
|
354
|
+
)
|
|
355
|
+
: null;
|
|
356
|
+
|
|
357
|
+
const batchOutputs: MlxArray[] = [];
|
|
358
|
+
try {
|
|
359
|
+
for (let b = 0; b < batch!; b++) {
|
|
360
|
+
const tokenOutputs: MlxArray[] = [];
|
|
361
|
+
try {
|
|
362
|
+
for (let token = 0; token < tokens!; token++) {
|
|
363
|
+
const base = (b * tokens! + token) * this.config.numRoutedExperts;
|
|
364
|
+
const route = routeGlm52MoeF32(
|
|
365
|
+
logitsHost.subarray(
|
|
366
|
+
base,
|
|
367
|
+
base + this.config.numRoutedExperts,
|
|
368
|
+
),
|
|
369
|
+
correctionBias,
|
|
370
|
+
{
|
|
371
|
+
topK: this.config.numExpertsPerToken,
|
|
372
|
+
normalize: this.config.normTopkProb,
|
|
373
|
+
routedScale: this.config.routedScalingFactor,
|
|
374
|
+
},
|
|
375
|
+
);
|
|
376
|
+
const row = input.slice(
|
|
377
|
+
[b, token, 0],
|
|
378
|
+
[b + 1, token + 1, this.config.hiddenSize],
|
|
379
|
+
);
|
|
380
|
+
const routed: Array<Glm52RoutedExpertOutput<MlxArray>> = [];
|
|
381
|
+
try {
|
|
382
|
+
for (const expertId of route.indices) {
|
|
383
|
+
routed.push({
|
|
384
|
+
expertId,
|
|
385
|
+
output: swiglu(
|
|
386
|
+
this.weights,
|
|
387
|
+
row,
|
|
388
|
+
`${prefix}.experts.${expertId}`,
|
|
389
|
+
this.config.moeIntermediateSize,
|
|
390
|
+
this.config.hiddenSize,
|
|
391
|
+
),
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
const sharedRow = shared?.slice(
|
|
395
|
+
[b, token, 0],
|
|
396
|
+
[b + 1, token + 1, this.config.hiddenSize],
|
|
397
|
+
) ?? null;
|
|
398
|
+
const output = composeGlm52MoeOutputsMlx(
|
|
399
|
+
route,
|
|
400
|
+
routed,
|
|
401
|
+
sharedRow,
|
|
402
|
+
);
|
|
403
|
+
sharedRow?.dispose();
|
|
404
|
+
tokenOutputs.push(output);
|
|
405
|
+
} finally {
|
|
406
|
+
row.dispose();
|
|
407
|
+
for (const contribution of routed)
|
|
408
|
+
contribution.output.dispose();
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const batchOutput = tokenOutputs.length === 1
|
|
412
|
+
? tokenOutputs[0]!
|
|
413
|
+
: ops.concatAxis(tokenOutputs, 1);
|
|
414
|
+
batchOutputs.push(batchOutput);
|
|
415
|
+
} finally {
|
|
416
|
+
if (tokenOutputs.length > 1)
|
|
417
|
+
for (const output of tokenOutputs) output.dispose();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return batchOutputs.length === 1
|
|
421
|
+
? batchOutputs[0]!
|
|
422
|
+
: ops.concatAxis(batchOutputs, 0);
|
|
423
|
+
} finally {
|
|
424
|
+
shared?.dispose();
|
|
425
|
+
if (batchOutputs.length > 1)
|
|
426
|
+
for (const output of batchOutputs) output.dispose();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async forwardAsync(input: MlxArray): Promise<MlxArray> {
|
|
431
|
+
const prefix = `model.layers.${this.layer}.mlp`;
|
|
432
|
+
if (this.layer < this.config.firstKDenseReplace || !this.expertBackend)
|
|
433
|
+
return this.forward(input);
|
|
434
|
+
|
|
435
|
+
const router = this.weights.tensor(`${prefix}.gate.weight`);
|
|
436
|
+
const routerTranspose = ops.transposeAxes(router, [1, 0]);
|
|
437
|
+
const logits = ops.matmul(input, routerTranspose);
|
|
438
|
+
routerTranspose.dispose();
|
|
439
|
+
const logitsHost = logits.toFloat32();
|
|
440
|
+
logits.dispose();
|
|
441
|
+
const correctionBias = this.weights
|
|
442
|
+
.tensor(`${prefix}.gate.e_score_correction_bias`)
|
|
443
|
+
.toFloat32();
|
|
444
|
+
const [batch, tokens] = input.shape;
|
|
445
|
+
const logitsByRow: Float32Array[] = [];
|
|
446
|
+
for (let row = 0; row < batch! * tokens!; row++) {
|
|
447
|
+
const begin = row * this.config.numRoutedExperts;
|
|
448
|
+
logitsByRow.push(
|
|
449
|
+
logitsHost.subarray(begin, begin + this.config.numRoutedExperts),
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
const plan = planGlm52MoeBatchF32(
|
|
453
|
+
logitsByRow,
|
|
454
|
+
correctionBias,
|
|
455
|
+
{
|
|
456
|
+
topK: this.config.numExpertsPerToken,
|
|
457
|
+
normalize: this.config.normTopkProb,
|
|
458
|
+
routedScale: this.config.routedScalingFactor,
|
|
459
|
+
},
|
|
460
|
+
);
|
|
461
|
+
this.pilot?.observeActual(this.layer, plan.routes);
|
|
462
|
+
const sharedIntermediate =
|
|
463
|
+
this.config.moeIntermediateSize * this.config.numSharedExperts;
|
|
464
|
+
const shared = sharedIntermediate > 0
|
|
465
|
+
? swiglu(
|
|
466
|
+
this.weights,
|
|
467
|
+
input,
|
|
468
|
+
`${prefix}.shared_experts`,
|
|
469
|
+
sharedIntermediate,
|
|
470
|
+
this.config.hiddenSize,
|
|
471
|
+
)
|
|
472
|
+
: null;
|
|
473
|
+
try {
|
|
474
|
+
return await this.expertBackend.execute({
|
|
475
|
+
layer: this.layer,
|
|
476
|
+
input,
|
|
477
|
+
plan,
|
|
478
|
+
shared,
|
|
479
|
+
});
|
|
480
|
+
} finally {
|
|
481
|
+
shared?.dispose();
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export class Glm52DecoderLayer {
|
|
487
|
+
readonly mla: Glm52Mla;
|
|
488
|
+
readonly mlp: Glm52Mlp;
|
|
489
|
+
readonly dsa: Glm52DsaIndexer | null;
|
|
490
|
+
readonly inputNorm: MlxArray;
|
|
491
|
+
readonly postAttentionNorm: MlxArray;
|
|
492
|
+
|
|
493
|
+
constructor(
|
|
494
|
+
readonly config: Glm52Config,
|
|
495
|
+
readonly weights: Glm52WeightSource,
|
|
496
|
+
readonly layer: number,
|
|
497
|
+
hasDsa: boolean,
|
|
498
|
+
expertBackend: Glm52ExpertExecutionBackend | null = null,
|
|
499
|
+
pilot: Glm52PilotTracker | null = null,
|
|
500
|
+
readonly denseBenchmarkPrefillTokens = 0,
|
|
501
|
+
) {
|
|
502
|
+
const prefix = `model.layers.${layer}`;
|
|
503
|
+
this.mla = new Glm52Mla(config, weights, layer);
|
|
504
|
+
this.mlp = new Glm52Mlp(config, weights, layer, expertBackend, pilot);
|
|
505
|
+
this.inputNorm = weights.tensor(`${prefix}.input_layernorm.weight`);
|
|
506
|
+
this.postAttentionNorm = weights.tensor(
|
|
507
|
+
`${prefix}.post_attention_layernorm.weight`,
|
|
508
|
+
);
|
|
509
|
+
this.dsa = hasDsa && config.indexerTypes[layer] === "full"
|
|
510
|
+
? new Glm52DsaIndexer(config, weights, layer)
|
|
511
|
+
: null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Keep a small sparse verify window batched through residual/MLP while
|
|
516
|
+
* evaluating its causal DSA+MLA attention rows serially. This preserves one
|
|
517
|
+
* exact selection per query without collapsing native MTP into full-model
|
|
518
|
+
* M=1 forwards.
|
|
519
|
+
*/
|
|
520
|
+
private attend(
|
|
521
|
+
input: MlxArray,
|
|
522
|
+
cache: LatentAttentionCache,
|
|
523
|
+
dsaState: Glm52DsaSelectionState | null,
|
|
524
|
+
reads: Glm52PhaseReads,
|
|
525
|
+
): MlxArray {
|
|
526
|
+
const normalized = rmsNormF32Mlx(
|
|
527
|
+
input,
|
|
528
|
+
this.inputNorm,
|
|
529
|
+
this.config.rmsNormEps,
|
|
530
|
+
);
|
|
531
|
+
const batch = input.shape[0]!;
|
|
532
|
+
const tokens = input.shape[1]!;
|
|
533
|
+
const denseBenchmarkPrefill =
|
|
534
|
+
this.denseBenchmarkPrefillTokens > 0 &&
|
|
535
|
+
tokens > 1 &&
|
|
536
|
+
cache.offset + tokens <= this.denseBenchmarkPrefillTokens;
|
|
537
|
+
const sparseVerifyBatch =
|
|
538
|
+
dsaState !== null &&
|
|
539
|
+
tokens > 1 &&
|
|
540
|
+
tokens <= GLM52_DSA_SPARSE_DECODE_BATCH_MAX &&
|
|
541
|
+
cache.offset + tokens > this.config.indexTopk &&
|
|
542
|
+
!denseBenchmarkPrefill;
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
if (sparseVerifyBatch) {
|
|
546
|
+
const rows: MlxArray[] = [];
|
|
547
|
+
try {
|
|
548
|
+
for (let token = 0; token < tokens; token++) {
|
|
549
|
+
const row = normalized.slice(
|
|
550
|
+
[0, token, 0],
|
|
551
|
+
[batch, token + 1, this.config.hiddenSize],
|
|
552
|
+
);
|
|
553
|
+
let dsaKey: MlxArray | null = null;
|
|
554
|
+
let positions: MlxArray | Glm52MlaBatchedSelection | null = null;
|
|
555
|
+
try {
|
|
556
|
+
if (this.dsa) {
|
|
557
|
+
const step = this.dsa.projectAndSelect(
|
|
558
|
+
row,
|
|
559
|
+
cache,
|
|
560
|
+
dsaState,
|
|
561
|
+
);
|
|
562
|
+
dsaKey = step.key;
|
|
563
|
+
positions = step.selectedPositions;
|
|
564
|
+
} else {
|
|
565
|
+
positions = batch > 1
|
|
566
|
+
? { rows: Array.from({ length: batch }, (_, row) =>
|
|
567
|
+
dsaState.selectSharedPositions(this.layer, (cache.rowOffsets[row] ?? 0) + 1, row)) }
|
|
568
|
+
: dsaState.selectSharedPositions(this.layer, cache.offset + 1);
|
|
569
|
+
}
|
|
570
|
+
rows.push(this.mla.forward(
|
|
571
|
+
row,
|
|
572
|
+
cache,
|
|
573
|
+
dsaKey,
|
|
574
|
+
reads.tokenSerial,
|
|
575
|
+
positions,
|
|
576
|
+
));
|
|
577
|
+
} finally {
|
|
578
|
+
row.dispose();
|
|
579
|
+
dsaKey?.dispose();
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return ops.concatAxis(rows, 1);
|
|
583
|
+
} finally {
|
|
584
|
+
for (const row of rows) row.dispose();
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
let dsaKey: MlxArray | null = null;
|
|
589
|
+
let positions: MlxArray | Glm52MlaBatchedSelection | null = null;
|
|
590
|
+
try {
|
|
591
|
+
if (this.dsa) {
|
|
592
|
+
if (!dsaState) throw new Error("DSA full layer has no selection state");
|
|
593
|
+
const step = this.dsa.projectAndSelect(
|
|
594
|
+
normalized,
|
|
595
|
+
cache,
|
|
596
|
+
dsaState,
|
|
597
|
+
denseBenchmarkPrefill,
|
|
598
|
+
);
|
|
599
|
+
dsaKey = step.key;
|
|
600
|
+
positions = step.selectedPositions;
|
|
601
|
+
} else if (dsaState) {
|
|
602
|
+
positions = denseBenchmarkPrefill || cache.offset + tokens <= this.config.indexTopk
|
|
603
|
+
? null
|
|
604
|
+
: cache.batchSize !== null && cache.batchSize > 1
|
|
605
|
+
? {
|
|
606
|
+
rows: cache.rowOffsets.map((offset, row) =>
|
|
607
|
+
dsaState.selectSharedPositions(
|
|
608
|
+
this.layer,
|
|
609
|
+
offset + tokens,
|
|
610
|
+
row,
|
|
611
|
+
)
|
|
612
|
+
),
|
|
613
|
+
}
|
|
614
|
+
: dsaState.selectSharedPositions(
|
|
615
|
+
this.layer,
|
|
616
|
+
cache.offset + tokens,
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return this.mla.forward(
|
|
620
|
+
normalized,
|
|
621
|
+
cache,
|
|
622
|
+
dsaKey,
|
|
623
|
+
reads.window,
|
|
624
|
+
positions,
|
|
625
|
+
);
|
|
626
|
+
} finally {
|
|
627
|
+
dsaKey?.dispose();
|
|
628
|
+
}
|
|
629
|
+
} finally {
|
|
630
|
+
normalized.dispose();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
forward(
|
|
635
|
+
input: MlxArray,
|
|
636
|
+
cache: LatentAttentionCache,
|
|
637
|
+
dsaState: Glm52DsaSelectionState | null,
|
|
638
|
+
reads: Glm52PhaseReads,
|
|
639
|
+
): MlxArray {
|
|
640
|
+
const attention = this.attend(input, cache, dsaState, reads);
|
|
641
|
+
const residual = ops.add(input, attention);
|
|
642
|
+
attention.dispose();
|
|
643
|
+
const postNorm = rmsNormF32Mlx(
|
|
644
|
+
residual,
|
|
645
|
+
this.postAttentionNorm,
|
|
646
|
+
this.config.rmsNormEps,
|
|
647
|
+
);
|
|
648
|
+
const feedForward = this.mlp.forward(postNorm);
|
|
649
|
+
postNorm.dispose();
|
|
650
|
+
const output = ops.add(residual, feedForward);
|
|
651
|
+
residual.dispose();
|
|
652
|
+
feedForward.dispose();
|
|
653
|
+
return output;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
async forwardAsync(
|
|
657
|
+
input: MlxArray,
|
|
658
|
+
cache: LatentAttentionCache,
|
|
659
|
+
dsaState: Glm52DsaSelectionState | null,
|
|
660
|
+
reads: Glm52PhaseReads,
|
|
661
|
+
): Promise<MlxArray> {
|
|
662
|
+
const attention = this.attend(input, cache, dsaState, reads);
|
|
663
|
+
const residual = ops.add(input, attention);
|
|
664
|
+
attention.dispose();
|
|
665
|
+
this.mlp.pilot?.predictNext(this.layer, residual);
|
|
666
|
+
const postNorm = rmsNormF32Mlx(
|
|
667
|
+
residual,
|
|
668
|
+
this.postAttentionNorm,
|
|
669
|
+
this.config.rmsNormEps,
|
|
670
|
+
);
|
|
671
|
+
let feedForward: MlxArray | null = null;
|
|
672
|
+
try {
|
|
673
|
+
feedForward = await this.mlp.forwardAsync(postNorm);
|
|
674
|
+
return ops.add(residual, feedForward);
|
|
675
|
+
} finally {
|
|
676
|
+
postNorm.dispose();
|
|
677
|
+
residual.dispose();
|
|
678
|
+
feedForward?.dispose();
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
export class Glm52Model implements MlxDeclaredGraph, MlxTokenPhases {
|
|
684
|
+
readonly config: ModelConfig;
|
|
685
|
+
readonly glmConfig: Glm52Config;
|
|
686
|
+
readonly weights: Glm52WeightSource;
|
|
687
|
+
readonly weightsBytes: number;
|
|
688
|
+
readonly capabilities: Glm52ModelCapabilities;
|
|
689
|
+
readonly prefixBase = "model";
|
|
690
|
+
readonly loraState = new LoraState();
|
|
691
|
+
/** Attends its own compressed MLA storage, which no KV scheme converts. Adapters
|
|
692
|
+
* are not offered on streamed experts. */
|
|
693
|
+
get graphCapabilities(): GraphDeclaration {
|
|
694
|
+
return declareGraph({
|
|
695
|
+
sparseAttention: this.capabilities?.dsa === true,
|
|
696
|
+
nativeDraft: this.capabilities?.mtpEnabled === true
|
|
697
|
+
? { kind: NATIVE_MTP_DRAFT, numDraftTokens: this.capabilities.mtpDraftTokens ?? 3 } : null,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
/** The checkpoint's native MTP row (`nativeDraft`): the head's numerics over this model's shared
|
|
701
|
+
* embeddings, output head and resident weights. Refused unless the MTP tier is loaded. */
|
|
702
|
+
nativeDraftHead(): Glm52MtpGraph {
|
|
703
|
+
if (!this.capabilities.mtpMetadata)
|
|
704
|
+
throw new Error("GLM-5.2 artifact does not contain a complete MTP row");
|
|
705
|
+
if (this.capabilities.mtpEnabled === false)
|
|
706
|
+
throw new Error("native GLM-5.2 MTP is disabled for this model instance");
|
|
707
|
+
if (this.glmConfig.numNextnPredictLayers !== 1) {
|
|
708
|
+
throw new Error(
|
|
709
|
+
`native GLM-5.2 MTP requires exactly one next-token layer; got ` +
|
|
710
|
+
`${this.glmConfig.numNextnPredictLayers}`,
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
const mtpBackend = this.expertRuntime?.mtpExecutor ?? null;
|
|
714
|
+
if (this.expertBackend && !mtpBackend) {
|
|
715
|
+
throw new Error(
|
|
716
|
+
"streamed GLM-5.2 MTP requires the bounded int8 MTP expert tier",
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
return new Glm52MtpGraph(this, new Glm52DecoderLayer(
|
|
720
|
+
this.glmConfig,
|
|
721
|
+
this.weights,
|
|
722
|
+
this.glmConfig.numHiddenLayers,
|
|
723
|
+
false,
|
|
724
|
+
mtpBackend,
|
|
725
|
+
));
|
|
726
|
+
}
|
|
727
|
+
expertResidency(): Record<string, unknown> | null {
|
|
728
|
+
const runtime = this.expertRuntime;
|
|
729
|
+
return runtime ? { main_residency: runtime.manager.snapshot(), mtp_residency: runtime.mtp?.manager.snapshot() ?? null,
|
|
730
|
+
last_turn: runtime.lastTelemetry, last_repin: runtime.lastRepin } : null;
|
|
731
|
+
}
|
|
732
|
+
readonly layers: Glm52DecoderLayer[];
|
|
733
|
+
readonly finalNorm: MlxArray;
|
|
734
|
+
readonly expertBackend: Glm52ExpertExecutionBackend | null;
|
|
735
|
+
readonly expertRuntime: Glm52ExpertRuntime | null;
|
|
736
|
+
readonly pilot: Glm52PilotTracker | null;
|
|
737
|
+
readonly dsaPrefillMode: "exact" | "dense-benchmark";
|
|
738
|
+
readonly dsaBenchmarkPrefillTokens: number;
|
|
739
|
+
#dsaSelectionObserver: Glm52DsaSelectionObserver | null = null;
|
|
740
|
+
|
|
741
|
+
constructor(
|
|
742
|
+
weights: Glm52WeightSource,
|
|
743
|
+
config: ModelConfig,
|
|
744
|
+
glmConfig: Glm52Config,
|
|
745
|
+
capabilities: Glm52ModelCapabilities,
|
|
746
|
+
expertBackend: Glm52ExpertExecutionBackend | null = null,
|
|
747
|
+
expertRuntime: Glm52ExpertRuntime | null = null,
|
|
748
|
+
dsaPrefillMode: "exact" | "dense-benchmark" = "exact",
|
|
749
|
+
dsaBenchmarkPrefillTokens = 0,
|
|
750
|
+
) {
|
|
751
|
+
if (config.modelType !== "glm_moe_dsa" ||
|
|
752
|
+
glmConfig.modelType !== "glm_moe_dsa") {
|
|
753
|
+
throw new Error("Glm52Model requires glm_moe_dsa configuration");
|
|
754
|
+
}
|
|
755
|
+
if (config.text.numHiddenLayers !== glmConfig.numHiddenLayers)
|
|
756
|
+
throw new Error("generic and dedicated GLM-5.2 configs disagree");
|
|
757
|
+
this.weights = weights;
|
|
758
|
+
this.config = config;
|
|
759
|
+
this.glmConfig = glmConfig;
|
|
760
|
+
this.weightsBytes = weights.weightsBytes;
|
|
761
|
+
this.capabilities = capabilities;
|
|
762
|
+
this.dsaPrefillMode = dsaPrefillMode;
|
|
763
|
+
if (
|
|
764
|
+
!Number.isSafeInteger(dsaBenchmarkPrefillTokens) ||
|
|
765
|
+
dsaBenchmarkPrefillTokens < 0 ||
|
|
766
|
+
(dsaPrefillMode === "dense-benchmark" && dsaBenchmarkPrefillTokens < 1) ||
|
|
767
|
+
(dsaPrefillMode === "exact" && dsaBenchmarkPrefillTokens !== 0)
|
|
768
|
+
) {
|
|
769
|
+
throw new Error(
|
|
770
|
+
"dense-benchmark DSA prefill requires a positive exact prompt length",
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
this.dsaBenchmarkPrefillTokens = dsaBenchmarkPrefillTokens;
|
|
774
|
+
this.expertBackend = expertBackend;
|
|
775
|
+
this.expertRuntime = expertRuntime;
|
|
776
|
+
this.pilot = expertRuntime?.pilotMeasureEnabled
|
|
777
|
+
? new Glm52PilotTracker({
|
|
778
|
+
config: glmConfig,
|
|
779
|
+
weights,
|
|
780
|
+
hintK: expertRuntime.pilotHintK,
|
|
781
|
+
twoStep: expertRuntime.pilotTwoStep,
|
|
782
|
+
hintSink: expertRuntime.pilotHintK > 0
|
|
783
|
+
? expertRuntime.manager
|
|
784
|
+
: undefined,
|
|
785
|
+
})
|
|
786
|
+
: null;
|
|
787
|
+
if (this.pilot) expertRuntime!.attachPilot(this.pilot);
|
|
788
|
+
this.layers = Array.from(
|
|
789
|
+
{ length: glmConfig.numHiddenLayers },
|
|
790
|
+
(_, layer) => new Glm52DecoderLayer(
|
|
791
|
+
glmConfig,
|
|
792
|
+
weights,
|
|
793
|
+
layer,
|
|
794
|
+
capabilities.dsa,
|
|
795
|
+
expertBackend,
|
|
796
|
+
this.pilot,
|
|
797
|
+
dsaBenchmarkPrefillTokens,
|
|
798
|
+
),
|
|
799
|
+
);
|
|
800
|
+
this.finalNorm = weights.tensor("model.norm.weight");
|
|
801
|
+
|
|
802
|
+
const multiSequencePrompt: MlxCapturingForward = (ids, cache) => this.#forward(ids, cache, GLM52_PHASE_READS.window);
|
|
803
|
+
this.prompt = [{ from: 1, to: Infinity, operation: multiSequencePrompt }];
|
|
804
|
+
this.promptChunk = this.prompt;
|
|
805
|
+
this.multiSequencePrompt = this.prompt;
|
|
806
|
+
this.multiSequencePromptChunk = this.multiSequencePrompt;
|
|
807
|
+
this.appendKnown = [
|
|
808
|
+
{ from: 1, to: 1, operation: (ids, cache) => this.#forward(ids, cache, GLM52_PHASE_READS.oneToken) },
|
|
809
|
+
{ from: 2, to: Infinity, operation: (ids, cache) => this.#forward(ids, cache, GLM52_PHASE_READS.window) },
|
|
810
|
+
];
|
|
811
|
+
this.logits = Object.freeze({
|
|
812
|
+
default: (hidden: MlxArray) => this.logitsFromHidden(hidden),
|
|
813
|
+
});
|
|
814
|
+
this.decode = Object.freeze({
|
|
815
|
+
default: (ids: MlxArray, cache: Cache[]) => this.#forward(ids, cache, GLM52_PHASE_READS.oneToken),
|
|
816
|
+
});
|
|
817
|
+
this.verify = Object.freeze({
|
|
818
|
+
default: async (ids: MlxArray, cache: Cache[]) => {
|
|
819
|
+
const executor = this.expertRuntime?.executor;
|
|
820
|
+
executor?.setFixedKernelFamily(true);
|
|
821
|
+
try { return await this.#forward(ids, cache, GLM52_PHASE_READS.window); }
|
|
822
|
+
finally { executor?.setFixedKernelFamily(false); }
|
|
823
|
+
},
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
static async open(modelDir: string, caches: Glm52LatentCaches = GLM52_F32_CACHES): Promise<Glm52LoadedModel> {
|
|
829
|
+
const glmConfig = await loadGlm52Config(modelDir);
|
|
830
|
+
const config = await loadModelConfig(modelDir);
|
|
831
|
+
const weights = ColibriGlm52Weights.open(modelDir);
|
|
832
|
+
try {
|
|
833
|
+
const detected = validateGlm52ContainerLayout(
|
|
834
|
+
weights.container,
|
|
835
|
+
glmConfig,
|
|
836
|
+
);
|
|
837
|
+
return bindGraphCaches(new Glm52Model(weights, config, glmConfig, {
|
|
838
|
+
dsa: detected.hasDsa,
|
|
839
|
+
mtpMetadata: detected.hasMtp,
|
|
840
|
+
}, null, null, "exact", 0), caches);
|
|
841
|
+
} catch (error) {
|
|
842
|
+
weights.dispose();
|
|
843
|
+
throw error;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
static async openStreamed(
|
|
848
|
+
modelDir: string,
|
|
849
|
+
options: Glm52StreamedOpenOptions,
|
|
850
|
+
): Promise<Glm52LoadedModel> {
|
|
851
|
+
const glmConfig = await loadGlm52Config(modelDir);
|
|
852
|
+
const config = await loadModelConfig(modelDir);
|
|
853
|
+
const weights = ColibriGlm52ResidentWeights.open(modelDir, {
|
|
854
|
+
includeMtp: options.enableMtp !== false,
|
|
855
|
+
});
|
|
856
|
+
let runtime: Glm52ExpertRuntime | null = null;
|
|
857
|
+
try {
|
|
858
|
+
const detected = validateGlm52ContainerLayout(
|
|
859
|
+
weights.container,
|
|
860
|
+
glmConfig,
|
|
861
|
+
);
|
|
862
|
+
const {
|
|
863
|
+
enableDsa: _enableDsa,
|
|
864
|
+
dsaPrefillMode,
|
|
865
|
+
dsaBenchmarkPrefillTokens,
|
|
866
|
+
caches,
|
|
867
|
+
...runtimeOptions
|
|
868
|
+
} = options;
|
|
869
|
+
runtime = await Glm52ExpertRuntime.open(modelDir, glmConfig, {
|
|
870
|
+
...runtimeOptions,
|
|
871
|
+
fixedBytes: weights.weightsBytes + options.reserveBytes,
|
|
872
|
+
});
|
|
873
|
+
return bindGraphCaches(new Glm52Model(
|
|
874
|
+
weights,
|
|
875
|
+
config,
|
|
876
|
+
glmConfig,
|
|
877
|
+
{
|
|
878
|
+
dsa: detected.hasDsa && options.enableDsa !== false,
|
|
879
|
+
mtpMetadata: detected.hasMtp,
|
|
880
|
+
mtpEnabled: detected.hasMtp && options.enableMtp !== false,
|
|
881
|
+
mtpDraftTokens: options.mtpDraftTokens ?? 3,
|
|
882
|
+
},
|
|
883
|
+
runtime.executor,
|
|
884
|
+
runtime,
|
|
885
|
+
dsaPrefillMode ?? "exact",
|
|
886
|
+
dsaBenchmarkPrefillTokens ?? 0,
|
|
887
|
+
), caches ?? GLM52_F32_CACHES);
|
|
888
|
+
} catch (error) {
|
|
889
|
+
runtime?.close();
|
|
890
|
+
weights.dispose();
|
|
891
|
+
throw error;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
loraTargets(): Map<string, QuantizedLinear> {
|
|
896
|
+
return new Map();
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/** One latent attention cache per layer, the lego the composition's KV
|
|
900
|
+
* scheme and paging name for it (`composedLatentCache`): f32 by default, the
|
|
901
|
+
* latent, RoPE key and (on a DSA layer) index key encoded f32-first under a
|
|
902
|
+
* quantized scheme, in pages under paging. */
|
|
903
|
+
get cacheLayers(): readonly MlxCacheLayer[] { return this.layers.map(layer=>({kind:"latent" as const,geometry:{kvLoraRank:this.glmConfig.kvLoraRank,ropeHeadDim:this.glmConfig.qkRopeHeadDim,maxTokens:this.glmConfig.maxPositionEmbeddings,...(this.capabilities.dsa && layer.dsa ? {indexHeadDim:this.glmConfig.indexHeadDim}:{})}})); }
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
/** Attach probe-only telemetry for selections computed by FULL DSA layers. */
|
|
907
|
+
setDsaSelectionObserver(observer: Glm52DsaSelectionObserver | null): void {
|
|
908
|
+
this.#dsaSelectionObserver = observer;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/** The scoring forward (`MlxSequenceForward`) of a resident graph; a streamed
|
|
912
|
+
* graph's forward is asynchronous, and it refuses this. */
|
|
913
|
+
sequenceHidden(ids: MlxArray, cache: Cache[], width: number): MlxArray {
|
|
914
|
+
if (this.expertBackend)
|
|
915
|
+
throw new Error("a streamed GLM graph has no synchronous scoring forward");
|
|
916
|
+
// One row of one token is a one-query read; every wider scoring forward is a window.
|
|
917
|
+
return this.#sequence(ids, cache, width === 1 ? GLM52_PHASE_READS.oneToken : GLM52_PHASE_READS.window);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
#sequence(ids: MlxArray, cache: Cache[], reads: Glm52PhaseReads): MlxArray {
|
|
921
|
+
const tokenCount = ids.shape[1] ?? 1;
|
|
922
|
+
const firstOffset = cache[0]?.offset ?? 0;
|
|
923
|
+
if (
|
|
924
|
+
this.capabilities.dsa &&
|
|
925
|
+
!(
|
|
926
|
+
this.dsaPrefillMode === "dense-benchmark" &&
|
|
927
|
+
firstOffset + tokenCount <= this.dsaBenchmarkPrefillTokens
|
|
928
|
+
) &&
|
|
929
|
+
tokenCount > 1 &&
|
|
930
|
+
tokenCount > GLM52_DSA_SPARSE_DECODE_BATCH_MAX &&
|
|
931
|
+
firstOffset + tokenCount > this.glmConfig.indexTopk
|
|
932
|
+
) {
|
|
933
|
+
// Bound sparse-selection state for long prefills while retaining all
|
|
934
|
+
// request rows in each forward. Short verify windows keep the residual
|
|
935
|
+
// and expert graph batched across both requests and query positions.
|
|
936
|
+
const rows: MlxArray[] = [];
|
|
937
|
+
try {
|
|
938
|
+
for (let token = 0; token < tokenCount; token++) {
|
|
939
|
+
const row = ids.slice([0, token], [ids.shape[0]!, token + 1]);
|
|
940
|
+
try {
|
|
941
|
+
rows.push(this.#sequence(row, cache, GLM52_PHASE_READS.oneToken));
|
|
942
|
+
} finally {
|
|
943
|
+
row.dispose();
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (rows.length === 1) return rows[0]!;
|
|
947
|
+
return ops.concatAxis(rows, 1);
|
|
948
|
+
} finally {
|
|
949
|
+
if (rows.length > 1)
|
|
950
|
+
for (const row of rows) row.dispose();
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const embedded = this.weights.embedding(
|
|
954
|
+
ids,
|
|
955
|
+
"model.embed_tokens.weight",
|
|
956
|
+
this.glmConfig.vocabSize,
|
|
957
|
+
this.glmConfig.hiddenSize,
|
|
958
|
+
);
|
|
959
|
+
try {
|
|
960
|
+
return this.forwardEmbeddings(embedded, cache, reads);
|
|
961
|
+
} finally {
|
|
962
|
+
embedded.dispose();
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
async #forward(ids: MlxArray, cache: Cache[], reads: Glm52PhaseReads): Promise<MlxArray> {
|
|
967
|
+
const tokenCount = ids.shape[1] ?? 1;
|
|
968
|
+
const firstOffset = cache[0]?.offset ?? 0;
|
|
969
|
+
if (
|
|
970
|
+
this.capabilities.dsa &&
|
|
971
|
+
!(
|
|
972
|
+
this.dsaPrefillMode === "dense-benchmark" &&
|
|
973
|
+
firstOffset + tokenCount <= this.dsaBenchmarkPrefillTokens
|
|
974
|
+
) &&
|
|
975
|
+
tokenCount > 1 &&
|
|
976
|
+
tokenCount > GLM52_DSA_SPARSE_DECODE_BATCH_MAX &&
|
|
977
|
+
firstOffset + tokenCount > this.glmConfig.indexTopk
|
|
978
|
+
) {
|
|
979
|
+
const rows: MlxArray[] = [];
|
|
980
|
+
try {
|
|
981
|
+
for (let token = 0; token < tokenCount; token++) {
|
|
982
|
+
const row = ids.slice([0, token], [ids.shape[0]!, token + 1]);
|
|
983
|
+
try {
|
|
984
|
+
rows.push(await this.#forward(row, cache, GLM52_PHASE_READS.oneToken));
|
|
985
|
+
} finally {
|
|
986
|
+
row.dispose();
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
if (rows.length === 1) return rows[0]!;
|
|
990
|
+
return ops.concatAxis(rows, 1);
|
|
991
|
+
} finally {
|
|
992
|
+
if (rows.length > 1)
|
|
993
|
+
for (const row of rows) row.dispose();
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
const embedded = this.weights.embedding(
|
|
997
|
+
ids,
|
|
998
|
+
"model.embed_tokens.weight",
|
|
999
|
+
this.glmConfig.vocabSize,
|
|
1000
|
+
this.glmConfig.hiddenSize,
|
|
1001
|
+
);
|
|
1002
|
+
try {
|
|
1003
|
+
return await this.forwardEmbeddingsAsync(embedded, cache, reads);
|
|
1004
|
+
} finally {
|
|
1005
|
+
embedded.dispose();
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// Each phase names its MLA reads (`GLM52_PHASE_READS`): windows reconstruct, one token per sequence absorbs.
|
|
1010
|
+
readonly prompt: readonly MlxPromptRange[];
|
|
1011
|
+
readonly promptChunk: typeof this.prompt;
|
|
1012
|
+
readonly multiSequencePromptChunk: typeof this.multiSequencePrompt;
|
|
1013
|
+
readonly multiSequencePrompt: readonly MlxPromptRange[];
|
|
1014
|
+
|
|
1015
|
+
/** Known tokens: one sequence's tokens are its rows, so the one-row operation is one token. */
|
|
1016
|
+
readonly appendKnown: MlxKnownOperations;
|
|
1017
|
+
readonly logits: MlxRowTable<MlxHeadForward>;
|
|
1018
|
+
readonly decode: MlxRowTable<MlxCapturingForward>;
|
|
1019
|
+
/** A verify window on the row-independent M=1 streamed-expert kernel family
|
|
1020
|
+
* (`setFixedKernelFamily`), so a token's experts take the same kernels
|
|
1021
|
+
* whatever rows verify beside it. Composed into the operation: the scheduler
|
|
1022
|
+
* never pins or unpins it. */
|
|
1023
|
+
readonly verify: MlxRowTable<MlxCapturingForward>;
|
|
1024
|
+
|
|
1025
|
+
/** The decoder over `embeddings` (borrowed). `cache` holds one latent
|
|
1026
|
+
* attention cache per layer (`makeCache`), which each layer's MLA block reads
|
|
1027
|
+
* through the read it was built with, attending as the calling phase's
|
|
1028
|
+
* `reads` name. */
|
|
1029
|
+
forwardEmbeddings(
|
|
1030
|
+
embeddings: MlxArray,
|
|
1031
|
+
cache: Cache[],
|
|
1032
|
+
reads: Glm52PhaseReads,
|
|
1033
|
+
): MlxArray {
|
|
1034
|
+
if (cache.length !== this.layers.length)
|
|
1035
|
+
throw new Error(`GLM cache has ${cache.length} layers, expected ${this.layers.length}`);
|
|
1036
|
+
const dsaState = this.capabilities.dsa
|
|
1037
|
+
? new Glm52DsaSelectionState(
|
|
1038
|
+
this.glmConfig.indexTopk,
|
|
1039
|
+
this.#dsaSelectionObserver,
|
|
1040
|
+
)
|
|
1041
|
+
: null;
|
|
1042
|
+
// The RuntimeModel contract keeps caller-provided embeddings caller-owned.
|
|
1043
|
+
// Take our own handle before entering the consuming layer loop.
|
|
1044
|
+
let current = ops.contiguous(embeddings);
|
|
1045
|
+
try {
|
|
1046
|
+
for (let layer = 0; layer < this.layers.length; layer++) {
|
|
1047
|
+
const next = this.layers[layer]!.forward(
|
|
1048
|
+
current,
|
|
1049
|
+
cache[layer] as LatentAttentionCache,
|
|
1050
|
+
dsaState,
|
|
1051
|
+
reads,
|
|
1052
|
+
);
|
|
1053
|
+
current.dispose();
|
|
1054
|
+
current = next;
|
|
1055
|
+
}
|
|
1056
|
+
return rmsNormF32Mlx(
|
|
1057
|
+
current,
|
|
1058
|
+
this.finalNorm,
|
|
1059
|
+
this.glmConfig.rmsNormEps,
|
|
1060
|
+
);
|
|
1061
|
+
} finally {
|
|
1062
|
+
current.dispose();
|
|
1063
|
+
dsaState?.dispose();
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/** `forwardEmbeddings` over streamed experts, every layer evaluated before the next. */
|
|
1068
|
+
async forwardEmbeddingsAsync(
|
|
1069
|
+
embeddings: MlxArray,
|
|
1070
|
+
cache: Cache[],
|
|
1071
|
+
reads: Glm52PhaseReads,
|
|
1072
|
+
): Promise<MlxArray> {
|
|
1073
|
+
if (cache.length !== this.layers.length)
|
|
1074
|
+
throw new Error(`GLM cache has ${cache.length} layers, expected ${this.layers.length}`);
|
|
1075
|
+
const dsaState = this.capabilities.dsa
|
|
1076
|
+
? new Glm52DsaSelectionState(
|
|
1077
|
+
this.glmConfig.indexTopk,
|
|
1078
|
+
this.#dsaSelectionObserver,
|
|
1079
|
+
)
|
|
1080
|
+
: null;
|
|
1081
|
+
let current = ops.contiguous(embeddings);
|
|
1082
|
+
try {
|
|
1083
|
+
for (let layer = 0; layer < this.layers.length; layer++) {
|
|
1084
|
+
const next = await this.layers[layer]!.forwardAsync(
|
|
1085
|
+
current,
|
|
1086
|
+
cache[layer] as LatentAttentionCache,
|
|
1087
|
+
dsaState,
|
|
1088
|
+
reads,
|
|
1089
|
+
);
|
|
1090
|
+
// The streamed path is a bounded-residency graph. Detach every layer
|
|
1091
|
+
// before advancing so dense-prefix and post-expert compose graphs
|
|
1092
|
+
// cannot retain transient dequantized weights across layer boundaries.
|
|
1093
|
+
next.eval();
|
|
1094
|
+
synchronize(gpuStream);
|
|
1095
|
+
current.dispose();
|
|
1096
|
+
current = next;
|
|
1097
|
+
}
|
|
1098
|
+
return rmsNormF32Mlx(
|
|
1099
|
+
current,
|
|
1100
|
+
this.finalNorm,
|
|
1101
|
+
this.glmConfig.rmsNormEps,
|
|
1102
|
+
);
|
|
1103
|
+
} finally {
|
|
1104
|
+
current.dispose();
|
|
1105
|
+
dsaState?.dispose();
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
logitsFromHidden(hidden: MlxArray): MlxArray {
|
|
1110
|
+
return this.weights.linear(
|
|
1111
|
+
hidden,
|
|
1112
|
+
"lm_head.weight",
|
|
1113
|
+
this.glmConfig.vocabSize,
|
|
1114
|
+
this.glmConfig.hiddenSize,
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
dispose(): void {
|
|
1119
|
+
this.weights.dispose();
|
|
1120
|
+
this.expertRuntime?.close();
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
import { Glm52WeightSource } from "../../contracts/mlx/glm52-weights";
|
|
1125
|
+
export { type Glm52WeightSource } from "../../contracts/mlx/glm52-weights";
|
|
1126
|
+
|
|
1127
|
+
export type Glm52LoadedModel = Glm52Model & { makeCache(): Cache[]; readonly stateCodecs?: CacheCodecProvider };
|