mlx-bun 0.4.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 +1453 -88
- 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 +10 -8
- 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 +12 -10
- package/src/{serve → server}/chat-stage.ts +27 -22
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +42 -42
- 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 +42 -83
- package/src/server/generated-token-history.ts +57 -0
- 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 +8 -8
- package/src/{serve → server}/request-prep.ts +82 -68
- 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 -94
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- 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/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -1841
- package/docs/design/decode-speed-program.md +0 -2349
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -705
- package/docs/design/kv-cache.md +0 -824
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -1990
- package/docs/design/turboquant.md +0 -2212
- package/docs/design/unified-engine-frontier-plan.md +0 -1880
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -594
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/release-notes-v0.4.0.md +0 -45
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3613
- package/docs/reference/cli.md +0 -585
- package/docs/reference/distribution.md +0 -355
- package/docs/reference/environment.md +0 -398
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -674
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -334
- package/docs/reference/server-api.md +0 -1775
- package/docs/reference/server-config.md +0 -846
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/conformer.ts +0 -647
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/transcode.ts +0 -67
- 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 -108
- package/src/backends/mlx/batch-group.ts +0 -1790
- 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 -106
- 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/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -45
- 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 -130
- 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 -133
- 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/model-prompt.ts +0 -164
- package/src/backends/mlx/model-serving.ts +0 -79
- package/src/backends/mlx/prefill-cohort.ts +0 -89
- package/src/backends/mlx/prefill-rows.ts +0 -200
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -41
- package/src/backends/mlx/rollback.ts +0 -89
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -242
- package/src/backends/mlx/speculative-group.ts +0 -359
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -114
- 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 -165
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3168
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -60
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -259
- package/src/contracts/prefix-cache.ts +0 -23
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -45
- 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 -53
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -72
- 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 -452
- 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 -1346
- package/src/grammar.ts +0 -591
- 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 -39
- 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 -257
- package/src/kv-store.ts +0 -1099
- package/src/lab/README.md +0 -18
- 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-kv-rows.ts +0 -83
- package/src/lab/paged-kv/paged-kv.ts +0 -270
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -49
- 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 -388
- 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 -512
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/ops.ts +0 -1021
- 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 -93
- 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 -55
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -189
- package/src/model/fingerprint.ts +0 -33
- 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 -2351
- package/src/model/gemma4.ts +0 -1315
- 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 -67
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -443
- 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 -252
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -819
- 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 -102
- 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 -83
- 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/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native-pack.ts +0 -162
- 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 -1932
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -460
- 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 -81
- package/src/safetensors.ts +0 -158
- package/src/sampler.ts +0 -1011
- 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/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 -496
- 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 -43
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -147
- 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/server.ts +0 -1314
- package/src/spec/assistant-rows.ts +0 -92
- 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 -317
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -204
- 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 -219
- package/src/spec/qwen-mtp-source.ts +0 -383
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -585
- package/src/spec/source.ts +0 -215
- package/src/spec/two-model-rows.ts +0 -61
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -372
- package/src/ssd-durability.ts +0 -211
- 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 -168
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -373
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -196
- package/src/vision/qwen3vl-tower.ts +0 -555
- package/src/vision/siglip.ts +0 -599
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2143
- package/src/web/app.js +0 -5703
- 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 -1057
- package/src/web/src/composer.ts +0 -959
- 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/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/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
|
@@ -1,694 +0,0 @@
|
|
|
1
|
-
// L2 flash-attention training kernels — port of optiq/ops/flash_attention_{metal,
|
|
2
|
-
// backward_metal}.py. FlashAttention-2 as Metal kernels: the forward runs in one
|
|
3
|
-
// dispatch with online softmax (never materializing the [.,L,L] score matrix),
|
|
4
|
-
// and the backward is three dispatches (D-vec, dKV, dQ) that recompute scores per
|
|
5
|
-
// tile. Memory is O(seq·head_dim), not O(seq²) — this is what lets long-context
|
|
6
|
-
// LoRA training fit where stock fast-sdpa (L1) tops out ~2048 tokens.
|
|
7
|
-
//
|
|
8
|
-
// Bit-exact to OPTIQ (the L2 oracle), NOT to mlx-lm: online softmax accumulates
|
|
9
|
-
// in fp32 but stores fp16, so it differs from one-shot SDPA. Wired through
|
|
10
|
-
// CustomVjp (the forward is a CustomKernel with no auto-vjp).
|
|
11
|
-
//
|
|
12
|
-
// Shaders are copied verbatim from optiq; only the host glue is TS.
|
|
13
|
-
|
|
14
|
-
import { MlxArray } from "../mlx/array";
|
|
15
|
-
import { Dtype } from "../mlx/ffi";
|
|
16
|
-
import * as ops from "../mlx/ops";
|
|
17
|
-
import { MetalKernel } from "../mlx/metal-kernel";
|
|
18
|
-
import { CustomVjp } from "../mlx/custom-vjp";
|
|
19
|
-
import { createCausalMask, type Mask } from "./gemma4-base";
|
|
20
|
-
|
|
21
|
-
export const SUPPORTED_HEAD_DIMS = new Set([64, 96, 128, 256, 512]);
|
|
22
|
-
|
|
23
|
-
/** (BLOCK_Q, BLOCK_KV) for the forward kernel at this head_dim. */
|
|
24
|
-
function forwardTiles(headDim: number): [number, number] {
|
|
25
|
-
if (headDim <= 64) return [64, 64];
|
|
26
|
-
if (headDim <= 128) return [32, 32];
|
|
27
|
-
if (headDim <= 256) return [16, 16];
|
|
28
|
-
if (headDim <= 512) return [8, 8];
|
|
29
|
-
throw new Error(`unsupported head_dim=${headDim}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** uint32 [n] array (matches optiq's shape/causal input dtype). COPY into an
|
|
33
|
-
* mlx-owned array (not the pinning fromView) — these tiny kernel-arg arrays are
|
|
34
|
-
* disposed before the lazy kernel evaluates; pinning leaks the host buffer per
|
|
35
|
-
* call (see flash-cce.ts u32 for the full diagnosis). */
|
|
36
|
-
function u32(values: number[]): MlxArray {
|
|
37
|
-
return MlxArray.fromBytesCopy(new Uint8Array(new Uint32Array(values).buffer), [values.length], Dtype.uint32);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Forward shader — verbatim from optiq flash_attention_metal.py _KERNEL_SOURCE.
|
|
41
|
-
const FWD_SOURCE = `
|
|
42
|
-
const uint q_tile_idx = threadgroup_position_in_grid.x;
|
|
43
|
-
const uint head = threadgroup_position_in_grid.y; // 0..Hq-1
|
|
44
|
-
const uint batch = threadgroup_position_in_grid.z;
|
|
45
|
-
const uint tid = thread_position_in_threadgroup.x;
|
|
46
|
-
|
|
47
|
-
const uint B = shape[0];
|
|
48
|
-
const uint Hq = shape[1];
|
|
49
|
-
const uint Hkv = shape[2];
|
|
50
|
-
const uint Tq = shape[3];
|
|
51
|
-
const uint Tkv = shape[4];
|
|
52
|
-
const uint D = shape[5];
|
|
53
|
-
|
|
54
|
-
const float fscale = scale[0];
|
|
55
|
-
const uint is_causal = causal[0];
|
|
56
|
-
|
|
57
|
-
const uint reps = Hq / Hkv;
|
|
58
|
-
const uint kv_head = head / reps;
|
|
59
|
-
|
|
60
|
-
const uint q_row_global = q_tile_idx * BQ + tid;
|
|
61
|
-
const bool q_row_valid = q_row_global < Tq;
|
|
62
|
-
|
|
63
|
-
threadgroup half q_tile[BQ * D_MAX];
|
|
64
|
-
threadgroup half k_tile[BKV * D_MAX];
|
|
65
|
-
threadgroup half v_tile[BKV * D_MAX];
|
|
66
|
-
|
|
67
|
-
float m_i = -INFINITY;
|
|
68
|
-
float l_i = 0.0f;
|
|
69
|
-
float o_i[D_MAX];
|
|
70
|
-
for (uint d = 0; d < D; ++d) { o_i[d] = 0.0f; }
|
|
71
|
-
|
|
72
|
-
if (q_row_valid) {
|
|
73
|
-
const uint q_base = ((batch * Hq + head) * Tq + q_row_global) * D;
|
|
74
|
-
for (uint d = 0; d < D; ++d) {
|
|
75
|
-
q_tile[tid * D + d] = q[q_base + d];
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
for (uint d = 0; d < D; ++d) {
|
|
79
|
-
q_tile[tid * D + d] = 0.0h;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
83
|
-
|
|
84
|
-
const uint n_kv_tiles = (Tkv + BKV - 1u) / BKV;
|
|
85
|
-
for (uint kv_tile = 0u; kv_tile < n_kv_tiles; ++kv_tile) {
|
|
86
|
-
const uint kv_base_row = kv_tile * BKV;
|
|
87
|
-
|
|
88
|
-
const uint rows_this_tile = min((uint)BKV, Tkv - kv_base_row);
|
|
89
|
-
if (tid < rows_this_tile) {
|
|
90
|
-
const uint kv_global_row = kv_base_row + tid;
|
|
91
|
-
const uint kv_global = ((batch * Hkv + kv_head) * Tkv + kv_global_row) * D;
|
|
92
|
-
for (uint d = 0; d < D; ++d) {
|
|
93
|
-
k_tile[tid * D + d] = k[kv_global + d];
|
|
94
|
-
v_tile[tid * D + d] = v[kv_global + d];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
98
|
-
|
|
99
|
-
if (is_causal && kv_base_row > q_row_global) {
|
|
100
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
float s[BKV];
|
|
105
|
-
float row_max = -INFINITY;
|
|
106
|
-
for (uint j = 0u; j < rows_this_tile; ++j) {
|
|
107
|
-
float dot = 0.0f;
|
|
108
|
-
for (uint d = 0u; d < D; ++d) {
|
|
109
|
-
dot += (float)q_tile[tid * D + d] * (float)k_tile[j * D + d];
|
|
110
|
-
}
|
|
111
|
-
dot *= fscale;
|
|
112
|
-
const uint kpos = kv_base_row + j;
|
|
113
|
-
if (is_causal && kpos > q_row_global) {
|
|
114
|
-
dot = -INFINITY;
|
|
115
|
-
} else if (shape[6] != 0u && q_row_global >= kpos && (q_row_global - kpos) >= shape[6]) {
|
|
116
|
-
dot = -INFINITY; // sliding window: too far in the past
|
|
117
|
-
}
|
|
118
|
-
s[j] = dot;
|
|
119
|
-
row_max = max(row_max, dot);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const float m_new = max(m_i, row_max);
|
|
123
|
-
// Skip a tile that is fully masked for this q row (every score -inf) —
|
|
124
|
-
// happens with a sliding window when a past tile is entirely out of range.
|
|
125
|
-
// Without this guard the online softmax does exp(-inf - -inf) = NaN.
|
|
126
|
-
if (m_new > -INFINITY) {
|
|
127
|
-
const float rescale = exp(m_i - m_new);
|
|
128
|
-
float row_sum = 0.0f;
|
|
129
|
-
for (uint j = 0u; j < rows_this_tile; ++j) {
|
|
130
|
-
s[j] = exp(s[j] - m_new);
|
|
131
|
-
row_sum += s[j];
|
|
132
|
-
}
|
|
133
|
-
l_i = rescale * l_i + row_sum;
|
|
134
|
-
|
|
135
|
-
for (uint d = 0u; d < D; ++d) {
|
|
136
|
-
float new_contrib = 0.0f;
|
|
137
|
-
for (uint j = 0u; j < rows_this_tile; ++j) {
|
|
138
|
-
new_contrib += s[j] * (float)v_tile[j * D + d];
|
|
139
|
-
}
|
|
140
|
-
o_i[d] = rescale * o_i[d] + new_contrib;
|
|
141
|
-
}
|
|
142
|
-
m_i = m_new;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (q_row_valid) {
|
|
149
|
-
const uint out_base = ((batch * Hq + head) * Tq + q_row_global) * D;
|
|
150
|
-
const float inv_l = 1.0f / l_i;
|
|
151
|
-
for (uint d = 0u; d < D; ++d) {
|
|
152
|
-
o[out_base + d] = (half)(o_i[d] * inv_l);
|
|
153
|
-
}
|
|
154
|
-
const uint lse_base = (batch * Hq + head) * Tq + q_row_global;
|
|
155
|
-
l_out[lse_base] = m_i + log(l_i);
|
|
156
|
-
}
|
|
157
|
-
`;
|
|
158
|
-
|
|
159
|
-
const fwdKernels = new Map<number, MetalKernel>();
|
|
160
|
-
function fwdKernel(headDim: number): MetalKernel {
|
|
161
|
-
let k = fwdKernels.get(headDim);
|
|
162
|
-
if (!k) {
|
|
163
|
-
const [bq, bkv] = forwardTiles(headDim);
|
|
164
|
-
const header = `#define BQ ${bq}\n#define BKV ${bkv}\n#define D_MAX ${headDim}\n`;
|
|
165
|
-
k = new MetalKernel({
|
|
166
|
-
name: `optiq_flash_attention_fwd_d${headDim}`,
|
|
167
|
-
inputNames: ["q", "k", "v", "shape", "scale", "causal"],
|
|
168
|
-
outputNames: ["o", "l_out"],
|
|
169
|
-
source: FWD_SOURCE,
|
|
170
|
-
header,
|
|
171
|
-
ensureRowContiguous: true,
|
|
172
|
-
});
|
|
173
|
-
fwdKernels.set(headDim, k);
|
|
174
|
-
}
|
|
175
|
-
return k;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** Single-dispatch Metal flash-attention forward. q,k,v are fp16
|
|
179
|
-
* ([B,Hq,Tq,D] / [B,Hkv,Tkv,D]). Returns [O fp16, L fp32 (log-sum-exp)]. */
|
|
180
|
-
export function flashForward(
|
|
181
|
-
q: MlxArray, k: MlxArray, v: MlxArray, scale: number, causal: boolean, window = 0,
|
|
182
|
-
): [MlxArray, MlxArray] {
|
|
183
|
-
const [B, Hq, Tq, D] = q.shape as [number, number, number, number];
|
|
184
|
-
const [, Hkv, Tkv] = k.shape as [number, number, number, number];
|
|
185
|
-
const [bq] = forwardTiles(D);
|
|
186
|
-
const nQTiles = Math.ceil(Tq / bq);
|
|
187
|
-
|
|
188
|
-
const shape = u32([B, Hq, Hkv, Tq, Tkv, D, window]);
|
|
189
|
-
const scaleArr = MlxArray.fromFloat32(new Float32Array([scale]), [1]);
|
|
190
|
-
const causalArr = u32([causal ? 1 : 0]);
|
|
191
|
-
try {
|
|
192
|
-
const outs = fwdKernel(D).apply([q, k, v, shape, scaleArr, causalArr], {
|
|
193
|
-
outputs: [
|
|
194
|
-
{ shape: [B, Hq, Tq, D], dtype: Dtype.float16 },
|
|
195
|
-
{ shape: [B, Hq, Tq], dtype: Dtype.float32 },
|
|
196
|
-
],
|
|
197
|
-
grid: [nQTiles * bq, Hq, B],
|
|
198
|
-
threadGroup: [bq, 1, 1],
|
|
199
|
-
});
|
|
200
|
-
return [outs[0]!, outs[1]!];
|
|
201
|
-
} finally {
|
|
202
|
-
shape.dispose();
|
|
203
|
-
scaleArr.dispose();
|
|
204
|
-
causalArr.dispose();
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// ---------------------------------------------------------------------------
|
|
209
|
-
// Backward — three Metal dispatches (D-vec, dKV, dQ), verbatim from optiq
|
|
210
|
-
// flash_attention_backward_metal.py.
|
|
211
|
-
// ---------------------------------------------------------------------------
|
|
212
|
-
|
|
213
|
-
/** (BQ_BWD, BKV_BWD) for the backward kernels at this head_dim. */
|
|
214
|
-
function backwardTiles(headDim: number): [number, number] {
|
|
215
|
-
if (headDim <= 64) return [32, 32];
|
|
216
|
-
if (headDim <= 128) return [16, 32];
|
|
217
|
-
if (headDim <= 256) return [8, 16];
|
|
218
|
-
if (headDim <= 512) return [4, 8];
|
|
219
|
-
throw new Error(`unsupported head_dim=${headDim}`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Pass 1: D_i = rowsum(dO_i ⊙ O_i). No tile defines needed.
|
|
223
|
-
const D_SOURCE = `
|
|
224
|
-
const uint idx = thread_position_in_grid.x;
|
|
225
|
-
const uint B = shape[0];
|
|
226
|
-
const uint Hq = shape[1];
|
|
227
|
-
const uint Tq = shape[2];
|
|
228
|
-
const uint D = shape[3];
|
|
229
|
-
const uint total = B * Hq * Tq;
|
|
230
|
-
if (idx >= total) return;
|
|
231
|
-
|
|
232
|
-
const uint base = idx * D;
|
|
233
|
-
float acc = 0.0f;
|
|
234
|
-
for (uint d = 0u; d < D; ++d) {
|
|
235
|
-
acc += (float)o[base + d] * (float)do_[base + d];
|
|
236
|
-
}
|
|
237
|
-
d_out[idx] = acc;
|
|
238
|
-
`;
|
|
239
|
-
|
|
240
|
-
// Pass 2: dK, dV — one dispatch per KV tile, inner loop over Q tiles.
|
|
241
|
-
const DKV_SOURCE = `
|
|
242
|
-
const uint kv_tile_idx = threadgroup_position_in_grid.x;
|
|
243
|
-
const uint kv_head = threadgroup_position_in_grid.y; // 0..Hkv-1
|
|
244
|
-
const uint batch = threadgroup_position_in_grid.z;
|
|
245
|
-
const uint tid = thread_position_in_threadgroup.x;
|
|
246
|
-
|
|
247
|
-
const uint B = shape[0];
|
|
248
|
-
const uint Hq = shape[1];
|
|
249
|
-
const uint Hkv = shape[2];
|
|
250
|
-
const uint Tq = shape[3];
|
|
251
|
-
const uint Tkv = shape[4];
|
|
252
|
-
const uint D = shape[5];
|
|
253
|
-
const uint reps = Hq / Hkv;
|
|
254
|
-
|
|
255
|
-
const float fscale = scale[0];
|
|
256
|
-
const uint is_causal = causal[0];
|
|
257
|
-
|
|
258
|
-
const uint kv_row_global = kv_tile_idx * BKV + tid;
|
|
259
|
-
const bool kv_row_valid = kv_row_global < Tkv;
|
|
260
|
-
|
|
261
|
-
threadgroup half q_tile[BQ * D_MAX];
|
|
262
|
-
threadgroup half do_tile[BQ * D_MAX];
|
|
263
|
-
threadgroup half k_tile[BKV * D_MAX];
|
|
264
|
-
threadgroup half v_tile[BKV * D_MAX];
|
|
265
|
-
threadgroup float l_tile[BQ];
|
|
266
|
-
threadgroup float dRow[BQ];
|
|
267
|
-
|
|
268
|
-
float dK_j[D_MAX];
|
|
269
|
-
float dV_j[D_MAX];
|
|
270
|
-
for (uint d = 0u; d < D; ++d) {
|
|
271
|
-
dK_j[d] = 0.0f;
|
|
272
|
-
dV_j[d] = 0.0f;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (kv_row_valid) {
|
|
276
|
-
const uint kv_base = ((batch * Hkv + kv_head) * Tkv + kv_row_global) * D;
|
|
277
|
-
for (uint d = 0u; d < D; ++d) {
|
|
278
|
-
k_tile[tid * D + d] = k[kv_base + d];
|
|
279
|
-
v_tile[tid * D + d] = v[kv_base + d];
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
283
|
-
|
|
284
|
-
const uint n_q_tiles = (Tq + BQ - 1u) / BQ;
|
|
285
|
-
for (uint q_h_rel = 0u; q_h_rel < reps; ++q_h_rel) {
|
|
286
|
-
const uint q_head = kv_head * reps + q_h_rel;
|
|
287
|
-
|
|
288
|
-
for (uint qi = 0u; qi < n_q_tiles; ++qi) {
|
|
289
|
-
const uint q_base_row = qi * BQ;
|
|
290
|
-
|
|
291
|
-
if (is_causal && (q_base_row + BQ) <= kv_tile_idx * BKV) {
|
|
292
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const uint rows_this_q = min((uint)BQ, Tq - q_base_row);
|
|
297
|
-
if (tid < rows_this_q) {
|
|
298
|
-
const uint q_global_row = q_base_row + tid;
|
|
299
|
-
const uint q_base = ((batch * Hq + q_head) * Tq + q_global_row) * D;
|
|
300
|
-
for (uint d = 0u; d < D; ++d) {
|
|
301
|
-
q_tile[tid * D + d] = q[q_base + d];
|
|
302
|
-
do_tile[tid * D + d] = do_[q_base + d];
|
|
303
|
-
}
|
|
304
|
-
const uint lse_idx = (batch * Hq + q_head) * Tq + q_global_row;
|
|
305
|
-
l_tile[tid] = l_in[lse_idx];
|
|
306
|
-
dRow[tid] = d_vec[lse_idx];
|
|
307
|
-
}
|
|
308
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
309
|
-
|
|
310
|
-
if (kv_row_valid) {
|
|
311
|
-
for (uint i = 0u; i < rows_this_q; ++i) {
|
|
312
|
-
float s = 0.0f;
|
|
313
|
-
for (uint d = 0u; d < D; ++d) {
|
|
314
|
-
s += (float)q_tile[i * D + d] * (float)k_tile[tid * D + d];
|
|
315
|
-
}
|
|
316
|
-
s *= fscale;
|
|
317
|
-
const uint q_row_global = q_base_row + i;
|
|
318
|
-
if (is_causal && kv_row_global > q_row_global) {
|
|
319
|
-
s = -INFINITY;
|
|
320
|
-
} else if (shape[6] != 0u && q_row_global >= kv_row_global && (q_row_global - kv_row_global) >= shape[6]) {
|
|
321
|
-
s = -INFINITY; // sliding window
|
|
322
|
-
}
|
|
323
|
-
const float p = exp(s - l_tile[i]);
|
|
324
|
-
|
|
325
|
-
float dp = 0.0f;
|
|
326
|
-
for (uint d = 0u; d < D; ++d) {
|
|
327
|
-
dp += (float)do_tile[i * D + d] * (float)v_tile[tid * D + d];
|
|
328
|
-
}
|
|
329
|
-
const float ds = p * (dp - dRow[i]);
|
|
330
|
-
|
|
331
|
-
for (uint d = 0u; d < D; ++d) {
|
|
332
|
-
dV_j[d] += p * (float)do_tile[i * D + d];
|
|
333
|
-
}
|
|
334
|
-
for (uint d = 0u; d < D; ++d) {
|
|
335
|
-
dK_j[d] += ds * (float)q_tile[i * D + d] * fscale;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (kv_row_valid) {
|
|
344
|
-
const uint out_base = ((batch * Hkv + kv_head) * Tkv + kv_row_global) * D;
|
|
345
|
-
for (uint d = 0u; d < D; ++d) {
|
|
346
|
-
dk_out[out_base + d] = (half)dK_j[d];
|
|
347
|
-
dv_out[out_base + d] = (half)dV_j[d];
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
`;
|
|
351
|
-
|
|
352
|
-
// Pass 3: dQ — one dispatch per Q tile, inner loop over KV tiles.
|
|
353
|
-
const DQ_SOURCE = `
|
|
354
|
-
const uint q_tile_idx = threadgroup_position_in_grid.x;
|
|
355
|
-
const uint head = threadgroup_position_in_grid.y; // 0..Hq-1
|
|
356
|
-
const uint batch = threadgroup_position_in_grid.z;
|
|
357
|
-
const uint tid = thread_position_in_threadgroup.x;
|
|
358
|
-
|
|
359
|
-
const uint B = shape[0];
|
|
360
|
-
const uint Hq = shape[1];
|
|
361
|
-
const uint Hkv = shape[2];
|
|
362
|
-
const uint Tq = shape[3];
|
|
363
|
-
const uint Tkv = shape[4];
|
|
364
|
-
const uint D = shape[5];
|
|
365
|
-
|
|
366
|
-
const uint reps = Hq / Hkv;
|
|
367
|
-
const uint kv_head = head / reps;
|
|
368
|
-
|
|
369
|
-
const float fscale = scale[0];
|
|
370
|
-
const uint is_causal = causal[0];
|
|
371
|
-
|
|
372
|
-
const uint q_row_global = q_tile_idx * BQ + tid;
|
|
373
|
-
const bool q_row_valid = q_row_global < Tq;
|
|
374
|
-
|
|
375
|
-
threadgroup half k_tile[BKV * D_MAX];
|
|
376
|
-
threadgroup half v_tile[BKV * D_MAX];
|
|
377
|
-
|
|
378
|
-
half q_i[D_MAX];
|
|
379
|
-
half do_i[D_MAX];
|
|
380
|
-
float l_i = 0.0f;
|
|
381
|
-
float D_i = 0.0f;
|
|
382
|
-
float dq_i[D_MAX];
|
|
383
|
-
for (uint d = 0u; d < D; ++d) { dq_i[d] = 0.0f; }
|
|
384
|
-
|
|
385
|
-
if (q_row_valid) {
|
|
386
|
-
const uint q_base = ((batch * Hq + head) * Tq + q_row_global) * D;
|
|
387
|
-
for (uint d = 0u; d < D; ++d) {
|
|
388
|
-
q_i[d] = q[q_base + d];
|
|
389
|
-
do_i[d] = do_[q_base + d];
|
|
390
|
-
}
|
|
391
|
-
const uint lse_idx = (batch * Hq + head) * Tq + q_row_global;
|
|
392
|
-
l_i = l_in[lse_idx];
|
|
393
|
-
D_i = d_vec[lse_idx];
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const uint n_kv_tiles = (Tkv + BKV - 1u) / BKV;
|
|
397
|
-
for (uint kj = 0u; kj < n_kv_tiles; ++kj) {
|
|
398
|
-
const uint kv_base_row = kj * BKV;
|
|
399
|
-
|
|
400
|
-
const uint rows_this_tile = min((uint)BKV, Tkv - kv_base_row);
|
|
401
|
-
for (uint r = tid; r < rows_this_tile; r += BQ) {
|
|
402
|
-
const uint kv_global_row = kv_base_row + r;
|
|
403
|
-
const uint kv_base = ((batch * Hkv + kv_head) * Tkv + kv_global_row) * D;
|
|
404
|
-
for (uint d = 0u; d < D; ++d) {
|
|
405
|
-
k_tile[r * D + d] = k[kv_base + d];
|
|
406
|
-
v_tile[r * D + d] = v[kv_base + d];
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
410
|
-
|
|
411
|
-
// Skip a KV tile only when it is entirely beyond this Q tile's last row
|
|
412
|
-
// (fully causally masked). The condition is UNIFORM across the threadgroup
|
|
413
|
-
// (q_tile_idx·BQ is the same for every thread), so the barrier below is hit
|
|
414
|
-
// by all threads — using the per-thread q_row_global here would diverge the
|
|
415
|
-
// barrier (undefined behavior). The per-element mask below still handles the
|
|
416
|
-
// partial diagonal tile.
|
|
417
|
-
if (is_causal && kv_base_row >= (q_tile_idx * BQ + BQ)) {
|
|
418
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (q_row_valid) {
|
|
423
|
-
for (uint j = 0u; j < rows_this_tile; ++j) {
|
|
424
|
-
float s = 0.0f;
|
|
425
|
-
for (uint d = 0u; d < D; ++d) {
|
|
426
|
-
s += (float)q_i[d] * (float)k_tile[j * D + d];
|
|
427
|
-
}
|
|
428
|
-
s *= fscale;
|
|
429
|
-
const uint kpos = kv_base_row + j;
|
|
430
|
-
if (is_causal && kpos > q_row_global) {
|
|
431
|
-
s = -INFINITY;
|
|
432
|
-
} else if (shape[6] != 0u && q_row_global >= kpos && (q_row_global - kpos) >= shape[6]) {
|
|
433
|
-
s = -INFINITY; // sliding window
|
|
434
|
-
}
|
|
435
|
-
float p = exp(s - l_i);
|
|
436
|
-
float dp = 0.0f;
|
|
437
|
-
for (uint d = 0u; d < D; ++d) {
|
|
438
|
-
dp += (float)do_i[d] * (float)v_tile[j * D + d];
|
|
439
|
-
}
|
|
440
|
-
float ds = p * (dp - D_i);
|
|
441
|
-
for (uint d = 0u; d < D; ++d) {
|
|
442
|
-
dq_i[d] += ds * (float)k_tile[j * D + d] * fscale;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (q_row_valid) {
|
|
450
|
-
const uint out_base = ((batch * Hq + head) * Tq + q_row_global) * D;
|
|
451
|
-
for (uint d = 0u; d < D; ++d) {
|
|
452
|
-
dq_out[out_base + d] = (half)dq_i[d];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
`;
|
|
456
|
-
|
|
457
|
-
let dKernelCache: MetalKernel | null = null;
|
|
458
|
-
function dKernel(): MetalKernel {
|
|
459
|
-
if (!dKernelCache)
|
|
460
|
-
dKernelCache = new MetalKernel({
|
|
461
|
-
name: "optiq_flash_attention_D",
|
|
462
|
-
inputNames: ["o", "do_", "shape"],
|
|
463
|
-
outputNames: ["d_out"],
|
|
464
|
-
source: D_SOURCE,
|
|
465
|
-
ensureRowContiguous: true,
|
|
466
|
-
});
|
|
467
|
-
return dKernelCache;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const dkvKernels = new Map<number, MetalKernel>();
|
|
471
|
-
function dkvKernel(headDim: number): MetalKernel {
|
|
472
|
-
let k = dkvKernels.get(headDim);
|
|
473
|
-
if (!k) {
|
|
474
|
-
const [bq, bkv] = backwardTiles(headDim);
|
|
475
|
-
const header = `#define BQ ${bq}\n#define BKV ${bkv}\n#define D_MAX ${headDim}\n`;
|
|
476
|
-
k = new MetalKernel({
|
|
477
|
-
name: `optiq_flash_attention_dKV_d${headDim}`,
|
|
478
|
-
inputNames: ["q", "k", "v", "do_", "l_in", "d_vec", "shape", "scale", "causal"],
|
|
479
|
-
outputNames: ["dk_out", "dv_out"],
|
|
480
|
-
source: DKV_SOURCE,
|
|
481
|
-
header,
|
|
482
|
-
ensureRowContiguous: true,
|
|
483
|
-
});
|
|
484
|
-
dkvKernels.set(headDim, k);
|
|
485
|
-
}
|
|
486
|
-
return k;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const dqKernels = new Map<number, MetalKernel>();
|
|
490
|
-
function dqKernel(headDim: number): MetalKernel {
|
|
491
|
-
let k = dqKernels.get(headDim);
|
|
492
|
-
if (!k) {
|
|
493
|
-
const [bq, bkv] = backwardTiles(headDim);
|
|
494
|
-
const header = `#define BQ ${bq}\n#define BKV ${bkv}\n#define D_MAX ${headDim}\n`;
|
|
495
|
-
k = new MetalKernel({
|
|
496
|
-
name: `optiq_flash_attention_dQ_d${headDim}`,
|
|
497
|
-
inputNames: ["q", "k", "v", "do_", "l_in", "d_vec", "shape", "scale", "causal"],
|
|
498
|
-
outputNames: ["dq_out"],
|
|
499
|
-
source: DQ_SOURCE,
|
|
500
|
-
header,
|
|
501
|
-
ensureRowContiguous: true,
|
|
502
|
-
});
|
|
503
|
-
dqKernels.set(headDim, k);
|
|
504
|
-
}
|
|
505
|
-
return k;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/** Three-dispatch Metal backward. q,k,v,O,dO fp16; L fp32. Returns [dQ,dK,dV]. */
|
|
509
|
-
export function flashBackward(
|
|
510
|
-
q: MlxArray, k: MlxArray, v: MlxArray, O: MlxArray, L: MlxArray, dO: MlxArray,
|
|
511
|
-
scale: number, causal: boolean, window = 0,
|
|
512
|
-
): [MlxArray, MlxArray, MlxArray] {
|
|
513
|
-
const [B, Hq, Tq, D] = q.shape as [number, number, number, number];
|
|
514
|
-
const [, Hkv, Tkv] = k.shape as [number, number, number, number];
|
|
515
|
-
const [bq, bkv] = backwardTiles(D);
|
|
516
|
-
|
|
517
|
-
const dShape = u32([B, Hq, Tq, D]);
|
|
518
|
-
const Dvec = dKernel().apply([O, dO, dShape], {
|
|
519
|
-
outputs: [{ shape: [B, Hq, Tq], dtype: Dtype.float32 }],
|
|
520
|
-
grid: [B * Hq * Tq, 1, 1],
|
|
521
|
-
threadGroup: [256, 1, 1],
|
|
522
|
-
})[0]!;
|
|
523
|
-
dShape.dispose();
|
|
524
|
-
|
|
525
|
-
const shape = u32([B, Hq, Hkv, Tq, Tkv, D, window]);
|
|
526
|
-
const scaleArr = MlxArray.fromFloat32(new Float32Array([scale]), [1]);
|
|
527
|
-
const causalArr = u32([causal ? 1 : 0]);
|
|
528
|
-
try {
|
|
529
|
-
const nKvTiles = Math.ceil(Tkv / bkv);
|
|
530
|
-
const dkv = dkvKernel(D).apply([q, k, v, dO, L, Dvec, shape, scaleArr, causalArr], {
|
|
531
|
-
outputs: [
|
|
532
|
-
{ shape: [B, Hkv, Tkv, D], dtype: Dtype.float16 },
|
|
533
|
-
{ shape: [B, Hkv, Tkv, D], dtype: Dtype.float16 },
|
|
534
|
-
],
|
|
535
|
-
grid: [nKvTiles * bkv, Hkv, B],
|
|
536
|
-
threadGroup: [bkv, 1, 1],
|
|
537
|
-
});
|
|
538
|
-
const nQTiles = Math.ceil(Tq / bq);
|
|
539
|
-
const dq = dqKernel(D).apply([q, k, v, dO, L, Dvec, shape, scaleArr, causalArr], {
|
|
540
|
-
outputs: [{ shape: [B, Hq, Tq, D], dtype: Dtype.float16 }],
|
|
541
|
-
grid: [nQTiles * bq, Hq, B],
|
|
542
|
-
threadGroup: [bq, 1, 1],
|
|
543
|
-
});
|
|
544
|
-
// dK is written by the kernel in the correct [B,Hkv,Tkv,D] layout
|
|
545
|
-
// (dK_j[d] → [kv_row][d]); no post-transpose. (An earlier "fix" transposed
|
|
546
|
-
// it on the false belief the buffer was swapped — that transpose is only the
|
|
547
|
-
// identity at Tkv==D and corrupted dK for Tkv≠D; removed after
|
|
548
|
-
// flash-dkv-debug.ts (deleted 2026-08-23; git history) showed the raw output is correct.)
|
|
549
|
-
return [dq[0]!, dkv[0]!, dkv[1]!];
|
|
550
|
-
} finally {
|
|
551
|
-
Dvec.dispose();
|
|
552
|
-
shape.dispose();
|
|
553
|
-
scaleArr.dispose();
|
|
554
|
-
causalArr.dispose();
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// ---------------------------------------------------------------------------
|
|
559
|
-
// Differentiable op: flash forward + manual backward via CustomVjp.
|
|
560
|
-
// ---------------------------------------------------------------------------
|
|
561
|
-
|
|
562
|
-
// One CustomVjp per (head_dim, scale, causal) — the closures capture those as
|
|
563
|
-
// constants and read q/k/v from the input vector, so a single instance is
|
|
564
|
-
// reused across layers/steps. Module-cached (never disposed): the closures
|
|
565
|
-
// must outlive every value_and_grad apply.
|
|
566
|
-
const faCache = new Map<string, CustomVjp>();
|
|
567
|
-
function faOp(headDim: number, scale: number, causal: boolean, window: number): CustomVjp {
|
|
568
|
-
const key = `${headDim}|${scale}|${causal ? 1 : 0}|${window}`;
|
|
569
|
-
let cv = faCache.get(key);
|
|
570
|
-
if (!cv) {
|
|
571
|
-
cv = new CustomVjp(
|
|
572
|
-
(ins) => {
|
|
573
|
-
const [O, L] = flashForward(ins[0]!, ins[1]!, ins[2]!, scale, causal, window);
|
|
574
|
-
return [O, L];
|
|
575
|
-
},
|
|
576
|
-
(primals, cots, outs) => {
|
|
577
|
-
// primals=[q,k,v]; cots=[dO, dL] (dL=0, discarded); outs=[O, L]
|
|
578
|
-
return flashBackward(primals[0]!, primals[1]!, primals[2]!, outs[0]!, outs[1]!, cots[0]!, scale, causal, window);
|
|
579
|
-
},
|
|
580
|
-
);
|
|
581
|
-
faCache.set(key, cv);
|
|
582
|
-
}
|
|
583
|
-
return cv;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/** Differentiable flash attention matching optiq's training kernel. q,k,v are
|
|
587
|
-
* [B,Hq,Tq,D]/[B,Hkv,Tkv,D]; bf16 is cast to fp16 (kernel dtype) and the
|
|
588
|
-
* output cast back. Only causal/full attention (sliding-window masks fall
|
|
589
|
-
* back to ops.sdpa at the call site, mirroring optiq's router). */
|
|
590
|
-
export function flashAttention(
|
|
591
|
-
q: MlxArray, k: MlxArray, v: MlxArray, scale: number, causal: boolean, window = 0,
|
|
592
|
-
): MlxArray {
|
|
593
|
-
const D = q.shape[3]!;
|
|
594
|
-
const inDtype = q.dtype;
|
|
595
|
-
const f16 = inDtype === Dtype.float16;
|
|
596
|
-
const q16 = f16 ? q : q.astype(Dtype.float16);
|
|
597
|
-
const k16 = f16 ? k : k.astype(Dtype.float16);
|
|
598
|
-
const v16 = f16 ? v : v.astype(Dtype.float16);
|
|
599
|
-
|
|
600
|
-
const outs = faOp(D, scale, causal, window).apply([q16, k16, v16]);
|
|
601
|
-
const O = outs[0]!;
|
|
602
|
-
outs[1]?.dispose(); // L — only needed inside the vjp (mlx keeps it via the graph)
|
|
603
|
-
const result = f16 ? O : O.astype(inDtype);
|
|
604
|
-
if (!f16) {
|
|
605
|
-
O.dispose();
|
|
606
|
-
q16.dispose();
|
|
607
|
-
k16.dispose();
|
|
608
|
-
v16.dispose();
|
|
609
|
-
}
|
|
610
|
-
return result;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// ---------------------------------------------------------------------------
|
|
614
|
-
// Training-attention routing (opt-in; default null = ops.sdpa).
|
|
615
|
-
//
|
|
616
|
-
// Parity oracle, made explicit:
|
|
617
|
-
// - DEFAULT (ops.sdpa) is the L1 path: mlx-lm's tuner differentiates the same
|
|
618
|
-
// mx.fast.scaled_dot_product_attention, so training through it is bit-faithful
|
|
619
|
-
// to mlx-lm. Exact dQ/dK/dV (finite-difference cross-checked), fast, but
|
|
620
|
-
// O(L²) backward memory (materializes the score matrix).
|
|
621
|
-
// - This flash kernel is the L2 path: a port of mlx-optiq's
|
|
622
|
-
// flash_attention_metal (O(L) backward memory). Its parity oracle is OPTIQ,
|
|
623
|
-
// not finite differences. Confirmed: optiq's flash dK == ops.sdpa to f16
|
|
624
|
-
// (scripts/oracle/flash-optiq-check.py, rel 0.0%), and mlx-bun's flash == ops.sdpa
|
|
625
|
-
// (tests/unit/flash-attention.test.ts) ⟹ mlx-bun flash == optiq flash (L2 parity).
|
|
626
|
-
//
|
|
627
|
-
// Two real port bugs were fixed to reach that parity (the original diverged
|
|
628
|
-
// ~100% from optiq on dK): a spurious dK transpose in flashBackward (corrupted
|
|
629
|
-
// dK for Tkv≠D), and a per-thread (divergent) threadgroup_barrier in the dQ
|
|
630
|
-
// causal tile-skip. flash is opt-in (MLX_BUN_TRAIN_ATTN=flash) for memory-bound
|
|
631
|
-
// long context; it is ~30× slower than ops.sdpa. flashSupported gates
|
|
632
|
-
// head_dim/seq; sliding-window (array-mask) layers fall back to manualSdpa.
|
|
633
|
-
// ---------------------------------------------------------------------------
|
|
634
|
-
|
|
635
|
-
let trainAttnMode: "flash" | "manual" | null = null;
|
|
636
|
-
export function setTrainingAttn(mode: "flash" | "manual" | null): void {
|
|
637
|
-
trainAttnMode = mode;
|
|
638
|
-
}
|
|
639
|
-
export function getTrainingAttn(): "flash" | "manual" | null {
|
|
640
|
-
return trainAttnMode;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/** Can the flash kernel handle this q? (head_dim supported, seq≥32, fp16/bf16.) */
|
|
644
|
-
export function flashSupported(q: MlxArray): boolean {
|
|
645
|
-
const T = q.shape[2]!;
|
|
646
|
-
const D = q.shape[3]!;
|
|
647
|
-
return SUPPORTED_HEAD_DIMS.has(D) && T >= 32 &&
|
|
648
|
-
(q.dtype === Dtype.float16 || q.dtype === Dtype.bfloat16);
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
/** Materialized differentiable attention (matmul → mask → softmax → matmul),
|
|
652
|
-
* GQA-aware. A correct-vjp fallback for shapes/masks the flash kernel doesn't
|
|
653
|
-
* take. (ops.sdpa's dK vjp is CORRECT — FD-verified, the training default;
|
|
654
|
-
* the old "broken dK" note here predated the flash-kernel root-cause: the
|
|
655
|
-
* bugs were flash's own dK transpose + dQ barrier, both fixed.) O(L²) —
|
|
656
|
-
* pair with gradient checkpointing. */
|
|
657
|
-
export function manualSdpa(q: MlxArray, k: MlxArray, v: MlxArray, scale: number, mask: Mask): MlxArray {
|
|
658
|
-
const [B, Hq, T, Dh] = q.shape as [number, number, number, number];
|
|
659
|
-
const Hkv = k.shape[1]!;
|
|
660
|
-
const Tk = k.shape[2]!;
|
|
661
|
-
const reps = Hq / Hkv;
|
|
662
|
-
|
|
663
|
-
const q5 = ops.reshape(q, [B, Hkv, reps, T, Dh]);
|
|
664
|
-
const k5 = ops.reshape(k, [B, Hkv, 1, Tk, Dh]);
|
|
665
|
-
const v5 = ops.reshape(v, [B, Hkv, 1, Tk, Dh]);
|
|
666
|
-
const kT = ops.transposeAxes(k5, [0, 1, 2, 4, 3]); // [B,Hkv,1,Dh,Tk]
|
|
667
|
-
let scores = ops.matmul(q5, kT); // [B,Hkv,reps,T,Tk]
|
|
668
|
-
k5.dispose();
|
|
669
|
-
kT.dispose();
|
|
670
|
-
if (scale !== 1.0) {
|
|
671
|
-
const s2 = ops.mulScalar(scores, scale);
|
|
672
|
-
scores.dispose();
|
|
673
|
-
scores = s2;
|
|
674
|
-
}
|
|
675
|
-
if (mask.mode === "causal" || mask.mode === "array") {
|
|
676
|
-
const mBool = mask.mode === "causal" ? createCausalMask(T, 0, null) : mask.arr!;
|
|
677
|
-
const ninf = ops.scalarLike(-3.0e38, scores);
|
|
678
|
-
const masked = ops.where(mBool, scores, ninf);
|
|
679
|
-
scores.dispose();
|
|
680
|
-
ninf.dispose();
|
|
681
|
-
if (mask.mode === "causal") mBool.dispose();
|
|
682
|
-
scores = masked;
|
|
683
|
-
}
|
|
684
|
-
const probs = ops.softmaxAxis(scores, -1, true);
|
|
685
|
-
scores.dispose();
|
|
686
|
-
const out5 = ops.matmul(probs, v5); // [B,Hkv,reps,T,Dh]
|
|
687
|
-
probs.dispose();
|
|
688
|
-
v5.dispose();
|
|
689
|
-
q5.dispose();
|
|
690
|
-
const out = ops.reshape(out5, [B, Hq, T, Dh]);
|
|
691
|
-
out5.dispose();
|
|
692
|
-
return out;
|
|
693
|
-
}
|
|
694
|
-
|