Coverage for transformer_lens/model_bridge/supported_architectures/glm4_moe.py: 100%
11 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-21 19:27 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-21 19:27 +0000
1"""GLM-4.5 MoE architecture adapter.
3Supports GLM-4.5/4.6/4.7 mixture-of-experts families (`Glm4MoeForCausalLM`).
5Key features:
6- RMSNorm with partial pre-norm layout.
7- RoPE-style rotary embeddings (partial RoPE supported by Hugging Face model logic).
8- Q/K normalization blocks (`q_norm`, `k_norm`) and GQA / MQA handling.
9- Sparse MoE block in `model.layers[i].mlp`, with optional dense-prefix layers.
10- QKVO rearrangements for bridge-side attention hooks.
12Optional Parameters (may not exist in state_dict):
13-------------------------------------------------
14- blocks.{i}.mlp.gate - absent on dense-prefix layers before sparse MoE starts.
15"""
17from typing import Any
19from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
20from transformer_lens.model_bridge.generalized_components import (
21 BlockBridge,
22 EmbeddingBridge,
23 LinearBridge,
24 MoEBridge,
25 MoERouterBridge,
26 PositionEmbeddingsAttentionBridge,
27 RMSNormalizationBridge,
28 RotaryEmbeddingBridge,
29 UnembeddingBridge,
30)
33class Glm4MoeArchitectureAdapter(ArchitectureAdapter):
34 """Architecture adapter for GLM-4.5 / 4.6 / 4.7 MoE decoder models.
36 GLM-4x MoE families use RMSNorm, RoPE and sparse routing, with early
37 dense-MLP layers in some checkpoints. The dense layers are represented by
38 a present-but-slightly-thinner `mlp` sub-module where routing is absent.
39 """
41 def __init__(self, cfg: Any) -> None:
42 """Initialize the GLM-4 MoE architecture adapter."""
43 super().__init__(cfg)
45 self._set_rms_rotary_defaults()
46 # Force eager attention for output_attentions / compatibility-path parity.
47 self.cfg.attn_implementation = "eager"
48 # GLM-4 defaults do not prepend BOS in current tiny checkpoints.
49 self.cfg.default_prepend_bos = False
51 # QKVO rearrangements; MoE experts and gate are passed through unchanged.
52 self.weight_processing_conversions = {
53 **self._qkvo_weight_conversions(),
54 }
56 self.component_mapping = {
57 "embed": EmbeddingBridge(name="model.embed_tokens"),
58 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb", config=self.cfg),
59 "blocks": BlockBridge(
60 name="model.layers",
61 submodules={
62 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
63 "ln2": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
64 "attn": PositionEmbeddingsAttentionBridge(
65 name="self_attn",
66 config=self.cfg,
67 submodules={
68 "q": LinearBridge(name="q_proj"),
69 "k": LinearBridge(name="k_proj"),
70 "v": LinearBridge(name="v_proj"),
71 "o": LinearBridge(name="o_proj"),
72 # Present only when use_qk_norm=True (config default False).
73 "q_norm": RMSNormalizationBridge(
74 name="q_norm", config=self.cfg, optional=True
75 ),
76 "k_norm": RMSNormalizationBridge(
77 name="k_norm", config=self.cfg, optional=True
78 ),
79 },
80 requires_attention_mask=True,
81 requires_position_embeddings=True,
82 ),
83 # Dense prefix layers (idx < first_k_dense_replace) expose
84 # `mlp` with no router; the dense_* projections bind there
85 # and carry the gated-MLP neuron hooks.
86 "mlp": MoEBridge(
87 name="mlp",
88 config=self.cfg,
89 sparse_required=("gate",),
90 submodules={
91 "gate": MoERouterBridge(name="gate", optional=True),
92 # Dense-layer projections (present only on the
93 # dense layers of this interleaved stack); their
94 # presence is what makes MoEBridge bind gated-MLP
95 # neuron hooks there (#1645).
96 "dense_gate": LinearBridge(name="gate_proj", optional=True),
97 "dense_in": LinearBridge(name="up_proj", optional=True),
98 "dense_out": LinearBridge(name="down_proj", optional=True),
99 },
100 ),
101 },
102 ),
103 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
104 "unembed": UnembeddingBridge(name="lm_head", config=self.cfg),
105 }