@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,116 @@
|
|
|
1
|
+
// Greedy selection preserves dtype-rounded normalized scores, including ties.
|
|
2
|
+
// Native logsumexp retains the reference reduction. Tiled selection avoids
|
|
3
|
+
// writing the vocabulary-sized normalized array. Inputs remain borrowed.
|
|
4
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
5
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
6
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
7
|
+
import { CompiledFunction, isShapelessTracing } from "@mlx-bun/mlx/compile";
|
|
8
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
9
|
+
|
|
10
|
+
const header = `
|
|
11
|
+
inline bool better(float x, uint xi, float y, uint yi) {
|
|
12
|
+
return x > y || (x == y && xi < yi);
|
|
13
|
+
}`;
|
|
14
|
+
|
|
15
|
+
// Four simdgroups reduce score/index pairs. Lowest token ID wins every tie.
|
|
16
|
+
// The caller finishes the simd==0 block by writing its output from lane zero.
|
|
17
|
+
const reduction = `
|
|
18
|
+
for (uint distance = 16; distance > 0; distance >>= 1) {
|
|
19
|
+
float other = simd_shuffle_down(best, distance);
|
|
20
|
+
uint oi = simd_shuffle_down(bestId, distance);
|
|
21
|
+
if (lane + distance < 32 && better(other, oi, best, bestId)) {
|
|
22
|
+
best = other; bestId = oi;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
threadgroup float scores[4];
|
|
26
|
+
threadgroup uint ids[4];
|
|
27
|
+
if (lane == 0) { scores[simd] = best; ids[simd] = bestId; }
|
|
28
|
+
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
29
|
+
if (simd == 0) {
|
|
30
|
+
best = lane < 4 ? scores[lane] : -INFINITY;
|
|
31
|
+
bestId = lane < 4 ? ids[lane] : 0xffffffffu;
|
|
32
|
+
for (uint distance = 2; distance > 0; distance >>= 1) {
|
|
33
|
+
float other = simd_shuffle_down(best, distance);
|
|
34
|
+
uint oi = simd_shuffle_down(bestId, distance);
|
|
35
|
+
if (lane + distance < 4 && better(other, oi, best, bestId)) {
|
|
36
|
+
best = other; bestId = oi;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const partialSource = `
|
|
42
|
+
const uint tid = thread_position_in_threadgroup.x;
|
|
43
|
+
const uint lane = tid % 32, simd = tid / 32;
|
|
44
|
+
const uint row = threadgroup_position_in_grid.y;
|
|
45
|
+
const uint tile = threadgroup_position_in_grid.x;
|
|
46
|
+
float best = -INFINITY;
|
|
47
|
+
uint bestId = 0xffffffffu;
|
|
48
|
+
for (uint i = tile * 1024 + tid; i < min(uint(V), (tile + 1) * 1024); i += 128) {
|
|
49
|
+
float value = float(T(logits[row * V + i] - lse[row]));
|
|
50
|
+
// A nonfinite logsumexp produces only NaN/-inf normalized scores.
|
|
51
|
+
// Native argmax selects token zero for this degenerate row.
|
|
52
|
+
value = isnan(value) ? -INFINITY : value;
|
|
53
|
+
if (better(value, i, best, bestId)) { best = value; bestId = i; }
|
|
54
|
+
}
|
|
55
|
+
${reduction}
|
|
56
|
+
if (lane == 0) { values[row * P + tile] = best; indices[row * P + tile] = bestId; }
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const finishSource = `
|
|
61
|
+
const uint tid = thread_position_in_threadgroup.x;
|
|
62
|
+
const uint lane = tid % 32, simd = tid / 32;
|
|
63
|
+
const uint row = threadgroup_position_in_grid.y;
|
|
64
|
+
float best = -INFINITY;
|
|
65
|
+
uint bestId = 0xffffffffu;
|
|
66
|
+
for (uint i = tid; i < P; i += 128) {
|
|
67
|
+
float value = values[row * P + i];
|
|
68
|
+
uint id = indices[row * P + i];
|
|
69
|
+
if (better(value, id, best, bestId)) { best = value; bestId = id; }
|
|
70
|
+
}
|
|
71
|
+
${reduction}
|
|
72
|
+
if (lane == 0) out[row] = bestId;
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
let partial: MetalKernel | undefined;
|
|
77
|
+
let finish: MetalKernel | undefined;
|
|
78
|
+
let compiled: CompiledFunction | undefined;
|
|
79
|
+
|
|
80
|
+
function kernelGraph(logits: MlxArray): MlxArray {
|
|
81
|
+
const shape = logits.shape;
|
|
82
|
+
const vocab = shape.at(-1)!, rows = logits.size / vocab, tiles = Math.ceil(vocab / 1024);
|
|
83
|
+
partial ??= new MetalKernel({ name: "normalized_argmax_partial", header,
|
|
84
|
+
inputNames: ["logits", "lse"], outputNames: ["values", "indices"], source: partialSource });
|
|
85
|
+
finish ??= new MetalKernel({ name: "normalized_argmax_finish", header,
|
|
86
|
+
inputNames: ["values", "indices"], outputNames: ["out"], source: finishSource });
|
|
87
|
+
using lse = ops.logsumexpAxis(logits, -1, true);
|
|
88
|
+
const [values, indices] = partial.apply([logits, lse], {
|
|
89
|
+
outputs: [{ shape: [rows, tiles], dtype: Dtype.float32 }, { shape: [rows, tiles], dtype: Dtype.uint32 }],
|
|
90
|
+
grid: [tiles * 128, rows, 1], threadGroup: [128, 1, 1],
|
|
91
|
+
templateInts: { V: vocab, P: tiles }, templateDtypes: { T: logits.dtype },
|
|
92
|
+
});
|
|
93
|
+
try {
|
|
94
|
+
using tokens = finish.apply([values!, indices!], {
|
|
95
|
+
outputs: [{ shape: [rows], dtype: Dtype.uint32 }],
|
|
96
|
+
grid: [128, rows, 1], threadGroup: [128, 1, 1], templateInts: { P: tiles },
|
|
97
|
+
})[0]!;
|
|
98
|
+
return ops.reshape(tokens, shape.slice(0, -1));
|
|
99
|
+
} finally { values!.dispose(); indices!.dispose(); }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Return owned greedy IDs with the same shape/rounding as argmax(logprobs).
|
|
103
|
+
* Fixed-shape compilation caches graph/FFI work for repeated row geometries.
|
|
104
|
+
* Shapeless enclosing graphs retain native operations, which support symbolic
|
|
105
|
+
* sizes; integer/empty inputs also retain the original operation semantics. */
|
|
106
|
+
export function normalizedArgmax(logits: MlxArray): MlxArray {
|
|
107
|
+
const dtype = logits.dtype;
|
|
108
|
+
if (isShapelessTracing() || logits.size === 0 ||
|
|
109
|
+
(dtype !== Dtype.float32 && dtype !== Dtype.float16 && dtype !== Dtype.bfloat16)) {
|
|
110
|
+
using lse = ops.logsumexpAxis(logits, -1, true);
|
|
111
|
+
using scores = ops.sub(logits, lse);
|
|
112
|
+
return ops.argmaxAxis(scores, -1);
|
|
113
|
+
}
|
|
114
|
+
compiled ??= new CompiledFunction(([input]) => [kernelGraph(input!)], false);
|
|
115
|
+
return compiled.apply([logits])[0]!;
|
|
116
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// XGrammar's additive 0/-Infinity mask contract, decoded from packed bits.
|
|
2
|
+
// Reference: mlc-ai/xgrammar b5048784, apply_token_bitmask_mlx.py (Apache-2.0).
|
|
3
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
4
|
+
import { CompiledFunction } from "@mlx-bun/mlx/compile";
|
|
5
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
6
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
7
|
+
|
|
8
|
+
let compiled: CompiledFunction | undefined;
|
|
9
|
+
let kernel: MetalKernel | undefined;
|
|
10
|
+
|
|
11
|
+
function maskGraph(logits: MlxArray, bits: MlxArray): MlxArray {
|
|
12
|
+
kernel ??= new MetalKernel({
|
|
13
|
+
name: "mlx_bun_token_bitmask",
|
|
14
|
+
inputNames: ["logits", "bits"],
|
|
15
|
+
outputNames: ["out"],
|
|
16
|
+
source: String.raw`
|
|
17
|
+
const uint i = thread_position_in_grid.x;
|
|
18
|
+
if (i >= SIZE) return;
|
|
19
|
+
const uint id = i % V;
|
|
20
|
+
const uint word = uint(bits[id >> 5]);
|
|
21
|
+
const bool valid = ((word >> (id & 31)) & 1u) != 0;
|
|
22
|
+
out[i] = logits[i] + T(valid ? 0.0f : -INFINITY);
|
|
23
|
+
`,
|
|
24
|
+
});
|
|
25
|
+
return kernel.apply([logits, bits], {
|
|
26
|
+
outputs: [{ shape: logits.shape, dtype: logits.dtype }],
|
|
27
|
+
grid: [logits.size, 1, 1],
|
|
28
|
+
threadGroup: [128, 1, 1],
|
|
29
|
+
templateDtypes: { T: logits.dtype },
|
|
30
|
+
templateInts: { V: logits.shape.at(-1)!, SIZE: logits.size },
|
|
31
|
+
})[0]!;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Apply one little-endian token bitmask to every row along the final axis.
|
|
35
|
+
* Borrow logits; return an owned lazy result. Copy the mutable host bits now,
|
|
36
|
+
* so a matcher can advance before GPU evaluation. Missing words reject tokens.
|
|
37
|
+
* Preserve the additive-mask expression, including NaNs and signed zero.
|
|
38
|
+
* Shape-specialized compilation handles bf16/f16/f32 and strided inputs. */
|
|
39
|
+
export function applyTokenBitmask(logits: MlxArray, bits: Int32Array): MlxArray {
|
|
40
|
+
const vocab = logits.shape.at(-1);
|
|
41
|
+
if (!vocab || logits.size === 0 || logits.size > 0x7fffffff)
|
|
42
|
+
throw new Error("token bitmask requires nonempty logits with at most 2^31-1 elements");
|
|
43
|
+
if (![Dtype.bfloat16, Dtype.float16, Dtype.float32].includes(logits.dtype))
|
|
44
|
+
throw new Error("token bitmask requires bf16, f16 or f32 logits");
|
|
45
|
+
const copy = new Int32Array(Math.ceil(vocab / 32));
|
|
46
|
+
copy.set(bits.subarray(0, copy.length));
|
|
47
|
+
const deviceBits = MlxArray.fromInt32(copy, [copy.length]);
|
|
48
|
+
try {
|
|
49
|
+
compiled ??= new CompiledFunction(([x, mask]) => [maskGraph(x!, mask!)], false);
|
|
50
|
+
return compiled.apply([logits, deviceBits])[0]!;
|
|
51
|
+
} finally { deviceBits.dispose(); }
|
|
52
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Compiled (fused) Gemma logit softcap, matching mlx-lm's gemma4_text.py
|
|
2
|
+
// `@partial(mx.compile) logit_softcap`. The unfused composition lives in
|
|
3
|
+
// logits.ts; the two are separate on purpose (see compiledLogitSoftcap).
|
|
4
|
+
|
|
5
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
6
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
7
|
+
import { CompiledFunction } from "@mlx-bun/mlx/compile";
|
|
8
|
+
|
|
9
|
+
/** gemma4_text.py `@partial(mx.compile) def logit_softcap(softcap, x):
|
|
10
|
+
* return mx.tanh(x / softcap) * softcap`
|
|
11
|
+
* The oracle fuses divide+tanh+multiply into ONE kernel; our default
|
|
12
|
+
* `logitSoftcap` (logits.ts) runs them UNFUSED (standalone div + tanh + mul →
|
|
13
|
+
* a separate `vn_Tanh` + `vsn_Divide`). Keyed by cap so the softcap is baked
|
|
14
|
+
* as a graph constant (matching the oracle's weak-scalar → the
|
|
15
|
+
* `…Divide…Tanh…Multiply…_VC_` kernel). The two implementations are
|
|
16
|
+
* intentionally separate: this one reproduces the oracle's compiled kernel
|
|
17
|
+
* (Gemma4's final softcap, outside a compiled trace); `logitSoftcap` is the
|
|
18
|
+
* plain composition used elsewhere (Universal attention/final softcap, and
|
|
19
|
+
* inside a compiled trace). Neither may replace the other. */
|
|
20
|
+
const _softcapClosures = new Map<number, CompiledFunction>();
|
|
21
|
+
export function compiledLogitSoftcap(x: MlxArray, cap: number): MlxArray {
|
|
22
|
+
let fn = _softcapClosures.get(cap);
|
|
23
|
+
if (!fn) {
|
|
24
|
+
fn = new CompiledFunction((inputs) => {
|
|
25
|
+
const xx = inputs[0]!; // tanh(x / softcap) * softcap
|
|
26
|
+
const capArr = ops.scalarLike(cap, xx);
|
|
27
|
+
const scaled = ops.div(xx, capArr);
|
|
28
|
+
const t = ops.tanh(scaled); scaled.dispose();
|
|
29
|
+
const out = ops.mul(t, capArr); t.dispose(); capArr.dispose();
|
|
30
|
+
return [out];
|
|
31
|
+
});
|
|
32
|
+
_softcapClosures.set(cap, fn);
|
|
33
|
+
}
|
|
34
|
+
return fn.apply([x])[0]!;
|
|
35
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
|
|
3
|
+
/** The only definition of the 1MAD decode arithmetic; every kernel header includes it. */
|
|
4
|
+
export const HEADER = String.raw`
|
|
5
|
+
static inline float trellis_bf16(float v) {
|
|
6
|
+
uint u = as_type<uint>(v);
|
|
7
|
+
u = (u + 0x7FFFu + ((u >> 16) & 1u)) & 0xFFFF0000u;
|
|
8
|
+
return as_type<float>(u);
|
|
9
|
+
}
|
|
10
|
+
// QTIP 1MAD computed code for state s: x = s*34038481 + 76625530 (mod 2^32),
|
|
11
|
+
// y = sum of the four bytes of x - 510, value = y / 147.800537109375. Two
|
|
12
|
+
// byte-pair adds replace the four extracts; precise divide matches the host
|
|
13
|
+
// LUT (lut1mad below) bit for bit.
|
|
14
|
+
static inline int trellis_y(uint s) {
|
|
15
|
+
const uint x = s * 34038481u + 76625530u;
|
|
16
|
+
const uint p = (x & 0x00FF00FFu) + ((x >> 8) & 0x00FF00FFu);
|
|
17
|
+
return (int)((p & 0xFFFFu) + (p >> 16)) - 510;
|
|
18
|
+
}
|
|
19
|
+
static inline float trellis_val(uint s) {
|
|
20
|
+
return metal::precise::divide((float)trellis_y(s), 147.800537109375f);
|
|
21
|
+
}
|
|
22
|
+
// y × (1/d) refined by one residual step: q' = fma(fma(-q, d, y), 1/d, q).
|
|
23
|
+
// Correctly rounded for every y in [-510, 510] (checked host-side against
|
|
24
|
+
// the LUT), 3 FMA-class ops instead of a precise divide. Every expansion and
|
|
25
|
+
// prefill kernel that reproduces the host LUT decodes through this.
|
|
26
|
+
static inline float trellis_refined_y(int y) {
|
|
27
|
+
const float yf = (float)y;
|
|
28
|
+
const float r = 1.0f / 147.800537109375f;
|
|
29
|
+
const float q = yf * r;
|
|
30
|
+
const float e = metal::fma(-q, 147.800537109375f, yf);
|
|
31
|
+
return metal::fma(e, r, q);
|
|
32
|
+
}
|
|
33
|
+
static inline float trellis_val_rcp(uint s) { return trellis_refined_y(trellis_y(s)); }
|
|
34
|
+
// Unrefined y × (1/d) (≤1 ulp f32): the packed matvec/scatter weight is this
|
|
35
|
+
// f32 code value, a different numerical contract from the LUT-exact decode above.
|
|
36
|
+
static inline float trellis_unrefined_y(int y) {
|
|
37
|
+
return (float)y * (1.0f / 147.800537109375f);
|
|
38
|
+
}
|
|
39
|
+
// The code value y as f32 without an integer-to-float conversion: y + 510
|
|
40
|
+
// (0..1020) ORed into the mantissa of 2^23, whose ULP is one, minus 2^23 + 510.
|
|
41
|
+
// Equal to (float)trellis_y(s). Factored kernels accumulate y·x and apply
|
|
42
|
+
// scale·TRELLIS_RCP once per output (or fold it into each input row).
|
|
43
|
+
static inline float trellis_y_f32(uint s) {
|
|
44
|
+
return as_type<float>(0x4b000000u | uint(trellis_y(s) + 510)) - 8389118.0f;
|
|
45
|
+
}
|
|
46
|
+
#define TRELLIS_RCP (1.0f / 147.800537109375f)
|
|
47
|
+
// For y in [-510, 510], 2^23 has unit f32 spacing, so setting its low
|
|
48
|
+
// mantissa bits constructs 2^23+y+510 exactly. Subtracting 2^23+510
|
|
49
|
+
// recovers the same f32 y as the integer conversion; the reciprocal is unchanged.
|
|
50
|
+
static inline float trellis_unrefined_bits_y(int y) {
|
|
51
|
+
const float lifted = as_type<float>(0x4b000000u | uint(y + 510));
|
|
52
|
+
return (lifted - 8389118.0f) * (1.0f / 147.800537109375f);
|
|
53
|
+
}
|
|
54
|
+
// VARIANT: 0 = inline 1MAD + precise divide; 1 = inline 1MAD × reciprocal
|
|
55
|
+
// (1 ulp risk vs the host LUT); 2 = 4096-entry f32 LUT in threadgroup memory;
|
|
56
|
+
// 3 = the same LUT gathered from device memory.
|
|
57
|
+
// 4 = NO decode (timing floor only, wrong numerics); 5 = rcp decode, no bf16
|
|
58
|
+
// rounding; 6 = unrefined y×(1/d) (≤1 ulp f32), no bf16 rounding — the
|
|
59
|
+
// weight is f32 code×scale, more accurate than the artifact's stored bf16.
|
|
60
|
+
#define TRELLIS_DECODE(win, lutTG, lut) \
|
|
61
|
+
((VARIANT) == 0 ? trellis_val(win) : \
|
|
62
|
+
(VARIANT) == 1 || (VARIANT) == 5 ? trellis_val_rcp(win) : \
|
|
63
|
+
(VARIANT) == 6 ? trellis_unrefined_y(trellis_y(win)) : \
|
|
64
|
+
(VARIANT) == 2 ? lutTG[win] : \
|
|
65
|
+
(VARIANT) == 4 ? (float)(win) : lut[win])
|
|
66
|
+
#define TRELLIS_ROUND(v) ((VARIANT) >= 4 ? (v) : trellis_bf16(v))
|
|
67
|
+
// state_t of one packed block: L bits at offset (BT-1-t)*K, wrapping (32-bit ops).
|
|
68
|
+
static inline uint trellis_state(const device uint32_t* blk, uint wpb, uint t, uint bt, uint k, uint l) {
|
|
69
|
+
const uint p = (bt - 1u - t) * k;
|
|
70
|
+
const uint wi = p >> 5;
|
|
71
|
+
const uint off = p & 31u;
|
|
72
|
+
uint win = blk[wi] >> off;
|
|
73
|
+
if (off + l > 32u) win |= blk[(wi + 1u == wpb) ? 0u : (wi + 1u)] << (32u - off);
|
|
74
|
+
return win & ((1u << l) - 1u);
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
/** The one-row threadgroup-codebook kernels' table read (gate-up-codebook, down-codebook): the code value of the
|
|
79
|
+
* L-bit window at bit `off` of a lane's words w, read as the L + 2 bits [off - 2, off + L), the window's byte offset
|
|
80
|
+
* in a float table plus two low bits that the M1 Max (applegpu_g13s) threadgroup load ignores for a 4-byte element,
|
|
81
|
+
* so one bit-field extract serves each window; the kernels' bit-identity tests hold them to the reference bits. A
|
|
82
|
+
* field that crosses a word, or starts below bit 0, reads the virtual words v (v[i]: the high half of w[i - 1] and
|
|
83
|
+
* the low half of w[i], bits [32i - 16, 32i + 16)). `off` and `l` are compile-time constants at every call. */
|
|
84
|
+
export const CODEBOOK_WINDOW = String.raw`
|
|
85
|
+
static inline float trellis_codebook_window(const threadgroup uchar* table, thread const uint* w, thread const uint* v,
|
|
86
|
+
uint off, uint l) {
|
|
87
|
+
const int f = int(off) - 2;
|
|
88
|
+
const uint mask = (1u << (l + 2u)) - 1u;
|
|
89
|
+
uint bits;
|
|
90
|
+
if (f >= 0 && uint(f & 31) + l + 2u <= 32u) bits = (w[f >> 5] >> uint(f & 31)) & mask;
|
|
91
|
+
else { const uint vi = uint(f + 16) >> 5; bits = (v[vi] >> uint(f + 16 - 32 * int(vi))) & mask; }
|
|
92
|
+
return *(const threadgroup float*)(table + bits);
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
export function lut1mad(L: number): Float32Array {
|
|
97
|
+
const n = 1 << L;
|
|
98
|
+
const out = new Float32Array(n);
|
|
99
|
+
const M = (1n << 32n) - 1n;
|
|
100
|
+
for (let i = 0; i < n; i++) {
|
|
101
|
+
let x = BigInt(i) & M;
|
|
102
|
+
x = (x * 34038481n + 76625530n) & M;
|
|
103
|
+
const y =
|
|
104
|
+
Number((x & 255n) + ((x >> 8n) & 255n) + ((x >> 16n) & 255n) + ((x >> 24n) & 255n)) - 510;
|
|
105
|
+
out[i] = y / 147.800537109375;
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function wordsPerBlock(T: number, k: number): number {
|
|
111
|
+
if ((T * k) % 32 !== 0) throw new Error(`T·k = ${T * k} not a multiple of 32`);
|
|
112
|
+
return (T * k) / 32;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const luts = new Map<number, MlxArray>();
|
|
116
|
+
export function lutFor(L: number): MlxArray {
|
|
117
|
+
let a = luts.get(L);
|
|
118
|
+
if (!a) { a = MlxArray.fromFloat32(lut1mad(L), [1 << L]); a.eval(); luts.set(L, a); }
|
|
119
|
+
return a;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Variants 7..13 retain variant 6 decoded values.
|
|
123
|
+
export function decoderVariant(selected: number): number { return selected >= 7 && selected <= 13 ? 6 : selected; }
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
3
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
4
|
+
import type { TrellisGeometry } from "./geometry";
|
|
5
|
+
import { CODEBOOK_WINDOW, HEADER } from "./codebook";
|
|
6
|
+
import { TRELLIS_CODEBOOK_DOWN_THREADS } from "./launch";
|
|
7
|
+
|
|
8
|
+
// Axis-0 (down) projection of one activation row over T 256 Trellis codes,
|
|
9
|
+
// decoding through a threadgroup codebook (every code value y·(1/147.8) of the
|
|
10
|
+
// 2^L states, generated once per threadgroup). Each lane owns P = 16
|
|
11
|
+
// consecutive positions of one block: it loads the words they span (plus the
|
|
12
|
+
// next lane's first word for the last windows) for U input rows ahead, aligns
|
|
13
|
+
// them to its first bit once per row where P·K is not a multiple of 32 (the
|
|
14
|
+
// 3-bit codes, whose odd lanes start at bit 16), then reads every window with
|
|
15
|
+
// one bit-field extract at a compile-time shift (CODEBOOK_WINDOW, codebook.ts).
|
|
16
|
+
// No lane exchanges data, so lanes past the last block return at once.
|
|
17
|
+
// Split-K over input rows into SPLITS f32 partials, summed as MLX sums them
|
|
18
|
+
// (a threadgroup adds the four splits of the first stage, FOLD the rest) and
|
|
19
|
+
// cast to the activation dtype. Every position accumulates the same f32 code·scale weights over the same
|
|
20
|
+
// rows in the same order as trellisScatter's single-row kernels at variant 13
|
|
21
|
+
// (the balanced one for the 3-bit block interleave), so the output is theirs
|
|
22
|
+
// bit for bit.
|
|
23
|
+
const SPLITS = 128, P = 16, U = 2;
|
|
24
|
+
|
|
25
|
+
const SOURCE = String.raw`
|
|
26
|
+
threadgroup float codebook[4096]; // 2^L codes, then the eight SIMD groups' partials
|
|
27
|
+
for (uint i = thread_position_in_threadgroup.x; i < (1u << (uint)L); i += (uint)THREADS)
|
|
28
|
+
codebook[i] = trellis_unrefined_bits_y(trellis_y(i));
|
|
29
|
+
threadgroup_barrier(metal::mem_flags::mem_threadgroup);
|
|
30
|
+
constexpr uint BITS = (uint)(P * K); // a lane's bits
|
|
31
|
+
constexpr uint SHIFT = BITS % 32u; // 0, or 16: odd lanes start at bit 16 of a word
|
|
32
|
+
constexpr bool ALIGNED = SHIFT == 0u;
|
|
33
|
+
constexpr uint NA = (BITS + (uint)L - (uint)K + 31u) / 32u; // words its windows span from its first bit
|
|
34
|
+
constexpr uint NL = ALIGNED ? NA : NA + 1u; // words it loads
|
|
35
|
+
constexpr uint LB = 256u / (uint)P; // lanes per block
|
|
36
|
+
constexpr uint WPB = 8u * (uint)K; // words per block
|
|
37
|
+
constexpr uint NB = (uint)(C / 256); // blocks
|
|
38
|
+
constexpr uint SGS = (NB + 32u / LB - 1u) / (32u / LB); // SIMD groups per split
|
|
39
|
+
constexpr ulong ROWW = INTERLEAVE ? 2ul * WPB : (ulong)NB * WPB;
|
|
40
|
+
constexpr uint ROWS_PER = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
|
|
41
|
+
constexpr uint SG_COLS = 32u * (uint)P; // a SIMD group's columns
|
|
42
|
+
// Threadgroup t: row group y = t % 32 and SIMD groups (k, c) = (s % 4, s / 4) take split y + 32k of column group
|
|
43
|
+
// 2·(t / 32) + c, so the threadgroup holds the four splits MLX's column sum adds first for 2·SG_COLS columns.
|
|
44
|
+
const uint lane = thread_index_in_simdgroup;
|
|
45
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
46
|
+
const uint ty = threadgroup_position_in_grid.y;
|
|
47
|
+
const uint y = ty % 32u;
|
|
48
|
+
const uint split = y + 32u * (sg % 4u);
|
|
49
|
+
const uint colGroup = 2u * (ty / 32u) + sg / 4u;
|
|
50
|
+
const uint li = lane % LB;
|
|
51
|
+
const uint blk = colGroup * (32u / LB) + lane / LB;
|
|
52
|
+
const bool active = colGroup < SGS && blk < NB;
|
|
53
|
+
const device uint32_t* blockWords = codes + (!active ? 0ul : INTERLEAVE
|
|
54
|
+
? (ulong)(blk / 2u) * (ulong)R * 2ul * WPB + (blk % 2u) * WPB : (ulong)blk * WPB);
|
|
55
|
+
const uint first = (li * BITS) >> 5;
|
|
56
|
+
const bool shifted = !ALIGNED && (li & 1u);
|
|
57
|
+
uint idx[NL];
|
|
58
|
+
#pragma clang loop unroll(full)
|
|
59
|
+
for (uint i = 0; i < NL; ++i) idx[i] = (first + i) % WPB;
|
|
60
|
+
const uint r0 = split * ROWS_PER;
|
|
61
|
+
const uint rows = !active ? 0u : (uint)R % (uint)SPLITS == 0u ? ROWS_PER : r0 >= (uint)R ? 0u : metal::min(ROWS_PER, (uint)R - r0);
|
|
62
|
+
const threadgroup uchar* table = (const threadgroup uchar*)codebook;
|
|
63
|
+
float acc[P];
|
|
64
|
+
#pragma clang loop unroll(full)
|
|
65
|
+
for (uint i = 0; i < (uint)P; ++i) acc[i] = 0.0f;
|
|
66
|
+
uint r = 0;
|
|
67
|
+
for (; r + (uint)U <= rows; r += (uint)U) {
|
|
68
|
+
uint ld[U][NL];
|
|
69
|
+
float xr[U], sr[U];
|
|
70
|
+
#pragma clang loop unroll(full)
|
|
71
|
+
for (uint u = 0; u < (uint)U; ++u) {
|
|
72
|
+
const device uint32_t* rowWords = blockWords + (ulong)(r0 + r + u) * ROWW;
|
|
73
|
+
#pragma clang loop unroll(full)
|
|
74
|
+
for (uint i = 0; i < NL; ++i) ld[u][i] = rowWords[idx[i]];
|
|
75
|
+
xr[u] = float(x[r0 + r + u]);
|
|
76
|
+
sr[u] = float(scales[r0 + r + u]);
|
|
77
|
+
}
|
|
78
|
+
#pragma clang loop unroll(full)
|
|
79
|
+
for (uint u = 0; u < (uint)U; ++u) {
|
|
80
|
+
uint w[NA], v[NA];
|
|
81
|
+
#pragma clang loop unroll(full)
|
|
82
|
+
for (uint i = 0; i < NA; ++i) w[i] = shifted ? (ld[u][i] >> SHIFT) | (ld[u][i + 1] << (32u - SHIFT)) : ld[u][i];
|
|
83
|
+
v[0] = w[0] << 16;
|
|
84
|
+
#pragma clang loop unroll(full)
|
|
85
|
+
for (uint i = 1; i < NA; ++i) v[i] = (w[i - 1] >> 16) | (w[i] << 16);
|
|
86
|
+
#pragma clang loop unroll(full)
|
|
87
|
+
for (uint i = 0; i < (uint)P; ++i) {
|
|
88
|
+
const float code = trellis_codebook_window(table, w, v, i * (uint)K, (uint)L);
|
|
89
|
+
acc[i] = metal::fma(code * sr[u], xr[u], acc[i]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (; r < rows; ++r) {
|
|
94
|
+
const device uint32_t* rowWords = blockWords + (ulong)(r0 + r) * ROWW;
|
|
95
|
+
uint ld[NL];
|
|
96
|
+
#pragma clang loop unroll(full)
|
|
97
|
+
for (uint i = 0; i < NL; ++i) ld[i] = rowWords[idx[i]];
|
|
98
|
+
const float xr = float(x[r0 + r]);
|
|
99
|
+
const float sr = float(scales[r0 + r]);
|
|
100
|
+
uint w[NA], v[NA];
|
|
101
|
+
#pragma clang loop unroll(full)
|
|
102
|
+
for (uint i = 0; i < NA; ++i) w[i] = shifted ? (ld[i] >> SHIFT) | (ld[i + 1] << (32u - SHIFT)) : ld[i];
|
|
103
|
+
v[0] = w[0] << 16;
|
|
104
|
+
#pragma clang loop unroll(full)
|
|
105
|
+
for (uint i = 1; i < NA; ++i) v[i] = (w[i - 1] >> 16) | (w[i] << 16);
|
|
106
|
+
#pragma clang loop unroll(full)
|
|
107
|
+
for (uint i = 0; i < (uint)P; ++i) {
|
|
108
|
+
const float code = trellis_codebook_window(table, w, v, i * (uint)K, (uint)L);
|
|
109
|
+
acc[i] = metal::fma(code * sr, xr, acc[i]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// The four splits' partials meet in the codebook's memory; each column's first sum stage, ((0 + p[y]) + p[y + 32])
|
|
113
|
+
// + ..., in MLX's order, goes out as row y of the 32 the fold sums.
|
|
114
|
+
threadgroup_barrier(metal::mem_flags::mem_threadgroup);
|
|
115
|
+
threadgroup float* sums = codebook;
|
|
116
|
+
const uint local = (lane / LB) * 256u + 255u - li * (uint)P;
|
|
117
|
+
#pragma clang loop unroll(full)
|
|
118
|
+
for (uint i = 0; i < (uint)P; ++i) sums[sg * SG_COLS + local - i] = acc[i];
|
|
119
|
+
threadgroup_barrier(metal::mem_flags::mem_threadgroup);
|
|
120
|
+
for (uint c = thread_position_in_threadgroup.x; c < 2u * SG_COLS; c += (uint)THREADS) {
|
|
121
|
+
const uint group2 = c / SG_COLS, col = (2u * (ty / 32u) + group2) * SG_COLS + c % SG_COLS;
|
|
122
|
+
if (col >= (uint)C) continue;
|
|
123
|
+
float t = 0.0f;
|
|
124
|
+
#pragma clang loop unroll(full)
|
|
125
|
+
for (uint k = 0; k < 4u; ++k) t = sums[(group2 * 4u + k) * SG_COLS + c % SG_COLS] + t;
|
|
126
|
+
partial[(ulong)y * (ulong)C + col] = t;
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
// The second stage of MLX's column sum over the SPLITS partials (col_reduce_looped, 32x32 tiles, the reduction it runs
|
|
131
|
+
// at this shape) and the cast to T, bit for bit: SIMD group s of a threadgroup's 32 columns sums each of its four
|
|
132
|
+
// columns over the 32 first-stage rows (lane y holds row y) with simd_sum.
|
|
133
|
+
const FOLD = String.raw`
|
|
134
|
+
const uint lane = thread_index_in_simdgroup;
|
|
135
|
+
const uint col = threadgroup_position_in_grid.x * 32u + simdgroup_index_in_threadgroup * 4u;
|
|
136
|
+
const float4 t = *(const device float4*)(partial + (ulong)lane * (ulong)C + col);
|
|
137
|
+
#pragma clang loop unroll(full)
|
|
138
|
+
for (uint i = 0; i < 4u; ++i) {
|
|
139
|
+
const float v = metal::simd_sum(t[i]);
|
|
140
|
+
if (lane == 0u) out[col + i] = T(v);
|
|
141
|
+
}
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
let kernel: MetalKernel | undefined;
|
|
145
|
+
let fold: MetalKernel | undefined;
|
|
146
|
+
|
|
147
|
+
function launch(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, interleave: boolean): MlxArray {
|
|
148
|
+
const groupsPerSplit = Math.ceil((g.cols / 256) / (P / 8));
|
|
149
|
+
if (x2.shape[0] !== 1) throw new Error("downCodebookRow: expects one activation row");
|
|
150
|
+
if (g.axis !== 0 || g.T !== 256 || g.L > 12 || g.cols % 256) throw new Error("downCodebookRow: needs axis-0 codes at T 256, L <= 12");
|
|
151
|
+
kernel ??= new MetalKernel({ name: "mlx_bun_trellis_down_codebook_row", inputNames: ["x", "codes", "scales"],
|
|
152
|
+
outputNames: ["partial"], source: SOURCE, header: HEADER + CODEBOOK_WINDOW, ensureRowContiguous: true });
|
|
153
|
+
fold ??= new MetalKernel({ name: "mlx_bun_trellis_down_codebook_fold", inputNames: ["partial"], outputNames: ["out"],
|
|
154
|
+
source: FOLD, ensureRowContiguous: true });
|
|
155
|
+
// 32 row groups, each threadgroup two SIMD groups' columns of four splits.
|
|
156
|
+
const [partial] = kernel.apply([x2, codes, scales], {
|
|
157
|
+
outputs: [{ shape: [1, 32, g.cols], dtype: Dtype.float32 }],
|
|
158
|
+
grid: [TRELLIS_CODEBOOK_DOWN_THREADS, 32 * Math.ceil(groupsPerSplit / 2), 1],
|
|
159
|
+
threadGroup: [TRELLIS_CODEBOOK_DOWN_THREADS, 1, 1],
|
|
160
|
+
templateDtypes: { T: x2.dtype },
|
|
161
|
+
templateInts: { R: g.rows, C: g.cols, K: g.k, L: g.L, P, U, SPLITS, THREADS: TRELLIS_CODEBOOK_DOWN_THREADS,
|
|
162
|
+
INTERLEAVE: Number(interleave) },
|
|
163
|
+
});
|
|
164
|
+
const [out] = fold.apply([partial!], {
|
|
165
|
+
outputs: [{ shape: [1, g.cols], dtype: x2.dtype }],
|
|
166
|
+
grid: [8 * 32 * g.cols / 32, 1, 1], threadGroup: [8 * 32, 1, 1],
|
|
167
|
+
templateDtypes: { T: x2.dtype }, templateInts: { C: g.cols },
|
|
168
|
+
});
|
|
169
|
+
partial!.dispose();
|
|
170
|
+
return out!;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** x2 [1, inFeatures] · W → [1, outFeatures] in x2's dtype over row-major 2- or
|
|
174
|
+
* 4-bit codes [rows, cols·K/32]. Borrows inputs. */
|
|
175
|
+
export function downCodebookRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
176
|
+
if (g.blockInterleave || codes.ndim !== 2 || (g.k !== 2 && g.k !== 4)) throw new Error("downCodebookRow: needs row-major 2- or 4-bit codes");
|
|
177
|
+
return launch(x2, codes, scales, g, false);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** The same over 3-bit block-interleaved codes [cols/512, rows, 48]. */
|
|
181
|
+
export function downK3InterleavedCodebookRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
182
|
+
if (g.blockInterleave !== 2 || g.k !== 3) throw new Error("downK3InterleavedCodebookRow: needs 3-bit block-interleaved codes");
|
|
183
|
+
return launch(x2, codes, scales, g, true);
|
|
184
|
+
}
|