Coverage for transformer_lens/model_bridge/supported_architectures/gemma1.py: 100%
13 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"""Gemma1 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 Gemma1ArchitectureAdapter(ArchitectureAdapter):
22 """Architecture adapter for Gemma1 models."""
24 def __init__(self, cfg: Any) -> None:
25 """Initialize the Gemma1 architecture adapter."""
26 super().__init__(cfg)
28 self._set_rms_rotary_defaults()
30 # Gemma models use BOS tokens (tokenizer prepends BOS by default)
31 # Matches HookedTransformer behavior (default_prepend_bos = True)
32 self.cfg.default_prepend_bos = True
33 # Gemma models use (1.0 + weight) in RMSNorm instead of just weight
34 # See: https://github.com/huggingface/transformers/pull/29402
35 self.cfg.rmsnorm_uses_offset = True
37 self.weight_processing_conversions = {
38 # NOTE: Gemma1 scales embeddings by sqrt(d_model) at RUNTIME inside
39 # GemmaTextScaledWordEmbedding.forward() (HF transformers >= 5.0).
40 # That layer is what bridge.embed wraps, so embed.hook_out already
41 # captures the scaled value — matching HookedTransformer's hook_embed
42 # (which uses pre-scaled W_E). We must NOT pre-scale weights here and
43 # we must NOT install a runtime hook_conversion that re-scales.
44 #
45 # Attention weight conversions
46 **self._qkvo_weight_conversions(),
47 # Norm weights carry no conversion entry: cfg.rmsnorm_uses_offset is the
48 # only offset signal — weight processing and the runtime norm read it
49 # directly and apply (1 + w) themselves.
50 # MLP weight conversions - transpose from [out, in] to [in, out]
51 "blocks.{i}.mlp.gate.weight": ParamProcessingConversion(
52 tensor_conversion=TransposeTensorConversion(),
53 ),
54 "blocks.{i}.mlp.in.weight": ParamProcessingConversion(
55 tensor_conversion=TransposeTensorConversion(),
56 ),
57 "blocks.{i}.mlp.out.weight": ParamProcessingConversion(
58 tensor_conversion=TransposeTensorConversion(),
59 ),
60 # Unembed weight conversion - transpose from [vocab, d_model] to [d_model, vocab]
61 "unembed.weight": ParamProcessingConversion(
62 tensor_conversion=TransposeTensorConversion(),
63 ),
64 }
66 self.component_mapping = {
67 "embed": EmbeddingBridge(name="model.embed_tokens"),
68 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb", config=self.cfg),
69 "blocks": BlockBridge(
70 name="model.layers",
71 submodules={
72 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
73 "ln2": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
74 "attn": PositionEmbeddingsAttentionBridge(
75 name="self_attn",
76 config=self.cfg,
77 submodules={
78 "q": LinearBridge(name="q_proj"),
79 "k": LinearBridge(name="k_proj"),
80 "v": LinearBridge(name="v_proj"),
81 "o": LinearBridge(name="o_proj"),
82 },
83 requires_attention_mask=True,
84 requires_position_embeddings=True,
85 ),
86 "mlp": self._gated_mlp(),
87 },
88 ),
89 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
90 "unembed": UnembeddingBridge(name="lm_head"),
91 }