Coverage for transformer_lens/model_bridge/supported_architectures/gemma2.py: 83%
19 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-10-10 05:10 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-10-10 05:10 +0000
1"""Gemma2 architecture adapter."""
3from typing import Any
5from transformer_lens.conversion_utils.conversion_steps import TransposeTensorConversion
6from transformer_lens.conversion_utils.param_processing_conversion import (
7 ParamProcessingConversion,
8)
9from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
10from transformer_lens.model_bridge.generalized_components import (
11 BlockBridge,
12 EmbeddingBridge,
13 LinearBridge,
14 PositionEmbeddingsAttentionBridge,
15 RMSNormalizationBridge,
16 RotaryEmbeddingBridge,
17 UnembeddingBridge,
18)
21class Gemma2ArchitectureAdapter(ArchitectureAdapter):
22 """Architecture adapter for Gemma2 models."""
24 def __init__(self, cfg: Any) -> None:
25 """Initialize the Gemma2 architecture adapter."""
26 super().__init__(cfg)
28 self._set_rms_rotary_defaults()
30 self.cfg.uses_rms_norm = True
31 # Gemma models use (1.0 + weight) in RMSNorm instead of just weight
32 # See: https://github.com/huggingface/transformers/pull/29402
33 self.cfg.rmsnorm_uses_offset = True
35 # Gemma2 uses logit softcapping
36 if hasattr(self.cfg, "final_logit_softcapping"): 36 ↛ 37line 36 didn't jump to line 37 because the condition on line 36 was never true
37 self.cfg.output_logits_soft_cap = self.cfg.final_logit_softcapping
38 if hasattr(self.cfg, "attn_logit_softcapping"): 38 ↛ 39line 38 didn't jump to line 39 because the condition on line 38 was never true
39 self.cfg.attn_scores_soft_cap = self.cfg.attn_logit_softcapping
41 # Note: n_key_value_heads is now automatically mapped from num_key_value_heads
42 # by map_default_transformer_lens_config() in sources/transformers.py
44 self.weight_processing_conversions = {
45 # NOTE: Gemma2 scales embeddings by sqrt(d_model) at RUNTIME inside
46 # Gemma2TextScaledWordEmbedding.forward() (HF transformers >= 5.0).
47 # That layer is what bridge.embed wraps, so embed.hook_out already
48 # captures the scaled value — matching HookedTransformer's hook_embed
49 # (which uses pre-scaled W_E). We must NOT pre-scale weights here and
50 # we must NOT install a runtime hook_conversion that re-scales.
51 **self._qkvo_weight_conversions(),
52 # Norm weights carry no conversion entry: cfg.rmsnorm_uses_offset is the
53 # only offset signal — weight processing and the runtime norm read it
54 # directly and apply (1 + w) themselves.
55 # MLP weight conversions - transpose from [out, in] to [in, out]
56 "blocks.{i}.mlp.gate.weight": ParamProcessingConversion(
57 tensor_conversion=TransposeTensorConversion(),
58 ),
59 "blocks.{i}.mlp.in.weight": ParamProcessingConversion(
60 tensor_conversion=TransposeTensorConversion(),
61 ),
62 "blocks.{i}.mlp.out.weight": ParamProcessingConversion(
63 tensor_conversion=TransposeTensorConversion(),
64 ),
65 # # Unembed weight conversion - transpose from [vocab, d_model] to [d_model, vocab]
66 "unembed.weight": ParamProcessingConversion(
67 tensor_conversion=TransposeTensorConversion(),
68 ),
69 }
71 self.component_mapping = {
72 "embed": EmbeddingBridge(name="model.embed_tokens"),
73 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb"),
74 "blocks": BlockBridge(
75 name="model.layers",
76 config=self.cfg,
77 submodules={
78 # Gemma 2 uses RMSNorm for all normalization layers
79 **self._block_norms(),
80 # Gemma 2 uses PositionEmbeddingsAttentionBridge like Gemma 3
81 "attn": PositionEmbeddingsAttentionBridge(
82 name="self_attn",
83 config=self.cfg,
84 submodules={
85 "q": LinearBridge(name="q_proj"),
86 "k": LinearBridge(name="k_proj"),
87 "v": LinearBridge(name="v_proj"),
88 "o": LinearBridge(name="o_proj"),
89 },
90 requires_attention_mask=True,
91 requires_position_embeddings=True,
92 ),
93 "mlp": self._gated_mlp(),
94 },
95 ),
96 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
97 "unembed": UnembeddingBridge(name="lm_head", config=self.cfg),
98 }
100 def _block_norms(self):
101 """Norm-layout seam; VaultGemma drops the two post-norms."""
102 return {
103 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
104 "ln1_post": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
105 "ln2": RMSNormalizationBridge(name="pre_feedforward_layernorm", config=self.cfg),
106 "ln2_post": RMSNormalizationBridge(name="post_feedforward_layernorm", config=self.cfg),
107 }