mlx-bun 0.5.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1449 -109
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +7 -5
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +10 -10
- package/src/{serve → server}/chat-stage.ts +14 -14
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +33 -41
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +25 -82
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +6 -8
- package/src/{serve → server}/request-prep.ts +47 -50
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -107
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
- package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -2054
- package/docs/design/decode-speed-program.md +0 -2404
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -821
- package/docs/design/kv-cache.md +0 -993
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -2129
- package/docs/design/turboquant.md +0 -2225
- package/docs/design/unified-engine-frontier-plan.md +0 -1987
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -593
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/public-readiness-handoff.md +0 -244
- package/docs/planning/public-readiness.md +0 -149
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3587
- package/docs/reference/cli.md +0 -646
- package/docs/reference/distribution.md +0 -380
- package/docs/reference/environment.md +0 -494
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -688
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -346
- package/docs/reference/server-api.md +0 -1945
- package/docs/reference/server-config.md +0 -973
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/audiotoolbox.ts +0 -112
- package/src/audio/conformer.ts +0 -655
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/mic-capture.ts +0 -98
- package/src/audio/silero-vad.ts +0 -379
- package/src/audio/transcode.ts +0 -67
- package/src/audio/whisper-decode.ts +0 -774
- package/src/audio/whisper-fast.ts +0 -732
- package/src/audio/whisper-format.ts +0 -73
- package/src/audio/whisper-mel.ts +0 -185
- package/src/audio/whisper-timing.ts +0 -274
- package/src/audio/whisper-tokenizer.ts +0 -239
- package/src/audio/whisper-transcribe.ts +0 -410
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -129
- package/src/backends/mlx/batch-group.ts +0 -1874
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -107
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/encoder-cache.ts +0 -25
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -58
- package/src/backends/mlx/fill-group.ts +0 -497
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -174
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -161
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/mixed-iteration.ts +0 -62
- package/src/backends/mlx/model-prompt.ts +0 -178
- package/src/backends/mlx/model-serving.ts +0 -80
- package/src/backends/mlx/paged-cache-codec.ts +0 -27
- package/src/backends/mlx/prefill-cohort.ts +0 -100
- package/src/backends/mlx/prefill-policy.ts +0 -26
- package/src/backends/mlx/prefill-rows.ts +0 -244
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/prompt-input.ts +0 -29
- package/src/backends/mlx/qwen-prompt-input.ts +0 -40
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -54
- package/src/backends/mlx/rollback.ts +0 -92
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -251
- package/src/backends/mlx/speculative-group.ts +0 -438
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -131
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3490
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -70
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/object-cache.ts +0 -8
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -261
- package/src/contracts/prefix-cache.ts +0 -33
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -54
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -64
- package/src/engine/execution-tasks.ts +0 -44
- package/src/engine/namespaced-cache.ts +0 -13
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -92
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -463
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1352
- package/src/grammar.ts +0 -604
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -45
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -279
- package/src/kv-store.ts +0 -1135
- package/src/lab/README.md +0 -22
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-attention.ts +0 -117
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
- package/src/lab/paged-kv/paged-kv.ts +0 -336
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -54
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -425
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -531
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/normalized-argmax.ts +0 -116
- package/src/mlx/ops.ts +0 -1108
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -94
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -57
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -215
- package/src/model/fingerprint.ts +0 -45
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2370
- package/src/model/gemma4.ts +0 -1395
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -70
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -468
- package/src/model/quantized-append-attention.ts +0 -31
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -250
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -881
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -110
- package/src/model/token-groups.ts +0 -66
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -89
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/model/whisper.ts +0 -435
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native/mic_capture.swift +0 -92
- package/src/native-pack.ts +0 -163
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1940
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -682
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -77
- package/src/safetensors.ts +0 -165
- package/src/sampler.ts +0 -1012
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/audio-routes.ts +0 -323
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -537
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -49
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -161
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/serve/transcription-server.ts +0 -64
- package/src/serve/transcription-service.ts +0 -502
- package/src/server.ts +0 -1282
- package/src/spec/assistant-rows.ts +0 -93
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -318
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -226
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -230
- package/src/spec/qwen-mtp-source.ts +0 -386
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -587
- package/src/spec/source.ts +0 -228
- package/src/spec/two-model-rows.ts +0 -62
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -431
- package/src/ssd-durability.ts +0 -209
- package/src/storage/host-buffer.ts +0 -24
- package/src/storage/kv-writer.ts +0 -83
- package/src/storage/kv-writer.worker.js +0 -264
- package/src/storage/retention-policy.ts +0 -37
- package/src/tiered-prompt-cache.ts +0 -45
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -176
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -409
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -233
- package/src/vision/qwen3vl-tower.ts +0 -566
- package/src/vision/siglip.ts +0 -607
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2155
- package/src/web/app.js +0 -5863
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1060
- package/src/web/src/composer.ts +0 -962
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/src/voice.ts +0 -141
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/{serve → server}/generated-token-history.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
|
@@ -1,2225 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
status: active
|
|
3
|
-
axis: ON
|
|
4
|
-
canonical-for: turboquant
|
|
5
|
-
plan-anchor: "Phase: TurboQuant weights — rotation-folded quantization, Qwen3.8-27B target `[ ]` (opened 2026-08-17)"
|
|
6
|
-
last-verified: 2026-08-23
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# TurboQuant — rotation-based quantization (KV leg landed, weights leg open)
|
|
10
|
-
|
|
11
|
-
One canonical doc for both legs of the rotate-then-quantize program.
|
|
12
|
-
Sources folded in: `docs/design/turboquant.md` (KV, landed 2026-07-06)
|
|
13
|
-
and `docs/design/turboquant.md` (weights, open). Status/changelog
|
|
14
|
-
prose lives in PLAN.md under the plan-anchor above (weights) and the closed
|
|
15
|
-
Phase 13 entry (KV); this doc keeps mechanism, invariants, decisions with
|
|
16
|
-
rationale, measured curves, and open items.
|
|
17
|
-
|
|
18
|
-
## Naming: TurboQuant is a KV method by origin
|
|
19
|
-
|
|
20
|
-
TurboQuant (arXiv:2504.19874, Google) is a KV-cache quantizer: rotate the
|
|
21
|
-
value vectors so their marginals are near-Gaussian, then Lloyd-Max quantize.
|
|
22
|
-
That is the leg we ship under `--kv-quant turbo`. The **weights leg is this
|
|
23
|
-
repo's extension** of the same mechanism to weight matrices — mechanically
|
|
24
|
-
it is the QuaRot/SpinQuant family (rotation folded offline into adjacent
|
|
25
|
-
weights, then quantized with mlx's stock formats), not anything the
|
|
26
|
-
TurboQuant paper describes. The shared name records the shared idea
|
|
27
|
-
(rotate → Gaussian marginal → better codebook coverage) and that both are
|
|
28
|
-
the QUANTIZER axis of the mixed-precision program: they compose with, and
|
|
29
|
-
never replace, per-layer allocation (OptiQ-style) and calibration.
|
|
30
|
-
|
|
31
|
-
| leg | what is rotated | when | oracle | state |
|
|
32
|
-
|---|---|---|---|---|
|
|
33
|
-
| KV | value vectors (keys affine, unrotated) | online, per appended token | vllm-metal `turboquant.py` | landed 2026-07-06 |
|
|
34
|
-
| weights | residual-stream basis of every linear | offline, folded into weights | QuaRot + SpinQuant fold code; mlx-lm GPTQ | open (PLAN "TurboQuant weights") |
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
# Part A — KV leg (`--kv-quant turbo`)
|
|
39
|
-
|
|
40
|
-
## What it is
|
|
41
|
-
|
|
42
|
-
Rotation-based KV-cache quantization: signed int8 affine keys + FWHT-rotated
|
|
43
|
-
3-bit Lloyd-Max values, per-32-group fp16 scales. More usable context at the
|
|
44
|
-
same memory (2.56× KV compression at the k8/v3 default, head_dim 128). Owner
|
|
45
|
-
seam: L2 cache format, L1-unmodified attention (dequantize-on-fetch), opt-in
|
|
46
|
-
only — the naked default stays L1 (bf16 KV).
|
|
47
|
-
|
|
48
|
-
## Oracle chain (decided 2026-07-06)
|
|
49
|
-
|
|
50
|
-
Two unrelated implementations share the name; do not conflate:
|
|
51
|
-
|
|
52
|
-
- **The paper** (arXiv:2504.19874): dense QR random rotation, no groups, no
|
|
53
|
-
K/V asymmetry, optional QJL residual stage. Anchors the WHY (rotate →
|
|
54
|
-
Gaussian marginal → Lloyd-Max optimal; 4^-b distortion law), not the layout.
|
|
55
|
-
- **vllm-metal** (`vllm-project/vllm-metal`,
|
|
56
|
-
`vllm_metal/attention/caches/turboquant.py` + `kernels_v2/turboquant.metal`):
|
|
57
|
-
the engineering variant. optiq's `runtime/mtp/turboquant.py` config layer is
|
|
58
|
-
lifted verbatim from it (byte-identical `CENTROIDS_3BIT`, matching op
|
|
59
|
-
signatures in optiq `cache_state.py`). **This is our oracle** — "the oracle
|
|
60
|
-
is whoever ships it." Its Python reference is pure MLX; we vendor it at
|
|
61
|
-
`lab/repro/vllm-metal-turboquant/turboquant_reference.py` (fetch provenance
|
|
62
|
-
in `PROVENANCE.md` beside it) and generate bit-exact goldens through the
|
|
63
|
-
oracle venv. Quirks are preserved on purpose: the port matches what the file
|
|
64
|
-
computes, not what its comments say.
|
|
65
|
-
- mlx-vlm's module is a THIRD design (whole-vector norms, MSE/Prod codecs,
|
|
66
|
-
keys rotated too) — not our target; its unit-vector MSE anchors
|
|
67
|
-
(≈{0.36, 0.117, 0.03} at bits {1,2,3}) remain useful sanity checks.
|
|
68
|
-
- vllm-metal's rendered docs claim keys are rotated; the code never rotates
|
|
69
|
-
keys. Trust the source.
|
|
70
|
-
|
|
71
|
-
## Algorithm (vllm-metal reference semantics, exact)
|
|
72
|
-
|
|
73
|
-
Per token, per kv-head, groups of 32 along head_dim (head_dim ∈
|
|
74
|
-
{64,128,256,512} — `TURBOQUANT_HEAD_DIMS` in `src/mlx/turboquant-tables.ts`).
|
|
75
|
-
|
|
76
|
-
**Keys — NO rotation, asymmetric affine, per-32-group:**
|
|
77
|
-
- signed (int8, bits=8): `max_val=127; scale=(max−min)/(2·max_val);
|
|
78
|
-
zero=round((max+min)/(2·scale)); idx=clip(round(x/scale − zero), −127, 127)`,
|
|
79
|
-
one byte per element (no packing at 8 bits).
|
|
80
|
-
- unsigned (bits ∈ {2,4,5}): `max_val=2^bits−1; scale=(max−min)/max_val;
|
|
81
|
-
zero=round(min/scale); idx=clip(round(x/scale − zero), 0, max_val)`, packed.
|
|
82
|
-
- Dequant (both): `x̂=(idx+zero)·scale`; scale/zero fp16, one pair per group.
|
|
83
|
-
- The reference routes intermediates through fp16 and deliberately drops the
|
|
84
|
-
`+1e-8` scale epsilon (it underflows in fp16). Our port upcasts the affine
|
|
85
|
-
arithmetic to fp32 (production feeds bf16 K; bf16 arithmetic shifted
|
|
86
|
-
rounding-boundary indices vs the reference) and casts only scale/zero to
|
|
87
|
-
fp16 at the end — reproducing the reference's real defect that a
|
|
88
|
-
constant-valued block overflows zero_point to ±Inf. The golden test asserts
|
|
89
|
-
it (`src/mlx/turboquant-ops.ts` header).
|
|
90
|
-
|
|
91
|
-
**Values — FWHT + Lloyd-Max, per-32-group RMS scale:**
|
|
92
|
-
- `y = FWHT(x · signs)`, `signs ∈ {±1}^d` from
|
|
93
|
-
`mx.random.randint(0,2,(d,), key=mx.random.key(42))`; FWHT normalizes by 1/√d.
|
|
94
|
-
- `scale = sqrt(mean(y²))` per 32-group (RMS, not min/max); `y_n = y/(scale+1e-8)`.
|
|
95
|
-
- `idx = searchsorted(BOUNDARIES, y_n)`. 3-bit table: centroids
|
|
96
|
-
±{0.24509, 0.75601, 1.34391, 2.15195}, boundaries ±{0.50055, 1.04996,
|
|
97
|
-
1.74793}, 0. Other widths (2/4/5/8): the reference's iterative Lloyd-Max on
|
|
98
|
-
a unit normal (key(0), 500 iterations), generated ONCE and hardcoded —
|
|
99
|
-
parity by construction, no runtime iteration.
|
|
100
|
-
- Pack: flat little-endian bitstream, element i at bits [i·b, i·b+b); values
|
|
101
|
-
may straddle bytes (3-bit: 8 values → 3 bytes).
|
|
102
|
-
- Dequant: `x̂ = InvFWHT(centroids[idx] · scale · signs⁻¹)`.
|
|
103
|
-
|
|
104
|
-
**Bytes per token per head (k8v3, d=128):** 128 (K int8) + 8+8 (K
|
|
105
|
-
scale/zero) + 48 (V packed) + 8 (V scale) = 200 vs 512 bf16 → 2.56×. This
|
|
106
|
-
reproduces optiq's `compression_ratio`. Sign vectors are hardcoded constants
|
|
107
|
-
per head_dim (what vllm-metal does in its .metal source) — deterministic
|
|
108
|
-
across machines and spill/restore.
|
|
109
|
-
|
|
110
|
-
## Architecture in mlx-bun (verified 2026-08-23)
|
|
111
|
-
|
|
112
|
-
Dequantize-on-fetch: `TurboQuantKVCache implements Cache`
|
|
113
|
-
(`src/model/gemma4-base.ts`; does NOT subclass KVCache, which keeps it
|
|
114
|
-
auto-excluded from batching). `updateAndFetch(k,v)` quantizes only the newly
|
|
115
|
-
appended tokens into packed storage and returns the dequantized bf16 active
|
|
116
|
-
window, so stock `ops.sdpa` runs unmodified — the pattern optiq's
|
|
117
|
-
`runtime/kv/rotating.py` uses. A novel cache class fails every generated-file
|
|
118
|
-
`#matches()` guard and falls back to the monolith by design. Quantization
|
|
119
|
-
groups run along head_dim only — token-axis slicing stays byte-safe
|
|
120
|
-
(standing invariant).
|
|
121
|
-
|
|
122
|
-
Code map:
|
|
123
|
-
- `src/mlx/turboquant-ops.ts` — fwht (binds `mlx_hadamard_transform`),
|
|
124
|
-
encode/decode keys + values, pack/unpack, `unrotateValues`.
|
|
125
|
-
- `src/mlx/turboquant-tables.ts` — GENERATED by `bun scripts/regen.ts
|
|
126
|
-
turboquant` (job file `scripts/regen/turboquant.ts`, which shells out to
|
|
127
|
-
`lab/repro/vllm-metal-turboquant/gen_goldens.py` under the oracle venv):
|
|
128
|
-
sign vectors per head_dim + Lloyd-Max tables per bit-width; also writes
|
|
129
|
-
`goldens/turboquant.json` (machine-independent, flat goldens set).
|
|
130
|
-
- `src/config.ts` — `TurboQuantScheme {kBits, vBits}`,
|
|
131
|
-
`parseTurboQuantScheme` (`turbo` = k8v3; `TURBOQUANT_VALID_KBITS`
|
|
132
|
-
{2,4,5,8}, `TURBOQUANT_VALID_VBITS` {2,3,4,5,8}).
|
|
133
|
-
- `src/cli.ts` — `--kv-quant turbo[:k<bits>v<bits>]` on serve/generate/bench.
|
|
134
|
-
- `src/kv-scheme.ts` — `KvScheme` kind `"turbo"`; `cacheKey` =
|
|
135
|
-
`turbo-k<k>v<v>` (the SSD-cache / prompt-cache anti-collision key);
|
|
136
|
-
`bytesAt` bills bf16 (conservative — no projector for the packed layout
|
|
137
|
-
yet); `fitOptions` is empty for turbo for the same reason.
|
|
138
|
-
- `src/generate.ts` `maybeQuantizeKv()` → `maybeTurboQuantizeKv()` — the
|
|
139
|
-
single conversion chokepoint (serve serial lane + generate + eval all flow
|
|
140
|
-
through it); `TurboQuantKVCache.fromKVCache`; `RotatingKVCache` layers stay
|
|
141
|
-
bf16 with a one-time warning; keeps the `quantizedKvStart` semantics.
|
|
142
|
-
- `src/backends/mlx/kv-codec.ts` and `src/model/turboquant-codec.ts` separate
|
|
143
|
-
encoding and existing fused kernel selection from storage membership.
|
|
144
|
-
- `KvTensorRows` owns arbitrary encoded planes; `BatchedTurboQuantKVCache`
|
|
145
|
-
binds the five TQ planes to shared positions and a rotated-value attention
|
|
146
|
-
port. Gemma owns pre-write row positions across cache appends and releases
|
|
147
|
-
shared positions with the shared attention state.
|
|
148
|
-
- `src/backends/mlx/cache-layout.ts` supplies ordinary and target-transaction
|
|
149
|
-
layouts. The gateway binds start-zero TQ and grouped Qwen MTP capabilities;
|
|
150
|
-
the scheduler only chooses work. Server head-dimension validation remains.
|
|
151
|
-
`turboQuant` and `kvQuant` are mutually exclusive.
|
|
152
|
-
- `src/kv-store.ts` — `CacheKind "turboquant"`; header carries kBits/vBits
|
|
153
|
-
+ head_dim; snapshot/restore/clone branches.
|
|
154
|
-
- `src/model/fingerprint.ts` — NOT touched, by symmetry: uniform
|
|
155
|
-
`--kv-quant 4|8` is a CLI-only runtime lever that never feeds
|
|
156
|
-
`configFingerprint()` either; the anti-collision mechanism for this class
|
|
157
|
-
of lever is the scheme key above, not the fingerprint.
|
|
158
|
-
- Tests: `tests/turboquant-ops.test.ts` (golden bit-exactness vs the
|
|
159
|
-
vendored reference + model-free math props), `tests/turboquant-cache.test.ts`
|
|
160
|
-
(cache invariants, growth/trim, persistence roundtrip; synthetic arrays).
|
|
161
|
-
- Curve script: `scripts/turboquant/eval-turboquant-curve.ts` — bf16
|
|
162
|
-
baseline + {k8v8,k8v4,k8v3,k8v2,k4v3,k4v2} sequentially, reusing
|
|
163
|
-
`src/eval/kl.ts`'s `evaluateKlKvArm` (teacher-forced serving-decode KL,
|
|
164
|
-
real `fromKVCache` conversion) and `src/eval/perplexity.ts`'s `evalPpl`.
|
|
165
|
-
- Reference docs: server-config.md, cli.md, docs/reference/server-config.md carry the
|
|
166
|
-
flag surface.
|
|
167
|
-
|
|
168
|
-
## Deferred inverse FWHT (landed 2026-07-06, post-v1)
|
|
169
|
-
|
|
170
|
-
Attention is linear in V, so `InvFWHT(Σᵢ wᵢ·v̂ᵢ) = Σᵢ wᵢ·InvFWHT(v̂ᵢ)`:
|
|
171
|
-
`updateAndFetchDeferredV` returns the V window still in the rotated domain
|
|
172
|
-
and the attention site un-rotates the OUTPUT once per query row
|
|
173
|
-
(`tq.unrotateValues`) — O(q·d log d) per step instead of O(T·d log d).
|
|
174
|
-
Opt-in per attention site via `SharedKv.vRotated` (monolith `gemma4.ts` —
|
|
175
|
-
KV-shared consumer layers inherit the flag through `sharedIn` — and
|
|
176
|
-
`minicpm5.ts`); every other consumer keeps calling `updateAndFetch` (eager)
|
|
177
|
-
and stays correct. Not bit-identical to eager (bf16 rounding in the rotated
|
|
178
|
-
domain before the transform); measured k8v3 KL 0.0338 vs eager 0.0325 —
|
|
179
|
-
same quality. Paired fetch-path A/B on a LOADED M1 Max: never slower,
|
|
180
|
-
~10-20% off fetch cost at 4k ctx, noise-level at 8k (dequant gather
|
|
181
|
-
dominates both) — no speed claim until a quiet-machine
|
|
182
|
-
`scripts/bench-serve.ts all` run; the win is removing the O(T) transform,
|
|
183
|
-
which matters more once the gather itself is fused. (The class-level doc
|
|
184
|
-
comment on `TurboQuantKVCache` still calls deferred-InvFWHT a non-goal; the
|
|
185
|
-
method exists two screens below it — the comment is stale, the code is
|
|
186
|
-
authoritative.)
|
|
187
|
-
|
|
188
|
-
## Packed-value decode fusion investigation
|
|
189
|
-
|
|
190
|
-
The Mac-quant video follow-up in decode-speed-program §7.11 exposed an
|
|
191
|
-
unpack/gather/scale chain that also exists in our shipped KV decoder. A
|
|
192
|
-
research-only Metal prototype reads the byte-packed values and fp16 group
|
|
193
|
-
scales directly from the active cache window, gathers the existing f32
|
|
194
|
-
Lloyd-Max centroids and multiplies in f32. The eager path keeps the native
|
|
195
|
-
inverse Hadamard, sign multiplication and bf16 cast. The deferred path casts
|
|
196
|
-
the same f32 values to bf16. Keys and the quantized representation stay the
|
|
197
|
-
same. The four-dimensional launch reads cache strides without copying its
|
|
198
|
-
capacity slice; context length, capacity and head count remain runtime inputs.
|
|
199
|
-
There is no specialization for each new token position.
|
|
200
|
-
|
|
201
|
-
On the M4 Pro 24 GB, the initial 140 cases preserve 280 flat/grid comparisons
|
|
202
|
-
across value bits 2/3/4/5/8, head dimensions 64/128/256/512, multiple batch/head
|
|
203
|
-
counts, strided cache windows and both rotation paths. Three six-process
|
|
204
|
-
repeats preserve another 1,440 candidate comparisons and every cross-process
|
|
205
|
-
fixture/output hash. These add fp16 scales and the production 32-value group
|
|
206
|
-
to the initial bf16/f32 and 64-value-group operation coverage. Every process
|
|
207
|
-
returns to its primed native sign/centroid-cache allocation. The all-dimension
|
|
208
|
-
screen retains 5,104 bytes; each D256 repeat retains 2,288 bytes. The generated
|
|
209
|
-
kernel keys stay constant across the three tested context lengths.
|
|
210
|
-
|
|
211
|
-
The last repeat uses synthetic [1,8,N,256] caches with fp16 scales and groups
|
|
212
|
-
of 32. For eager V3 decode, paired median operation time falls 46.72% at N128,
|
|
213
|
-
77.43% at N2048 and 81.37% at N8192. V5 falls 54.66%, 82.12% and 84.93%. Every
|
|
214
|
-
V3/V5 pair improves. At N8192, peak temporary allocation falls about 250 MiB
|
|
215
|
-
for V3 and 282 MiB for V5. The repeat checks outputs before timing and after
|
|
216
|
-
the last rep of each arm; the earlier screen read the output on the CPU
|
|
217
|
-
between every rep, which changed the timing regime. Raw screens are retained.
|
|
218
|
-
These are operation diagnostics on a loaded machine, not RSS or full-model
|
|
219
|
-
speed claims. This Qwen artifact has four KV heads, so the next gate runs the
|
|
220
|
-
actual model. The experimental full-model branch keeps V8 on its native path
|
|
221
|
-
while the larger low-bit gain is assessed.
|
|
222
|
-
|
|
223
|
-
Evidence in reports/qwen38-rd: tq-value-grid.json,
|
|
224
|
-
tq-value-repeat{,-review}.json, tq-value-f16-repeat{,-review}.json and
|
|
225
|
-
tq-value-production-repeat{,-review}.json. Full-model logits, live cache and
|
|
226
|
-
recurrent state, seeded generation, actual HTTP timing, fallback/lifetime and
|
|
227
|
-
quiet acceptance are required before production integration or a default.
|
|
228
|
-
|
|
229
|
-
The first Qwen k8v3 full-model pair now preserves all 20 forward/state and
|
|
230
|
-
continuation comparisons plus four greedy/seeded-sampled generations at
|
|
231
|
-
128/2048 input tokens. Both arms make 4,880 cache-value calls. The candidate
|
|
232
|
-
uses one D256/V3/group32/fp16-scale specialization across every context length;
|
|
233
|
-
final active allocation is identical at 1,016,898 bytes. Timing is mixed:
|
|
234
|
-
single-token forwards improve, while three of four complete generations lose.
|
|
235
|
-
During the candidate process, one-minute load rises from 2.80 to 7.57 and
|
|
236
|
-
system swap grows about 323 MiB, so this pair cannot isolate the cause of the
|
|
237
|
-
slowdown. It is retained in full, and no production/default decision follows.
|
|
238
|
-
Evidence: tq-value-full{,-review}.json. Actual Bun HTTP comparisons follow.
|
|
239
|
-
|
|
240
|
-
An additional 270 finite-scale-boundary cases preserve 540 comparisons,
|
|
241
|
-
including zero, signed zero, fp16 subnormals and large scales at every head
|
|
242
|
-
dimension, with the actual four-KV-head shape included. All allocations return
|
|
243
|
-
to the primed 5,104-byte global cache. Evidence: tq-value-edge.json. The first
|
|
244
|
-
actual HTTP pair preserves all five responses, call maps and final allocation.
|
|
245
|
-
Measured complete time falls 0.77% for the 58-token code prompt and 1.38% for
|
|
246
|
-
the 1,806-token inventory prompt. The latter improves decode throughput 7.57%
|
|
247
|
-
but worsens TTFT 3.80%; it is a screening pair, not acceptance. Six alternating
|
|
248
|
-
fresh-server pairs now preserve all 30 paired responses, call maps, source
|
|
249
|
-
hashes and process exits. Each server ends with the same 11,936,577,410 active
|
|
250
|
-
bytes, which includes the retained model. Paired median complete time falls
|
|
251
|
-
0.82% on the short prompt, all six pairs, and 2.87% on the long prompt, four of
|
|
252
|
-
six pairs. Long-prompt decode throughput rises 7.33%, five of six pairs; TTFT
|
|
253
|
-
worsens 0.75% in the paired median and is split three wins/three losses. Per-
|
|
254
|
-
request sampled RSS differences are small and inconsistent, so this is not a
|
|
255
|
-
physical-memory claim. Retain both losing long-prompt pairs. Evidence:
|
|
256
|
-
tq-value-http-repeat{,-review}.json. Test decode-only eligibility to separate
|
|
257
|
-
prefill scheduling from decode, then broader context/quant/cache and quiet
|
|
258
|
-
acceptance. No production/default change yet.
|
|
259
|
-
|
|
260
|
-
A separate decode-only V arm also preserves 20 forward/state cases and four
|
|
261
|
-
generations. Exact call maps show 4,480 fused M1 reads and 400 native
|
|
262
|
-
multi-token reads; active allocation remains 1,016,898 bytes. Evidence:
|
|
263
|
-
tq-value-decode-full{,-review}.json. A first timing pair improves complete
|
|
264
|
-
generation, but it is not the policy decision.
|
|
265
|
-
|
|
266
|
-
The next prototype decodes packed K and V in one launch, retaining K's f32
|
|
267
|
-
addition before multiplication and V's f32 centroid multiplication. It passes
|
|
268
|
-
720 initial pair comparisons. An expanded screen checks all 20 served K/V bit
|
|
269
|
-
combinations with distinct key/value scales, including finite boundary values,
|
|
270
|
-
and preserves all 2,400 comparisons. Equal scale values in the initial
|
|
271
|
-
synthetic fixtures could not detect a swapped scale input; the expanded
|
|
272
|
-
fixtures close that gap. Actual-model scales were already independent.
|
|
273
|
-
|
|
274
|
-
Six fresh-process operation repeats preserve another 432 comparisons. With
|
|
275
|
-
actual four-head D256 caches, fp16 scales and group32, joint k8v3 decoding is
|
|
276
|
-
9.60%, 22.80% and 43.19% faster than V-only fusion at N128/2048/8192 in the
|
|
277
|
-
paired median, all six pairs at each context. These include the native inverse
|
|
278
|
-
rotation. Peak temporary allocation falls another 0.53/8.5/34 MiB. The full
|
|
279
|
-
Qwen pair preserves 20 forward/state comparisons and four generations, all
|
|
280
|
-
4,880 cache calls, one generated specialization and identical final active
|
|
281
|
-
allocation. Source and raw evidence: tq-kv-screen.json,
|
|
282
|
-
tq-kv-independent.json, tq-kv-repeat{,-review}.json and
|
|
283
|
-
tq-kv-full{,-review}.json.
|
|
284
|
-
|
|
285
|
-
The actual Bun HTTP follow-up completes all six arm orders across 18 fresh
|
|
286
|
-
servers. Its 90 requests preserve all 60 candidate/control response comparisons,
|
|
287
|
-
call and eligibility maps, process exits and source hashes. Every server retains
|
|
288
|
-
the same 11,936,577,410 active bytes. Each candidate uses one shader specialization
|
|
289
|
-
across both prompt lengths. These runs use the same R6 weights, k8v3 cache,
|
|
290
|
-
serial execution, greedy seed42 and no prompt reuse or speculative draft.
|
|
291
|
-
|
|
292
|
-
| Candidate versus original | 58-token prompt: complete time | 1,806-token prompt: complete time | Long-prompt decode throughput | Long-prompt TTFT |
|
|
293
|
-
|---|---|---|---|---|
|
|
294
|
-
| V fusion only on M1 appends | −0.81%, 6/6 wins | −3.42%, 5/6 wins | +7.53%, 5/6 wins | −0.14%, 5/6 wins |
|
|
295
|
-
| Joint K/V at all append shapes | −0.76%, 5/6 wins | −4.57%, 6/6 wins | +10.35%, 6/6 wins | −0.17%, 5/6 wins |
|
|
296
|
-
|
|
297
|
-
Values are medians of paired changes, not ratios of unpaired medians. Joint
|
|
298
|
-
decoding also improves long-prompt complete time over decode-only V by 1.20%,
|
|
299
|
-
all six pairs; its short-prompt median is 0.08% slower. The first joint short
|
|
300
|
-
request loses 3.70%, and the first decode-only long request loses 2.30%; both
|
|
301
|
-
remain in the report. TTFT is effectively flat. Observed RSS deltas remain
|
|
302
|
-
small and do not establish physical-memory savings. Evidence:
|
|
303
|
-
tq-kv-policy-http{,-review}.json. Extend the exact gates to 8,192 context tokens,
|
|
304
|
-
RTN4 and deferred-rotation consumers, then check integrated lifetime/fallback
|
|
305
|
-
behavior. These are M4 Pro diagnostics with existing system swap; quiet
|
|
306
|
-
acceptance and a production/default decision remain open.
|
|
307
|
-
|
|
308
|
-
The 8,192-token R6 gate also passes: six full forward/state/continuation cases
|
|
309
|
-
at M1/4/128 and two 64-token greedy/sampled generations are exact. Both arms
|
|
310
|
-
make 2,960 cache calls and finish at 1,016,898 active bytes; the candidate still
|
|
311
|
-
uses one shader key. In this single pair, complete generation time falls 9.11%
|
|
312
|
-
and 7.43%, and native peak allocation falls 126.97 MiB. The measured M1 forward
|
|
313
|
-
falls from 200.84 to 118.87 ms. These are screening timings, not repeated HTTP
|
|
314
|
-
acceptance or physical-memory savings. Evidence: tq-kv-long-full{,-review}.json.
|
|
315
|
-
|
|
316
|
-
A further prototype folds inverse Hadamard, normalization, signs and bf16 cast
|
|
317
|
-
into the joint decoder. It copies the exact radix-16 butterfly and indexing from
|
|
318
|
-
MLX 0.31.2's MIT-licensed Metal Hadamard implementation. All 480 shape/bit/dtype/
|
|
319
|
-
finite-boundary cases preserve both candidate comparisons. Six fresh processes
|
|
320
|
-
then preserve all 36 performance cells, but the literal one-row threadgroup
|
|
321
|
-
layout loses to joint decode plus native rotation: k8v3 paired median operation
|
|
322
|
-
time rises 12.76%/20.11%/24.67% at N128/2048/8192. Lower temporary allocation
|
|
323
|
-
alone does not justify this version. The follow-up tests independent rows in
|
|
324
|
-
one threadgroup, preserving each row's arithmetic and participation in barriers
|
|
325
|
-
at partial tails. Evidence: tq-kv-rotation-screen.json and
|
|
326
|
-
tq-kv-rotation-repeat{,-review}.json. No full-model run is justified for the
|
|
327
|
-
losing layout.
|
|
328
|
-
|
|
329
|
-
Grouping independent rows into one threadgroup preserves the same 960 boundary
|
|
330
|
-
comparisons, including partially occupied tail groups. Six fresh-process repeats
|
|
331
|
-
preserve all 36 timing cells. At N8192, this version improves over joint decode
|
|
332
|
-
plus native rotation by 22.28% for k8v3 and 23.20% for k4v3, all six pairs, while
|
|
333
|
-
halving the operation's peak temporary allocation from 64 to 32 MiB. It remains
|
|
334
|
-
slower at N128 and N2048; for k8v3 the paired medians are +4.08% and +20.43%.
|
|
335
|
-
Only a long-context candidate is justified for full-model/request testing.
|
|
336
|
-
Evidence: tq-kv-rotation-rows-screen.json and
|
|
337
|
-
tq-kv-rotation-rows-repeat{,-review}.json. The baseline layout does not advance.
|
|
338
|
-
|
|
339
|
-
Joint decoding also passes the RTN4 full-model counterpart: 18 forward/state/
|
|
340
|
-
continuation cases at context128/2048/8192 and four generations are exact, with
|
|
341
|
-
5,536 matching cache calls, one specialization and 1,000,514 final active bytes
|
|
342
|
-
per arm. Its first paired generation timings improve, but repeated RTN4 HTTP
|
|
343
|
-
acceptance remains. A nonfinite follow-up preserves 960 additional comparisons
|
|
344
|
-
across every served bit pair, all head dimensions and scale dtypes, including
|
|
345
|
-
NaNs, infinities and arbitrary f32 zero-point fractions. This covers the
|
|
346
|
-
reference codec's documented zero-scale/infinite-fp16-zero behavior.
|
|
347
|
-
|
|
348
|
-
The MiniCPM5-1B counterpart exercises deferred V rotation: all 20 forward/state
|
|
349
|
-
cases, four generations and 7,320 cache calls match. Both arms finish at 524,860
|
|
350
|
-
active bytes; the candidate uses one D128 specialization. These are correctness
|
|
351
|
-
and first-pair timing gates, not repeated cross-model serving claims. Evidence:
|
|
352
|
-
tq-kv-rtn4-full{,-review}.json, tq-kv-nonfinite.json and
|
|
353
|
-
tq-kv-minicpm-full{,-review}.json. Gemma D512 and integrated operation/fallback/
|
|
354
|
-
lifetime checks follow.
|
|
355
|
-
|
|
356
|
-
Gemma-4-e4b's D512 deferred consumer also passes: 20 forward/state cases, four
|
|
357
|
-
generations and 1,220 matching cache reads, one specialization and 1,057,864
|
|
358
|
-
final active bytes per arm. Evidence: tq-kv-gemma-e4b-full{,-review}.json.
|
|
359
|
-
|
|
360
|
-
The joint decoder was initially integrated as an experimental opt-in. The environment
|
|
361
|
-
setting and supported inputs are documented in server-config.md. A shared
|
|
362
|
-
`src/mlx/turboquant-kv-decode.ts` owns only the packed Metal operation; the existing
|
|
363
|
-
codec owns inverse rotation and the cache captures operation selection once.
|
|
364
|
-
Request/execution interfaces, quantization and persistence remain unchanged.
|
|
365
|
-
The original codec remains the fallback and correctness reference. Five new
|
|
366
|
-
operation tests pass 1,102 assertions across served bit combinations, head
|
|
367
|
-
dimensions, independent group sizes, nonfinite values, strided storage, fallback
|
|
368
|
-
and shapeless-trace behavior, borrowing and exact post-disposal allocation.
|
|
369
|
-
All three typechecks pass. With fusion enabled, the existing 26 codec/cache
|
|
370
|
-
tests also pass, including growth, trim and mixed-cache persistence. Their
|
|
371
|
-
snapshot helpers now release temporary casts and owned state views instead of
|
|
372
|
-
letting test-only allocations obscure the lifecycle checks. The integrated
|
|
373
|
-
model/HTTP evidence follows; prototype timings above are not automatically
|
|
374
|
-
attributed to the production dispatch.
|
|
375
|
-
|
|
376
|
-
The integrated R6 gate now preserves all 20 forward/state/continuation cases,
|
|
377
|
-
four generations, 4,880 cache reads and 1,016,898 final active bytes per arm.
|
|
378
|
-
Passive observation confirms that every enabled read reaches the production
|
|
379
|
-
kernel, with one specialization. The full model-free tier passes 1,873 tests
|
|
380
|
-
with 10 skips; typechecks and pure hygiene also pass. Evidence:
|
|
381
|
-
tq-kv-integrated-full{,-review}.json and tq-kv-integrated-code-checks.json.
|
|
382
|
-
The integrated RTN4 counterpart also preserves all 20 forward/state cases,
|
|
383
|
-
four generations, 4,880 reads and 1,000,514 final active bytes. Its first-pair
|
|
384
|
-
timings are mixed: three complete-generation cells regress 0.44–1.88%, while
|
|
385
|
-
the 2,048-token sampled cell improves 4.33%. Exactness alone does not establish
|
|
386
|
-
a speed gain. Evidence: tq-kv-integrated-rtn4-full{,-review}.json.
|
|
387
|
-
|
|
388
|
-
Six integrated R6 HTTP pairs preserve all 30 response comparisons, call maps,
|
|
389
|
-
one candidate specialization and equal post-exit active allocation. Paired
|
|
390
|
-
medians for the 58-token prompt are −0.74% complete time and +0.75% decode,
|
|
391
|
-
both six wins. At 1,806 prompt tokens they are −3.61% complete time, four wins,
|
|
392
|
-
and +10.33% decode, five wins. Long-prompt TTFT is +1.81%, three wins. Both
|
|
393
|
-
complete-time losses, +0.55% and +10.95%, remain in the result. This repeat is
|
|
394
|
-
noisier than the prototype, with no established TTFT improvement.
|
|
395
|
-
|
|
396
|
-
The same run stops after its first RTN4 pair on a 10,944-byte difference in
|
|
397
|
-
post-exit active allocation, with less retained in the candidate. All five
|
|
398
|
-
responses and the cache call maps match. The original run remains marked
|
|
399
|
-
incomplete; the later allocation investigation and revised assessment appear
|
|
400
|
-
below. Every child exits
|
|
401
|
-
cleanly and all 547 recorded source hashes remain unchanged. Evidence:
|
|
402
|
-
tq-kv-integrated-http{,-review}.json. A separate instrumented allocation/GC
|
|
403
|
-
diagnostic follows; its timings cannot be compared with ordinary serving.
|
|
404
|
-
|
|
405
|
-
The HTTP extension keeps the existing RSS collector and adds the calibrated
|
|
406
|
-
native process reader. R6's whole-server sampled physical-footprint maximum
|
|
407
|
-
falls in every pair, with a median difference of 2.04 GiB; this includes
|
|
408
|
-
startup, warmups and both prompt shapes. Measured-request RSS is nearly flat.
|
|
409
|
-
These observations do not identify per-request physical peaks or prove
|
|
410
|
-
savings across models. Longer-context, pressure, repeated deferred-model
|
|
411
|
-
serving and quiet acceptance remain before any default decision.
|
|
412
|
-
|
|
413
|
-
A fresh six-pair RTN4 repeat completes all 60 requests with all 30 response
|
|
414
|
-
comparisons and cache call maps exact. Both prompt shapes improve complete
|
|
415
|
-
time and decode throughput in every pair. At 58 prompt tokens the paired
|
|
416
|
-
medians are −3.07% complete time and +3.35% decode; at 1,806 they are −5.95%
|
|
417
|
-
and +15.47%. TTFT medians are about −0.63% in both cells. These use k8v3 KV,
|
|
418
|
-
serial execution and 128 generated tokens, without a speculative draft.
|
|
419
|
-
|
|
420
|
-
The repeat still fails its exact process-exit allocation gate. The candidate
|
|
421
|
-
retains 15,135,029,250 bytes in all six servers; four controls match, while
|
|
422
|
-
the last two retain 18,624 and 6,976 fewer bytes. Together with the earlier
|
|
423
|
-
smaller candidate observation, this varies in both arms. An array-tracked
|
|
424
|
-
diagnostic preserves 1,851 live wrappers and identical allocation before and
|
|
425
|
-
after explicit GC, but does not reproduce the variation. It establishes no
|
|
426
|
-
GC fix or kernel leak. The lighter observation below resolves the acceptance
|
|
427
|
-
metric, while preserving these failed reports. Evidence:
|
|
428
|
-
tq-kv-integrated-rtn4-http{,-review}.json and tq-kv-memory{,-review}.json.
|
|
429
|
-
|
|
430
|
-
The lighter array observer reproduces a 2,560-byte capacity difference while
|
|
431
|
-
both servers retain exactly 1,851 wrappers with matching dtype/shape counts
|
|
432
|
-
and logical bytes, before and after GC. This exposes a flaw in the exact-byte
|
|
433
|
-
gate: MLX's Metal allocator counts `MTLBuffer.length`, and its cache can reuse
|
|
434
|
-
a larger buffer for a smaller request. A controlled native reproduction gives
|
|
435
|
-
identical 4,096-byte arrays with either 4,096 or 6,144 active bytes. Clearing
|
|
436
|
-
unused buffers preserves that difference; disposing the live array releases
|
|
437
|
-
it completely. See the pinned allocator.cpp and buffer_cache.h plus
|
|
438
|
-
allocator-capacity-repro.json. The server's individual backing capacities were
|
|
439
|
-
not enumerated, so reuse explains the metric's limitation without attributing
|
|
440
|
-
every byte. Ownership acceptance uses the matching live-array inventory and
|
|
441
|
-
the exact native/cache disposal gates; active capacity remains a reported
|
|
442
|
-
measurement. Original failed reports remain unchanged. The revised assessment
|
|
443
|
-
is tq-kv-integrated-rtn4-http-acceptance.json.
|
|
444
|
-
|
|
445
|
-
The integrated 8K R6 gate also passes all six forward/state/continuation cases
|
|
446
|
-
and both 64-token greedy/sampled generations, with 2,960 matching cache reads,
|
|
447
|
-
one specialization and equal final allocation. In the first three-arm block,
|
|
448
|
-
joint decoding improves complete generation by 8.63%/7.59% versus the original.
|
|
449
|
-
Adding row-grouped inverse rotation only at N≥8192 preserves all results and
|
|
450
|
-
improves a further 1.25%/0.90% over integrated joint decoding. Its 2,256 rotation
|
|
451
|
-
calls exactly match eligibility, with 704 ordinary joint calls. The operation's
|
|
452
|
-
lower temporary allocation does not reduce the whole generation's peak further.
|
|
453
|
-
These are screening timings; the repeated long-context HTTP result follows. Evidence:
|
|
454
|
-
tq-kv-rotation-long{,-review}.json.
|
|
455
|
-
|
|
456
|
-
The six-block long-context HTTP repeat completes all 18 fresh servers and 54
|
|
457
|
-
requests in all six arm orders. At 8,846 prompt tokens and 128 generated tokens,
|
|
458
|
-
joint decoding versus the original codec improves paired-median decode by
|
|
459
|
-
83.87% and complete time by 12.77%. Adding row-grouped inverse rotation improves
|
|
460
|
-
a further 5.39% decode and 1.05% complete time over the integrated joint decoder.
|
|
461
|
-
Every paired complete-time and decode comparison improves. The incremental
|
|
462
|
-
TTFT median is −0.24%, with four of six wins; sampled request RSS is slightly
|
|
463
|
-
higher, so this establishes no RSS saving. All response text, usage, finish
|
|
464
|
-
reasons, call/eligibility maps and retained capacity match; all children exit
|
|
465
|
-
cleanly and all 547 recorded source hashes remain fixed. These are R6/k8v3,
|
|
466
|
-
serial, greedy seed42 diagnostics on the M4 Pro, without a draft. They do not
|
|
467
|
-
apply to bf16-cache rows. Evidence: tq-kv-rotation-long-http{,-review}.json.
|
|
468
|
-
|
|
469
|
-
That result justifies integrating the inverse operation into the same opt-in.
|
|
470
|
-
The numeric module `src/mlx/turboquant-kv-inverse.ts` owns a single D256 shader,
|
|
471
|
-
with 16 rows per threadgroup, unrolled radix16 butterflies and exact 1/16
|
|
472
|
-
normalization. The codec selects it only for the measured eager k8v3, B1/H4,
|
|
473
|
-
fp16/group32 regime at N≥8192; other calls retain joint decoding or the original
|
|
474
|
-
codec. Packed arrays and codec-table strides are explicit. N changes the grid,
|
|
475
|
-
never the shader specialization, and padded rows participate in every barrier.
|
|
476
|
-
The updated operation suite passes nine tests and 1,226 assertions, including
|
|
477
|
-
threshold/partial-row, nonfinite, strided-table, fallback and ownership checks.
|
|
478
|
-
Actual integrated model and serving acceptance against the saved prior joint
|
|
479
|
-
codec remain separate from the prototype's timing evidence. The R6 native
|
|
480
|
-
integration gate passes twelve forward/state/continuation cases and four
|
|
481
|
-
64-token greedy/sampled generations at contexts 2048/8192. Logits, tokens,
|
|
482
|
-
logprobs, complete cache states, prefix snapshots and usage are identical.
|
|
483
|
-
The candidate's 2,256 inverse calls match eligibility exactly, with 3,088 joint
|
|
484
|
-
calls; both arms release to the same retained allocation. Source hashes remain
|
|
485
|
-
fixed and both children exit cleanly. A brief concurrent CPU build prevents
|
|
486
|
-
accepting this gate's timing. Evidence:
|
|
487
|
-
tq-kv-inverse-integrated-r6-full{,-review}.json.
|
|
488
|
-
|
|
489
|
-
The MLX 0.32.2 controls now pass the same integrated model gate on both R6 and
|
|
490
|
-
RTN4. Every full logit/state/continuation case and greedy/sampled generation is
|
|
491
|
-
exact, with matching call maps, equal final active allocation and clean exits.
|
|
492
|
-
The version-specific records are mlx-upgrade-0.32.2/{r6,rtn4}-kv-inverse-full.json.
|
|
493
|
-
The integrated serving repeat now completes six usable timing pairs per quant
|
|
494
|
-
on the M4 Pro 24 GB, with the same 8,846-token prompt, k8v3, greedy seed42 and
|
|
495
|
-
128 generated tokens. Inverse rotation improves the paired-median HTTP decode
|
|
496
|
-
rate by 4.69% on R6 and 5.98% on RTN4; every decode pair improves. Complete
|
|
497
|
-
request time improves 0.79% on R6, with all six pairs improving. RTN4's complete
|
|
498
|
-
time is inconclusive: its median improves 0.38%, but only three pairs improve
|
|
499
|
-
and prefill variation exceeds the incremental saving. Neither result establishes
|
|
500
|
-
a general RSS reduction. All 78 responses across the original and replacement
|
|
501
|
-
runs match text, usage and finish reason. Call/eligibility maps match, all 26
|
|
502
|
-
servers exit cleanly and source/library hashes stay fixed. One original R6
|
|
503
|
-
timing pair was excluded after an MLX unit test overlapped its warmup; the
|
|
504
|
-
predeclared replacement supplies that pair. These are loaded-machine
|
|
505
|
-
diagnostics, not canonical acceptance. Evidence:
|
|
506
|
-
mlx-upgrade-0.32.2/inverse-kv-http{,-replacement,-review,-isolation}.json.
|
|
507
|
-
Combined pressure and quiet acceptance remain.
|
|
508
|
-
|
|
509
|
-
The consolidated 0.32.2 runtime also passes six paired actual HTTP blocks per
|
|
510
|
-
MiniCPM5-1B and Gemma4-e4b with the joint decoder off/on. Their deferred value
|
|
511
|
-
paths use D128 and D512 respectively. All 120 responses, including warmups,
|
|
512
|
-
match in text, usage and finish reason; every call map matches and all 24
|
|
513
|
-
servers exit cleanly. Source and native-library hashes remain fixed. Both
|
|
514
|
-
models improve complete request time in every measured pair. MiniCPM improves
|
|
515
|
-
substantially at both tested prompt lengths; Gemma's benefit is larger on the
|
|
516
|
-
longer prompt. Sampled RSS establishes no reduction. The server-exit observer
|
|
517
|
-
still sees resident model arrays, so its active capacity is not a disposal-to-
|
|
518
|
-
zero test. Native operation and full-model ownership gates remain separate.
|
|
519
|
-
These are M4 Pro 24 GB diagnostics with k8v3, greedy seed 42 and 128 generated
|
|
520
|
-
tokens. Those measurements used serial placement; shared integration is covered below.
|
|
521
|
-
Evidence: mlx-upgrade-0.32.2/deferred-kv-http{,-review}.json. This closes
|
|
522
|
-
the deferred-model serving comparison; broader pressure and quiet gates remain.
|
|
523
|
-
|
|
524
|
-
Direct packed-key attention is closed as an additional speed candidate. A
|
|
525
|
-
research port of MLX 0.31.2's two-pass vector attention replaces each K load
|
|
526
|
-
with the existing signed-k8 zero/scale arithmetic and bf16 rounding. It keeps
|
|
527
|
-
the native block selection, score reduction, online softmax, bf16 partial
|
|
528
|
-
output and final reduction order. The dense source port and packed-key variant
|
|
529
|
-
both match all 72 operation cases at D256, one query, GQA 6 and N1024 through
|
|
530
|
-
16384, including group32/64, fp16/bf16/f32 metadata and strided arrays. Every
|
|
531
|
-
owned allocation is released. Scope is M4 Pro, no mask or sinks, with eager
|
|
532
|
-
V already decoded; this does not cover arbitrary SDPA inputs.
|
|
533
|
-
|
|
534
|
-
Six fresh-process repeats then measure the complete eager k8v3 decode plus
|
|
535
|
-
attention using actual encoder output. All 72 cells preserve their inputs
|
|
536
|
-
and both candidate outputs, with 3,888 timed operations and matching source
|
|
537
|
-
hashes. Fixture allocations return to the same warmed codec-table baseline
|
|
538
|
-
after every cell. Direct key loads with the earlier fused V decoder improve
|
|
539
|
-
over the original operations, but lose against the integrated joint K/V
|
|
540
|
-
decoder plus native attention. Paired median regressions are about 14% at
|
|
541
|
-
N1024/1025, 19% at N2048, 6% at N8192/8193 and 8% at N16384, for contiguous
|
|
542
|
-
and strided caches. All six pairs lose except two noisy N2048 contiguous
|
|
543
|
-
cells. Peak temporary allocation falls by the removed bf16 K window, about
|
|
544
|
-
16 MiB at N8192 and 32 MiB at N16384, without a measured whole-model memory
|
|
545
|
-
benefit. The initial key-only improvement therefore does not justify a new
|
|
546
|
-
model/cache dispatch or production kernel. Evidence: tq-key-sdpa-screen.json
|
|
547
|
-
and tq-key-sdpa-complete-repeat{,-review}.json. The pinned source is MLX's
|
|
548
|
-
MIT-licensed sdpa_vector.h and scaled_dot_product_attention.cpp under
|
|
549
|
-
upstream/mlx-0.31.2; the closed research helpers are removed.
|
|
550
|
-
|
|
551
|
-
## Gates — all passed 2026-07-06 (M1 Max 32 GB)
|
|
552
|
-
|
|
553
|
-
1. **Quantizer parity (bit-exact, the hard gate):** encode indices, scales,
|
|
554
|
-
zeros, packed bytes, and dequant outputs match the vendored reference on
|
|
555
|
-
golden vectors (head_dim 64/128; configs k8v3/k4v3/k4v2/k8v4/k2v5/k5v8 —
|
|
556
|
-
every kBits/vBits value the CLI accepts).
|
|
557
|
-
2. **Math sanity (model-free):** FWHT involution/orthogonality; 3-bit
|
|
558
|
-
roundtrip MSE on unit-normal data in the paper's D_mse≈0.03 band.
|
|
559
|
-
3. **Quality-vs-bpw curve (Phase 13 exit criterion)** — MiniCPM5-1B,
|
|
560
|
-
teacher-forced serving-decode KL vs bf16, 8 prompts × 128 tokens, 32
|
|
561
|
-
decode steps; affine baselines via the same harness:
|
|
562
|
-
|
|
563
|
-
| scheme | effective KV bits | mean KL vs bf16 |
|
|
564
|
-
|---|---|---|
|
|
565
|
-
| bf16 | 16.00 | 0 (control) |
|
|
566
|
-
| uniform kv8 (affine g64) | 8.50 | 0.00246 |
|
|
567
|
-
| turbo k8v8 | 8.75 | 0.00214 |
|
|
568
|
-
| turbo k8v4 | 6.75 | 0.00936 |
|
|
569
|
-
| **turbo k8v3 (default)** | **6.25** | **0.0325** |
|
|
570
|
-
| turbo k8v2 | 5.75 | 0.175 |
|
|
571
|
-
| uniform kv4 (affine g64) | 4.50 | 0.0516 |
|
|
572
|
-
| turbo k4v3 | 4.25 | 0.0622 |
|
|
573
|
-
| turbo k4v2 | 3.75 | 0.205 |
|
|
574
|
-
|
|
575
|
-
Shape reproduces the paper's law: value bits dominate, ~4^-b decay, cliff
|
|
576
|
-
at v2. Turbo adds operating points between affine kv8/kv4; the k8v3
|
|
577
|
-
default (2.56× KV compression) beats uniform kv4's KL with room to spare.
|
|
578
|
-
Live smokes: cpm5 + e4b coherent under turbo:k8v3 (e4b emits the
|
|
579
|
-
rotating-layers-stay-bf16 warning). The paper's LongBench numbers were NOT
|
|
580
|
-
rerun — the reproduction is shape-level plus the codec-level D_mse anchor.
|
|
581
|
-
4. Whole-repo `tsc --noEmit` = 0; fast suite green; turbo requests route
|
|
582
|
-
serial with a clear reason.
|
|
583
|
-
|
|
584
|
-
The Phase 18 composition is integrated in the unreleased working tree;
|
|
585
|
-
`~/.cache/mlx-bun/turboquant-composition-validation` remains a frozen comparison.
|
|
586
|
-
It extracts the existing
|
|
587
|
-
encode/decode operations behind a KV codec interface and applies that codec to
|
|
588
|
-
one owner of five tensor fields with shared row positions. Merge, retirement,
|
|
589
|
-
rollback and extraction operate on encoded bytes. A rotated-value attention
|
|
590
|
-
port lets Gemma and MiniCPM consumers retain the existing deferred inverse
|
|
591
|
-
rotation with either storage layout.
|
|
592
|
-
|
|
593
|
-
On M1 Max and M4 Pro, the focused codec/kernel/row checks pass 29 tests and
|
|
594
|
-
2,828 assertions. A native Qwen target test passes 2,824 assertions on each
|
|
595
|
-
machine, comparing retained state and subsequent full logits at the same B=2
|
|
596
|
-
shape across unequal accepted prefixes. Existing fused kernel selection is
|
|
597
|
-
preserved. The subsequent MLX cache-layout binding now serves ordinary and
|
|
598
|
-
Qwen MTP groups through those same encoded rows. Scheduling retains its
|
|
599
|
-
method lifecycle; sampling and fused codec selection are unchanged. The
|
|
600
|
-
method key and paired-prefix namespace include the TurboQuant scheme.
|
|
601
|
-
Temporary extracted-state views use the existing lease interface.
|
|
602
|
-
|
|
603
|
-
Fused K8/V3 serving passes on both Macs: MTP2 and MTP4 each prove true B4,
|
|
604
|
-
seeded logprobs, mixed grammar, joins and retirement; ordinary tests prove
|
|
605
|
-
B1/B2/B3 and immutable RAM donor reuse. Paired RAM and SSD restart tests
|
|
606
|
-
preserve target/draft/hidden state and continuations. Full suites pass
|
|
607
|
-
2,078 tests on M1 and 2,082 on M4, with typechecks clear. MTP3 also passes
|
|
608
|
-
the M1 native/HTTP gate. On M1, all 21 saved-boundary requests match across
|
|
609
|
-
8 GiB synchronous, 1 GiB synchronous and 1 GiB asynchronous RAM-cache arms,
|
|
610
|
-
including full usage and acceptance. Each arm durably flushes all seven
|
|
611
|
-
snapshots with no missing, pending, dropped or failed writes. The constrained
|
|
612
|
-
arms cause six eviction spills; the async observer confirms 3,264 submissions.
|
|
613
|
-
These sequential shared-server pressure checks cause substantial swapping;
|
|
614
|
-
B4 correctness is a separate native gate, and no speed or memory-reduction
|
|
615
|
-
claim follows. The subsequent M4 combined pressure gate also passes with both asynchronous and blocking submissions exercised; full usage, responses and final persistence match. Current measurements and provenance live in benchmarks.md. This closes the named pressure gate; performance and default selection remain separate.
|
|
616
|
-
Shared TurboQuant integration ships in v0.4.0; v0.3.0 retained the earlier
|
|
617
|
-
placement limits.
|
|
618
|
-
Evidence: `reports/qwen38-closeout/composition-baseline/turboquant-composition-manifest.json`.
|
|
619
|
-
Integration evidence: `reports/qwen38-closeout/composition-baseline/turboquant-serving/`.
|
|
620
|
-
Broader family checks pass MiniCPM seeded/logprob serving but reproduce a
|
|
621
|
-
Gemma e4b/12B failure: attention borrows the row-offset array across a cache
|
|
622
|
-
append that releases it. The adopted ownership fix passes seeded/logprob and
|
|
623
|
-
prefix checks on both Gemma families, MiniCPM/Qwen prefix controls, and the
|
|
624
|
-
complete suites on both Macs. M4 acceptance also passes fused and unfused
|
|
625
|
-
Gemma seeded sampling, affine KV4 controls and Qwen MTP3 B4 serving.
|
|
626
|
-
MiniCPM prefix checks allow the existing policy to supersede trimmable donors
|
|
627
|
-
while proving byte identity and continuation through retirement.
|
|
628
|
-
|
|
629
|
-
### Fused codec default selection
|
|
630
|
-
|
|
631
|
-
The unreleased decoder selects packed K/V fusion by default when a caller
|
|
632
|
-
chooses TurboQuant. `turboQuantFusedDecode` resolves the runtime policy once;
|
|
633
|
-
ordinary storage, shared rows and delayed conversion capture the same value.
|
|
634
|
-
Copies and restored rows retain the codec selection through their existing
|
|
635
|
-
interfaces. `MLX_BUN_TURBOQUANT_FUSED_DECODE=0` selects the original operations.
|
|
636
|
-
The numerical kernels and eligibility rules are unchanged from the accepted
|
|
637
|
-
opt-in. TurboQuant quantization itself remains an explicit cache-format choice.
|
|
638
|
-
The current shared-serving comparison and combined pressure measurements are
|
|
639
|
-
recorded in benchmarks.md; the earlier six-pair timing and native/state gates
|
|
640
|
-
above remain the evidence for the fused implementation.
|
|
641
|
-
|
|
642
|
-
## KV-leg limits and non-goals (recorded so they don't creep)
|
|
643
|
-
|
|
644
|
-
- Full-attention layers only; rotating/sliding-window layers stay bf16 (warn
|
|
645
|
-
once, never throw). Head dims outside {64,128,256,512} refused at server
|
|
646
|
-
start.
|
|
647
|
-
- Shared ordinary execution supports row-local delayed TurboQuant; Qwen MTP
|
|
648
|
-
requires start zero. Delayed affine conversion and paged-KV combinations
|
|
649
|
-
remain unsupported.
|
|
650
|
-
- No fused quantized-SDPA Metal kernel (remaining fetch cost is
|
|
651
|
-
unpack+gather); no QJL residual stage; no entropy coding (the paper
|
|
652
|
-
declined it too).
|
|
653
|
-
- Strict legacy serial speculation and draft providers without grouped TQ
|
|
654
|
-
support retain their existing exclusions. A shared server with one active
|
|
655
|
-
row is the TQ/MTP B1 path.
|
|
656
|
-
- No speed claims: v1 dequant-on-fetch is expected slower per step at long
|
|
657
|
-
context; this ships as a memory/context feature like uniform KV. Admission
|
|
658
|
-
still bills turbo as bf16 (server-config.md says so).
|
|
659
|
-
|
|
660
|
-
---
|
|
661
|
-
|
|
662
|
-
# Part B — Weights leg (rotation-folded quantization)
|
|
663
|
-
|
|
664
|
-
## What it is
|
|
665
|
-
|
|
666
|
-
Fold an orthogonal rotation R offline into producer/consumer weight pairs so
|
|
667
|
-
every weight matrix is quantized in a rotated basis where outlier channels
|
|
668
|
-
are smeared into near-Gaussian marginals — then quantize with mlx's EXISTING
|
|
669
|
-
formats (affine / mxfp4 / nvfp4). Zero runtime cost, zero new kernels,
|
|
670
|
-
output loadable by stock mlx-lm. The QuaRot/SpinQuant family; composes with
|
|
671
|
-
(does not replace) per-layer allocation (OptiQ-style) and calibration.
|
|
672
|
-
|
|
673
|
-
Target: the best-possible Qwen3.8-27B (+ MTP companion) on our hardware,
|
|
674
|
-
beating OptiQ-4bit / plain 4bit at equal effective bpw (gate: ppl + frozen
|
|
675
|
-
6-task eval, eval DB rows, per-bpw-band comparisons).
|
|
676
|
-
|
|
677
|
-
Why weights differ from KV (the 2026-07-06 framing that opened the leg):
|
|
678
|
-
- Weights win on one axis: the rotation FOLDS into adjacent matrices offline
|
|
679
|
-
(R into one layer, Rᵀ into the next) — no online transform at all.
|
|
680
|
-
- Weights lose on the other: they are static, so calibration-aware methods
|
|
681
|
-
(GPTQ/AWQ/imatrix, optiq sensitivity maps) are admissible and set a higher
|
|
682
|
-
baseline than any calibration-free scheme — the win to chase is rotation
|
|
683
|
-
COMPOSED WITH calibration/allocation, not instead of it.
|
|
684
|
-
- A Lloyd-Max weight FORMAT needs custom quantized-matmul kernels — the 26B
|
|
685
|
-
gather-qmv shelving (dispatch fixed-cost ate the prize) is the precedent.
|
|
686
|
-
Folding into mlx's existing affine format needs none.
|
|
687
|
-
- Activation quant (W4A4) is mispriced on this hardware (no int4 tensor
|
|
688
|
-
cores, decode is weight-bandwidth-bound; docs/design/orpo-training.md).
|
|
689
|
-
|
|
690
|
-
## Oracle chain
|
|
691
|
-
|
|
692
|
-
Folding mechanics come from the reference repos (read 2026-08-17, full-file
|
|
693
|
-
agent reads):
|
|
694
|
-
|
|
695
|
-
- **QuaRot** (arXiv:2404.00456, github spcl/QuaRot):
|
|
696
|
-
`fake_quant/rotation_utils.py` (fuse_ln_linear, fuse_layer_norms,
|
|
697
|
-
rotate_model), `fake_quant/hadamard_utils.py` (get_hadK, matmul_hadU,
|
|
698
|
-
random_hadamard_matrix), `fake_quant/model_utils.py`.
|
|
699
|
-
- **SpinQuant** (arXiv:2405.16406, github facebookresearch/SpinQuant):
|
|
700
|
-
`utils/fuse_norm_utils.py` (a copy of QuaRot's γ-fold),
|
|
701
|
-
`eval_utils/rotation_utils.py` (R1/R2 folds), `optimize_rotation.py`
|
|
702
|
-
(Cayley-SGD learned R — deferred to W5-learned).
|
|
703
|
-
- **GPTQ**: `mlx_lm/quant/gptq.py` in the pinned venv (forked minimally in
|
|
704
|
-
`scripts/turboquant/tq-gptq.py`; see the two upstream defects below).
|
|
705
|
-
- **Sensitivity**: `mlx_lm.quant.dynamic_quant` (gradient KL) + OptiQ's
|
|
706
|
-
published `optiq/sensitivity.json` for this exact 27B (`sensitivities[b]`
|
|
707
|
-
= measured KL GAIN at b bits — the first read had the sign flipped).
|
|
708
|
-
|
|
709
|
-
Weight layout: torch and MLX `nn.Linear` are both `[out, in]`, `y = x @ W.T`
|
|
710
|
-
— their fold table transfers verbatim.
|
|
711
|
-
|
|
712
|
-
## The recipe (weight-only, fully offline)
|
|
713
|
-
|
|
714
|
-
Order matters: γ-fold FIRST (R1 commutes only with gain-free RMSNorm), then
|
|
715
|
-
R1, then R2, then quantize.
|
|
716
|
-
|
|
717
|
-
**0. Untie embeddings** if `tie_word_embeddings` (clone into a separate
|
|
718
|
-
lm_head, set the flag false). Required: step 1 transforms lm_head but not
|
|
719
|
-
embed_tokens (SpinQuant `ptq.py` does exactly this).
|
|
720
|
-
|
|
721
|
-
**1. γ-fold (norm fusion)** — for each RMSNorm feeding linears,
|
|
722
|
-
`W' = W · diag(γ)` on the INPUT dim, then set that norm's γ to ones (keep the
|
|
723
|
-
module + its eps — do NOT copy QuaRot's replacement RMSN, which hardcodes
|
|
724
|
-
eps=1e-5; our subjects use 1e-6):
|
|
725
|
-
- input_layernorm → q/k/v_proj
|
|
726
|
-
- post_attention_layernorm → gate/up_proj
|
|
727
|
-
- final norm → lm_head
|
|
728
|
-
|
|
729
|
-
**2. R1 residual fold** — one hidden-size orthogonal R1:
|
|
730
|
-
|
|
731
|
-
| matrix | transform | reason |
|
|
732
|
-
|---|---|---|
|
|
733
|
-
| embed_tokens | `W @ R1` | writes residual (rows are embeddings) |
|
|
734
|
-
| q/k/v_proj | `W @ R1` | reads residual (input dim) |
|
|
735
|
-
| o_proj (+bias) | `R1ᵀ @ W` | writes residual (output dim) |
|
|
736
|
-
| gate/up_proj | `W @ R1` | reads residual |
|
|
737
|
-
| down_proj (+bias) | `R1ᵀ @ W` | writes residual |
|
|
738
|
-
| lm_head | `W @ R1` | reads residual |
|
|
739
|
-
|
|
740
|
-
Q/K outputs untouched → RoPE unaffected. Input-side folds never touch biases
|
|
741
|
-
(bias lives on the output).
|
|
742
|
-
|
|
743
|
-
**3. R2 per-head v/o fold — SpinQuant's version, NOT QuaRot's.** Per layer,
|
|
744
|
-
one head_dim-sized orthogonal R2 applied block-diagonally: v_proj output
|
|
745
|
-
blocks get R2ᵀ, o_proj input blocks get R2; softmax weights are R2-invariant
|
|
746
|
-
so it cancels exactly, incl. under GQA (same R2 for all heads; repeat_kv
|
|
747
|
-
replicates whole heads). QuaRot's variant folds a FULL Hadamard into o_proj
|
|
748
|
-
and needs an ONLINE cross-head Hadamard (`online_partial_had`) to cancel —
|
|
749
|
-
folding its v-side alone breaks the network. Skip QuaRot's pairing entirely.
|
|
750
|
-
|
|
751
|
-
**4. Quantize** the folded weights with the stock convert path (affine g64 /
|
|
752
|
-
mxfp4 / nvfp4 arms; only affine has been measured — see W3).
|
|
753
|
-
|
|
754
|
-
### Deviations from the references (decided, with reasons)
|
|
755
|
-
|
|
756
|
-
These are the strings persisted per artifact in `optiq_metadata.json`
|
|
757
|
-
`weight_transforms[].deviations` (`src/quantize/rotate.ts`).
|
|
758
|
-
|
|
759
|
-
- **No embedding mean-centering.** Their `fuse_layer_norms` mean-centers
|
|
760
|
-
embedding rows (SliceGPT LayerNorm→RMSNorm trick). For RMSNorm models this
|
|
761
|
-
is NOT an exact invariance — they do it anyway; we don't, because W0's exit
|
|
762
|
-
criterion is logit parity of the folded bf16 model.
|
|
763
|
-
- **Delete the hidden R4 half-fold.** BOTH repos' `rotate_mlp_output`
|
|
764
|
-
unconditionally applies a full Hadamard to down_proj's input dim right
|
|
765
|
-
after the R1ᵀ fold — the offline HALF of R4, which requires the runtime
|
|
766
|
-
`online_full_had` on down_proj's activation (QuaRot rotation_utils.py:173 /
|
|
767
|
-
SpinQuant eval_utils/rotation_utils.py 98-100). Weight-only must skip both
|
|
768
|
-
halves. The `R1ᵀ @ W_down` part stays.
|
|
769
|
-
- **No R3.** Post-RoPE Q/K rotation exists only for KV-cache quant (their
|
|
770
|
-
code registers it only when k_bits < 16). Our KV story is Part A — online
|
|
771
|
-
rotation remains KV-only.
|
|
772
|
-
- **γ kept in the module as ones (eps preserved).**
|
|
773
|
-
- **Fold precision: fp32, not fp64.** References fold in fp64 (fp16-era
|
|
774
|
-
caution). Our weights are bf16 (8-bit mantissa); fp32 accumulation at
|
|
775
|
-
n≲6k leaves ample headroom. Escape hatch if a parity gate fails: fold
|
|
776
|
-
goldens in the oracle venv (mlx CPU float64).
|
|
777
|
-
|
|
778
|
-
### R generation
|
|
779
|
-
|
|
780
|
-
- Random-Hadamard R1 = `diag(±1 signs) · H_n / √n` (QuIP#-style). Signs are
|
|
781
|
-
a seed-pinned splitmix32 stream (`signVector(seed, n, lane)`; R1 = lane 0,
|
|
782
|
-
layer i's R2 = lane i+1) so the same (seed, n, lane) yields the same signs
|
|
783
|
-
on every machine. R is never needed at runtime; provenance (transform id,
|
|
784
|
-
family, seed, deviations) is written to `optiq_metadata.json`.
|
|
785
|
-
- Supported n: the Llama adapter asserts power-of-two hidden and head dims;
|
|
786
|
-
the Qwen adapter accepts `n = m·2^k, m ∈ {1,12,20,28}` — what mlx's
|
|
787
|
-
`hadamard_transform` takes natively (verified live at 5120 = 20·256). The
|
|
788
|
-
references' Kronecker table for other K values is NOT implemented; callers
|
|
789
|
-
get a clear throw. (QR-of-Gaussian "random" mode from the references is
|
|
790
|
-
likewise not implemented.)
|
|
791
|
-
- R2 default: plain signed Hadamard of head_dim (must be pow-2).
|
|
792
|
-
- Learned R (SpinQuant Cayley-SGD R1 + per-layer R2) stays deferred until a
|
|
793
|
-
random-R recipe wins on task evals; it folds identically afterward.
|
|
794
|
-
|
|
795
|
-
## Implementation seam (verified 2026-08-23)
|
|
796
|
-
|
|
797
|
-
`src/quantize/weight-transform.ts` separates pure tensor-name planning from
|
|
798
|
-
lazy tensor application:
|
|
799
|
-
- `WeightTransform { id, plan(names, config), createContext(weights, plan) }`;
|
|
800
|
-
`plan()` is name/config analysis only (no arrays, no device work);
|
|
801
|
-
`WeightTransformContext.apply(outputName, source)` returns a lazy owned
|
|
802
|
-
array and never disposes `source`.
|
|
803
|
-
- `WeightTransformPlan.sourceByOutput` makes untie/clone explicit (a
|
|
804
|
-
synthesized `lm_head.weight` maps to `model.embed_tokens.weight`).
|
|
805
|
-
- Adapters: `llamaWeightTransform` (`rotation.llama`), `qwen35WeightTransform`
|
|
806
|
-
(`rotation.qwen3_5`), `qwenMtpWeightTransform` (`rotation.qwen3_5_mtp`), and
|
|
807
|
-
`automaticRotationWeightTransform` (`rotation.auto`) which selects by
|
|
808
|
-
schema: MTP if `fc.weight` + `pre_fc_norm_hidden.weight` are present, else
|
|
809
|
-
by `model_type` ∈ {qwen3_5, llama}, else throws.
|
|
810
|
-
- Fold math lives in `src/quantize/rotate.ts` (`foldLlamaWeights`,
|
|
811
|
-
`planQwen35Fold`, `planQwenMtpFold`, `QwenFoldContext`; f32 chains → bf16;
|
|
812
|
-
every returned array is a lazy graph over the source mmap so the writer
|
|
813
|
-
materializes one tensor at a time).
|
|
814
|
-
- `src/quantize/quantizer.ts` `quantizeModelDir` applies the plan in its
|
|
815
|
-
existing module walk; refuses a transform when the source is already
|
|
816
|
-
quantized ("requires full-precision source weights"); writes
|
|
817
|
-
`weight_transforms` into both the uniform and the mixed-precision
|
|
818
|
-
`optiq_metadata.json`. Mixed-precision calibration receives a
|
|
819
|
-
`ProbeSource`; the default builds an 8-bit probe through the lower-level
|
|
820
|
-
writer instead of recursively re-entering the top-level quantizer.
|
|
821
|
-
- CLI: `mlx-bun convert --rotate-weights [--rotation-seed N]` (default seed
|
|
822
|
-
42; cli.md documents it). An MTP companion must be folded with the same
|
|
823
|
-
seed as its trunk.
|
|
824
|
-
- Tests: `tests/weight-transform-plan.test.ts`,
|
|
825
|
-
`tests/weight-transform-numerics.test.ts`.
|
|
826
|
-
|
|
827
|
-
Src-vs-doc note: the production Llama adapter currently REQUIRES tied
|
|
828
|
-
embeddings (`planLlamaWeightTransform` throws if `lm_head.weight` exists) —
|
|
829
|
-
the "untie if tied" recipe step is exercised only in that direction; an
|
|
830
|
-
untied Llama source is not yet accepted. The Qwen adapter handles both.
|
|
831
|
-
|
|
832
|
-
## W1 — Qwen3.8 (qwen3_5) corridor map (2026-08-18, from `src/model/qwen3_5.ts` + `src/spec/qwen-mtp-source.ts` + `src/vision/qwen3vl-tower.ts` + tensor dumps)
|
|
833
|
-
|
|
834
|
-
**R2 is architecturally OFF for this family:** full attention computes
|
|
835
|
-
`o_proj(attention_output · σ(gate))` — q_proj emits 2×head_dim per head and
|
|
836
|
-
the gate multiplies the attention output ELEMENTWISE in head space. An
|
|
837
|
-
elementwise gate does not commute with a per-head rotation, so only γ+R1
|
|
838
|
-
apply. hidden 5120 = 20·256 — mlx's hadamard_transform takes it natively.
|
|
839
|
-
|
|
840
|
-
Trunk corridors (prefix `language_model.`):
|
|
841
|
-
- readers (@R1 input dim, γ folded in): self_attn.q/k/v_proj,
|
|
842
|
-
linear_attn.in_proj_{qkv,z,b,a}, mlp.gate/up_proj, lm_head (γ = model.norm)
|
|
843
|
-
- writers (R1ᵀ output dim): self_attn.o_proj, linear_attn.out_proj,
|
|
844
|
-
mlp.down_proj
|
|
845
|
-
- vision: `vision_tower.merger.linear_fc2` weight+bias is the ONLY
|
|
846
|
-
vision→residual seam (deepstack is empty for qwen3_5 and not ported) —
|
|
847
|
-
output-dim fold; everything else in the tower passes through bf16
|
|
848
|
-
- untouched internal bases: q_norm/k_norm (head-space), linear_attn.{norm,
|
|
849
|
-
A_log, conv1d, dt_bias} (post-projection), rotary
|
|
850
|
-
- 27B trunk is untied; the 0.8B proof subject is tied (untie step exercised)
|
|
851
|
-
|
|
852
|
-
MTP companion (separate artifact, same seed/R1 — shared residual basis):
|
|
853
|
-
- `fc [H,2H]`: input block 0 = embedding stream (γ = pre_fc_norm_embedding),
|
|
854
|
-
block 1 = hidden stream (γ = pre_fc_norm_hidden) — per-block γ+@R1 — plus
|
|
855
|
-
an output-dim R1ᵀ fold; both pre-fc norms → ones
|
|
856
|
-
- `layers.0`: standard full-attention corridor treatment
|
|
857
|
-
- **final `norm` γ is DROPPED (→ ones):** it feeds the SHARED trunk lm_head,
|
|
858
|
-
which already carries the trunk's final γ. Draft logits see γ_trunk instead
|
|
859
|
-
of γ_mtp — draft-quality-only (the verified target path is exact); revisit
|
|
860
|
-
lever = ship a private folded head inside the companion. Persisted as the
|
|
861
|
-
`mtp-final-gamma-dropped` deviation.
|
|
862
|
-
|
|
863
|
-
Small-scale proof (0.8B, dequantized from OptiQ-4bit since no bf16 is
|
|
864
|
-
published; fold-parity on dequant-vs-folded-dequant tests the fold exactly):
|
|
865
|
-
teacher-forced logits through STOCK mlx-lm (also the W2 cross-stack check) —
|
|
866
|
-
worst per-position KL 0.00353, argmax flips 2/42 positions BOTH at reference
|
|
867
|
-
margin 0.0 (exact ties). Scripts: `scripts/turboquant/dequant-model.ts`,
|
|
868
|
-
`scripts/turboquant/fold-qwen35.ts`, `scripts/turboquant/tq-fold-parity.py`.
|
|
869
|
-
|
|
870
|
-
Quantization packaging (corrected 2026-08-18: OptiQ does NOT fully strip
|
|
871
|
-
vision — its main weights omit it but `optiq/optiq_vision.safetensors`
|
|
872
|
-
carries it, and `optiq/mtp.safetensors` bundles MTP; their artifact also
|
|
873
|
-
publishes `optiq/sensitivity.json`. No kv_config.json is published.) Our
|
|
874
|
-
packaging: language modules quantize uniformly (embed + lm_head included),
|
|
875
|
-
`vision_tower.*` is predicate-excluded and stays bf16 both IN-MAIN (mlx-vlm
|
|
876
|
-
compatible — OptiQ's sidecar-only vision is not) and as the `optiq/` sidecar
|
|
877
|
-
(`scripts/turboquant/tq-make-vision-sidecar.ts`), so one self-contained
|
|
878
|
-
artifact serves text+vision across stacks; the folded MTP companion ships at
|
|
879
|
-
`<model>/mtp/` (engine: `--draft-kind mtp` with no `--draft-model` resolves
|
|
880
|
-
it).
|
|
881
|
-
|
|
882
|
-
## Subject models
|
|
883
|
-
|
|
884
|
-
- **W0/W3: mlx-community/Llama-3.2-1B-Instruct-bf16** (~2.5 GB; the
|
|
885
|
-
reference repos' literal target family; TIED embeddings → exercises step
|
|
886
|
-
0; hidden 2048 / head_dim 64, both pow-2). MiniCPM5-1B is the alternate
|
|
887
|
-
subject (no published mlx bf16; geometry fold-friendly: untied, head_dim
|
|
888
|
-
128, hidden 1536 = had12 ⊗ H128, eps 1e-6).
|
|
889
|
-
- **W4: mlx-community/Qwen3.8-27B-bf16** (11 shards, 54.7 GB) +
|
|
890
|
-
`Qwen3.8-27B-MTP-bf16` companion (~850 MB). The companion shares the
|
|
891
|
-
trunk's residual basis → must fold consistently (W1 decision). 27B bf16
|
|
892
|
-
never fully loads on either laptop: folding bit-identity is proven at W0
|
|
893
|
-
scale plus per-tensor checks; the 27B only ever RUNS folded-and-quantized.
|
|
894
|
-
Streaming fold/quantize (`ShardedWriter` + `Weights.releaseShard`; fold
|
|
895
|
-
peak 17.9 GB after the naive whole-list path OOM'd a 51 GB model).
|
|
896
|
-
|
|
897
|
-
## W0 fold proof (2026-08-17, Llama-3.2-1B, M1 Max 32 GB, busy box — correctness only)
|
|
898
|
-
|
|
899
|
-
Folded model loads + generates through the UNMODIFIED engine
|
|
900
|
-
(UniversalDenseModel path); teacher-forced two-model KL (16×256 tok) mean
|
|
901
|
-
0.00131 / median 0.00119 / p95 0.00287 — below the KV curve's
|
|
902
|
-
quality-neutral kv8 yardstick (0.00246); greedy 64-token trajectories 3/6
|
|
903
|
-
token-identical, 3 diverge only at near-ties (margins 0.0/0.125/0.125);
|
|
904
|
-
folded weights fully re-expressed (mean|Δ|≈mean|w|), per-tensor max|w| down
|
|
905
|
-
3–5× (q_proj 0.676→0.162, down_proj 0.578→0.110, gate 0.965→0.367), down_proj
|
|
906
|
-
excess kurtosis 1.19→0.22. Runner: `scripts/turboquant/w0-fold-llama.ts`
|
|
907
|
-
(`--skip-r1/--skip-r2` bisection arms + `turboquant_fold.json` sidecar).
|
|
908
|
-
|
|
909
|
-
## W3/W4 measured curve (2026-08-18, RTN affine g64, ppl via stock mlx-lm on the local UF-derived corpus, seq 512; M1 Max 32 GB)
|
|
910
|
-
|
|
911
|
-
**Headline: rotation-only + RTN does NOT beat plain RTN at the 4-bit
|
|
912
|
-
operating point; it wins decisively at 3-bit — the paper's law, reproduced.**
|
|
913
|
-
Per-module function-space Frobenius error is a wash at 4-bit (~0.091 all
|
|
914
|
-
arms, `scripts/turboquant/tq-quant-error.py` — γs are tame, 0.7–2.7, no
|
|
915
|
-
module class is the culprit); the 4-bit regression is the anisotropy story
|
|
916
|
-
(isotropic rotated error vs activation-aligned plain error), which is what
|
|
917
|
-
GPTQ-style calibration fixes — the composition named as the real win.
|
|
918
|
-
|
|
919
|
-
0.8B lab (dequant-OptiQ source; PAIRED arms; bf16 anchor 6.41, 48×512):
|
|
920
|
-
|
|
921
|
-
| arm | bpw | ppl |
|
|
922
|
-
|---|---|---|
|
|
923
|
-
| plain 4-bit | 4.50 | 7.01 |
|
|
924
|
-
| TQ(R1+γ) 4-bit | 4.50 | 7.39 ← regression, reproduces 27B |
|
|
925
|
-
| plain 3-bit | 3.50 | 19.19 ← RTN collapse |
|
|
926
|
-
| **TQ 3-bit** | 3.50 | **14.54** ← rotation −24% ppl |
|
|
927
|
-
| plain mixed (3-bit MLP, 4-bit attn/embed) | 4.15 | 9.69 |
|
|
928
|
-
| **TQ mixed (same profile)** | 4.24 | **9.22** ← paired rotation win |
|
|
929
|
-
|
|
930
|
-
27B (32×512, same corpus): plain 4-bit 4.659 ±0.093 (4.50 bpw, 15.0 GB) ·
|
|
931
|
-
TQ 4-bit 4.923 ±0.102 (+5.7%, consistent with the lab) · **TQ-mixed (4-bit
|
|
932
|
-
attn/embed + 3-bit MLP) 4.932 ±0.098 at 3.86 bpw / 13.9 GB** — matches
|
|
933
|
-
rotated-uniform-4-bit quality at −0.64 bpw; the artifact of record for the
|
|
934
|
-
14z M4-Pro fit lever.
|
|
935
|
-
|
|
936
|
-
AWQ-style equalization spike (norm-carried per-channel scales, α=0.5,
|
|
937
|
-
function-preservation verified at KL 0.0037/0 flips): TQ+eq 7.363 (≈no
|
|
938
|
-
change), plain+eq 7.809 (HURT — per-channel scales inside a g64 group widen
|
|
939
|
-
group ranges; real AWQ grid-searches a far gentler α and the real 4-bit fix
|
|
940
|
-
is GPTQ-style compensated rounding). Scripts kept:
|
|
941
|
-
`scripts/turboquant/tq-collect-actstats.py` + `tq-equalize.ts`.
|
|
942
|
-
|
|
943
|
-
**End-to-end validation of the TQ-mixed 27B artifact (2026-08-18, M1 Max,
|
|
944
|
-
busy box — correctness only):** server chat with correct arithmetic
|
|
945
|
-
reasoning (thinking → `reasoning` field); vision through the folded merger +
|
|
946
|
-
sidecar correctly identifies the gradient fixture's colors over HTTP; MTP
|
|
947
|
-
via the 14g harness with the same-seed folded companion: 71% acceptance,
|
|
948
|
-
2.40 tok/target-forward, arms token-identical (losslessness), ON/OFF 0.726×
|
|
949
|
-
(consistent with the stock 0.821× correct-but-slower verdict; MTP stays
|
|
950
|
-
opt-in).
|
|
951
|
-
|
|
952
|
-
Consequence for the release recipe: do NOT ship rotated uniform-4-bit (loses
|
|
953
|
-
to the trivial baseline); rotation's band is the ≤4-bpw mixed recipe where
|
|
954
|
-
it is decisively ahead. The 4.5-bpw flagship win waits for the calibration
|
|
955
|
-
composition (W5).
|
|
956
|
-
|
|
957
|
-
## W5a corrected-GPTQ matrix (2026-08-18; 0.8B lab, 4.5 bpw arms, 48×512 ppl, anchor = dequant-OptiQ 6.41 — verified lossless: original OptiQ scores 6.4077)
|
|
958
|
-
|
|
959
|
-
mlx-lm's shipped GPTQ (`mlx_lm/quant/gptq.py`) has TWO real defects that
|
|
960
|
-
partially cancel: the in-loop update window is `k:k+j` (over-propagates past
|
|
961
|
-
the block edge; must be `k:j` — the k term itself writes the quantized value
|
|
962
|
-
since e·Hinv[k,k] = w−q) and `err[..., k:k+1]` indexes a group-local buffer
|
|
963
|
-
with the GLOBAL k (mlx out-of-range slice assignment silently no-ops →
|
|
964
|
-
cross-group propagation lost after block 0). Fixing only err
|
|
965
|
-
DOUBLE-compensates [j, k+j) and REGRESSES below RTN (measured: 7.22/7.50);
|
|
966
|
-
fixing both = paper GPTQ. [mlx-lm #1878](https://github.com/ml-explore/mlx-lm/issues/1878) contains the CPU-only reproduction, observed results against mlx-lm 0.31.3 and upstream `e5962529`, and proposed two-line correction; [mlx-lm PR #1880](https://github.com/ml-explore/mlx-lm/pull/1880) carries the fix plus `tests/test_gptq.py` (column-by-column reference, four groups fail on `main`, single-group control passes on both). Fork:
|
|
967
|
-
`scripts/turboquant/tq-gptq.py` (also restricts GPTQ+fallback to language
|
|
968
|
-
modules — vision H is a zero scalar and stays bf16).
|
|
969
|
-
|
|
970
|
-
| arm | ppl |
|
|
971
|
-
|---|---|
|
|
972
|
-
| **plain + GPTQ (fixed)** | **6.741** |
|
|
973
|
-
| TQ(R1) + GPTQ (fixed) | 6.847 |
|
|
974
|
-
| plain RTN | 7.010 |
|
|
975
|
-
| TQ RTN | 7.390 |
|
|
976
|
-
|
|
977
|
-
**Verdict: calibration is the main course; rotation SUBTRACTS at the 4-bit
|
|
978
|
-
band even under GPTQ on this family** (gap −1.6%; GPTQ closes half the
|
|
979
|
-
RTN→anchor gap). Rotation remains the sub-4-bpw lever (−24% at 3-bit). 27B
|
|
980
|
-
needs a chunked Hessian/GPTQ driver (stock flow = whole bf16 model + all
|
|
981
|
-
Hessians resident; down_proj H = 1.2 GB f32 each) —
|
|
982
|
-
`scripts/turboquant/tq-gptq-27b.py` (per-layer checkpoints, resumable, peak
|
|
983
|
-
≈ one bf16 layer + one Hessian + activations ≈ 6 GB).
|
|
984
|
-
|
|
985
|
-
## W5c 27B production results (2026-08-18)
|
|
986
|
-
|
|
987
|
-
**v2 run (uniform GPTQ-4): BROKEN artifact (ppl 306k).** Root cause,
|
|
988
|
-
evidence-backed: the compensation loop DIVERGED on layers with
|
|
989
|
-
rank-deficient calibration Hessians (layer-0 down_proj group scales grew
|
|
990
|
-
0.003 → 27 monotonically across columns, max 2.8e7; cosine ~0 vs source;
|
|
991
|
-
neighbors healthy). Early layers see low-rank activations (layer-0 input =
|
|
992
|
-
raw embeddings; rank ≤ distinct calibration tokens), so 5120 dims outran
|
|
993
|
-
the standard 1% damping — the 0.8B (1024 dims) never hit it.
|
|
994
|
-
|
|
995
|
-
**v3 fixes (all landed in the 27B driver):** divergence guard in
|
|
996
|
-
`gptq_one_guarded` (GPTQ scales vs 4× the RTN scale ceiling per matrix;
|
|
997
|
-
damping escalation 1e-2→10; RTN fallback = never worse than RTN); 4×
|
|
998
|
-
calibration (128×512); sensitivity-driven per-module bits from OptiQ's
|
|
999
|
-
published sensitivity.json; greedy benefit-per-param to `--target-bpw`.
|
|
1000
|
-
v3 27B: 169 modules @8-bit, 4.80 bpw, 17.0 GB, ZERO guard triggers (the
|
|
1001
|
-
calibration bump fixed conditioning outright), 64 layers in 166 min.
|
|
1002
|
-
|
|
1003
|
-
**27B ppl ladder (73×512, UF corpus, stock mlx-lm):** plain RTN-4 4.570
|
|
1004
|
-
±0.060 · OptiQ 5.14 bpw 4.574 ±0.061 · GPTQ+sens 4.80 bpw 4.618 ±0.061.
|
|
1005
|
-
**At 27B every sane ≥4.5-bpw recipe SATURATES this instrument** — OptiQ's
|
|
1006
|
-
+0.6 bpw buys nothing measurable, and GPTQ shows a small consistent deficit
|
|
1007
|
-
(likely calibration-domain mismatch: calibration_v5 vs chat-flavored eval
|
|
1008
|
-
text). This contradicts the 0.8B lab ordering (GPTQ clearly won there) —
|
|
1009
|
-
quantization robustness grows with scale. Decision moved to task
|
|
1010
|
-
benchmarks: MMLU-100 + GSM8K-50 across the arms (`scripts/turboquant/
|
|
1011
|
-
tq-evals.py`, paired items through stock mlx-lm).
|
|
1012
|
-
|
|
1013
|
-
## FINAL BOARD + DECISION (2026-08-18 night 2)
|
|
1014
|
-
|
|
1015
|
-
Task evals (lean mlx-lm runner, paired items; in-engine sweep swap-thrashed
|
|
1016
|
-
the box — 73 GB swap at 0.7 GB resident — killed, gap recorded below):
|
|
1017
|
-
|
|
1018
|
-
| arm | bpw | GB | ppl(73×512) | MMLU-100 | GSM8K-50 |
|
|
1019
|
-
|---|---|---|---|---|---|
|
|
1020
|
-
| **GPTQ+sens v3 (SHIPPED as mjriii/Qwen3.8-27B)** | 4.80 | 16.3 | 4.618 | 87 | **96** |
|
|
1021
|
-
| plain RTN 4-bit | 4.50 | 15.0 | **4.570** | 88 | 94 |
|
|
1022
|
-
| OptiQ published | 5.14 | 18.1 | 4.574 | **89** | 92 |
|
|
1023
|
-
| TQ-mixed (staged, small-footprint variant) | 3.86 | 13.0 | 4.93 | 82 | 96 |
|
|
1024
|
-
|
|
1025
|
-
All ≥4.5-bpw arms statistically tied on every instrument — 27B quality
|
|
1026
|
-
SATURATES at 4-bit; recipes differentiate below 4 bpw and on completeness.
|
|
1027
|
-
THE artifact = v3 (never trails; protective recipe; one-repo
|
|
1028
|
-
vision+video+MTP; additive to the ecosystem where plain-4bit already exists
|
|
1029
|
-
publicly). Serve gauntlet on THE artifact through OUR engine: text ✓
|
|
1030
|
-
(23×19), image ✓ ("Green and pink"), video ✓ (gradient motion described;
|
|
1031
|
-
AVFoundation chain), MTP harness 76% accept / 2.53 tok-per-forward with an
|
|
1032
|
-
output-divergence flag vs plain greedy (consistent with verify-width
|
|
1033
|
-
reduction-order near-ties, 12B step-0 class — margin analysis queued; NOT
|
|
1034
|
-
claimed lossless on the card).
|
|
1035
|
-
|
|
1036
|
-
## Territory-mapping campaign (2026-08-18/19, Josh-directed: "map all the levers before concluding TQ-off")
|
|
1037
|
-
|
|
1038
|
-
**sens3 arm (Josh's recipe: rotated 3-bit base + sensitivity-driven 8-bit,
|
|
1039
|
-
4.26 bpw / 15.25 GB incl. vision):** ppl 4.630 ±0.058 — TIED with the
|
|
1040
|
-
4.80-bpw flagship (4.618) at −0.54 bpw, and a full recovery over unprotected
|
|
1041
|
-
TQ-mixed (4.93). GSM8K 46/50 = 92% (plateau band). **MMLU 83/100 — the
|
|
1042
|
-
3-bit-base dip persists** (TQ-mixed scored 82): two independent 3-bit-base
|
|
1043
|
-
arms at 82–83 vs the 87–89 plateau → the knowledge-recall damage is SMEARED
|
|
1044
|
-
across the MLP long tail; KL-derived sensitivity shields fluency, not
|
|
1045
|
-
recall.
|
|
1046
|
-
|
|
1047
|
-
Perplexity proxy calibration (from our own table): deltas <~0.1 ppl are
|
|
1048
|
-
task-invisible; ppl's remaining role is catastrophe detection + screening
|
|
1049
|
-
(see the g128 lesson below, which retired the "~0.3 ppl = visible damage"
|
|
1050
|
-
rule). mlx kernel bound: group_size ∈ {32, 64, 128} — 256+ needs custom
|
|
1051
|
-
kernels (non-goal).
|
|
1052
|
-
|
|
1053
|
-
**Group-size lab (0.8B ppl) + 27B g128 arm:** rotation does NOT buy
|
|
1054
|
-
coarse-group tolerance at 4-bit (tax +4.7% rotated vs +4.2% plain); at 3-bit
|
|
1055
|
-
the dividend is real but partial (+29% vs +47%; rotated 3.25 bpw ≈ plain 3.5
|
|
1056
|
-
bpw). 27B plain-4bit-g128 (4.25 bpw): ppl 4.714 (+3%), MMLU 88 (plateau!),
|
|
1057
|
-
**GSM8K 62% — COLLAPSE via generation-behavior damage** (correct-but-rambling
|
|
1058
|
-
truncations + instant-EOS empty outputs; single-forward instruments blind to
|
|
1059
|
-
it). Lessons: (1) ppl deltas DO NOT bound task damage (+0.14 ppl ↔ −32 GSM8K
|
|
1060
|
-
pts) — every finalist needs generative tasks; (2) g128 disqualified for
|
|
1061
|
-
generative work.
|
|
1062
|
-
|
|
1063
|
-
**Run B — the full suite (rotation + GPTQ + sensitivity, 4.80 bpw, 17.0 GB,
|
|
1064
|
-
zero guard triggers):** ppl **4.5965** (best quantized arm, tied w/
|
|
1065
|
-
plain-4bit) · MMLU 84 · raw-completion GSM8K **24% — and the collapse is a
|
|
1066
|
-
FORMAT CLIFF, not a reasoning failure**: when it answers it is flawless, but
|
|
1067
|
-
3/4 raw few-shot prompts get INSTANT EOS; under the native chat template it
|
|
1068
|
-
always answers (3/5 correct at a tight token cap). g128's 62% was the same
|
|
1069
|
-
failure at lower frequency. **Methodology consequence: the raw-completion
|
|
1070
|
-
GSM8K column conflates math ability with EOS-cliff robustness** — different
|
|
1071
|
-
quant-noise realizations displace a razor-thin answer-vs-stop margin at
|
|
1072
|
-
token 0. The map carries TWO generative columns: templated GSM8K
|
|
1073
|
-
(serving-path reasoning) and raw-completion GSM8K (format-robustness probe).
|
|
1074
|
-
Neither ppl nor MMLU sees any of this.
|
|
1075
|
-
|
|
1076
|
-
## THE FRONTIER (campaign complete, 2026-08-19; chart artifact `reports/frontier-map-2026-08-19.html` is machine-local — `reports/` is gitignored)
|
|
1077
|
-
|
|
1078
|
-
| arm | bpw | GB | ppl | MMLU | tGSM | rawGSM | tok/s* | Pareto |
|
|
1079
|
-
|---|---|---|---|---|---|---|---|---|
|
|
1080
|
-
| **rot+sens48 RTN (Josh's recipe)** | 4.79 | 17.0 | 4.680 | **90** | 94 | 84 | **11.80** | **YES** |
|
|
1081
|
-
| GPTQ+sens (staged flagship) | 4.80 | 17.0 | 4.618 | 87 | 94 | **96** | 11.42 | — |
|
|
1082
|
-
| rot+GPTQ+sens (full suite) | 4.80 | 17.0 | **4.597** | 84 | 94 | 24 | 11.77 | — |
|
|
1083
|
-
| OptiQ published | 5.14 | 18.1 | 4.574 | 89 | 94 | 92 | 8.92 | — (dominated) |
|
|
1084
|
-
| **TQ-mixed** | 3.86 | 13.0 | 4.932 | 82 | 82 | 96 | 10.94 | **YES** |
|
|
1085
|
-
| bf16 ceiling (streamed eval, `tq-bf16-ceiling.py`) | 16 | 54.4 | 4.552 | 87 | n/a | n/a | n/a | ref |
|
|
1086
|
-
|
|
1087
|
-
*M1 Max 32 GB, busy box, spreads 8–34% — directional until a quiet
|
|
1088
|
-
`scripts/bench-serve.ts all` run (probes: `scripts/turboquant/tq-tps.ts`).
|
|
1089
|
-
|
|
1090
|
-
Findings of record: (1) the ≥4.5-bpw band sits AT the bf16 ceiling (ppl
|
|
1091
|
-
within ~1%, MMLU within noise — a quant scoring 90 vs ceiling 87 proves ±3
|
|
1092
|
-
noise); (2) BOTH Pareto points are ROTATED — rotation at 4-bit is
|
|
1093
|
-
competitive exactly when paired with sensitivity allocation (the earlier
|
|
1094
|
-
uniform-rotation loss concentrated in the sensitive modules, as Josh
|
|
1095
|
-
hypothesized), and mandatory below 4 bpw; (3) OptiQ is dominated on all
|
|
1096
|
-
three axes (its extra 0.34 bpw buys nothing and costs ~25% decode); (4)
|
|
1097
|
-
GPTQ's measurable 27B contribution is ppl-only — it buys no task quality at
|
|
1098
|
-
this scale and (with rotation) costs raw-format robustness; (5) 3-bit
|
|
1099
|
-
kernels pay an unpack tax that eats their bandwidth win on M1 (see the M4
|
|
1100
|
-
row for the reversal); (6) cross-engine parity CERTIFIED (byte-identical
|
|
1101
|
-
greedy, ours vs stock mlx-lm, on the staged flagship). Certification
|
|
1102
|
-
benchmark for the chosen artifact: GPQA Diamond at reasoning_effort=xhigh
|
|
1103
|
-
(`scripts/turboquant/tq-gpqa.py`, local mlx-lm or `--server-url` through a
|
|
1104
|
-
running `mlx-bun serve`; greedy runs bit-identical across the two paths).
|
|
1105
|
-
|
|
1106
|
-
## M4 Pro 24 GB speed rows (2026-08-20, mlx-bun, `scripts/turboquant/tq-speed-row.ts`)
|
|
1107
|
-
|
|
1108
|
-
Winner artifact (rot+sens48), second reference machine (M4 Pro, 24 GB,
|
|
1109
|
-
~273 GB/s), `sysctl iogpu.wired_limit_mb=21504`, DeltaNet leak fix applied:
|
|
1110
|
-
|
|
1111
|
-
| prompt | prefill tok/s | TTFT | decode tok/s | notes |
|
|
1112
|
-
|---|---|---|---|---|
|
|
1113
|
-
| 1,024 | 127 | 8.1 s | 14.66 (1.1%) | chunk 2048 |
|
|
1114
|
-
| 8,192 | 124 | 66 s | 14.13 (1.3%) | chunk 2048 |
|
|
1115
|
-
| 32,768 | 114 | 288 s | 12.77 | chunk 1024 (peak 19.3 GB) |
|
|
1116
|
-
|
|
1117
|
-
- **Compute-bound decode confirmed cross-machine:** 14.7 tok/s here vs 11.8
|
|
1118
|
-
on the M1 Max (400 GB/s) — the machine with 68% of the bandwidth is 25%
|
|
1119
|
-
FASTER. Decode is dequant-ALU-bound, not weight-streaming-bound (M1
|
|
1120
|
-
telemetry: GPU 100% @ ~266 GB/s of 400). Headroom to the ~24 tok/s
|
|
1121
|
-
bandwidth roofline is a future perf program.
|
|
1122
|
-
- **Decode-at-depth is nearly flat** (−13% at 32× context): only 16 of 64
|
|
1123
|
-
layers grow KV; DeltaNet state is constant.
|
|
1124
|
-
- **Prefill transient scales with chunk × offset** (~2.8 GB at 24k with
|
|
1125
|
-
2048-chunks; measured via `MLX_BUN_PREFILL_MEM_LOG` and
|
|
1126
|
-
`scripts/turboquant/tq-mem-probe.ts`): on 24 GB the 32k row needs
|
|
1127
|
-
1024-token chunks (−8% prefill). Engine follow-up: serve should scale
|
|
1128
|
-
prefillChunkSize from fit.ts headroom automatically.
|
|
1129
|
-
- Prefill absolute rate (~125 tok/s) is the weak axis — suspected DeltaNet
|
|
1130
|
-
per-token recurrence during prefill; compare against mlx-lm same-box
|
|
1131
|
-
before treating as our bug (oracle-gap rule).
|
|
1132
|
-
|
|
1133
|
-
Compact sibling (TQ-mixed) on the M4, same protocol, chunk 1024 all rows:
|
|
1134
|
-
|
|
1135
|
-
| prompt | prefill tok/s | TTFT | decode tok/s (spread) |
|
|
1136
|
-
|---|---|---|---|
|
|
1137
|
-
| 1,024 | 117 | 8.8 s | **17.14** (0.7%) |
|
|
1138
|
-
| 8,192 | 124 | 66 s | 16.05 (2.4%) |
|
|
1139
|
-
| 32,768 | 85 | 6.4 min | 13.80 (2.9%) |
|
|
1140
|
-
|
|
1141
|
-
**The 3-bit speed verdict is GPU-generation-dependent:** on M1 Max the
|
|
1142
|
-
3-bit-heavy artifact decoded SLOWER than the 4/8 winner (10.94 vs 11.80 —
|
|
1143
|
-
unpack ALU dominates); on M4 Pro it decodes FASTER (17.14 vs 14.66 — newer
|
|
1144
|
-
ALU absorbs the unpack, fewer bytes win). Card guidance: M1-class → winner
|
|
1145
|
-
fastest; M4-class → compact is smaller AND faster. Compact 32k prefill
|
|
1146
|
-
(85 tok/s) is its weak axis. Peak not instrumented this run; estimated
|
|
1147
|
-
~16 GB at 32k (likely fits the DEFAULT 24 GB wired limit — untested).
|
|
1148
|
-
|
|
1149
|
-
## Known engine gaps found in passing (not TQ defects)
|
|
1150
|
-
|
|
1151
|
-
- `mlx-bun perplexity` cannot score qwen3_5: it routes through
|
|
1152
|
-
`trainForward`, whose cache stub lacks the DeltaNet `SSMCache.advance`
|
|
1153
|
-
(`qwen3_5.ts:226` throws on plain and TQ arms identically). 27B ppl runs
|
|
1154
|
-
through stock mlx-lm (`scripts/turboquant/tq-ppl.py`) — which doubles as
|
|
1155
|
-
the cross-stack load check for the release artifact.
|
|
1156
|
-
- bf16 (unquantized) qwen3_5 trunks don't load in our engine:
|
|
1157
|
-
`QuantizedEmbedding.load`/`QuantizedLinear.load` hard-require `.scales`.
|
|
1158
|
-
The small-scale fold proof ran through stock mlx-lm instead. Backlog: not
|
|
1159
|
-
needed to serve the published quant.
|
|
1160
|
-
- `scripts/eval.ts` capability tasks at 27B swap-thrashed a 32 GB box — root
|
|
1161
|
-
cause fixed (chunked `forwardHidden` prefill + allocator clear cadence);
|
|
1162
|
-
verify at 27B post-GPQA.
|
|
1163
|
-
- Qwen MTP via the HTTP serve lane 500'd (`[slice] Invalid number of
|
|
1164
|
-
indices…`) — pre-existing serving-path bug, reproduced with stock
|
|
1165
|
-
artifacts; FIXED 2026-08-20 (draft gate + `[1,V]` sampler contract). The
|
|
1166
|
-
paired MTP harness is `scripts/turboquant/tq-mtp-ab.ts` (its header still
|
|
1167
|
-
cites its old name, `qwen38-mtp-ab.ts`).
|
|
1168
|
-
- DeltaNet prefill leak (~1 MB/token, `contiguous()` returning a no-op view
|
|
1169
|
-
that pinned whole chunk buffers) FOUND+FIXED 2026-08-20 via this program's
|
|
1170
|
-
dogfood gate; 27B now fits 24 GB (peak 19.2 GB at 16k probe).
|
|
1171
|
-
|
|
1172
|
-
## Weights-leg non-goals
|
|
1173
|
-
|
|
1174
|
-
The original W recipe's scope below does not limit the 2026-09 Qwen performance
|
|
1175
|
-
program. Custom formats, kernels, alternative algorithms and online-transform
|
|
1176
|
-
candidates are now in scope under the gates in
|
|
1177
|
-
[decode-speed-program.md](decode-speed-program.md#7-qwen38-27b-research-program).
|
|
1178
|
-
|
|
1179
|
-
Mirrors the PLAN.md phase: no custom Lloyd-Max weight format / new qmm
|
|
1180
|
-
kernels; no activation quantization; no runtime weight rotation of any kind
|
|
1181
|
-
(weights fold offline; online rotation remains the KV codec's job); no
|
|
1182
|
-
GGUF/AWQ export; group_size > 128.
|
|
1183
|
-
|
|
1184
|
-
---
|
|
1185
|
-
|
|
1186
|
-
## Q campaign — sub-4-bpw frontier: KL instrument, trellis, LDLQ, mixed-k (2026-08-31 → 09-02, M1 Max 32 GB)
|
|
1187
|
-
|
|
1188
|
-
Josh's frame: the best Qwen3.8-27B for THIS 32 GB box — smallest, smartest,
|
|
1189
|
-
fastest — using the rotation ("that was the entire point") plus the levers
|
|
1190
|
-
the 900+ published quants do not combine: trellis coding (QTIP/TCQ), LDLQ,
|
|
1191
|
-
and borrowed sensitivity measurements (EXL3/Unsloth/OptiQ). Program tag Q.
|
|
1192
|
-
|
|
1193
|
-
**Q0 instrument — mean KL vs a bf16 teacher, on 32 GB.** `scripts/turboquant/
|
|
1194
|
-
tq-dump-teacher-logits.py` streams the bf16 27B through stock mlx-lm once and
|
|
1195
|
-
writes, per teacher-forced position, the top-2048 logits + full-vocab
|
|
1196
|
-
logsumexp (fp16 lossless for bf16; captures 99.79% of full-vocab KL);
|
|
1197
|
-
`tq-kl-vs-teacher.py` (Python) and `bun scripts/eval.ts kl --reference-logits`
|
|
1198
|
-
(serving path) score any candidate; self-KL is exactly 0 and the two stacks
|
|
1199
|
-
read the dump byte-identically. Corpus `runs/kl-corpus/uf-4096x32` (32×4096
|
|
1200
|
-
UF-derived chat, sha `6594cfbf…`); dump `runs/kl-teacher/qwen38-27b-bf16`
|
|
1201
|
-
(1.61 GB). Calibration warning of record: this protocol runs ~25× hotter than
|
|
1202
|
-
the published self-generated-trace charts (RTN-4 = 0.1396 here vs ~0.005
|
|
1203
|
-
there) — only within-dump comparisons are valid, never cross-paper numbers.
|
|
1204
|
-
|
|
1205
|
-
**KL ladder (mean KL(bf16‖cand), same dump, lower is better):**
|
|
1206
|
-
|
|
1207
|
-
| arm | bpw | GiB | KL | MMLU | tGSM | rawGSM |
|
|
1208
|
-
|---|---|---|---|---|---|---|
|
|
1209
|
-
| bf16 | 16 | 54 | 0 | | | |
|
|
1210
|
-
| RTN-4 g64 (all 4-bit) | 4.5 | 15.0 | 0.1396 | | | |
|
|
1211
|
-
| **Q3: rotation + LDLQ + mixed-k 3.00** (fake-quant; carrier8 dense 0.1568) | **3.55** | **~11.9 proj.** | **0.1553** | **88** | 48 | 44 |
|
|
1212
|
-
| flagship GPTQ+sens (mjriii/Qwen3.8-27B) | 4.80 | 17.0 | 0.1646 | 87 | 94 | 96 |
|
|
1213
|
-
| **compact allocation, NO rotation** (`tqalloc-norot`) | 3.858 | 13.13 | **0.2524** | 85 | 98 | **0/50** |
|
|
1214
|
-
| q1-latemlp, no rotation | ~3.9 | | 0.2837 | | | |
|
|
1215
|
-
| **trellis k3 uniform + rotation** (q2a, fake-quant) | ~3.4 | | 0.4240 | | | |
|
|
1216
|
-
| trellis k3 uniform, no rotation (q2b) | ~3.4 | | 0.5648 | | | |
|
|
1217
|
-
| compact allocation + rotation (mjriii/Qwen3.8-27B-TQ) | 3.86 | 13.9 | 0.6054 | 82 | 82 | 96 |
|
|
1218
|
-
| q1-latemlp + rotation | ~3.9 | | 0.6519 | | | |
|
|
1219
|
-
|
|
1220
|
-
Findings of record: (1) **rotation is a 2×2 crossover, not a lever with a
|
|
1221
|
-
sign** — it HELPS the trellis (0.565 → 0.424) and HURTS affine g64
|
|
1222
|
-
(0.252 → 0.605): the trellis codes a Gaussian source and needs the Hadamard;
|
|
1223
|
-
affine's per-64 scale+bias already absorbs the outliers the rotation spreads.
|
|
1224
|
-
(2) **KL is the screen, not the verdict**: the lowest-KL sub-4-bpw arm scores
|
|
1225
|
-
0/50 on raw GSM (an EOS cliff a single-forward instrument cannot see) while the
|
|
1226
|
-
rotated compact arm at 2.4× the KL scores 96 — every finalist still needs the
|
|
1227
|
-
task columns. (3) No trellis cell beats the affine compact arm yet; the two
|
|
1228
|
-
open levers are LDLQ (Hessian error feedback) and mixed k — the published
|
|
1229
|
-
EXL3 numbers (their protocol: SC 3 bpw 0.0257 vs UD-Q3_K_XL 0.0209; 4 bpw
|
|
1230
|
-
0.0062) say both are worth ~20–70%. (4) Weight-MSE is NOT a screen: it
|
|
1231
|
-
predicted the unrotated trellis at 0.18–0.21; the measured KL was 0.5648.
|
|
1232
|
-
(5) **The full recipe wins (2026-09-02):** rotation + LDLQ + EXL3-derived
|
|
1233
|
-
mixed k at the 3.00 MLP budget scores KL 0.1553 at 3.55 coded bpw — below
|
|
1234
|
-
the shipped 4.80-bpw flagship (0.1646), 38% below the previous sub-4 best
|
|
1235
|
-
(compact-norot 0.2524), 11% above all-4-bit RTN (0.1396) — with MMLU 88/100
|
|
1236
|
-
(flagship 87, compact 85), tGSM 48/50 (flagship 48), rawGSM 44/50 (flagship
|
|
1237
|
-
48, compact-norot 0): no EOS cliff. Each lever alone lost (q2a 0.4240); the
|
|
1238
|
-
levers compound. At n=100/50 a one-point gap is noise: the claim of record
|
|
1239
|
-
is "matches the 4.8-bpw flagship at 3.55 bpw", not "beats it". Gate Q3 PASSED.
|
|
1240
|
-
|
|
1241
|
-
**Q2 trellis codec** (`scripts/turboquant/tq-trellis.ts`): QTIP bitshift
|
|
1242
|
-
trellis L=12, k∈{1..4}, V=1, T=256, tail-biting Viterbi, 1MAD/RPTC/random
|
|
1243
|
-
codebooks; `--validate` reproduces QTIP Table 2 exactly; 1.2 Mw/s on M1 Max
|
|
1244
|
-
after replacing `argmax` (MLX ArgReduce is 85× slower than `max`) with
|
|
1245
|
-
compare + uint8 max. Driver `tq-quantize-trellis.ts`: streaming fold +
|
|
1246
|
-
quantize, trellis on the 192 MLP tensors along the rotated axis, affine
|
|
1247
|
-
elsewhere per the compact allocation, fake-quant output (decoded bf16 flagged
|
|
1248
|
-
`false`, so stock mlx-lm loads it). Real packed kernels (Q2b) only if a recipe
|
|
1249
|
-
wins: Metal has no `lop3`, so decode costs 4–5 ALU ops/weight; M1 decode is
|
|
1250
|
-
already ALU-bound (3-bit affine at 54% of roofline) → predicted 7–9 tok/s on
|
|
1251
|
-
M1 (a regression), wash-to-win on M4 Pro; ~257 dispatches/token; fallback is
|
|
1252
|
-
load-time expansion to affine.
|
|
1253
|
-
|
|
1254
|
-
**Q2c LDLQ** (`tq-ldlq-hessians.py` + `--ldlq <hdir>`): per-layer MLP input
|
|
1255
|
-
Hessians in the folded basis (gate/up captured pre-γ so H' = R1ᵀ E[nnᵀ] R1;
|
|
1256
|
-
down basis-free), block-LDL on CPU, BlockLDLQ error feedback at block T (=
|
|
1257
|
-
the trellis block, so only the objective changes vs q2a), 4× unweighted-peak
|
|
1258
|
-
guard, 20 GiB leak abort. Calibration = 512×128 rows of the SAME chat domain
|
|
1259
|
-
(disjoint from the scored rows; a domain mismatch was measured to hurt GPTQ).
|
|
1260
|
-
Hessians: 64 layers in 35 min, 0/128 factorization fallbacks. The uniform-k3
|
|
1261
|
-
LDLQ arm (Q2c) was paused at 72/192 and superseded: Q3 went straight to the
|
|
1262
|
-
full recipe, so LDLQ's isolated contribution is not separately measured
|
|
1263
|
-
(q2a → Q3 is LDLQ + mixed-k together, 0.4240 → 0.1553). Bug found on resume
|
|
1264
|
-
(2026-09-02): the k-map refactor's block loop shadowed the codec k
|
|
1265
|
-
(`trellisFor(blockIdx)`); the Trellis ctor now rejects K outside [1,L), the
|
|
1266
|
-
L=0 selftest is byte-identical again, and the real-L probe on layer 21 runs
|
|
1267
|
-
at 5.6 GiB peak with the unweighted MSE +32/+46% (gate/down), as expected for
|
|
1268
|
-
a Hessian-weighted objective.
|
|
1269
|
-
|
|
1270
|
-
**Q3 mixed k** (`--k-map reports/qwen38-allocation/trellis-kmap.json
|
|
1271
|
-
--k-budget 3.00`): per-tensor k∈{2,3,4} greedily allocated from turboderp's
|
|
1272
|
-
EXL3 per-tensor KLD-vs-k table for this exact model (gate/up tied like EXL3's
|
|
1273
|
-
own recipe; 94.3% agreement with their 3.00 bpw recipe). Budgets 2.75 / 3.00
|
|
1274
|
-
/ 3.25 avg-MLP-bpw = k2/k3/k4 68/104/20, 26/140/26, 2/140/50 (≈10.8 / 11.3 /
|
|
1275
|
-
11.8 GiB projected). Run 2026-09-01/02 at 3.00: 259 min (257 in the encoder,
|
|
1276
|
-
1.11 Mw/s), 192 trellis tensors, 3.5468 coded bpw over 27.3 G params, 38 GiB
|
|
1277
|
-
fake-quant on disk; artifact `mjriii/Qwen3.8-27B-q3-trellis-ldlq-k300-fakequant`
|
|
1278
|
-
on the external volume, KL row `rows/q3-ldlq-k300.json`. Result: see finding
|
|
1279
|
-
(5). 3.25 not run — 3.00 already clears the gate; a 2.75 arm is the next
|
|
1280
|
-
size lever, not 3.25.
|
|
1281
|
-
|
|
1282
|
-
**Q2b packed format + kernels** (`src/quantize/trellis.ts`,
|
|
1283
|
-
`src/model/trellis-linear.ts`, driver `scripts/turboquant/
|
|
1284
|
-
tq-quantize-trellis-packed.ts`; the fake-quant codec/driver that produced the
|
|
1285
|
-
Q3 record are frozen, these are new files). On disk a trellis tensor is
|
|
1286
|
-
`.weight` uint32 `[rows, cols·k/32]` + `.scales` fp16 `[rows]`, config entry
|
|
1287
|
-
`{mode:"trellis", bits:k, group_size:T, trellis:{L, code:"1mad", axis}}`
|
|
1288
|
-
(axis 1 = coded along the input dim, stored `[out, in·k/32]`; axis 0 = along
|
|
1289
|
-
the output dim, stored as Wᵀ `[in, out·k/32]`). One block = T·k bits; symbol
|
|
1290
|
-
b_t sits at bit offset (T−1−t)·k — REVERSED time — so the L-bit window at that
|
|
1291
|
-
offset (wrapping, tail-biting) IS state_t, and any weight decodes in O(1):
|
|
1292
|
-
two word loads, shift, mask, LUT. No sequential dependency, hence a plain
|
|
1293
|
-
matvec. Three Metal kernels share that primitive: `reduce` (axis 1, one SIMD
|
|
1294
|
-
group per output row, lanes stride consecutive coded positions → coalesced,
|
|
1295
|
-
`simd_sum`), `scatter` (axis 0, 32 lanes = 32 consecutive outputs of one
|
|
1296
|
-
block, loop over inputs, split-K ×16 partials summed by one mlx op), and
|
|
1297
|
-
`expand` (whole tensor → bf16 for M>4, then a stock matmul; ≤178 MB
|
|
1298
|
-
per expanded tensor). Packed prefill evaluates each projection before
|
|
1299
|
-
building the next. Qwen also evaluates each layer's cache outputs: the
|
|
1300
|
-
copied conv tail otherwise retains the whole chunk's conv input until
|
|
1301
|
-
end-of-chunk cache evaluation. Decode remains lazy and uses packed kernels.
|
|
1302
|
-
These evaluation boundaries bound temporary buffer lifetimes; disposing a
|
|
1303
|
-
JS tensor handle alone does not release a lazy consumer's references.
|
|
1304
|
-
The reconstructed weight is bf16(f32(lut[state])·f32(scale)) in
|
|
1305
|
-
every path — bit-identical to the fake-quant artifact's stored bf16 (unit test
|
|
1306
|
-
`tests/unit/trellis-linear.test.ts`: host unpack + expand kernel exact for
|
|
1307
|
-
k∈{2,3,4}; matvecs within 2e-3 of a bf16 matmul). Engine wiring is additive:
|
|
1308
|
-
`QuantSpec.trellis`, `loadLinear`/`Qwen3MLP` pick `TrellisLinear` per module;
|
|
1309
|
-
trellis MLP tensors are not LoRA targets yet. `MLX_BUN_TRELLIS=expand` is the
|
|
1310
|
-
load-time fallback (8-bit affine carrier). Encoding a packed artifact reruns
|
|
1311
|
-
the Viterbi (the fake-quant stores values, not states; a state path cannot be
|
|
1312
|
-
recovered from values because the 4096 states map onto 1021 distinct values).
|
|
1313
|
-
|
|
1314
|
-
**Q2b measured (2026-09-02, M1 Max 32 GB).** Packed Q3 artifact
|
|
1315
|
-
(`Qwen3.8-27B-q3-trellis-ldlq-k300-packed`): **12.14 GiB** on disk (fake-quant
|
|
1316
|
-
38 GiB, flagship 17 GiB), LDLQ applied 192/192, 0 guard trips; decoded
|
|
1317
|
-
weights bit-identical to the fake-quant artifact through the expand kernel
|
|
1318
|
-
(0 mismatches in 89 M per tensor, k=2 and k=3, both axes). Loads and generates
|
|
1319
|
-
through the qwen3_5 graph; KL through OUR serving path 0.15501 (mlx-lm on the
|
|
1320
|
-
fake-quant: 0.15532). Decode kernels, pipelined 8-deep (the in-graph cost; an
|
|
1321
|
-
eval-per-call bench adds ~0.3 ms of sync and misleads), gate/up [17408×5120]
|
|
1322
|
-
and down [5120×17408], k=3, M=1:
|
|
1323
|
-
|
|
1324
|
-
| kernel | no decode (floor) | inline 1MAD, f32 weight | stock affine 3-bit g64 |
|
|
1325
|
-
|---|---|---|---|
|
|
1326
|
-
| gate/up matvec (reduce) | 0.24 ms | 0.41 ms | 0.16 ms |
|
|
1327
|
-
| gate+up+swiglu fused | 0.37 ms | 0.73 ms | 2×0.16 |
|
|
1328
|
-
| down matvec (scatter) | 0.54 ms | 0.77 ms | 0.16 ms |
|
|
1329
|
-
|
|
1330
|
-
Whole model: **9.3 tok/s** vs the 4.80-bpw affine flagship at **18.9** on the
|
|
1331
|
-
same box (kernels v3, `c0a1e00`); the first kernels read 4.4. What the
|
|
1332
|
-
decomposition says: (1) the 1MAD decode is ~12 int ops/weight and costs
|
|
1333
|
-
0.17 ms per 89 M weights; a precise divide cost 1 ms (replaced by y×(1/d),
|
|
1334
|
-
which is 1-ulp-off f32 for 398 of 1021 code values — a 2-FMA residual step
|
|
1335
|
-
restores exactness at +0.05 ms, `trellis_val_rcp`); (2) rounding the decoded
|
|
1336
|
-
weight to bf16 (to match the artifact's stored bf16) cost as much as the
|
|
1337
|
-
decode, so the served weight is now f32 code×scale — MORE accurate than the
|
|
1338
|
-
fake-quant, no longer bit-identical to it — measured on the served DECODE
|
|
1339
|
-
path (`eval.ts kl --decode --self MLX_BUN_TRELLIS_VARIANT 1→6`, 16 prompts ×
|
|
1340
|
-
32 teacher-forced steps): KL(bit-exact ‖ f32-weight) mean 0.00089, p95
|
|
1341
|
-
0.0025, i.e. 0.6% of the model's own 0.155 to the teacher (the prefill/expand
|
|
1342
|
-
path always rounds to bf16 and is unaffected); (3) the threadgroup LUT (16 KB) halves
|
|
1343
|
-
occupancy and the device LUT gathers 32 lines per load — both slower than
|
|
1344
|
-
computing the code; (4) the axis-0 (down) matvec is the hard one: the code
|
|
1345
|
-
sequence runs along the OUTPUT dim, so a reduction over inputs is a column
|
|
1346
|
-
gather; lanes-over-outputs looping rows costs a full line per 16-byte
|
|
1347
|
-
segment, and lane-per-word (whole-line reads, shuffle for spilled windows)
|
|
1348
|
-
did not beat it — its no-decode floor is 3× affine. M1 decode at these sizes
|
|
1349
|
-
is latency/occupancy bound (affine reaches 200 GB/s of 400), so every ALU op
|
|
1350
|
-
per weight lands on the wall clock. Verdict: the packed format works and is
|
|
1351
|
-
the honest 12 GiB artifact; on M1 Max it decodes at ~half the flagship's
|
|
1352
|
-
speed. Levers left: code down_proj along its INPUT dim (a recipe change —
|
|
1353
|
-
the rotated axis is the output dim — needs a re-encode and a KL check),
|
|
1354
|
-
half-precision LUT (8 KB, occupancy back, +double rounding), or accept
|
|
1355
|
-
M4-class ALU. `MLX_BUN_TRELLIS=expand` (8-bit carrier, 23 GiB) is the
|
|
1356
|
-
full-speed fallback where it fits.
|
|
1357
|
-
|
|
1358
|
-
**The down_proj axis, settled (2026-09-02 night).** Re-encoded the same recipe
|
|
1359
|
-
with `--down-axis in` (down_proj coded along its INPUT dim — the un-rotated
|
|
1360
|
-
intermediate — so all three MLP projections decode with the plain reduce
|
|
1361
|
-
kernel; `--reuse` copied the 128 unchanged gate/up tensors, so only 64 Viterbi
|
|
1362
|
-
runs, 98 min):
|
|
1363
|
-
|
|
1364
|
-
| arm | bpw | GiB | KL (engine) | top-1 | decode tok/s |
|
|
1365
|
-
|---|---|---|---|---|---|
|
|
1366
|
-
| down coded along the ROTATED output dim | 3.5468 | 12.14 | 0.15501 | 86.38% | 9.3 |
|
|
1367
|
-
| **down coded along the INPUT dim** | 3.5463 | 12.14 | **0.15543** | **86.59%** | **11.3** |
|
|
1368
|
-
|
|
1369
|
-
KL is a wash (+0.0004, 0.3% of the arm's own distance to the teacher) and
|
|
1370
|
-
top-1 is marginally BETTER — so on the screen the input axis looked like a
|
|
1371
|
-
free +22% decode. **The task columns overturned it** (8-bit carriers, same
|
|
1372
|
-
frozen items, `tq-evals.py`):
|
|
1373
|
-
|
|
1374
|
-
| arm | MMLU-100 | tGSM-50 | rawGSM-50 |
|
|
1375
|
-
|---|---|---|---|
|
|
1376
|
-
| down along the rotated output dim | 88 | 48 | **44** |
|
|
1377
|
-
| down along the input dim | 88 | 47 | **29** |
|
|
1378
|
-
|
|
1379
|
-
The rawGSM regression is STRICTLY NESTED — 15 items the output-axis arm
|
|
1380
|
-
answers correctly that the input-axis arm fails, **0 the other way** (McNemar
|
|
1381
|
-
p ≈ 3e-5) — and the failure mode is an EMPTY continuation: on those items the
|
|
1382
|
-
model emits EOS immediately after `A:` (verified by dumping the raw
|
|
1383
|
-
generations). That is the same EOS-cliff class as the unrotated affine arm
|
|
1384
|
-
(`tqalloc-norot`, rawGSM 0/50 at KL 0.2524), and it is invisible to MMLU
|
|
1385
|
-
(logprob over four letters), to templated GSM (chat template, 47 vs 48), and
|
|
1386
|
-
to KL (a single-forward instrument that never asks the model to STOP).
|
|
1387
|
-
|
|
1388
|
-
**Finding of record (third instance of "KL is the screen, not the verdict"):
|
|
1389
|
-
one-sided incoherence processing must reach the CODED axis.** R1 gaussianizes
|
|
1390
|
-
down_proj's output dim; coding along the un-rotated input dim leaves that
|
|
1391
|
-
sequence non-Gaussian for a codebook that assumes unit-variance Gaussian
|
|
1392
|
-
inputs, and what breaks is not average next-token quality but the model's
|
|
1393
|
-
raw-format stopping behavior. **Carry-forward stays the output-axis arm**
|
|
1394
|
-
(`…-k300-packed`, 9.3 tok/s); `--down-axis in` is kept as the measured
|
|
1395
|
-
counter-example, not a default, and the scatter kernel stays load-bearing.
|
|
1396
|
-
The re-encode also surfaced a driver bug: the LDLQ Hessian must be chosen by
|
|
1397
|
-
MODULE, not by trellis axis (`2b29b18`).
|
|
1398
|
-
|
|
1399
|
-
**Eval carrier** (`scripts/turboquant/tq-repack-fakequant.ts`): a 38 GiB
|
|
1400
|
-
fake-quant cannot load dense on 32 GB, and `tq-evals.py` (MMLU logprob
|
|
1401
|
-
scoring, GSM greedy generation) needs the whole model resident. The tool
|
|
1402
|
-
re-packs exactly the bf16 MLP tensors flagged `false` as 8-bit g64 affine
|
|
1403
|
-
(≈ −45 dB, negligible next to the ≈ −13 dB trellis error) and passes every
|
|
1404
|
-
other tensor through byte-identical: 23 GiB, loads in 24 s, dense KL 0.1568
|
|
1405
|
-
vs 0.1553 streamed (+1%, identity confirmed). All task columns for trellis
|
|
1406
|
-
arms are measured on the carrier. NOT a shipping format — the real footprint
|
|
1407
|
-
needs Q2b (packed trellis + Metal decode kernel).
|
|
1408
|
-
|
|
1409
|
-
## Packed kernel experiments (2026-09-05, M4 Pro 24 GB)
|
|
1410
|
-
|
|
1411
|
-
Experimental `MLX_BUN_TRELLIS_VARIANT=7` reuses each decoded gate/up weight
|
|
1412
|
-
across M=2..4 input vectors. The new kernels live in
|
|
1413
|
-
`src/model/trellis-shared-m.ts`; the original kernels remain the default
|
|
1414
|
-
(variant 6). Variant 7 keeps the same two-accumulator order, reductions and
|
|
1415
|
-
bf16 activation boundaries. M=1, scatter/down and M>4 expansion retain the
|
|
1416
|
-
variant-6 decoder and kernels. No weight format or crossover changed.
|
|
1417
|
-
|
|
1418
|
-
The kernel diagnostic now loads an individual layer's real packed tensors
|
|
1419
|
-
with `--model-path`, selecting a gate bit-width via `--k` (and optionally
|
|
1420
|
-
`--layer`). It records the actual per-role geometry, tensor SHA-256 hashes,
|
|
1421
|
-
source identity, every timing sample and memory. `--variants 6,7` compares
|
|
1422
|
-
the implementations; `--reference-variant 6` checks outputs separately from
|
|
1423
|
-
timing. `--m`, `--seed`, `--reps` and `--pipe` control the micro-workload;
|
|
1424
|
-
`--skip-affine` excludes synthetic affine controls, which are not a quality
|
|
1425
|
-
comparison. `--json reports/<name>.json` preserves results. Its complete-MLP
|
|
1426
|
-
cell retains gate/up → SwiGLU → down dependencies and production barriers.
|
|
1427
|
-
`--kernel-module` permits isolated candidate modules with the same exports.
|
|
1428
|
-
|
|
1429
|
-
The first screen covers the packed artifact's k2/k3/k4 matrices at
|
|
1430
|
-
M=1/2/3/4/5/8. Shared-M reduce and fused gate/up prototypes match the observed
|
|
1431
|
-
outputs at M=1..4. Six sequential AB/BA blocks with different activation seeds
|
|
1432
|
-
retain the gain in the complete MLP. Raw evidence is under
|
|
1433
|
-
`reports/qwen38-rd/paired-shared-m/`; integrated variant-7 checks are under
|
|
1434
|
-
`reports/qwen38-rd/variant7/`. Unit tests also compare exact output bytes for
|
|
1435
|
-
bf16/f32, both axes, fused activation, the complete MLP and the M=4/5 boundary.
|
|
1436
|
-
The complete packed 27B also passes candidate/current equality for all logits,
|
|
1437
|
-
live KV/recurrent state and a subsequent token at M=1..5. Six AB/BA full-model
|
|
1438
|
-
forward blocks at M=2/4 preserve state/logit identity on distinct token inputs;
|
|
1439
|
-
results are in `reports/qwen38-rd/shared-m-full-model.json`. These timings
|
|
1440
|
-
project every position from a short shared prefix. They do not measure HTTP
|
|
1441
|
-
generation or strict fill's last-position-only head. The machine fails the
|
|
1442
|
-
quiet/swap gate, so user-workload A/B and quiet M4 Pro evidence remain required
|
|
1443
|
-
before a default. `tests/parity/trellis-shared-m.test.ts` retains the native
|
|
1444
|
-
gate behind `MLX_BUN_TEST_TRELLIS_MODEL`; `MLX_BUN_TRELLIS_AB_REPORT` optionally
|
|
1445
|
-
records the diagnostic forward timings.
|
|
1446
|
-
|
|
1447
|
-
Experimental variant 8 combines variant 7 with balanced 3-bit scatter in
|
|
1448
|
-
`src/model/trellis-balanced-scatter.ts`. The incumbent assigns one packed word
|
|
1449
|
-
per lane and leaves eight SIMD lanes idle for a 3-bit block. The candidate
|
|
1450
|
-
assigns eight outputs to each of all 32 lanes, loads adjacent packed words
|
|
1451
|
-
and aligns them once before constant-shift decoding. It preserves each
|
|
1452
|
-
output's row/FMA order, all split boundaries, partial reduction and final
|
|
1453
|
-
cast. This path requires k=3, T=256 and L<=12; other geometries retain the
|
|
1454
|
-
incumbent scatter. M>4 still expands. The default remains variant 6.
|
|
1455
|
-
|
|
1456
|
-
Balanced lanes alone improve the diagnostic screen; aligning words improves
|
|
1457
|
-
it further. Row-loop unrolling does not materially improve the aligned
|
|
1458
|
-
candidate, so it is not retained. The unroll screen has no repeatable-win
|
|
1459
|
-
verdict for k2/k4. Raw screens: `reports/qwen38-rd/balanced3-screen/`,
|
|
1460
|
-
`scatter-unroll-screen/` and `aligned3-screen/`. Six blocks comparing
|
|
1461
|
-
variants 6/7/8 at k3 and M=1/2/4 retain the down/complete-MLP gain with exact
|
|
1462
|
-
observed outputs (`variant8-paired/`). Native packed-model logits, live state
|
|
1463
|
-
and subsequent-token checks also pass M=1..5. Six full-model A/B blocks at
|
|
1464
|
-
M=1/2/4 retain the gain (`variant8-full-model.json`). Select this gate with
|
|
1465
|
-
`MLX_BUN_TRELLIS_AB_VARIANT=8`; these remain short-prefix diagnostics.
|
|
1466
|
-
|
|
1467
|
-
`MLX_BUN_TRELLIS_AB_LAST=1` selects a native append screen at
|
|
1468
|
-
M=1/2/3/4/5/8/9/16 with only the last vocabulary projection, closer to strict
|
|
1469
|
-
fill's work. The variant-7 screen preserves state/logit identity and confirms
|
|
1470
|
-
the M=4/5 cost discontinuity (`shared-m-append-lengths.json`). Splitting a long
|
|
1471
|
-
span crosses the packed-f32/expanded-bf16 paths and is a separate numerical
|
|
1472
|
-
experiment; the timing curve does not authorize that change.
|
|
1473
|
-
|
|
1474
|
-
A device lookup table of variant-6 f32 code values also matched the observed
|
|
1475
|
-
outputs but slowed the M=1 kernels for every tested bit width. That candidate
|
|
1476
|
-
is a measured loss on this chip/regime (`reports/qwen38-rd/lut6-*.json`). The
|
|
1477
|
-
M=4/5 gate-projection cost discontinuity remains; changing the crossover also
|
|
1478
|
-
changes the accumulation/precision path and needs separate numerical gates.
|
|
1479
|
-
|
|
1480
|
-
The smaller-table follow-up also loses on the M4 Pro. A constant-address-space
|
|
1481
|
-
table stores all 4,096 integer code values in signed 16-bit entries, preserving
|
|
1482
|
-
the reciprocal, scaling and reduction arithmetic. It matches the k3 M=1
|
|
1483
|
-
checks but slows both projections and complete MLP execution. Device and
|
|
1484
|
-
threadgroup tables store the same integers exactly in fp16, avoiding the
|
|
1485
|
-
double rounding of fp16 normalized code values. Both lose at M=1/4; the
|
|
1486
|
-
threadgroup version is the less costly choice. Those two experiments change
|
|
1487
|
-
gate/up decoding while retaining the aligned k3 scatter's computed decoder.
|
|
1488
|
-
None proceeds to full-model integration. Evidence: `trellis-constant-short-k3-m1.json`,
|
|
1489
|
-
`trellis-device-half-k3-m1.json`, `trellis-device-half-k3-m4.json`,
|
|
1490
|
-
`trellis-threadgroup-half-k3-m1.json` and `trellis-threadgroup-half-k3-m4.json`
|
|
1491
|
-
under `reports/qwen38-rd/`, with source manifests and every timing sample.
|
|
1492
|
-
|
|
1493
|
-
A later scatter-specific table experiment starts from the interleaved
|
|
1494
|
-
variant-13 artifact. Each threadgroup computes the exact 4,096 integer code
|
|
1495
|
-
values into an 8 KiB signed-short table; packed float multiplication and the
|
|
1496
|
-
original dense-expansion LUT remain unchanged. An initial 45-process screen
|
|
1497
|
-
across bf16/f16/f32 and M1/2/4/5/8 preserves all output hashes. Changing all
|
|
1498
|
-
decode sites still loses because gate/up slows. The apparent M1 scatter gain
|
|
1499
|
-
does not survive the narrower repeated control.
|
|
1500
|
-
|
|
1501
|
-
Restricting the table to the balanced scatter kernels completes 72 processes
|
|
1502
|
-
with exact separate-process output hashes, including complete MLP outputs
|
|
1503
|
-
and M5/8 fallback. Six alternating bf16 pairs on the M4 Pro 24 GB change
|
|
1504
|
-
complete-MLP time by +1.28% at M1, -0.62% at M2 and -4.12% at M4. All M1
|
|
1505
|
-
pairs lose and all M2/M4 pairs improve. A 20-process M3 follow-up also preserves
|
|
1506
|
-
every output hash; its six bf16 pairs improve the down projection by a median
|
|
1507
|
-
8.02% and the complete MLP by 2.52%. The smaller fp16/fp32 screens preserve
|
|
1508
|
-
identity but do not establish retention. Each native/candidate pair reaches
|
|
1509
|
-
the same final active-allocation baseline. These are diagnostic operation
|
|
1510
|
-
timings, with fixed sources and all samples retained. The next full-model
|
|
1511
|
-
prototype targets only M3/4 for the tested k3/L12/T256 interleaved down shape.
|
|
1512
|
-
Ordinary M1 stays procedural. Full-model state, generation and actual serving
|
|
1513
|
-
acceptance remain before integration. Evidence: `trellis-threadgroup-codebook.json`,
|
|
1514
|
-
`trellis-threadgroup-scatter{,-review}.json` and
|
|
1515
|
-
`trellis-threadgroup-scatter-m3{,-review}.json` in the campaign directory.
|
|
1516
|
-
|
|
1517
|
-
The narrow full-model screen then preserves all 24 forward comparisons,
|
|
1518
|
-
including every vocabulary row at M1..8, live attention/recurrent state and
|
|
1519
|
-
the next token's logits/state. It also preserves four greedy/seeded-sampled
|
|
1520
|
-
generation streams and their log-probabilities, counts and final cache bytes.
|
|
1521
|
-
The prefix snapshot stays unchanged. Both fresh processes exit cleanly with
|
|
1522
|
-
fixed sources, equal scatter-call counts and the same 1,015,814-byte final
|
|
1523
|
-
active counter after model/cache disposal. The first pair's measured M3/4
|
|
1524
|
-
forwards improve by 1.6–2.8%; ordinary 64-token generation changes by less
|
|
1525
|
-
than 0.1%. This is an initial screen. Six balanced process pairs and actual
|
|
1526
|
-
MTP serving comparisons remain before retaining the prototype. Evidence:
|
|
1527
|
-
`trellis-scatter-full{,-review}.json`.
|
|
1528
|
-
|
|
1529
|
-
Six balanced fresh-process pairs preserve all 144 forward/logit/state and
|
|
1530
|
-
24 generation comparisons, with fixed sources, identical call counts and
|
|
1531
|
-
the same final active allocation. Taking the two measured forward samples
|
|
1532
|
-
within each process before pairing, median M3/M4 forward changes are
|
|
1533
|
-
-1.44/-2.00%, improving every pair. Ordinary 64-token greedy/sampled complete
|
|
1534
|
-
times change by +0.045/-0.125%. The unchanged M128 prefill control is 2.59%
|
|
1535
|
-
slower in this sequence and loses all six pairs. A focused M128-only control
|
|
1536
|
-
tests whether that regression requires preceding M3/4 work. The initial actual MTP HTTP pair preserves all seven responses,
|
|
1537
|
-
7,100 eligible scatter calls per arm and equal final active counters, but
|
|
1538
|
-
its complete-time changes are mixed. Evidence:
|
|
1539
|
-
`trellis-scatter-full-repeat{,-review}.json` and
|
|
1540
|
-
`trellis-scatter-http{,-review}.json`.
|
|
1541
|
-
|
|
1542
|
-
Six subsequent balanced MTP HTTP pairs preserve all 42 paired responses,
|
|
1543
|
-
call maps and final active allocations. Median complete-request changes are
|
|
1544
|
-
-1.53% for code, -1.29% for explanation and -1.04% for JSON. Code and explanation
|
|
1545
|
-
improve in every pair; JSON improves in four of six. TTFT changes by less than
|
|
1546
|
-
0.71% and median paired sampled peak RSS increases by 2.16 MiB. These are
|
|
1547
|
-
M4 Pro 24 GB diagnostic results, with static swap still failing preflight.
|
|
1548
|
-
They support a small serving benefit in this scope, not ordinary M1 decode.
|
|
1549
|
-
The separate four-pair M128-only control executes no eligible M3/4 scatter
|
|
1550
|
-
calls. All 20 forward/state comparisons remain exact and final active memory
|
|
1551
|
-
is 16,390 bytes in every process. Its median paired time increases by 0.52%,
|
|
1552
|
-
with individual process-median differences from 0.06% to 1.01%. This does not
|
|
1553
|
-
reproduce the earlier 2.59% magnitude, but does not identify its cause either.
|
|
1554
|
-
Keep both results and inspect scheduling before integration. Evidence:
|
|
1555
|
-
`trellis-scatter-http-repeat{,-review}.json` and
|
|
1556
|
-
`trellis-scatter-prefill{,-review}.json`.
|
|
1557
|
-
|
|
1558
|
-
A four-pair sequence control adds 80 exact forward/state/continuation cases,
|
|
1559
|
-
with the same 16,390-byte final active counter in all eight processes. M3/M4
|
|
1560
|
-
forwards improve by median 1.45/1.73%, in every pair. The same-input M128
|
|
1561
|
-
measurement immediately before and after those calls changes by -0.92/-1.77%
|
|
1562
|
-
between arms; the after-versus-before difference does not show the suspected
|
|
1563
|
-
slowdown. The unchanged M512 control instead changes by +1.11%, losing three
|
|
1564
|
-
of four pairs. These controls do not reproduce the original M128 result or
|
|
1565
|
-
establish a prefill benefit. Keep prefill variation in the uncertainty of this
|
|
1566
|
-
small candidate and require integrated, combined and quiet acceptance.
|
|
1567
|
-
Evidence: `trellis-scatter-sequence{,-review}.json`.
|
|
1568
|
-
|
|
1569
|
-
The normal-scheduling recorder preserves the three HTTP responses and all
|
|
1570
|
-
scatter calls in a separate JSON pair. The measured request has 76,928
|
|
1571
|
-
dispatches, 3,153 command buffers with dispatches, 50,001 barriers and 3,870
|
|
1572
|
-
concurrent dispatches in both arms. Temporary-reference counts and bytes also
|
|
1573
|
-
match. Buffers without dispatches and fence waits differ slightly. Candidate
|
|
1574
|
-
command-span union falls by about 51 ms, while gaps between those spans grow
|
|
1575
|
-
by about 72 ms; instrumented complete time increases by 0.32%. Command spans
|
|
1576
|
-
include internal waits and do not measure active GPU utilization. This pair
|
|
1577
|
-
shows how scheduling gaps can cancel a small operation gain; it does not
|
|
1578
|
-
override the six normal-library serving pairs or prove the cause of the
|
|
1579
|
-
prefill difference. Evidence: `trellis-scatter-http-trace{,-review}.json`.
|
|
1580
|
-
|
|
1581
|
-
The first ordinary four-request serving pair also preserves all 12 paired
|
|
1582
|
-
responses, submitted-row counts, scatter-call maps and final active allocation.
|
|
1583
|
-
The measured 256-token cohort completes in 11.342 versus 11.778 seconds,
|
|
1584
|
-
3.70% faster, with 4,050 eligible M4 scatter calls across its three cohorts.
|
|
1585
|
-
This is one M4 Pro 24 GB diagnostic pair, not a repeat verdict. Explicit API
|
|
1586
|
-
seeds require the serial lane, so this fixture uses temperature-zero argmax
|
|
1587
|
-
without an explicit seed. The initial seeded attempt is retained as a rejected
|
|
1588
|
-
batch fixture. Evidence: `trellis-scatter-cohort-v2{,-review}.json`.
|
|
1589
|
-
|
|
1590
|
-
The codebook is now part of experimental variant 13. Qwen's MLP loader enables
|
|
1591
|
-
it for the 5120/17408 down projection. `TrellisLinear` further requires bf16,
|
|
1592
|
-
k3/L12/T256, two-block interleaving and M3/4. The generic shared scatter kernel
|
|
1593
|
-
receives that decision as a compile-time integer. The table is initialized
|
|
1594
|
-
before the threadgroup's bounds return, and no new MLX allocation or graph
|
|
1595
|
-
boundary is introduced. Request and execution interfaces do not select it.
|
|
1596
|
-
The 23 focused tests and all three typechecks pass. The new test compares
|
|
1597
|
-
actual output bytes and dispatch eligibility across three dtypes, variants
|
|
1598
|
-
6/10/13, M1/2/3/4/5/8 and an incomplete row tile. Evidence:
|
|
1599
|
-
`trellis-scatter-integration-source-change.json`,
|
|
1600
|
-
`trellis-scatter-integration-focused-tests-final.txt` and
|
|
1601
|
-
`trellis-scatter-integration-typecheck.txt`.
|
|
1602
|
-
|
|
1603
|
-
The integrated full-model gate preserves all 24 forward/logit/state and four
|
|
1604
|
-
generation comparisons, the immutable prefix, call maps and final allocation.
|
|
1605
|
-
M3/M4 each exercise 150 table calls in the candidate. Timing also improves in
|
|
1606
|
-
unchanged control shapes during an unrelated CPU workload burst; those broad
|
|
1607
|
-
changes cannot be attributed to this kernel. Six integrated MTP HTTP pairs
|
|
1608
|
-
then preserve all 42 responses and the same final active counter. Median
|
|
1609
|
-
complete-time changes are -1.07/-1.27/-1.19% for code/explanation/JSON, with
|
|
1610
|
-
5/6, 5/6 and 4/6 pairs improving. TTFT changes remain below 0.46%. Retain every
|
|
1611
|
-
losing pair and the diagnostic classification. Repeated ordinary four-request
|
|
1612
|
-
serving, combined/pressure and quiet M4 Pro acceptance remain. Evidence:
|
|
1613
|
-
`trellis-scatter-integrated-full{,-review}.json` and
|
|
1614
|
-
`trellis-scatter-integrated-http{,-review}.json`.
|
|
1615
|
-
|
|
1616
|
-
Six integrated ordinary four-request serving pairs preserve all 72 paired
|
|
1617
|
-
responses, counts and finish reasons. Every cohort admits four batched rows,
|
|
1618
|
-
uses the eligible M4 kernel and returns to the same final active counter.
|
|
1619
|
-
Median measured cohort time changes by -1.49%, improving four of six pairs.
|
|
1620
|
-
Four measured pairs have identical per-cohort call maps; their median is also
|
|
1621
|
-
-1.49%, with three improving. The other two retain arrival-dependent M1/M2
|
|
1622
|
-
work differences. Report all pairs and the work-matched subset separately;
|
|
1623
|
-
do not silently discard scheduling differences or losing samples. The first
|
|
1624
|
-
integrated attempt preserved all responses but failed its stricter total-call
|
|
1625
|
-
map gate, motivating snapshots collected outside timed cohorts. This remains
|
|
1626
|
-
diagnostic evidence, with combined/pressure and quiet acceptance open. Evidence:
|
|
1627
|
-
`trellis-scatter-integrated-cohort.json` and
|
|
1628
|
-
`trellis-scatter-integrated-cohort-v2{,-review}.json`.
|
|
1629
|
-
|
|
1630
|
-
Sharing activation loads across multiple gate/up output rows per SIMD group
|
|
1631
|
-
also loses in the k3 M=1 screen. Every tested layout preserves the incumbent
|
|
1632
|
-
output bytes. One row per group reproduces the incumbent timing; two, four
|
|
1633
|
-
and eight rows increase complete-MLP time. Reducing the threadgroup to one
|
|
1634
|
-
or two SIMD groups does not rescue the two/four-row candidates. The original
|
|
1635
|
-
row mapping remains. Evidence: `trellis-shared-rows-k3-r*-m1.json` and
|
|
1636
|
-
`trellis-shared-rows-k3-r*-s*-m1.json` in the campaign report directory.
|
|
1637
|
-
|
|
1638
|
-
An integer arithmetic rewrite replaces the final byte-pair sum and subtraction
|
|
1639
|
-
with `as_type<int>(p * 65537u - (510u << 16)) >> 16`. If
|
|
1640
|
-
`p = a + (b << 16)`, with both byte-pair sums at most 510, this returns
|
|
1641
|
-
`a + b - 510` exactly. Host exhaustive-state/edge/random checks and all real
|
|
1642
|
-
k2/k3/k4 M=1/4 operation checks pass. The timing screen gives no useful
|
|
1643
|
-
additional gain, so the readable existing expression remains. Evidence:
|
|
1644
|
-
`trellis-y-mad-manifest.json` and `trellis-y-mad-k*-m*.json`.
|
|
1645
|
-
|
|
1646
|
-
The activation audit identifies a separate numerical distinction in the
|
|
1647
|
-
existing Lab path. Its fused kernel uses a float32 precise-exp sigmoid,
|
|
1648
|
-
whereas compiled MLX uses a dtype-specific abs/exp expression. Real k3 inputs
|
|
1649
|
-
at M=1/4 differ for bf16 and f32. Applying the old activation independently
|
|
1650
|
-
to the two projection outputs reproduces the fused result exactly, isolating
|
|
1651
|
-
the difference to the activation. Earlier small-input tolerance tests did
|
|
1652
|
-
not establish bit identity here. Existing variant-to-variant identity results
|
|
1653
|
-
still compare the same packed activation. Changing it requires a separately
|
|
1654
|
-
declared numerical/quality experiment; no default is changed by this audit.
|
|
1655
|
-
Evidence: `trellis-activation-audit.json`.
|
|
1656
|
-
|
|
1657
|
-
Variant 9 tests evaluation barriers separately. It keeps the variant-8
|
|
1658
|
-
kernels but lets the three expanded projections remain lazy until the
|
|
1659
|
-
existing layer-end hidden/state evaluation. The native last-head sweep
|
|
1660
|
-
preserves logits and live state at all observed lengths. M>4 improves while
|
|
1661
|
-
peak allocation grows; small M is unchanged. Evidence is in
|
|
1662
|
-
`reports/qwen38-rd/variant9-full-model.json`, with per-arm memory peaks.
|
|
1663
|
-
Larger prefill and the frozen long-agent pressure replay remain required.
|
|
1664
|
-
The default's per-projection barriers remain in place.
|
|
1665
|
-
|
|
1666
|
-
The variant-13 follow-up fixes the interleaved artifact and all kernels,
|
|
1667
|
-
then changes only the returned expanded projection's evaluation. It compares
|
|
1668
|
-
blocking evaluation, deferral to the existing layer boundary and asynchronous
|
|
1669
|
-
submission followed by that same layer boundary. All 35 warm/measured cases
|
|
1670
|
-
at M1/8/16/128/512 preserve logits, live state and continuation. Six balanced
|
|
1671
|
-
blocks exercise 64 expansion boundaries at M16 and 192 at M128/512; M1/8
|
|
1672
|
-
have none and are controls. Deferred evaluation reduces median paired time
|
|
1673
|
-
by 2.46%, 5.15% and 2.03% at M16/128/512; asynchronous evaluation reduces it
|
|
1674
|
-
by 2.39%, 6.56% and 2.89%. Every affected pair improves. M128/512 peak MLX
|
|
1675
|
-
allocation grows by about 362/380 MB for deferral and 368/403 MB for async.
|
|
1676
|
-
These M4 Pro 24 GB diagnostics do not remove the memory gate.
|
|
1677
|
-
Evidence: `reports/qwen38-rd/trellis-v13-boundary-full-model{,-review}.json`.
|
|
1678
|
-
|
|
1679
|
-
The serial HTTP follow-up completes six balanced three-arm blocks with 18
|
|
1680
|
-
clean server exits, fixed sources and 126 requests. All 84 paired response
|
|
1681
|
-
texts, usage counts and finish reasons match. At 128/512 prompt tokens,
|
|
1682
|
-
deferral reduces median paired TTFT by 2.88%/0.53%; asynchronous submission
|
|
1683
|
-
reduces it by 4.10%/1.41%, with all six pairs improving in each cell. Async
|
|
1684
|
-
complete-response time falls by 0.90%/0.67%. Six-token TTFT and all decode
|
|
1685
|
-
cells stay approximately flat. Per-server peak RSS is approximately flat;
|
|
1686
|
-
the separately measured MLX transient-allocation increase still applies.
|
|
1687
|
-
Evidence: `trellis-v13-boundary-http-serial{,-review}.json`.
|
|
1688
|
-
|
|
1689
|
-
The saved-agent pressure gate rejects unrestricted deferral on this M4.
|
|
1690
|
-
The synchronous control completes all seven requests, including 14,465 prompt
|
|
1691
|
-
tokens, 12,953 cached tokens and a 512-token response, followed by a durable
|
|
1692
|
-
SSD flush and clean exit. Deferral preserves the first five responses but
|
|
1693
|
-
fails on the sixth request at 12,954 prompt tokens. Native tracing reports
|
|
1694
|
-
Metal command-buffer insufficient memory and the child exits with SIGTRAP.
|
|
1695
|
-
Sources remain fixed. The asynchronous and mapped arms had not started;
|
|
1696
|
-
their outcome cannot be inferred from this failure. Keep per-projection
|
|
1697
|
-
barriers while testing bounded alternatives. Evidence:
|
|
1698
|
-
`qwen-long-boundary-serial{,-review}.json` and its deferred server trace.
|
|
1699
|
-
|
|
1700
|
-
A fresh synchronous/asynchronous pair reaches the same result. The control
|
|
1701
|
-
again completes all seven requests with a durable final flush and clean exit.
|
|
1702
|
-
Async preserves the first five responses, then fails the sixth request with
|
|
1703
|
-
the same Metal insufficient-memory error. Source fingerprints remain fixed.
|
|
1704
|
-
Thus both unrestricted alternatives fail this pressure gate despite their
|
|
1705
|
-
short-prompt timing gains. A further candidate must retain blocking evaluation
|
|
1706
|
-
when available headroom is insufficient. Evidence:
|
|
1707
|
-
`qwen-long-async-serial{,-review}.json` and its async server trace.
|
|
1708
|
-
|
|
1709
|
-
The next policy submits asynchronously only while MLX active allocation is
|
|
1710
|
-
below 75% of the device's recommended working set, retaining blocking
|
|
1711
|
-
evaluation above that ceiling. It still evaluates at the existing layer
|
|
1712
|
-
boundary. All 35 native warm/measured cases preserve logits, live cache bytes
|
|
1713
|
-
and continuation. The short native sweep stays below the ceiling and exercises
|
|
1714
|
-
asynchronous submission at every expanded projection. Median paired time
|
|
1715
|
-
falls 2.00%/5.40%/3.07% at M16/128/512, with six wins per cell; M1/8 controls
|
|
1716
|
-
are approximately flat. The short sweep does not exercise the pressure fallback.
|
|
1717
|
-
Evidence: `trellis-v13-bounded-full-model{,-review}.json`.
|
|
1718
|
-
|
|
1719
|
-
The bounded policy also passes a fresh serial saved-agent pair. All seven
|
|
1720
|
-
responses and usage counts match, both servers exit cleanly, and the final
|
|
1721
|
-
SSD flush reports durable state with no pending, missing or failed writes.
|
|
1722
|
-
The candidate submits 1,152 expanded projections asynchronously and evaluates
|
|
1723
|
-
2,112 synchronously, exercising both branches. Its maximum observed active
|
|
1724
|
-
allocation is 17.216 GB; the 14.302 GB threshold controls scheduling, not total
|
|
1725
|
-
allocation. Peak sampled RSS is 13.370/13.743 GB for control/candidate.
|
|
1726
|
-
This single pair establishes the pressure gate, not a timing or RSS win.
|
|
1727
|
-
The default scheduler pressure gate remains.
|
|
1728
|
-
Evidence: `qwen-long-bounded-serial{,-review}.json`.
|
|
1729
|
-
|
|
1730
|
-
Six fresh serial HTTP pairs then complete 84 requests with fixed sources,
|
|
1731
|
-
clean exits and all 42 paired responses identical. The bounded policy reduces
|
|
1732
|
-
median paired TTFT by 4.42%/1.78% at 128/512 prompt tokens, with six wins in
|
|
1733
|
-
each cell. Complete-response time falls 0.95%/0.80%; decode speed and the
|
|
1734
|
-
six-token control are approximately flat. Median per-server sampled peak
|
|
1735
|
-
RSS is 12.364/12.362 GB for synchronous/bounded evaluation. Each candidate
|
|
1736
|
-
server exercises 768 asynchronous boundaries in this short sweep. These M4
|
|
1737
|
-
diagnostics retain the separate native transient-allocation increase and
|
|
1738
|
-
do not replace the default scheduler or quiet-machine gates. Evidence:
|
|
1739
|
-
`trellis-v13-bounded-http-serial{,-review}.json`.
|
|
1740
|
-
|
|
1741
|
-
The actual continuous-scheduler follow-up completes six pairs and 84 requests.
|
|
1742
|
-
All 42 paired response texts, usage counts and finish reasons match; each
|
|
1743
|
-
request reports `"batched"` and increments scheduler submissions. Sources
|
|
1744
|
-
remain fixed and all 12 servers exit cleanly. Median paired TTFT falls
|
|
1745
|
-
4.46% at 128 tokens with six wins and 1.30% at 512 with five wins.
|
|
1746
|
-
Complete-response time falls 0.96%/0.60%. Decode and six-token controls remain
|
|
1747
|
-
approximately flat; median sampled peak RSS is 12.381/12.352 GB. MLX is seeded
|
|
1748
|
-
to 42 at startup with greedy sampling; request-level seed is omitted because
|
|
1749
|
-
it selects serial placement. Evidence:
|
|
1750
|
-
`trellis-v13-bounded-http-default{,-review}.json`.
|
|
1751
|
-
|
|
1752
|
-
The continuous saved-agent gate also passes all seven paired responses with
|
|
1753
|
-
fixed sources. Every request reports the batched lane and a scheduler
|
|
1754
|
-
submission. Both servers finish durable SSD flushes with no pending, missing
|
|
1755
|
-
or failed writes and exit cleanly. The candidate again uses 1,152 async and
|
|
1756
|
-
2,112 blocking expansion boundaries; maximum observed active allocation is
|
|
1757
|
-
17.265 GB. Sampled peak RSS is 12.842/12.992 GB for control/candidate.
|
|
1758
|
-
This one pair closes the prototype's continuous pressure gate, not a timing
|
|
1759
|
-
or memory-saving claim. Evidence: `qwen-long-bounded-default{,-review}.json`.
|
|
1760
|
-
|
|
1761
|
-
The integrated opt-in `MLX_BUN_TRELLIS_ASYNC_EXPAND` now applies that policy
|
|
1762
|
-
to variant 13. It reads the execution's existing runtime snapshot and caches
|
|
1763
|
-
only the fixed device threshold per linear layer. It preserves layer barriers
|
|
1764
|
-
and blocks expanded projections above the threshold. Default remains off;
|
|
1765
|
-
other variants retain their current behavior. Typechecks, hygiene and all
|
|
1766
|
-
1,822 model-free tests pass. Integrated native, both short HTTP repeats and both
|
|
1767
|
-
long-agent pressure gates pass on the M4 Pro. Evidence:
|
|
1768
|
-
`trellis-async-integrated-{typecheck,hygiene,model-free}.txt`.
|
|
1769
|
-
|
|
1770
|
-
The integrated native sweep preserves all 35 logit/live-cache/continuation
|
|
1771
|
-
cases with fixed sources. An observer records the implementation's own async
|
|
1772
|
-
and blocking calls without substituting a scheduling decision. Median paired
|
|
1773
|
-
forward time falls 2.09%/6.19%/2.80% at M16/128/512, with all six pairs
|
|
1774
|
-
improving. M1/M8 exercise no expansion boundaries; their paired timings are
|
|
1775
|
-
+1.16%/-0.21%, so the M1 control variation remains visible. M128/512 peak
|
|
1776
|
-
MLX allocation again grows about 368/403 MB. Integrated serving and pressure
|
|
1777
|
-
gates remain. Evidence: `trellis-async-production-full-model{,-review}.json`.
|
|
1778
|
-
|
|
1779
|
-
The integrated serial HTTP repeat also passes all 42 paired responses across
|
|
1780
|
-
12 clean server exits with fixed sources. Median paired TTFT falls 4.00% at
|
|
1781
|
-
128 prompt tokens in all six pairs and 1.43% at 512 in five pairs. Request
|
|
1782
|
-
wall time falls 0.88%/0.63%; decode and the six-token control remain flat.
|
|
1783
|
-
Median sampled peak RSS is 12.331/12.355 GB for control/candidate. Each
|
|
1784
|
-
candidate server exercises 768 async boundaries, with no blocking fallback
|
|
1785
|
-
in these short prompts. These are M4 Pro diagnostics; pressure and quiet
|
|
1786
|
-
acceptance remain. Evidence:
|
|
1787
|
-
`trellis-async-production-http-serial{,-review}.json`.
|
|
1788
|
-
|
|
1789
|
-
The integrated continuous repeat passes another 42 paired responses and
|
|
1790
|
-
12 clean exits with fixed sources. Every request reports the batched lane
|
|
1791
|
-
and exactly one scheduler submission. Median paired TTFT falls 3.96%/1.40%
|
|
1792
|
-
at 128/512 prompt tokens, with six/five improving pairs. Wall time falls
|
|
1793
|
-
0.87%/0.63% in five/four pairs. Decode and the six-token control remain flat.
|
|
1794
|
-
Median sampled peak RSS is 12.353/12.349 GB. Short prompts exercise the async
|
|
1795
|
-
branch only; integrated long-agent pressure gates are next. Evidence:
|
|
1796
|
-
`trellis-async-production-http-default{,-review}.json`.
|
|
1797
|
-
|
|
1798
|
-
The integrated serial saved-agent gate preserves all seven paired responses
|
|
1799
|
-
and usage records with fixed sources and clean exits. Both SSD flushes finish
|
|
1800
|
-
durably with no pending, missing or failed snapshots and a longest durable
|
|
1801
|
-
prefix of 14,976 tokens. The candidate uses 1,151 async and 2,113 blocking
|
|
1802
|
-
boundaries; its maximum observed active allocation is 17.227 GB. Sampled peak
|
|
1803
|
-
RSS is 13.550/13.544 GB for control/candidate. The longest request prefills
|
|
1804
|
-
14,465 tokens, reuses 12,953 and generates 512. This is a single pressure
|
|
1805
|
-
gate under system swap, without a performance or memory-saving claim.
|
|
1806
|
-
Continuous pressure acceptance remains. Evidence:
|
|
1807
|
-
`trellis-async-production-long-serial{,-review}.json`.
|
|
1808
|
-
|
|
1809
|
-
The integrated continuous saved-agent pair also passes all seven responses,
|
|
1810
|
-
usage records, source hashes and clean exits. Every request uses the batched
|
|
1811
|
-
lane with one scheduler submission. Both final flushes are durable, with
|
|
1812
|
-
14 snapshots, a 14,976-token longest prefix and no pending, missing or failed
|
|
1813
|
-
writes. The candidate uses 1,152 async and 2,112 blocking boundaries; maximum
|
|
1814
|
-
observed active allocation is 17.253 GB. Sampled peak RSS is 12.994/12.873 GB
|
|
1815
|
-
for control/candidate. This completes the integrated M4 pressure gates; the
|
|
1816
|
-
one-pair RSS difference is not a memory-saving claim. Broader callers, combined
|
|
1817
|
-
optimizations and quiet M4 Pro acceptance remain. Evidence:
|
|
1818
|
-
`trellis-async-production-long-default{,-review}.json`.
|
|
1819
|
-
|
|
1820
|
-
Variant 10 shares scatter weight decoding and scales across M=2..4 in
|
|
1821
|
-
`src/model/trellis-shared-scatter.ts`. It uses aligned k3 decoding where
|
|
1822
|
-
eligible and the incumbent packed-word mapping for other bit widths. Every
|
|
1823
|
-
output retains its row/FMA order, split boundaries, sum and cast. M=1 uses
|
|
1824
|
-
the existing variant-8 path; M>4 keeps the projection barriers. Variant 10
|
|
1825
|
-
does not combine the variant-9 memory experiment.
|
|
1826
|
-
|
|
1827
|
-
Real k2/k3/k4 screens improve down and complete-MLP time with exact observed
|
|
1828
|
-
outputs. Unit checks cover both axes, bf16/f32 inputs, M=1..5 and the complete
|
|
1829
|
-
MLP. The packed 27B passes exact logits, live state and continuation checks
|
|
1830
|
-
at M=1..5. Six native A/B blocks against variant 8 improve M=2..4 while M=1
|
|
1831
|
-
is unchanged. Raw evidence is in `shared-scatter-screen/`,
|
|
1832
|
-
`shared-scatter-all-screen/` and `variant10-full-model.json` under
|
|
1833
|
-
`reports/qwen38-rd/`. The native gate accepts
|
|
1834
|
-
`MLX_BUN_TRELLIS_AB_BASELINE=8 MLX_BUN_TRELLIS_AB_VARIANT=10`.
|
|
1835
|
-
|
|
1836
|
-
Variant 11 combines variant 10 with tiled axis-1 prefill at M=5..32.
|
|
1837
|
-
`src/model/trellis-tiled-prefill.ts` reconstructs bf16 weights in threadgroup
|
|
1838
|
-
storage and consumes them through SIMD-group matrix operations. Its shared
|
|
1839
|
-
operation accepts other compatible matrix shapes; automatic experimental
|
|
1840
|
-
dispatch is limited to the measured 5120-to-17408 geometry, bf16, T=256,
|
|
1841
|
-
L=12 and k=2/3/4. Down projections keep stock expansion and matmul.
|
|
1842
|
-
Dense expansion and layer-end evaluation boundaries remain in place.
|
|
1843
|
-
|
|
1844
|
-
The initial computed-code prototype failed the full model despite matching
|
|
1845
|
-
the sampled synthetic matrices. Expansion consumes the precise host LUT,
|
|
1846
|
-
whereas variant-6 packed matvec uses an unrefined reciprocal. Refining that
|
|
1847
|
-
reciprocal before scaling reproduces expansion's bf16 weights. The corrected
|
|
1848
|
-
prototype passes logits, live cache state and continuation at M=1/4/5/8/16/32;
|
|
1849
|
-
six paired native blocks improve M=5..32 without a larger observed peak.
|
|
1850
|
-
Evidence: `trellis-tiled-initial-review.json`,
|
|
1851
|
-
`trellis-tiled-refined-gate-model.json` and its review under
|
|
1852
|
-
`reports/qwen38-rd/`. The integrated kernel repeats the full-model gate in
|
|
1853
|
-
`variant11-full-model.json`. Six process A/B blocks per serving method also
|
|
1854
|
-
improve first-token and complete-request latency on one six-token raw prompt,
|
|
1855
|
-
with identical output at eight and 64 generated tokens. Serial and continuous
|
|
1856
|
-
B=1 paths agree; this does not test concurrent users. Evidence:
|
|
1857
|
-
`trellis-v11-http.json` and its review. Broader native/HTTP workloads, pressure
|
|
1858
|
-
replay and quiet M4 Pro acceptance remain required. Variant 6 remains the default.
|
|
1859
|
-
|
|
1860
|
-
Variant 12 also reconstructs axis-0 weights inside split-K matrix tiles at
|
|
1861
|
-
M=5..8. The shared `trellis-splitk-prefill.ts` operation follows MLX 0.31.2's
|
|
1862
|
-
partition geometry, float partials and ordered final sum, then rounds to bf16.
|
|
1863
|
-
The measured dispatch profile covers 17408-to-5120 matrices at k2/k3/k4.
|
|
1864
|
-
It avoids the dense down-projection weight allocation. Dense expansion and
|
|
1865
|
-
layer evaluation boundaries remain. Larger M, wider tiles, padding and a device
|
|
1866
|
-
lookup table did not give a consistent advantage in the initial sweep.
|
|
1867
|
-
|
|
1868
|
-
Other-shape unit checks include transposed inputs and a longer final K
|
|
1869
|
-
partition. Both the prototype and integrated packed 27B preserve logits,
|
|
1870
|
-
live state and continuation. Six paired integrated blocks improve M=5/8;
|
|
1871
|
-
M=1..4/9/16/32 retain their existing path and timing. Evidence:
|
|
1872
|
-
`trellis-splitk-screen-review.json`, `trellis-splitk-tuning-review.json`,
|
|
1873
|
-
`trellis-splitk-full-model-review.json` and `variant12-full-model.json` under
|
|
1874
|
-
`reports/qwen38-rd/`. Combined native and HTTP results are recorded in
|
|
1875
|
-
decode-speed-program §7; quiet-machine acceptance remains open.
|
|
1876
|
-
|
|
1877
|
-
The calibrated operation trace led to a second tile pass. At M=5..8, both
|
|
1878
|
-
direct kernels now use eight output rows and place all four SIMD groups
|
|
1879
|
-
across columns. This removes unused row work while preserving each output's
|
|
1880
|
-
matrix products, accumulation order, weight rounding and split reduction.
|
|
1881
|
-
Contiguous packed reads with transposed threadgroup writes were slower in
|
|
1882
|
-
the controlled screen; neither that layout nor padding is retained.
|
|
1883
|
-
|
|
1884
|
-
Direct tiles also avoid per-projection evaluation. They keep activations and
|
|
1885
|
-
bounded partials without constructing a dense weight matrix, so the existing
|
|
1886
|
-
model layer boundary bounds their graph. Expansion paths retain their original
|
|
1887
|
-
projection evaluations. A four-arm full-model experiment separates tile
|
|
1888
|
-
geometry from synchronization: all logits, live cache bytes and continuation
|
|
1889
|
-
match across six blocks at M=1/4/5/8/16/32/128. The combination improves the
|
|
1890
|
-
eligible shapes with a small temporary-memory increase. A subsequent six-pair
|
|
1891
|
-
check at M=5/8 adds the smaller split-K tile with exact outputs and unchanged
|
|
1892
|
-
peak allocation. These changes remain within the experimental variants;
|
|
1893
|
-
variant 6 is unchanged. Evidence: `trellis-tile-layout-screen-review.json`,
|
|
1894
|
-
`trellis-tile-full-model-review.json`,
|
|
1895
|
-
`trellis-splitk-bm8-other-bits-review.json` and
|
|
1896
|
-
`trellis-splitk-bm8-full-model-review.json` under `reports/qwen38-rd/`.
|
|
1897
|
-
The first layout screen also changed evaluation boundaries and is excluded
|
|
1898
|
-
from isolated-kernel speed attribution. The integrated operation passes
|
|
1899
|
-
targeted units and ten old/new full-model append lengths. Six subsequent
|
|
1900
|
-
HTTP process pairs improve actual eight-request throughput and B=1 TTFT,
|
|
1901
|
-
with identical responses and verified scheduler activity. Evidence:
|
|
1902
|
-
`trellis-tile-integrated-forward-review.json` and `trellis-tile-http-review.json`.
|
|
1903
|
-
Six old/new native process pairs also preserve every emitted ID and finish
|
|
1904
|
-
reason, with lower first-token latency and a small complete-request gain;
|
|
1905
|
-
single-row decode is unchanged. All workers complete with fixed source hashes.
|
|
1906
|
-
Evidence: `trellis-tile-native-review.json`. These remain loaded-machine
|
|
1907
|
-
diagnostics, with quiet M4 Pro acceptance pending.
|
|
1908
|
-
|
|
1909
|
-
A corrected larger-prefill sweep checks ten tile geometries, packed-load
|
|
1910
|
-
orders and threadgroup padding choices on actual k3 gate/down matrices at
|
|
1911
|
-
M=128 and 512. Every one of the 40 cases reproduces the expansion-plus-matmul
|
|
1912
|
-
output bytes, but none beats that existing path in six AB/BA timing pairs.
|
|
1913
|
-
Both arms include output evaluation and GPU synchronization; the candidate
|
|
1914
|
-
gets no pipeline-only timing advantage. Larger tiles and coalesced packed
|
|
1915
|
-
loads therefore remain rejected for these measured shapes. Keep MLX's native
|
|
1916
|
-
matrix multiplication and investigate the separate expansion operation.
|
|
1917
|
-
Evidence: `trellis-large-prefill-screen.json` and
|
|
1918
|
-
`trellis-large-prefill-screen-review.json` in the campaign report directory.
|
|
1919
|
-
|
|
1920
|
-
A source audit also rejects an assumed fp16 throughput shortcut. In pinned
|
|
1921
|
-
[MLX 0.31.2 Steel GEMM](https://github.com/ml-explore/mlx/blob/v0.31.2/mlx/backend/metal/kernels/steel/gemm/kernels/steel_gemm_fused.metal),
|
|
1922
|
-
both half and bf16 instantiations explicitly select float accumulation.
|
|
1923
|
-
`BlockMMA` loads both input tiles into float matrix fragments before the
|
|
1924
|
-
matrix multiply. Changing storage dtype alone therefore does not select a
|
|
1925
|
-
half-fragment multiply in this path. This is a dispatch/arithmetic finding,
|
|
1926
|
-
not a measured bf16-versus-fp16 performance comparison; other native paths
|
|
1927
|
-
need their own inspection before making the same claim.
|
|
1928
|
-
|
|
1929
|
-
Variant 13 builds on variant 12 with `trellis-vector-expand.ts`: four adjacent
|
|
1930
|
-
weights share two packed-word reads and the scale. An unrolled loop extracts
|
|
1931
|
-
their circular windows and refines the computed code value to reproduce the
|
|
1932
|
-
host f32 LUT before bf16 rounding. MLX's matrix multiplication and each dense
|
|
1933
|
-
projection's evaluation boundary remain unchanged. The operation is independent
|
|
1934
|
-
of the model; dispatch requires bf16 output, k2/k3/k4, T=256 and L=12. Other
|
|
1935
|
-
packing/dtypes retain their existing expansion.
|
|
1936
|
-
|
|
1937
|
-
The actual-weight screen passes all 96 configurations across three bit widths
|
|
1938
|
-
and both projection axes. Four values per thread with 128 threads gives a
|
|
1939
|
-
consistent isolated improvement. Explicit wider output stores add little in
|
|
1940
|
-
a subsequent exact 24-case screen and are not retained. The initial full-model
|
|
1941
|
-
prototype preserves logits, all live cache bytes and continuation in seven
|
|
1942
|
-
blocks at M=1/8/16/128/512, including six measured AB/BA pairs. Eligible prefills
|
|
1943
|
-
improve; M=1 and M=8 retain the variant-12 path. The integrated kernel repeats
|
|
1944
|
-
those checks and passes the repository parity harness, whose variant-13 arm
|
|
1945
|
-
also exercises larger prefills. All HTTP responses match in two existing-suite
|
|
1946
|
-
pairs, but their timing is mostly flat; see decode-speed-program §7. Closed
|
|
1947
|
-
research helpers are removed after recording their results. These are M4 Pro
|
|
1948
|
-
diagnostics, with the
|
|
1949
|
-
default still variant 6. Evidence: `trellis-vector-expand-screen-review.json`,
|
|
1950
|
-
`trellis-vector-store-screen-review.json` and
|
|
1951
|
-
`trellis-vector-expand-full-model-review.json` in the campaign directory.
|
|
1952
|
-
|
|
1953
|
-
The R6 layout screen rearranges groups of coded blocks across input rows,
|
|
1954
|
-
preserving the codes, payload size, arithmetic and split-K reduction order.
|
|
1955
|
-
All six actual k3 down-projection layouts invert to the original code bytes
|
|
1956
|
-
and produce identical output bytes. Two groupings improve the isolated
|
|
1957
|
-
operation; the original-order control is flat. Both full-model groupings
|
|
1958
|
-
preserve every eligible matrix's code bytes, logits, live cache state and
|
|
1959
|
-
continuation, with a small single-token forward improvement. Group two is
|
|
1960
|
-
simpler and group ten offers no additional model gain. The prototype
|
|
1961
|
-
retains both layouts to alternate A/B arms, so its additional residency and
|
|
1962
|
-
packing cost are recorded separately. Six subsequent production-generation
|
|
1963
|
-
pairs with a fixed seed and 64 outputs preserve every emitted ID, final live
|
|
1964
|
-
cache byte and continuation logit. The small gain survives the complete
|
|
1965
|
-
generation loop. Six fresh-server pairs in each of serial and default
|
|
1966
|
-
scheduling then preserve all 60 paired responses. Both prompt lengths retain
|
|
1967
|
-
the small decode and complete-request improvement; the default scheduler's
|
|
1968
|
-
longer-prompt TTFT is approximately flat. All servers exit cleanly, and
|
|
1969
|
-
telemetry proves the configured execution path. Both arms retain the extra
|
|
1970
|
-
code copy, so their flat RSS comparison is not a memory improvement. A stored
|
|
1971
|
-
format usable by every prefill, scatter and expansion reader remains open.
|
|
1972
|
-
No artifact or production dispatch is changed. Evidence:
|
|
1973
|
-
`trellis-block-interleave-screen-review.json` and
|
|
1974
|
-
`trellis-block-interleave-full-model-{g2,g10}-review.json`, plus
|
|
1975
|
-
`trellis-block-interleave-native-generation-g2-interface-review.json` in the
|
|
1976
|
-
campaign directory, plus `trellis-block-interleave-http-{serial,default}-review.json`.
|
|
1977
|
-
The first generation driver used the wrong iterator
|
|
1978
|
-
interface and failed before timing; its failed report remains separate.
|
|
1979
|
-
|
|
1980
|
-
The replacement-layout reader prototype now preserves all 27 actual-matrix
|
|
1981
|
-
projection cases across bf16/f16/f32 and three dense expansions. It covers
|
|
1982
|
-
single-token and shared M2..4 scatter, M5..8 split-K and larger dense prefills,
|
|
1983
|
-
through M512. The operation timings show small-batch gains with marginal
|
|
1984
|
-
prefill regressions. The first full-model reader check preserves 63 cases,
|
|
1985
|
-
but its wrapper changes input disposal and output evaluation order. A repeat
|
|
1986
|
-
with the incumbent order preserves all 35 cases and retains the single-token
|
|
1987
|
-
gain; M8/16 are approximately flat, while M128/512 are slightly slower.
|
|
1988
|
-
Changing expansion threadgroup traversal preserves all five operation cases;
|
|
1989
|
-
moderate row tiles improve that reader slightly, while fully prioritizing
|
|
1990
|
-
contiguous code reads loses. The revised traversal preserves all 35 full-model
|
|
1991
|
-
cases, retains the small single-token gain and has approximately flat prefills
|
|
1992
|
-
in that repeat. The next gate uses a separate stored artifact through serving,
|
|
1993
|
-
with every reader consuming one resident code copy. Evidence:
|
|
1994
|
-
`trellis-interleaved-readers-screen-review.json`,
|
|
1995
|
-
`trellis-interleaved-readers-full-model-count-review.json`,
|
|
1996
|
-
`trellis-interleaved-readers-order-full-model-review.json`,
|
|
1997
|
-
`trellis-interleaved-vector-schedule-screen-review.json` and
|
|
1998
|
-
`trellis-interleaved-readers-schedule-full-model-review.json`. Those prototype
|
|
1999
|
-
measurements keep both code copies resident; the stored-artifact gate below
|
|
2000
|
-
removes that extra allocation.
|
|
2001
|
-
|
|
2002
|
-
The integrated reader accepts an optional U32 code shape
|
|
2003
|
-
`[coded_columns / 512, stored_rows, 48]` for k3, T256, L12, 1MAD, axis0.
|
|
2004
|
-
Each 48-word row holds two original coded blocks; block groups precede rows.
|
|
2005
|
-
Scales retain their original one-value-per-stored-row representation. The
|
|
2006
|
-
existing 2D format retains its addressing. Shape validation rejects other
|
|
2007
|
-
3D geometries, and every scatter/expansion reader selects its address formula
|
|
2008
|
-
at compile time. Variant 13 also uses the measured moderate row traversal
|
|
2009
|
-
when rows divide its tile size; other shapes retain the original traversal.
|
|
2010
|
-
No request, scheduler or state interface changes. Focused tests preserve all
|
|
2011
|
-
14 variants, bf16/f16/f32 outputs, strided inputs and expansion, with explicit
|
|
2012
|
-
split-K partition-tail and malformed-format checks. Broader artifact and
|
|
2013
|
-
serving acceptance remain open; this is not a default artifact change. All three
|
|
2014
|
-
typechecks, hygiene and the complete model-free tier pass. A separately
|
|
2015
|
-
written artifact verifies all converted code inverses and every unchanged
|
|
2016
|
-
tensor payload. Native and HTTP comparisons load one artifact per process,
|
|
2017
|
-
without runtime repacking or duplicate codes. Closed layout prototype helpers
|
|
2018
|
-
are removed; their raw reports remain. The first native artifact driver fails
|
|
2019
|
-
before spawning a child because of an unsupported stdout option; its corrected
|
|
2020
|
-
file-descriptor version has a separate report. Evidence:
|
|
2021
|
-
`trellis-interleave-integrated-tests.txt`,
|
|
2022
|
-
`trellis-interleave-integrated-tail-tests.txt`,
|
|
2023
|
-
`trellis-interleave-model-free.txt` and `trellis-interleave-artifact-review.json`.
|
|
2024
|
-
The converter's header padding does not determine the kernel buffer's
|
|
2025
|
-
alignment. `Weights` uses native MLX safetensors loading, whose pinned
|
|
2026
|
-
`Load::eval_cpu` allocates its output buffer and reads the payload into it.
|
|
2027
|
-
The paired kernels therefore consume MLX-owned buffers in both artifacts;
|
|
2028
|
-
they do not access the file mapping at the tensor's raw header offset.
|
|
2029
|
-
The packed quantizer's optional `--interleave-codes` switch produces this
|
|
2030
|
-
layout for eligible tensors, including row-major tensors read through
|
|
2031
|
-
`--reuse`. Other tensors retain their layout. The shared codec helper only
|
|
2032
|
-
reorders words; the quantizer records the number of interleaved modules.
|
|
2033
|
-
Six fresh-process native artifact pairs now preserve all warm/measured
|
|
2034
|
-
forward logits, live states, continuations and generation IDs. Single-token
|
|
2035
|
-
and M4 forwards improve in every pair; M8 is slightly slower, M16 improves,
|
|
2036
|
-
and longer prefills are mixed. Complete 64-token generation improves in every
|
|
2037
|
-
pair with equal peak MLX allocation. One slower M512 sample remains included.
|
|
2038
|
-
This removes the prototype's duplicate-code residency from the comparison;
|
|
2039
|
-
HTTP RSS and timing have their own gate below. Evidence:
|
|
2040
|
-
`trellis-interleave-artifact-native-fd-review.json` and
|
|
2041
|
-
`trellis-interleave-encoder-tests.txt`. Native research helpers are removed
|
|
2042
|
-
after recording the finding; the artifact converter is superseded by the
|
|
2043
|
-
quantizer's layout option and the retained codec helper.
|
|
2044
|
-
|
|
2045
|
-
Six fresh-server serial HTTP artifact pairs preserve all 42 paired responses,
|
|
2046
|
-
including warmups, usage, finish reasons and stream completion. Each process
|
|
2047
|
-
loads only its selected artifact, uses production readers at variant 13, and
|
|
2048
|
-
exits cleanly. Source hashes remain fixed. Decode improves in every measured
|
|
2049
|
-
pair at each actual prompt length of 6, 128 and 512 tokens; TTFT changes are
|
|
2050
|
-
small or mixed. RSS is approximately flat, with no retained duplicate code
|
|
2051
|
-
buffer. These M4 Pro diagnostics use cache-disabled requests and do not
|
|
2052
|
-
establish cached, pressure or quiet-machine acceptance. Six further pairs
|
|
2053
|
-
under the default continuous scheduler preserve another 42 paired responses
|
|
2054
|
-
with clean exits and fixed sources. Telemetry confirms the configured batch
|
|
2055
|
-
capacity of eight, one submitted row per request and no remaining active or
|
|
2056
|
-
pending rows. These are single-prompt measurements. Decode improves in every
|
|
2057
|
-
pair at all three lengths; TTFT changes remain small or mixed, and RSS is
|
|
2058
|
-
approximately flat. Evidence:
|
|
2059
|
-
`trellis-interleave-artifact-http-{serial,default}-review.json`.
|
|
2060
|
-
The completed HTTP research helper is removed; raw responses, telemetry,
|
|
2061
|
-
source hashes and server logs remain in the reports.
|
|
2062
|
-
|
|
2063
|
-
A separate M<=8 crossover prototype improves complete-MLP time at M=5/8
|
|
2064
|
-
but changes output bytes for every tested bit width. It replaces expanded
|
|
2065
|
-
bf16 matrix arithmetic with packed f32 code-times-scale arithmetic, so this
|
|
2066
|
-
is a Lab precision change, not an exact optimization. The prototype is not
|
|
2067
|
-
retained in production dispatch. `reports/qwen38-rd/m8-screen/` records the
|
|
2068
|
-
timings and numerical differences. Quality and long-state checks must precede
|
|
2069
|
-
any use of the larger crossover or equivalent small-chunk span splitting.
|
|
2070
|
-
|
|
2071
|
-
# Open items (weights leg — mirrors the PLAN.md phase boxes; PLAN.md owns status)
|
|
2072
|
-
|
|
2073
|
-
- **W5 calibration composition** — PLAN sub-boxes W5a (0.8B matrix), W5b
|
|
2074
|
-
(allocation axis, pick the best ≤4.5 bpw recipe), W5c (chunked 27B
|
|
2075
|
-
production run + gates) remain unchecked in PLAN.md although the results
|
|
2076
|
-
above were measured; closing them is a PLAN.md edit, not new work.
|
|
2077
|
-
Deferred lever inside W5: learned R (SpinQuant Cayley-SGD) — only if a
|
|
2078
|
-
random-R recipe wins first.
|
|
2079
|
-
- **W6 release — SINGLE REPO:** one artifact = quantized trunk + bf16 vision
|
|
2080
|
-
(in-main + optiq sidecar) + folded MTP companion at `mtp/`. Engine landed
|
|
2081
|
-
(`--draft-kind mtp` bundled resolution). Publish the winner via
|
|
2082
|
-
`mlx-bun upload`; awaiting Josh's go. Card notes owed: M1-vs-M4 3-bit
|
|
2083
|
-
speed guidance; MTP not claimed lossless; adapters trained on the artifact
|
|
2084
|
-
are rotation-basis-married to it.
|
|
2085
|
-
- **W6.5 dogfood gate (publish blocker, ahead of W6 upload):** open
|
|
2086
|
-
sub-items — `mlx-bun perplexity` on qwen3_5 (SSMCache.advance stub);
|
|
2087
|
-
dogfood close-out (re-score a ~30-question GPQA subset through mlx-bun and
|
|
2088
|
-
match the mlx-lm scores); 24 GB near-ceiling UX (detect weightsBytes ≈
|
|
2089
|
-
default iogpu wired limit and PRINT the sysctl advice up front instead of
|
|
2090
|
-
dying mid-request — clamp/advise, never refuse).
|
|
2091
|
-
- **W7 Pareto frontier (Josh's frame: "we shouldn't operate in a vacuum"):**
|
|
2092
|
-
(intelligence × tok/s × memory) for local models on consumer Macs at the
|
|
2093
|
-
24 GB and 32 GB budgets, defended against NON-OURS points: ours
|
|
2094
|
-
{GPTQ-4bit, TQ-mixed} × mlx-bun; published {OptiQ-4bit, mlx-community
|
|
2095
|
-
RTN-4bit} × {mlx-bun, mlx-lm}; cross-ecosystem anchor {GGUF Q4_K_M ×
|
|
2096
|
-
llama.cpp/Ollama}. Still owed: quiet-box tps per arm (labeled
|
|
2097
|
-
host/chip/RAM), peak footprint + max-context-that-fits per budget, the
|
|
2098
|
-
GGUF anchor. The KV axis composes: `--kv-quant turbo` (k8v3) is the
|
|
2099
|
-
context-headroom lever at fixed weight bpw. `scripts/turboquant/
|
|
2100
|
-
farm-setup.sh` provisions a rented Apple-silicon worker for these runs.
|
|
2101
|
-
- **Q campaign (sub-4 bpw):** Q3 passed its gate (finding 5); Q2b packed
|
|
2102
|
-
format landed and measured (12.1 GiB, KL 0.1550 through the engine, 9.3
|
|
2103
|
-
tok/s vs 18.9 on M1 Max — "Q2b measured"); the down_proj axis is settled the
|
|
2104
|
-
OTHER way (input-dim coding buys +22% decode but reintroduces the raw-GSM
|
|
2105
|
-
EOS cliff, 29/50 vs 44/50 strictly nested — the coded axis must be the
|
|
2106
|
-
rotated one). Owed: a 2.75-budget arm
|
|
2107
|
-
for the size axis; task columns on q2a/q2b for the ladder's completeness;
|
|
2108
|
-
root-cause the rawGSM EOS cliff on the unrotated affine arm. Source bf16,
|
|
2109
|
-
all Q artifacts, Hessians live on the external `/Volumes/MLX-Models` volume.
|
|
2110
|
-
- **Engine follow-up from the M4 rows:** serve should scale
|
|
2111
|
-
prefillChunkSize from fit.ts headroom automatically; prefill-rate
|
|
2112
|
-
oracle comparison vs mlx-lm same-box.
|
|
2113
|
-
- **KV-leg projector:** `KvScheme.bytesAt` bills turbo as bf16; a packed-
|
|
2114
|
-
layout projector would let admission advertise the real window.
|
|
2115
|
-
- **Queued post-campaign (GPU owned by certification until then):** DSpark×27B
|
|
2116
|
-
Track A (confidence-scheduled verification on the stock MTP head) and
|
|
2117
|
-
Track B (multi-token drafter on the TQ trunk; gate: beat MTP's 0.68
|
|
2118
|
-
generalizing acceptance or drop); ORPO LoRA on the TQ 27B (QLoRA shape:
|
|
2119
|
-
frozen 17 GB base + bf16 adapters; first step a one-layer-backward memory
|
|
2120
|
-
probe). Designs live in docs/design/speculative-decoding.md §"27B program".
|
|
2121
|
-
|
|
2122
|
-
## Invariants (both legs)
|
|
2123
|
-
|
|
2124
|
-
- Rotation never enters the runtime graph for weights; for KV it enters only
|
|
2125
|
-
inside the cache class (dequantize-on-fetch or deferred un-rotation at the
|
|
2126
|
-
attention site). L1 attention math stays unmodified.
|
|
2127
|
-
- Quantization groups run along head_dim (KV) — token-axis surgery stays
|
|
2128
|
-
byte-safe.
|
|
2129
|
-
- Oracle-backed at the codec level (KV: vllm-metal goldens; weights: fold
|
|
2130
|
-
parity vs stock mlx-lm on the folded bf16 model). Quality of a recipe is
|
|
2131
|
-
a measured curve with host/chip/RAM labels, never inferred from ppl alone
|
|
2132
|
-
— every finalist needs generative tasks (templated + raw GSM8K).
|
|
2133
|
-
- Same seed for a trunk and its MTP companion; provenance persisted in
|
|
2134
|
-
`optiq_metadata.json`.
|
|
2135
|
-
- Comparisons are per-bpw-band and paired (same corpus, same items, same
|
|
2136
|
-
scorer); no perf claims off a loaded box.
|
|
2137
|
-
|
|
2138
|
-
## History
|
|
2139
|
-
|
|
2140
|
-
- 2026-06-12 — TurboQuant KV promoted from research path to Phase 13.
|
|
2141
|
-
- 2026-07-06 — KV v1 landed end-to-end (codec, `TurboQuantKVCache`,
|
|
2142
|
-
`--kv-quant turbo`, kv-store persistence, goldens vs vllm-metal); Gate 3
|
|
2143
|
-
curve passed on MiniCPM5-1B; deferred inverse FWHT landed same day; the
|
|
2144
|
-
weights leg noted as "Future".
|
|
2145
|
-
- 2026-07-07 — review fixes: spec-lane exclusion (turbo was silently routed
|
|
2146
|
-
into speculation), head-dim refusal at server start.
|
|
2147
|
-
- 2026-08-17 — weights phase opened; W0 Llama fold proof (`rotate.ts`).
|
|
2148
|
-
- 2026-08-18 — W1 corridor map, W2 streaming fold/quantize at 27B, W3/W4
|
|
2149
|
-
curves + TQ-mixed artifact, W5a corrected-GPTQ matrix, W5c v3 27B run,
|
|
2150
|
-
FINAL BOARD (v3 staged as mjriii/Qwen3.8-27B).
|
|
2151
|
-
- 2026-08-19 — territory campaign + THE FRONTIER; W6.5 dogfood gate opened.
|
|
2152
|
-
- 2026-08-20 — `WeightTransform` seam promoted into production convert
|
|
2153
|
-
(`--rotate-weights`, `optiq_metadata.json` provenance); MTP serve lane
|
|
2154
|
-
fixed; DeltaNet prefill leak fixed; M4 Pro 24 GB speed rows.
|
|
2155
|
-
- 2026-08-23 — research scripts moved to `scripts/turboquant/`; this
|
|
2156
|
-
consolidated doc.
|
|
2157
|
-
- 2026-08-31 — Q0 KL-vs-bf16-teacher instrument (both stacks); transformers-5.8
|
|
2158
|
-
checkpoint loader.
|
|
2159
|
-
- 2026-09-01 — Q2 trellis codec + driver, rotation 2×2, Q2c LDLQ, Q3 k-map;
|
|
2160
|
-
KL ladder above.
|
|
2161
|
-
- 2026-09-02 — Q3 full recipe (rot + LDLQ + k-map 3.00) PASSED: KL 0.1553 at
|
|
2162
|
-
3.55 bpw, MMLU 88 / tGSM 48 / rawGSM 44; eval-carrier repack tool; LDLQ
|
|
2163
|
-
loop-shadow bug fixed.
|
|
2164
|
-
|
|
2165
|
-
## Delayed row conversion and reusable precision boundaries
|
|
2166
|
-
|
|
2167
|
-
`DelayedTurboQuantKVCache` implements the existing batchable cache and
|
|
2168
|
-
rotated-value attention ports. It keeps serial row caches during a mixed
|
|
2169
|
-
plain/TQ phase and invokes the existing maintenance operation before each
|
|
2170
|
-
row's next append. `KvTensorRows` supplies positions and masks without
|
|
2171
|
-
dummy tensor planes. Once every row converts, `BatchedTurboQuantKVCache`
|
|
2172
|
-
owns the encoded rows. The scheduler invokes a generic preparation hook;
|
|
2173
|
-
it does not implement threshold, codec or inverse-rotation logic.
|
|
2174
|
-
|
|
2175
|
-
The rotated-value port can capture an output transform for its fetched
|
|
2176
|
-
state. Plain value rows pass through unchanged, and TQ rows receive the
|
|
2177
|
-
existing inverse rotation. Gemma carries that transform through its donor
|
|
2178
|
-
KV consumers. Model projections and attention remain at B=N. Start-zero
|
|
2179
|
-
layouts and kernel selection retain their existing paths.
|
|
2180
|
-
|
|
2181
|
-
A cache's `minimumReusableOffset` records an irreversible precision
|
|
2182
|
-
boundary. Delayed maintenance sets it to the actual conversion offset,
|
|
2183
|
-
which can exceed the configured threshold when a prefill chunk crosses it.
|
|
2184
|
-
Clone, row extraction and SSD metadata retain the bound. RAM/SSD selection
|
|
2185
|
-
and ancestor supersession check it independently of physical trimmability.
|
|
2186
|
-
Earlier plain donors remain reusable after a converted descendant appears.
|
|
2187
|
-
Old TQ SSD headers lacking the bound conservatively use their stored offset.
|
|
2188
|
-
|
|
2189
|
-
Focused tests cover exact mixed-row bytes and output transforms through
|
|
2190
|
-
reordering, retirement and re-admission, plus RAM/SSD ancestor retention,
|
|
2191
|
-
restart, continuation and old-header compatibility. Native seeded/logprob
|
|
2192
|
-
and prefix gates accept positive thresholds via their test environment
|
|
2193
|
-
switches. Shared Qwen MTP also uses the delayed layout. Its transaction
|
|
2194
|
-
begins conversion from committed history before verification. A verify block
|
|
2195
|
-
may cross the configured threshold; resolution converts at the retained
|
|
2196
|
-
offset after rollback and before checkpoint publication, so rejected tokens
|
|
2197
|
-
never set the precision boundary.
|
|
2198
|
-
The draft provider retains its existing paired checkpoint format.
|
|
2199
|
-
|
|
2200
|
-
Mixed rollback and final packed promotion preserve each row's physical left
|
|
2201
|
-
padding. Re-aligning it based on another row's accepted count changes SDPA
|
|
2202
|
-
reduction positions even when all live cache bytes match. Same-batch native
|
|
2203
|
-
controls check every target layer and subsequent hidden rows after unequal
|
|
2204
|
-
acceptance. Affine delayed speculation and the legacy serial TQ speculative
|
|
2205
|
-
path remain excluded. This implementation changes no defaults.
|
|
2206
|
-
|
|
2207
|
-
### Wider split-K verification screen
|
|
2208
|
-
|
|
2209
|
-
The current packed down-projection operation covers five through eight input
|
|
2210
|
-
vectors. An isolated candidate extended that operation through 32 vectors,
|
|
2211
|
-
using 8-, 16- or 32-row tiles while retaining the native split partition and
|
|
2212
|
-
accumulation order. Scheduler and speculation policy were unchanged.
|
|
2213
|
-
|
|
2214
|
-
Actual 2-, 3- and 4-bit artifact projections pass exact expanded-weight
|
|
2215
|
-
controls at every new width and three input seeds on both Macs. Full Qwen
|
|
2216
|
-
logits, recurrent/KV state and continuation match the unchanged eligibility
|
|
2217
|
-
control at B1/B2/B4/B8 on both Macs. Call-count assertions prove the wider
|
|
2218
|
-
kernels ran. Updated unit coverage includes wider partition tails and
|
|
2219
|
-
noncontiguous inputs; both complete suites and typechecks pass.
|
|
2220
|
-
|
|
2221
|
-
The alternating M4 prompt-lookup comparison preserves all requests but loses
|
|
2222
|
-
concurrent throughput. This wider eligibility is not adopted. Future work
|
|
2223
|
-
needs serving dispatch/cost attribution before additional tile tuning.
|
|
2224
|
-
Measurements: benchmarks.md. Evidence and source manifest:
|
|
2225
|
-
`reports/qwen38-closeout/composition-baseline/trellis-batch-width/`.
|