@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,360 @@
|
|
|
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 { positiveInteger } from "../../runtime/integers";
|
|
5
|
+
import { GLM52_EXPERT_SLOT_ALIGNMENT, validateRange, type Glm52CanonicalMetalLayout } from "./layout";
|
|
6
|
+
export { GLM52_EXPERT_SLOT_ALIGNMENT } from "./layout";
|
|
7
|
+
export type { Glm52CanonicalMetalLayout, Glm52CanonicalQ4MetalLayout, Glm52CanonicalQ8MetalLayout } from "./layout";
|
|
8
|
+
|
|
9
|
+
const SIMD_WIDTH = 32;
|
|
10
|
+
const SIMD_GROUPS = 4;
|
|
11
|
+
const THREADS = SIMD_WIDTH * SIMD_GROUPS;
|
|
12
|
+
const ROWS_PER_THREADGROUP = SIMD_GROUPS;
|
|
13
|
+
|
|
14
|
+
/** Wrap a live, aligned ExpertIOSlabStore slot without copying it.
|
|
15
|
+
*
|
|
16
|
+
* The residency lease remains owned by the caller and must not be released
|
|
17
|
+
* until the returned expert output has been evaluated and the GPU stream has
|
|
18
|
+
* completed.
|
|
19
|
+
*/
|
|
20
|
+
export function glm52CanonicalQ4SlotView(
|
|
21
|
+
pointer: number,
|
|
22
|
+
layout: Glm52CanonicalMetalLayout,
|
|
23
|
+
): MlxArray {
|
|
24
|
+
if (!Number.isSafeInteger(pointer) || pointer <= 0)
|
|
25
|
+
throw new Error("expert slot pointer must be a positive safe integer");
|
|
26
|
+
if (pointer % GLM52_EXPERT_SLOT_ALIGNMENT !== 0) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"expert slot pointer must be page-aligned for zero-copy Metal access",
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return MlxArray.fromPointer(pointer, [layout.slotBytes], Dtype.uint8);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const glm52CanonicalQ8SlotView = glm52CanonicalQ4SlotView;
|
|
35
|
+
|
|
36
|
+
// One simdgroup owns one output row. The packed Q4 byte stream and F32 row
|
|
37
|
+
// scales are read straight from the canonical residency slot. Every product is
|
|
38
|
+
// explicitly dequantized to float and accumulated with an F32 FMA.
|
|
39
|
+
const GATE_UP_SOURCE = String.raw`
|
|
40
|
+
const uint lane = thread_index_in_simdgroup;
|
|
41
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
42
|
+
const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
|
|
43
|
+
const uint sample = thread_position_in_grid.z;
|
|
44
|
+
if (row >= (uint)I || sample >= (uint)M) return;
|
|
45
|
+
const device T* sampleX = x + (ulong)sample * (ulong)H;
|
|
46
|
+
|
|
47
|
+
const device uint32_t* gateRow =
|
|
48
|
+
(const device uint32_t*)(slot + GATE_W) + (ulong)row * (ulong)(H / 8);
|
|
49
|
+
const device uint32_t* upRow =
|
|
50
|
+
(const device uint32_t*)(slot + UP_W) + (ulong)row * (ulong)(H / 8);
|
|
51
|
+
const device float* gateScales = (const device float*)(slot + GATE_S);
|
|
52
|
+
const device float* upScales = (const device float*)(slot + UP_S);
|
|
53
|
+
const float gateScale = gateScales[row];
|
|
54
|
+
const float upScale = upScales[row];
|
|
55
|
+
|
|
56
|
+
float gateAcc = 0.0f;
|
|
57
|
+
float upAcc = 0.0f;
|
|
58
|
+
for (uint word = lane; word < (uint)(H / 8); word += 32u) {
|
|
59
|
+
const uint32_t gatePacked = gateRow[word];
|
|
60
|
+
const uint32_t upPacked = upRow[word];
|
|
61
|
+
const uint k0 = word * 8u;
|
|
62
|
+
for (uint place = 0; place < 8u; ++place) {
|
|
63
|
+
const float xv = float(sampleX[k0 + place]);
|
|
64
|
+
const float gateWeight =
|
|
65
|
+
float((gatePacked >> (place * 4u)) & 0xFu) - 8.0f;
|
|
66
|
+
const float upWeight =
|
|
67
|
+
float((upPacked >> (place * 4u)) & 0xFu) - 8.0f;
|
|
68
|
+
gateAcc = metal::fma(gateWeight, xv, gateAcc);
|
|
69
|
+
upAcc = metal::fma(upWeight, xv, upAcc);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const float gate = metal::simd_sum(gateAcc) * gateScale;
|
|
74
|
+
const float up = metal::simd_sum(upAcc) * upScale;
|
|
75
|
+
if (lane == 0u) {
|
|
76
|
+
// Match the production BF16 graph's materialization boundaries: gate and
|
|
77
|
+
// up are rounded to T, then SiLU and the product are rounded to T.
|
|
78
|
+
const T gateT = T(gate);
|
|
79
|
+
const T upT = T(up);
|
|
80
|
+
const T sigmoidT = T(1.0f / (1.0f + metal::precise::exp(-float(gateT))));
|
|
81
|
+
const T siluT = T(float(gateT) * float(sigmoidT));
|
|
82
|
+
mid[(ulong)sample * (ulong)I + row] =
|
|
83
|
+
T(float(siluT) * float(upT));
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const DOWN_SOURCE = String.raw`
|
|
88
|
+
const uint lane = thread_index_in_simdgroup;
|
|
89
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
90
|
+
const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
|
|
91
|
+
const uint sample = thread_position_in_grid.z;
|
|
92
|
+
if (row >= (uint)H || sample >= (uint)M) return;
|
|
93
|
+
const device T* sampleMid = mid + (ulong)sample * (ulong)I;
|
|
94
|
+
|
|
95
|
+
const device uint32_t* downRow =
|
|
96
|
+
(const device uint32_t*)(slot + DOWN_W) + (ulong)row * (ulong)(I / 8);
|
|
97
|
+
const device float* downScales = (const device float*)(slot + DOWN_S);
|
|
98
|
+
const float scale = downScales[row];
|
|
99
|
+
float acc = 0.0f;
|
|
100
|
+
for (uint word = lane; word < (uint)(I / 8); word += 32u) {
|
|
101
|
+
const uint32_t packed = downRow[word];
|
|
102
|
+
const uint k0 = word * 8u;
|
|
103
|
+
for (uint place = 0; place < 8u; ++place) {
|
|
104
|
+
const float xv = float(sampleMid[k0 + place]);
|
|
105
|
+
const float weight =
|
|
106
|
+
float((packed >> (place * 4u)) & 0xFu) - 8.0f;
|
|
107
|
+
acc = metal::fma(weight, xv, acc);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const float value = metal::simd_sum(acc) * scale;
|
|
111
|
+
if (lane == 0u)
|
|
112
|
+
out[(ulong)sample * (ulong)H + row] = T(value);
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
const Q8_GATE_UP_SOURCE = String.raw`
|
|
116
|
+
const uint lane = thread_index_in_simdgroup;
|
|
117
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
118
|
+
const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
|
|
119
|
+
const uint sample = thread_position_in_grid.z;
|
|
120
|
+
if (row >= (uint)I || sample >= (uint)M) return;
|
|
121
|
+
|
|
122
|
+
const device int8_t* gateRow =
|
|
123
|
+
(const device int8_t*)(slot + GATE_W) + (ulong)row * (ulong)H;
|
|
124
|
+
const device int8_t* upRow =
|
|
125
|
+
(const device int8_t*)(slot + UP_W) + (ulong)row * (ulong)H;
|
|
126
|
+
const device float* gateScales = (const device float*)(slot + GATE_S);
|
|
127
|
+
const device float* upScales = (const device float*)(slot + UP_S);
|
|
128
|
+
const float gateScale = gateScales[row];
|
|
129
|
+
const float upScale = upScales[row];
|
|
130
|
+
float gateAcc = 0.0f;
|
|
131
|
+
float upAcc = 0.0f;
|
|
132
|
+
for (uint k = lane; k < (uint)H; k += 32u) {
|
|
133
|
+
const float xv = float(x[(ulong)sample * (ulong)H + k]);
|
|
134
|
+
gateAcc = metal::fma(float(gateRow[k]), xv, gateAcc);
|
|
135
|
+
upAcc = metal::fma(float(upRow[k]), xv, upAcc);
|
|
136
|
+
}
|
|
137
|
+
const float gate = metal::simd_sum(gateAcc) * gateScale;
|
|
138
|
+
const float up = metal::simd_sum(upAcc) * upScale;
|
|
139
|
+
if (lane == 0u) {
|
|
140
|
+
const T gateT = T(gate);
|
|
141
|
+
const T upT = T(up);
|
|
142
|
+
const T sigmoidT = T(1.0f / (1.0f + metal::precise::exp(-float(gateT))));
|
|
143
|
+
const T siluT = T(float(gateT) * float(sigmoidT));
|
|
144
|
+
mid[(ulong)sample * (ulong)I + row] = T(float(siluT) * float(upT));
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
const Q8_DOWN_SOURCE = String.raw`
|
|
149
|
+
const uint lane = thread_index_in_simdgroup;
|
|
150
|
+
const uint sg = simdgroup_index_in_threadgroup;
|
|
151
|
+
const uint row = thread_position_in_grid.y * (uint)ROWS_TG + sg;
|
|
152
|
+
const uint sample = thread_position_in_grid.z;
|
|
153
|
+
if (row >= (uint)H || sample >= (uint)M) return;
|
|
154
|
+
|
|
155
|
+
const device int8_t* downRow =
|
|
156
|
+
(const device int8_t*)(slot + DOWN_W) + (ulong)row * (ulong)I;
|
|
157
|
+
const device float* downScales = (const device float*)(slot + DOWN_S);
|
|
158
|
+
const float scale = downScales[row];
|
|
159
|
+
float acc = 0.0f;
|
|
160
|
+
for (uint k = lane; k < (uint)I; k += 32u) {
|
|
161
|
+
const float xv = float(mid[(ulong)sample * (ulong)I + k]);
|
|
162
|
+
acc = metal::fma(float(downRow[k]), xv, acc);
|
|
163
|
+
}
|
|
164
|
+
const float value = metal::simd_sum(acc) * scale;
|
|
165
|
+
if (lane == 0u) out[(ulong)sample * (ulong)H + row] = T(value);
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
/** What differs between the Q4 and Q8 kernel families: the Metal sources, the
|
|
169
|
+
* weight packing the validators check, and the error wording. */
|
|
170
|
+
interface CanonicalExecutorSpec {
|
|
171
|
+
readonly label: "Q4" | "Q8";
|
|
172
|
+
readonly kernelPrefix: string;
|
|
173
|
+
readonly gateUpSource: string;
|
|
174
|
+
readonly downSource: string;
|
|
175
|
+
/** Weights stored per byte (Q4 packs two, Q8 one). */
|
|
176
|
+
readonly weightsPerByte: 1 | 2;
|
|
177
|
+
/** Output dimensions must divide by this many packed weights (Q4: one uint32 word). */
|
|
178
|
+
readonly dimensionMultiple: number;
|
|
179
|
+
readonly subject: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function validateCall(
|
|
183
|
+
input: MlxArray,
|
|
184
|
+
slot: MlxArray,
|
|
185
|
+
layout: Glm52CanonicalMetalLayout,
|
|
186
|
+
spec: CanonicalExecutorSpec,
|
|
187
|
+
): void {
|
|
188
|
+
const hidden = positiveInteger(layout.hiddenSize, "hidden size");
|
|
189
|
+
const intermediate = positiveInteger(
|
|
190
|
+
layout.intermediateSize,
|
|
191
|
+
"intermediate size",
|
|
192
|
+
);
|
|
193
|
+
positiveInteger(layout.slotBytes, "expert slot bytes");
|
|
194
|
+
if (hidden % spec.dimensionMultiple !== 0 || intermediate % spec.dimensionMultiple !== 0) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`${spec.label} expert dimensions must be divisible by ${spec.dimensionMultiple}`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (hidden % ROWS_PER_THREADGROUP !== 0 ||
|
|
200
|
+
intermediate % ROWS_PER_THREADGROUP !== 0) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`${spec.label} expert output dimensions must be divisible by ${ROWS_PER_THREADGROUP}`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
if (
|
|
206
|
+
input.shape.length !== 2 ||
|
|
207
|
+
!Number.isSafeInteger(input.shape[0]) ||
|
|
208
|
+
input.shape[0]! < 1 ||
|
|
209
|
+
input.shape[1] !== hidden
|
|
210
|
+
) {
|
|
211
|
+
throw new Error(`${spec.subject} requires input [M,${hidden}]`);
|
|
212
|
+
}
|
|
213
|
+
if (input.dtype !== Dtype.bfloat16 && input.dtype !== Dtype.float32)
|
|
214
|
+
throw new Error(`${spec.subject} requires bfloat16 or float32 input`);
|
|
215
|
+
if (slot.dtype !== Dtype.uint8 || slot.shape.length !== 1)
|
|
216
|
+
throw new Error("canonical expert slot must be a flat uint8 array");
|
|
217
|
+
if (slot.size < layout.slotBytes)
|
|
218
|
+
throw new Error("canonical expert slot array is shorter than its layout");
|
|
219
|
+
|
|
220
|
+
const perByte = spec.weightsPerByte;
|
|
221
|
+
const ranges = [
|
|
222
|
+
[layout.downWeightOffset, hidden * intermediate / perByte, "down weights"],
|
|
223
|
+
[layout.gateWeightOffset, intermediate * hidden / perByte, "gate weights"],
|
|
224
|
+
[layout.upWeightOffset, intermediate * hidden / perByte, "up weights"],
|
|
225
|
+
[layout.downScaleOffset, hidden * 4, "down scales"],
|
|
226
|
+
[layout.gateScaleOffset, intermediate * 4, "gate scales"],
|
|
227
|
+
[layout.upScaleOffset, intermediate * 4, "up scales"],
|
|
228
|
+
] as const;
|
|
229
|
+
for (const [offset, length, label] of ranges)
|
|
230
|
+
validateRange(offset, length, layout.slotBytes, label);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Row-independent routed-SwiGLU kernel pair (gate/up, then down) that reads a
|
|
235
|
+
* canonical residency slot directly. M=1 decode and a pinned speculative
|
|
236
|
+
* verify batch use the identical source and dispatch geometry; only grid.z
|
|
237
|
+
* changes. The Q4 and Q8 families below differ only in their spec.
|
|
238
|
+
*/
|
|
239
|
+
class Glm52CanonicalMetalExecutor {
|
|
240
|
+
readonly #gateUp: MetalKernel;
|
|
241
|
+
readonly #down: MetalKernel;
|
|
242
|
+
readonly #spec: CanonicalExecutorSpec;
|
|
243
|
+
#disposed = false;
|
|
244
|
+
|
|
245
|
+
constructor(spec: CanonicalExecutorSpec) {
|
|
246
|
+
this.#spec = spec;
|
|
247
|
+
this.#gateUp = new MetalKernel({
|
|
248
|
+
name: `${spec.kernelPrefix}_gate_up`,
|
|
249
|
+
inputNames: ["x", "slot"],
|
|
250
|
+
outputNames: ["mid"],
|
|
251
|
+
source: spec.gateUpSource,
|
|
252
|
+
ensureRowContiguous: true,
|
|
253
|
+
});
|
|
254
|
+
this.#down = new MetalKernel({
|
|
255
|
+
name: `${spec.kernelPrefix}_down`,
|
|
256
|
+
inputNames: ["mid", "slot"],
|
|
257
|
+
outputNames: ["out"],
|
|
258
|
+
source: spec.downSource,
|
|
259
|
+
ensureRowContiguous: true,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
execute(
|
|
264
|
+
input: MlxArray,
|
|
265
|
+
slot: MlxArray,
|
|
266
|
+
layout: Glm52CanonicalMetalLayout,
|
|
267
|
+
): MlxArray {
|
|
268
|
+
if (this.#disposed)
|
|
269
|
+
throw new Error(`${this.#spec.subject} executor used after dispose`);
|
|
270
|
+
validateCall(input, slot, layout, this.#spec);
|
|
271
|
+
const samples = input.shape[0]!;
|
|
272
|
+
const templateInts = {
|
|
273
|
+
M: samples,
|
|
274
|
+
H: layout.hiddenSize,
|
|
275
|
+
I: layout.intermediateSize,
|
|
276
|
+
DOWN_W: layout.downWeightOffset,
|
|
277
|
+
GATE_W: layout.gateWeightOffset,
|
|
278
|
+
UP_W: layout.upWeightOffset,
|
|
279
|
+
DOWN_S: layout.downScaleOffset,
|
|
280
|
+
GATE_S: layout.gateScaleOffset,
|
|
281
|
+
UP_S: layout.upScaleOffset,
|
|
282
|
+
ROWS_TG: ROWS_PER_THREADGROUP,
|
|
283
|
+
};
|
|
284
|
+
const [mid] = this.#gateUp.apply([input, slot], {
|
|
285
|
+
outputs: [{
|
|
286
|
+
shape: [samples, layout.intermediateSize],
|
|
287
|
+
dtype: input.dtype,
|
|
288
|
+
}],
|
|
289
|
+
grid: [
|
|
290
|
+
THREADS,
|
|
291
|
+
layout.intermediateSize / ROWS_PER_THREADGROUP,
|
|
292
|
+
samples,
|
|
293
|
+
],
|
|
294
|
+
threadGroup: [THREADS, 1, 1],
|
|
295
|
+
templateDtypes: { T: input.dtype },
|
|
296
|
+
templateInts,
|
|
297
|
+
});
|
|
298
|
+
if (!mid) throw new Error(`${this.#spec.subject} gate/up kernel returned no output`);
|
|
299
|
+
try {
|
|
300
|
+
const [output] = this.#down.apply([mid, slot], {
|
|
301
|
+
outputs: [{
|
|
302
|
+
shape: [samples, layout.hiddenSize],
|
|
303
|
+
dtype: input.dtype,
|
|
304
|
+
}],
|
|
305
|
+
grid: [
|
|
306
|
+
THREADS,
|
|
307
|
+
layout.hiddenSize / ROWS_PER_THREADGROUP,
|
|
308
|
+
samples,
|
|
309
|
+
],
|
|
310
|
+
threadGroup: [THREADS, 1, 1],
|
|
311
|
+
templateDtypes: { T: input.dtype },
|
|
312
|
+
templateInts,
|
|
313
|
+
});
|
|
314
|
+
if (!output) throw new Error(`${this.#spec.subject} down kernel returned no output`);
|
|
315
|
+
return output;
|
|
316
|
+
} finally {
|
|
317
|
+
mid.dispose();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
dispose(): void {
|
|
322
|
+
if (this.#disposed) return;
|
|
323
|
+
this.#disposed = true;
|
|
324
|
+
this.#gateUp.dispose();
|
|
325
|
+
this.#down.dispose();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Q4 (packed nibbles, affine zero-point 8) kernel family for the GLM-5.2
|
|
330
|
+
* production geometry. */
|
|
331
|
+
export class Glm52CanonicalQ4MetalExecutor extends Glm52CanonicalMetalExecutor {
|
|
332
|
+
constructor() {
|
|
333
|
+
super({
|
|
334
|
+
label: "Q4",
|
|
335
|
+
kernelPrefix: "mlx_bun_glm52_q4_slot",
|
|
336
|
+
gateUpSource: GATE_UP_SOURCE,
|
|
337
|
+
downSource: DOWN_SOURCE,
|
|
338
|
+
weightsPerByte: 2,
|
|
339
|
+
dimensionMultiple: 8,
|
|
340
|
+
subject: "GLM Metal streamed expert decode",
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Fixed M=1..gamma signed-Q8 kernel family for native MTP draft and accepted
|
|
346
|
+
* token absorption. The row dot-product and materialization boundaries are
|
|
347
|
+
* identical for every batch width; only grid.z changes. */
|
|
348
|
+
export class Glm52CanonicalQ8MetalExecutor extends Glm52CanonicalMetalExecutor {
|
|
349
|
+
constructor() {
|
|
350
|
+
super({
|
|
351
|
+
label: "Q8",
|
|
352
|
+
kernelPrefix: "mlx_bun_glm52_q8_slot",
|
|
353
|
+
gateUpSource: Q8_GATE_UP_SOURCE,
|
|
354
|
+
downSource: Q8_DOWN_SOURCE,
|
|
355
|
+
weightsPerByte: 1,
|
|
356
|
+
dimensionMultiple: 1,
|
|
357
|
+
subject: "GLM MTP Metal streamed expert",
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/** tanh(x / cap) * cap with weak-scalar semantics, UNFUSED (standalone div, tanh,
|
|
6
|
+
* mul), as plain-Python oracle sites compose it. The mx.compile'd one
|
|
7
|
+
* (gemma4_text.py) is `compiledLogitSoftcap` in softcap.ts; the two are
|
|
8
|
+
* separate on purpose so each site dispatches the same kernels as its oracle. */
|
|
9
|
+
export function logitSoftcap(logits: MlxArray, cap: number): MlxArray {
|
|
10
|
+
const capArr = ops.scalarLike(cap, logits);
|
|
11
|
+
const scaled = ops.div(logits, capArr);
|
|
12
|
+
const t = ops.tanh(scaled);
|
|
13
|
+
scaled.dispose();
|
|
14
|
+
const out = ops.mul(t, capArr);
|
|
15
|
+
t.dispose();
|
|
16
|
+
capArr.dispose();
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** argmax over vocab at the last sequence position of [1, L, V]. */
|
|
21
|
+
export function argmaxLastPosition(logits: MlxArray): number {
|
|
22
|
+
const [, L, V] = logits.shape as [number, number, number];
|
|
23
|
+
const last = logits.slice([0, L - 1, 0], [1, L, V]);
|
|
24
|
+
const am = ops.argmaxAxis(last, -1);
|
|
25
|
+
const id = ops.itemUint32(am);
|
|
26
|
+
last.dispose();
|
|
27
|
+
am.dispose();
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Last-position logits as f32 (for the parity harness). */
|
|
32
|
+
export function lastPositionLogits(logits: MlxArray): Float32Array {
|
|
33
|
+
const [, L, V] = logits.shape as [number, number, number];
|
|
34
|
+
const last = logits.slice([0, L - 1, 0], [1, L, V]);
|
|
35
|
+
const f32 = last.toFloat32();
|
|
36
|
+
last.dispose();
|
|
37
|
+
return f32;
|
|
38
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
3
|
+
|
|
4
|
+
// One-row matmul over MLX affine 3- or 4-bit, group-64 weights: y = x · Wᵀ for
|
|
5
|
+
// a single activation row, bit for bit MLX 0.32.2's affine_qmv_fast (the
|
|
6
|
+
// kernel MLX's quantized matmul runs at one row). Every output keeps MLX's
|
|
7
|
+
// arithmetic: each lane owns 16 values of every 512-value K step (lane·16 on),
|
|
8
|
+
// computes MLX's load_vector (x_thread, its bf16 sum) and qdot over them,
|
|
9
|
+
// adds each step's qdot into its partial from 0 in K order, and the 32
|
|
10
|
+
// partials meet in simd_sum. Only what does not touch a bit changes:
|
|
11
|
+
// - load_vector runs once per threadgroup, every 16-value chunk of x into
|
|
12
|
+
// threadgroup memory, where MLX recomputes it per simdgroup and K step (its
|
|
13
|
+
// bf16 sum chain is software-rounded on the M1 Max);
|
|
14
|
+
// - each masked weight field's float is formed as (q | 2^23 bits) − 2^23, which
|
|
15
|
+
// is float(q) exactly (q < 2^23), in place of an integer convert;
|
|
16
|
+
// - R = 4 rows per simdgroup and S = 16 simdgroups per threadgroup (MLX: 4
|
|
17
|
+
// and 2), so 64 rows share one threadgroup's x.
|
|
18
|
+
// Measured on the M1 Max, each layer's weights back to back, against MLX's
|
|
19
|
+
// quantized matmul at one row: 3-bit 5120 to 10240 outputs 0.082 ms against
|
|
20
|
+
// 0.100, 5120 to 6144 0.053 against 0.062, 6144 to 5120 0.054 against 0.062,
|
|
21
|
+
// 4-bit 5120 to 248320 (the head) 1.96 against 2.26; 4-bit projections of 1024
|
|
22
|
+
// to 12288 outputs level or up to 3% slower (left on MLX's).
|
|
23
|
+
const R = 4, S = 16;
|
|
24
|
+
|
|
25
|
+
const HEADER = String.raw`
|
|
26
|
+
// MLX 0.32.2 load_vector (quantized.h) at values_per_thread 16, bits 3 and 4.
|
|
27
|
+
template <typename T, int bits>
|
|
28
|
+
inline float mlxq_load_vector(const device T* x, thread float* x_thread) {
|
|
29
|
+
float sum = 0;
|
|
30
|
+
if (bits == 3) {
|
|
31
|
+
for (int i = 0; i < 16; i += 8) {
|
|
32
|
+
sum += x[i] + x[i + 1] + x[i + 2] + x[i + 3] + x[i + 4] + x[i + 5] +
|
|
33
|
+
x[i + 6] + x[i + 7];
|
|
34
|
+
x_thread[i] = x[i];
|
|
35
|
+
x_thread[i + 1] = x[i + 1] / 8.0f;
|
|
36
|
+
x_thread[i + 2] = x[i + 2] / 64.0f;
|
|
37
|
+
x_thread[i + 3] = x[i + 3] / 2.0f;
|
|
38
|
+
x_thread[i + 4] = x[i + 4] / 16.0f;
|
|
39
|
+
x_thread[i + 5] = x[i + 5] / 128.0f;
|
|
40
|
+
x_thread[i + 6] = x[i + 6] / 4.0f;
|
|
41
|
+
x_thread[i + 7] = x[i + 7] / 32.0f;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
for (int i = 0; i < 16; i += 4) {
|
|
45
|
+
sum += x[i] + x[i + 1] + x[i + 2] + x[i + 3];
|
|
46
|
+
x_thread[i] = x[i];
|
|
47
|
+
x_thread[i + 1] = x[i + 1] / 16.0f;
|
|
48
|
+
x_thread[i + 2] = x[i + 2] / 256.0f;
|
|
49
|
+
x_thread[i + 3] = x[i + 3] / 4096.0f;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return sum;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// float(q) for a masked field q < 2^23: q in the mantissa of 2^23, minus 2^23.
|
|
56
|
+
#define MLXQ_F(q) (as_type<float>((uint)(q) | 0x4B000000u) - 8388608.0f)
|
|
57
|
+
|
|
58
|
+
// MLX 0.32.2 qdot (quantized.h) at values_per_thread 16, bits 3 and 4: the
|
|
59
|
+
// same products and additions in the same order.
|
|
60
|
+
template <int bits>
|
|
61
|
+
inline float mlxq_qdot(const device uint8_t* w, const threadgroup float* x_thread, float scale, float bias, float sum) {
|
|
62
|
+
float accum = 0;
|
|
63
|
+
if (bits == 3) {
|
|
64
|
+
for (int i = 0; i < 2; i++) {
|
|
65
|
+
x_thread += 8 * i;
|
|
66
|
+
w += 3 * i;
|
|
67
|
+
accum += MLXQ_F(w[0] & 0x07) * x_thread[0];
|
|
68
|
+
accum += MLXQ_F(w[0] & 0x38) * x_thread[1];
|
|
69
|
+
accum += MLXQ_F(w[0] & 0xc0) * x_thread[2];
|
|
70
|
+
accum += MLXQ_F(w[1] & 0x01) * (x_thread[2] * 256.0f);
|
|
71
|
+
accum += MLXQ_F(w[1] & 0x0e) * x_thread[3];
|
|
72
|
+
accum += MLXQ_F(w[1] & 0x70) * x_thread[4];
|
|
73
|
+
accum += MLXQ_F(w[1] & 0x80) * x_thread[5];
|
|
74
|
+
accum += MLXQ_F(w[2] & 0x03) * (x_thread[5] * 256.0f);
|
|
75
|
+
accum += MLXQ_F(w[2] & 0x1c) * x_thread[6];
|
|
76
|
+
accum += MLXQ_F(w[2] & 0xe0) * x_thread[7];
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const device uint16_t* ws = (const device uint16_t*)w;
|
|
80
|
+
for (int i = 0; i < 4; i++) {
|
|
81
|
+
accum +=
|
|
82
|
+
(x_thread[4 * i] * MLXQ_F(ws[i] & 0x000f) +
|
|
83
|
+
x_thread[4 * i + 1] * MLXQ_F(ws[i] & 0x00f0) +
|
|
84
|
+
x_thread[4 * i + 2] * MLXQ_F(ws[i] & 0x0f00) +
|
|
85
|
+
x_thread[4 * i + 3] * MLXQ_F(ws[i] & 0xf000));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return scale * accum + sum * bias;
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
const SOURCE = String.raw`
|
|
93
|
+
constexpr int BPL = 2 * BITS; // weight bytes per lane per K step
|
|
94
|
+
constexpr int ROWB = K * BITS / 8;
|
|
95
|
+
constexpr int GROUPS = K / 64;
|
|
96
|
+
const uint sg = simdgroup_index_in_threadgroup, lane = thread_index_in_simdgroup;
|
|
97
|
+
// MLX's x_thread for every 16-value chunk of x, and each chunk's sum.
|
|
98
|
+
threadgroup float xs[K];
|
|
99
|
+
threadgroup float ss[K / 16];
|
|
100
|
+
for (int c = (int)(sg * 32 + lane); c < K / 16; c += S * 32) {
|
|
101
|
+
thread float t[16];
|
|
102
|
+
ss[c] = mlxq_load_vector<T, BITS>(x + c * 16, t);
|
|
103
|
+
for (int j = 0; j < 16; j++) xs[c * 16 + j] = t[j];
|
|
104
|
+
}
|
|
105
|
+
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
106
|
+
const int row0 = (threadgroup_position_in_grid.y * S + sg) * R;
|
|
107
|
+
const device uint8_t* ws = (const device uint8_t*)w + row0 * ROWB + lane * BPL;
|
|
108
|
+
const device T* sc = scales + row0 * GROUPS + lane / 4;
|
|
109
|
+
const device T* bi = biases + row0 * GROUPS + lane / 4;
|
|
110
|
+
float result[R] = {0};
|
|
111
|
+
#pragma clang loop unroll_count(1)
|
|
112
|
+
for (int k = 0; k < K; k += 512) {
|
|
113
|
+
const float sum = ss[(k + lane * 16) / 16];
|
|
114
|
+
const threadgroup float* x_thread = xs + k + lane * 16;
|
|
115
|
+
for (int r = 0; r < R; r++) {
|
|
116
|
+
const float s = sc[r * GROUPS];
|
|
117
|
+
const float b = bi[r * GROUPS];
|
|
118
|
+
result[r] += mlxq_qdot<BITS>(ws + r * ROWB, x_thread, s, b, sum);
|
|
119
|
+
}
|
|
120
|
+
ws += 32 * BPL;
|
|
121
|
+
sc += 8;
|
|
122
|
+
bi += 8;
|
|
123
|
+
}
|
|
124
|
+
for (int r = 0; r < R; r++) {
|
|
125
|
+
const float v = simd_sum(result[r]);
|
|
126
|
+
if (lane == 0) y[row0 + r] = static_cast<T>(v);
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
let kernel: MetalKernel | undefined;
|
|
131
|
+
|
|
132
|
+
/** Eligible: affine 3- or 4-bit, group 64, one row, K a multiple of 512 whose x_thread fits threadgroup memory
|
|
133
|
+
* (K <= 7680), N a multiple of 64. */
|
|
134
|
+
export function affineRowEligible(rows: number, w: MlxArray, scales: MlxArray, spec: { bits: number; groupSize: number; mode: string }): boolean {
|
|
135
|
+
if (spec.mode !== "affine" || spec.groupSize !== 64 || (spec.bits !== 3 && spec.bits !== 4)) return false;
|
|
136
|
+
const N = scales.shape[0]!, K = scales.shape[1]! * 64;
|
|
137
|
+
return rows === 1 && K % 512 === 0 && K <= 7680 && N % (R * S) === 0 && w.shape.length === 2;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** x [..., K] (one row) · Wᵀ → [..., N] in x's dtype, for `bits`-bit weights: MLX's quantized matmul's bits.
|
|
141
|
+
* Borrows inputs. */
|
|
142
|
+
export function affineRow(x: MlxArray, w: MlxArray, scales: MlxArray, biases: MlxArray, bits: 3 | 4): MlxArray {
|
|
143
|
+
const K = x.shape.at(-1)!, M = x.size / K, N = scales.shape[0]!;
|
|
144
|
+
if (M !== 1) throw new Error(`affineRow: M=${M}, one row only`);
|
|
145
|
+
kernel ??= new MetalKernel({ name: "mlx_bun_affine_row", inputNames: ["x", "w", "scales", "biases"],
|
|
146
|
+
outputNames: ["y"], source: SOURCE, header: HEADER, ensureRowContiguous: true });
|
|
147
|
+
const [y] = kernel.apply([x, w, scales, biases], {
|
|
148
|
+
outputs: [{ shape: [...x.shape.slice(0, -1), N], dtype: x.dtype }],
|
|
149
|
+
grid: [32, N / R, 1], threadGroup: [32, S, 1],
|
|
150
|
+
templateDtypes: { T: x.dtype },
|
|
151
|
+
templateInts: { N, K, BITS: bits, R, S },
|
|
152
|
+
});
|
|
153
|
+
return y!;
|
|
154
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
3
|
+
|
|
4
|
+
/** Run independent affine M=1 matrix-vector products in one native batched call.
|
|
5
|
+
* Weight/scales/bias views share their original buffers. MLX 0.32.2's
|
|
6
|
+
* flattened M>=2 path uses different arithmetic, so appending known tokens
|
|
7
|
+
* must explicitly select this layout when preserving decode state.
|
|
8
|
+
*/
|
|
9
|
+
export function quantizedMatmulRows(
|
|
10
|
+
x: MlxArray, w: MlxArray, scales: MlxArray, biases: MlxArray | null,
|
|
11
|
+
spec: ops.QuantSpec,
|
|
12
|
+
): MlxArray {
|
|
13
|
+
const shape = x.shape, width = shape[shape.length - 1]!;
|
|
14
|
+
const rows = shape.reduce((a, b) => a * b, 1) / width;
|
|
15
|
+
if (rows === 1) return ops.quantizedMatmul(x, w, scales, biases, spec);
|
|
16
|
+
if (spec.mode !== "affine")
|
|
17
|
+
throw new Error("Independent-row batched matmul requires affine quantization");
|
|
18
|
+
if (w.shape.length !== 2 || scales.shape.length !== 2 || (biases && biases.shape.length !== 2))
|
|
19
|
+
throw new Error("Independent-row matmul requires shared two-dimensional weights");
|
|
20
|
+
const views: MlxArray[] = [];
|
|
21
|
+
const view = (value: MlxArray, newShape: number[]) => {
|
|
22
|
+
const result = ops.reshape(value, newShape); views.push(result); return result;
|
|
23
|
+
};
|
|
24
|
+
let output: MlxArray | undefined;
|
|
25
|
+
try {
|
|
26
|
+
const input = view(x, [rows, 1, width]);
|
|
27
|
+
const weight = view(w, [1, ...w.shape]);
|
|
28
|
+
const scale = view(scales, [1, ...scales.shape]);
|
|
29
|
+
const bias = biases ? view(biases, [1, ...biases.shape]) : null;
|
|
30
|
+
output = ops.quantizedMatmul(input, weight, scale, bias, spec);
|
|
31
|
+
return ops.reshape(output, [...shape.slice(0, -1), output.shape.at(-1)!]);
|
|
32
|
+
} finally {
|
|
33
|
+
output?.dispose();
|
|
34
|
+
for (const value of views) value.dispose();
|
|
35
|
+
}
|
|
36
|
+
}
|