@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,341 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
import { cloneKvCaches } from "./persistence";
|
|
4
|
+
import { type AttentionRead, type BatchableCache, type Cache, type CommittedAttentionCache, type Mask, type PaddedPrefillCache, type PrefillPadding } from "../contracts/mlx/cache";
|
|
5
|
+
import { AttentionMasks, decodeByPosition } from "./attention-read";
|
|
6
|
+
import { affineCausalLease, type AffineKernels } from "./affine-attention";
|
|
7
|
+
import type { AffineKernelSet } from "./kv";
|
|
8
|
+
import { RotatingKVCache } from "./rotating-kv";
|
|
9
|
+
import { RotatingQuantizedKVCache } from "./rotating-quantized-kv";
|
|
10
|
+
import { BatchedRotatingCache, buildBatchedRotatingMask } from "./batched-rotating";
|
|
11
|
+
import { BatchedRotatingQuantCache } from "./batched-rotating-quant";
|
|
12
|
+
import { BatchedRotatingState, type RotatingPositionSnapshot } from "./batched-rotating-state";
|
|
13
|
+
import { plainRowStorage, quantizedRowStorage, temporalStorageView } from "./batched-row-storage";
|
|
14
|
+
import type { TransitioningKvPositions, TransitionedKvLayout } from "./transitioning-kv-rows";
|
|
15
|
+
import { captureRotatingDonorAttention } from "./rotating-kv-donor";
|
|
16
|
+
|
|
17
|
+
import { rollbackRotatingRing } from "./rotating-row-transaction";
|
|
18
|
+
|
|
19
|
+
const fields = ["packed", "scales", "biases"] as const;
|
|
20
|
+
type Ring = BatchedRotatingCache | BatchedRotatingQuantCache;
|
|
21
|
+
|
|
22
|
+
function combinedPosition(rings: readonly Ring[]): RotatingPositionSnapshot {
|
|
23
|
+
const states = rings.map(ring => ring.positionSnapshot);
|
|
24
|
+
return { ...states[0]!, offsets: states.map(state => state.offsets[0]!),
|
|
25
|
+
leftPad: states.map(state => state.leftPad[0]!),
|
|
26
|
+
prefillEnds: states[0]!.prefillEnds
|
|
27
|
+
? states.map(state => state.prefillEnds![0]!) : undefined };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** One logical request with the group's physical ring geometry. This keeps
|
|
31
|
+
* masks stable while different requests cross their precision boundary. */
|
|
32
|
+
export class AlignedRotatingCache implements Cache {
|
|
33
|
+
minimumReusableOffset = 0;
|
|
34
|
+
constructor(public inner: Ring) {}
|
|
35
|
+
get offset(): number { return this.inner.validOffset(0); }
|
|
36
|
+
get affineConversion(): AlignedRotatingCache | undefined { return this.inner instanceof BatchedRotatingCache ? this : undefined; }
|
|
37
|
+
get quantizedAttention() { return this.inner instanceof BatchedRotatingQuantCache ? this.inner : undefined; }
|
|
38
|
+
signature(): string { return this.inner.signature(); }
|
|
39
|
+
captureDonorAttention() { return captureRotatingDonorAttention(this.inner); }
|
|
40
|
+
updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.inner.updateAndFetch(k, v); }
|
|
41
|
+
makeMask(tokens: number, window: number | null): Mask { return this.inner.makeMask(tokens, window); }
|
|
42
|
+
isTrimmable(): boolean { return this.inner.positionSnapshot.totalOffset < this.inner.maxSize; }
|
|
43
|
+
trim(count: number): void { this.inner.trim(count); }
|
|
44
|
+
rollback(before: number, keep: number, preserveColumns: boolean): void {
|
|
45
|
+
this.inner = rollbackRotatingRing(this.inner, [before], keep, preserveColumns);
|
|
46
|
+
}
|
|
47
|
+
state(): MlxArray[] { return this.inner.state(); }
|
|
48
|
+
bytesPerToken(): number {
|
|
49
|
+
const state = this.state(), tokens = state[0]?.shape[2] ?? 0;
|
|
50
|
+
return tokens ? state.reduce((n, a) => n + a.nbytes, 0) / tokens : 0;
|
|
51
|
+
}
|
|
52
|
+
dispose(): void { this.inner.dispose(); }
|
|
53
|
+
extract(limit?: number): Cache {
|
|
54
|
+
const row = this.inner.extractRow(0, limit) ?? (this.inner instanceof BatchedRotatingQuantCache
|
|
55
|
+
? new RotatingQuantizedKVCache(this.inner.maxSize, this.inner.groupSize, this.inner.bits, this.inner.kernels)
|
|
56
|
+
: new RotatingKVCache(this.inner.maxSize));
|
|
57
|
+
row.minimumReusableOffset = this.minimumReusableOffset;
|
|
58
|
+
return row;
|
|
59
|
+
}
|
|
60
|
+
/** Quantize the ring's physical columns; the converted ring attends with the
|
|
61
|
+
* set `kernels` builds for its bits, group size and activation dtype. */
|
|
62
|
+
toQuantized(groupSize: number, bits: number, kernels: AffineKernelSet): AlignedRotatingCache {
|
|
63
|
+
const plain = this.inner as BatchedRotatingCache;
|
|
64
|
+
const set = kernels(bits, groupSize, plain.keys!.dtype);
|
|
65
|
+
const keys = ops.quantize(plain.keys!, groupSize, bits);
|
|
66
|
+
let values: ops.QuantizedTensor;
|
|
67
|
+
try { values = ops.quantize(plain.values!, groupSize, bits); }
|
|
68
|
+
catch (error) { quantizedRowStorage.dispose(keys); throw error; }
|
|
69
|
+
const next = new AlignedRotatingCache(BatchedRotatingQuantCache.adoptPhysical(keys, values, groupSize, bits, set, plain.positionSnapshot));
|
|
70
|
+
next.minimumReusableOffset = this.minimumReusableOffset;
|
|
71
|
+
this.dispose();
|
|
72
|
+
return next;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Borrow the newest valid window from a solo cache, including a temporary
|
|
77
|
+
* oversized block. No dequantization or physical-ring normalization in place. */
|
|
78
|
+
export function rotatingSourcePosition(row: RotatingKVCache | RotatingQuantizedKVCache): BatchedRotatingState {
|
|
79
|
+
const state = new BatchedRotatingState(row.maxSize, [0], [row.offset]);
|
|
80
|
+
const length = row instanceof RotatingKVCache ? row.keys?.shape[2] ?? 0 : row.keys?.packed.shape[2] ?? 0;
|
|
81
|
+
state.restore({ maxSize: row.maxSize, offsets: [row.offset], leftPad: [0], totalOffset: row.offset,
|
|
82
|
+
ringIndex: row.ringIdx, rotated: row.ringIdx < row.offset && row.ringIdx < length });
|
|
83
|
+
return state;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Take ownership of solo rows and align them once at membership changes.
|
|
87
|
+
* Several rows need one ring geometry, so each is laid out in temporal order
|
|
88
|
+
* behind its left padding. A single row already has one: it keeps its own
|
|
89
|
+
* physical columns, ring phase and offset, so the adopted row attends over its
|
|
90
|
+
* keys in the order the solo cache does and later writes land where the solo
|
|
91
|
+
* cache's would (a solo wrapped ring is not in temporal order). */
|
|
92
|
+
export function alignRotatingRows(rows: Cache[]): AlignedRotatingCache[] {
|
|
93
|
+
if (rows.length === 1) {
|
|
94
|
+
const adopted = adoptRotatingRow(rows[0]!);
|
|
95
|
+
rows[0]!.dispose();
|
|
96
|
+
return [adopted];
|
|
97
|
+
}
|
|
98
|
+
const width = Math.max(0, ...rows.map(row => Math.min(row.offset, (row as RotatingKVCache).maxSize)));
|
|
99
|
+
const prototype = rows.find(row => row.state().length > 0) as RotatingKVCache | RotatingQuantizedKVCache | undefined;
|
|
100
|
+
const emptyPlane = (field: "keys" | "values"): MlxArray | null => {
|
|
101
|
+
if (!width || !prototype) return null;
|
|
102
|
+
const tensor = prototype[field]!;
|
|
103
|
+
if (tensor instanceof MlxArray) return ops.zeros([1, tensor.shape[1]!, width, tensor.shape[3]!], tensor.dtype);
|
|
104
|
+
return ops.zeros([1, tensor.packed.shape[1]!, width, tensor.packed.shape[3]! * 32 / (prototype as RotatingQuantizedKVCache).bits], tensor.scales.dtype);
|
|
105
|
+
};
|
|
106
|
+
const result: AlignedRotatingCache[] = [];
|
|
107
|
+
try {
|
|
108
|
+
for (const source of rows) {
|
|
109
|
+
if (!(source instanceof RotatingKVCache || source instanceof RotatingQuantizedKVCache))
|
|
110
|
+
throw new Error(`rotating layout cannot adopt ${source.signature()}`);
|
|
111
|
+
const length = Math.min(source.offset, source.maxSize), pad = width - length;
|
|
112
|
+
const position: RotatingPositionSnapshot = { maxSize: source.maxSize, offsets: [source.offset], leftPad: [pad],
|
|
113
|
+
totalOffset: width, ringIndex: width, rotated: false };
|
|
114
|
+
const state = rotatingSourcePosition(source);
|
|
115
|
+
const options = { from: Math.max(0, state.activeLength - length), to: state.activeLength };
|
|
116
|
+
let inner: Ring;
|
|
117
|
+
if (source instanceof RotatingKVCache) {
|
|
118
|
+
using k = source.keys ? temporalStorageView(plainRowStorage, source.keys, state, options) : null;
|
|
119
|
+
using v = source.values ? temporalStorageView(plainRowStorage, source.values, state, options) : null;
|
|
120
|
+
const keys = k ? plainRowStorage.padLeft(k, pad) : emptyPlane("keys");
|
|
121
|
+
let values: MlxArray | null;
|
|
122
|
+
try { values = v ? plainRowStorage.padLeft(v, pad) : emptyPlane("values"); }
|
|
123
|
+
catch (error) { keys?.dispose(); throw error; }
|
|
124
|
+
inner = BatchedRotatingCache.adoptPhysical(keys, values, position);
|
|
125
|
+
} else {
|
|
126
|
+
const k = source.keys ? temporalStorageView(quantizedRowStorage, source.keys, state, options) : null;
|
|
127
|
+
const v = source.values ? temporalStorageView(quantizedRowStorage, source.values, state, options) : null;
|
|
128
|
+
const empty = (field: "keys" | "values") => {
|
|
129
|
+
using tensor = emptyPlane(field);
|
|
130
|
+
return tensor ? ops.quantize(tensor, source.groupSize, source.bits) : null;
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
const keys = k ? quantizedRowStorage.padLeft(k, pad) : empty("keys");
|
|
134
|
+
let values: ops.QuantizedTensor | null;
|
|
135
|
+
try { values = v ? quantizedRowStorage.padLeft(v, pad) : empty("values"); }
|
|
136
|
+
catch (error) { if (keys) quantizedRowStorage.dispose(keys); throw error; }
|
|
137
|
+
inner = BatchedRotatingQuantCache.adoptPhysical(keys, values, source.groupSize, source.bits, source.kernels, position);
|
|
138
|
+
} finally { if (k) quantizedRowStorage.dispose(k); if (v) quantizedRowStorage.dispose(v); }
|
|
139
|
+
}
|
|
140
|
+
const row = new AlignedRotatingCache(inner); row.minimumReusableOffset = source.minimumReusableOffset ?? 0;
|
|
141
|
+
result.push(row);
|
|
142
|
+
}
|
|
143
|
+
} catch (error) { for (const row of result) row.dispose(); throw error; }
|
|
144
|
+
for (const row of rows) row.dispose();
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** One solo row in its own ring geometry: owned views of its physical
|
|
149
|
+
* planes with the position its source reports (rotatingSourcePosition). Every
|
|
150
|
+
* view taken is released if any later step fails; the source stays with the
|
|
151
|
+
* caller either way. */
|
|
152
|
+
function adoptRotatingRow(source: Cache): AlignedRotatingCache {
|
|
153
|
+
if (!(source instanceof RotatingKVCache || source instanceof RotatingQuantizedKVCache))
|
|
154
|
+
throw new Error(`rotating layout cannot adopt ${source.signature()}`);
|
|
155
|
+
const position = rotatingSourcePosition(source).snapshot();
|
|
156
|
+
const views: MlxArray[] = [];
|
|
157
|
+
const view = (array: MlxArray): MlxArray => {
|
|
158
|
+
const owned = plainRowStorage.slice(array, 0, 1, 0, array.shape[2]!);
|
|
159
|
+
views.push(owned);
|
|
160
|
+
return owned;
|
|
161
|
+
};
|
|
162
|
+
try {
|
|
163
|
+
let inner: Ring;
|
|
164
|
+
if (source instanceof RotatingKVCache) {
|
|
165
|
+
inner = BatchedRotatingCache.adoptPhysical(source.keys ? view(source.keys) : null, source.values ? view(source.values) : null, position);
|
|
166
|
+
} else {
|
|
167
|
+
const triple = (plane: ops.QuantizedTensor | null): ops.QuantizedTensor | null =>
|
|
168
|
+
plane ? { packed: view(plane.packed), scales: view(plane.scales), biases: view(plane.biases) } : null;
|
|
169
|
+
const keys = triple(source.keys), values = triple(source.values);
|
|
170
|
+
inner = BatchedRotatingQuantCache.adoptPhysical(keys, values, source.groupSize, source.bits, source.kernels, position);
|
|
171
|
+
}
|
|
172
|
+
const row = new AlignedRotatingCache(inner); row.minimumReusableOffset = source.minimumReusableOffset ?? 0;
|
|
173
|
+
return row;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
for (const owned of views) owned.dispose();
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Position state has no codec or attention arithmetic. */
|
|
181
|
+
export class RotatingKvPositions implements TransitioningKvPositions {
|
|
182
|
+
#state: BatchedRotatingState;
|
|
183
|
+
#rope?: MlxArray;
|
|
184
|
+
constructor(maxSize: number) { this.#state = new BatchedRotatingState(maxSize, []); }
|
|
185
|
+
get rowOffsets(): readonly number[] { return this.#state.offsets; }
|
|
186
|
+
get leftPad(): readonly number[] { return this.#state.leftPad; }
|
|
187
|
+
get offset(): number { return this.#state.totalOffset; }
|
|
188
|
+
get batchSize(): number | null { return this.#state.batchSize || null; }
|
|
189
|
+
get ropeOffsetArr(): MlxArray | undefined {
|
|
190
|
+
if (!this.batchSize) return undefined;
|
|
191
|
+
return this.#rope ??= ops.fromInt32([...this.rowOffsets], [this.batchSize]);
|
|
192
|
+
}
|
|
193
|
+
sync(rows: readonly Cache[]): void {
|
|
194
|
+
this.#rope?.dispose(); this.#rope = undefined;
|
|
195
|
+
if (!rows.length) { this.#state = new BatchedRotatingState(this.#state.maxSize, []); return; }
|
|
196
|
+
this.#state.restore(combinedPosition(rows.map(row => (row as AlignedRotatingCache).inner)));
|
|
197
|
+
}
|
|
198
|
+
filterRows(keep: readonly number[]): void { this.#state.filter(keep); this.#rope?.dispose(); this.#rope = undefined; }
|
|
199
|
+
makeMask(tokens: number, window: number | null): Mask {
|
|
200
|
+
return { mode: "array", arr: buildBatchedRotatingMask(this.#state.batchSize, tokens, this.#state.leftPad,
|
|
201
|
+
this.#state.maxSize, window ?? this.#state.maxSize, this.#state.ringIndex, this.#state.totalOffset, this.#state.rotated,
|
|
202
|
+
tokens > 1 || this.#state.hasPendingPadding) };
|
|
203
|
+
}
|
|
204
|
+
dispose(): void { this.#rope?.dispose(); this.#rope = undefined; this.#state = new BatchedRotatingState(this.#state.maxSize, []); }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Once all rows use affine storage, concatenate their already-aligned planes
|
|
208
|
+
* without changing ring columns or rebuilding any attention mask.
|
|
209
|
+
* Reads are the current ring's (`BatchedRotatingQuantCache`); every ring this
|
|
210
|
+
* layout builds shares its `masks` and `kernels`. */
|
|
211
|
+
export class RotatingAffineLayout implements TransitionedKvLayout, PaddedPrefillCache, CommittedAttentionCache {
|
|
212
|
+
#inner?: BatchedRotatingQuantCache;
|
|
213
|
+
#before?: number[];
|
|
214
|
+
#minimum: number[] = [];
|
|
215
|
+
constructor(
|
|
216
|
+
readonly maxSize: number,
|
|
217
|
+
readonly groupSize: number,
|
|
218
|
+
readonly bits: number,
|
|
219
|
+
/** The composition's kernels: every ring this layout builds attends with
|
|
220
|
+
* them (decode, masked windows), and `SpeculativeRotatingAffineLayout`
|
|
221
|
+
* reads a plain causal window with their window kernel. */
|
|
222
|
+
readonly kernels: AffineKernels,
|
|
223
|
+
/** The per-forward masks of the model this layout serves. */
|
|
224
|
+
readonly masks = new AttentionMasks(),
|
|
225
|
+
) {}
|
|
226
|
+
get minimumReusableOffset(): number { return Math.max(0, ...this.#minimum); }
|
|
227
|
+
get quantizedAttention() { return this.#inner; }
|
|
228
|
+
/** The current ring. */
|
|
229
|
+
protected get ring(): BatchedRotatingQuantCache { return this.#inner!; }
|
|
230
|
+
appendDecode(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner!.appendDecode(k, v); }
|
|
231
|
+
appendWindow(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner!.appendWindow(k, v); }
|
|
232
|
+
/** A committed span, one decode per position (`decodeByPosition`). */
|
|
233
|
+
appendCommitted(k: MlxArray, v: MlxArray): AttentionRead { return decodeByPosition(this, k, v); }
|
|
234
|
+
captureDonorAttention(): import("../contracts/mlx/cache").KvDonorAttention {
|
|
235
|
+
return captureRotatingDonorAttention(this.#inner!);
|
|
236
|
+
}
|
|
237
|
+
get rowOffsets(): readonly number[] { return this.#inner?.offsetArr ?? []; }
|
|
238
|
+
get leftPad(): readonly number[] { return this.#inner?.leftPad ?? []; }
|
|
239
|
+
get offset(): number { return this.#inner?.offset ?? 0; }
|
|
240
|
+
get batchSize(): number | null { return this.#inner?.batchSize || null; }
|
|
241
|
+
get ropeOffsetArr(): MlxArray | undefined { return this.#inner?.ropeOffsetArr; }
|
|
242
|
+
get maxTokens(): number { return this.maxSize; }
|
|
243
|
+
signature(): string { return `kv:rotating-affine:${this.maxSize}:${this.groupSize}:${this.bits}`; }
|
|
244
|
+
makeEmptyBatch(): RotatingAffineLayout { return new RotatingAffineLayout(this.maxSize, this.groupSize, this.bits, this.kernels, this.masks); }
|
|
245
|
+
makeMask(tokens: number, window: number | null): Mask { return this.#inner!.makeMask(tokens, window); }
|
|
246
|
+
preparePrefill(padding: PrefillPadding): void { this.#inner!.preparePrefill(padding); }
|
|
247
|
+
finalizePrefill(): void { this.#inner!.finalizePrefill(); }
|
|
248
|
+
bytesPerToken(): number {
|
|
249
|
+
const tokens = this.#inner?.keys?.packed.shape[2] ?? 0;
|
|
250
|
+
return tokens ? this.state().reduce((n, a) => n + a.nbytes, 0) / (tokens * this.#inner!.batchSize) : 0;
|
|
251
|
+
}
|
|
252
|
+
projectedBytes(tokens: number): number { return this.bytesPerToken() * Math.min(tokens, this.maxSize); }
|
|
253
|
+
isTrimmable(): boolean { return this.#inner!.positionSnapshot.totalOffset < this.maxSize; }
|
|
254
|
+
trim(count: number): void { this.#inner!.trim(count); }
|
|
255
|
+
specRoundBegin(): void { this.#before = [...this.rowOffsets]; }
|
|
256
|
+
specRoundCommit(): void { this.#before = undefined; }
|
|
257
|
+
specRoundRollback(keep: number | readonly number[]): void {
|
|
258
|
+
this.#inner = rollbackRotatingRing(this.#inner!, this.#before!, keep);
|
|
259
|
+
this.#before = undefined;
|
|
260
|
+
}
|
|
261
|
+
updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.#inner!.updateAndFetch(k, v); }
|
|
262
|
+
releaseRopeArr(): void { this.#inner?.releaseRopeArr(); }
|
|
263
|
+
mergeRows(rows: readonly Cache[]): void {
|
|
264
|
+
const owned: Cache[] = [];
|
|
265
|
+
try {
|
|
266
|
+
for (const row of rows) {
|
|
267
|
+
if (row instanceof RotatingAffineLayout) {
|
|
268
|
+
for (let i = 0; i < (row.batchSize ?? 0); i++) owned.push(row.extractRow(i));
|
|
269
|
+
} else if (row instanceof AlignedRotatingCache) owned.push(row.extract());
|
|
270
|
+
else owned.push(...cloneKvCaches([row.composed ? row.composed.storage() : row]));
|
|
271
|
+
}
|
|
272
|
+
if (!owned.length) { this.dispose(); return; }
|
|
273
|
+
const aligned = alignRotatingRows(owned); owned.length = 0;
|
|
274
|
+
try { this.adoptAlignedRows(aligned); } finally { for (const row of aligned) row.dispose(); }
|
|
275
|
+
} finally { for (const row of owned) row.dispose(); }
|
|
276
|
+
}
|
|
277
|
+
adoptAlignedRows(rows: readonly AlignedRotatingCache[]): void {
|
|
278
|
+
const rings = rows.map(row => (row as AlignedRotatingCache).inner as BatchedRotatingQuantCache);
|
|
279
|
+
const position = combinedPosition(rings);
|
|
280
|
+
if (rings.every(row => !row.keys)) {
|
|
281
|
+
const empty = BatchedRotatingQuantCache.adoptPhysical(null, null, this.groupSize, this.bits, this.kernels,
|
|
282
|
+
position, this.masks);
|
|
283
|
+
this.#inner?.dispose(); this.#inner = empty; this.#minimum = rows.map(row => row.minimumReusableOffset ?? 0);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const merge = (field: "keys" | "values") => {
|
|
287
|
+
const planes: MlxArray[] = [];
|
|
288
|
+
try {
|
|
289
|
+
for (const part of fields) planes.push(ops.concatAxis(rings.map(row => row[field]![part]), 0));
|
|
290
|
+
return { packed: planes[0]!, scales: planes[1]!, biases: planes[2]! };
|
|
291
|
+
} catch (error) { for (const plane of planes) plane.dispose(); throw error; }
|
|
292
|
+
};
|
|
293
|
+
const keys = merge("keys"); let values: ops.QuantizedTensor;
|
|
294
|
+
try { values = merge("values"); } catch (error) { quantizedRowStorage.dispose(keys); throw error; }
|
|
295
|
+
const inner = BatchedRotatingQuantCache.adoptPhysical(keys, values, this.groupSize, this.bits, this.kernels,
|
|
296
|
+
position, this.masks);
|
|
297
|
+
this.#inner?.dispose(); this.#inner = inner; this.#minimum = rows.map(row => row.minimumReusableOffset ?? 0);
|
|
298
|
+
}
|
|
299
|
+
filterRows(keep: readonly number[]): void { this.#inner!.filterRows(keep); this.#minimum = keep.map(row => this.#minimum[row]!); }
|
|
300
|
+
extractRow(row: number): Cache {
|
|
301
|
+
return this.extract(row);
|
|
302
|
+
}
|
|
303
|
+
protected extract(row: number, limit?: number): Cache {
|
|
304
|
+
const result = this.#inner!.extractRow(row, limit) ?? new RotatingQuantizedKVCache(this.maxSize, this.groupSize, this.bits, this.#inner!.kernels);
|
|
305
|
+
result.minimumReusableOffset = this.#minimum[row] ?? 0; return result;
|
|
306
|
+
}
|
|
307
|
+
state(): MlxArray[] { return this.#inner?.state() ?? []; }
|
|
308
|
+
dispose(): void { this.#inner?.dispose(); this.#inner = undefined; this.#minimum = []; this.#before = undefined; }
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** A committed speculative checkpoint contains only the newest valid window.
|
|
312
|
+
* While no row is padded and the window has room, the mask is plain causal
|
|
313
|
+
* (`makeMask` hands the graphs the "" and "causal" strings): a window there
|
|
314
|
+
* writes through the ring and attends under the bottom-right causal matrix with
|
|
315
|
+
* the window kernel. Otherwise reads are the ring's, under its batched rotating
|
|
316
|
+
* mask. Decode is the ring's in both states; its mask then selects every stored
|
|
317
|
+
* position, so the unfused port computes the same bits as with no mask. */
|
|
318
|
+
export class SpeculativeRotatingAffineLayout extends RotatingAffineLayout {
|
|
319
|
+
#ropeForOffset = -1;
|
|
320
|
+
override get ropeOffsetArr(): MlxArray | undefined {
|
|
321
|
+
if (this.#ropeForOffset !== this.offset) {
|
|
322
|
+
this.releaseRopeArr(); this.#ropeForOffset = this.offset;
|
|
323
|
+
}
|
|
324
|
+
return super.ropeOffsetArr;
|
|
325
|
+
}
|
|
326
|
+
override makeEmptyBatch(): SpeculativeRotatingAffineLayout {
|
|
327
|
+
return new SpeculativeRotatingAffineLayout(this.maxSize, this.groupSize, this.bits, this.kernels, this.masks);
|
|
328
|
+
}
|
|
329
|
+
override appendWindow(k: MlxArray, v: MlxArray): AttentionRead {
|
|
330
|
+
const L = k.shape[2]!;
|
|
331
|
+
if (!(this.leftPad.every(pad => pad === 0) && this.offset + L <= this.maxSize)) return super.appendWindow(k, v);
|
|
332
|
+
return this.ring.appendWindowUnder(k, v, affineCausalLease(this.masks, L, this.offset + L), this.kernels.window);
|
|
333
|
+
}
|
|
334
|
+
override makeMask(tokens: number, window: number | null): Mask {
|
|
335
|
+
if (this.leftPad.every(pad => pad === 0) &&
|
|
336
|
+
this.offset + tokens <= Math.min(this.maxSize, window ?? this.maxSize))
|
|
337
|
+
return { mode: tokens === 1 ? "" : "causal", arr: null };
|
|
338
|
+
return super.makeMask(tokens, window);
|
|
339
|
+
}
|
|
340
|
+
override extractRow(row: number): Cache { return this.extract(row, this.maxSize); }
|
|
341
|
+
}
|