Repository navigation
feat(tools): emit dual-backend q8_0 lm dtypes from the moshi GGUF converter - #115
Open
gabewillen wants to merge 1 commit into
Open
gabewillen wants to merge 1 commit into
gabewillen wants to merge 1 commit into
Conversation
…verter The Metal kernel actor's mul_mat only accepts f32/f16/q8_0 and its get_rows only accepts f32/f16 codebooks, while the PersonaPlex LM cache is q4_k. Generalize --quantize q8_0 to also support the lm component so the generator can emit an artifact whose dtypes both the aarch64 CPU and Metal kernels dispatch: - lm matmul weight classes (the existing LM_Q4_K_PACKABLE_PATTERNS set) are dequantized to f32 (faithful ggml q4_K/q4_0/q8_0 decoders) and requantized to q8_0 when the row length blocks (ne0 % 32 == 0); non-blockable rows (e.g. a 16-wide depformer gate) stay/upcast to a float that both backends accept - op_get_rows codebook tensors (text_emb, emb.*, depformer embeddings) are upcast to f16 when not already f32/f16 (Metal get_rows is float only; f16 is CPU-valid too) - everything else streams through unchanged; moshi.lm.quantization and the manifest record the rewrite Adds a --self-test that pins the q4_K decoder to golden ggml values and runs both the focused rewrite and a full convert() on the tiny f32 lm fixture, asserting matmul weights become q8_0 with no unsupported dtypes left behind. Existing lm/mimi/voice fixture output is byte-identical.
There was a problem hiding this comment.
Pull request overview
Extends the Moshi GGUF converter’s optional --quantize q8_0 mode to support LM caches by rewriting selected LM matmul weights into q8_0 (dual-dispatch for aarch64 CPU + Metal) and upcasting get_rows embedding/codebook tensors to f16, while preserving non-target tensors unchanged and recording the rewrite in GGUF KV + manifest metadata.
Changes:
- Add LM-specific quantization pipeline (
quantize_lm_tensors) including faithful dequant helpers for q4_K/q4_0/q8_0 and f16/f32 passthrough. - Introduce
LM_EMBEDDING_PATTERNSandread_enriched_gguf_tensors()to validate emitted dtypes and implement--self-testcovering both synthetic cases and an end-to-end tiny fixture. - Update CLI/manifest/KV behavior to support LM quantization (
moshi.lm.quantization,lm_embedding_upcast_to_f16) and make--source/--outputoptional for self-test runs.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| values = dequantize_q4_K(blocks, 4, 256) | ||
| for row in range(4): | ||
| for base in (0, 64, 128, 192): | ||
| qoff = (base // 64) * 32 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Metal kernel actor (
PR #114) rejects the PersonaPlex LM cache: itsop_mul_matonly accepts f32/f16/q8_0 andop_get_rowsonly accepts f32/f16 codebooks, while the LM cache is q4_k.This generalizes
--quantize q8_0intools/bench/moshi_gguf_convert.pyto also support thelmcomponent, so the generator can emit an artifact whose dtypes both the aarch64 CPU and Metal kernels dispatch ("right dtypes for both CPU and metal"):LM_Q4_K_PACKABLE_PATTERNSset) → q8_0, via faithful ggmlq4_K/q4_0/q8_0dequant →q8_0requant. Rows that don't block (e.g. a 16-wide depformer gate) stay or upcast to a float both backends accept.op_get_rowscodebooks (text_emb,emb.*, depformer embeddings) → f16 when not already f32/f16.moshi.lm.quantization+ manifest record the rewrite.Verification (
python3 tools/bench/moshi_gguf_convert.py --self-test):convert()on the tiny f32 LM fixture: transformer weights become q8_0, no matmul tensor left in an unsupported dtype, manifest records q8_0.Note: this is the dtype layer only — PersonaPlex-on-Metal still needs
rms_norm/rope/mul/argmaxkernels beyond the dtype fix, but the weight representation blocker is gone.Note
Low Risk
Bench-only converter changes; default conversion path is unchanged unless
--quantize q8_0is used on an lm GGUF.Overview
Extends
--quantize q8_0inmoshi_gguf_convert.pyfrom mimi-only tolm, so PersonaPlex-style q4_k caches can be rewritten into dtypes aarch64 CPU and Metal both accept.For lm, matmul weights matching
LM_Q4_K_PACKABLE_PATTERNSare dequantized (ggml q4_K/q4_0/q8_0/f16/f32) and requantized to q8_0 when row length aligns to 32; narrow or already-float matmul rows stay f32/f16 or upcast to f16 instead of padded q8_0. Embedding/codebook tensors used byget_rows(text_emb,emb.*, depformer embeddings) are upcast to f16 when quantized, since Metal only allows f32/f16 there. Conversion recordsmoshi.lm.quantizationand manifest fields includinglm_embedding_upcast_to_f16.Adds faithful dequant helpers,
quantize_lm_tensors,read_enriched_gguf_tensorsfor verification,--self-test(synthetic q4_k/q4_0 cache plus end-to-end tiny fixture viaconvert()), and makes--source/--outputoptional when self-testing.Reviewed by Cursor Bugbot for commit dc3245a. Bugbot is set up for automated code reviews on this repo. Configure here.