feat(qwen36): name a checkpoint by its geometry, and a converter that refuses what it cannot place - #1326
Open
kreuzzelg wants to merge 1 commit into
Open
feat(qwen36): name a checkpoint by its geometry, and a converter that refuses what it cannot place#1326kreuzzelg wants to merge 1 commit into
kreuzzelg wants to merge 1 commit into
Conversation
This was referenced Sep 6, 2026
JustVugg
added a commit
to donovan-yohan/colibri
that referenced
this pull request
Sep 6, 2026
A GLM-5.3 container was announced as "GLM-5.2 744B". The engine loaded the right weights and ran them correctly; the banner named a different model. This is not fixable by detection, and that is the point of the change rather than an excuse for it. Z.ai state on GLM-5.3's own card that it "uses the same base model as GLM-5.2 -- every gain comes from post-training", and the checkpoints agree: diffing the two real config.json leaves one extra key (moe_router_dtype) and the transformers_version that wrote the file. Same 78 layers, 256 experts, hidden 6144, moe_intermediate 2048. JustVugg#1326's rule for Qwen -- name a checkpoint by its geometry -- cannot apply, because the geometry is identical. No rule over the configuration can name one and not the other, now or later. So the family says what it actually loads: GLM-5.2/5.3, at the 744B scale both share. Verified by resolving both real configs through the registry. The docs move with it wherever the family is ENUMERATED: the "families run today" line in all four READMEs, the model table and the RAM table in README.md, the model card and the nav entry on the site. Mentions of GLM-5.2 as a fact -- DSA came from its lightning indexer, its native MTP head, benchmarks measured on it, the pre-converted 5.2 container on Hugging Face -- are still true and are left alone. Three tests pin the reason, because the obvious later "improvement" is to add detection: both configs resolve to one family, neither differing key may be read by the registry, and the name must state both models. Reverting the name fails the third and nothing else. 751 Python tests green.
kreuzzelg
force-pushed
the
qwen36-size-aware-descriptor
branch
from
September 10, 2026 19:01
af89d53 to
b10cf6b
Compare
… refuses what it cannot place Qwen/Qwen3.8-2.4T-A95B declares the same model_type as Qwen3.6-35B-A3B (qwen3_5_moe_text) and resolves to this engine today, where the banner announces it as "Qwen3.6-35B-A3B · 35B" (JustVugg#1045). Fixed on its own merits, with the pieces that make the 2.4T shape a verified one rather than a guessed one -- without a single weight of it. A model_type resolves to exactly one family, so a second descriptor is not an option. Instead `DisplayVariant` pairs a geometry (config keys that must match exactly) with a name, and `display_for(resolved)` picks the first match: 40/256/2048 -> "Qwen3.6-35B-A3B · 35B", 92/512/8192 -> "Qwen3.8-2.4T-A95B · 2.4T". A config matching neither -- a tiny fixture, a third sibling -- is named by its own model_type and measured geometry, never by a sibling's parameter count. The registry refuses a variant that matches everything, and a family whose static display_name is not among its variants (the READMEs are held to that name). `coli`'s banner reads the family config (text_config-aware), so the VL-wrapped 35B repo and the flat 2.4T config both display right. The converter selected `<prefix>layers.<i>.` and four globals and let the rest fall through unmentioned. That skipped the `mtp.*` head and the `visual.*` tower by accident, and would have copied an unfamiliar tensor inside a layer as f16 without a word. `tools/qwen36_tensor_kinds.py` now classifies every name before the first shard is read: layer tensors by an exact suffix list, `mtp.*` / `visual.*` skipped ON PURPOSE with a count and a reason, anything else refused with the names. `test_qwen36_tensor_kinds` pins the contract to the safetensors indexes of both real checkpoints (1609 and 1045 tensors) and to the per-expert layout transformers saves. One correction found on the way: the comment claimed the real 35B ships per-expert tensors. Both real checkpoints ship the FUSED layout (`experts.gate_up_proj` / `down_proj`); only the tiny fixture is per-expert. `make_qwen36_tiny.py --geometry qwen38-2p4t`: 92 layers / interval 4 / 512 experts top-10 / 16:1 attention heads / 8:1 DeltaNet heads, and the saved shard rewritten into what the checkpoints ship -- fused experts plus a one-layer `mtp.*` head with `mtp_num_hidden_layers: 1`. The converter has to split the one and skip the other; the engine has to match the transformers reference. The default preset reproduces the shipped fixture's reference exactly. - old fixture: reference identical, converted shard bit-identical (cmp), 16/16 at cap 1/2/8 - 2.4T geometry: 19 mtp tensors skipped and said so, 1587 placed in 92 layers, 16/16 at cap 1/2/512, 0.35 s per run - ASan/UBSan (nm confirms 31 __asan symbols): no diagnostic on either fixture under PILOT=1 WIDE=2 - registry planner on the real 2.4T config: KV 1.44 GiB @8k, 46.0 GiB @256k, DeltaNet state 0.55 GiB context-free -- the numbers quoted in JustVugg#1045; the engine's KV cache is F32 (ensure_kv: falloc), so they stand - python suite: 743 tests, OK (skipped=35) - the new CI step run locally word for word `--seed 3` for the 2.4T rung: the default seed collapses this geometry's reference to one repeated token, which a shape error could still reproduce; seed 3 gives twelve distinct tokens over sixteen. Not done here, and said in docs/qwen36.md: running the 2.4T. The warmstart keeps every expert in RAM by design, ~1.4 TB of int4 for this checkpoint; that needs the disk-streaming design, not this one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DLj9ctDNPGTsYxgBuDmy5a
kreuzzelg
force-pushed
the
qwen36-size-aware-descriptor
branch
from
September 13, 2026 21:32
b10cf6b to
6c6354e
Compare
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.
Fixes the banner defect confirmed in #1045 (comment 5458211750), and lands the pieces that make the Qwen3.8-2.4T-A95B shape a verified one rather than a guessed one — without a single weight of it.
The defect
Qwen/Qwen3.8-2.4T-A95Bdeclares the samemodel_typeas Qwen3.6-35B-A3B (qwen3_5_moe_text) and resolves to the qwen36 engine today, where the banner announces it as "Qwen3.6-35B-A3B · 35B". A loader that misreports what it loaded costs someone a day.Registry: display by geometry
A
model_typeresolves to exactly one family (_BY_TYPE), so a second descriptor is not available. Instead the descriptor carriesdisplay_variants: aDisplayVariantpairs a geometry (config keys that must match exactly) with a name, anddisplay_for(resolved)picks the first match.Qwen3.6-35B-A3B · 35B MoE · 21 GB on diskQwen3.8-2.4T-A95B · 2.4T MoEqwen3_5_moe_text · 8L x 8E MoE— its own model_type and measured numbers, never a sibling's parameter countThe registry refuses a variant that matches everything, and a family whose static
display_nameis not among its variants (the READMEs are held to that name by the existing contract test).coli's banner reads the family config, so the VL-wrapped 35B repo (text_config) and the flat 2.4T config both display right.public_metadatacarries the variants.Converter: every tensor name is placed, or it stops
While checking the 2.4T index I found the class of defect you described for GLM-5.3, live in this converter. It selected
<prefix>layers.<i>.plus four globals and let the rest fall through unmentioned. That skipped themtp.*head and thevisual.*tower by accident, and would have copied an unfamiliar tensor inside a layer as f16 without a word.tools/qwen36_tensor_kinds.pynow classifies every name before the first shard is read: layer tensors by an exact suffix list,mtp.*/visual.*skipped on purpose with a count and a reason (skipping 19mtp.*tensor(s): multi-token-prediction head …, config mtp_num_hidden_layers=1), anything else refused with the names. Torch-free, sotests/test_qwen36_tensor_kinds.pyruns wherever the registry tests run; it pins the contract to the safetensors indexes of both real checkpoints (1609 and 1045 tensors) and to the per-expert layout transformers saves.One correction on the way: a comment claimed the real 35B ships per-expert tensors. Both real checkpoints ship the fused layout (
experts.gate_up_proj/down_proj, one tensor per layer) and both carry the mtp head; only the tiny fixture is per-expert. So the "five-minute index check" I proposed in #1045 was aimed at the wrong regex —expert_inventorydescribes the container, not the checkpoint — and the real thing to verify was the fused split and the deliberate skip. Both are now under test.Fixture: the 2.4T shape at toy widths, in the real layout
make_qwen36_tiny.py --geometry qwen38-2p4t: 92 layers / interval 4 / 512 experts top-10 / 16:1 attention heads / 8:1 DeltaNet heads, and the saved shard rewritten into what the checkpoints ship — fused experts plus a one-layermtp.*head withmtp_num_hidden_layers: 1. The converter has to split the one and skip the other; the engine has to match the transformers reference token for token. The default preset reproduces the shipped fixture's reference exactly, so the existing gate is unchanged.CI (
qwen36-tiny-check) gains a step: build the 2.4T fixture, assert the converter said it skipped 19 mtp tensors and placed 1587 in 92 layers, assert nomtp.*survives in the container, token-exact at cap 1 / 2 / 512; the sanitizer step now runs both fixtures.Verified
cmp), 16/16 at cap 1/2/8nmconfirms 31__asansymbols — the lesson of fix(pilot): the prefetch worker outlives the Model it dereferences #1277): no diagnostic on either fixture underPILOT=1 WIDE=2ensure_kv→falloc), so they stand; the F16 caveat I raised there is closed--seed 3for the 2.4T rung: the default seed collapses this geometry's reference to one repeated token, which a shape error could still reproduce; seed 3 gives twelve distinct tokens over sixteenNot in this PR, and said in
docs/qwen36.mdRunning the 2.4T. The warmstart keeps every expert in RAM by design, ~1.4 TB of int4 for this checkpoint; that needs the disk-streaming design, not this one. What this PR guarantees is that the shape is right before anyone spends the bandwidth.
Thanks to claude code!