@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,290 @@
|
|
|
1
|
+
// Sampling — port of mlx-lm's sample_utils.make_sampler /
|
|
2
|
+
// make_logits_processors (temperature, top-p, top-k, min-p, XTC,
|
|
3
|
+
// repetition/presence/frequency penalties, logit bias).
|
|
4
|
+
// All filtering happens on-device; only the chosen token id crosses to JS.
|
|
5
|
+
// Seeded: each step derives a fresh key from (seed, step) so runs are
|
|
6
|
+
// reproducible without sharing global RNG state. (mlx-lm draws XTC's
|
|
7
|
+
// uniform and the categorical from one global stream; we split the
|
|
8
|
+
// per-step key into (xtc, categorical) subkeys instead — deterministic,
|
|
9
|
+
// and the XTC-off path is unchanged.)
|
|
10
|
+
|
|
11
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
12
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
13
|
+
|
|
14
|
+
/** HLG sampling parameters — a piecewise tone curve on the logprobs.
|
|
15
|
+
* See `02d723a:docs/archive/hlg-sampling.md`. Knobs are in nats (the logprob unit). */
|
|
16
|
+
export interface HlgParams {
|
|
17
|
+
/** m — mid-region slope. Folds temperature: m = 1/temperature. */
|
|
18
|
+
gain: number;
|
|
19
|
+
/** w — half-width of the linear mid region. Infinity ⇒ no rolloff (pure temperature). */
|
|
20
|
+
width: number;
|
|
21
|
+
/** β_h — highlight rolloff scale. ≤ 0 ⇒ no shoulder (highlights stay linear). */
|
|
22
|
+
shoulder: number;
|
|
23
|
+
/** β_t — shadow rolloff scale. ≤ 0 ⇒ no toe (shadows stay linear). */
|
|
24
|
+
toe: number;
|
|
25
|
+
/** pivot (middle grey) placement — changes where the curve centers, hence its
|
|
26
|
+
* shape. "top": μ = max(ℓ) − offset. "entropy": μ = Σp·ℓ = −H (center of mass
|
|
27
|
+
* in tonal space). "median": μ = the logprob at the 50% cumulative-mass
|
|
28
|
+
* boundary (auto-levels). */
|
|
29
|
+
pivot?: "top" | "entropy" | "median";
|
|
30
|
+
/** shift applied to the pivot base: μ = base − pivotOffset. */
|
|
31
|
+
pivotOffset?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const HLG_LOG_EPS = 1e-9;
|
|
35
|
+
|
|
36
|
+
/** Pivot (middle grey) μ_base for the tone curve, in logprob units — the same
|
|
37
|
+
* curve, centered three different ways. Operates on the full logprob vector. */
|
|
38
|
+
function hlgPivotBase(
|
|
39
|
+
lp: MlxArray,
|
|
40
|
+
mode: "top" | "entropy" | "median",
|
|
41
|
+
k: <T extends MlxArray>(a: T) => T,
|
|
42
|
+
): MlxArray {
|
|
43
|
+
if (mode === "entropy") {
|
|
44
|
+
// center of mass in tonal space: μ = Σ p·ℓ = −H (p = exp(ℓ); ℓ are logprobs)
|
|
45
|
+
const probs = k(ops.exp(lp));
|
|
46
|
+
return k(ops.sumAxis(k(ops.mul(probs, lp)), -1, true));
|
|
47
|
+
}
|
|
48
|
+
if (mode === "median") {
|
|
49
|
+
// logprob at the 50% cumulative-mass boundary (auto-levels / histogram median)
|
|
50
|
+
const probs = k(ops.exp(lp));
|
|
51
|
+
const idxDesc = k(ops.argsortAxis(k(ops.neg(lp)), -1)); // ascending of −ℓ = ℓ descending
|
|
52
|
+
const sortedProbs = k(ops.takeAlongAxis(probs, idxDesc, -1));
|
|
53
|
+
const sortedLp = k(ops.takeAlongAxis(lp, idxDesc, -1));
|
|
54
|
+
const cum = k(ops.cumsum(sortedProbs, -1));
|
|
55
|
+
const keep = k(ops.greaterEqual(cum, k(ops.scalarLike(0.5, cum))));
|
|
56
|
+
const masked = k(ops.where(keep, sortedLp, k(ops.scalarLike(-Infinity, sortedLp))));
|
|
57
|
+
return k(ops.maxAxis(masked, -1, true)); // first crossover = max logprob of the ≥0.5 suffix
|
|
58
|
+
}
|
|
59
|
+
return k(ops.maxAxis(lp, -1, true)); // "top": the peak
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Remap logprobs through the centered curve g(z), z = ℓ − μ:
|
|
63
|
+
* toe (z < −w): −m·w − m·β_t·ln(1 + (−z − w)/β_t) gentle shadow rolloff
|
|
64
|
+
* mid (|z| ≤ w): m·z contrast gain
|
|
65
|
+
* shoulder(z > w): m·w + m·β_h·ln(1 + ( z − w)/β_h) highlight rolloff
|
|
66
|
+
* Monotone in ℓ ⇒ ranking-preserving (argmax unchanged). With width = ∞ (or
|
|
67
|
+
* β_h, β_t ≤ 0) it returns mulScalar(lp, m) — temperature T = 1/m — bit-exact
|
|
68
|
+
* by construction (the same op the temperature path uses). `-inf` (masked)
|
|
69
|
+
* tokens map to `-inf`. */
|
|
70
|
+
export function applyHlg(lp: MlxArray, p: HlgParams): MlxArray {
|
|
71
|
+
const m = p.gain;
|
|
72
|
+
const hasShoulder = Number.isFinite(p.width) && p.shoulder > 0;
|
|
73
|
+
const hasToe = Number.isFinite(p.width) && p.toe > 0;
|
|
74
|
+
// No-rolloff regime ≡ temperature: identical op to the temperature sampler.
|
|
75
|
+
if (!hasShoulder && !hasToe) return ops.mulScalar(lp, m);
|
|
76
|
+
|
|
77
|
+
const w = p.width;
|
|
78
|
+
const off = p.pivotOffset ?? 0;
|
|
79
|
+
const tmp: MlxArray[] = [];
|
|
80
|
+
const k = <T extends MlxArray>(a: T): T => {
|
|
81
|
+
tmp.push(a);
|
|
82
|
+
return a;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// pivot μ = base(mode) − off ; centered coordinate z = ℓ − μ
|
|
86
|
+
const base = hlgPivotBase(lp, p.pivot ?? "top", k);
|
|
87
|
+
const mu = k(ops.sub(base, k(ops.scalarLike(off, base))));
|
|
88
|
+
const z = k(ops.sub(lp, mu));
|
|
89
|
+
const wC = k(ops.scalarLike(w, lp));
|
|
90
|
+
let g: MlxArray = k(ops.mulScalar(z, m)); // mid: m·z
|
|
91
|
+
|
|
92
|
+
if (hasShoulder) {
|
|
93
|
+
const bh = p.shoulder;
|
|
94
|
+
const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(z, wC)), 1 / bh))));
|
|
95
|
+
const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
|
|
96
|
+
const shoulder = k(ops.add(k(ops.scalarLike(m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bh))));
|
|
97
|
+
g = k(ops.where(k(ops.greaterEqual(z, wC)), shoulder, g));
|
|
98
|
+
}
|
|
99
|
+
if (hasToe) {
|
|
100
|
+
const bt = p.toe;
|
|
101
|
+
const negz = k(ops.neg(z));
|
|
102
|
+
const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(negz, wC)), 1 / bt))));
|
|
103
|
+
const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
|
|
104
|
+
const toe = k(ops.sub(k(ops.scalarLike(-m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bt))));
|
|
105
|
+
g = k(ops.where(k(ops.less(z, k(ops.scalarLike(-w, lp)))), toe, g));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const a of tmp) if (a !== g) a.dispose();
|
|
109
|
+
return g;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Literal HLG OETF (ARIB STD-B67 / ITU-R BT.2100) — the actual transfer
|
|
113
|
+
// function, exact constants. Input L = p/p_max ∈ (0,1] (exposure-normalized: the
|
|
114
|
+
// top token is reference white). Output V ∈ [0,1]:
|
|
115
|
+
// V = √3 · √L for 0 ≤ L ≤ 1/12 (gamma/sqrt: shadows → 0 softly)
|
|
116
|
+
// V = a·ln(12L − b) + c for 1/12 < L ≤ 1 (log: highlights compressed)
|
|
117
|
+
// We sample ∝ V by feeding log(V) to the categorical draw. Monotone in ℓ ⇒
|
|
118
|
+
// ranking-preserving. No knobs — this is HLG itself.
|
|
119
|
+
const HLG_A = 0.17883277;
|
|
120
|
+
const HLG_B = 0.28466892; // 1 − 4a
|
|
121
|
+
const HLG_C = 0.55991073; // 0.5 − a·ln(4a)
|
|
122
|
+
const HLG_SQRT3 = Math.sqrt(3);
|
|
123
|
+
const HLG_KNEE = 1 / 12;
|
|
124
|
+
|
|
125
|
+
export function applyHlgOetf(lp: MlxArray): MlxArray {
|
|
126
|
+
const tmp: MlxArray[] = [];
|
|
127
|
+
const k = <T extends MlxArray>(a: T): T => {
|
|
128
|
+
tmp.push(a);
|
|
129
|
+
return a;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// L = p / p_max = exp(ℓ − ℓmax) ∈ (0, 1]
|
|
133
|
+
const lmax = k(ops.maxAxis(lp, -1, true));
|
|
134
|
+
const L = k(ops.exp(k(ops.sub(lp, lmax))));
|
|
135
|
+
|
|
136
|
+
// lower (L ≤ 1/12): V = √3 · √L
|
|
137
|
+
const lo = k(ops.mulScalar(k(ops.sqrt(L)), HLG_SQRT3));
|
|
138
|
+
// upper (L > 1/12): V = a·ln(12L − b) + c (clamp the arg > 0 for the unused lane)
|
|
139
|
+
const arg = k(ops.maximum(k(ops.sub(k(ops.mulScalar(L, 12)), k(ops.scalarLike(HLG_B, L)))), k(ops.scalarLike(HLG_LOG_EPS, L))));
|
|
140
|
+
const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, L))));
|
|
141
|
+
const V = k(ops.where(k(ops.greaterEqual(L, k(ops.scalarLike(HLG_KNEE, L)))), hi, lo));
|
|
142
|
+
|
|
143
|
+
// sample ∝ V → logits = log(V)
|
|
144
|
+
const out = ops.log(k(ops.maximum(V, k(ops.scalarLike(HLG_LOG_EPS, V)))));
|
|
145
|
+
for (const a of tmp) a.dispose();
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** OOTF system gamma from nominal peak display luminance L_W (cd/m²).
|
|
150
|
+
* γ = 1.2 + 0.42·log10(L_W/1000); γ = 1.2 exactly at L_W = 1000. */
|
|
151
|
+
export function hlgGammaForLw(lw: number): number {
|
|
152
|
+
return 1.2 + 0.42 * Math.log10(lw / 1000);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Literal HLG EOTF (signal → display linear) = inverse OETF then OOTF — the
|
|
156
|
+
// DECODE direction. Treat p/p_max as the signal E'. The inverse OETF squares the
|
|
157
|
+
// lower half (E = E'²/3) so the tail is SUPPRESSED (the opposite of the OETF,
|
|
158
|
+
// which expands it). The OOTF on a single-"pixel" (grayscale) distribution has
|
|
159
|
+
// no colour channels for luminance to couple, so it reduces exactly to a gamma
|
|
160
|
+
// power law E^γ — i.e. temperature. Sample ∝ E^γ ⇒ logits = γ·log(E).
|
|
161
|
+
export function applyHlgEotf(lp: MlxArray, gamma: number): MlxArray {
|
|
162
|
+
const tmp: MlxArray[] = [];
|
|
163
|
+
const k = <T extends MlxArray>(a: T): T => {
|
|
164
|
+
tmp.push(a);
|
|
165
|
+
return a;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const d = k(ops.sub(lp, k(ops.maxAxis(lp, -1, true)))); // ℓ − ℓmax ≤ 0
|
|
169
|
+
const Ep = k(ops.exp(d)); // signal E' = p/p_max ∈ (0, 1]
|
|
170
|
+
// log E from the inverse OETF, computed stably per branch (the deep tail
|
|
171
|
+
// underflows if E is formed directly, so the lower branch stays in log-space):
|
|
172
|
+
// E' ≤ 1/2: E = E'²/3 → log E = 2·(ℓ−ℓmax) − ln3 (exact)
|
|
173
|
+
// E' > 1/2: E = (exp((E'−c)/a)+b)/12 → log E = log(that) (well-conditioned)
|
|
174
|
+
const logElo = k(ops.sub(k(ops.mulScalar(d, 2)), k(ops.scalarLike(Math.log(3), d))));
|
|
175
|
+
const hiArg = k(ops.exp(k(ops.mulScalar(k(ops.sub(Ep, k(ops.scalarLike(HLG_C, Ep)))), 1 / HLG_A))));
|
|
176
|
+
const hiE = k(ops.mulScalar(k(ops.add(hiArg, k(ops.scalarLike(HLG_B, Ep)))), 1 / 12));
|
|
177
|
+
const logEhi = k(ops.log(hiE));
|
|
178
|
+
const logE = k(ops.where(k(ops.greaterEqual(Ep, k(ops.scalarLike(0.5, Ep)))), logEhi, logElo));
|
|
179
|
+
// OOTF (grayscale) → gamma: sample ∝ E^γ ⇒ logits = γ·log(E)
|
|
180
|
+
const out = ops.mulScalar(logE, gamma);
|
|
181
|
+
for (const a of tmp) a.dispose();
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// The FULL HLG chain: OETF signal shape, THEN OOTF scaling.
|
|
186
|
+
// 1. E = p/p_max ∈ (0,1] (top token = the max-brightness reference)
|
|
187
|
+
// 2. E' = √(3E) for E ≤ 1/12 (gamma/√ toe below the knee)
|
|
188
|
+
// = a·ln(12E−b)+c for E > 1/12 (log highlights above the knee)
|
|
189
|
+
// 3. R_d = α · E'^γ (OOTF: α = max brightness, scales everything
|
|
190
|
+
// under it; γ = 1.2+0.42·log10(L_W/1000))
|
|
191
|
+
// R_d are the final logits → categorical. α > 0 ⇒ monotone (ranking preserved).
|
|
192
|
+
export function applyHlgPipeline(lp: MlxArray, alpha: number, gamma: number): MlxArray {
|
|
193
|
+
const tmp: MlxArray[] = [];
|
|
194
|
+
const k = <T extends MlxArray>(a: T): T => {
|
|
195
|
+
tmp.push(a);
|
|
196
|
+
return a;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// 1. E = p/p_max ∈ (0,1]
|
|
200
|
+
const E = k(ops.exp(k(ops.sub(lp, k(ops.maxAxis(lp, -1, true))))));
|
|
201
|
+
// 2. OETF: √(3E) below the knee, a·ln(12E−b)+c above
|
|
202
|
+
const lo = k(ops.sqrt(k(ops.mulScalar(E, 3))));
|
|
203
|
+
const arg = k(ops.maximum(k(ops.sub(k(ops.mulScalar(E, 12)), k(ops.scalarLike(HLG_B, E)))), k(ops.scalarLike(HLG_LOG_EPS, E))));
|
|
204
|
+
const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, E))));
|
|
205
|
+
const Eprime = k(ops.where(k(ops.greaterEqual(E, k(ops.scalarLike(HLG_KNEE, E)))), hi, lo));
|
|
206
|
+
// 3. OOTF: R_d = α · E'^γ = α · exp(γ·log E')
|
|
207
|
+
const EpGamma = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(Eprime, k(ops.scalarLike(HLG_LOG_EPS, Eprime)))))), gamma))));
|
|
208
|
+
const out = ops.mulScalar(EpGamma, alpha);
|
|
209
|
+
for (const a of tmp) a.dispose();
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── User-specified HLGShaper (windowed-anchor input) ────────────────────────
|
|
214
|
+
// logit → windowed-anchor signal x∈[0,1] (top W nats span the curve; min-max
|
|
215
|
+
// over the 262k vocab dumped every candidate into the shoulder, so we anchor at
|
|
216
|
+
// the top instead) → piecewise OETF (log shoulder above x_m, power mid, CUBIC
|
|
217
|
+
// toe that suppresses to 0) → OOTF (normalize to peak, ^γ) → ×out_scale →
|
|
218
|
+
// softmax. Geometry constants derived once from the default knobs, exactly as
|
|
219
|
+
// HLGShaper.__init__ does (cubic toe coeffs from a 2×2 solve).
|
|
220
|
+
export interface HlgShaperParams {
|
|
221
|
+
lw?: number; // L_W (cd/m²) → OOTF γ
|
|
222
|
+
outScale?: number; // explicit override; default auto-derived from targetGap/refGap
|
|
223
|
+
targetGap?: number; // desired top-1-to-reference final-logit gap (sets sharpness, W-independent)
|
|
224
|
+
refGap?: number; // reference token sits this many nats below the top
|
|
225
|
+
window?: number; // W: nats below the top spanning the curve
|
|
226
|
+
xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
|
|
227
|
+
sM?: number; // mid sharpness — how hard above-median tokens are elevated
|
|
228
|
+
A?: number; // shoulder compression — how hard confidence is tamed
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function applyHlgShaper(lp: MlxArray, opts: HlgShaperParams = {}): MlxArray {
|
|
232
|
+
const lw = opts.lw ?? 1200, window = opts.window ?? 10;
|
|
233
|
+
const xM = opts.xM ?? 0.55, yM = opts.yM ?? 0.5, xFloor = opts.xFloor ?? 0.2, yFloor = opts.yFloor ?? 0.18;
|
|
234
|
+
const p = opts.p ?? 2.0, sM = opts.sM ?? 0.7, A = opts.A ?? 0.35;
|
|
235
|
+
const targetGap = opts.targetGap ?? 15, refGap = opts.refGap ?? 4;
|
|
236
|
+
// geometry derived per call (cheap scalar math), exactly as HLGShaper.__init__
|
|
237
|
+
const dxf = xM - xFloor;
|
|
238
|
+
const kc = (yM - sM * dxf - yFloor) / Math.pow(dxf, p); // mid reaches y_floor
|
|
239
|
+
const sFloor = sM + kc * p * Math.pow(dxf, p - 1); // mid slope at the toe join
|
|
240
|
+
const det = -Math.pow(xFloor, 4); // solve [[xf³,xf²],[3xf²,2xf]]·[e,f]=[y_floor,s_floor]
|
|
241
|
+
const ec = (yFloor * (2 * xFloor) - xFloor ** 2 * sFloor) / det;
|
|
242
|
+
const fc = (xFloor ** 3 * sFloor - yFloor * (3 * xFloor ** 2)) / det;
|
|
243
|
+
const yPeak = yM + A * Math.log(1 + (sM / A) * (1 - xM));
|
|
244
|
+
const gamma = 1.2 + 0.42 * Math.log10(Math.max(lw, 1e-3) / 1000);
|
|
245
|
+
|
|
246
|
+
// out_scale AUTO-derived so the top-1-to-reference final-logit gap = targetGap,
|
|
247
|
+
// INDEPENDENT of W — decouples the two knobs so W is a clean 1-D sweep. The
|
|
248
|
+
// reference token sits refGap nats below the top; its post-shape value is the
|
|
249
|
+
// scalar curve evaluated in JS (no device cost). Calibrated so W=5 ⇒ os ≈ 18.
|
|
250
|
+
const oetfS = (xx: number): number => {
|
|
251
|
+
let yy: number;
|
|
252
|
+
if (xx >= xM) yy = yM + A * Math.log(Math.max(1 + (sM / A) * (xx - xM), 1e-9));
|
|
253
|
+
else if (xx >= xFloor) yy = yM - sM * (xM - xx) - kc * Math.pow(Math.max(xM - xx, 0), p);
|
|
254
|
+
else yy = ec * xx ** 3 + fc * xx ** 2;
|
|
255
|
+
return Math.max(yy, 0);
|
|
256
|
+
};
|
|
257
|
+
const shapeS = (xx: number): number => Math.pow(Math.max(oetfS(xx) / yPeak, 1e-9), gamma);
|
|
258
|
+
const xRef = Math.max(0, Math.min(1, 1 - refGap / window));
|
|
259
|
+
const outScale = opts.outScale ?? targetGap / Math.max(1e-6, 1 - shapeS(xRef));
|
|
260
|
+
|
|
261
|
+
const tmp: MlxArray[] = [];
|
|
262
|
+
const k = <T extends MlxArray>(a: T): T => {
|
|
263
|
+
tmp.push(a);
|
|
264
|
+
return a;
|
|
265
|
+
};
|
|
266
|
+
const C = (v: number, like: MlxArray): MlxArray => k(ops.scalarLike(v, like));
|
|
267
|
+
|
|
268
|
+
// x = clamp((ℓ − ℓmax)/W + 1, 0, 1) — windowed anchor at the top
|
|
269
|
+
const lmax = k(ops.maxAxis(lp, -1, true));
|
|
270
|
+
const x = k(ops.clip(k(ops.add(k(ops.mulScalar(k(ops.sub(lp, lmax)), 1 / window)), C(1, lp))), C(0, lp), C(1, lp)));
|
|
271
|
+
|
|
272
|
+
// OETF: up (x≥x_m) log shoulder, mid power, toe (x<x_floor) cubic suppress
|
|
273
|
+
const upArg = k(ops.maximum(k(ops.add(C(1, x), k(ops.mulScalar(k(ops.sub(x, C(xM, x))), sM / A)))), C(1e-9, x)));
|
|
274
|
+
const up = k(ops.add(C(yM, x), k(ops.mulScalar(k(ops.log(upArg)), A))));
|
|
275
|
+
const dm = k(ops.sub(C(xM, x), x));
|
|
276
|
+
const dmPow = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(dm, C(1e-9, x))))), p))));
|
|
277
|
+
const mid = k(ops.sub(k(ops.sub(C(yM, x), k(ops.mulScalar(dm, sM)))), k(ops.mulScalar(dmPow, kc))));
|
|
278
|
+
const x2 = k(ops.square(x));
|
|
279
|
+
const x3 = k(ops.mul(x, x2));
|
|
280
|
+
const toe = k(ops.add(k(ops.mulScalar(x3, ec)), k(ops.mulScalar(x2, fc))));
|
|
281
|
+
const upMid = k(ops.where(k(ops.greaterEqual(x, C(xM, x))), up, mid));
|
|
282
|
+
const y = k(ops.maximum(k(ops.where(k(ops.greaterEqual(x, C(xFloor, x))), upMid, toe)), C(0, x)));
|
|
283
|
+
|
|
284
|
+
// OOTF: r = (max(y/y_peak, 1e-9))^γ ; then softmax(r · out_scale)
|
|
285
|
+
const yn = k(ops.maximum(k(ops.mulScalar(y, 1 / yPeak)), C(1e-9, y)));
|
|
286
|
+
const r = k(ops.exp(k(ops.mulScalar(k(ops.log(yn)), gamma))));
|
|
287
|
+
const out = ops.mulScalar(r, outScale);
|
|
288
|
+
for (const a of tmp) a.dispose();
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Sampling — port of mlx-lm's sample_utils.make_sampler /
|
|
2
|
+
// make_logits_processors (temperature, top-p, top-k, min-p, XTC,
|
|
3
|
+
// repetition/presence/frequency penalties, logit bias).
|
|
4
|
+
// All filtering happens on-device; only the chosen token id crosses to JS.
|
|
5
|
+
// Seeded: each step derives a fresh key from (seed, step) so runs are
|
|
6
|
+
// reproducible without sharing global RNG state. (mlx-lm draws XTC's
|
|
7
|
+
// uniform and the categorical from one global stream; we split the
|
|
8
|
+
// per-step key into (xtc, categorical) subkeys instead — deterministic,
|
|
9
|
+
// and the XTC-off path is unchanged.)
|
|
10
|
+
|
|
11
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
12
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
13
|
+
import { LogitsProcessor,LogitsProcessorOptions } from "./types";
|
|
14
|
+
|
|
15
|
+
/** Start of the recent-token window, matching Python's `tokens[-context_size:]`
|
|
16
|
+
* slice semantics exactly (context_size 0 ⇒ `[-0:]` ⇒ the WHOLE history). */
|
|
17
|
+
function windowStart(n: number, contextSize: number): number {
|
|
18
|
+
return contextSize === 0 ? 0 : Math.max(0, n - contextSize);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Retain only tokens an enabled processor can inspect. Bias uses no history.
|
|
22
|
+
* Zero-sized windows mean unlimited history, matching Python's [-0:]. */
|
|
23
|
+
export function logitsHistoryLimit(options: LogitsProcessorOptions): number {
|
|
24
|
+
let limit = 0;
|
|
25
|
+
for (const [penalty, context = 20] of [
|
|
26
|
+
[options.repetitionPenalty, options.repetitionContextSize],
|
|
27
|
+
[options.presencePenalty, options.presenceContextSize],
|
|
28
|
+
[options.frequencyPenalty, options.frequencyContextSize],
|
|
29
|
+
]) {
|
|
30
|
+
if (penalty === undefined || penalty === 0) continue;
|
|
31
|
+
// Preserve existing processor behavior for unusual programmatic values.
|
|
32
|
+
if (!Number.isSafeInteger(context) || context <= 0) return Infinity;
|
|
33
|
+
limit = Math.max(limit, context);
|
|
34
|
+
}
|
|
35
|
+
return limit;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function makeLogitsProcessors(opts: LogitsProcessorOptions = {}): LogitsProcessor[] {
|
|
39
|
+
const out: LogitsProcessor[] = [];
|
|
40
|
+
const {
|
|
41
|
+
logitBias,
|
|
42
|
+
repetitionPenalty, repetitionContextSize = 20,
|
|
43
|
+
presencePenalty, presenceContextSize = 20,
|
|
44
|
+
frequencyPenalty, frequencyContextSize = 20,
|
|
45
|
+
} = opts;
|
|
46
|
+
|
|
47
|
+
// logit_bias first, as in mlx-lm's make_logits_processors. Reference:
|
|
48
|
+
// `logits.at[:, indices].add(values)` — dict keys are unique, so a
|
|
49
|
+
// gather → add → put round-trip is exactly equivalent to the scatter-add.
|
|
50
|
+
const biasIds = logitBias ? Object.keys(logitBias).map(Number) : [];
|
|
51
|
+
if (logitBias && biasIds.length > 0) {
|
|
52
|
+
const biasVals = Float32Array.from(biasIds.map((id) => logitBias[id]!));
|
|
53
|
+
out.push((_tokens, logits) => {
|
|
54
|
+
const K = biasIds.length;
|
|
55
|
+
const idx = ops.fromInt32(biasIds, [1, K]);
|
|
56
|
+
const vals32 = MlxArray.fromFloat32(biasVals, [1, K]);
|
|
57
|
+
const vals = vals32.astype(logits.dtype);
|
|
58
|
+
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
59
|
+
const biased = ops.add(selected, vals);
|
|
60
|
+
const updated = ops.putAlongAxis(logits, idx, biased, -1);
|
|
61
|
+
for (const a of [idx, vals32, vals, selected, biased]) a.dispose();
|
|
62
|
+
return updated;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (repetitionPenalty !== undefined && repetitionPenalty !== 0) {
|
|
67
|
+
if (repetitionPenalty < 0)
|
|
68
|
+
throw new Error("repetitionPenalty must be non-negative");
|
|
69
|
+
out.push((tokens, logits) => {
|
|
70
|
+
if (!tokens) return logits;
|
|
71
|
+
const n = tokens.shape[0]!;
|
|
72
|
+
if (n === 0) return logits;
|
|
73
|
+
const start = windowStart(n, repetitionContextSize);
|
|
74
|
+
const recent = tokens.slice([start], [n]);
|
|
75
|
+
const idx = ops.reshape(recent, [1, n - start]);
|
|
76
|
+
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
77
|
+
const zero = ops.scalarLike(0, selected);
|
|
78
|
+
const isNeg = ops.less(selected, zero);
|
|
79
|
+
const timesP = ops.mulScalar(selected, repetitionPenalty);
|
|
80
|
+
const pen = ops.scalarLike(repetitionPenalty, selected);
|
|
81
|
+
const overP = ops.div(selected, pen);
|
|
82
|
+
const penalized = ops.where(isNeg, timesP, overP);
|
|
83
|
+
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
84
|
+
for (const a of [recent, idx, selected, zero, isNeg, timesP, pen, overP, penalized])
|
|
85
|
+
a.dispose();
|
|
86
|
+
return updated;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// make_presence_penalty: `logits[:, tokens] -= penalty` — a plain
|
|
91
|
+
// fancy-index assignment, so duplicate occurrences all write the SAME
|
|
92
|
+
// value (original − penalty): the penalty applies once per distinct token.
|
|
93
|
+
if (presencePenalty !== undefined && presencePenalty !== 0) {
|
|
94
|
+
out.push((tokens, logits) => {
|
|
95
|
+
if (!tokens) return logits;
|
|
96
|
+
const n = tokens.shape[0]!;
|
|
97
|
+
if (n === 0) return logits;
|
|
98
|
+
const start = windowStart(n, presenceContextSize);
|
|
99
|
+
const recent = tokens.slice([start], [n]);
|
|
100
|
+
const idx = ops.reshape(recent, [1, n - start]);
|
|
101
|
+
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
102
|
+
const pen = ops.scalarLike(presencePenalty, selected);
|
|
103
|
+
const penalized = ops.sub(selected, pen);
|
|
104
|
+
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
105
|
+
for (const a of [recent, idx, selected, pen, penalized]) a.dispose();
|
|
106
|
+
return updated;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// make_frequency_penalty: `logits.at[:, tokens].subtract(penalty)` — a
|
|
111
|
+
// scatter-subtract that ACCUMULATES over duplicates: each token loses
|
|
112
|
+
// penalty × (occurrence count in the window). We compute the count per
|
|
113
|
+
// position ([m,m] equality matrix summed over a row — m ≤ contextSize, tiny)
|
|
114
|
+
// so every duplicate writes the identical final value and a put_along_axis
|
|
115
|
+
// reproduces the scatter-accumulate exactly.
|
|
116
|
+
if (frequencyPenalty !== undefined && frequencyPenalty !== 0) {
|
|
117
|
+
out.push((tokens, logits) => {
|
|
118
|
+
if (!tokens) return logits;
|
|
119
|
+
const n = tokens.shape[0]!;
|
|
120
|
+
if (n === 0) return logits;
|
|
121
|
+
const start = windowStart(n, frequencyContextSize);
|
|
122
|
+
const m = n - start;
|
|
123
|
+
const recent = tokens.slice([start], [n]);
|
|
124
|
+
const col = ops.reshape(recent, [m, 1]);
|
|
125
|
+
const idx = ops.reshape(recent, [1, m]);
|
|
126
|
+
const eq = ops.equal(col, idx); // [m, m]
|
|
127
|
+
const counts = ops.sumAxis(eq, -1, false); // [m] occurrences of tokens[i]
|
|
128
|
+
const countsF = counts.astype(logits.dtype);
|
|
129
|
+
const countsRow = ops.reshape(countsF, [1, m]);
|
|
130
|
+
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
131
|
+
const pen = ops.scalarLike(frequencyPenalty, selected);
|
|
132
|
+
const penTotal = ops.mul(countsRow, pen); // penalty × count
|
|
133
|
+
const penalized = ops.sub(selected, penTotal);
|
|
134
|
+
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
135
|
+
for (const a of [recent, col, idx, eq, counts, countsF, countsRow, selected, pen, penTotal, penalized])
|
|
136
|
+
a.dispose();
|
|
137
|
+
return updated;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Sampling — port of mlx-lm's sample_utils.make_sampler /
|
|
2
|
+
// make_logits_processors (temperature, top-p, top-k, min-p, XTC,
|
|
3
|
+
// repetition/presence/frequency penalties, logit bias).
|
|
4
|
+
// All filtering happens on-device; only the chosen token id crosses to JS.
|
|
5
|
+
// Seeded: each step derives a fresh key from (seed, step) so runs are
|
|
6
|
+
// reproducible without sharing global RNG state. (mlx-lm draws XTC's
|
|
7
|
+
// uniform and the categorical from one global stream; we split the
|
|
8
|
+
// per-step key into (xtc, categorical) subkeys instead — deterministic,
|
|
9
|
+
// and the XTC-off path is unchanged.)
|
|
10
|
+
|
|
11
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
12
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
13
|
+
import { applyCurve } from "./curve";
|
|
14
|
+
import { applyMinP,applyTopK,applyTopP,applyXtc } from "./filters";
|
|
15
|
+
import { HlgParams,applyHlg,applyHlgEotf,applyHlgOetf,applyHlgPipeline,applyHlgShaper,hlgGammaForLw } from "./hlg";
|
|
16
|
+
import { Sampler,SamplerOptions } from "./types";
|
|
17
|
+
|
|
18
|
+
const GOLDEN = 0x9e3779b97f4a7c15n;
|
|
19
|
+
|
|
20
|
+
/** The seeded per-step key: (seed, step) mixed by the golden-ratio constant. Also
|
|
21
|
+
* the derivation behind KeyStream (draft.ts). */
|
|
22
|
+
export function stepKey(seed: number, step: number): MlxArray {
|
|
23
|
+
const mixed = (BigInt(seed) ^ ((BigInt(step) + 1n) * GOLDEN)) & 0xffffffffffffffffn;
|
|
24
|
+
return ops.randomKey(mixed);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function makeSampler(opts: SamplerOptions = {}): Sampler {
|
|
28
|
+
const {
|
|
29
|
+
temperature = 0, topP = 0, topK = 0, minP = 0, minTokensToKeep = 1,
|
|
30
|
+
xtcProbability = 0, xtcThreshold = 0, xtcSpecialTokens = [],
|
|
31
|
+
seed = 0, hlg, curve,
|
|
32
|
+
} = opts;
|
|
33
|
+
|
|
34
|
+
// v2 curve sampler: the drawn log-prob transfer curve REPLACES temperature +
|
|
35
|
+
// softmax. Stochastic and seeded by design (the curve IS the sampling shape),
|
|
36
|
+
// so it overrides the greedy default — the designer wants variety across N.
|
|
37
|
+
if (curve) {
|
|
38
|
+
return (lp, step) => {
|
|
39
|
+
const shaped = applyCurve(lp, curve);
|
|
40
|
+
const tok = ops.randomCategorical(shaped, stepKey(seed, step));
|
|
41
|
+
shaped.dispose();
|
|
42
|
+
return tok;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Greedy: HLG is a no-op (a monotone curve cannot move the argmax), so the
|
|
47
|
+
// greedy path is untouched whether or not HLG is enabled.
|
|
48
|
+
if (temperature === 0)
|
|
49
|
+
return (lp) => ops.argmaxAxis(lp, -1);
|
|
50
|
+
|
|
51
|
+
// HLG is a REPLACEMENT sampler: when enabled, the tone curve IS the whole
|
|
52
|
+
// post-logits step — its toe does the tail control that top_p/top_k would, so
|
|
53
|
+
// they are NOT applied. Otherwise we do exactly what we used to: top_p, top_k,
|
|
54
|
+
// then temperature scaling. (Temperature still folds into the mid gain m = 1/T
|
|
55
|
+
// unless the config sets an explicit gain.)
|
|
56
|
+
if (hlg?.enabled === true) {
|
|
57
|
+
const useOetf = hlg.oetf === true;
|
|
58
|
+
const useEotf = hlg.eotf === true;
|
|
59
|
+
const usePipeline = hlg.pipeline === true;
|
|
60
|
+
const eotfGamma = hlgGammaForLw(hlg.lw ?? 1000);
|
|
61
|
+
const alpha = hlg.maxBrightness ?? 5;
|
|
62
|
+
const params: HlgParams = {
|
|
63
|
+
gain: hlg.gain ?? 1 / temperature,
|
|
64
|
+
width: hlg.width,
|
|
65
|
+
shoulder: hlg.shoulder,
|
|
66
|
+
toe: hlg.toe,
|
|
67
|
+
pivot: hlg.pivot,
|
|
68
|
+
pivotOffset: hlg.pivotOffset,
|
|
69
|
+
};
|
|
70
|
+
return (lp, step) => {
|
|
71
|
+
const scaled = hlg.shaper === true
|
|
72
|
+
? applyHlgShaper(lp, { lw: hlg.lw, outScale: hlg.maxBrightness, window: hlg.window, sM: hlg.sM, A: hlg.shoulderA, targetGap: hlg.targetGap, refGap: hlg.refGap, xM: hlg.xM, yM: hlg.yM, xFloor: hlg.xFloor, yFloor: hlg.yFloor, p: hlg.p })
|
|
73
|
+
: usePipeline ? applyHlgPipeline(lp, alpha, eotfGamma)
|
|
74
|
+
: useEotf ? applyHlgEotf(lp, eotfGamma) : useOetf ? applyHlgOetf(lp) : applyHlg(lp, params);
|
|
75
|
+
const key = stepKey(seed, step);
|
|
76
|
+
const tok = ops.randomCategorical(scaled, key);
|
|
77
|
+
scaled.dispose();
|
|
78
|
+
key.dispose();
|
|
79
|
+
return tok;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Filter chain order matches mlx-lm's make_sampler: top_p → min_p → xtc →
|
|
84
|
+
// top_k, then categorical(logprobs / temperature).
|
|
85
|
+
return (lp, step) => {
|
|
86
|
+
let cur = lp;
|
|
87
|
+
const owned: MlxArray[] = [];
|
|
88
|
+
let key = stepKey(seed, step);
|
|
89
|
+
if (topP > 0 && topP < 1) { cur = applyTopP(cur, topP); owned.push(cur); }
|
|
90
|
+
if (minP !== 0) { cur = applyMinP(cur, minP, minTokensToKeep); owned.push(cur); }
|
|
91
|
+
if (xtcProbability > 0) {
|
|
92
|
+
// Split the step key: subkey 0 → XTC's uniform, subkey 1 → categorical.
|
|
93
|
+
const split = ops.randomSplitNum(key, 2);
|
|
94
|
+
const row0 = split.slice([0, 0], [1, 2]);
|
|
95
|
+
const row1 = split.slice([1, 0], [2, 2]);
|
|
96
|
+
const xtcKey = ops.reshape(row0, [2]);
|
|
97
|
+
key.dispose();
|
|
98
|
+
key = ops.reshape(row1, [2]);
|
|
99
|
+
for (const a of [split, row0, row1]) a.dispose();
|
|
100
|
+
cur = applyXtc(cur, xtcProbability, xtcThreshold, xtcSpecialTokens, xtcKey);
|
|
101
|
+
owned.push(cur);
|
|
102
|
+
xtcKey.dispose();
|
|
103
|
+
}
|
|
104
|
+
if (topK > 0) { cur = applyTopK(cur, topK); owned.push(cur); }
|
|
105
|
+
const scaled = ops.mulScalar(cur, 1 / temperature);
|
|
106
|
+
const tok = ops.randomCategorical(scaled, key);
|
|
107
|
+
scaled.dispose();
|
|
108
|
+
key.dispose();
|
|
109
|
+
for (const a of owned) a.dispose();
|
|
110
|
+
return tok;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** logits [..., V] → logprobs [..., V] (logits - logsumexp). */
|
|
115
|
+
export function toLogprobs(logits: MlxArray): MlxArray {
|
|
116
|
+
const lse = ops.logsumexpAxis(logits, -1, true);
|
|
117
|
+
const out = ops.sub(logits, lse);
|
|
118
|
+
lse.dispose();
|
|
119
|
+
return out;
|
|
120
|
+
}
|