Skip to content

Nightly 2026-07-13: GGUF end-to-end — one .gguf file is the whole model (Qwen2.5 + LFM2.5) - #5

Merged
physics515 merged 6 commits into
mainfrom
mummu-nightly-2026-07-13
Jul 13, 2026
Merged

Nightly 2026-07-13: GGUF end-to-end — one .gguf file is the whole model (Qwen2.5 + LFM2.5)#5
physics515 merged 6 commits into
mainfrom
mummu-nightly-2026-07-13

Conversation

@physics515

Copy link
Copy Markdown
Owner

Automated nightly run (~4.5 h wall-clock, 6 commits). Theme: the P3 GGUF import path went from "container + partial dequant" to a single .gguf file is a complete, running model — config, weights, AND tokenizer — for both zoo LLM architectures, wired through the registry so apps can install GGUF models end-to-end.

Dependency freshness (standalone increment)

  • cargo update: uuid 1.23.4→1.23.5, zmij 1.0.21→1.0.22 (lock-only).
  • cargo upgrade --incompatible offered wgpu 29→30 and tokenizers 0.22→0.23 — both REVERTED per the intentional parity-validated pin (burn 0.21 + wgpu 29 + tokenizers 0.22, documented in Cargo.toml). No migration item needed: the pins are deliberate, not blocked.
  • Gates after bump: 121 (then-current) unit tests, GPU budget 107.4 ms TTFT / 13.3 tok/s, CPU budget 15.1 tok/s. (First GPU gate attempt read 9.2 tok/s under a 7.8 GiB-ambient desktop; re-run passed comfortably — environmental, not the deps.)

1) GGUF → running model (Qwen2.5)

  • Every GGUF storage dtype now dequantizes: added Q4_0/Q4_1/Q5_0/Q5_1 legacy blocks + Q2_K/Q3_K/Q5_K superblocks (exact ggml-quants ports, each with hand-computed block unit tests). Q8_1/Q8_K stay loud errors (activation formats).
  • GgufFile::dequant_to_safetensors: bridges a GGUF onto the exact checked-load pipeline the safetensors path trusts (in-memory blob; dims reversed = row-major HF layout; unmapped tensor names are loud errors; 48 GiB RAM bound).
  • Qwen2Config::from_gguf (hyperparameters from qwen2.* metadata) + qwen2::load_from_gguf.
  • The Qwen2 module gained an optional untied lm_head — llama.cpp GGUFs materialize the tied head as a separate higher-precision output.weight (Q6_K in the real file); also unlocks untied safetensors checkpoints (7B class).
  • Proof (real weights, 4070 Ti SUPER): Qwen2.5-1.5B Q4_K_M greedy-decodes \"2+2 equals 4.\"; first-token top-1 identical to the bf16 safetensors build, top-5 overlap 4/5, logit cosine 0.977 (quantization drift; a layout bug reads ≈ 0). Parity gate re-passed byte-identically after the lm_head change (max |Δlogit| 2.670e-5 vs Candle; Ollama fp16 greedy leg exact).

2) Tokenizer from GGUF metadata

  • mummu::tokenizer::tokenizer_from_gguf: rebuilds the HF tokenizers pipeline from tokenizer.ggml.* — per-family pre-tokenizer regex registry (llama.cpp-style, unknown ids error loudly), ByteLevel BPE, token id = array index, CONTROL/USER_DEFINED → special/plain added tokens with post-build id verification, UNUSED padding skipped.
  • Proof: byte-identical ids vs the checkpoint's tokenizer.json on an 8-prompt battery (ChatML + specials, unicode/CJK/emoji, whitespace runs, contractions, empty) and identical decodes.

3) LFM2.5 hybrid GGUF import

  • Lfm2Config::from_gguf: layer kinds derived from llama.cpp's per-layer head_count_kv array (0 = shortconv, nonzero = attention; i32 in real files); feed_forward_length arrives pre-adjusted.
  • Name map covers the hybrid's per-head q/k norms + shortconv.*; new GgufMap::Reshape un-squeezes the depthwise conv kernel (ggml [K,C] → checkpoint [C,1,K], same bytes, element count validated).
  • Tokenizer registry gains the lfm2 pre (digits-≤3 regex, no NFC, BOS post-processor from add_bos_token; LFM2's 500+ low-id specials work via BPE-vocab id reuse).
  • Proof (official LiquidAI Q4_K_M, 697 MB, downloaded this run, vs the same checkpoint's local bf16 safetensors): 5 F32 tensors incl. both conv kernels bit-exact; tokenizer byte-identical over a 6-prompt × 2-mode battery; end-to-end on the GPU the one file greedy-decodes \"2 + 2 equals 4.\", top-1 identical to bf16, logit cosine 0.9914. (Not the strict P2/P7 parity gate — that still needs the llama.cpp same-quant reference leg, tracked.)

4) Registry learns GGUF

  • ModelSpec.format: Safetensors | Gguf { file } (serde-defaulted — old manifests parse); GGUF specs fetch their one file through the resumable/sha256-verified hub path; catalog gains Q4_K_M entries for both models (¼ the download).
  • Real-network proof: the LFM2.5 GGUF spec installed end-to-end — 697 MB via spec.fetch, header parses (lfm2, 148 tensors), tokenizer builds from metadata.

Verification summary

  • 140 unit tests green (was 121), names verified; cargo fmt / clippy --all-targets clean; release build green.
  • All 7 real-file GGUF tests + 4 real-inference tests + f16 gate + both tool-call proofs' shared paths re-ran green.
  • Parity gate: byte-identical both legs. Perf budgets: GPU 106.7 ms TTFT / 13.5 tok/s (≥10 budget), CPU 13.5 tok/s (≥6) — no regression, bench/BASELINE.md unchanged.

Research folded into ROADMAP

  • CubeCL now ships quantization primitives (block-scaled MMA, quantized matmul views, FP4/FP2) — new P9 [ ] to evaluate as the keep-quantized matmul substrate (the actual VRAM lever; today's GGUF path dequants to f32).
  • GPTQ/AWQ are algorithms-not-formats: safetensors + quantization_config, group-128 int4 standard; vLLM compressed-tensors is the unified on-disk convention to target (P3 note).
  • llama.cpp's LFM2.5 tool-parser bug (#23838) is fixed upstream (PR #24178); raw-completion mode remains the right P7 logits-leg route; LiquidAI ships official F16 GGUFs = the same-weights reference artifact that leg needs.

What's next

  • Keep-quantized in VRAM (P9): Q4_K_M currently dequants to the same f32 footprint — the CubeCL quant primitives are the identified lever.
  • LFM2.5 strict parity leg (P7): llama-server raw /completion logprobs on the official F16 GGUF (now that the file + fixed upstream exist).
  • Quantized-reference parity for GGUF loads (new P3 [ ]): assert our dequant matches ggml's compute path token-for-token.
  • P6 placement plan / VRAM inventory remains the biggest open front.

🤖 Generated with Claude Code

physics515 and others added 6 commits July 13, 2026 07:06
wgpu 30 / tokenizers 0.23 majors offered by cargo-upgrade were reverted:
burn 0.21 + wgpu 29 + tokenizers 0.22 is the intentional parity-validated
pin (see Cargo.toml). Gates green: 121 unit tests, GPU budget 107.4 ms /
13.3 tok/s, CPU budget 15.1 tok/s.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…om_gguf

- dequantize every GGUF storage dtype: adds Q4_0/Q4_1/Q5_0/Q5_1 legacy
  blocks and Q2_K/Q3_K/Q5_K superblocks (exact ggml-quants ports, each
  with hand-computed block tests); Q8_1/Q8_K stay loud errors
  (activation formats, never tensor storage)
- GgufFile::dequant_to_safetensors: bridge a GGUF onto the exact
  checked-load pipeline safetensors uses (in-memory blob, dims reversed
  = row-major HF layout, unmapped tensor names error loudly, 48 GiB
  RAM bound)
- Qwen2Config::from_gguf: hyperparameters from qwen2.* metadata; vocab
  from the embedding tensor; EOS from tokenizer.ggml.eos_token_id
- qwen2::load_from_gguf: one .gguf file -> a running model
- Qwen2 gains an optional untied lm_head: llama.cpp GGUFs materialize
  the tied head as a separate (higher-precision) output.weight; also
  unlocks untied safetensors checkpoints (Qwen2-7B class)

Proof (real weights, 4070 Ti SUPER): Qwen2.5-1.5B Q4_K_M greedy-decodes
'2+2 equals 4.'; first-token top-1 identical to the bf16 build, top-5
overlap 4/5, logit cosine 0.977. Parity gate re-passed byte-identically
after the lm_head change (max dlogit 2.670e-5; Ollama greedy exact).
133 unit tests; f16, real-inference, and budget gates green
(GPU 107.4 ms / 13.6 tok/s, CPU 14.8 tok/s).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…model

- mummu::tokenizer::tokenizer_from_gguf rebuilds the HF tokenizers
  pipeline from tokenizer.ggml.* metadata: NFC -> Split(per-family
  pre-tokenizer regex, llama.cpp-style registry keyed by
  tokenizer.ggml.pre; unknown ids error loudly) -> ByteLevel -> BPE
- token id = tokens-array index; CONTROL(3) -> special added tokens,
  USER_DEFINED(4) -> plain added tokens, UNUSED(5) [PADn] skipped;
  every added-token id is verified post-build (drift = loud error)
- GgufValue::as_i64 for the signed token_type array
- the end-to-end GPU test now sources tokenizer + config + weights
  from the single .gguf file

Proof: byte-identical ids vs the checkpoint's tokenizer.json across an
8-prompt battery (ChatML with specials, unicode/CJK/emoji, whitespace
runs, contractions, numbers, empty) and identical decodes; end-to-end
Q4_K_M decode re-passed ('2+2 equals 4.'). 135 unit tests green,
clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ed-tensors convention (P3), llama.cpp LFM2.5 parser fix upstream (P7)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Lfm2Config::from_gguf: hyperparameters from lfm2.* metadata; layer
  kinds derived from llama.cpp's per-layer head_count_kv array (0 =
  shortconv, nonzero = attention; i32 in real files, all nonzero must
  agree); feed_forward_length arrives pre-adjusted
- lfm2 tensor-name map incl. per-head q/k norms and shortconv.*; the
  depthwise conv kernel is the one shape special-case: new
  GgufMap::Reshape un-squeezes ggml's [K, C] back to the checkpoint's
  [C, 1, K] (same bytes; element count validated)
- tokenizer registry gains the lfm2 pre: digits-in-<=3-groups regex, no
  NFC, BOS post-processor from tokenizer.ggml.add_bos_token; added
  tokens at LOW ids (LFM2 puts 500+ specials at 0..) work by seeding
  the BPE vocab and letting add_tokens reuse the model id

Proof (official LiquidAI Q4_K_M vs the same checkpoint's local bf16
safetensors): 5 F32 tensors incl. both conv kernels bit-exact;
tokenizer byte-identical over a 6-prompt x 2-mode battery; REAL-GPU
end-to-end — the one file greedy-decodes '2 + 2 equals 4.', top-1
identical to the bf16 build, logit cosine 0.9914. 138 unit tests;
qwen2 GGUF suite, parity gate (2.670e-5, Ollama byte-identical), and
budget gates (GPU 106.7 ms / 13.5 tok/s, CPU 13.5 tok/s) all re-passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…to-end

- ModelSpec.format: WeightFormat::Safetensors | Gguf { file }
  (serde-defaulted, so manifests written before the field still parse)
- GGUF specs fetch their one file through the resumable/verified hub
  path; gguf_path() names the local file; validation rejects empty,
  traversal, absolute, and non-.gguf file names
- catalog: single-file Q4_K_M entries for Qwen2.5-1.5B-Instruct and
  LFM2.5-1.2B-Instruct (quarter the download of the safetensors)

REAL-NETWORK proof (real_hub.rs): the LFM2.5 GGUF spec installs
end-to-end — 697 MB fetched via spec.fetch, header parses as lfm2
(148 tensors), tokenizer builds from its metadata. 140 unit tests,
clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 13:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This nightly PR completes the “single-file GGUF is a whole runnable model” workflow by adding (1) a safetensors-bridge dequant path for GGUF weights, (2) tokenizer reconstruction from GGUF metadata, and (3) registry support for fetching/installing GGUF models end-to-end (Qwen2.5 + LFM2.5).

Changes:

  • Add GgufFile::dequant_to_safetensors plus additional ggml dequantizers to cover all GGUF storage dtypes needed for real models.
  • Introduce mummu::tokenizer::tokenizer_from_gguf to rebuild HF tokenizers pipelines from tokenizer.ggml.* metadata.
  • Extend Qwen2 and LFM2 loaders/config parsing to support GGUF inputs; update the registry to fetch either safetensors or single-file GGUF specs.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ROADMAP.md Marks GGUF and tokenizer-from-metadata work as shipped; adds follow-up parity/VRAM items.
README.md Updates documentation to reflect GGUF end-to-end model + tokenizer support.
crates/mummu/tests/real_hub.rs Adds a real-network GGUF spec install test (ignored by default).
crates/mummu/tests/real_gguf.rs Adds real-file tokenizer parity tests and end-to-end GPU decode parity checks for Qwen2/LFM2.
crates/mummu/src/tokenizer.rs New module to reconstruct a byte-level BPE tokenizer from GGUF metadata.
crates/mummu/src/registry.rs Adds WeightFormat and GGUF fetch/path support in ModelSpec.
crates/mummu/src/models/qwen2.rs Adds GGUF config parsing + GGUF loader; supports optional untied lm_head.
crates/mummu/src/models/lfm2.rs Adds GGUF config parsing + GGUF loader; adds conv-kernel reshape mapping.
crates/mummu/src/lib.rs Exposes the new tokenizer module.
crates/mummu/src/gguf.rs Adds dequant-to-safetensors bridge, GgufMap::Reshape, more dequantizers, and tests.
Cargo.lock Lockfile-only dependency updates (uuid, zmij).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +162 to +164
let byte_level = ByteLevel::new(false, false, false);
tok.with_pre_tokenizer(Some(Sequence::new(vec![split.into(), byte_level.into()])));
tok.with_decoder(Some(byte_level));
Comment on lines +101 to +105
let hidden_size = gguf_usize(f, "qwen2.embedding_length")?;
let num_attention_heads = gguf_usize(f, "qwen2.attention.head_count")?;
let embd = f
.tensor("token_embd.weight")
.ok_or("GGUF has no token_embd.weight tensor")?;
Comment on lines +74 to +77
let safe = !file.is_empty()
&& !file.contains("..")
&& !file.starts_with('/')
&& file.ends_with(".gguf");
@physics515
physics515 merged commit 4787041 into main Jul 13, 2026
1 check passed
@physics515
physics515 deleted the mummu-nightly-2026-07-13 branch July 13, 2026 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants