Coverage for transformer_lens/model_bridge/supported_architectures/glm4_moe.py: 100%
12 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-01 16:23 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-01 16:23 +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 Glm4MoeRouterBridge(MoERouterBridge):
34 """Tuple-preserving router bridge for ``Glm4MoeTopkRouter``."""
37class Glm4MoeArchitectureAdapter(ArchitectureAdapter):
38 """Architecture adapter for GLM-4.5 / 4.6 / 4.7 MoE decoder models.
40 GLM-4x MoE families use RMSNorm, RoPE and sparse routing, with early
41 dense-MLP layers in some checkpoints. The dense layers are represented by
42 a present-but-slightly-thinner `mlp` sub-module where routing is absent.
43 """
45 def __init__(self, cfg: Any) -> None:
46 """Initialize the GLM-4 MoE architecture adapter."""
47 super().__init__(cfg)
49 self._set_rms_rotary_defaults()
50 # Force eager attention for output_attentions / compatibility-path parity.
51 self.cfg.attn_implementation = "eager"
52 # GLM-4 defaults do not prepend BOS in current tiny checkpoints.
53 self.cfg.default_prepend_bos = False
55 # QKVO rearrangements; MoE experts and gate are passed through unchanged.
56 self.weight_processing_conversions = {
57 **self._qkvo_weight_conversions(),
58 }
60 self.component_mapping = {
61 "embed": EmbeddingBridge(name="model.embed_tokens"),
62 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb", config=self.cfg),
63 "blocks": BlockBridge(
64 name="model.layers",
65 submodules={
66 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
67 "ln2": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
68 "attn": PositionEmbeddingsAttentionBridge(
69 name="self_attn",
70 config=self.cfg,
71 submodules={
72 "q": LinearBridge(name="q_proj"),
73 "k": LinearBridge(name="k_proj"),
74 "v": LinearBridge(name="v_proj"),
75 "o": LinearBridge(name="o_proj"),
76 # Present only when use_qk_norm=True (config default False).
77 "q_norm": RMSNormalizationBridge(
78 name="q_norm", config=self.cfg, optional=True
79 ),
80 "k_norm": RMSNormalizationBridge(
81 name="k_norm", config=self.cfg, optional=True
82 ),
83 },
84 requires_attention_mask=True,
85 requires_position_embeddings=True,
86 ),
87 # Dense prefix layers (idx < first_k_dense_replace) expose
88 # `mlp` with no router; the dense_* projections bind there
89 # and carry the gated-MLP neuron hooks.
90 "mlp": MoEBridge(
91 name="mlp",
92 config=self.cfg,
93 sparse_required=("gate",),
94 submodules={
95 "gate": Glm4MoeRouterBridge(name="gate", optional=True),
96 # Dense-layer projections (present only on the
97 # dense layers of this interleaved stack); their
98 # presence is what makes MoEBridge bind gated-MLP
99 # neuron hooks there (#1645).
100 "dense_gate": LinearBridge(name="gate_proj", optional=True),
101 "dense_in": LinearBridge(name="up_proj", optional=True),
102 "dense_out": LinearBridge(name="down_proj", optional=True),
103 },
104 ),
105 },
106 ),
107 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
108 "unembed": UnembeddingBridge(name="lm_head", config=self.cfg),
109 }