Coverage for transformer_lens/model_bridge/supported_architectures/t5gemma.py: 47%
35 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"""T5Gemma architecture adapter.
3T5GemmaForConditionalGeneration is an encoder-decoder model combining:
4- Gemma-style RoPE, GQA, gated MLP, and RMSNorm with offset (+1.0)
5- Encoder-decoder cross-attention in the decoder stack
6- Nested config: encoder/decoder dims live in cfg.encoder / cfg.decoder
8Key differences from plain T5:
9- Uses model.encoder.layers / model.decoder.layers (not .block)
10- No relative position bias; uses RoPE instead
11- All norms are Gemma-style (weight + 1.0)
12- lm_head is T5GemmaLMHead wrapping out_proj (no .weight at the top level)
13"""
15from typing import Any
17from transformer_lens.conversion_utils.conversion_steps import (
18 RearrangeTensorConversion,
19 TransposeTensorConversion,
20)
21from transformer_lens.conversion_utils.param_processing_conversion import (
22 ParamProcessingConversion,
23)
24from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
25from transformer_lens.model_bridge.generalized_components import (
26 AttentionBridge,
27 BlockBridge,
28 EmbeddingBridge,
29 LinearBridge,
30 PositionEmbeddingsAttentionBridge,
31 RMSNormalizationBridge,
32 RotaryEmbeddingBridge,
33 UnembeddingBridge,
34)
35from transformer_lens.model_bridge.generalized_components.t5gemma_decoder_block import (
36 T5GemmaDecoderBlockBridge,
37)
38from transformer_lens.utilities.attn_implementation import force_eager_attention
41class T5GemmaArchitectureAdapter(ArchitectureAdapter):
42 """Architecture adapter for T5GemmaForConditionalGeneration.
44 Encoder: BlockBridge over model.encoder.layers (Gemma-style, no cross-attn)
45 Decoder: T5GemmaDecoderBlockBridge over model.decoder.layers (adds cross-attn hooks)
46 """
48 def __init__(self, cfg: Any) -> None:
49 super().__init__(cfg)
51 self.supports_fold_ln = False
53 # Config flags used by bridge weight processing
54 self._set_rms_rotary_defaults()
55 # Gemma-family GELU; the nested enc/dec config defeats the auto-mapper,
56 # which would otherwise leave act_fn at the "relu" default.
57 self.cfg.act_fn = "gelu_pytorch_tanh"
58 # T5Gemma uses Gemma-style (1.0 + weight) RMSNorm offset
59 self.cfg.rmsnorm_uses_offset = True
61 # n_heads/n_kv are decoder-effective; unbalanced pairs (t5gemma-9b-2b)
62 # set different encoder counts, surfaced by the builder.
63 n_heads = self.cfg.n_heads
64 n_kv = getattr(self.cfg, "n_key_value_heads", None) or n_heads
65 enc_heads = getattr(self.cfg, "encoder_attention_heads", None) or n_heads
66 enc_kv = getattr(self.cfg, "encoder_key_value_heads", None) or n_kv
68 self.weight_processing_conversions = {
69 # Encoder self-attention
70 "encoder_blocks.{i}.self_attn.q_proj.weight": ParamProcessingConversion(
71 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=enc_heads),
72 ),
73 "encoder_blocks.{i}.self_attn.k_proj.weight": ParamProcessingConversion(
74 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=enc_kv),
75 ),
76 "encoder_blocks.{i}.self_attn.v_proj.weight": ParamProcessingConversion(
77 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=enc_kv),
78 ),
79 "encoder_blocks.{i}.self_attn.o_proj.weight": ParamProcessingConversion(
80 tensor_conversion=RearrangeTensorConversion("m (n h) -> n h m", n=enc_heads),
81 ),
82 # Norm weights carry no conversion entry: cfg.rmsnorm_uses_offset is the
83 # only offset signal — weight processing and the runtime norm read it
84 # directly and apply (1 + w) themselves.
85 # Encoder MLP (gated)
86 "encoder_blocks.{i}.mlp.gate_proj.weight": ParamProcessingConversion(
87 tensor_conversion=TransposeTensorConversion(),
88 ),
89 "encoder_blocks.{i}.mlp.up_proj.weight": ParamProcessingConversion(
90 tensor_conversion=TransposeTensorConversion(),
91 ),
92 "encoder_blocks.{i}.mlp.down_proj.weight": ParamProcessingConversion(
93 tensor_conversion=TransposeTensorConversion(),
94 ),
95 # Decoder self-attention
96 "decoder_blocks.{i}.self_attn.q_proj.weight": ParamProcessingConversion(
97 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_heads),
98 ),
99 "decoder_blocks.{i}.self_attn.k_proj.weight": ParamProcessingConversion(
100 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_kv),
101 ),
102 "decoder_blocks.{i}.self_attn.v_proj.weight": ParamProcessingConversion(
103 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_kv),
104 ),
105 "decoder_blocks.{i}.self_attn.o_proj.weight": ParamProcessingConversion(
106 tensor_conversion=RearrangeTensorConversion("m (n h) -> n h m", n=n_heads),
107 ),
108 # Decoder cross-attention
109 "decoder_blocks.{i}.cross_attn.q_proj.weight": ParamProcessingConversion(
110 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_heads),
111 ),
112 "decoder_blocks.{i}.cross_attn.k_proj.weight": ParamProcessingConversion(
113 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_kv),
114 ),
115 "decoder_blocks.{i}.cross_attn.v_proj.weight": ParamProcessingConversion(
116 tensor_conversion=RearrangeTensorConversion("(n h) m -> n m h", n=n_kv),
117 ),
118 "decoder_blocks.{i}.cross_attn.o_proj.weight": ParamProcessingConversion(
119 tensor_conversion=RearrangeTensorConversion("m (n h) -> n h m", n=n_heads),
120 ),
121 # Decoder MLP (gated)
122 "decoder_blocks.{i}.mlp.gate_proj.weight": ParamProcessingConversion(
123 tensor_conversion=TransposeTensorConversion(),
124 ),
125 "decoder_blocks.{i}.mlp.up_proj.weight": ParamProcessingConversion(
126 tensor_conversion=TransposeTensorConversion(),
127 ),
128 "decoder_blocks.{i}.mlp.down_proj.weight": ParamProcessingConversion(
129 tensor_conversion=TransposeTensorConversion(),
130 ),
131 # Unembed
132 "unembed.weight": ParamProcessingConversion(
133 tensor_conversion=TransposeTensorConversion(),
134 ),
135 }
137 self.component_mapping = {
138 # Encoder embedding and positional
139 "encoder_embed": EmbeddingBridge(name="model.encoder.embed_tokens"),
140 "encoder_rotary_emb": RotaryEmbeddingBridge(name="model.encoder.rotary_emb"),
141 # Encoder layers - Gemma-style BlockBridge (pre/post norms, RoPE attention, gated MLP)
142 "encoder_blocks": BlockBridge(
143 name="model.encoder.layers",
144 config=self.cfg,
145 submodules={
146 "ln1": RMSNormalizationBridge(name="pre_self_attn_layernorm", config=self.cfg),
147 "ln1_post": RMSNormalizationBridge(
148 name="post_self_attn_layernorm", config=self.cfg
149 ),
150 "attn": PositionEmbeddingsAttentionBridge(
151 name="self_attn",
152 config=self.cfg,
153 submodules={
154 "q": LinearBridge(name="q_proj"),
155 "k": LinearBridge(name="k_proj"),
156 "v": LinearBridge(name="v_proj"),
157 "o": LinearBridge(name="o_proj"),
158 },
159 requires_attention_mask=True,
160 requires_position_embeddings=True,
161 is_causal=False, # T5Gemma encoder is bidirectional
162 ),
163 "ln2": RMSNormalizationBridge(
164 name="pre_feedforward_layernorm", config=self.cfg
165 ),
166 "ln2_post": RMSNormalizationBridge(
167 name="post_feedforward_layernorm", config=self.cfg
168 ),
169 "mlp": self._gated_mlp(),
170 },
171 ),
172 # Encoder final norm
173 "encoder_ln_final": RMSNormalizationBridge(name="model.encoder.norm", config=self.cfg),
174 # Decoder embedding and positional
175 "decoder_embed": EmbeddingBridge(name="model.decoder.embed_tokens"),
176 "decoder_rotary_emb": RotaryEmbeddingBridge(name="model.decoder.rotary_emb"),
177 # Decoder layers — T5GemmaDecoderBlockBridge (adds cross-attn + two mid hooks)
178 "decoder_blocks": T5GemmaDecoderBlockBridge(
179 name="model.decoder.layers",
180 config=self.cfg,
181 submodules={
182 # Self-attention norms
183 "ln1": RMSNormalizationBridge(name="pre_self_attn_layernorm", config=self.cfg),
184 "ln1_post": RMSNormalizationBridge(
185 name="post_self_attn_layernorm", config=self.cfg
186 ),
187 "self_attn": PositionEmbeddingsAttentionBridge(
188 name="self_attn",
189 config=self.cfg,
190 submodules={
191 "q": LinearBridge(name="q_proj"),
192 "k": LinearBridge(name="k_proj"),
193 "v": LinearBridge(name="v_proj"),
194 "o": LinearBridge(name="o_proj"),
195 },
196 requires_attention_mask=True,
197 requires_position_embeddings=True,
198 ),
199 # Cross-attention norms
200 "ln2": RMSNormalizationBridge(name="pre_cross_attn_layernorm", config=self.cfg),
201 "ln2_post": RMSNormalizationBridge(
202 name="post_cross_attn_layernorm", config=self.cfg
203 ),
204 "cross_attn": AttentionBridge(
205 name="cross_attn",
206 config=self.cfg,
207 submodules={
208 "q": LinearBridge(name="q_proj"),
209 "k": LinearBridge(name="k_proj"),
210 "v": LinearBridge(name="v_proj"),
211 "o": LinearBridge(name="o_proj"),
212 },
213 is_cross_attention=True,
214 ),
215 # MLP norms
216 "ln3": RMSNormalizationBridge(
217 name="pre_feedforward_layernorm", config=self.cfg
218 ),
219 "ln3_post": RMSNormalizationBridge(
220 name="post_feedforward_layernorm", config=self.cfg
221 ),
222 "mlp": self._gated_mlp(),
223 },
224 ),
225 # Decoder final norm
226 "decoder_ln_final": RMSNormalizationBridge(name="model.decoder.norm", config=self.cfg),
227 # lm_head is T5GemmaLMHead; the weight lives on its inner out_proj Linear
228 "unembed": UnembeddingBridge(name="lm_head.out_proj", config=self.cfg),
229 }
231 def setup_component_testing(self, hf_model: Any, bridge_model: Any = None) -> None:
232 """Set up rotary embedding references for T5Gemma component testing.
234 Both the encoder and decoder carry their own rotary_emb. We set the
235 reference on all PositionEmbeddingsAttentionBridge instances so that
236 component-level forward calls can compute RoPE correctly.
237 """
238 encoder_rotary = hf_model.model.encoder.rotary_emb
239 decoder_rotary = hf_model.model.decoder.rotary_emb
241 force_eager_attention(hf_model)
243 if bridge_model is not None:
244 for block in getattr(bridge_model, "encoder_blocks", []):
245 if hasattr(block, "attn"):
246 block.attn.set_rotary_emb(encoder_rotary)
247 for block in getattr(bridge_model, "decoder_blocks", []):
248 if hasattr(block, "self_attn"):
249 block.self_attn.set_rotary_emb(decoder_rotary)
251 enc_attn = self.get_generalized_component("encoder_blocks.0.attn")
252 enc_attn.set_rotary_emb(encoder_rotary)
253 dec_self_attn = self.get_generalized_component("decoder_blocks.0.self_attn")
254 dec_self_attn.set_rotary_emb(decoder_rotary)