@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,180 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
5
|
+
import type { TrellisGeometry } from "./geometry";
|
|
6
|
+
import { HEADER, wordsPerBlock } from "./codebook";
|
|
7
|
+
import { TRELLIS_THREADS, TRELLIS_SG_PER_TG } from "./launch";
|
|
8
|
+
|
|
9
|
+
// Axis-0 (down) projections over row-major Trellis codes [rows, cols·K/32]
|
|
10
|
+
// with the input scale factored out: each input row's activation is
|
|
11
|
+
// pre-multiplied by scale·(1/147.8) and weights contribute their code value y
|
|
12
|
+
// (trellis_y_f32). Lane-per-word of a block with running sums per position,
|
|
13
|
+
// split-K over input rows into SPLITS f32 partials that one MLX sum folds.
|
|
14
|
+
// Same traversal as trellisScatter; reassociated relative to its f32
|
|
15
|
+
// code·scale weights (not bit-identical; gate by KL).
|
|
16
|
+
const SPLITS = 128;
|
|
17
|
+
|
|
18
|
+
// One activation row.
|
|
19
|
+
const ROW_SOURCE = String.raw`
|
|
20
|
+
const uint lane = thread_index_in_simdgroup;
|
|
21
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
22
|
+
const uint wpb = (uint)(BT * K / 32);
|
|
23
|
+
const uint nb = 32u / wpb; // blocks per SIMD group
|
|
24
|
+
const uint nBlocks = (uint)C / (uint)BT;
|
|
25
|
+
const uint groups = (nBlocks + nb - 1u) / nb;
|
|
26
|
+
const uint group = thread_position_in_grid.y * (uint)SG_TG + sg;
|
|
27
|
+
const uint split = thread_position_in_grid.z;
|
|
28
|
+
const uint bi = lane / wpb;
|
|
29
|
+
const uint wi = lane - bi * wpb;
|
|
30
|
+
const uint blk = group * nb + bi;
|
|
31
|
+
const bool active = (group < groups) && (bi < nb) && (blk < nBlocks);
|
|
32
|
+
const uint nbrLane = bi * wpb + ((wi + 1u == wpb) ? 0u : wi + 1u);
|
|
33
|
+
// This lane's positions: symbol offsets p = multiples of K inside [32wi, 32wi+32).
|
|
34
|
+
const uint pBase = 32u * wi;
|
|
35
|
+
const uint p0 = ((pBase + (uint)K - 1u) / (uint)K) * (uint)K;
|
|
36
|
+
uint offs[NP];
|
|
37
|
+
bool valid[NP];
|
|
38
|
+
bool spill[NP];
|
|
39
|
+
uint cols[NP];
|
|
40
|
+
#pragma clang loop unroll(full)
|
|
41
|
+
for (uint i = 0; i < (uint)NP; ++i) {
|
|
42
|
+
const uint p = p0 + i * (uint)K;
|
|
43
|
+
valid[i] = active && (p < pBase + 32u);
|
|
44
|
+
offs[i] = p - pBase;
|
|
45
|
+
spill[i] = offs[i] + (uint)L > 32u;
|
|
46
|
+
const uint t = (uint)BT - 1u - p / (uint)K;
|
|
47
|
+
cols[i] = blk * (uint)BT + t;
|
|
48
|
+
}
|
|
49
|
+
const ulong rowWords = (ulong)nBlocks * wpb;
|
|
50
|
+
const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
|
|
51
|
+
const uint r0 = split * rowsPer;
|
|
52
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
53
|
+
const device uint32_t* col0 = codes + (ulong)blk * wpb + wi;
|
|
54
|
+
const uint mask = (1u << (uint)L) - 1u;
|
|
55
|
+
float acc[NP];
|
|
56
|
+
#pragma clang loop unroll(full)
|
|
57
|
+
for (uint i = 0; i < (uint)NP; ++i) acc[i] = 0.0f;
|
|
58
|
+
for (uint r = r0; r < r1; ++r) {
|
|
59
|
+
const uint word = active ? col0[(ulong)r * rowWords] : 0u;
|
|
60
|
+
const uint nxt = metal::simd_shuffle(word, (ushort)nbrLane);
|
|
61
|
+
const float xr = float(x[r]);
|
|
62
|
+
const float sr = float(scales[r]);
|
|
63
|
+
#pragma clang loop unroll(full)
|
|
64
|
+
for (uint i = 0; i < (uint)NP; ++i) {
|
|
65
|
+
uint win = word >> offs[i];
|
|
66
|
+
if (spill[i]) win |= nxt << (32u - offs[i]);
|
|
67
|
+
win &= mask;
|
|
68
|
+
acc[i] = metal::fma(trellis_y_f32(win), xr * (sr * TRELLIS_RCP), acc[i]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const ulong outBase = (ulong)split * (ulong)C;
|
|
72
|
+
#pragma clang loop unroll(full)
|
|
73
|
+
for (uint i = 0; i < (uint)NP; ++i)
|
|
74
|
+
if (valid[i]) partial[outBase + cols[i]] = acc[i];
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
// M activation rows sharing each decoded weight.
|
|
78
|
+
const ROWS_SOURCE = String.raw`
|
|
79
|
+
const uint lane = thread_index_in_simdgroup;
|
|
80
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
81
|
+
const uint wpb = (uint)(BT * K / 32);
|
|
82
|
+
const uint nb = 32u / wpb; // blocks per SIMD group
|
|
83
|
+
const uint nBlocks = (uint)C / (uint)BT;
|
|
84
|
+
const uint groups = (nBlocks + nb - 1u) / nb;
|
|
85
|
+
const uint group = thread_position_in_grid.y * (uint)SG_TG + sg;
|
|
86
|
+
const uint split = thread_position_in_grid.z;
|
|
87
|
+
const uint bi = lane / wpb;
|
|
88
|
+
const uint wi = lane - bi * wpb;
|
|
89
|
+
const uint blk = group * nb + bi;
|
|
90
|
+
const bool active = (group < groups) && (bi < nb) && (blk < nBlocks);
|
|
91
|
+
const uint nbrLane = bi * wpb + ((wi + 1u == wpb) ? 0u : wi + 1u);
|
|
92
|
+
const uint pBase = 32u * wi;
|
|
93
|
+
const uint p0 = ((pBase + (uint)K - 1u) / (uint)K) * (uint)K;
|
|
94
|
+
uint offs[NP];
|
|
95
|
+
bool valid[NP];
|
|
96
|
+
bool spill[NP];
|
|
97
|
+
uint cols[NP];
|
|
98
|
+
#pragma clang loop unroll(full)
|
|
99
|
+
for (uint i = 0; i < (uint)NP; ++i) {
|
|
100
|
+
const uint p = p0 + i * (uint)K;
|
|
101
|
+
valid[i] = active && (p < pBase + 32u);
|
|
102
|
+
offs[i] = p - pBase;
|
|
103
|
+
spill[i] = offs[i] + (uint)L > 32u;
|
|
104
|
+
const uint t = (uint)BT - 1u - p / (uint)K;
|
|
105
|
+
cols[i] = blk * (uint)BT + t;
|
|
106
|
+
}
|
|
107
|
+
const ulong rowWords = (ulong)nBlocks * wpb;
|
|
108
|
+
const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
|
|
109
|
+
const uint r0 = split * rowsPer;
|
|
110
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
111
|
+
const device uint32_t* col0 = codes + (ulong)blk * wpb + wi;
|
|
112
|
+
const uint mask = (1u << (uint)L) - 1u;
|
|
113
|
+
float acc[M][NP];
|
|
114
|
+
#pragma clang loop unroll(full)
|
|
115
|
+
for (uint m = 0; m < (uint)M; ++m)
|
|
116
|
+
#pragma clang loop unroll(full)
|
|
117
|
+
for (uint i = 0; i < (uint)NP; ++i) acc[m][i] = 0.0f;
|
|
118
|
+
for (uint r = r0; r < r1; ++r) {
|
|
119
|
+
const uint word = active ? col0[(ulong)r * rowWords] : 0u;
|
|
120
|
+
const uint nxt = metal::simd_shuffle(word, (ushort)nbrLane);
|
|
121
|
+
float xr[M];
|
|
122
|
+
#pragma clang loop unroll(full)
|
|
123
|
+
for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]) * (float(scales[r]) * TRELLIS_RCP);
|
|
124
|
+
#pragma clang loop unroll(full)
|
|
125
|
+
for (uint i = 0; i < (uint)NP; ++i) {
|
|
126
|
+
uint win = word >> offs[i];
|
|
127
|
+
if (spill[i]) win |= nxt << (32u - offs[i]);
|
|
128
|
+
win &= mask;
|
|
129
|
+
const float weight = trellis_y_f32(win);
|
|
130
|
+
#pragma clang loop unroll(full)
|
|
131
|
+
for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
#pragma clang loop unroll(full)
|
|
135
|
+
for (uint m = 0; m < (uint)M; ++m) {
|
|
136
|
+
const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
|
|
137
|
+
#pragma clang loop unroll(full)
|
|
138
|
+
for (uint i = 0; i < (uint)NP; ++i)
|
|
139
|
+
if (valid[i]) partial[outBase + cols[i]] = acc[m][i];
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
let rowKernel: MetalKernel | undefined, rowsKernel: MetalKernel | undefined;
|
|
144
|
+
|
|
145
|
+
function launch(kernel: MetalKernel, x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, M: number): MlxArray {
|
|
146
|
+
if (g.axis !== 0 || g.blockInterleave || codes.ndim !== 2) throw new Error("downFactored: needs row-major axis-0 codes");
|
|
147
|
+
const wpb = wordsPerBlock(g.T, g.k), nb = Math.floor(32 / wpb);
|
|
148
|
+
if (nb < 1) throw new Error(`downFactored: block of ${wpb} words exceeds one SIMD group`);
|
|
149
|
+
const groups = Math.ceil((g.cols / g.T) / nb);
|
|
150
|
+
const [partial] = kernel.apply([x2, codes, scales], {
|
|
151
|
+
outputs: [{ shape: [M, SPLITS, g.cols], dtype: Dtype.float32 }],
|
|
152
|
+
grid: [TRELLIS_THREADS, Math.ceil(groups / TRELLIS_SG_PER_TG), SPLITS],
|
|
153
|
+
threadGroup: [TRELLIS_THREADS, 1, 1],
|
|
154
|
+
templateDtypes: { T: x2.dtype },
|
|
155
|
+
templateInts: { M, R: g.rows, C: g.cols, BT: g.T, K: g.k, L: g.L, SG_TG: TRELLIS_SG_PER_TG, SPLITS, NP: Math.ceil(32 / g.k) },
|
|
156
|
+
});
|
|
157
|
+
const sum = ops.sumAxis(partial!, 1, false);
|
|
158
|
+
partial!.dispose();
|
|
159
|
+
const out = sum.astype(x2.dtype);
|
|
160
|
+
sum.dispose();
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** x2 [1, inFeatures] · W → [1, outFeatures] in x2's dtype. Borrows inputs. */
|
|
165
|
+
export function downFactoredRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
166
|
+
if (x2.shape[0] !== 1) throw new Error("downFactoredRow: expects one activation row");
|
|
167
|
+
rowKernel ??= new MetalKernel({ name: "mlx_bun_trellis_down_factored_row", inputNames: ["x", "codes", "scales"],
|
|
168
|
+
outputNames: ["partial"], source: ROW_SOURCE, header: HEADER, ensureRowContiguous: true });
|
|
169
|
+
return launch(rowKernel, x2, codes, scales, g, 1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** x2 [M, inFeatures] · W → [M, outFeatures] for 2..4 rows sharing each
|
|
173
|
+
* decoded weight. Borrows inputs. */
|
|
174
|
+
export function downFactoredRows(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
175
|
+
const M = x2.shape[0]!;
|
|
176
|
+
if (M < 2 || M > 4) throw new Error(`downFactoredRows: M=${M} outside 2..4`);
|
|
177
|
+
rowsKernel ??= new MetalKernel({ name: "mlx_bun_trellis_down_factored_rows", inputNames: ["x", "codes", "scales"],
|
|
178
|
+
outputNames: ["partial"], source: ROWS_SOURCE, header: HEADER, ensureRowContiguous: true });
|
|
179
|
+
return launch(rowsKernel, x2, codes, scales, g, M);
|
|
180
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
5
|
+
import type { TrellisGeometry } from "./geometry";
|
|
6
|
+
import { HEADER } from "./codebook";
|
|
7
|
+
import { TRELLIS_THREADS, TRELLIS_SG_PER_TG } from "./launch";
|
|
8
|
+
|
|
9
|
+
// Axis-0 (down) projections over 3-bit Trellis codes in the block-interleaved
|
|
10
|
+
// layout [cols/512, rows, 48] (T 256, L 12): every lane owns 8 consecutive
|
|
11
|
+
// positions (24 bits) of one block, so all 32 lanes are busy. The input scale
|
|
12
|
+
// is factored out: each input row's activation is pre-multiplied by
|
|
13
|
+
// scale·(1/147.8) and weights contribute their code value y. Split-K over
|
|
14
|
+
// input rows into SPLITS f32 partials folded by one MLX sum. Same traversal as
|
|
15
|
+
// the balanced trellisScatter; reassociated relative to its f32 code·scale
|
|
16
|
+
// weights (not bit-identical; gate by KL).
|
|
17
|
+
const SPLITS = 128, K = 3, BT = 256, L = 12, WPB = BT * K / 32;
|
|
18
|
+
|
|
19
|
+
// One activation row.
|
|
20
|
+
const ROW_SOURCE = String.raw`
|
|
21
|
+
const uint lane = thread_index_in_simdgroup;
|
|
22
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
23
|
+
const uint block = thread_position_in_grid.y * (uint)SG_TG + sg;
|
|
24
|
+
const uint nBlocks = (uint)C / ${BT}u;
|
|
25
|
+
const uint split = thread_position_in_grid.z;
|
|
26
|
+
if (block >= nBlocks) return;
|
|
27
|
+
const ulong rowWords = 2ul * ${WPB}u;
|
|
28
|
+
const uint pBase = lane * 8u * ${K}u;
|
|
29
|
+
const uint wi = pBase >> 5u;
|
|
30
|
+
const uint off = pBase & 31u;
|
|
31
|
+
const uint next = (wi + 1u == ${WPB}u) ? 0u : wi + 1u;
|
|
32
|
+
const device uint32_t* words = codes + (ulong)(block / 2) * R * 2 * ${WPB}u + (block % 2) * ${WPB}u;
|
|
33
|
+
const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
|
|
34
|
+
const uint r0 = split * rowsPer;
|
|
35
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
36
|
+
float acc[8];
|
|
37
|
+
#pragma clang loop unroll(full)
|
|
38
|
+
for (uint i = 0; i < 8u; ++i) acc[i] = 0.0f;
|
|
39
|
+
for (uint r = r0; r < r1; ++r) {
|
|
40
|
+
const uint word = words[(ulong)r * rowWords + wi];
|
|
41
|
+
const uint nxt = words[(ulong)r * rowWords + next];
|
|
42
|
+
const uint lo = off == 0u ? word : (word >> off) | (nxt << (32u - off));
|
|
43
|
+
const uint hi = off == 0u ? nxt : nxt >> off;
|
|
44
|
+
const float xr = float(x[r]);
|
|
45
|
+
const float sr = float(scales[r]);
|
|
46
|
+
#pragma clang loop unroll(full)
|
|
47
|
+
for (uint i = 0; i < 8u; ++i) {
|
|
48
|
+
const uint shift = i * ${K}u;
|
|
49
|
+
uint win = lo >> shift;
|
|
50
|
+
if (shift + ${L}u > 32u) win |= hi << (32u - shift);
|
|
51
|
+
win &= (1u << ${L}u) - 1u;
|
|
52
|
+
acc[i] = metal::fma(trellis_y_f32(win), xr * (sr * TRELLIS_RCP), acc[i]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const ulong outBase = (ulong)split * (ulong)C;
|
|
56
|
+
#pragma clang loop unroll(full)
|
|
57
|
+
for (uint i = 0; i < 8u; ++i)
|
|
58
|
+
partial[outBase + block * ${BT}u + ${BT - 1}u - lane * 8u - i] = acc[i];
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
// M activation rows sharing each decoded weight.
|
|
62
|
+
const ROWS_SOURCE = String.raw`
|
|
63
|
+
const uint lane = thread_index_in_simdgroup;
|
|
64
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
65
|
+
const uint block = thread_position_in_grid.y * (uint)SG_TG + sg;
|
|
66
|
+
const uint nBlocks = (uint)C / ${BT}u;
|
|
67
|
+
const uint split = thread_position_in_grid.z;
|
|
68
|
+
if (block >= nBlocks) return;
|
|
69
|
+
const ulong rowWords = 2ul * ${WPB}u;
|
|
70
|
+
const uint pBase = lane * 8u * ${K}u;
|
|
71
|
+
const uint wi = pBase >> 5u;
|
|
72
|
+
const uint off = pBase & 31u;
|
|
73
|
+
const uint next = (wi + 1u == ${WPB}u) ? 0u : wi + 1u;
|
|
74
|
+
const device uint32_t* words = codes + (ulong)(block / 2) * R * 2 * ${WPB}u + (block % 2) * ${WPB}u;
|
|
75
|
+
const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
|
|
76
|
+
const uint r0 = split * rowsPer;
|
|
77
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
78
|
+
float acc[M][8];
|
|
79
|
+
#pragma clang loop unroll(full)
|
|
80
|
+
for (uint m = 0; m < (uint)M; ++m)
|
|
81
|
+
#pragma clang loop unroll(full)
|
|
82
|
+
for (uint i = 0; i < 8u; ++i) acc[m][i] = 0.0f;
|
|
83
|
+
for (uint r = r0; r < r1; ++r) {
|
|
84
|
+
const uint word = words[(ulong)r * rowWords + wi];
|
|
85
|
+
const uint nxt = words[(ulong)r * rowWords + next];
|
|
86
|
+
const uint lo = off == 0u ? word : (word >> off) | (nxt << (32u - off));
|
|
87
|
+
const uint hi = off == 0u ? nxt : nxt >> off;
|
|
88
|
+
float xr[M];
|
|
89
|
+
#pragma clang loop unroll(full)
|
|
90
|
+
for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]) * (float(scales[r]) * TRELLIS_RCP);
|
|
91
|
+
#pragma clang loop unroll(full)
|
|
92
|
+
for (uint i = 0; i < 8u; ++i) {
|
|
93
|
+
const uint shift = i * ${K}u;
|
|
94
|
+
uint win = lo >> shift;
|
|
95
|
+
if (shift + ${L}u > 32u) win |= hi << (32u - shift);
|
|
96
|
+
win &= (1u << ${L}u) - 1u;
|
|
97
|
+
const float weight = trellis_y_f32(win);
|
|
98
|
+
#pragma clang loop unroll(full)
|
|
99
|
+
for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
#pragma clang loop unroll(full)
|
|
103
|
+
for (uint m = 0; m < (uint)M; ++m) {
|
|
104
|
+
const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
|
|
105
|
+
#pragma clang loop unroll(full)
|
|
106
|
+
for (uint i = 0; i < 8u; ++i)
|
|
107
|
+
partial[outBase + block * ${BT}u + ${BT - 1}u - lane * 8u - i] = acc[m][i];
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
let rowKernel: MetalKernel | undefined, rowsKernel: MetalKernel | undefined;
|
|
112
|
+
|
|
113
|
+
function launch(kernel: MetalKernel, x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, M: number): MlxArray {
|
|
114
|
+
if (g.axis !== 0 || g.blockInterleave !== 2 || g.k !== K || g.T !== BT || g.L !== L)
|
|
115
|
+
throw new Error("downK3InterleavedFactored: needs 3-bit block-interleaved axis-0 codes (T 256, L 12)");
|
|
116
|
+
const [partial] = kernel.apply([x2, codes, scales], {
|
|
117
|
+
outputs: [{ shape: [M, SPLITS, g.cols], dtype: Dtype.float32 }],
|
|
118
|
+
grid: [TRELLIS_THREADS, Math.ceil(g.cols / BT / TRELLIS_SG_PER_TG), SPLITS],
|
|
119
|
+
threadGroup: [TRELLIS_THREADS, 1, 1],
|
|
120
|
+
templateDtypes: { T: x2.dtype },
|
|
121
|
+
templateInts: { M, R: g.rows, C: g.cols, SG_TG: TRELLIS_SG_PER_TG, SPLITS },
|
|
122
|
+
});
|
|
123
|
+
const sum = ops.sumAxis(partial!, 1, false);
|
|
124
|
+
partial!.dispose();
|
|
125
|
+
const out = sum.astype(x2.dtype);
|
|
126
|
+
sum.dispose();
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** x2 [1, inFeatures] · W → [1, outFeatures] in x2's dtype. Borrows inputs. */
|
|
131
|
+
export function downK3InterleavedFactoredRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
132
|
+
if (x2.shape[0] !== 1) throw new Error("downK3InterleavedFactoredRow: expects one activation row");
|
|
133
|
+
rowKernel ??= new MetalKernel({ name: "mlx_bun_trellis_down_k3i_factored_row", inputNames: ["x", "codes", "scales"],
|
|
134
|
+
outputNames: ["partial"], source: ROW_SOURCE, header: HEADER, ensureRowContiguous: true });
|
|
135
|
+
return launch(rowKernel, x2, codes, scales, g, 1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** x2 [M, inFeatures] · W → [M, outFeatures] for 2..4 rows sharing each
|
|
139
|
+
* decoded weight. Borrows inputs. */
|
|
140
|
+
export function downK3InterleavedFactoredRows(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
141
|
+
const M = x2.shape[0]!;
|
|
142
|
+
if (M < 2 || M > 4) throw new Error(`downK3InterleavedFactoredRows: M=${M} outside 2..4`);
|
|
143
|
+
rowsKernel ??= new MetalKernel({ name: "mlx_bun_trellis_down_k3i_factored_rows", inputNames: ["x", "codes", "scales"],
|
|
144
|
+
outputNames: ["partial"], source: ROWS_SOURCE, header: HEADER, ensureRowContiguous: true });
|
|
145
|
+
return launch(rowsKernel, x2, codes, scales, g, M);
|
|
146
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
5
|
+
import { HEADER } from "./codebook";
|
|
6
|
+
import type { TrellisGeometry } from "./geometry";
|
|
7
|
+
|
|
8
|
+
// Down projection on the simdgroup matrix unit for any number of activation
|
|
9
|
+
// rows: down-mma's splits and accumulation (each output row bit for bit the
|
|
10
|
+
// same), with every decoded B fragment feeding an MMA for MT blocks of 8 rows;
|
|
11
|
+
// grid z walks chunks of 8·MT rows. A simdgroup's S sub-tiles and MT follow
|
|
12
|
+
// the layout and the rows (`plan`): neither changes a sum. Each code value y
|
|
13
|
+
// is read from a half table of the 2^L values (exact in half) the threadgroup
|
|
14
|
+
// generates once, in place of the 1MAD arithmetic (the M1 Max form, where the
|
|
15
|
+
// matrix products issue on the ordinary ALU pipes and the integer decode
|
|
16
|
+
// competes with them); a window is one bit-field extract (one that straddles a
|
|
17
|
+
// word reads a virtual word: the high half of one word and the low half of the
|
|
18
|
+
// next) and the B fragments are half. Input rows come in whole steps of 8 (the
|
|
19
|
+
// rows a multiple of 8, so is every split's); activation rows past M repeat
|
|
20
|
+
// the last row and are not written. The row count is read at run time (one
|
|
21
|
+
// pipeline per geometry and launch). SPLITS f32 partials [M, SPLITS, C] fold
|
|
22
|
+
// in one MLX sum. Two kernels, one per code layout: row-major [rows, cols·K/32]
|
|
23
|
+
// and the 3-bit block interleave [cols/512, rows, 48]. Measured on the M1 Max at
|
|
24
|
+
// the Qwen down shape (17408 x 5120, real weights) at 8, 16, 24, 32 and 64 rows,
|
|
25
|
+
// 3-bit interleaved: 0.24, 0.44, 0.64, 0.84 and 1.65 ms, against 0.66, 0.67,
|
|
26
|
+
// 0.87, 1.24 and 2.39 decoding with the 1MAD arithmetic (downMma at 8 rows
|
|
27
|
+
// 0.45); 2-bit row-major: 0.24, 0.40, 0.58, 0.76 and 1.49, against 0.62, 0.64,
|
|
28
|
+
// 0.88, 1.08 and 2.13 (downMma 0.43).
|
|
29
|
+
const SG_TG = 4, SPLITS = 8;
|
|
30
|
+
|
|
31
|
+
/** One pass of the kernel: S sub-tiles per simdgroup, MT blocks of 8 rows per decoded fragment. */
|
|
32
|
+
export interface DownPass { readonly S: number; readonly MT: number }
|
|
33
|
+
|
|
34
|
+
/** One block of 8 rows per pass, sixteen sub-tiles: the cheapest pass for 1..8 rows in either layout. */
|
|
35
|
+
export const DOWN_ONE_BLOCK: DownPass = Object.freeze({ S: 16, MT: 1 });
|
|
36
|
+
|
|
37
|
+
/** Each layout's passes and their relative cost, measured per pass at 8 to 128 rows: the 3-bit interleave runs one
|
|
38
|
+
* block per pass at every row count; row-major codes take sixteen sub-tiles for one block and eight for two or
|
|
39
|
+
* three. */
|
|
40
|
+
const PLANS: Readonly<Record<"rowMajor" | "interleaved", readonly (DownPass & { readonly cost: number })[]>> = {
|
|
41
|
+
interleaved: [{ ...DOWN_ONE_BLOCK, cost: 1 }],
|
|
42
|
+
rowMajor: [{ ...DOWN_ONE_BLOCK, cost: 0.6 }, { S: 8, MT: 2, cost: 1 }, { S: 8, MT: 3, cost: 1.44 }],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** The pass for M rows: the one whose passes cost least in all (the more blocks on a tie). */
|
|
46
|
+
function plan(layout: keyof typeof PLANS, M: number): DownPass {
|
|
47
|
+
let best = { S: 0, MT: 0, cost: Infinity };
|
|
48
|
+
for (const { S, MT, cost } of PLANS[layout]) {
|
|
49
|
+
const total = Math.ceil(M / (8 * MT)) * cost;
|
|
50
|
+
if (total <= best.cost) best = { S, MT, cost: total };
|
|
51
|
+
}
|
|
52
|
+
return { S: best.S, MT: best.MT };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const SOURCE = String.raw`
|
|
56
|
+
const uint M = (uint)x_shape[0];
|
|
57
|
+
const uint lane = thread_index_in_simdgroup;
|
|
58
|
+
threadgroup half codebook[1 << L];
|
|
59
|
+
for (uint i = simdgroup_index_in_threadgroup * 32u + lane; i < (1u << (uint)L); i += 32u * (uint)SG_TG)
|
|
60
|
+
codebook[i] = half(trellis_y_f32(i));
|
|
61
|
+
threadgroup_barrier(metal::mem_flags::mem_threadgroup);
|
|
62
|
+
const uint id = threadgroup_position_in_grid.y * (uint)SG_TG + simdgroup_index_in_threadgroup;
|
|
63
|
+
const uint groupsPerBlock = 32u / (uint)S;
|
|
64
|
+
const uint nGroups = ((uint)C / 256u) * groupsPerBlock;
|
|
65
|
+
if (id >= nGroups * (uint)SPLITS) return;
|
|
66
|
+
const uint cg = id % nGroups, split = id / nGroups;
|
|
67
|
+
const uint block = cg / groupsPerBlock, pg = (cg % groupsPerBlock) * 8u * (uint)S;
|
|
68
|
+
const uint fm = ((lane / 4u) & 4u) + ((lane / 2u) % 4u);
|
|
69
|
+
const uint fn = ((lane / 4u) & 2u) * 2u + (lane % 2u) * 2u;
|
|
70
|
+
const uint wpb = 8u * (uint)K;
|
|
71
|
+
const ulong rowWords = (ulong)(INTERLEAVE ? 2u : (uint)C / 256u) * wpb;
|
|
72
|
+
const device uint32_t* words = codes + (INTERLEAVE
|
|
73
|
+
? (ulong)(block / 2u) * (ulong)R * 2u * wpb + (block % 2u) * wpb : (ulong)block * wpb);
|
|
74
|
+
// This lane's 2S positions start at p0; realign its bit window to bit 0.
|
|
75
|
+
const uint p0 = pg + (uint)S * fn;
|
|
76
|
+
const uint bit0 = p0 * (uint)K, w0 = bit0 >> 5, off0 = bit0 & 31u;
|
|
77
|
+
const uint mBase = threadgroup_position_in_grid.z * 8u * (uint)MT;
|
|
78
|
+
const uint rowsPer = (((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS + 7u) & ~7u;
|
|
79
|
+
const uint r0 = split * rowsPer;
|
|
80
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
81
|
+
const device T* xm[MT];
|
|
82
|
+
metal::simdgroup_float8x8 acc[S][MT];
|
|
83
|
+
#pragma clang loop unroll(full)
|
|
84
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) {
|
|
85
|
+
xm[bk] = x + (ulong)metal::min(mBase + 8u * bk + fm, M - 1u) * (ulong)R;
|
|
86
|
+
#pragma clang loop unroll(full)
|
|
87
|
+
for (uint s = 0; s < (uint)S; ++s) acc[s][bk] = metal::make_filled_simdgroup_matrix<float, 8, 8>(0.0f);
|
|
88
|
+
}
|
|
89
|
+
// The window's words in a row's block (the last ones wrap to its first).
|
|
90
|
+
uint wordAt[NW + 1];
|
|
91
|
+
#pragma clang loop unroll(full)
|
|
92
|
+
for (uint i = 0; i <= (uint)NW; ++i) wordAt[i] = (w0 + i) % wpb;
|
|
93
|
+
const device uint32_t* rowCodes = words + (ulong)(r0 + fm) * rowWords;
|
|
94
|
+
for (uint r = r0; r < r1; r += 8u, rowCodes += 8u * rowWords) {
|
|
95
|
+
uint raw[NW + 1];
|
|
96
|
+
#pragma clang loop unroll(full)
|
|
97
|
+
for (uint i = 0; i <= (uint)NW; ++i) raw[i] = rowCodes[wordAt[i]];
|
|
98
|
+
uint w[NW], v[NW];
|
|
99
|
+
#pragma clang loop unroll(full)
|
|
100
|
+
for (uint i = 0; i < (uint)NW; ++i) w[i] = off0 ? (raw[i] >> off0) | (raw[i + 1] << (32u - off0)) : raw[i];
|
|
101
|
+
// Virtual word i: bits [32i - 16, 32i + 16) of the realigned window.
|
|
102
|
+
#pragma clang loop unroll(full)
|
|
103
|
+
for (uint i = 1; i < (uint)NW; ++i) v[i] = (w[i - 1] >> 16) | (w[i] << 16);
|
|
104
|
+
const uint ra = r + fn;
|
|
105
|
+
const float sa = float(scales[ra]) * TRELLIS_RCP, sb = float(scales[ra + 1u]) * TRELLIS_RCP;
|
|
106
|
+
metal::simdgroup_float8x8 a[MT];
|
|
107
|
+
#pragma clang loop unroll(full)
|
|
108
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) {
|
|
109
|
+
a[bk].thread_elements()[0] = float(xm[bk][ra]) * sa;
|
|
110
|
+
a[bk].thread_elements()[1] = float(xm[bk][ra + 1u]) * sb;
|
|
111
|
+
}
|
|
112
|
+
#pragma clang loop unroll(full)
|
|
113
|
+
for (uint s = 0; s < (uint)S; ++s) {
|
|
114
|
+
metal::simdgroup_half8x8 b;
|
|
115
|
+
b.thread_elements()[0] = codebook[block_state<K, L>(w, v, s)];
|
|
116
|
+
b.thread_elements()[1] = codebook[block_state<K, L>(w, v, s + (uint)S)];
|
|
117
|
+
#pragma clang loop unroll(full)
|
|
118
|
+
for (uint bk = 0; bk < (uint)MT; ++bk)
|
|
119
|
+
metal::simdgroup_multiply_accumulate(acc[s][bk], a[bk], b, acc[s][bk]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
#pragma clang loop unroll(full)
|
|
123
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) {
|
|
124
|
+
const uint m = mBase + 8u * bk + fm;
|
|
125
|
+
if (m >= M) continue;
|
|
126
|
+
device float* out = partial + ((ulong)m * (ulong)SPLITS + split) * (ulong)C + (ulong)block * 256u + 255u - p0;
|
|
127
|
+
#pragma clang loop unroll(full)
|
|
128
|
+
for (uint s = 0; s < (uint)S; ++s) {
|
|
129
|
+
out[-(int)s] = acc[s][bk].thread_elements()[0];
|
|
130
|
+
out[-(int)((uint)S + s)] = acc[s][bk].thread_elements()[1];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
// State at position t of a realigned window (bits [t·K, +L) of w), one extract (virtual words v past a word edge).
|
|
136
|
+
const STATE_HEADER = String.raw`
|
|
137
|
+
template <int K, int L_>
|
|
138
|
+
inline uint block_state(thread const uint* w, thread const uint* v, uint t) {
|
|
139
|
+
const uint b = t * (uint)K;
|
|
140
|
+
const uint off = b & 31u;
|
|
141
|
+
if (off + (uint)L_ <= 32u) return (w[b >> 5] >> off) & ((1u << (uint)L_) - 1u);
|
|
142
|
+
const uint vi = (b + 16u) >> 5;
|
|
143
|
+
return (v[vi] >> (b + 16u - 32u * vi)) & ((1u << (uint)L_) - 1u);
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
function launch(kernel: MetalKernel, x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, interleave: 0 | 1,
|
|
148
|
+
{ S, MT }: DownPass): MlxArray {
|
|
149
|
+
const M = x2.shape[0]!;
|
|
150
|
+
if (x2.ndim !== 2 || M < 1) throw new Error("downMmaWide: expects [rows, inputs]");
|
|
151
|
+
if (g.axis !== 0 || g.T !== 256 || g.cols % 256 !== 0 || g.rows % 8 !== 0 || g.L > 12)
|
|
152
|
+
throw new Error("downMmaWide: unsupported geometry");
|
|
153
|
+
const nGroups = (g.cols / 256) * (32 / S);
|
|
154
|
+
// Words covering 2S positions plus the L-bit window, after realignment.
|
|
155
|
+
const NW = Math.ceil((2 * S * g.k + g.L - 1) / 32) + 1;
|
|
156
|
+
const [partial] = kernel.apply([x2, codes, scales], {
|
|
157
|
+
outputs: [{ shape: [M, SPLITS, g.cols], dtype: Dtype.float32 }],
|
|
158
|
+
grid: [32 * SG_TG, Math.ceil((nGroups * SPLITS) / SG_TG), Math.ceil(M / (8 * MT))], threadGroup: [32 * SG_TG, 1, 1],
|
|
159
|
+
templateDtypes: { T: x2.dtype },
|
|
160
|
+
templateInts: { R: g.rows, C: g.cols, K: g.k, L: g.L, SPLITS, SG_TG, INTERLEAVE: interleave, MT, S, NW },
|
|
161
|
+
});
|
|
162
|
+
using sum = ops.sumAxis(partial!, 1, false);
|
|
163
|
+
partial!.dispose();
|
|
164
|
+
return sum.astype(x2.dtype);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let rowMajor: MetalKernel | undefined, interleaved: MetalKernel | undefined;
|
|
168
|
+
|
|
169
|
+
/** x2 [M, inFeatures] · W → [M, outFeatures] in x2's dtype for row-major axis-0 codes (T 256, L at most 12, input
|
|
170
|
+
* features a multiple of 8), any number of rows, in passes of the given shape. Borrows inputs. */
|
|
171
|
+
export function downMmaWidePass(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, pass: DownPass): MlxArray {
|
|
172
|
+
if (g.blockInterleave || codes.ndim !== 2) throw new Error("downMmaWide: needs row-major codes");
|
|
173
|
+
rowMajor ??= new MetalKernel({ name: "mlx_bun_trellis_down_mma_wide", inputNames: ["x", "codes", "scales"],
|
|
174
|
+
outputNames: ["partial"], source: SOURCE, header: HEADER + STATE_HEADER, ensureRowContiguous: true });
|
|
175
|
+
return launch(rowMajor, x2, codes, scales, g, 0, pass);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** downMmaWidePass for 3-bit block-interleaved codes [cols/512, rows, 48]. */
|
|
179
|
+
export function downK3InterleavedMmaWidePass(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry,
|
|
180
|
+
pass: DownPass): MlxArray {
|
|
181
|
+
if (g.blockInterleave !== 2 || g.k !== 3) throw new Error("downK3InterleavedMmaWide: needs 3-bit block-interleaved codes");
|
|
182
|
+
interleaved ??= new MetalKernel({ name: "mlx_bun_trellis_down_k3i_mma_wide", inputNames: ["x", "codes", "scales"],
|
|
183
|
+
outputNames: ["partial"], source: SOURCE, header: HEADER + STATE_HEADER, ensureRowContiguous: true });
|
|
184
|
+
return launch(interleaved, x2, codes, scales, g, 1, pass);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** downMmaWidePass in the pass the row count plans. */
|
|
188
|
+
export function downMmaWide(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
189
|
+
return downMmaWidePass(x2, codes, scales, g, plan("rowMajor", x2.shape[0]!));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** downK3InterleavedMmaWidePass in the pass the row count plans. */
|
|
193
|
+
export function downK3InterleavedMmaWide(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
194
|
+
return downK3InterleavedMmaWidePass(x2, codes, scales, g, plan("interleaved", x2.shape[0]!));
|
|
195
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
5
|
+
import { HEADER } from "./codebook";
|
|
6
|
+
import type { TrellisGeometry } from "./geometry";
|
|
7
|
+
|
|
8
|
+
// Verify-width down projection on the simdgroup matrix unit, 1..8 activation
|
|
9
|
+
// rows (one block of 8). A simdgroup owns 8·S consecutive positions of one
|
|
10
|
+
// 256-position coded block and a split of the input rows. Per 8-row step every
|
|
11
|
+
// lane decodes 2S contiguous positions of one input row (its bit window
|
|
12
|
+
// realigned once) into the B fragments of S output sub-tiles; the A fragments
|
|
13
|
+
// hold x·scale·(1/147.8) and each feeds S multiplies. Sub-tile s, fragment
|
|
14
|
+
// column i is position P_g + S·i + s (output column 255 - that, per block).
|
|
15
|
+
// SPLITS f32 partials [M, SPLITS, C] fold in one MLX sum. Two kernels, one per
|
|
16
|
+
// code layout: row-major [rows, cols·K/32] and the 3-bit block interleave
|
|
17
|
+
// [cols/512, rows, 48]. Not bit-identical to the matvec kernels; gate by KL.
|
|
18
|
+
const SG_TG = 4, MT = 1, S = 16, SPLITS = 8;
|
|
19
|
+
|
|
20
|
+
const SOURCE = String.raw`
|
|
21
|
+
const uint lane = thread_index_in_simdgroup;
|
|
22
|
+
const uint id = threadgroup_position_in_grid.y * (uint)SG_TG + simdgroup_index_in_threadgroup;
|
|
23
|
+
const uint groupsPerBlock = 32u / (uint)S;
|
|
24
|
+
const uint nGroups = ((uint)C / 256u) * groupsPerBlock;
|
|
25
|
+
if (id >= nGroups * (uint)SPLITS) return;
|
|
26
|
+
const uint cg = id % nGroups, split = id / nGroups;
|
|
27
|
+
const uint block = cg / groupsPerBlock, pg = (cg % groupsPerBlock) * 8u * (uint)S;
|
|
28
|
+
const uint fm = ((lane / 4u) & 4u) + ((lane / 2u) % 4u);
|
|
29
|
+
const uint fn = ((lane / 4u) & 2u) * 2u + (lane % 2u) * 2u;
|
|
30
|
+
const uint wpb = 8u * (uint)K;
|
|
31
|
+
const ulong rowWords = (ulong)(INTERLEAVE ? 2u : (uint)C / 256u) * wpb;
|
|
32
|
+
const device uint32_t* words = codes + (INTERLEAVE
|
|
33
|
+
? (ulong)(block / 2u) * (ulong)R * 2u * wpb + (block % 2u) * wpb : (ulong)block * wpb);
|
|
34
|
+
// This lane's 2S positions start at p0; realign its bit window to bit 0.
|
|
35
|
+
const uint p0 = pg + (uint)S * fn;
|
|
36
|
+
const uint bit0 = p0 * (uint)K, w0 = bit0 >> 5, off0 = bit0 & 31u;
|
|
37
|
+
const uint mBase = threadgroup_position_in_grid.z * 8u * (uint)MT;
|
|
38
|
+
const uint rowsPer = (((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS + 7u) & ~7u;
|
|
39
|
+
const uint r0 = split * rowsPer;
|
|
40
|
+
const uint r1 = metal::min((uint)R, r0 + rowsPer);
|
|
41
|
+
metal::simdgroup_float8x8 acc[S][MT];
|
|
42
|
+
#pragma clang loop unroll(full)
|
|
43
|
+
for (uint s = 0; s < (uint)S; ++s)
|
|
44
|
+
#pragma clang loop unroll(full)
|
|
45
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) acc[s][bk] = metal::make_filled_simdgroup_matrix<float, 8, 8>(0.0f);
|
|
46
|
+
for (uint r = r0; r < r1; r += 8u) {
|
|
47
|
+
const uint rw = r + fm;
|
|
48
|
+
const device uint32_t* rowCodes = words + (ulong)metal::min(rw, (uint)R - 1u) * rowWords;
|
|
49
|
+
uint raw[NW + 1];
|
|
50
|
+
#pragma clang loop unroll(full)
|
|
51
|
+
for (uint i = 0; i <= (uint)NW; ++i) {
|
|
52
|
+
const uint wi = w0 + i;
|
|
53
|
+
raw[i] = rowCodes[wi % wpb];
|
|
54
|
+
}
|
|
55
|
+
uint w[NW];
|
|
56
|
+
#pragma clang loop unroll(full)
|
|
57
|
+
for (uint i = 0; i < (uint)NW; ++i) w[i] = off0 ? (raw[i] >> off0) | (raw[i + 1] << (32u - off0)) : raw[i];
|
|
58
|
+
metal::simdgroup_float8x8 a[MT];
|
|
59
|
+
const uint ra = r + fn;
|
|
60
|
+
const float sa = ra < r1 ? float(scales[ra]) * TRELLIS_RCP : 0.0f;
|
|
61
|
+
const float sb = ra + 1u < r1 ? float(scales[ra + 1u]) * TRELLIS_RCP : 0.0f;
|
|
62
|
+
#pragma clang loop unroll(full)
|
|
63
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) {
|
|
64
|
+
const uint m = mBase + 8u * bk + fm;
|
|
65
|
+
const bool ok = m < (uint)M;
|
|
66
|
+
const device T* xm = x + (ulong)(ok ? m : 0u) * (ulong)R;
|
|
67
|
+
a[bk].thread_elements()[0] = ok && ra < r1 ? float(xm[ra]) * sa : 0.0f;
|
|
68
|
+
a[bk].thread_elements()[1] = ok && ra + 1u < r1 ? float(xm[ra + 1u]) * sb : 0.0f;
|
|
69
|
+
}
|
|
70
|
+
const bool rowOk = rw < r1;
|
|
71
|
+
#pragma clang loop unroll(full)
|
|
72
|
+
for (uint s = 0; s < (uint)S; ++s) {
|
|
73
|
+
metal::simdgroup_float8x8 b;
|
|
74
|
+
b.thread_elements()[0] = rowOk ? trellis_y_f32((block_state<K, L>(w, s))) : 0.0f;
|
|
75
|
+
b.thread_elements()[1] = rowOk ? trellis_y_f32((block_state<K, L>(w, s + (uint)S))) : 0.0f;
|
|
76
|
+
#pragma clang loop unroll(full)
|
|
77
|
+
for (uint bk = 0; bk < (uint)MT; ++bk)
|
|
78
|
+
metal::simdgroup_multiply_accumulate(acc[s][bk], a[bk], b, acc[s][bk]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
#pragma clang loop unroll(full)
|
|
82
|
+
for (uint bk = 0; bk < (uint)MT; ++bk) {
|
|
83
|
+
const uint m = mBase + 8u * bk + fm;
|
|
84
|
+
if (m >= (uint)M) continue;
|
|
85
|
+
device float* out = partial + ((ulong)m * (ulong)SPLITS + split) * (ulong)C + (ulong)block * 256u + 255u - p0;
|
|
86
|
+
#pragma clang loop unroll(full)
|
|
87
|
+
for (uint s = 0; s < (uint)S; ++s) {
|
|
88
|
+
out[-(int)s] = acc[s][bk].thread_elements()[0];
|
|
89
|
+
out[-(int)((uint)S + s)] = acc[s][bk].thread_elements()[1];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
// State at position t of a realigned window (bit t·K of w, LSB first).
|
|
95
|
+
const STATE_HEADER = String.raw`
|
|
96
|
+
template <int K, int L_>
|
|
97
|
+
inline uint block_state(thread const uint* w, uint t) {
|
|
98
|
+
const uint b = t * (uint)K;
|
|
99
|
+
const uint wi = b >> 5;
|
|
100
|
+
const uint off = b & 31u;
|
|
101
|
+
uint win = w[wi] >> off;
|
|
102
|
+
if (off + (uint)L_ > 32u) win |= w[wi + 1] << (32u - off);
|
|
103
|
+
return win & ((1u << (uint)L_) - 1u);
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
function launch(kernel: MetalKernel, x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, interleave: 0 | 1): MlxArray {
|
|
109
|
+
const M = x2.shape[0]!;
|
|
110
|
+
if (M < 1 || M > 8) throw new Error(`downMma: M=${M} outside 1..8`);
|
|
111
|
+
if (g.axis !== 0 || g.T !== 256 || g.cols % 256 !== 0 || g.L > 12) throw new Error("downMma: unsupported geometry");
|
|
112
|
+
const nGroups = (g.cols / 256) * (32 / S);
|
|
113
|
+
// Words covering 2S positions plus the L-bit window, after realignment.
|
|
114
|
+
const NW = Math.ceil((2 * S * g.k + g.L - 1) / 32) + 1;
|
|
115
|
+
const [partial] = kernel.apply([x2, codes, scales], {
|
|
116
|
+
outputs: [{ shape: [M, SPLITS, g.cols], dtype: Dtype.float32 }],
|
|
117
|
+
grid: [32 * SG_TG, Math.ceil((nGroups * SPLITS) / SG_TG), 1], threadGroup: [32 * SG_TG, 1, 1],
|
|
118
|
+
templateDtypes: { T: x2.dtype },
|
|
119
|
+
templateInts: { M, R: g.rows, C: g.cols, K: g.k, L: g.L, SPLITS, SG_TG, INTERLEAVE: interleave, MT, S, NW },
|
|
120
|
+
});
|
|
121
|
+
const sum = ops.sumAxis(partial!, 1, false);
|
|
122
|
+
partial!.dispose();
|
|
123
|
+
const out = sum.astype(x2.dtype);
|
|
124
|
+
sum.dispose();
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let rowMajor: MetalKernel | undefined, interleaved: MetalKernel | undefined;
|
|
129
|
+
|
|
130
|
+
/** x2 [M, inFeatures] · W → [M, outFeatures] in x2's dtype for row-major
|
|
131
|
+
* axis-0 codes (T 256). Borrows inputs. */
|
|
132
|
+
export function downMma(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
133
|
+
if (g.blockInterleave || codes.ndim !== 2) throw new Error("downMma: needs row-major codes");
|
|
134
|
+
rowMajor ??= new MetalKernel({ name: "mlx_bun_trellis_down_mma", inputNames: ["x", "codes", "scales"],
|
|
135
|
+
outputNames: ["partial"], source: SOURCE, header: HEADER + STATE_HEADER, ensureRowContiguous: true });
|
|
136
|
+
return launch(rowMajor, x2, codes, scales, g, 0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** downMma for 3-bit block-interleaved codes [cols/512, rows, 48]. */
|
|
140
|
+
export function downK3InterleavedMma(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry): MlxArray {
|
|
141
|
+
if (g.blockInterleave !== 2 || g.k !== 3) throw new Error("downK3InterleavedMma: needs 3-bit block-interleaved codes");
|
|
142
|
+
interleaved ??= new MetalKernel({ name: "mlx_bun_trellis_down_k3i_mma", inputNames: ["x", "codes", "scales"],
|
|
143
|
+
outputNames: ["partial"], source: SOURCE, header: HEADER + STATE_HEADER, ensureRowContiguous: true });
|
|
144
|
+
return launch(interleaved, x2, codes, scales, g, 1);
|
|
145
|
+
}
|