Skip to content

Commit 9ce3353

Browse files
committed
fix(glm): preserve dense KV-B weights
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 39ff6824-d35f-4d3b-8f5f-043a7119a100
1 parent 5163cdc commit 9ce3353

3 files changed

Lines changed: 42 additions & 11 deletions

File tree

‎src/mobius/integrations/gguf/_route_census_test.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ def test_every_route_has_one_actionable_classification() -> None:
6464
}
6565
assert Counter(item.category for item in items) == {
6666
"dependency-or-runtime-abi-blocked": 100,
67-
"evidence-only": 107,
68-
"immediately-implementable": 53,
67+
"evidence-only": 108,
68+
"immediately-implementable": 52,
6969
"intentionally-rejected": 19,
7070
"artifact-unavailable": 5,
7171
}
@@ -94,6 +94,7 @@ def test_route_reasons_are_sourced_from_authoritative_records() -> None:
9494
def test_known_route_boundaries_are_not_collapsed() -> None:
9595
by_id = {item.route_id: item for item in iter_remaining_route_work()}
9696
assert by_id["architecture:bitnet"].category == "evidence-only"
97+
assert by_id["architecture:glm-dsa"].category == "evidence-only"
9798
assert by_id["architecture:deepseek4"].category == "dependency-or-runtime-abi-blocked"
9899
assert by_id["architecture:rwkv6"].category == "dependency-or-runtime-abi-blocked"
99100
assert by_id["architecture:bailingmoe2"].category == "intentionally-rejected"

‎src/mobius/models/glm_moe_dsa.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ def preprocess_weights(
673673
state_dict = dict(state_dict)
674674
kv_b_suffix = ".self_attn.kv_b_proj.weight"
675675
for key in tuple(state_dict):
676-
if not key.endswith(kv_b_suffix):
676+
if not self.config.use_dsa or not key.endswith(kv_b_suffix):
677677
continue
678678
tensor = state_dict.pop(key)
679679
expected_rows = self.config.num_attention_heads * (

‎src/mobius/models/glm_moe_dsa_test.py‎

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -374,17 +374,10 @@ def test_moe_layers_fuse_to_qmoe_when_quantized(self):
374374
class TestPreprocessWeights:
375375
def _state_dict(self, config: ArchitectureConfig) -> dict[str, torch.Tensor]:
376376
model = GlmMoeDsaCausalLMModel(config)
377-
state = {
377+
return {
378378
name: torch.zeros(tuple(int(d) for d in p.shape))
379379
for name, p in model.named_parameters()
380380
}
381-
# Convert Mobius's own attribute-path names into the HF-style
382-
# ``model.layers.N.*`` names preprocess_weights expects on input.
383-
renamed = {
384-
f"model.{name}" if not name.startswith("lm_head") else name: v
385-
for name, v in state.items()
386-
}
387-
return renamed
388381

389382
def test_drops_mtp_layer_weights_with_warning(self, caplog):
390383
config = _glm_config(num_hidden_layers=4)
@@ -420,6 +413,43 @@ def test_dsa_path_keeps_indexer_weights(self):
420413
out = model.preprocess_weights(state)
421414
assert any(".self_attn.indexer." in k for k in out)
422415

416+
@pytest.mark.parametrize("use_dsa", [True, False], ids=["dsa", "dense"])
417+
def test_preprocessed_weights_cover_every_graph_parameter(self, use_dsa: bool):
418+
config = _glm_config(
419+
num_hidden_layers=1,
420+
indexer_types=["full"],
421+
use_dsa=use_dsa,
422+
)
423+
model = GlmMoeDsaCausalLMModel(config)
424+
graph = build_from_module(model, config, task="glm-moe-dsa")["model"].graph
425+
state = {
426+
name: torch.zeros(tuple(int(d) for d in initializer.shape))
427+
for name, initializer in graph.initializers.items()
428+
if initializer.const_value is None
429+
}
430+
expected = set(state)
431+
432+
if use_dsa:
433+
prefix = "model.layers.0.self_attn."
434+
key_rows = state.pop(f"{prefix}k_b_proj.weight").reshape(
435+
config.num_attention_heads,
436+
config.qk_nope_head_dim,
437+
config.kv_lora_rank,
438+
)
439+
value_rows = state.pop(f"{prefix}v_b_proj.weight").reshape(
440+
config.num_attention_heads,
441+
config.v_head_dim,
442+
config.kv_lora_rank,
443+
)
444+
state[f"{prefix}kv_b_proj.weight"] = torch.cat(
445+
(key_rows, value_rows), dim=1
446+
).reshape(-1, config.kv_lora_rank)
447+
448+
out = model.preprocess_weights(state)
449+
450+
assert expected
451+
assert set(out) == expected
452+
423453
def test_splits_hf_fused_kv_b_projection(self):
424454
config = _glm_config(num_hidden_layers=1, indexer_types=["full"])
425455
model = GlmMoeDsaCausalLMModel(config)

0 commit comments

Comments
 (0)