mlx-bun 0.5.0 → 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/README.md +1449 -109
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +7 -5
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +10 -10
- package/src/{serve → server}/chat-stage.ts +14 -14
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +33 -41
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +25 -82
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +6 -8
- package/src/{serve → server}/request-prep.ts +47 -50
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -107
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
- package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -2054
- package/docs/design/decode-speed-program.md +0 -2404
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -821
- package/docs/design/kv-cache.md +0 -993
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -2129
- package/docs/design/turboquant.md +0 -2225
- package/docs/design/unified-engine-frontier-plan.md +0 -1987
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -593
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/public-readiness-handoff.md +0 -244
- package/docs/planning/public-readiness.md +0 -149
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3587
- package/docs/reference/cli.md +0 -646
- package/docs/reference/distribution.md +0 -380
- package/docs/reference/environment.md +0 -494
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -688
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -346
- package/docs/reference/server-api.md +0 -1945
- package/docs/reference/server-config.md +0 -973
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/audiotoolbox.ts +0 -112
- package/src/audio/conformer.ts +0 -655
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/mic-capture.ts +0 -98
- package/src/audio/silero-vad.ts +0 -379
- package/src/audio/transcode.ts +0 -67
- package/src/audio/whisper-decode.ts +0 -774
- package/src/audio/whisper-fast.ts +0 -732
- package/src/audio/whisper-format.ts +0 -73
- package/src/audio/whisper-mel.ts +0 -185
- package/src/audio/whisper-timing.ts +0 -274
- package/src/audio/whisper-tokenizer.ts +0 -239
- package/src/audio/whisper-transcribe.ts +0 -410
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -129
- package/src/backends/mlx/batch-group.ts +0 -1874
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -107
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/encoder-cache.ts +0 -25
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -58
- package/src/backends/mlx/fill-group.ts +0 -497
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -174
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -161
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/mixed-iteration.ts +0 -62
- package/src/backends/mlx/model-prompt.ts +0 -178
- package/src/backends/mlx/model-serving.ts +0 -80
- package/src/backends/mlx/paged-cache-codec.ts +0 -27
- package/src/backends/mlx/prefill-cohort.ts +0 -100
- package/src/backends/mlx/prefill-policy.ts +0 -26
- package/src/backends/mlx/prefill-rows.ts +0 -244
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/prompt-input.ts +0 -29
- package/src/backends/mlx/qwen-prompt-input.ts +0 -40
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -54
- package/src/backends/mlx/rollback.ts +0 -92
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -251
- package/src/backends/mlx/speculative-group.ts +0 -438
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -131
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3490
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -70
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/object-cache.ts +0 -8
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -261
- package/src/contracts/prefix-cache.ts +0 -33
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -54
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -64
- package/src/engine/execution-tasks.ts +0 -44
- package/src/engine/namespaced-cache.ts +0 -13
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -92
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -463
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1352
- package/src/grammar.ts +0 -604
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -45
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -279
- package/src/kv-store.ts +0 -1135
- package/src/lab/README.md +0 -22
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-attention.ts +0 -117
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
- package/src/lab/paged-kv/paged-kv.ts +0 -336
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -54
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -425
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -531
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/normalized-argmax.ts +0 -116
- package/src/mlx/ops.ts +0 -1108
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -94
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -57
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -215
- package/src/model/fingerprint.ts +0 -45
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2370
- package/src/model/gemma4.ts +0 -1395
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -70
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -468
- package/src/model/quantized-append-attention.ts +0 -31
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -250
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -881
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -110
- package/src/model/token-groups.ts +0 -66
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -89
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/model/whisper.ts +0 -435
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native/mic_capture.swift +0 -92
- package/src/native-pack.ts +0 -163
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1940
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -682
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -77
- package/src/safetensors.ts +0 -165
- package/src/sampler.ts +0 -1012
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/audio-routes.ts +0 -323
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -537
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -49
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -161
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/serve/transcription-server.ts +0 -64
- package/src/serve/transcription-service.ts +0 -502
- package/src/server.ts +0 -1282
- package/src/spec/assistant-rows.ts +0 -93
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -318
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -226
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -230
- package/src/spec/qwen-mtp-source.ts +0 -386
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -587
- package/src/spec/source.ts +0 -228
- package/src/spec/two-model-rows.ts +0 -62
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -431
- package/src/ssd-durability.ts +0 -209
- package/src/storage/host-buffer.ts +0 -24
- package/src/storage/kv-writer.ts +0 -83
- package/src/storage/kv-writer.worker.js +0 -264
- package/src/storage/retention-policy.ts +0 -37
- package/src/tiered-prompt-cache.ts +0 -45
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -176
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -409
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -233
- package/src/vision/qwen3vl-tower.ts +0 -566
- package/src/vision/siglip.ts +0 -607
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2155
- package/src/web/app.js +0 -5863
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1060
- package/src/web/src/composer.ts +0 -962
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/src/voice.ts +0 -141
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/{serve → server}/generated-token-history.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
package/src/sampler.ts
DELETED
|
@@ -1,1012 +0,0 @@
|
|
|
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 { Dtype } from "./mlx/ffi";
|
|
12
|
-
import { normalizedArgmax } from "./mlx/normalized-argmax";
|
|
13
|
-
import { MlxArray } from "./mlx/array";
|
|
14
|
-
import * as ops from "./mlx/ops";
|
|
15
|
-
import type { TokenLogprobs } from "./contracts/generation";
|
|
16
|
-
import type { SampledToken, SamplingSession } from "./contracts/sampling";
|
|
17
|
-
import { applyCurve, type CurveParams } from "./lab/curve/curve-sampler";
|
|
18
|
-
|
|
19
|
-
/** Resolved HLG sampling config (the user-facing knobs). The mid gain is NOT
|
|
20
|
-
* here — it folds from temperature (m = 1/T) when the sampler is built. */
|
|
21
|
-
export interface HlgConfig {
|
|
22
|
-
enabled: boolean;
|
|
23
|
-
width: number;
|
|
24
|
-
shoulder: number;
|
|
25
|
-
toe: number;
|
|
26
|
-
pivot?: "top" | "entropy" | "median";
|
|
27
|
-
pivotOffset: number;
|
|
28
|
-
/** Use the LITERAL HLG OETF (gamma below 1/12, log above) instead of the
|
|
29
|
-
* parametric toe/mid/shoulder curve. Ignores gain/width/shoulder/toe/pivot. */
|
|
30
|
-
oetf?: boolean;
|
|
31
|
-
/** Use the LITERAL HLG EOTF (inverse OETF → OOTF gamma) — the decode/display
|
|
32
|
-
* direction (suppresses the tail). Ignores the parametric knobs. */
|
|
33
|
-
eotf?: boolean;
|
|
34
|
-
/** EOTF only: nominal peak display luminance L_W (cd/m²) → OOTF gamma.
|
|
35
|
-
* Default 1000 (γ = 1.2). Lower = flatter (more diverse), higher = sharper. */
|
|
36
|
-
lw?: number;
|
|
37
|
-
/** Use the FULL HLG chain: OETF signal shape → OOTF scaling (applyHlgPipeline).
|
|
38
|
-
* γ from `lw`. Ignores the parametric knobs. */
|
|
39
|
-
pipeline?: boolean;
|
|
40
|
-
/** Pipeline only: α = max brightness — the top logit the OOTF scales everything
|
|
41
|
-
* under ("the most confidence we want"). Default 5. For the shaper, reused as
|
|
42
|
-
* `out_scale` (default 12). */
|
|
43
|
-
maxBrightness?: number;
|
|
44
|
-
/** Use the user-specified HLGShaper (windowed anchor → piecewise OETF with a
|
|
45
|
-
* cubic suppress-toe → OOTF → ×out_scale). `lw`→L_W, `maxBrightness`→out_scale. */
|
|
46
|
-
shaper?: boolean;
|
|
47
|
-
/** Shaper only: W = nats of headroom below the top logit that span the curve
|
|
48
|
-
* (`x = clamp((ℓ−ℓmax)/W + 1, 0, 1)`). Default 10. */
|
|
49
|
-
window?: number;
|
|
50
|
-
/** Shaper only: s_m — mid sharpness (how hard above-median tokens are elevated). */
|
|
51
|
-
sM?: number;
|
|
52
|
-
/** Shaper only: A — shoulder compression (how hard top-end confidence is tamed). */
|
|
53
|
-
shoulderA?: number;
|
|
54
|
-
/** Shaper only: target top-to-reference logit gap (out_scale auto-derives from this
|
|
55
|
-
* so it's decoupled from W). Default 15. */
|
|
56
|
-
targetGap?: number;
|
|
57
|
-
/** Shaper only: reference token nats below the top for the auto out_scale. Default 4. */
|
|
58
|
-
refGap?: number;
|
|
59
|
-
/** Shaper only: curve geometry (the pivots / toe / mid power). Default to the
|
|
60
|
-
* HLGShaper constants (xM 0.55, yM 0.5, xFloor 0.2, yFloor 0.18, p 2.0) when unset. */
|
|
61
|
-
xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
|
|
62
|
-
/** Optional explicit mid gain m. Default: folds from temperature (m = 1/T),
|
|
63
|
-
* so temperature stays the contrast knob. An explicit value decouples mid
|
|
64
|
-
* contrast from temperature — needed to probe mid-boost while holding the
|
|
65
|
-
* model's recommended temperature fixed. */
|
|
66
|
-
gain?: number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface SamplerOptions {
|
|
70
|
-
temperature?: number;
|
|
71
|
-
topP?: number;
|
|
72
|
-
topK?: number;
|
|
73
|
-
/** min-p: keep tokens whose probability ≥ minP · p(top token). mlx-lm's
|
|
74
|
-
* `min_p`. Applied after top-p, before XTC/top-k (reference chain order). */
|
|
75
|
-
minP?: number;
|
|
76
|
-
/** Minimum number of tokens min-p may never filter out. Default 1. */
|
|
77
|
-
minTokensToKeep?: number;
|
|
78
|
-
/** XTC ("exclude top choices"): with this probability per step, drop every
|
|
79
|
-
* token above the threshold EXCEPT the least likely of them. */
|
|
80
|
-
xtcProbability?: number;
|
|
81
|
-
/** Probability a token must exceed to be an XTC removal candidate. [0, 0.5]. */
|
|
82
|
-
xtcThreshold?: number;
|
|
83
|
-
/** Token ids XTC never removes (mlx-lm's server passes EOS + "\n"). */
|
|
84
|
-
xtcSpecialTokens?: number[];
|
|
85
|
-
seed?: number;
|
|
86
|
-
/** HLG tone-curve sampling. When enabled, replaces temperature's flat slope
|
|
87
|
-
* with the piecewise curve (temperature becomes the mid gain). Off/undefined
|
|
88
|
-
* ⇒ the plain temperature path, unchanged. docs/archive/hlg-sampling.md. */
|
|
89
|
-
hlg?: HlgConfig;
|
|
90
|
-
/** v2 log-prob transfer-curve sampler. When set, the drawn monotone curve
|
|
91
|
-
* REPLACES temperature+softmax entirely (stochastic, seeded) — see
|
|
92
|
-
* src/lab/curve/curve-sampler.ts. Identity curve ≡ temperature 1. */
|
|
93
|
-
curve?: CurveParams;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface LogitsProcessorOptions {
|
|
97
|
-
/** Additive per-token-id logit bias, applied before any penalty
|
|
98
|
-
* (mlx-lm's `logit_bias`: {tokenId: bias}). */
|
|
99
|
-
logitBias?: Record<number, number>;
|
|
100
|
-
repetitionPenalty?: number;
|
|
101
|
-
repetitionContextSize?: number;
|
|
102
|
-
/** OpenAI-style presence penalty: subtracted ONCE from a token's logit if it
|
|
103
|
-
* occurred at all in the recent window. May be negative. */
|
|
104
|
-
presencePenalty?: number;
|
|
105
|
-
presenceContextSize?: number;
|
|
106
|
-
/** OpenAI-style frequency penalty: subtracted once PER OCCURRENCE of the
|
|
107
|
-
* token in the recent window. May be negative. */
|
|
108
|
-
frequencyPenalty?: number;
|
|
109
|
-
frequencyContextSize?: number;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** logprobs [1, V] → sampled token array (uint32, shape [1]). */
|
|
113
|
-
export type Sampler = (logprobs: MlxArray, step: number) => MlxArray;
|
|
114
|
-
|
|
115
|
-
/** (deviceTokens [n] | null, logits [1, V]) → logits [1, V]. */
|
|
116
|
-
export type LogitsProcessor = (tokens: MlxArray | null, logits: MlxArray) => MlxArray;
|
|
117
|
-
|
|
118
|
-
/** Optional arrays captured from the same post-processor logprobs used to
|
|
119
|
-
* sample a token. The caller controls readback timing and owns disposal. */
|
|
120
|
-
export interface StepExtras {
|
|
121
|
-
sel: MlxArray | null;
|
|
122
|
-
topIdx: MlxArray | null;
|
|
123
|
-
topVals: MlxArray | null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export type StepSample<T> = SampledToken<T, StepExtras>;
|
|
127
|
-
|
|
128
|
-
interface StepGrammar {
|
|
129
|
-
readonly isTerminated: boolean;
|
|
130
|
-
ready(): Promise<void>;
|
|
131
|
-
applyMask(logits: MlxArray): MlxArray;
|
|
132
|
-
accept(token: number): void;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export interface StepSamplerOptions extends SamplerOptions, LogitsProcessorOptions {
|
|
136
|
-
grammar?: StepGrammar | null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
interface StepSamplerConfigBase {
|
|
140
|
-
/** The grammar owner already awaited ready(), or this sampler must do it. */
|
|
141
|
-
grammarWait: "external" | "before-sample";
|
|
142
|
-
/** Update processor history in sample(), or let the decode loop commit later. */
|
|
143
|
-
historyUpdate: "after-sample" | "manual";
|
|
144
|
-
initialHistory?: readonly number[];
|
|
145
|
-
captureSelectedLogprob?: boolean;
|
|
146
|
-
captureTopLogprobs?: number;
|
|
147
|
-
/** Eager-number mode can advance grammar after sampling. */
|
|
148
|
-
acceptGrammar?: boolean;
|
|
149
|
-
eosTokenIds?: readonly number[];
|
|
150
|
-
/** Reuse a sampler already shared with a speculative draft source. */
|
|
151
|
-
sampler?: Sampler;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface DeviceStepSamplerConfig extends StepSamplerConfigBase {
|
|
155
|
-
tokenRepresentation: "device";
|
|
156
|
-
grammarWait: "external";
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export interface NumberStepSamplerConfig extends StepSamplerConfigBase {
|
|
160
|
-
tokenRepresentation: "number";
|
|
161
|
-
grammarWait: "before-sample";
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export type DeviceStepSampler = SamplingSession<MlxArray, MlxArray, StepSample<MlxArray>>;
|
|
165
|
-
export type NumberStepSampler = SamplingSession<MlxArray, MlxArray, Promise<StepSample<number>>>;
|
|
166
|
-
|
|
167
|
-
const GOLDEN = 0x9e3779b97f4a7c15n;
|
|
168
|
-
|
|
169
|
-
function stepKey(seed: number, step: number): MlxArray {
|
|
170
|
-
const mixed = (BigInt(seed) ^ ((BigInt(step) + 1n) * GOLDEN)) & 0xffffffffffffffffn;
|
|
171
|
-
return ops.randomKey(mixed);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function negInfLike(a: MlxArray): MlxArray {
|
|
175
|
-
return ops.scalarLike(-Infinity, a);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** apply_top_p: keep the smallest set of tokens whose cumulative
|
|
179
|
-
* probability exceeds top_p; others → -inf. */
|
|
180
|
-
export function applyTopP(lp: MlxArray, topP: number): MlxArray {
|
|
181
|
-
const probs = ops.exp(lp);
|
|
182
|
-
const sortedIdx = ops.argsortAxis(lp, -1);
|
|
183
|
-
const sortedProbs = ops.takeAlongAxis(probs, sortedIdx, -1);
|
|
184
|
-
const cum = ops.cumsum(sortedProbs, -1);
|
|
185
|
-
// scatter arange back through sortedIdx to invert the permutation
|
|
186
|
-
const V = lp.shape[lp.shape.length - 1]!;
|
|
187
|
-
const zerosIdx = ops.zeros(sortedIdx.shape, sortedIdx.dtype);
|
|
188
|
-
const ar = ops.arange(0, V, 1, sortedIdx.dtype);
|
|
189
|
-
const arB = ops.reshape(ar, sortedIdx.shape);
|
|
190
|
-
const inverse = ops.putAlongAxis(zerosIdx, sortedIdx, arB, -1);
|
|
191
|
-
const cumOrig = ops.takeAlongAxis(cum, inverse, -1);
|
|
192
|
-
const threshold = ops.scalarLike(1 - topP, cumOrig);
|
|
193
|
-
const keep = ops.less(threshold, cumOrig); // cum > 1 - topP
|
|
194
|
-
const ninf = negInfLike(lp);
|
|
195
|
-
const out = ops.where(keep, lp, ninf);
|
|
196
|
-
for (const a of [probs, sortedIdx, sortedProbs, cum, zerosIdx, ar, arB, inverse, cumOrig, threshold, keep, ninf])
|
|
197
|
-
a.dispose();
|
|
198
|
-
return out;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** apply_top_k: all but the k highest logprobs → -inf. */
|
|
202
|
-
export function applyTopK(lp: MlxArray, topK: number): MlxArray {
|
|
203
|
-
const V = lp.shape[lp.shape.length - 1]!;
|
|
204
|
-
const negLp = ops.neg(lp);
|
|
205
|
-
const part = ops.argpartitionAxis(negLp, topK - 1, -1);
|
|
206
|
-
const maskIdx = part.slice([0, topK], [1, V]);
|
|
207
|
-
const ninf = negInfLike(lp);
|
|
208
|
-
const out = ops.putAlongAxis(lp, maskIdx, ninf, -1);
|
|
209
|
-
for (const a of [negLp, part, maskIdx, ninf]) a.dispose();
|
|
210
|
-
return out;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** apply_min_p: mask tokens whose probability is below minP · p(top token).
|
|
214
|
-
* Faithful to the reference (mlx-lm 0.31.3 sample_utils.apply_min_p): the
|
|
215
|
-
* threshold is computed in log space directly against the max logprob —
|
|
216
|
-
* `scaled_min_p = max(lp) + log(minP)` — no full sort; min_tokens_to_keep
|
|
217
|
-
* survivors are recovered with an argpartition on the top tail. */
|
|
218
|
-
export function applyMinP(lp: MlxArray, minP: number, minTokensToKeep = 1): MlxArray {
|
|
219
|
-
if (!(minP >= 0 && minP <= 1))
|
|
220
|
-
throw new Error(`minP has to be a float in the [0, 1] interval, but is ${minP}`);
|
|
221
|
-
if (!Number.isInteger(minTokensToKeep) || minTokensToKeep < 1)
|
|
222
|
-
throw new Error(`minTokensToKeep has to be a positive integer, but is ${minTokensToKeep}`);
|
|
223
|
-
|
|
224
|
-
const owned: MlxArray[] = [];
|
|
225
|
-
const k = <T extends MlxArray>(a: T): T => { owned.push(a); return a; };
|
|
226
|
-
|
|
227
|
-
// Mask tokens that have a probability less than max(p) * min_p
|
|
228
|
-
const top = k(ops.maxAxis(lp, -1, true));
|
|
229
|
-
const scaledMinP = k(ops.add(top, k(ops.scalarLike(Math.log(minP), top))));
|
|
230
|
-
let remove = k(ops.less(lp, scaledMinP));
|
|
231
|
-
|
|
232
|
-
// Ensure at least min_tokens_to_keep survive the filter
|
|
233
|
-
if (minTokensToKeep > 1) {
|
|
234
|
-
const V = lp.shape[lp.shape.length - 1]!;
|
|
235
|
-
// mx.argpartition(lp, kth=-min_tokens_to_keep): negative kth ≡ V - k
|
|
236
|
-
const part = k(ops.argpartitionAxis(lp, V - minTokensToKeep, -1));
|
|
237
|
-
const topIdx = k(part.slice([0, V - minTokensToKeep], [1, V]));
|
|
238
|
-
const falses = k(ops.zeros([1, minTokensToKeep], Dtype.bool));
|
|
239
|
-
remove = k(ops.putAlongAxis(remove, topIdx, falses, -1));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const ninf = k(negInfLike(lp));
|
|
243
|
-
const out = ops.where(remove, ninf, lp);
|
|
244
|
-
for (const a of owned) a.dispose();
|
|
245
|
-
return out;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/** apply_xtc: with probability xtcProbability, remove every token whose
|
|
249
|
-
* probability exceeds the minimum above-threshold probability — i.e. drop
|
|
250
|
-
* the top choices, keeping the least likely token that still clears the
|
|
251
|
-
* threshold (plus everything below it). Special tokens are never removed.
|
|
252
|
-
* `key` seeds the per-step uniform draw (the reference uses the global RNG). */
|
|
253
|
-
export function applyXtc(
|
|
254
|
-
logits: MlxArray,
|
|
255
|
-
xtcProbability: number,
|
|
256
|
-
xtcThreshold: number,
|
|
257
|
-
xtcSpecialTokens: number[],
|
|
258
|
-
key: MlxArray | null,
|
|
259
|
-
): MlxArray {
|
|
260
|
-
if (!(xtcThreshold >= 0 && xtcThreshold <= 0.5))
|
|
261
|
-
throw new Error(`xtcThreshold has to be a float in the [0, 0.5] interval, but is ${xtcThreshold}`);
|
|
262
|
-
if (!(xtcProbability >= 0 && xtcProbability <= 1))
|
|
263
|
-
throw new Error(`xtcProbability has to be a float in the [0, 1] interval, but is ${xtcProbability}`);
|
|
264
|
-
|
|
265
|
-
const owned: MlxArray[] = [];
|
|
266
|
-
const k = <T extends MlxArray>(a: T): T => { owned.push(a); return a; };
|
|
267
|
-
|
|
268
|
-
const probs = k(ops.softmaxAxis(logits, -1, false));
|
|
269
|
-
// mask = probs > min(where(probs > threshold, probs, inf))
|
|
270
|
-
const thresh = k(ops.scalarLike(xtcThreshold, probs));
|
|
271
|
-
const above = k(ops.less(thresh, probs)); // probs > threshold
|
|
272
|
-
const inf = k(ops.scalarLike(Infinity, probs));
|
|
273
|
-
const aboveProbs = k(ops.where(above, probs, inf));
|
|
274
|
-
// min(x) = -max(-x) (no min reduction in the ops layer)
|
|
275
|
-
const minAbove = k(ops.neg(k(ops.maxAxis(k(ops.neg(aboveProbs)), -1, true))));
|
|
276
|
-
let mask = k(ops.less(minAbove, probs)); // probs > min above-threshold prob
|
|
277
|
-
if (xtcSpecialTokens.length > 0) {
|
|
278
|
-
const n = xtcSpecialTokens.length;
|
|
279
|
-
const idx = k(ops.fromInt32(xtcSpecialTokens, [1, n]));
|
|
280
|
-
const falses = k(ops.zeros([1, n], Dtype.bool));
|
|
281
|
-
mask = k(ops.putAlongAxis(mask, idx, falses, -1));
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// where(uniform() > xtcProbability, logits, where(mask, -inf, logits))
|
|
285
|
-
const u = k(ops.randomUniform([1], Dtype.float32, 0, 1, key));
|
|
286
|
-
const pArr = k(ops.scalarLike(xtcProbability, u));
|
|
287
|
-
const skip = k(ops.less(pArr, u)); // u > xtcProbability → leave logits alone
|
|
288
|
-
const ninf = k(negInfLike(logits));
|
|
289
|
-
const culled = k(ops.where(mask, ninf, logits));
|
|
290
|
-
const out = ops.where(skip, logits, culled);
|
|
291
|
-
for (const a of owned) a.dispose();
|
|
292
|
-
return out;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/** HLG sampling parameters — a piecewise tone curve on the logprobs.
|
|
296
|
-
* See docs/archive/hlg-sampling.md. Knobs are in nats (the logprob unit). */
|
|
297
|
-
export interface HlgParams {
|
|
298
|
-
/** m — mid-region slope. Folds temperature: m = 1/temperature. */
|
|
299
|
-
gain: number;
|
|
300
|
-
/** w — half-width of the linear mid region. Infinity ⇒ no rolloff (pure temperature). */
|
|
301
|
-
width: number;
|
|
302
|
-
/** β_h — highlight rolloff scale. ≤ 0 ⇒ no shoulder (highlights stay linear). */
|
|
303
|
-
shoulder: number;
|
|
304
|
-
/** β_t — shadow rolloff scale. ≤ 0 ⇒ no toe (shadows stay linear). */
|
|
305
|
-
toe: number;
|
|
306
|
-
/** pivot (middle grey) placement — changes where the curve centers, hence its
|
|
307
|
-
* shape. "top": μ = max(ℓ) − offset. "entropy": μ = Σp·ℓ = −H (center of mass
|
|
308
|
-
* in tonal space). "median": μ = the logprob at the 50% cumulative-mass
|
|
309
|
-
* boundary (auto-levels). */
|
|
310
|
-
pivot?: "top" | "entropy" | "median";
|
|
311
|
-
/** shift applied to the pivot base: μ = base − pivotOffset. */
|
|
312
|
-
pivotOffset?: number;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const HLG_LOG_EPS = 1e-9;
|
|
316
|
-
|
|
317
|
-
/** Pivot (middle grey) μ_base for the tone curve, in logprob units — the same
|
|
318
|
-
* curve, centered three different ways. Operates on the full logprob vector. */
|
|
319
|
-
function hlgPivotBase(
|
|
320
|
-
lp: MlxArray,
|
|
321
|
-
mode: "top" | "entropy" | "median",
|
|
322
|
-
k: <T extends MlxArray>(a: T) => T,
|
|
323
|
-
): MlxArray {
|
|
324
|
-
if (mode === "entropy") {
|
|
325
|
-
// center of mass in tonal space: μ = Σ p·ℓ = −H (p = exp(ℓ); ℓ are logprobs)
|
|
326
|
-
const probs = k(ops.exp(lp));
|
|
327
|
-
return k(ops.sumAxis(k(ops.mul(probs, lp)), -1, true));
|
|
328
|
-
}
|
|
329
|
-
if (mode === "median") {
|
|
330
|
-
// logprob at the 50% cumulative-mass boundary (auto-levels / histogram median)
|
|
331
|
-
const probs = k(ops.exp(lp));
|
|
332
|
-
const idxDesc = k(ops.argsortAxis(k(ops.neg(lp)), -1)); // ascending of −ℓ = ℓ descending
|
|
333
|
-
const sortedProbs = k(ops.takeAlongAxis(probs, idxDesc, -1));
|
|
334
|
-
const sortedLp = k(ops.takeAlongAxis(lp, idxDesc, -1));
|
|
335
|
-
const cum = k(ops.cumsum(sortedProbs, -1));
|
|
336
|
-
const keep = k(ops.greaterEqual(cum, k(ops.scalarLike(0.5, cum))));
|
|
337
|
-
const masked = k(ops.where(keep, sortedLp, k(ops.scalarLike(-Infinity, sortedLp))));
|
|
338
|
-
return k(ops.maxAxis(masked, -1, true)); // first crossover = max logprob of the ≥0.5 suffix
|
|
339
|
-
}
|
|
340
|
-
return k(ops.maxAxis(lp, -1, true)); // "top": the peak
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/** Remap logprobs through the centered curve g(z), z = ℓ − μ:
|
|
344
|
-
* toe (z < −w): −m·w − m·β_t·ln(1 + (−z − w)/β_t) gentle shadow rolloff
|
|
345
|
-
* mid (|z| ≤ w): m·z contrast gain
|
|
346
|
-
* shoulder(z > w): m·w + m·β_h·ln(1 + ( z − w)/β_h) highlight rolloff
|
|
347
|
-
* Monotone in ℓ ⇒ ranking-preserving (argmax unchanged). With width = ∞ (or
|
|
348
|
-
* β_h, β_t ≤ 0) it returns mulScalar(lp, m) — temperature T = 1/m — bit-exact
|
|
349
|
-
* by construction (the same op the temperature path uses). `-inf` (masked)
|
|
350
|
-
* tokens map to `-inf`. */
|
|
351
|
-
export function applyHlg(lp: MlxArray, p: HlgParams): MlxArray {
|
|
352
|
-
const m = p.gain;
|
|
353
|
-
const hasShoulder = Number.isFinite(p.width) && p.shoulder > 0;
|
|
354
|
-
const hasToe = Number.isFinite(p.width) && p.toe > 0;
|
|
355
|
-
// No-rolloff regime ≡ temperature: identical op to the temperature sampler.
|
|
356
|
-
if (!hasShoulder && !hasToe) return ops.mulScalar(lp, m);
|
|
357
|
-
|
|
358
|
-
const w = p.width;
|
|
359
|
-
const off = p.pivotOffset ?? 0;
|
|
360
|
-
const tmp: MlxArray[] = [];
|
|
361
|
-
const k = <T extends MlxArray>(a: T): T => {
|
|
362
|
-
tmp.push(a);
|
|
363
|
-
return a;
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
// pivot μ = base(mode) − off ; centered coordinate z = ℓ − μ
|
|
367
|
-
const base = hlgPivotBase(lp, p.pivot ?? "top", k);
|
|
368
|
-
const mu = k(ops.sub(base, k(ops.scalarLike(off, base))));
|
|
369
|
-
const z = k(ops.sub(lp, mu));
|
|
370
|
-
const wC = k(ops.scalarLike(w, lp));
|
|
371
|
-
let g: MlxArray = k(ops.mulScalar(z, m)); // mid: m·z
|
|
372
|
-
|
|
373
|
-
if (hasShoulder) {
|
|
374
|
-
const bh = p.shoulder;
|
|
375
|
-
const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(z, wC)), 1 / bh))));
|
|
376
|
-
const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
|
|
377
|
-
const shoulder = k(ops.add(k(ops.scalarLike(m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bh))));
|
|
378
|
-
g = k(ops.where(k(ops.greaterEqual(z, wC)), shoulder, g));
|
|
379
|
-
}
|
|
380
|
-
if (hasToe) {
|
|
381
|
-
const bt = p.toe;
|
|
382
|
-
const negz = k(ops.neg(z));
|
|
383
|
-
const inner = k(ops.add(k(ops.scalarLike(1, lp)), k(ops.mulScalar(k(ops.sub(negz, wC)), 1 / bt))));
|
|
384
|
-
const clamped = k(ops.maximum(inner, k(ops.scalarLike(HLG_LOG_EPS, lp))));
|
|
385
|
-
const toe = k(ops.sub(k(ops.scalarLike(-m * w, lp)), k(ops.mulScalar(k(ops.log(clamped)), m * bt))));
|
|
386
|
-
g = k(ops.where(k(ops.less(z, k(ops.scalarLike(-w, lp)))), toe, g));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
for (const a of tmp) if (a !== g) a.dispose();
|
|
390
|
-
return g;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Literal HLG OETF (ARIB STD-B67 / ITU-R BT.2100) — the actual transfer
|
|
394
|
-
// function, exact constants. Input L = p/p_max ∈ (0,1] (exposure-normalized: the
|
|
395
|
-
// top token is reference white). Output V ∈ [0,1]:
|
|
396
|
-
// V = √3 · √L for 0 ≤ L ≤ 1/12 (gamma/sqrt: shadows → 0 softly)
|
|
397
|
-
// V = a·ln(12L − b) + c for 1/12 < L ≤ 1 (log: highlights compressed)
|
|
398
|
-
// We sample ∝ V by feeding log(V) to the categorical draw. Monotone in ℓ ⇒
|
|
399
|
-
// ranking-preserving. No knobs — this is HLG itself.
|
|
400
|
-
const HLG_A = 0.17883277;
|
|
401
|
-
const HLG_B = 0.28466892; // 1 − 4a
|
|
402
|
-
const HLG_C = 0.55991073; // 0.5 − a·ln(4a)
|
|
403
|
-
const HLG_SQRT3 = Math.sqrt(3);
|
|
404
|
-
const HLG_KNEE = 1 / 12;
|
|
405
|
-
|
|
406
|
-
export function applyHlgOetf(lp: MlxArray): MlxArray {
|
|
407
|
-
const tmp: MlxArray[] = [];
|
|
408
|
-
const k = <T extends MlxArray>(a: T): T => {
|
|
409
|
-
tmp.push(a);
|
|
410
|
-
return a;
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
// L = p / p_max = exp(ℓ − ℓmax) ∈ (0, 1]
|
|
414
|
-
const lmax = k(ops.maxAxis(lp, -1, true));
|
|
415
|
-
const L = k(ops.exp(k(ops.sub(lp, lmax))));
|
|
416
|
-
|
|
417
|
-
// lower (L ≤ 1/12): V = √3 · √L
|
|
418
|
-
const lo = k(ops.mulScalar(k(ops.sqrt(L)), HLG_SQRT3));
|
|
419
|
-
// upper (L > 1/12): V = a·ln(12L − b) + c (clamp the arg > 0 for the unused lane)
|
|
420
|
-
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))));
|
|
421
|
-
const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, L))));
|
|
422
|
-
const V = k(ops.where(k(ops.greaterEqual(L, k(ops.scalarLike(HLG_KNEE, L)))), hi, lo));
|
|
423
|
-
|
|
424
|
-
// sample ∝ V → logits = log(V)
|
|
425
|
-
const out = ops.log(k(ops.maximum(V, k(ops.scalarLike(HLG_LOG_EPS, V)))));
|
|
426
|
-
for (const a of tmp) a.dispose();
|
|
427
|
-
return out;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/** OOTF system gamma from nominal peak display luminance L_W (cd/m²).
|
|
431
|
-
* γ = 1.2 + 0.42·log10(L_W/1000); γ = 1.2 exactly at L_W = 1000. */
|
|
432
|
-
export function hlgGammaForLw(lw: number): number {
|
|
433
|
-
return 1.2 + 0.42 * Math.log10(lw / 1000);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Literal HLG EOTF (signal → display linear) = inverse OETF then OOTF — the
|
|
437
|
-
// DECODE direction. Treat p/p_max as the signal E'. The inverse OETF squares the
|
|
438
|
-
// lower half (E = E'²/3) so the tail is SUPPRESSED (the opposite of the OETF,
|
|
439
|
-
// which expands it). The OOTF on a single-"pixel" (grayscale) distribution has
|
|
440
|
-
// no colour channels for luminance to couple, so it reduces exactly to a gamma
|
|
441
|
-
// power law E^γ — i.e. temperature. Sample ∝ E^γ ⇒ logits = γ·log(E).
|
|
442
|
-
export function applyHlgEotf(lp: MlxArray, gamma: number): MlxArray {
|
|
443
|
-
const tmp: MlxArray[] = [];
|
|
444
|
-
const k = <T extends MlxArray>(a: T): T => {
|
|
445
|
-
tmp.push(a);
|
|
446
|
-
return a;
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
const d = k(ops.sub(lp, k(ops.maxAxis(lp, -1, true)))); // ℓ − ℓmax ≤ 0
|
|
450
|
-
const Ep = k(ops.exp(d)); // signal E' = p/p_max ∈ (0, 1]
|
|
451
|
-
// log E from the inverse OETF, computed stably per branch (the deep tail
|
|
452
|
-
// underflows if E is formed directly, so the lower branch stays in log-space):
|
|
453
|
-
// E' ≤ 1/2: E = E'²/3 → log E = 2·(ℓ−ℓmax) − ln3 (exact)
|
|
454
|
-
// E' > 1/2: E = (exp((E'−c)/a)+b)/12 → log E = log(that) (well-conditioned)
|
|
455
|
-
const logElo = k(ops.sub(k(ops.mulScalar(d, 2)), k(ops.scalarLike(Math.log(3), d))));
|
|
456
|
-
const hiArg = k(ops.exp(k(ops.mulScalar(k(ops.sub(Ep, k(ops.scalarLike(HLG_C, Ep)))), 1 / HLG_A))));
|
|
457
|
-
const hiE = k(ops.mulScalar(k(ops.add(hiArg, k(ops.scalarLike(HLG_B, Ep)))), 1 / 12));
|
|
458
|
-
const logEhi = k(ops.log(hiE));
|
|
459
|
-
const logE = k(ops.where(k(ops.greaterEqual(Ep, k(ops.scalarLike(0.5, Ep)))), logEhi, logElo));
|
|
460
|
-
// OOTF (grayscale) → gamma: sample ∝ E^γ ⇒ logits = γ·log(E)
|
|
461
|
-
const out = ops.mulScalar(logE, gamma);
|
|
462
|
-
for (const a of tmp) a.dispose();
|
|
463
|
-
return out;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// The FULL HLG chain: OETF signal shape, THEN OOTF scaling.
|
|
467
|
-
// 1. E = p/p_max ∈ (0,1] (top token = the max-brightness reference)
|
|
468
|
-
// 2. E' = √(3E) for E ≤ 1/12 (gamma/√ toe below the knee)
|
|
469
|
-
// = a·ln(12E−b)+c for E > 1/12 (log highlights above the knee)
|
|
470
|
-
// 3. R_d = α · E'^γ (OOTF: α = max brightness, scales everything
|
|
471
|
-
// under it; γ = 1.2+0.42·log10(L_W/1000))
|
|
472
|
-
// R_d are the final logits → categorical. α > 0 ⇒ monotone (ranking preserved).
|
|
473
|
-
export function applyHlgPipeline(lp: MlxArray, alpha: number, gamma: number): MlxArray {
|
|
474
|
-
const tmp: MlxArray[] = [];
|
|
475
|
-
const k = <T extends MlxArray>(a: T): T => {
|
|
476
|
-
tmp.push(a);
|
|
477
|
-
return a;
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
// 1. E = p/p_max ∈ (0,1]
|
|
481
|
-
const E = k(ops.exp(k(ops.sub(lp, k(ops.maxAxis(lp, -1, true))))));
|
|
482
|
-
// 2. OETF: √(3E) below the knee, a·ln(12E−b)+c above
|
|
483
|
-
const lo = k(ops.sqrt(k(ops.mulScalar(E, 3))));
|
|
484
|
-
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))));
|
|
485
|
-
const hi = k(ops.add(k(ops.mulScalar(k(ops.log(arg)), HLG_A)), k(ops.scalarLike(HLG_C, E))));
|
|
486
|
-
const Eprime = k(ops.where(k(ops.greaterEqual(E, k(ops.scalarLike(HLG_KNEE, E)))), hi, lo));
|
|
487
|
-
// 3. OOTF: R_d = α · E'^γ = α · exp(γ·log E')
|
|
488
|
-
const EpGamma = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(Eprime, k(ops.scalarLike(HLG_LOG_EPS, Eprime)))))), gamma))));
|
|
489
|
-
const out = ops.mulScalar(EpGamma, alpha);
|
|
490
|
-
for (const a of tmp) a.dispose();
|
|
491
|
-
return out;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// ── User-specified HLGShaper (windowed-anchor input) ────────────────────────
|
|
495
|
-
// logit → windowed-anchor signal x∈[0,1] (top W nats span the curve; min-max
|
|
496
|
-
// over the 262k vocab dumped every candidate into the shoulder, so we anchor at
|
|
497
|
-
// the top instead) → piecewise OETF (log shoulder above x_m, power mid, CUBIC
|
|
498
|
-
// toe that suppresses to 0) → OOTF (normalize to peak, ^γ) → ×out_scale →
|
|
499
|
-
// softmax. Geometry constants derived once from the default knobs, exactly as
|
|
500
|
-
// HLGShaper.__init__ does (cubic toe coeffs from a 2×2 solve).
|
|
501
|
-
export interface HlgShaperParams {
|
|
502
|
-
lw?: number; // L_W (cd/m²) → OOTF γ
|
|
503
|
-
outScale?: number; // explicit override; default auto-derived from targetGap/refGap
|
|
504
|
-
targetGap?: number; // desired top-1-to-reference final-logit gap (sets sharpness, W-independent)
|
|
505
|
-
refGap?: number; // reference token sits this many nats below the top
|
|
506
|
-
window?: number; // W: nats below the top spanning the curve
|
|
507
|
-
xM?: number; yM?: number; xFloor?: number; yFloor?: number; p?: number;
|
|
508
|
-
sM?: number; // mid sharpness — how hard above-median tokens are elevated
|
|
509
|
-
A?: number; // shoulder compression — how hard confidence is tamed
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
export function applyHlgShaper(lp: MlxArray, opts: HlgShaperParams = {}): MlxArray {
|
|
513
|
-
const lw = opts.lw ?? 1200, window = opts.window ?? 10;
|
|
514
|
-
const xM = opts.xM ?? 0.55, yM = opts.yM ?? 0.5, xFloor = opts.xFloor ?? 0.2, yFloor = opts.yFloor ?? 0.18;
|
|
515
|
-
const p = opts.p ?? 2.0, sM = opts.sM ?? 0.7, A = opts.A ?? 0.35;
|
|
516
|
-
const targetGap = opts.targetGap ?? 15, refGap = opts.refGap ?? 4;
|
|
517
|
-
// geometry derived per call (cheap scalar math), exactly as HLGShaper.__init__
|
|
518
|
-
const dxf = xM - xFloor;
|
|
519
|
-
const kc = (yM - sM * dxf - yFloor) / Math.pow(dxf, p); // mid reaches y_floor
|
|
520
|
-
const sFloor = sM + kc * p * Math.pow(dxf, p - 1); // mid slope at the toe join
|
|
521
|
-
const det = -Math.pow(xFloor, 4); // solve [[xf³,xf²],[3xf²,2xf]]·[e,f]=[y_floor,s_floor]
|
|
522
|
-
const ec = (yFloor * (2 * xFloor) - xFloor ** 2 * sFloor) / det;
|
|
523
|
-
const fc = (xFloor ** 3 * sFloor - yFloor * (3 * xFloor ** 2)) / det;
|
|
524
|
-
const yPeak = yM + A * Math.log(1 + (sM / A) * (1 - xM));
|
|
525
|
-
const gamma = 1.2 + 0.42 * Math.log10(Math.max(lw, 1e-3) / 1000);
|
|
526
|
-
|
|
527
|
-
// out_scale AUTO-derived so the top-1-to-reference final-logit gap = targetGap,
|
|
528
|
-
// INDEPENDENT of W — decouples the two knobs so W is a clean 1-D sweep. The
|
|
529
|
-
// reference token sits refGap nats below the top; its post-shape value is the
|
|
530
|
-
// scalar curve evaluated in JS (no device cost). Calibrated so W=5 ⇒ os ≈ 18.
|
|
531
|
-
const oetfS = (xx: number): number => {
|
|
532
|
-
let yy: number;
|
|
533
|
-
if (xx >= xM) yy = yM + A * Math.log(Math.max(1 + (sM / A) * (xx - xM), 1e-9));
|
|
534
|
-
else if (xx >= xFloor) yy = yM - sM * (xM - xx) - kc * Math.pow(Math.max(xM - xx, 0), p);
|
|
535
|
-
else yy = ec * xx ** 3 + fc * xx ** 2;
|
|
536
|
-
return Math.max(yy, 0);
|
|
537
|
-
};
|
|
538
|
-
const shapeS = (xx: number): number => Math.pow(Math.max(oetfS(xx) / yPeak, 1e-9), gamma);
|
|
539
|
-
const xRef = Math.max(0, Math.min(1, 1 - refGap / window));
|
|
540
|
-
const outScale = opts.outScale ?? targetGap / Math.max(1e-6, 1 - shapeS(xRef));
|
|
541
|
-
|
|
542
|
-
const tmp: MlxArray[] = [];
|
|
543
|
-
const k = <T extends MlxArray>(a: T): T => {
|
|
544
|
-
tmp.push(a);
|
|
545
|
-
return a;
|
|
546
|
-
};
|
|
547
|
-
const C = (v: number, like: MlxArray): MlxArray => k(ops.scalarLike(v, like));
|
|
548
|
-
|
|
549
|
-
// x = clamp((ℓ − ℓmax)/W + 1, 0, 1) — windowed anchor at the top
|
|
550
|
-
const lmax = k(ops.maxAxis(lp, -1, true));
|
|
551
|
-
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)));
|
|
552
|
-
|
|
553
|
-
// OETF: up (x≥x_m) log shoulder, mid power, toe (x<x_floor) cubic suppress
|
|
554
|
-
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)));
|
|
555
|
-
const up = k(ops.add(C(yM, x), k(ops.mulScalar(k(ops.log(upArg)), A))));
|
|
556
|
-
const dm = k(ops.sub(C(xM, x), x));
|
|
557
|
-
const dmPow = k(ops.exp(k(ops.mulScalar(k(ops.log(k(ops.maximum(dm, C(1e-9, x))))), p))));
|
|
558
|
-
const mid = k(ops.sub(k(ops.sub(C(yM, x), k(ops.mulScalar(dm, sM)))), k(ops.mulScalar(dmPow, kc))));
|
|
559
|
-
const x2 = k(ops.square(x));
|
|
560
|
-
const x3 = k(ops.mul(x, x2));
|
|
561
|
-
const toe = k(ops.add(k(ops.mulScalar(x3, ec)), k(ops.mulScalar(x2, fc))));
|
|
562
|
-
const upMid = k(ops.where(k(ops.greaterEqual(x, C(xM, x))), up, mid));
|
|
563
|
-
const y = k(ops.maximum(k(ops.where(k(ops.greaterEqual(x, C(xFloor, x))), upMid, toe)), C(0, x)));
|
|
564
|
-
|
|
565
|
-
// OOTF: r = (max(y/y_peak, 1e-9))^γ ; then softmax(r · out_scale)
|
|
566
|
-
const yn = k(ops.maximum(k(ops.mulScalar(y, 1 / yPeak)), C(1e-9, y)));
|
|
567
|
-
const r = k(ops.exp(k(ops.mulScalar(k(ops.log(yn)), gamma))));
|
|
568
|
-
const out = ops.mulScalar(r, outScale);
|
|
569
|
-
for (const a of tmp) a.dispose();
|
|
570
|
-
return out;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
export function makeSampler(opts: SamplerOptions = {}): Sampler {
|
|
574
|
-
const {
|
|
575
|
-
temperature = 0, topP = 0, topK = 0, minP = 0, minTokensToKeep = 1,
|
|
576
|
-
xtcProbability = 0, xtcThreshold = 0, xtcSpecialTokens = [],
|
|
577
|
-
seed = 0, hlg, curve,
|
|
578
|
-
} = opts;
|
|
579
|
-
|
|
580
|
-
// v2 curve sampler: the drawn log-prob transfer curve REPLACES temperature +
|
|
581
|
-
// softmax. Stochastic and seeded by design (the curve IS the sampling shape),
|
|
582
|
-
// so it overrides the greedy default — the designer wants variety across N.
|
|
583
|
-
if (curve) {
|
|
584
|
-
return (lp, step) => {
|
|
585
|
-
const shaped = applyCurve(lp, curve);
|
|
586
|
-
const tok = ops.randomCategorical(shaped, stepKey(seed, step));
|
|
587
|
-
shaped.dispose();
|
|
588
|
-
return tok;
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
// Greedy: HLG is a no-op (a monotone curve cannot move the argmax), so the
|
|
593
|
-
// greedy path is untouched whether or not HLG is enabled.
|
|
594
|
-
if (temperature === 0)
|
|
595
|
-
return (lp) => ops.argmaxAxis(lp, -1);
|
|
596
|
-
|
|
597
|
-
// HLG is a REPLACEMENT sampler: when enabled, the tone curve IS the whole
|
|
598
|
-
// post-logits step — its toe does the tail control that top_p/top_k would, so
|
|
599
|
-
// they are NOT applied. Otherwise we do exactly what we used to: top_p, top_k,
|
|
600
|
-
// then temperature scaling. (Temperature still folds into the mid gain m = 1/T
|
|
601
|
-
// unless the config sets an explicit gain.)
|
|
602
|
-
if (hlg?.enabled === true) {
|
|
603
|
-
const useOetf = hlg.oetf === true;
|
|
604
|
-
const useEotf = hlg.eotf === true;
|
|
605
|
-
const usePipeline = hlg.pipeline === true;
|
|
606
|
-
const eotfGamma = hlgGammaForLw(hlg.lw ?? 1000);
|
|
607
|
-
const alpha = hlg.maxBrightness ?? 5;
|
|
608
|
-
const params: HlgParams = {
|
|
609
|
-
gain: hlg.gain ?? 1 / temperature,
|
|
610
|
-
width: hlg.width,
|
|
611
|
-
shoulder: hlg.shoulder,
|
|
612
|
-
toe: hlg.toe,
|
|
613
|
-
pivot: hlg.pivot,
|
|
614
|
-
pivotOffset: hlg.pivotOffset,
|
|
615
|
-
};
|
|
616
|
-
return (lp, step) => {
|
|
617
|
-
const scaled = hlg.shaper === true
|
|
618
|
-
? 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 })
|
|
619
|
-
: usePipeline ? applyHlgPipeline(lp, alpha, eotfGamma)
|
|
620
|
-
: useEotf ? applyHlgEotf(lp, eotfGamma) : useOetf ? applyHlgOetf(lp) : applyHlg(lp, params);
|
|
621
|
-
const key = stepKey(seed, step);
|
|
622
|
-
const tok = ops.randomCategorical(scaled, key);
|
|
623
|
-
scaled.dispose();
|
|
624
|
-
key.dispose();
|
|
625
|
-
return tok;
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Filter chain order matches mlx-lm's make_sampler: top_p → min_p → xtc →
|
|
630
|
-
// top_k, then categorical(logprobs / temperature).
|
|
631
|
-
return (lp, step) => {
|
|
632
|
-
let cur = lp;
|
|
633
|
-
const owned: MlxArray[] = [];
|
|
634
|
-
let key = stepKey(seed, step);
|
|
635
|
-
if (topP > 0 && topP < 1) { cur = applyTopP(cur, topP); owned.push(cur); }
|
|
636
|
-
if (minP !== 0) { cur = applyMinP(cur, minP, minTokensToKeep); owned.push(cur); }
|
|
637
|
-
if (xtcProbability > 0) {
|
|
638
|
-
// Split the step key: subkey 0 → XTC's uniform, subkey 1 → categorical.
|
|
639
|
-
const split = ops.randomSplitNum(key, 2);
|
|
640
|
-
const row0 = split.slice([0, 0], [1, 2]);
|
|
641
|
-
const row1 = split.slice([1, 0], [2, 2]);
|
|
642
|
-
const xtcKey = ops.reshape(row0, [2]);
|
|
643
|
-
key.dispose();
|
|
644
|
-
key = ops.reshape(row1, [2]);
|
|
645
|
-
for (const a of [split, row0, row1]) a.dispose();
|
|
646
|
-
cur = applyXtc(cur, xtcProbability, xtcThreshold, xtcSpecialTokens, xtcKey);
|
|
647
|
-
owned.push(cur);
|
|
648
|
-
xtcKey.dispose();
|
|
649
|
-
}
|
|
650
|
-
if (topK > 0) { cur = applyTopK(cur, topK); owned.push(cur); }
|
|
651
|
-
const scaled = ops.mulScalar(cur, 1 / temperature);
|
|
652
|
-
const tok = ops.randomCategorical(scaled, key);
|
|
653
|
-
scaled.dispose();
|
|
654
|
-
key.dispose();
|
|
655
|
-
for (const a of owned) a.dispose();
|
|
656
|
-
return tok;
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/** Start of the recent-token window, matching Python's `tokens[-context_size:]`
|
|
661
|
-
* slice semantics exactly (context_size 0 ⇒ `[-0:]` ⇒ the WHOLE history). */
|
|
662
|
-
function windowStart(n: number, contextSize: number): number {
|
|
663
|
-
return contextSize === 0 ? 0 : Math.max(0, n - contextSize);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
export function makeLogitsProcessors(opts: LogitsProcessorOptions = {}): LogitsProcessor[] {
|
|
667
|
-
const out: LogitsProcessor[] = [];
|
|
668
|
-
const {
|
|
669
|
-
logitBias,
|
|
670
|
-
repetitionPenalty, repetitionContextSize = 20,
|
|
671
|
-
presencePenalty, presenceContextSize = 20,
|
|
672
|
-
frequencyPenalty, frequencyContextSize = 20,
|
|
673
|
-
} = opts;
|
|
674
|
-
|
|
675
|
-
// logit_bias first, as in mlx-lm's make_logits_processors. Reference:
|
|
676
|
-
// `logits.at[:, indices].add(values)` — dict keys are unique, so a
|
|
677
|
-
// gather → add → put round-trip is exactly equivalent to the scatter-add.
|
|
678
|
-
const biasIds = logitBias ? Object.keys(logitBias).map(Number) : [];
|
|
679
|
-
if (logitBias && biasIds.length > 0) {
|
|
680
|
-
const biasVals = Float32Array.from(biasIds.map((id) => logitBias[id]!));
|
|
681
|
-
out.push((_tokens, logits) => {
|
|
682
|
-
const K = biasIds.length;
|
|
683
|
-
const idx = ops.fromInt32(biasIds, [1, K]);
|
|
684
|
-
const vals32 = MlxArray.fromFloat32(biasVals, [1, K]);
|
|
685
|
-
const vals = vals32.astype(logits.dtype);
|
|
686
|
-
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
687
|
-
const biased = ops.add(selected, vals);
|
|
688
|
-
const updated = ops.putAlongAxis(logits, idx, biased, -1);
|
|
689
|
-
for (const a of [idx, vals32, vals, selected, biased]) a.dispose();
|
|
690
|
-
return updated;
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
if (repetitionPenalty !== undefined && repetitionPenalty !== 0) {
|
|
695
|
-
if (repetitionPenalty < 0)
|
|
696
|
-
throw new Error("repetitionPenalty must be non-negative");
|
|
697
|
-
out.push((tokens, logits) => {
|
|
698
|
-
if (!tokens) return logits;
|
|
699
|
-
const n = tokens.shape[0]!;
|
|
700
|
-
if (n === 0) return logits;
|
|
701
|
-
const start = windowStart(n, repetitionContextSize);
|
|
702
|
-
const recent = tokens.slice([start], [n]);
|
|
703
|
-
const idx = ops.reshape(recent, [1, n - start]);
|
|
704
|
-
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
705
|
-
const zero = ops.scalarLike(0, selected);
|
|
706
|
-
const isNeg = ops.less(selected, zero);
|
|
707
|
-
const timesP = ops.mulScalar(selected, repetitionPenalty);
|
|
708
|
-
const pen = ops.scalarLike(repetitionPenalty, selected);
|
|
709
|
-
const overP = ops.div(selected, pen);
|
|
710
|
-
const penalized = ops.where(isNeg, timesP, overP);
|
|
711
|
-
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
712
|
-
for (const a of [recent, idx, selected, zero, isNeg, timesP, pen, overP, penalized])
|
|
713
|
-
a.dispose();
|
|
714
|
-
return updated;
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// make_presence_penalty: `logits[:, tokens] -= penalty` — a plain
|
|
719
|
-
// fancy-index assignment, so duplicate occurrences all write the SAME
|
|
720
|
-
// value (original − penalty): the penalty applies once per distinct token.
|
|
721
|
-
if (presencePenalty !== undefined && presencePenalty !== 0) {
|
|
722
|
-
out.push((tokens, logits) => {
|
|
723
|
-
if (!tokens) return logits;
|
|
724
|
-
const n = tokens.shape[0]!;
|
|
725
|
-
if (n === 0) return logits;
|
|
726
|
-
const start = windowStart(n, presenceContextSize);
|
|
727
|
-
const recent = tokens.slice([start], [n]);
|
|
728
|
-
const idx = ops.reshape(recent, [1, n - start]);
|
|
729
|
-
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
730
|
-
const pen = ops.scalarLike(presencePenalty, selected);
|
|
731
|
-
const penalized = ops.sub(selected, pen);
|
|
732
|
-
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
733
|
-
for (const a of [recent, idx, selected, pen, penalized]) a.dispose();
|
|
734
|
-
return updated;
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
// make_frequency_penalty: `logits.at[:, tokens].subtract(penalty)` — a
|
|
739
|
-
// scatter-subtract that ACCUMULATES over duplicates: each token loses
|
|
740
|
-
// penalty × (occurrence count in the window). We compute the count per
|
|
741
|
-
// position ([m,m] equality matrix summed over a row — m ≤ contextSize, tiny)
|
|
742
|
-
// so every duplicate writes the identical final value and a put_along_axis
|
|
743
|
-
// reproduces the scatter-accumulate exactly.
|
|
744
|
-
if (frequencyPenalty !== undefined && frequencyPenalty !== 0) {
|
|
745
|
-
out.push((tokens, logits) => {
|
|
746
|
-
if (!tokens) return logits;
|
|
747
|
-
const n = tokens.shape[0]!;
|
|
748
|
-
if (n === 0) return logits;
|
|
749
|
-
const start = windowStart(n, frequencyContextSize);
|
|
750
|
-
const m = n - start;
|
|
751
|
-
const recent = tokens.slice([start], [n]);
|
|
752
|
-
const col = ops.reshape(recent, [m, 1]);
|
|
753
|
-
const idx = ops.reshape(recent, [1, m]);
|
|
754
|
-
const eq = ops.equal(col, idx); // [m, m]
|
|
755
|
-
const counts = ops.sumAxis(eq, -1, false); // [m] occurrences of tokens[i]
|
|
756
|
-
const countsF = counts.astype(logits.dtype);
|
|
757
|
-
const countsRow = ops.reshape(countsF, [1, m]);
|
|
758
|
-
const selected = ops.takeAlongAxis(logits, idx, -1);
|
|
759
|
-
const pen = ops.scalarLike(frequencyPenalty, selected);
|
|
760
|
-
const penTotal = ops.mul(countsRow, pen); // penalty × count
|
|
761
|
-
const penalized = ops.sub(selected, penTotal);
|
|
762
|
-
const updated = ops.putAlongAxis(logits, idx, penalized, -1);
|
|
763
|
-
for (const a of [recent, col, idx, eq, counts, countsF, countsRow, selected, pen, penTotal, penalized])
|
|
764
|
-
a.dispose();
|
|
765
|
-
return updated;
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
return out;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
/** Whether scores can use stateless greedy sampling across independent rows. */
|
|
773
|
-
export function isPlainGreedy(
|
|
774
|
-
opts: StepSamplerOptions,
|
|
775
|
-
hasProcessors = makeLogitsProcessors(opts).length > 0,
|
|
776
|
-
): boolean {
|
|
777
|
-
return (opts.temperature ?? 0) === 0 && !opts.curve && !hasProcessors && !opts.grammar;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
export function stepExtrasArrays(extras: StepExtras | null): MlxArray[] {
|
|
781
|
-
return extras
|
|
782
|
-
? [extras.sel, extras.topIdx, extras.topVals].filter(
|
|
783
|
-
(array): array is MlxArray => array !== null,
|
|
784
|
-
)
|
|
785
|
-
: [];
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
export function disposeStepExtras(extras: StepExtras | null): void {
|
|
789
|
-
if (!extras) return;
|
|
790
|
-
extras.sel?.dispose();
|
|
791
|
-
extras.topIdx?.dispose();
|
|
792
|
-
extras.topVals?.dispose();
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
/** Read captured probabilities with their token, without adding casts behind
|
|
796
|
-
* the next decode step. Consumes the capture on success and failure. */
|
|
797
|
-
export function readStepExtras(extras: StepExtras | null): TokenLogprobs | undefined {
|
|
798
|
-
if (!extras) return undefined;
|
|
799
|
-
try {
|
|
800
|
-
const out: TokenLogprobs = {};
|
|
801
|
-
if (extras.sel) out.logprob = extras.sel.toFloat32Host()[0]!;
|
|
802
|
-
if (extras.topIdx && extras.topVals) {
|
|
803
|
-
const ids = extras.topIdx.toIntTokens();
|
|
804
|
-
const vals = extras.topVals.toFloat32Host();
|
|
805
|
-
out.top = Array.from(ids, (id, i) => ({ id, logprob: vals[i]! }))
|
|
806
|
-
.sort((a, b) => b.logprob - a.logprob);
|
|
807
|
-
}
|
|
808
|
-
return out;
|
|
809
|
-
} finally { disposeStepExtras(extras); }
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
export function makeStepSampler(
|
|
813
|
-
options: StepSamplerOptions,
|
|
814
|
-
config: DeviceStepSamplerConfig,
|
|
815
|
-
): DeviceStepSampler;
|
|
816
|
-
export function makeStepSampler(
|
|
817
|
-
options: StepSamplerOptions,
|
|
818
|
-
config: NumberStepSamplerConfig,
|
|
819
|
-
): NumberStepSampler;
|
|
820
|
-
export function makeStepSampler(
|
|
821
|
-
options: StepSamplerOptions,
|
|
822
|
-
config: DeviceStepSamplerConfig | NumberStepSamplerConfig,
|
|
823
|
-
): DeviceStepSampler | NumberStepSampler {
|
|
824
|
-
const sampler = config.sampler ?? makeSampler(options);
|
|
825
|
-
const processors = makeLogitsProcessors(options);
|
|
826
|
-
const grammar = options.grammar ?? null;
|
|
827
|
-
const captureSelected = config.captureSelectedLogprob === true;
|
|
828
|
-
const captureTop = Math.max(0, config.captureTopLogprobs ?? 0);
|
|
829
|
-
const capture = captureSelected || captureTop > 0;
|
|
830
|
-
const greedyWithoutMetadata = (options.temperature ?? 0) === 0 && !options.curve && !capture && !config.sampler;
|
|
831
|
-
let history: MlxArray | null = null;
|
|
832
|
-
|
|
833
|
-
const seedHistory = (tokens: readonly number[]): void => {
|
|
834
|
-
if (processors.length === 0) return;
|
|
835
|
-
const next = ops.fromInt32([...tokens], [tokens.length]);
|
|
836
|
-
const previous = history;
|
|
837
|
-
history = next;
|
|
838
|
-
previous?.dispose();
|
|
839
|
-
};
|
|
840
|
-
|
|
841
|
-
const commitDevice = (token: MlxArray): void => {
|
|
842
|
-
if (processors.length === 0) return;
|
|
843
|
-
const one = ops.reshape(token, [1]);
|
|
844
|
-
if (!history) {
|
|
845
|
-
history = one;
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
const previous = history;
|
|
849
|
-
try {
|
|
850
|
-
history = ops.concatAxis([previous, one], 0);
|
|
851
|
-
previous.dispose();
|
|
852
|
-
} finally {
|
|
853
|
-
one.dispose();
|
|
854
|
-
}
|
|
855
|
-
};
|
|
856
|
-
|
|
857
|
-
const commitNumbers = (tokens: readonly number[]): void => {
|
|
858
|
-
if (tokens.length === 0 || processors.length === 0) return;
|
|
859
|
-
const next = ops.fromInt32([...tokens], [tokens.length]);
|
|
860
|
-
if (!history) {
|
|
861
|
-
history = next;
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
const previous = history;
|
|
865
|
-
try {
|
|
866
|
-
history = ops.concatAxis([previous, next], 0);
|
|
867
|
-
previous.dispose();
|
|
868
|
-
} finally {
|
|
869
|
-
next.dispose();
|
|
870
|
-
}
|
|
871
|
-
};
|
|
872
|
-
|
|
873
|
-
const sampleDevice = (input: MlxArray, step: number): StepSample<MlxArray> => {
|
|
874
|
-
const vocab = input.shape[input.shape.length - 1]!;
|
|
875
|
-
let current = input.shape.length === 2 ? input : ops.reshape(input, [1, vocab]);
|
|
876
|
-
let ownsCurrent = current !== input;
|
|
877
|
-
let logprobs: MlxArray | null = null;
|
|
878
|
-
let token: MlxArray | null = null;
|
|
879
|
-
let extras: StepExtras | null = null;
|
|
880
|
-
try {
|
|
881
|
-
for (const processor of processors) {
|
|
882
|
-
const next = processor(history, current);
|
|
883
|
-
if (ownsCurrent && next !== current) current.dispose();
|
|
884
|
-
current = next;
|
|
885
|
-
ownsCurrent = current !== input;
|
|
886
|
-
}
|
|
887
|
-
if (grammar && !grammar.isTerminated) {
|
|
888
|
-
const next = grammar.applyMask(current);
|
|
889
|
-
if (ownsCurrent && next !== current) current.dispose();
|
|
890
|
-
current = next;
|
|
891
|
-
ownsCurrent = current !== input;
|
|
892
|
-
}
|
|
893
|
-
if (greedyWithoutMetadata)
|
|
894
|
-
return { token: normalizedArgmax(current), extras: null };
|
|
895
|
-
logprobs = toLogprobs(current);
|
|
896
|
-
if (ownsCurrent) current.dispose();
|
|
897
|
-
current = input;
|
|
898
|
-
ownsCurrent = false;
|
|
899
|
-
token = sampler(logprobs, step);
|
|
900
|
-
|
|
901
|
-
if (capture) {
|
|
902
|
-
extras = { sel: null, topIdx: null, topVals: null };
|
|
903
|
-
if (captureSelected) {
|
|
904
|
-
const idx = ops.reshape(token, [1, 1]);
|
|
905
|
-
try {
|
|
906
|
-
extras.sel = ops.takeAlongAxis(logprobs, idx, -1);
|
|
907
|
-
} finally {
|
|
908
|
-
idx.dispose();
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
if (captureTop > 0) {
|
|
912
|
-
const k = Math.min(captureTop, vocab);
|
|
913
|
-
let neg: MlxArray | null = null;
|
|
914
|
-
let partition: MlxArray | null = null;
|
|
915
|
-
let view: MlxArray | null = null;
|
|
916
|
-
try {
|
|
917
|
-
neg = ops.neg(logprobs);
|
|
918
|
-
partition = ops.argpartitionAxis(neg, k - 1, -1);
|
|
919
|
-
view = partition.slice([0, 0], [1, k]);
|
|
920
|
-
extras.topIdx = ops.contiguous(view);
|
|
921
|
-
extras.topVals = ops.takeAlongAxis(logprobs, extras.topIdx, -1);
|
|
922
|
-
} finally {
|
|
923
|
-
neg?.dispose();
|
|
924
|
-
partition?.dispose();
|
|
925
|
-
view?.dispose();
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
logprobs.dispose();
|
|
931
|
-
logprobs = null;
|
|
932
|
-
const result = { token, extras };
|
|
933
|
-
token = null;
|
|
934
|
-
extras = null;
|
|
935
|
-
return result;
|
|
936
|
-
} finally {
|
|
937
|
-
if (ownsCurrent) current.dispose();
|
|
938
|
-
logprobs?.dispose();
|
|
939
|
-
token?.dispose();
|
|
940
|
-
disposeStepExtras(extras);
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
|
|
944
|
-
if (config.initialHistory) seedHistory(config.initialHistory);
|
|
945
|
-
|
|
946
|
-
const common = {
|
|
947
|
-
independent: isPlainGreedy(options, processors.length > 0) && !capture && !config.sampler
|
|
948
|
-
? independentGreedySampling : undefined,
|
|
949
|
-
isPlainGreedy: isPlainGreedy(options, processors.length > 0),
|
|
950
|
-
capturesLogprobs: capture,
|
|
951
|
-
needsHistory: processors.length > 0,
|
|
952
|
-
seedHistory,
|
|
953
|
-
commitDevice,
|
|
954
|
-
commitNumbers,
|
|
955
|
-
dispose: () => {
|
|
956
|
-
history?.dispose();
|
|
957
|
-
history = null;
|
|
958
|
-
},
|
|
959
|
-
};
|
|
960
|
-
|
|
961
|
-
if (config.tokenRepresentation === "device") {
|
|
962
|
-
return {
|
|
963
|
-
...common,
|
|
964
|
-
sample(logits, step) {
|
|
965
|
-
const result = sampleDevice(logits, step);
|
|
966
|
-
if (config.historyUpdate === "after-sample") commitDevice(result.token);
|
|
967
|
-
return result;
|
|
968
|
-
},
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
return {
|
|
973
|
-
...common,
|
|
974
|
-
async sample(logits, step) {
|
|
975
|
-
if (grammar && !grammar.isTerminated) await grammar.ready();
|
|
976
|
-
const result = sampleDevice(logits, step);
|
|
977
|
-
let tokenArray: MlxArray | null = result.token;
|
|
978
|
-
try {
|
|
979
|
-
// Read the sampler's integer result directly. Adding an astype here
|
|
980
|
-
// would append work behind the next dispatched decode step.
|
|
981
|
-
const token = ops.itemUint32(tokenArray);
|
|
982
|
-
tokenArray.dispose();
|
|
983
|
-
tokenArray = null;
|
|
984
|
-
if (config.acceptGrammar && grammar && !config.eosTokenIds?.includes(token))
|
|
985
|
-
grammar.accept(token);
|
|
986
|
-
if (config.historyUpdate === "after-sample") commitNumbers([token]);
|
|
987
|
-
return { token, extras: result.extras };
|
|
988
|
-
} catch (error) {
|
|
989
|
-
disposeStepExtras(result.extras);
|
|
990
|
-
throw error;
|
|
991
|
-
} finally {
|
|
992
|
-
tokenArray?.dispose();
|
|
993
|
-
}
|
|
994
|
-
},
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
/** Stateless sampling across rows or verification positions. Preserve the
|
|
999
|
-
* normalized-score argmax, including rounding-created ties. */
|
|
1000
|
-
export const independentGreedySampling = Object.freeze({
|
|
1001
|
-
sample: normalizedArgmax,
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
/** logits [..., V] → logprobs [..., V] (logits - logsumexp). */
|
|
1005
|
-
export function toLogprobs(logits: MlxArray): MlxArray {
|
|
1006
|
-
const lse = ops.logsumexpAxis(logits, -1, true);
|
|
1007
|
-
const out = ops.sub(logits, lse);
|
|
1008
|
-
lse.dispose();
|
|
1009
|
-
return out;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
export { Dtype };
|