@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,72 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
import type { Cache } from "../../contracts/mlx/cache";
|
|
4
|
+
import { CompiledGegluMLP, PlainGegluMLP } from "../../layers/geglu";
|
|
5
|
+
import { disposing } from "../../layers/helpers";
|
|
6
|
+
import { QuantizedLinearPlain } from "../../layers/quantized-linear";
|
|
7
|
+
import { DecoderLayer, FixedExperts, type DonorRead, type Gemma4Phase, type Router } from "./blocks";
|
|
8
|
+
import { isExpertTracing, recordRouting } from "../../runtime/expert-trace";
|
|
9
|
+
|
|
10
|
+
/** Serving operations borrow the same projections that training and LoRA mount. */
|
|
11
|
+
export class ServingRouter {
|
|
12
|
+
readonly projection: QuantizedLinearPlain;
|
|
13
|
+
constructor(readonly base: Router) { this.projection = new QuantizedLinearPlain(base.proj); }
|
|
14
|
+
forward(x: MlxArray): { indices: MlxArray; weights: MlxArray } {
|
|
15
|
+
using normed = ops.rmsNorm(x, this.base.normWeight, this.base.eps);
|
|
16
|
+
using scores = this.projection.forward(normed);
|
|
17
|
+
using part = ops.argpartitionAxis(scores, this.base.numExperts - this.base.topK, -1);
|
|
18
|
+
const [B, L] = scores.shape;
|
|
19
|
+
const indices = part.slice([0, 0, this.base.numExperts - this.base.topK], [B!, L!, this.base.numExperts]);
|
|
20
|
+
let weights = ops.takeAlongAxis(scores, indices, -1);
|
|
21
|
+
weights = disposing(weights, ops.softmaxAxis(weights, -1, false));
|
|
22
|
+
using gathered = ops.takeAxis(this.base.perExpertScale, indices, 0);
|
|
23
|
+
weights = disposing(weights, ops.mul(weights, gathered));
|
|
24
|
+
if (isExpertTracing()) recordRouting(this.base.layerIdx, indices);
|
|
25
|
+
return { indices, weights };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class ServingDenseLayer {
|
|
30
|
+
readonly finish: (hidden: MlxArray, input: MlxArray | null) => MlxArray;
|
|
31
|
+
constructor(readonly base: DecoderLayer, readonly mlp: CompiledGegluMLP | PlainGegluMLP) {
|
|
32
|
+
// Artifact features are composed once; the request executes these operations.
|
|
33
|
+
const input = base.perLayerGate ? (h: MlxArray, p: MlxArray | null) => base.perLayerGated(h, p!) : (h: MlxArray) => h;
|
|
34
|
+
const scale = base.layerScalar ? (h: MlxArray) => base.scaled(h) : (h: MlxArray) => h;
|
|
35
|
+
this.finish = (h, p) => scale(input(h, p));
|
|
36
|
+
}
|
|
37
|
+
forwardAttn(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null) { return this.base.forwardAttn(x, cache, phase, donor); }
|
|
38
|
+
forwardMlp(h: MlxArray, input: MlxArray | null): MlxArray {
|
|
39
|
+
let f = this.base.preFfNorm.forward(h);
|
|
40
|
+
f = disposing(f, this.mlp.forward(f));
|
|
41
|
+
f = disposing(f, this.base.postFfNorm.forward(f));
|
|
42
|
+
const out = ops.add(h, f); f.dispose();
|
|
43
|
+
return this.finish(out, input);
|
|
44
|
+
}
|
|
45
|
+
forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null, input: MlxArray | null) {
|
|
46
|
+
const result = this.forwardAttn(x, cache, phase, donor);
|
|
47
|
+
try { return {h:this.forwardMlp(result.h,input),donor:result.donor}; }
|
|
48
|
+
catch(error) { result.donor?.dispose(); throw error; }
|
|
49
|
+
finally { result.h.dispose(); }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class ServingMoeLayer extends ServingDenseLayer {
|
|
54
|
+
readonly router: ServingRouter;
|
|
55
|
+
constructor(base: DecoderLayer, mlp: CompiledGegluMLP, readonly experts: FixedExperts) {
|
|
56
|
+
super(base, mlp); this.router = new ServingRouter(base.router!);
|
|
57
|
+
}
|
|
58
|
+
override forwardMlp(h: MlxArray, input: MlxArray | null): MlxArray {
|
|
59
|
+
let dense = this.base.preFfNorm.forward(h);
|
|
60
|
+
dense = disposing(dense, this.mlp.forward(dense));
|
|
61
|
+
dense = disposing(dense, this.base.postFfNorm1!.forward(dense));
|
|
62
|
+
const {indices,weights} = this.router.forward(h);
|
|
63
|
+
let expert = this.base.preFfNorm2!.forward(h);
|
|
64
|
+
expert = disposing(expert, this.experts.forward(expert,indices,weights));
|
|
65
|
+
expert = disposing(expert, this.base.postFfNorm2!.forward(expert));
|
|
66
|
+
indices.dispose(); weights.dispose();
|
|
67
|
+
let f = ops.add(dense,expert); dense.dispose(); expert.dispose();
|
|
68
|
+
f = disposing(f,this.base.postFfNorm.forward(f));
|
|
69
|
+
const out = ops.add(h,f); f.dispose();
|
|
70
|
+
return this.finish(out,input);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import type { Checkpoint } from "@mlx-bun/mlx/checkpoint";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import type { Cache, SharedKv } from "../../contracts/mlx/cache";
|
|
5
|
+
import type {
|
|
6
|
+
GradCheckpointRun, HeadQuant, LoraLeaves, PrefixLayout, SegmentedPass, TrainableGraph,
|
|
7
|
+
} from "../../contracts/mlx/trainable";
|
|
8
|
+
import { AttentionMasks } from "../../state/attention-read";
|
|
9
|
+
import { prefixSharedCaches, selectedTrainingAttention, TrainingCache } from "../../state/training-cache";
|
|
10
|
+
import type { LoraWeights } from "../../layers/lora";
|
|
11
|
+
import type { RMSNorm } from "../../layers/normalization";
|
|
12
|
+
import type { QuantizedEmbedding } from "../../layers/quantized-embedding";
|
|
13
|
+
|
|
14
|
+
/** Optional gradient-checkpointing context for the training forward. When set,
|
|
15
|
+
* the training forward wraps each layer in a Checkpoint so its interior activations
|
|
16
|
+
* are recomputed in the backward pass. `byLayer` maps a layer index to that
|
|
17
|
+
* layer's trainable LoRA weights, partitioned into the attention sub-block
|
|
18
|
+
* (q/k/v/o_proj) and the MLP sub-block (gate/up/down_proj + per-layer gate/
|
|
19
|
+
* projection) — re-swapped inside the closure so they are explicit checkpoint
|
|
20
|
+
* inputs (required because the autograd primals are disposed before the
|
|
21
|
+
* recompute). When `splitMlp` is set, the layer is wrapped in TWO checkpoints
|
|
22
|
+
* (attn sub-block + MLP sub-block) with the post-attn residual `hMid` as the
|
|
23
|
+
* boundary, so the backward recompute holds `max(attn,MLP)+hMid` instead of the
|
|
24
|
+
* whole layer (the intra-layer MLP split, lever 4). `keepAlive` collects the
|
|
25
|
+
* Checkpoint objects; the trainer disposes them after value_and_grad. */
|
|
26
|
+
export interface LayerLoras {
|
|
27
|
+
attn: LoraWeights[];
|
|
28
|
+
mlp: LoraWeights[];
|
|
29
|
+
}
|
|
30
|
+
export interface GradCheckpointCtx {
|
|
31
|
+
byLayer: Map<number, LayerLoras>;
|
|
32
|
+
splitMlp: boolean;
|
|
33
|
+
keepAlive: Checkpoint[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** What the training declaration reads from a Gemma 4 model (structural, so this
|
|
37
|
+
* module does not depend on the model file). */
|
|
38
|
+
export interface Gemma4Training {
|
|
39
|
+
readonly config: { readonly text: { readonly finalLogitSoftcapping: number | null } };
|
|
40
|
+
readonly embed: QuantizedEmbedding;
|
|
41
|
+
readonly finalNorm: RMSNorm;
|
|
42
|
+
readonly layers: readonly { readonly layerType: string }[];
|
|
43
|
+
/** The sliding layers' window. */
|
|
44
|
+
readonly windowSize: number;
|
|
45
|
+
/** Donor count: layers [0, numDonors) own caches; the rest share. */
|
|
46
|
+
readonly numDonors: number;
|
|
47
|
+
readonly previousKvs: readonly number[];
|
|
48
|
+
readonly cacheIndex: readonly number[];
|
|
49
|
+
readonly reusedDonors: Set<number>;
|
|
50
|
+
gradCkpt: GradCheckpointCtx | null;
|
|
51
|
+
/** The training forward over one training cache per donor layer, which owns
|
|
52
|
+
* its read; donors hand their sharers plain keys and values. */
|
|
53
|
+
forwardTrainingHidden(ids: MlxArray, cache: Cache[]): MlxArray;
|
|
54
|
+
embedForSegmented(ids: MlxArray): { hScaled: MlxArray; perLayer: MlxArray | null };
|
|
55
|
+
runLayerRange(
|
|
56
|
+
h: MlxArray, aIdx: number, bIdx: number, cache: Cache[],
|
|
57
|
+
perLayer: MlxArray | null, donorKvIn: Map<number, SharedKv>,
|
|
58
|
+
): { h: MlxArray; donorKvOut: Map<number, SharedKv> };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** One stateless training cache per donor layer, with that layer's sliding
|
|
62
|
+
* window, sharing one mask memo and attending with the run's training
|
|
63
|
+
* attention: prefix-shared caches under a layout, plain ones otherwise. */
|
|
64
|
+
function trainingCaches(model: Gemma4Training, prefix?: PrefixLayout): Cache[] {
|
|
65
|
+
const attention = selectedTrainingAttention();
|
|
66
|
+
const windows = model.layers.slice(0, model.numDonors)
|
|
67
|
+
.map(layer => layer.layerType === "sliding_attention" ? model.windowSize : null);
|
|
68
|
+
if (prefix) return prefixSharedCaches(prefix, windows, attention);
|
|
69
|
+
const masks = new AttentionMasks();
|
|
70
|
+
return windows.map(window => new TrainingCache(window, masks, attention));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Copy `a` into a graph-free leaf (an evaluated, row-major copy), disposing `a`. */
|
|
74
|
+
function detached(a: MlxArray): MlxArray {
|
|
75
|
+
const c = ops.contiguous(a);
|
|
76
|
+
const leaf = c.detachCopy();
|
|
77
|
+
c.dispose();
|
|
78
|
+
a.dispose();
|
|
79
|
+
return leaf;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One segmented pass over a Gemma 4 sequence: the per-layer-input tensor (a
|
|
83
|
+
* constant boundary sliced per layer) and one stateless training cache per
|
|
84
|
+
* donor layer (block-sparse with a logical-position window when
|
|
85
|
+
* prefix-shared), which builds its masks once for the pass; sharers read the
|
|
86
|
+
* donors' K/V through the donors' caches. */
|
|
87
|
+
class Gemma4SegmentedPass implements SegmentedPass {
|
|
88
|
+
readonly input: MlxArray;
|
|
89
|
+
private readonly caches: Cache[];
|
|
90
|
+
private readonly perLayer: MlxArray | null = null;
|
|
91
|
+
|
|
92
|
+
constructor(private readonly model: Gemma4Training, ids: MlxArray, prefix?: PrefixLayout) {
|
|
93
|
+
this.caches = trainingCaches(model, prefix);
|
|
94
|
+
let input: MlxArray | null = null;
|
|
95
|
+
let perLayer: MlxArray | null = null;
|
|
96
|
+
try {
|
|
97
|
+
const embedded = model.embedForSegmented(ids);
|
|
98
|
+
input = embedded.hScaled;
|
|
99
|
+
perLayer = embedded.perLayer ? detached(embedded.perLayer) : null;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
input?.dispose();
|
|
102
|
+
perLayer?.dispose();
|
|
103
|
+
this.releaseCaches();
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
this.input = input;
|
|
107
|
+
this.perLayer = perLayer;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private releaseCaches(): void {
|
|
111
|
+
for (const c of this.caches) c.dispose();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
runRange(h: MlxArray, lo: number, hi: number, donorKvIn: Map<number, SharedKv>) {
|
|
115
|
+
return this.model.runLayerRange(h, lo, hi, this.caches, this.perLayer, donorKvIn);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
dispose(): void {
|
|
119
|
+
this.releaseCaches();
|
|
120
|
+
this.perLayer?.dispose();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function checkpointRun(model: Gemma4Training, targets: readonly { modulePath: string; lw: LoraLeaves }[], splitMlp: boolean): GradCheckpointRun {
|
|
125
|
+
// Partition each layer's LoRA into the attention sub-block (self_attn.*) and
|
|
126
|
+
// the MLP sub-block (everything else in the layer: gate/up/down_proj +
|
|
127
|
+
// per_layer_*) so the split-MLP checkpoint can wrap them independently.
|
|
128
|
+
const byLayer: GradCheckpointCtx["byLayer"] = new Map();
|
|
129
|
+
for (const t of targets) {
|
|
130
|
+
const m = t.modulePath.match(/\.layers\.(\d+)\./);
|
|
131
|
+
if (!m) continue;
|
|
132
|
+
const li = Number(m[1]);
|
|
133
|
+
const ll = byLayer.get(li) ?? byLayer.set(li, { attn: [], mlp: [] }).get(li)!;
|
|
134
|
+
(t.modulePath.includes(".self_attn.") ? ll.attn : ll.mlp).push(t.lw);
|
|
135
|
+
}
|
|
136
|
+
// Checkpoints are created per forward and disposed after each step's backward.
|
|
137
|
+
const ctx: GradCheckpointCtx = { byLayer, splitMlp, keepAlive: [] };
|
|
138
|
+
model.gradCkpt = ctx;
|
|
139
|
+
return {
|
|
140
|
+
releaseStep() {
|
|
141
|
+
for (const ck of ctx.keepAlive) ck.dispose();
|
|
142
|
+
ctx.keepAlive.length = 0;
|
|
143
|
+
},
|
|
144
|
+
suspend() { model.gradCkpt = null; },
|
|
145
|
+
resume() { model.gradCkpt = ctx; },
|
|
146
|
+
end() {
|
|
147
|
+
model.gradCkpt = null;
|
|
148
|
+
for (const ck of ctx.keepAlive) ck.dispose();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Gemma 4's training declaration. */
|
|
154
|
+
export function gemma4Trainable(model: Gemma4Training): TrainableGraph {
|
|
155
|
+
const donorOf = model.layers.map((_, i) => (model.cacheIndex[i] === -1 ? model.previousKvs[i]! : null));
|
|
156
|
+
return {
|
|
157
|
+
lmHead(): HeadQuant {
|
|
158
|
+
// Tied: the quantized embedding is the head; the softcap comes from the config.
|
|
159
|
+
const e = model.embed;
|
|
160
|
+
return { w: e.w, scales: e.scales, biases: e.biases, spec: e.spec, softcap: model.config.text.finalLogitSoftcapping };
|
|
161
|
+
},
|
|
162
|
+
flashAttention: {
|
|
163
|
+
supported: false,
|
|
164
|
+
reason: "e4b SIGTRAPs on this path at seq >= 2048 and it has not been re-validated at that scale since the kernel fixes",
|
|
165
|
+
},
|
|
166
|
+
segmented: {
|
|
167
|
+
layerCount: model.layers.length,
|
|
168
|
+
sharedKv: { reusedDonors: model.reusedDonors, donorOf },
|
|
169
|
+
finalNorm: (h) => model.finalNorm.forward(h),
|
|
170
|
+
begin: (ids, prefix) => new Gemma4SegmentedPass(model, ids, prefix),
|
|
171
|
+
},
|
|
172
|
+
prefixShared: {
|
|
173
|
+
prefixSharedHidden(ids: MlxArray, layout: PrefixLayout): MlxArray {
|
|
174
|
+
// One prefix cache per DONOR layer (sharers read donors' K/V through
|
|
175
|
+
// the donors' caches); the caches read under the block-sparse masks.
|
|
176
|
+
const caches = trainingCaches(model, layout);
|
|
177
|
+
try {
|
|
178
|
+
return model.forwardTrainingHidden(ids, caches); // [1, T, hidden], post-finalNorm
|
|
179
|
+
} finally {
|
|
180
|
+
for (const c of caches) c.dispose();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
gradCheckpoint: { enable: (targets, splitMlp) => checkpointRun(model, targets, splitMlp) },
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
import type { ModelConfig } from "../../artifacts/config";
|
|
4
|
+
import type { Weights } from "../../artifacts/weights";
|
|
5
|
+
import type { Cache } from "../../contracts/mlx/cache";
|
|
6
|
+
import { RMSNorm } from "../../layers/normalization";
|
|
7
|
+
import { QuantizedLinear, QuantizedLinearPlain } from "../../layers/quantized-linear";
|
|
8
|
+
import { GegluMLP, PlainGegluMLP, CompiledGegluMLP, CompiledGeglu } from "../../layers/geglu";
|
|
9
|
+
import { Attention, Router, SwitchGLU, SortedSwitchGLU, UnsortedSwitchGLU, FixedExperts, type DonorRead, type Gemma4Phase } from "./blocks";
|
|
10
|
+
import { disposing } from "../../layers/helpers";
|
|
11
|
+
|
|
12
|
+
export class SlidingAttention extends Attention {
|
|
13
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, "sliding_attention", true, undefined, false); }
|
|
14
|
+
override forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, _donor: DonorRead | null) { return this.forwardSeparate(x, cache!, phase); }
|
|
15
|
+
}
|
|
16
|
+
export class FullAttention extends Attention {
|
|
17
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, "full_attention", true, undefined, false); }
|
|
18
|
+
override forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, _donor: DonorRead | null) { return this.forwardSeparate(x, cache!, phase); }
|
|
19
|
+
}
|
|
20
|
+
export class FullKEqVAttention extends Attention {
|
|
21
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, "full_attention", true, undefined, true); }
|
|
22
|
+
override forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, _donor: DonorRead | null) { return this.forwardKEqV(x, cache!, phase); }
|
|
23
|
+
}
|
|
24
|
+
export class SharedSlidingAttention extends Attention {
|
|
25
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, "sliding_attention", false, undefined, false); }
|
|
26
|
+
override forward(x: MlxArray, _cache: Cache | null, _phase: Gemma4Phase, donor: DonorRead | null) { return this.forwardShared(x, donor!); }
|
|
27
|
+
}
|
|
28
|
+
export class SharedFullAttention extends Attention {
|
|
29
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, "full_attention", false, undefined, false); }
|
|
30
|
+
override forward(x: MlxArray, _cache: Cache | null, _phase: Gemma4Phase, donor: DonorRead | null) { return this.forwardShared(x, donor!); }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Stored MLP projections. Each operation view names its activation literally. */
|
|
34
|
+
export class GemmaMlpWeights extends GegluMLP {
|
|
35
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) { super(weights, config, prefix, true); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Norms and scale owned by one written layer; model features are supplied as
|
|
39
|
+
* concrete attention and feed-forward operations by the file. */
|
|
40
|
+
export class GemmaLayerWeights {
|
|
41
|
+
readonly inputNorm: RMSNorm;
|
|
42
|
+
readonly postAttnNorm: RMSNorm;
|
|
43
|
+
readonly preFfNorm: RMSNorm;
|
|
44
|
+
readonly postFfNorm: RMSNorm;
|
|
45
|
+
readonly layerScalar: MlxArray;
|
|
46
|
+
readonly layerType: string;
|
|
47
|
+
readonly mlp: GemmaMlpWeights;
|
|
48
|
+
constructor(weights: Weights, config: ModelConfig, readonly prefix: string, readonly attn: Attention) {
|
|
49
|
+
const norm = (name: string) => new RMSNorm(weights.tensor(`${prefix}.${name}.weight`), config.text.rmsNormEps);
|
|
50
|
+
this.inputNorm = norm("input_layernorm"); this.postAttnNorm = norm("post_attention_layernorm");
|
|
51
|
+
this.preFfNorm = norm("pre_feedforward_layernorm"); this.postFfNorm = norm("post_feedforward_layernorm");
|
|
52
|
+
this.layerScalar = weights.tensor(`${prefix}.layer_scalar`);
|
|
53
|
+
this.layerType = attn.isSliding ? "sliding_attention" : "full_attention";
|
|
54
|
+
this.mlp = new GemmaMlpWeights(weights, config, `${prefix}.mlp`);
|
|
55
|
+
}
|
|
56
|
+
forwardAttn(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null): { h: MlxArray; donor: DonorRead | null } {
|
|
57
|
+
const normed = this.inputNorm.forward(x);
|
|
58
|
+
let result: { out: MlxArray; donor: DonorRead | null };
|
|
59
|
+
try { result = this.attn.forward(normed, cache, phase, donor); } finally { normed.dispose(); }
|
|
60
|
+
let hidden = result.out;
|
|
61
|
+
try {
|
|
62
|
+
hidden = disposing(hidden, this.postAttnNorm.forward(hidden));
|
|
63
|
+
hidden = disposing(hidden, ops.add(x, hidden));
|
|
64
|
+
return { h: hidden, donor: result.donor };
|
|
65
|
+
} catch (error) { hidden.dispose(); result.donor?.dispose(); throw error; }
|
|
66
|
+
}
|
|
67
|
+
scaled(x: MlxArray): MlxArray { return disposing(x, ops.mul(x, this.layerScalar)); }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class GemmaInputLayerWeights extends GemmaLayerWeights {
|
|
71
|
+
readonly perLayerGate: QuantizedLinear;
|
|
72
|
+
readonly perLayerProjection: QuantizedLinear;
|
|
73
|
+
readonly postPerLayerNorm: RMSNorm;
|
|
74
|
+
readonly #gate: QuantizedLinearPlain;
|
|
75
|
+
readonly #projection: QuantizedLinearPlain;
|
|
76
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string, attn: Attention) {
|
|
77
|
+
super(weights, config, prefix, attn);
|
|
78
|
+
this.perLayerGate = QuantizedLinear.load(weights, `${prefix}.per_layer_input_gate`, config);
|
|
79
|
+
this.perLayerProjection = QuantizedLinear.load(weights, `${prefix}.per_layer_projection`, config);
|
|
80
|
+
this.postPerLayerNorm = new RMSNorm(weights.tensor(`${prefix}.post_per_layer_input_norm.weight`), config.text.rmsNormEps);
|
|
81
|
+
this.#gate = new QuantizedLinearPlain(this.perLayerGate); this.#projection = new QuantizedLinearPlain(this.perLayerProjection);
|
|
82
|
+
}
|
|
83
|
+
perLayerGated(h: MlxArray, input: MlxArray): MlxArray {
|
|
84
|
+
let gate = this.#gate.forward(h);
|
|
85
|
+
gate = disposing(gate, ops.geluApprox(gate));
|
|
86
|
+
gate = disposing(gate, ops.mul(gate, input));
|
|
87
|
+
gate = disposing(gate, this.#projection.forward(gate));
|
|
88
|
+
gate = disposing(gate, this.postPerLayerNorm.forward(gate));
|
|
89
|
+
const out = ops.add(h, gate); h.dispose(); gate.dispose(); return out;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class GemmaMoeLayerWeights extends GemmaLayerWeights {
|
|
94
|
+
readonly router: Router;
|
|
95
|
+
readonly experts: SwitchGLU;
|
|
96
|
+
readonly postFfNorm1: RMSNorm;
|
|
97
|
+
readonly postFfNorm2: RMSNorm;
|
|
98
|
+
readonly preFfNorm2: RMSNorm;
|
|
99
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string, attn: Attention) {
|
|
100
|
+
super(weights, config, prefix, attn);
|
|
101
|
+
this.router = new PlainRouter(weights, config, `${prefix}.router`);
|
|
102
|
+
this.experts = new SwitchGLU(weights, config, `${prefix}.experts.switch_glu`, true);
|
|
103
|
+
const norm = (name: string) => new RMSNorm(weights.tensor(`${prefix}.${name}.weight`), config.text.rmsNormEps);
|
|
104
|
+
this.postFfNorm1 = norm("post_feedforward_layernorm_1"); this.postFfNorm2 = norm("post_feedforward_layernorm_2");
|
|
105
|
+
this.preFfNorm2 = norm("pre_feedforward_layernorm_2");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class GemmaDenseLayer {
|
|
110
|
+
constructor(readonly weights: GemmaLayerWeights, readonly mlp: PlainGegluMLP | CompiledGegluMLP) {}
|
|
111
|
+
get attn(): Attention { return this.weights.attn; }
|
|
112
|
+
get layerType(): string { return this.weights.layerType; }
|
|
113
|
+
forwardAttn(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null) { return this.weights.forwardAttn(x, cache, phase, donor); }
|
|
114
|
+
feedforward(h: MlxArray): MlxArray {
|
|
115
|
+
let feedforward = this.weights.preFfNorm.forward(h);
|
|
116
|
+
feedforward = disposing(feedforward, this.mlp.forward(feedforward));
|
|
117
|
+
feedforward = disposing(feedforward, this.weights.postFfNorm.forward(feedforward));
|
|
118
|
+
const output = ops.add(h, feedforward); feedforward.dispose();
|
|
119
|
+
return this.weights.scaled(output);
|
|
120
|
+
}
|
|
121
|
+
forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null, _input: MlxArray | null = null) {
|
|
122
|
+
const { h, donor: made } = this.forwardAttn(x, cache, phase, donor);
|
|
123
|
+
try { return { h: this.feedforward(h), donor: made }; }
|
|
124
|
+
catch (error) { made?.dispose(); throw error; } finally { h.dispose(); }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export class GemmaInputLayer {
|
|
129
|
+
constructor(readonly weights: GemmaInputLayerWeights, readonly mlp: PlainGegluMLP | CompiledGegluMLP) {}
|
|
130
|
+
get attn(): Attention { return this.weights.attn; }
|
|
131
|
+
get layerType(): string { return this.weights.layerType; }
|
|
132
|
+
forwardAttn(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null) { return this.weights.forwardAttn(x, cache, phase, donor); }
|
|
133
|
+
feedforward(h: MlxArray, input: MlxArray): MlxArray {
|
|
134
|
+
let feedforward = this.weights.preFfNorm.forward(h);
|
|
135
|
+
feedforward = disposing(feedforward, this.mlp.forward(feedforward));
|
|
136
|
+
feedforward = disposing(feedforward, this.weights.postFfNorm.forward(feedforward));
|
|
137
|
+
const output = ops.add(h, feedforward); feedforward.dispose();
|
|
138
|
+
return this.weights.scaled(this.weights.perLayerGated(output, input));
|
|
139
|
+
}
|
|
140
|
+
forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null, input: MlxArray | null) {
|
|
141
|
+
const { h, donor: made } = this.forwardAttn(x, cache, phase, donor);
|
|
142
|
+
try { return { h: this.feedforward(h, input!), donor: made }; }
|
|
143
|
+
catch (error) { made?.dispose(); throw error; } finally { h.dispose(); }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export class GemmaMoeLayer {
|
|
148
|
+
constructor(readonly weights: GemmaMoeLayerWeights, readonly mlp: CompiledGegluMLP, readonly experts: FixedExperts) {}
|
|
149
|
+
get attn(): Attention { return this.weights.attn; }
|
|
150
|
+
get layerType(): string { return this.weights.layerType; }
|
|
151
|
+
forwardAttn(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null) { return this.weights.forwardAttn(x, cache, phase, donor); }
|
|
152
|
+
feedforward(h: MlxArray): MlxArray {
|
|
153
|
+
let dense = this.weights.preFfNorm.forward(h);
|
|
154
|
+
dense = disposing(dense, this.mlp.forward(dense));
|
|
155
|
+
dense = disposing(dense, this.weights.postFfNorm1.forward(dense));
|
|
156
|
+
const { indices, weights } = this.weights.router.forward(h);
|
|
157
|
+
let expert = this.weights.preFfNorm2.forward(h);
|
|
158
|
+
expert = disposing(expert, this.experts.forward(expert, indices, weights));
|
|
159
|
+
expert = disposing(expert, this.weights.postFfNorm2.forward(expert));
|
|
160
|
+
indices.dispose(); weights.dispose();
|
|
161
|
+
let feedforward = ops.add(dense, expert); dense.dispose(); expert.dispose();
|
|
162
|
+
feedforward = disposing(feedforward, this.weights.postFfNorm.forward(feedforward));
|
|
163
|
+
const out = ops.add(h, feedforward); feedforward.dispose(); return this.weights.scaled(out);
|
|
164
|
+
}
|
|
165
|
+
forward(x: MlxArray, cache: Cache | null, phase: Gemma4Phase, donor: DonorRead | null, _input: MlxArray | null = null) {
|
|
166
|
+
const { h, donor: made } = this.forwardAttn(x, cache, phase, donor);
|
|
167
|
+
try { return { h: this.feedforward(h), donor: made }; }
|
|
168
|
+
catch (error) { made?.dispose(); throw error; } finally { h.dispose(); }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { PlainGegluMLP, CompiledGegluMLP, CompiledGeglu, SortedSwitchGLU, UnsortedSwitchGLU, FixedExperts };
|
|
173
|
+
|
|
174
|
+
/** Ordinary layer-input slices; trace slices have their own named layer. */
|
|
175
|
+
export class FixedPerLayerInputs extends PerLayerInputs {
|
|
176
|
+
readonly #projection: QuantizedLinearPlain;
|
|
177
|
+
readonly #layerCount: number;
|
|
178
|
+
readonly #hiddenSize: number;
|
|
179
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
180
|
+
super(weights, config, prefix);
|
|
181
|
+
this.#projection = new QuantizedLinearPlain(this.modelProjection);
|
|
182
|
+
this.#layerCount = config.text.numHiddenLayers; this.#hiddenSize = config.text.hiddenSize;
|
|
183
|
+
}
|
|
184
|
+
override compute(ids: MlxArray, hidden: MlxArray): MlxArray {
|
|
185
|
+
const [B, L] = ids.shape;
|
|
186
|
+
let inputs = this.embed.encode(ids);
|
|
187
|
+
inputs = disposing(inputs, ops.mulScalar(inputs, Math.sqrt(this.width)));
|
|
188
|
+
inputs = disposing(inputs, ops.reshape(inputs, [B!, L!, this.#layerCount, this.width]));
|
|
189
|
+
let projection = this.#projection.forward(hidden);
|
|
190
|
+
projection = disposing(projection, ops.mulScalar(projection, 1 / Math.sqrt(this.#hiddenSize)));
|
|
191
|
+
projection = disposing(projection, ops.reshape(projection, [B!, L!, this.#layerCount, this.width]));
|
|
192
|
+
projection = disposing(projection, this.projectionNorm.forward(projection));
|
|
193
|
+
const combined = ops.add(projection, inputs); projection.dispose(); inputs.dispose();
|
|
194
|
+
return disposing(combined, ops.mulScalar(combined, Math.SQRT1_2));
|
|
195
|
+
}
|
|
196
|
+
override layer(inputs: MlxArray, index: number, batch: number, length: number): MlxArray {
|
|
197
|
+
using slice = inputs.slice([0, 0, index, 0], [batch, length, index + 1, this.width]);
|
|
198
|
+
return ops.reshape(slice, [batch, length, this.width]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export class TracePerLayerInputs extends FixedPerLayerInputs {
|
|
202
|
+
override layer(inputs: MlxArray, index: number, batch: number, length: number): MlxArray {
|
|
203
|
+
using start = ops.fromInt32([index], [1]);
|
|
204
|
+
using slice = ops.sliceDynamic(inputs, start, [2], [batch, length, 1, this.width]);
|
|
205
|
+
return ops.reshape(slice, [batch, length, this.width]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
import { PerLayerInputs } from "./blocks";
|
|
210
|
+
|
|
211
|
+
/** Ordinary router slice, with no compiled-trace form selection. */
|
|
212
|
+
export class PlainRouter extends Router {
|
|
213
|
+
readonly #projection: QuantizedLinearPlain;
|
|
214
|
+
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
215
|
+
super(weights, config, prefix); this.#projection = new QuantizedLinearPlain(this.proj);
|
|
216
|
+
}
|
|
217
|
+
override forward(x: MlxArray): { indices: MlxArray; weights: MlxArray } {
|
|
218
|
+
using normed = ops.rmsNorm(x, this.normWeight, this.eps);
|
|
219
|
+
using scores = this.#projection.forward(normed);
|
|
220
|
+
using part = ops.argpartitionAxis(scores, this.numExperts - this.topK, -1);
|
|
221
|
+
const [B, L] = scores.shape;
|
|
222
|
+
const indices = part.slice([0, 0, this.numExperts - this.topK], [B!, L!, this.numExperts]);
|
|
223
|
+
let weights = ops.takeAlongAxis(scores, indices, -1);
|
|
224
|
+
weights = disposing(weights, ops.softmaxAxis(weights, -1, false));
|
|
225
|
+
using gathered = ops.takeAxis(this.perExpertScale, indices, 0);
|
|
226
|
+
weights = disposing(weights, ops.mul(weights, gathered));
|
|
227
|
+
if (isExpertTracing()) recordRouting(this.layerIdx, indices);
|
|
228
|
+
return { indices, weights };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
import { isExpertTracing, recordRouting } from "../../runtime/expert-trace";
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
import type { MlxLayerCapture } from "../../contracts/mlx/graph";
|
|
4
|
+
import type { Cache } from "../../contracts/mlx/cache";
|
|
5
|
+
import { GraphForwardScope } from "../../runtime/graph-forward";
|
|
6
|
+
import type { DonorRead, PerLayerInputs, Gemma4Phase } from "./blocks";
|
|
7
|
+
import type { GemmaLayerWeights, GemmaInputLayerWeights, GemmaMoeLayerWeights } from "./written-blocks";
|
|
8
|
+
import type { QuantizedLinear } from "../../layers/quantized-linear";
|
|
9
|
+
|
|
10
|
+
export interface GemmaLayerResult { h: MlxArray; donor: DonorRead | null }
|
|
11
|
+
|
|
12
|
+
/** Carries reads between explicitly written layer calls; owns every retained
|
|
13
|
+
* donor read and the current hidden handle during failures as well as success. */
|
|
14
|
+
export class GemmaForwardScope extends GraphForwardScope {
|
|
15
|
+
readonly reads: (DonorRead | null)[];
|
|
16
|
+
constructor(hidden: MlxArray, capture: MlxLayerCapture | null, caches: number) {
|
|
17
|
+
super(hidden, capture); this.reads = Array(caches).fill(null);
|
|
18
|
+
}
|
|
19
|
+
own(index: number, result: GemmaLayerResult): void {
|
|
20
|
+
result.donor!.dispose(); this.accept(index, result.h);
|
|
21
|
+
}
|
|
22
|
+
donor(index: number, result: GemmaLayerResult): void {
|
|
23
|
+
this.reads[index] = result.donor; this.accept(index, result.h);
|
|
24
|
+
}
|
|
25
|
+
shared(index: number, result: GemmaLayerResult): void { this.accept(index, result.h); }
|
|
26
|
+
override [Symbol.dispose](): void {
|
|
27
|
+
super[Symbol.dispose](); for (const read of this.reads) read?.dispose();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Inputs are sliced one layer at a time in the same order as the graph calls. */
|
|
32
|
+
export class GemmaInputForwardScope extends GemmaForwardScope {
|
|
33
|
+
readonly #inputs: MlxArray;
|
|
34
|
+
#current: MlxArray | null = null;
|
|
35
|
+
readonly #batch: number;
|
|
36
|
+
readonly #length: number;
|
|
37
|
+
constructor(hidden: MlxArray, ids: MlxArray, capture: MlxLayerCapture | null, caches: number,
|
|
38
|
+
readonly perLayer: PerLayerInputs) {
|
|
39
|
+
super(hidden, capture, caches);
|
|
40
|
+
[this.#batch, this.#length] = ids.shape as [number, number];
|
|
41
|
+
try { this.#inputs = perLayer.compute(ids, hidden); }
|
|
42
|
+
catch (error) { super[Symbol.dispose](); throw error; }
|
|
43
|
+
}
|
|
44
|
+
input(index: number): MlxArray {
|
|
45
|
+
this.#current?.dispose();
|
|
46
|
+
this.#current = this.perLayer.layer(this.#inputs, index, this.#batch, this.#length);
|
|
47
|
+
return this.#current;
|
|
48
|
+
}
|
|
49
|
+
override accept(index: number, next: MlxArray): void {
|
|
50
|
+
this.#current?.dispose(); this.#current = null; super.accept(index, next);
|
|
51
|
+
}
|
|
52
|
+
override [Symbol.dispose](): void {
|
|
53
|
+
this.#current?.dispose(); this.#inputs.dispose(); super[Symbol.dispose]();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Record only mounting targets; it never chooses a projection operation. */
|
|
58
|
+
export function denseLoraTargets(parts: readonly GemmaLayerWeights[]): Map<string, QuantizedLinear> {
|
|
59
|
+
const targets = new Map<string, QuantizedLinear>();
|
|
60
|
+
for (const layer of parts) {
|
|
61
|
+
const add = (suffix: string, projection: QuantizedLinear | null) => { if (projection) targets.set(`${layer.prefix}.${suffix}`, projection); };
|
|
62
|
+
add("self_attn.q_proj", layer.attn.qProj); add("self_attn.k_proj", layer.attn.kProj);
|
|
63
|
+
add("self_attn.v_proj", layer.attn.vProj); add("self_attn.o_proj", layer.attn.oProj);
|
|
64
|
+
add("mlp.gate_proj", layer.mlp.gate); add("mlp.up_proj", layer.mlp.up); add("mlp.down_proj", layer.mlp.down);
|
|
65
|
+
}
|
|
66
|
+
return targets;
|
|
67
|
+
}
|
|
68
|
+
export function inputLoraTargets(parts: readonly GemmaInputLayerWeights[]): Map<string, QuantizedLinear> {
|
|
69
|
+
const targets = denseLoraTargets(parts);
|
|
70
|
+
for (const layer of parts) {
|
|
71
|
+
targets.set(`${layer.prefix}.per_layer_input_gate`, layer.perLayerGate);
|
|
72
|
+
targets.set(`${layer.prefix}.per_layer_projection`, layer.perLayerProjection);
|
|
73
|
+
}
|
|
74
|
+
return targets;
|
|
75
|
+
}
|
|
76
|
+
export interface GemmaMixedGroup {
|
|
77
|
+
readonly ids: MlxArray;
|
|
78
|
+
readonly cache: Cache[];
|
|
79
|
+
readonly phase: Gemma4Phase;
|
|
80
|
+
readonly reads: (DonorRead | null)[];
|
|
81
|
+
h: MlxArray;
|
|
82
|
+
inputs: MlxArray | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Request-data iteration for a mixed forward. The file calls each layer in
|
|
86
|
+
* order and supplies literal attention and feed-forward operations; this scope
|
|
87
|
+
* only packs that layer's token rows and carries each group's owned state. */
|
|
88
|
+
export class GemmaMixedScope {
|
|
89
|
+
readonly groups: GemmaMixedGroup[] = [];
|
|
90
|
+
readonly #results: MlxArray[] = [];
|
|
91
|
+
constructor(readonly work: readonly { ids: MlxArray; state: Cache[]; phase: "decode" | "window" | "verify"; capture: MlxLayerCapture | null }[],
|
|
92
|
+
embed: (ids: MlxArray) => MlxArray, readonly caches: number, readonly perLayer: PerLayerInputs | null = null) {
|
|
93
|
+
try {
|
|
94
|
+
for (const row of work) {
|
|
95
|
+
const group: GemmaMixedGroup = { ids: row.ids, cache: row.state, phase: row.phase === "decode" ? "decode" : "window",
|
|
96
|
+
reads: Array(caches).fill(null), h: embed(row.ids), inputs: null };
|
|
97
|
+
this.groups.push(group);
|
|
98
|
+
if (perLayer) group.inputs = perLayer.compute(row.ids, group.h);
|
|
99
|
+
}
|
|
100
|
+
} catch (error) { this[Symbol.dispose](); throw error; }
|
|
101
|
+
}
|
|
102
|
+
layer(index: number, attend: (x: MlxArray, group: GemmaMixedGroup) => MlxArray,
|
|
103
|
+
feedforward: (x: MlxArray, input: MlxArray | null) => MlxArray): void {
|
|
104
|
+
const mids: MlxArray[] = [], inputs: MlxArray[] = [];
|
|
105
|
+
try {
|
|
106
|
+
for (const group of this.groups) {
|
|
107
|
+
mids.push(attend(group.h, group));
|
|
108
|
+
if (this.perLayer) inputs.push(this.perLayer.layer(group.inputs!, index, group.ids.shape[0]!, group.ids.shape[1]!));
|
|
109
|
+
}
|
|
110
|
+
let packedInput: MlxArray | null = null;
|
|
111
|
+
if (inputs.length) {
|
|
112
|
+
const flat = inputs.map(input => ops.reshape(input, [1, -1, this.perLayer!.width]));
|
|
113
|
+
try { packedInput = ops.concatAxis(flat, 1); } finally { for (const input of flat) input.dispose(); }
|
|
114
|
+
}
|
|
115
|
+
using held = packedInput;
|
|
116
|
+
const outputs = mapPackedTokens(mids, packed => feedforward(packed, held));
|
|
117
|
+
for (const [row, group] of this.groups.entries()) { group.h.dispose(); group.h = outputs[row]!; }
|
|
118
|
+
for (const [row, group] of this.groups.entries()) this.work[row]!.capture?.(index, group.h);
|
|
119
|
+
} finally { for (const mid of mids) mid.dispose(); for (const input of inputs) input.dispose(); }
|
|
120
|
+
}
|
|
121
|
+
finish(layerCount: number, norm: { forward(x: MlxArray): MlxArray }): MlxArray[] {
|
|
122
|
+
try {
|
|
123
|
+
for (const [index, group] of this.groups.entries()) {
|
|
124
|
+
const hidden = norm.forward(group.h); this.#results.push(hidden);
|
|
125
|
+
this.work[index]!.capture?.(layerCount, hidden);
|
|
126
|
+
}
|
|
127
|
+
return this.#results.splice(0);
|
|
128
|
+
} catch (error) { for (const result of this.#results) result.dispose(); this.#results.length = 0; throw error; }
|
|
129
|
+
}
|
|
130
|
+
[Symbol.dispose](): void {
|
|
131
|
+
for (const group of this.groups) { group.h.dispose(); group.inputs?.dispose(); for (const read of group.reads) read?.dispose(); }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function ownMixed(result: GemmaLayerResult): MlxArray { result.donor!.dispose(); return result.h; }
|
|
136
|
+
export function donorMixed(group: GemmaMixedGroup, cache: number, result: GemmaLayerResult): MlxArray { group.reads[cache] = result.donor; return result.h; }
|
|
137
|
+
export function sharedMixed(result: GemmaLayerResult): MlxArray { return result.h; }
|
|
138
|
+
|
|
139
|
+
import { mapPackedTokens } from "../../input/token-groups";
|
|
140
|
+
|
|
141
|
+
export function weightBytes(weights: { shards: { files: Map<string, { mmap: { size: number } }> } }): number {
|
|
142
|
+
return [...weights.shards.files.values()].reduce((total, file) => total + file.mmap.size, 0);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Construction ownership until the written graph transfers its constants. */
|
|
146
|
+
export class GemmaBuildScope {
|
|
147
|
+
readonly #constants: MlxArray[] = [];
|
|
148
|
+
hold<T extends GemmaLayerWeights>(layer: T): T {
|
|
149
|
+
if (layer.attn.ropeFreqs) this.#constants.push(layer.attn.ropeFreqs);
|
|
150
|
+
return layer;
|
|
151
|
+
}
|
|
152
|
+
holdMoe(layer: GemmaMoeLayerWeights): GemmaMoeLayerWeights {
|
|
153
|
+
this.hold(layer); this.#constants.push(layer.router.normWeight); return layer;
|
|
154
|
+
}
|
|
155
|
+
finish() { return ownResource(this.#constants.splice(0), disposeResources); }
|
|
156
|
+
[Symbol.dispose](): void { disposeResources(this.#constants.splice(0)); }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
import { ownResource, disposeResources } from "../../runtime/resources";
|