mlx-bun 0.0.13 → 0.3.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 +71 -578
- package/bin/mlx-bun.mjs +1 -1
- package/docs/README.md +91 -0
- package/docs/{design → archive}/hlg-sampling.md +3 -3
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
- package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
- package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
- package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
- package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
- package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
- package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +421 -0
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +395 -149
- package/docs/reference/distribution.md +321 -181
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +580 -142
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +137 -6
- package/docs/reference/server-api.md +938 -422
- package/docs/reference/server-config.md +652 -320
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +10 -5
- package/src/admission-plan.ts +18 -0
- package/src/anthropic.ts +92 -3
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +189 -61
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +263 -23
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +10 -79
- package/src/eval/tasks/bfcl.ts +2 -1
- package/src/eval/tasks/gsm8k.ts +2 -1
- package/src/eval/tasks/hashhop.ts +2 -1
- package/src/eval/tasks/humaneval.ts +5 -4
- package/src/eval/tasks/ifeval.ts +2 -1
- package/src/eval/tasks/mmlu.ts +2 -1
- package/src/expert-io.ts +3 -1
- package/src/expert-offload.ts +3 -1
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +24 -43
- package/src/generate.ts +740 -337
- package/src/grammar.ts +14 -8
- package/src/harness-pi.ts +15 -34
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +27 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +15 -14
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-scheme.ts +199 -0
- package/src/kv-store.ts +459 -234
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
- package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +20 -4
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +32 -170
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +3 -4
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +66 -22
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +64 -19
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/batched-mask.ts +9 -3
- package/src/model/batched-quant.ts +2 -2
- package/src/model/batched-rotating-quant.ts +45 -99
- package/src/model/batched-rotating-state.ts +73 -0
- package/src/model/batched-rotating.ts +57 -106
- package/src/model/batched-row-storage.ts +127 -0
- package/src/model/compiled-decode.ts +4 -3
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +87 -49
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +187 -17
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +52 -148
- package/src/model/generated/gemma4-26b.ts +34 -94
- package/src/model/generated/gemma4-e4b.ts +28 -76
- package/src/model/glm52-cache.ts +19 -9
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +28 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +7 -8
- package/src/model/profile.ts +443 -0
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3-delta.ts +98 -2
- package/src/model/qwen3-mrope.ts +252 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +336 -60
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/universal/dense.ts +1 -1
- package/src/model/universal/modules.ts +8 -1
- package/src/native/frame_extract.swift +140 -0
- package/src/native-pack.ts +15 -7
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +14 -320
- package/src/prompt-cache.ts +97 -54
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/atomic-output.ts +38 -0
- package/src/quantize/calibration.ts +2 -1
- package/src/quantize/config-writer.ts +16 -3
- package/src/quantize/index.ts +28 -1
- package/src/quantize/job.ts +11 -0
- package/src/quantize/quantizer.ts +265 -100
- package/src/quantize/rotate.ts +603 -0
- package/src/quantize/safetensors-writer.ts +79 -1
- package/src/quantize/sensitivity.ts +41 -59
- package/src/quantize/trellis.ts +586 -0
- package/src/quantize/weight-transform.ts +292 -0
- package/src/responses.ts +130 -3
- package/src/runtime-config.ts +81 -0
- package/src/sampler.ts +276 -4
- package/src/serve/admin-routes.ts +184 -0
- package/src/serve/aux-routes.ts +132 -0
- package/src/serve/batch-scheduler.ts +8 -1558
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +354 -0
- package/src/serve/completion-sink.ts +157 -0
- package/src/serve/discovery-routes.ts +204 -0
- package/src/serve/generation-gateway.ts +211 -243
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/kv-budget.ts +14 -0
- package/src/serve/lab-routes.ts +341 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +155 -0
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +512 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/prompt-response-trace.ts +147 -0
- package/src/serve/request-plan.ts +162 -0
- package/src/serve/request-prep.ts +346 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +101 -0
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +523 -3551
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +9 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +5 -4
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +9 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +528 -0
- package/src/spec/serve-loop.ts +179 -213
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +95 -24
- package/src/ssd-durability.ts +207 -0
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +14 -13
- package/src/train/forward.ts +38 -1
- package/src/train/loss.ts +3 -2
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +9 -6
- package/src/train/trainer.ts +9 -8
- package/src/vision/preprocess.ts +1 -1
- package/src/vision/prompt.ts +48 -2
- package/src/vision/qwen3vl-preprocess.ts +409 -0
- package/src/vision/qwen3vl-prompt.ts +196 -0
- package/src/vision/qwen3vl-tower.ts +555 -0
- package/src/vision/video-frames.ts +148 -0
- package/src/web/app.html +1 -1
- package/src/web/app.js +15 -6
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +16 -9
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +134 -33
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -268
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -189
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -288
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/investigations/hlg-ab.html +0 -34
- package/docs/investigations/hlg-explorer.html +0 -238
- package/docs/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/investigations/hlg-figs/cross.svg +0 -1
- package/docs/investigations/hlg-figs/edges.svg +0 -1
- package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/investigations/hlg-report.html +0 -262
- package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -100
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -13
- /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
- /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
- /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
- /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
- /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
- /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
- /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
- /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
- /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
- /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
- /package/docs/{planning → archive/planning}/journal.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
- /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
- /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -1,323 +1,462 @@
|
|
|
1
1
|
# Training / fine-tuning reference
|
|
2
2
|
|
|
3
|
-
How to fine-tune a served model with LoRA adapters: the
|
|
4
|
-
|
|
3
|
+
How to fine-tune a served model with LoRA adapters: the commands, the data
|
|
4
|
+
formats, every config field, the long-context memory stack, and the
|
|
5
|
+
methodology behind the knobs.
|
|
5
6
|
|
|
6
7
|
mlx-bun trains **LoRA adapters** (the base quantized weights stay frozen),
|
|
7
|
-
supports **SFT**, **DPO**, and **ORPO**, and runs on a single Apple-Silicon
|
|
8
|
-
output is a PEFT-compatible adapter you
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
for the long-context memory mechanism.
|
|
8
|
+
supports **SFT**, **DPO**, and **ORPO**, and runs on a single Apple-Silicon
|
|
9
|
+
GPU. The output is a PEFT-compatible adapter directory you mount into the
|
|
10
|
+
server (`mlx-bun serve <model> --adapter <dir>`) or fold into the base
|
|
11
|
+
weights (`mlx-bun fuse`).
|
|
12
12
|
|
|
13
|
-
> Source of truth:
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
>
|
|
13
|
+
> Source of truth: `mlx-bun train` in [`src/cli.ts`](../../src/cli.ts)
|
|
14
|
+
> (flags + defaults), the submit schema `FinetuneSubmit` in
|
|
15
|
+
> [`src/train/job.ts`](../../src/train/job.ts), and `DEFAULT_TRAIN_CONFIG` in
|
|
16
|
+
> [`src/train/trainer.ts`](../../src/train/trainer.ts). If this doc and the
|
|
17
|
+
> code disagree, the code wins.
|
|
17
18
|
|
|
18
19
|
## Entry points
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
(`finetuneRunner` in `src/train/job.ts`):
|
|
21
|
+
Every path drives the **same** runner (`finetuneRunner` in `src/train/job.ts`):
|
|
22
22
|
|
|
23
23
|
| Path | How | Use when |
|
|
24
24
|
|---|---|---|
|
|
25
|
-
| **CLI** | `mlx-bun train <model> --data <dir> [options]` — foreground,
|
|
26
|
-
| **
|
|
27
|
-
| **
|
|
28
|
-
| **
|
|
29
|
-
| **
|
|
30
|
-
| **
|
|
25
|
+
| **CLI** | `mlx-bun train <model> --data <dir> [options]` — foreground, streams loss to the terminal, ORPO with the full memory stack by default. `mlx-bun help train` lists every flag. | **The default.** |
|
|
26
|
+
| **Live dashboard** | `mlx-bun train-watch <adapter-dir>` — tails `<adapter-dir>/metrics.jsonl` from another terminal. | Watching a detached run |
|
|
27
|
+
| **Fuse** | `mlx-bun fuse <model> --adapter <dir> [--save-path <out>]` — fold the adapter into the base weights → standalone snapshot. | Shipping a merged model |
|
|
28
|
+
| **Web app** | The Fine-tune tab (`#/finetune`, behind the app's Developer toggle): model → dataset → hyperparameters → train, live train/val loss, merge/export. | Interactive |
|
|
29
|
+
| **HTTP API** | `POST /api/finetune/{inspect-dataset,submit,merge,export}` — same runner as a subprocess job with SSE events; documented in [server-api.md](server-api.md). | Scripted / remote |
|
|
30
|
+
| **ORPO launcher** | [`scripts/train-orpo.ts`](../../scripts/train-orpo.ts) — the CLI's ORPO stack driven by env vars (`MODEL=`, `DATA=`, `SEQ=`, `SEG=`, `RESUME=`, …). | Env-var scripting |
|
|
31
|
+
| **Library** | `import { finetuneRunner } from "./src/train/job"` (snake_case submit record + event emitter) or `trainLora` / `DEFAULT_TRAIN_CONFIG` from `./src/train` (camelCase `TrainConfig`). | Embedding training in your own TS |
|
|
31
32
|
|
|
32
|
-
The CLI and the launcher run
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
The CLI and the launcher run in-process in the foreground; the web app and
|
|
34
|
+
HTTP API run the job as a subprocess (crash isolation, one GPU lease across
|
|
35
|
+
concurrent server requests).
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
## Quickstart — ORPO on preference data
|
|
38
|
+
|
|
39
|
+
ORPO is the CLI default: reference-free, two forwards per step, and the
|
|
40
|
+
whole long-context stack (flash-CCE head + prefix-sharing + segmented
|
|
41
|
+
backward) is on unless you turn pieces off.
|
|
42
|
+
|
|
43
|
+
**1. Data.** `--data <dir>` must contain `train.jsonl` (+ optional
|
|
44
|
+
`valid.jsonl`); rows are `{"prompt": "...", "chosen": "...", "rejected": "..."}`
|
|
45
|
+
(`prompt` may also be a chat-messages array — it is rendered through the
|
|
46
|
+
model's chat template). To build one from UltraFeedback:
|
|
37
47
|
|
|
38
48
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"data_dir": "/path/to/dataset", // dir with train.jsonl (+ optional valid.jsonl)
|
|
42
|
-
"adapter_path": "/path/to/output-adapter",
|
|
43
|
-
"method": "sft",
|
|
44
|
-
"rank": 16, "iters": 300, "learning_rate": 2e-4, "max_seq_length": 2048
|
|
45
|
-
}'
|
|
46
|
-
# → { "jobId": "..." } then stream events from the jobs SSE endpoint
|
|
49
|
+
# <input.jsonl> = HuggingFaceH4/ultrafeedback_binarized exported to JSONL (you fetch it)
|
|
50
|
+
bun scripts/curate-ultrafeedback.ts <input.jsonl> ./prefs [maxTokens=2048] [valFrac=0.02]
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
**2. Plan without training.** `--dry-run` inspects the dataset (counts,
|
|
54
|
+
detected format) and prints the resolved plan box: model, loop knobs, head,
|
|
55
|
+
stack, adapter path.
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
```bash
|
|
58
|
+
mlx-bun train e4b --data ./prefs --dry-run
|
|
59
|
+
```
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
**3. Train — detached from your own shell.** The command blocks and streams
|
|
62
|
+
per-step loss, s/step, and peak memory until done. Save a mountable
|
|
63
|
+
checkpoint every N steps so a crash costs you nothing, and put the adapter
|
|
64
|
+
somewhere the server discovers it (see [Outputs](#outputs)).
|
|
57
65
|
|
|
58
66
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
bun scripts/chunk-finetune.ts
|
|
67
|
+
nohup mlx-bun train e4b --data ./prefs --iters 1000 --save-every 200 \
|
|
68
|
+
--adapter ~/.cache/mlx-bun/adapters/my-e4b > train.log 2>&1 &
|
|
62
69
|
```
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
**4. Watch it from another tab.**
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mlx-bun train-watch ~/.cache/mlx-bun/adapters/my-e4b
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**5. Resume** warm-starts the LoRA weights from a checkpoint or adapter dir
|
|
78
|
+
(optimizer state + LR schedule restart; rank/targets must match).
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
mlx-bun train e4b --data ./prefs --iters 500 \
|
|
82
|
+
--resume ~/.cache/mlx-bun/adapters/my-e4b/checkpoints/step-00200-val<loss> \
|
|
83
|
+
--adapter ~/.cache/mlx-bun/adapters/my-e4b-2
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**6. Serve or fuse.**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
mlx-bun serve e4b --adapter ~/.cache/mlx-bun/adapters/my-e4b
|
|
90
|
+
mlx-bun fuse e4b --adapter ~/.cache/mlx-bun/adapters/my-e4b --save-path ./my-e4b-merged
|
|
91
|
+
mlx-bun serve ./my-e4b-merged
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`<model>` is a registry query or a snapshot path (`e4b`, `MiniCPM5`, …);
|
|
95
|
+
omit it to auto-pick the default model. Per-model defaults: Gemma/e4b gets
|
|
96
|
+
`--seq 8192`, everything else `4096`. ORPO defaults `--rank 16 --scale 2.0
|
|
97
|
+
--seg 2`; SFT/DPO default `--rank 8 --scale 1.0` and **no** segmented
|
|
98
|
+
backward unless you pass `--seg <n>`.
|
|
99
|
+
|
|
100
|
+
Measured memory/throughput for these runs live in
|
|
101
|
+
[benchmarks.md](benchmarks.md) — this doc records only the ceilings that
|
|
102
|
+
decide whether a run fits (see [Sequence-length ceilings](#sequence-length-ceilings-measured)).
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
### `mlx-bun train` flags
|
|
105
|
+
|
|
106
|
+
| Flag | Default | Meaning |
|
|
68
107
|
|---|---|---|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
| `--data <dir>` | required | dataset dir with `train.jsonl` (+ `valid.jsonl`) |
|
|
109
|
+
| `--method <m>` | `orpo` | `sft` · `dpo` · `orpo` |
|
|
110
|
+
| `--adapter <dir>` | `~/.cache/mlx-bun/mlx-bun-finetunes/<method>-<model>` | output adapter dir (`<model>` = `e4b` for Gemma, else `cpm5`) |
|
|
111
|
+
| `--iters <n>` | 100 | training iterations |
|
|
112
|
+
| `--lr <f>` | orpo 1e-5 · dpo 5e-5 · sft 2e-4 | learning rate (ORPO/DPO: cosine schedule; ORPO warmup = min(10, iters/10)) |
|
|
113
|
+
| `--rank <n>` | orpo 16 · else 8 | LoRA rank (`by_bits`-scaled per layer) |
|
|
114
|
+
| `--scale <f>` | orpo 2.0 · else 1.0 | LoRA scale |
|
|
115
|
+
| `--seq <n>` | gemma 8192 · else 4096 | max sequence length |
|
|
116
|
+
| `--batch <n>` | 1 | batch size |
|
|
117
|
+
| `--grad-accum <n>` | 1 | gradient accumulation steps (effective batch = batch × grad-accum at batch-1 memory) |
|
|
118
|
+
| `--grad-clip <f>` | 1.0 | gradient-norm clip (0 = off) |
|
|
119
|
+
| `--seed <n>` | 0 | data-shuffle / init seed |
|
|
120
|
+
| `--val-size <n>` | 256 | max validation examples per eval |
|
|
121
|
+
| `--lambda <f>` | 0.1 | ORPO odds-ratio weight |
|
|
122
|
+
| `--sft-scope <s>` | `full` | ORPO chosen-NLL scope: `full` (paper/TRL-faithful prompt+response) · `response` (pre-2026-07 runs, bit-exact) |
|
|
123
|
+
| `--seg <n>` | orpo 2 · else 0 | layers per segment (segmented backward) |
|
|
124
|
+
| `--no-segment` | — | disable the segmented backward (all activations resident) |
|
|
125
|
+
| `--save-every <n>` | off | crash-safe mountable checkpoint every n steps (turns on `save_checkpoints`; eval runs at the same cadence) |
|
|
126
|
+
| `--resume <dir>` | — | warm-start LoRA weights from a checkpoint/adapter dir |
|
|
127
|
+
| `--no-flash` | — | ORPO: use the MLX fused linear-CE head instead of the flash-CCE Metal head |
|
|
128
|
+
| `--no-prefix` | — | ORPO: disable prefix-sharing (two-forward branches) |
|
|
129
|
+
| `--dry-run` | — | inspect the dataset + print the plan, don't train |
|
|
130
|
+
|
|
131
|
+
The CLI always sets `rank_scaling: by_bits`, `num_layers: -1`,
|
|
132
|
+
`steps_per_report: 1`, and for ORPO `orpo_chunk_size: 512` plus
|
|
133
|
+
`orpo_flash_ce` / `orpo_fused_ce` / `orpo_prefix_shared` from the flags
|
|
134
|
+
above. Anything not exposed as a flag (`lora_dropout`, `rs_lora`,
|
|
135
|
+
`lora_plus_ratio`, `grad_checkpoint`, `target_modules`, …) is reachable
|
|
136
|
+
through the submit record — see [Configuration reference](#configuration-reference).
|
|
137
|
+
|
|
138
|
+
### The launcher (env-var alternative)
|
|
139
|
+
|
|
140
|
+
[`scripts/train-orpo.ts`](../../scripts/train-orpo.ts) runs the identical
|
|
141
|
+
ORPO stack from env vars. `MODEL` is a snapshot **path** (a dir with
|
|
142
|
+
`config.json`), not a query.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
MODEL=<snapshot-dir> DATA=./prefs ITERS=200 bun scripts/train-orpo.ts
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
| Env | Default | Meaning |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `SEQ` | e4b 8192 · cpm 4096 | max sequence length |
|
|
151
|
+
| `SEG` | 2 | layers per segment; `SEGOFF=1` disables the segmented backward |
|
|
152
|
+
| `ITERS` / `LR` | 100 / 1e-5 | iterations / learning rate (cosine + short warmup) |
|
|
153
|
+
| `RANK` / `SCALE` | 16 / 2.0 | LoRA rank (by_bits scaled) / scale |
|
|
154
|
+
| `LAMBDA` | 0.1 | ORPO odds-ratio weight |
|
|
155
|
+
| `SFT_SCOPE` | `full` | `full` · `response` (as `--sft-scope`) |
|
|
156
|
+
| `FLASH=0` | (on) | MLX fused head instead of the flash Metal head |
|
|
157
|
+
| `PREFIX=0` | (on) | disable prefix-sharing |
|
|
158
|
+
| `SAVE_EVERY` | 0 (off) | mountable checkpoint every N steps |
|
|
159
|
+
| `RESUME` | — | adapter/checkpoint dir to warm-start from |
|
|
160
|
+
| `ADAPTER` | `~/.cache/mlx-bun/mlx-bun-finetunes/orpo-<e4b\|cpm5>` | output dir |
|
|
85
161
|
|
|
86
162
|
## Data formats
|
|
87
163
|
|
|
88
|
-
Each row of `train.jsonl` (and optional `valid.jsonl`) is auto-detected by
|
|
89
|
-
keys ([`src/train/dataset.ts`](../../src/train/dataset.ts)):
|
|
164
|
+
Each row of `train.jsonl` (and optional `valid.jsonl`) is auto-detected by
|
|
165
|
+
its keys ([`src/train/dataset.ts`](../../src/train/dataset.ts)):
|
|
90
166
|
|
|
91
167
|
| Format | Shape | Loss boundary |
|
|
92
168
|
|---|---|---|
|
|
93
|
-
| `messages` | `{"messages": [{"role","content"}, …]}` | response-only — loss on the final turn
|
|
169
|
+
| `messages` | `{"messages": [{"role","content"}, …]}` | response-only — loss on the final turn; prompt = chat-template render of all prior turns |
|
|
94
170
|
| `prompt-completion` | `{"prompt": "...", "completion": "..."}` | loss on the completion only |
|
|
95
171
|
| `text` | `{"text": "..."}` | full-sequence (no prompt mask) |
|
|
96
|
-
| `
|
|
172
|
+
| `preference` *(dpo / orpo)* | `{"prompt", "chosen", "rejected"}` | preference loss on chosen vs rejected; `prompt` may be a string or a messages array |
|
|
97
173
|
|
|
98
|
-
|
|
99
|
-
`
|
|
174
|
+
`mlx-bun train --dry-run` (or `POST /api/finetune/inspect-dataset`) reports
|
|
175
|
+
`n_train`, `n_valid`, and the detected format before any weights load.
|
|
100
176
|
|
|
101
177
|
## SFT vs DPO vs ORPO
|
|
102
178
|
|
|
103
|
-
- **SFT** (
|
|
104
|
-
cross-entropy. Default LR `2e-4`.
|
|
105
|
-
|
|
106
|
-
|
|
179
|
+
- **SFT** (`--method sft`) — supervised fine-tune; response-only
|
|
180
|
+
cross-entropy. Default LR `2e-4`. Instruction-following, formatting, task
|
|
181
|
+
adaptation. Segmented backward is available (`--seg <n>`) but off by
|
|
182
|
+
default.
|
|
183
|
+
- **DPO** (`--method dpo`) — Direct Preference Optimization on
|
|
107
184
|
chosen/rejected pairs; loss `-log σ(β·((π_c − ref_c) − (π_r − ref_r)))`
|
|
108
|
-
with reference log-probs computed at LoRA scale 0
|
|
109
|
-
with `dpo_beta`, `dpo_warmup_iters`,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
`L_OR = -log σ(log_odds)
|
|
114
|
-
`log_odds = (ℓ_w − ℓ_r) − (log1mexp(ℓ_w) − log1mexp(ℓ_r))`, where `ℓ` is
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
-
|
|
133
|
-
**
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
(default 1024) take the exact MLX fused
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
(
|
|
185
|
+
with reference log-probs computed at LoRA scale 0 (4 forwards/step).
|
|
186
|
+
Default LR `5e-5`. Tune with `dpo_beta`, `dpo_warmup_iters`,
|
|
187
|
+
`dpo_lr_schedule`. No segmented backward on this path.
|
|
188
|
+
- **ORPO** (`--method orpo`, the default) — Odds Ratio Preference
|
|
189
|
+
Optimization (Hong et al. 2024): a **reference-free** objective
|
|
190
|
+
`L = L_NLL(chosen) + λ·L_OR`, `L_OR = -log σ(log_odds)`,
|
|
191
|
+
`log_odds = (ℓ_w − ℓ_r) − (log1mexp(ℓ_w) − log1mexp(ℓ_r))`, where `ℓ` is
|
|
192
|
+
the length-normalized (mean over response tokens) log-prob. `--sft-scope
|
|
193
|
+
full` (default; paper/TRL-faithful) computes `L_NLL` as the token-mean CE
|
|
194
|
+
over the **full prompt+response** of the chosen sequence from the same
|
|
195
|
+
forward; `response` uses `L_NLL = −ℓ_w` (pre-2026-07 behavior, kept for
|
|
196
|
+
reproducing old runs). The odds-ratio terms are response-only in both
|
|
197
|
+
modes. Same data as DPO, no reference model (2 forwards/step). Default LR
|
|
198
|
+
`1e-5` — the loss carries a full NLL term a high LR destabilizes. Design:
|
|
199
|
+
[orpo-training](../design/orpo-training.md).
|
|
200
|
+
|
|
201
|
+
## The long-context stack (ORPO defaults)
|
|
202
|
+
|
|
203
|
+
Each piece is independently toggled, composes with the others (all B=1),
|
|
204
|
+
and falls back with a logged message when a precondition isn't met.
|
|
205
|
+
|
|
206
|
+
- **flash-CCE head** (`--no-flash` to disable; `orpo_flash_ce`) — the
|
|
207
|
+
`[M,vocab]`-free cross-entropy head in
|
|
208
|
+
[`src/train/flash-cce.ts`](../../src/train/flash-cce.ts): Apple's Cut
|
|
209
|
+
Cross-Entropy + Liger's fused linear-CE transpiled Triton → Metal, over
|
|
210
|
+
the **quantized** head (in-kernel dequant, MLX steel GEMM tiles, forward
|
|
211
|
+
and backward). Neither the logits nor a dequantized head ever touch HBM,
|
|
212
|
+
so head memory is flat in vocab and sequence length. Batches with
|
|
213
|
+
`M < MLX_BUN_FLASH_MIN_M` (default 1024) auto-take the exact MLX fused
|
|
214
|
+
head, which is faster at short M; `=0` always honors flash. Falls back to
|
|
215
|
+
the fused head when the tiling isn't clean. Two backward skips default ON
|
|
216
|
+
at `1e-5` (`MLX_BUN_CCE_BWD_FILTER_EPS`, the coefficient filter;
|
|
217
|
+
`MLX_BUN_CCE_BWD_BLOCK_EPS`, the lossless cold-block skip); set either to
|
|
218
|
+
`0` for exact gradients.
|
|
219
|
+
- **segmented backward** (`--seg <n>` / `--no-segment`; `segment_size`) —
|
|
220
|
+
[`src/train/segmented.ts`](../../src/train/segmented.ts). The forward
|
|
221
|
+
materializes and **detaches** the residual stream every n layers; the
|
|
222
|
+
head is differentiated against the last boundary; then each segment is
|
|
223
|
+
back-propagated in reverse via `mlx_vjp` with the incoming cotangent, so
|
|
224
|
+
only one segment's activations are live. Bit-identical to the plain
|
|
225
|
+
backward on MiniCPM5; bf16-class on e4b. Wired for MiniCPM5 and Gemma4
|
|
226
|
+
(SFT and ORPO); mutually exclusive with `grad_checkpoint`. Design + proofs:
|
|
227
|
+
[segmented-backward-training](../design/orpo-training.md).
|
|
228
|
+
- **prefix-sharing** (`--no-prefix`; `orpo_prefix_shared`) —
|
|
229
|
+
[`src/train/prefix-shared.ts`](../../src/train/prefix-shared.ts). One
|
|
230
|
+
forward over `[prompt; chosen; rejected]` with a block-sparse mask and
|
|
231
|
+
block-wise RoPE (each response resets to position P), so the shared
|
|
232
|
+
prompt is encoded once: layer-token cost `2(P+R) → P+2R`. Bit-exact with
|
|
233
|
+
the two-forward path; a big win when the prompt dominates, ~0 when the
|
|
234
|
+
response does. Rows whose chosen/rejected prompts aren't byte-identical
|
|
235
|
+
fall back to two-forward for that row (logged once). MiniCPM5 + Gemma4;
|
|
236
|
+
other models error out rather than silently degrade.
|
|
237
|
+
- **gradient checkpointing** (`grad_checkpoint`, API/library only) —
|
|
238
|
+
per-layer recompute; bit-identical. Cheaper than nothing, but it does not
|
|
239
|
+
stream the backward: at long context every layer's recompute is held at
|
|
240
|
+
once, which is what segmented backward fixes. `mlp_split` (Gemma4)
|
|
241
|
+
refines it to attention/MLP halves.
|
|
242
|
+
- **warm-start** (`--resume <dir>`; `warm_start_adapter`) — load LoRA
|
|
243
|
+
weights from an adapter/checkpoint dir; optimizer + schedule restart.
|
|
155
244
|
|
|
156
245
|
## Configuration reference
|
|
157
246
|
|
|
158
|
-
|
|
159
|
-
|
|
247
|
+
The snake_case submit record (`FinetuneSubmit`) — what the CLI builds, what
|
|
248
|
+
the web app and `POST /api/finetune/submit` accept, and what
|
|
249
|
+
`finetuneRunner` takes. `model_dir`, `data_dir`, `adapter_path` are
|
|
250
|
+
required; defaults are `DEFAULT_TRAIN_CONFIG` (the CLI overrides several —
|
|
251
|
+
see the flags table).
|
|
160
252
|
|
|
161
|
-
| Field
|
|
253
|
+
| Field | Type | Default | Effect |
|
|
162
254
|
|---|---|---|---|
|
|
163
|
-
| `method` | `sft` \| `dpo` \| `orpo` | `sft` |
|
|
255
|
+
| `method` | `sft` \| `dpo` \| `orpo` | `sft` | training objective |
|
|
164
256
|
| `rank` | int ≥2 | `8` | LoRA rank per adapted linear |
|
|
165
257
|
| `scale` | float >0 | `1.0` | LoRA α (effective update = α·BA) |
|
|
166
|
-
| `rank_scaling` | `constant` \| `by_bits` \| `by_kl` | `by_bits` |
|
|
167
|
-
| `target_modules` | string[] | `q,k,v,o,gate,up,down _proj` |
|
|
258
|
+
| `rank_scaling` | `constant` \| `by_bits` \| `by_kl` | `by_bits` | per-layer rank policy (see Methodology) |
|
|
259
|
+
| `target_modules` | string[] | `q,k,v,o,gate,up,down _proj` | which linears get adapters |
|
|
168
260
|
| `num_layers` | int | `-1` | `-1` = all layers; `N` = last N only |
|
|
169
|
-
| `iters` | int >0 | `100` |
|
|
170
|
-
| `learning_rate` | float >0 | `2e-4` (
|
|
171
|
-
| `max_seq_length` | int >0 | `512` |
|
|
172
|
-
| `batch_size` | int ≥1 | `1` |
|
|
173
|
-
| `grad_accumulation_steps` | int ≥1 | `1` |
|
|
261
|
+
| `iters` | int >0 | `100` | total training steps |
|
|
262
|
+
| `learning_rate` | float >0 | `2e-4` | AdamW LR (CLI: orpo 1e-5 / dpo 5e-5) |
|
|
263
|
+
| `max_seq_length` | int >0 | `512` | truncate/pad sequences (CLI: 8192 / 4096) |
|
|
264
|
+
| `batch_size` | int ≥1 | `1` | rows per step (B=1 is the no-padding path; B>1 length-sorts + pads to 32) |
|
|
265
|
+
| `grad_accumulation_steps` | int ≥1 | `1` | accumulate grads over N micro-steps |
|
|
174
266
|
| `seed` | int | `0` | RNG for shuffling + LoRA init |
|
|
175
|
-
| `steps_per_report` | int >0 | `10` |
|
|
176
|
-
| `steps_per_eval` | int >0 | `50` |
|
|
267
|
+
| `steps_per_report` | int >0 | `10` | train-loss metric every N steps (CLI: 1) |
|
|
268
|
+
| `steps_per_eval` | int >0 | `50` | eval on `valid.jsonl` every N steps (CLI: `--save-every`, else never) |
|
|
177
269
|
| `weight_decay` | float ≥0 | `0.01` | AdamW weight decay (β = `[0.9, 0.999]`, fixed) |
|
|
178
|
-
| `lora_dropout` | float [0,1) | `0.0` | LoRA-input dropout (PEFT-style)
|
|
179
|
-
| `rs_lora` | bool | `false` | rsLoRA — scale
|
|
180
|
-
| `lora_plus_ratio` | float ≥1 | `1.0` | LoRA+ — LR multiplier for the B leaves (A stays at base LR)
|
|
181
|
-
| `grad_checkpoint` | bool | `false` |
|
|
182
|
-
| `mlp_split` | bool | `false` |
|
|
183
|
-
| `segment_size` | int | `0`
|
|
184
|
-
| `save_checkpoints` | bool | `false` |
|
|
185
|
-
| `grad_clip_norm` | float ≥0 | `1.0` |
|
|
186
|
-
| `val_max_examples` | int >0 | `256` |
|
|
187
|
-
| `warm_start_adapter` | string | `""`
|
|
188
|
-
| `dpo_beta` | float >0 | `0.1` | DPO strength
|
|
189
|
-
| `dpo_warmup_iters` | int ≥0 | `0` | DPO LR warmup
|
|
190
|
-
| `dpo_lr_schedule` | `constant` \| `cosine` | `cosine` | DPO LR schedule
|
|
191
|
-
| `orpo_lambda` | float >0 | `0.1` | ORPO λ — weights
|
|
192
|
-
| `orpo_warmup_iters` | int ≥0 | `0` | ORPO LR warmup (
|
|
193
|
-
| `orpo_lr_schedule` | `constant` \| `cosine` | `cosine` | ORPO LR schedule
|
|
194
|
-
| `orpo_chunk_size` | int | `0`
|
|
195
|
-
| `orpo_fused_ce` | bool | `false` |
|
|
196
|
-
| `orpo_flash_ce` | bool | `false` |
|
|
197
|
-
| `orpo_prefix_shared` | bool | `false` |
|
|
198
|
-
| `sft_scope` | `full` \| `response` | `full` |
|
|
270
|
+
| `lora_dropout` | float [0,1) | `0.0` | LoRA-input dropout (PEFT-style); mask keyed by step+layer so segmented/checkpointed recompute reproduces it |
|
|
271
|
+
| `rs_lora` | bool | `false` | rsLoRA — scale by α/√rank so `rank_scaling` changes capacity, not step size; recorded in the adapter config and honored at inference |
|
|
272
|
+
| `lora_plus_ratio` | float ≥1 | `1.0` | LoRA+ — LR multiplier for the B leaves (A stays at base LR); 1 = off |
|
|
273
|
+
| `grad_checkpoint` | bool | `false` | recompute layer activations in backward (bit-identical) |
|
|
274
|
+
| `mlp_split` | bool | `false` | attention/MLP split inside the checkpoint (Gemma4; needs `grad_checkpoint`) |
|
|
275
|
+
| `segment_size` | int | `0` | `>0` = segmented backward, layers per segment (CLI: orpo 2) |
|
|
276
|
+
| `save_checkpoints` | bool | `false` | keep every eval-step checkpoint + write `metrics.json` (CLI: on with `--save-every`) |
|
|
277
|
+
| `grad_clip_norm` | float ≥0 | `1.0` | global-norm gradient clipping; `0` = off |
|
|
278
|
+
| `val_max_examples` | int >0 | `256` | fixed validation subset per eval |
|
|
279
|
+
| `warm_start_adapter` | string | `""` | adapter dir to warm-start from (`--resume`) |
|
|
280
|
+
| `dpo_beta` | float >0 | `0.1` | DPO strength |
|
|
281
|
+
| `dpo_warmup_iters` | int ≥0 | `0` | DPO LR warmup |
|
|
282
|
+
| `dpo_lr_schedule` | `constant` \| `cosine` | `cosine` | DPO LR schedule |
|
|
283
|
+
| `orpo_lambda` | float >0 | `0.1` | ORPO λ — weights only the odds-ratio term |
|
|
284
|
+
| `orpo_warmup_iters` | int ≥0 | `0` | ORPO LR warmup (CLI: min(10, iters/10)) |
|
|
285
|
+
| `orpo_lr_schedule` | `constant` \| `cosine` | `cosine` | ORPO LR schedule |
|
|
286
|
+
| `orpo_chunk_size` | int | `0` | token-chunk the response head to `[chunk,vocab]`; exact (CLI: 512) |
|
|
287
|
+
| `orpo_fused_ce` | bool | `false` | fused linear-CE head: one CustomVjp with the analytic softmax−onehot backward, no retained `[M,vocab]` (CLI: on when `--no-flash`) |
|
|
288
|
+
| `orpo_flash_ce` | bool | `false` | route the fused head through the flash-CCE Metal kernel; implies fused (CLI: on) |
|
|
289
|
+
| `orpo_prefix_shared` | bool | `false` | shared prompt-prefix single forward (CLI: on) |
|
|
290
|
+
| `sft_scope` | `full` \| `response` | `full` | scope of ORPO's chosen-NLL term (`--sft-scope`) |
|
|
199
291
|
|
|
200
292
|
### Environment variables (training)
|
|
201
293
|
|
|
202
|
-
| Env var |
|
|
203
|
-
|---|---|---|---|
|
|
204
|
-
| `MLX_BUN_TRAIN_ATTN` | **leave unset** | unset → `ops.sdpa` | Default `ops.sdpa` **is** mlx's fused flash-attention kernel — the correct, working path. `flash` selects a *different* hand-rolled O(L)-memory kernel: its two port bugs (dK buffer-transpose, dQ divergent causal barrier) are fixed and FD-validated (`tests/flash-attention.test.ts`, T≤256), but it is ~30× slower and the historical e4b ≥2K crash has **not been re-validated at that scale** since the fix — leave unset unless memory-bound and re-verified. |
|
|
205
|
-
| `MLX_BUN_MEM_LOG` | `1` to profile | off | Print per-step peak/active/cache memory |
|
|
206
|
-
|
|
207
|
-
> Training needs **no flag sanitization**: the old requirement to export
|
|
208
|
-
> `MLX_BUN_FUSED_GELU=0` / `MLX_BUN_PERF_KERNEL=0` (the no-vjp custom
|
|
209
|
-
> kernels) is gone — those kernels and their env vars were deleted
|
|
210
|
-
> 2026-07-05 ([unified-engine-frontier-plan.md](../design/unified-engine-frontier-plan.md)).
|
|
211
|
-
> Exporting them in an old recipe is harmless but does nothing.
|
|
212
|
-
|
|
213
|
-
## What we actually run (the e4b recipe)
|
|
214
|
-
|
|
215
|
-
Everything above is the full surface (*what you can do*). In practice the
|
|
216
|
-
fine-tune we run is [`scripts/ft-e4b-v2.sh`](../../scripts/ft-e4b-v2.sh):
|
|
217
|
-
e4b (gemma-4-e4b-it-OptiQ-4bit, pinned snapshot) on the lucien `chunk-v2-500`
|
|
218
|
-
curated set (450 train convs) through the segmented-backward trainer. It wraps
|
|
219
|
-
`chunk-finetune.ts` with a two-step workflow:
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
scripts/ft-e4b-v2.sh probe # 2-iter memory/stability check (~1 min) — RUN FIRST
|
|
223
|
-
scripts/ft-e4b-v2.sh train # the real run (~900 iters ≈ 2 epochs, batch_size 1)
|
|
224
|
-
ITERS=750 SEQ=4096 SEG=1 scripts/ft-e4b-v2.sh train # override any knob inline
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
What the recipe pins (and why it differs from the bare defaults):
|
|
228
|
-
|
|
229
|
-
| Knob | Recipe value | Why |
|
|
294
|
+
| Env var | Default | Effect |
|
|
230
295
|
|---|---|---|
|
|
231
|
-
|
|
|
232
|
-
|
|
|
233
|
-
| `
|
|
234
|
-
| `
|
|
235
|
-
| `
|
|
236
|
-
| `
|
|
237
|
-
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
296
|
+
| `MLX_BUN_TRAIN_ATTN` | unset → `ops.sdpa` | `ops.sdpa` **is** mlx's fused flash-attention kernel with an exact vjp — the working path. `flash` selects a hand-rolled O(L)-memory kernel: FD-validated at T≤256 (`tests/unit/flash-attention.test.ts`) but ~30× slower, and the trainer **refuses it for Gemma models** (e4b SIGTRAPed at seq ≥2048 and has not been re-validated at that scale). Leave unset. |
|
|
297
|
+
| `MLX_BUN_MEM_LOG` | off | `1` prints per-step peak/active/cache memory |
|
|
298
|
+
| `MLX_BUN_SEG_MEM_LOG` | off | `1` logs the within-step peak after each segmented phase (forward / head vjp / each segment) |
|
|
299
|
+
| `MLX_BUN_SEG_HEAD` | `checkpoint` | bounded head inside the segmented vjp: `checkpoint` (per-chunk recompute) or `fused` |
|
|
300
|
+
| `MLX_BUN_SEG_HEAD_CHUNK` | 512 | token-chunk for the segmented SFT head |
|
|
301
|
+
| `MLX_BUN_FLASH_MIN_M` | 1024 | rows shorter than this take the exact fused head instead of flash; `0` = always flash |
|
|
302
|
+
| `MLX_BUN_CCE_BWD_FILTER_EPS` / `MLX_BUN_CCE_BWD_BLOCK_EPS` | `1e-5` / `1e-5` | flash-CCE backward skips; `0` compiles each out (exact gradients) |
|
|
303
|
+
|
|
304
|
+
`MLX_BUN_CCE_*` beyond those two (`NOSTEEL`, `BWD_NOSTEEL`, `SCALAR`,
|
|
305
|
+
`LANE`, `BWD_SCALAR`, `SG_SKIPDQ`, `BWD_SKIP_P2*`) select kernel variants
|
|
306
|
+
for A/B work in `flash-cce.ts`; they are not user knobs. Training needs no
|
|
307
|
+
other env setup — the Gemma-specific flag sanitization older recipes
|
|
308
|
+
exported is gone (those kernels were deleted 2026-07-05; exporting the old
|
|
309
|
+
variables does nothing).
|
|
310
|
+
|
|
311
|
+
## Sequence-length ceilings (measured)
|
|
312
|
+
|
|
313
|
+
What decides whether a run fits. Full tables (peak GB and s/step per
|
|
314
|
+
seq/config) are in [benchmarks.md](benchmarks.md); the mechanism and the
|
|
315
|
+
measurement method are in
|
|
316
|
+
[segmented-backward-training](../design/orpo-training.md).
|
|
317
|
+
|
|
318
|
+
- **MiniCPM5-1B (24 layers), M1 Max 32 GB, 2026-06-16** — segmented
|
|
319
|
+
backward (`segment_size` 4) @2048: peak live **10.91 → 3.29 GB** vs the
|
|
320
|
+
plain backward; @4096 the plain backward spikes to 21–26 GB while
|
|
321
|
+
segmented stays at 6–8 GB. Trains at 8192 comfortably.
|
|
322
|
+
- **e4b (Gemma4, 42 layers), M1 Max 32 GB, 2026-06-16** — without
|
|
323
|
+
segmentation, `ops.sdpa` + `grad_checkpoint` peaks at **23.2 GB live @2048**
|
|
324
|
+
and crashes at 4096 (linear: ≈ 7.7 GB + 7.6 MB/token). With segmented
|
|
325
|
+
backward all 42 layers train at **8192 in 17.5 GB** (`segment_size` 2),
|
|
326
|
+
where `mlx_lm.lora --grad-checkpoint` OOMs on all-42 @8192 and needs its
|
|
327
|
+
default 16 trainable layers (25.7 GB) to fit.
|
|
328
|
+
- **e4b, M1 Max 32 GB, 2026-07-02** — `segment_size` is the whole knob:
|
|
329
|
+
mlx's sdpa backward materializes O(L²) scores for every layer (sliding
|
|
330
|
+
window is only a mask), so the worst segment is set by layer count.
|
|
331
|
+
`segment_size` 1 = **14.59 GB @8K**, +3% step time, loss identical —
|
|
332
|
+
fits a 24 GB M4 Pro.
|
|
333
|
+
- **e4b ORPO full stack (flash + prefix-share + seg 2), M1 Max 32 GB** —
|
|
334
|
+
fits at 8192 with headroom; prefix-sharing is what makes prompt-dominant
|
|
335
|
+
data cheap (memory and step time both drop when the prompt is encoded
|
|
336
|
+
once). Numbers are from short probe runs — they prove fit and finite
|
|
337
|
+
decreasing loss, not training quality.
|
|
338
|
+
|
|
339
|
+
Rules of thumb: e4b at multi-K context **requires** segmented backward
|
|
340
|
+
(`--seg`, on by default for ORPO; pass it explicitly for SFT); memory is
|
|
341
|
+
linear in `--seq`; on a 24 GB machine use `--seg 1` at 8K.
|
|
342
|
+
|
|
343
|
+
## Examples (task-specific recipes)
|
|
344
|
+
|
|
345
|
+
These are the scripts behind our own chunk-segmentation fine-tunes. They
|
|
346
|
+
carry task defaults (data paths, eval corpus) that point at a sibling
|
|
347
|
+
repo — override `DATA=` / `MODEL=` / `ADAPTER=` for your own data and treat
|
|
348
|
+
them as templates, not tools.
|
|
349
|
+
|
|
350
|
+
- [`scripts/examples/chunk-finetune.ts`](../../scripts/examples/chunk-finetune.ts)
|
|
351
|
+
— SFT via `finetuneRunner` directly, env-driven. `MODEL` defaults to a
|
|
352
|
+
MiniCPM5-1B-OptiQ-4bit snapshot; `SEQ` 8192, `ITERS` 2 (probe), `RANK`
|
|
353
|
+
16, `LR` 1e-5, `SCALE` 20, `SEG` 0, `EVAL_EVERY` auto, `CKPT=0` disables
|
|
354
|
+
keep-all checkpoints, `GRAD_CKPT=1` enables gradient checkpointing.
|
|
355
|
+
```bash
|
|
356
|
+
DATA=<dir> SEQ=8192 ITERS=2 bun scripts/examples/chunk-finetune.ts # memory/stability probe
|
|
357
|
+
DATA=<dir> SEQ=8192 ITERS=300 SEG=2 bun scripts/examples/chunk-finetune.ts # real run
|
|
358
|
+
```
|
|
359
|
+
- [`scripts/examples/ft-e4b-v2.sh`](../../scripts/examples/ft-e4b-v2.sh)
|
|
360
|
+
`probe|train` — wraps `chunk-finetune.ts` for e4b with `SEQ=8192 SEG=4
|
|
361
|
+
RANK=16 SCALE=20 LR=1e-5`, pinning the validated e4b OptiQ-4bit snapshot;
|
|
362
|
+
`probe` = 2 iters (run first), `train` = 900 iters (~2 epochs over 450
|
|
363
|
+
rows at batch 1).
|
|
364
|
+
```bash
|
|
365
|
+
DATA=<dir> scripts/examples/ft-e4b-v2.sh probe
|
|
366
|
+
DATA=<dir> ITERS=750 SEQ=4096 SEG=1 scripts/examples/ft-e4b-v2.sh train
|
|
367
|
+
```
|
|
368
|
+
- [`scripts/examples/chunk-eval.ts`](../../scripts/examples/chunk-eval.ts)
|
|
369
|
+
— in-process task eval (no server): loads a model, optionally mounts
|
|
370
|
+
`ADAPTER=<dir>`, generates over a frozen holdout, and scores with the
|
|
371
|
+
task's metric. Its holdout/scorer imports live in the sibling repo; copy
|
|
372
|
+
the shape for your own task eval. Pick checkpoints by the task eval, not
|
|
373
|
+
by val loss.
|
|
241
374
|
|
|
242
375
|
## Methodology
|
|
243
376
|
|
|
244
377
|
### LoRA
|
|
245
|
-
Adapters attach to the target linears; A is initialized uniform, B
|
|
246
|
-
so the adapted model equals the base
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
378
|
+
Adapters attach to the target linears; A is initialized uniform, B zeros,
|
|
379
|
+
so the adapted model equals the base at step 0. Only A/B are differentiated.
|
|
380
|
+
Default targets are the 7 attention+MLP projections per block
|
|
381
|
+
(`q/k/v/o_proj`, `gate/up/down_proj`). See
|
|
382
|
+
[`src/train/lora-params.ts`](../../src/train/lora-params.ts).
|
|
250
383
|
|
|
251
384
|
### Rank scaling (`rank_scaling`)
|
|
252
385
|
- `constant` — every target gets `rank`.
|
|
253
|
-
- `by_bits` *(default)* — `rank × (bits / 4)`, clamped ≥2
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
segment's activations live at a time. This is the path to multi-K context;
|
|
273
|
-
full mechanism, proofs, and measured peaks (e.g. MiniCPM5 10.91→3.29 GB
|
|
274
|
-
@2048) are in
|
|
275
|
-
[segmented-backward-training](../design/segmented-backward-training.md).
|
|
276
|
-
|
|
277
|
-
### Training attention kernel (`MLX_BUN_TRAIN_ATTN`)
|
|
278
|
-
- **default `ops.sdpa`** — mlx's fused SDPA; correct (0.00% vs autograd),
|
|
279
|
-
O(L²) backward memory. Use this.
|
|
280
|
-
- **`flash`** — opt-in O(L)-memory path. Its two port bugs (dK
|
|
281
|
-
buffer-transpose, dQ divergent causal barrier) were **fixed** and
|
|
282
|
-
FD-validated (`scripts/experiments/flash-fd-check.ts`; regression test
|
|
283
|
-
`tests/flash-attention.test.ts`, T≤256), but it remains ~30× slower than
|
|
284
|
-
`ops.sdpa`, and the historical e4b multi-K (≥2K) SIGTRAP has **not been
|
|
285
|
-
re-validated at that scale since the fix**
|
|
286
|
-
(`scripts/experiments/segmented-grad-test-e4b.ts` is the repro harness).
|
|
287
|
-
Prefer the default; treat `flash` as experimental on e4b long context.
|
|
288
|
-
Detail in segmented-backward-training §6.
|
|
386
|
+
- `by_bits` *(default)* — `rank × (bits / 4)`, clamped ≥2: wider adapters
|
|
387
|
+
on the more-sensitive (higher-bit) layers of a mixed-precision model. The
|
|
388
|
+
per-layer bits come from the loaded model's quant specs.
|
|
389
|
+
- `by_kl` — scales by per-layer KL importance from `optiq_metadata.json`,
|
|
390
|
+
clamped to [0.5×, 2×]; falls back to `by_bits` when none is recorded.
|
|
391
|
+
|
|
392
|
+
### Long-context memory
|
|
393
|
+
At long `max_seq_length` activation memory dominates, not the head. Two
|
|
394
|
+
levers, mutually exclusive: `grad_checkpoint` (per-layer recompute, does not
|
|
395
|
+
stream) and `segment_size` (segmented backward, streams one segment at a
|
|
396
|
+
time — the path to multi-K context). Detail, proofs, and the `mlx_vjp`
|
|
397
|
+
vs surrogate-`value_and_grad` leak lesson:
|
|
398
|
+
[segmented-backward-training](../design/orpo-training.md).
|
|
399
|
+
|
|
400
|
+
### Training attention
|
|
401
|
+
`ops.sdpa` (mlx's fused SDPA, exact vjp, O(L²) backward memory) is the
|
|
402
|
+
only supported path for Gemma and the default everywhere. The opt-in
|
|
403
|
+
`MLX_BUN_TRAIN_ATTN=flash` kernel is an O(L)-memory experiment — ~30×
|
|
404
|
+
slower and blocked for Gemma by the trainer (see the env table).
|
|
289
405
|
|
|
290
406
|
## Outputs
|
|
291
407
|
|
|
292
408
|
A finished run writes a PEFT-compatible adapter directory:
|
|
293
409
|
|
|
294
410
|
- `adapters.safetensors` — the `lora_a` / `lora_b` tensors
|
|
295
|
-
- `optiq_lora_config.json` — mlx-bun/optiq
|
|
411
|
+
- `optiq_lora_config.json` — mlx-bun/optiq metadata (per-layer ranks, scale, base model)
|
|
296
412
|
- `adapter_config.json` — PEFT-compatible config
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
`
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
413
|
+
- `metrics.jsonl` — append-only per-step log (what `train-watch` tails)
|
|
414
|
+
|
|
415
|
+
The save completes only after both config files are written — including
|
|
416
|
+
eval-step checkpoints — so a successful exit always leaves a mountable
|
|
417
|
+
directory. With `save_checkpoints` (`--save-every`), each eval step also
|
|
418
|
+
writes `checkpoints/step-<NNNNN>-val<loss>/` (each a full mountable adapter)
|
|
419
|
+
and `metrics.json` (config, wall seconds, peak GB, final/best train+val
|
|
420
|
+
loss, full val trajectory).
|
|
421
|
+
|
|
422
|
+
**Where to save.** The CLI default is
|
|
423
|
+
`~/.cache/mlx-bun/mlx-bun-finetunes/<method>-<model>`. The server's adapter
|
|
424
|
+
discovery (`GET /v1/adapters/available`, the web chat's adapter picker)
|
|
425
|
+
scans `~/.cache/mlx-bun-finetunes` and **`~/.cache/mlx-bun/adapters`** —
|
|
426
|
+
so pass `--adapter ~/.cache/mlx-bun/adapters/<name>` if you want the
|
|
427
|
+
adapter selectable without typing a path. `serve --adapter <dir>` and
|
|
428
|
+
`fuse --adapter <dir>` accept any directory.
|
|
429
|
+
|
|
430
|
+
Serving accepts both mlx-lm tensor layout (`[in, rank]` / `[rank, out]`)
|
|
431
|
+
and standard PEFT layout (`[rank, in]` / `[out, rank]`, including
|
|
432
|
+
`base_model.model.*` names); PEFT `use_rslora` metadata is honored as
|
|
433
|
+
`lora_alpha / sqrt(rank)`. Hot-swap and per-request selection:
|
|
434
|
+
[server-api.md](server-api.md) (Adapters) and
|
|
435
|
+
[adapters-end-to-end](../design/web-chat-redesign.md).
|
|
316
436
|
|
|
317
437
|
## Memory & performance tips
|
|
318
438
|
|
|
319
|
-
- Start at
|
|
320
|
-
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
- `
|
|
439
|
+
- Start at `--batch 1` (the no-padding path); raise only with headroom.
|
|
440
|
+
`--grad-accum` raises the effective batch at batch-1 memory.
|
|
441
|
+
- OOM → lower `--seq`, lower `--seg` (1 at 8K on 24 GB), or reduce
|
|
442
|
+
`--rank`.
|
|
443
|
+
- `MLX_BUN_MEM_LOG=1` for per-step peak; `MLX_BUN_SEG_MEM_LOG=1` to see
|
|
444
|
+
which phase the peak lives in.
|
|
445
|
+
- Short rows already take the exact fused head automatically
|
|
446
|
+
(`MLX_BUN_FLASH_MIN_M`); on response-dominant data `--no-prefix` costs
|
|
447
|
+
nothing and `--no-flash` is worth an A/B.
|
|
448
|
+
- Select checkpoints by the downstream task eval or val accuracy/loss —
|
|
449
|
+
not by preference margin, which keeps rising after the model has
|
|
450
|
+
started overfitting.
|
|
451
|
+
|
|
452
|
+
## Rules for agents working alongside a run
|
|
453
|
+
|
|
454
|
+
- **No GPU work while a training run is active.** The GPU is fully
|
|
455
|
+
occupied; a "quick" benchmark, parity test, or model load corrupts both
|
|
456
|
+
the probe's numbers and the run's throughput. Verify by reading source
|
|
457
|
+
and logs (`train-watch`, `train.log`, `metrics.jsonl`), not by executing.
|
|
458
|
+
- Long runs are launched by the user from their own shell (`nohup … &`),
|
|
459
|
+
never as a session-spawned background task.
|
|
460
|
+
- Docs for a training-surface change (flags, fields, defaults) land in the
|
|
461
|
+
same commit: this file, [cli.md](cli.md), and
|
|
462
|
+
[server-api.md](server-api.md) for the HTTP routes.
|