Coverage for transformer_lens/model_bridge/supported_architectures/qwen3.py: 100%
29 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"""Qwen3 architecture adapter.
3Base adapter for the Qwen3 model family. Provides shared config setup,
4attention bridge construction, and setup_component_testing used by
5Qwen3, Qwen3.5, and Qwen3Next variants.
6"""
8from typing import Any
10from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
11from transformer_lens.model_bridge.generalized_components import (
12 AttentionBridge,
13 BlockBridge,
14 EmbeddingBridge,
15 RMSNormalizationBridge,
16 RotaryEmbeddingBridge,
17 UnembeddingBridge,
18)
19from transformer_lens.model_bridge.generalized_components.gated_delta_net import (
20 GatedDeltaNetBridge,
21)
24class Qwen3ArchitectureAdapter(ArchitectureAdapter):
25 """Architecture adapter for Qwen3 dense models.
27 RMSNorm, RoPE, GQA, Q/K head norms, gated MLP. No biases.
28 Serves as base class for Qwen3.5 and Qwen3Next hybrid variants.
29 """
31 _testing_hybrid = True
33 def __init__(self, cfg: Any, *, hybrid: bool = False, lm_prefix: str = "model") -> None:
34 super().__init__(cfg)
35 self._setup_qwen3_config(cfg)
36 if hybrid:
37 self.supports_fold_ln = False
38 self.weight_processing_conversions: dict = {}
39 else:
40 self.weight_processing_conversions = {**self._qkvo_weight_conversions()}
41 self.component_mapping = self._build_component_mapping(hybrid=hybrid, lm_prefix=lm_prefix)
43 def _setup_qwen3_config(self, cfg: Any) -> None:
44 """Config shared across all Qwen3 variants (dense, hybrid, MoE)."""
45 self._set_rms_rotary_defaults()
46 self.cfg.default_prepend_bos = False
47 self.cfg.attn_implementation = "eager"
49 def _build_attention_bridge(self, optional: bool = False) -> AttentionBridge:
50 """Standard Qwen3 attention bridge with Q/K norms."""
51 return self._qkvo_attention_bridge(
52 optional=optional,
53 extra_submodules={
54 "q_norm": RMSNormalizationBridge(name="q_norm", config=self.cfg),
55 "k_norm": RMSNormalizationBridge(name="k_norm", config=self.cfg),
56 },
57 # None omits the flags, keeping the bridge class's own defaults.
58 requires_attention_mask=None,
59 requires_position_embeddings=None,
60 )
62 def _build_mlp_bridge(self):
63 """Dense gated MLP (gate_proj + up_proj -> down_proj). Override for MoE."""
64 return self._gated_mlp()
66 def _build_linear_attn_bridge(self, optional: bool = False) -> GatedDeltaNetBridge:
67 """GatedDeltaNet linear-attention bridge for hybrid variants."""
68 return GatedDeltaNetBridge(
69 name="linear_attn",
70 config=self.cfg,
71 optional=optional,
72 )
74 def _build_component_mapping(self, *, hybrid: bool = False, lm_prefix: str = "model") -> dict:
75 """Parametric component mapping. hybrid=True adds optional linear_attn; lm_prefix
76 nests the text model (``model``, or ``model.language_model`` for multimodal). lm_head
77 stays top-level.
78 """
79 block_submodules: dict = {
80 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
81 "ln2": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
82 "attn": self._build_attention_bridge(optional=hybrid),
83 "mlp": self._build_mlp_bridge(),
84 }
85 if hybrid:
86 block_submodules["linear_attn"] = self._build_linear_attn_bridge(optional=True)
87 return {
88 "embed": EmbeddingBridge(name=f"{lm_prefix}.embed_tokens"),
89 "rotary_emb": RotaryEmbeddingBridge(name=f"{lm_prefix}.rotary_emb", config=self.cfg),
90 "blocks": BlockBridge(name=f"{lm_prefix}.layers", submodules=block_submodules),
91 "ln_final": RMSNormalizationBridge(name=f"{lm_prefix}.norm", config=self.cfg),
92 "unembed": UnembeddingBridge(name="lm_head"),
93 }