Coverage for transformer_lens/components/t5_block.py: 88%
64 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
1from typing import Optional
3import torch
4import torch.nn as nn
5from jaxtyping import Float
7from transformer_lens.cache.key_value_cache_entry import (
8 TransformerLensKeyValueCacheEntry,
9)
10from transformer_lens.components import RMSNorm, T5Attention
11from transformer_lens.config.hooked_transformer_config import HookedTransformerConfig
12from transformer_lens.factories.mlp_factory import MLPFactory
13from transformer_lens.hook_points import HookPoint
14from transformer_lens.utilities import repeat_along_head_dimension
17class T5Block(nn.Module):
18 """
19 T5 decoder Block. Uses T5Layernorm, and T5attention instead of usual ones.
20 Also uses cross attention if is_decoder is True.
21 """
23 def __init__(self, cfg: HookedTransformerConfig, block_index: int, is_decoder: bool):
24 super().__init__()
25 self.cfg = cfg
26 self.is_decoder = is_decoder
28 self.ln1 = RMSNorm(cfg)
29 self.attn = T5Attention(
30 cfg, has_relative_attention_bias=block_index == 0, is_decoder=is_decoder
31 )
32 self.ln2 = RMSNorm(cfg)
33 if self.is_decoder:
34 self.cross_attn = T5Attention(cfg)
35 self.ln3 = RMSNorm(cfg)
36 self.mlp = MLPFactory.create_mlp(self.cfg) # [batch, pos, n_heads]
38 self.hook_q_input = HookPoint() # [batch, pos, n_heads, d_model]
39 self.hook_k_input = HookPoint() # [batch, pos, n_heads, d_model]
40 self.hook_v_input = HookPoint() # [batch, pos, n_heads, d_model]
42 self.hook_attn_in = HookPoint() # [batch, pos, d_model]
43 self.hook_attn_out = HookPoint() # [batch, pos, d_model]
44 if self.is_decoder:
45 self.hook_cross_attn_in = HookPoint() # [batch, pos, d_model]
46 self.hook_cross_attn_out = HookPoint() # [batch, pos, d_model]
47 self.hook_resid_mid_cross = HookPoint() # [batch, pos, d_model]
49 self.hook_mlp_in = HookPoint() # [batch, pos, d_model]
50 self.hook_mlp_out = HookPoint() # [batch, pos, d_model]
51 self.hook_resid_pre = HookPoint() # [batch, pos, d_model]
52 self.hook_resid_mid = HookPoint() # [batch, pos, d_model]
53 self.hook_resid_post = HookPoint() # [batch, pos, d_model]
55 def forward(
56 self,
57 resid_pre: Float[torch.Tensor, "batch pos d_model"],
58 additive_attention_mask: Optional[Float[torch.Tensor, "batch 1 1 pos"]] = None,
59 encoder_additive_attention_mask: Optional[
60 Float[torch.Tensor, "batch 1 1 encoder_pos"]
61 ] = None,
62 position_bias: Optional[Float[torch.Tensor, "1 head_index pos kv_pos"]] = None,
63 encoder_hidden_states: Optional[Float[torch.Tensor, "batch encoder_pos d_model"]] = None,
64 past_kv_cache_entry: Optional[TransformerLensKeyValueCacheEntry] = None,
65 ) -> Float[torch.Tensor, "batch pos d_model"]:
66 """A single Transformer block.
68 Args:
69 resid_pre (torch.Tensor): The residual stream - shape [batch, pos, d_model]
70 encoder_hidden_states (torch.Tensor): The hidden states of the encoder for cross attention - shape [batch, encoder_pos, d_model]
71 cache (TransformerLensKeyValueCache): A cache of previous keys and values, used only when generating text. Defaults to None.
72 attention_mask (torch.Tensor, optional): The attention mask for padded tokens. Defaults to None.
74 Returns:
75 Float[torch.Tensor, "batch pos d_model"]: The block output residual stream.
76 """
77 resid_pre = self.hook_resid_pre(resid_pre) # [batch, pos, d_model]
79 attn_in = resid_pre
81 if self.cfg.use_attn_in: 81 ↛ 82line 81 didn't jump to line 82 because the condition on line 81 was never true
82 attn_in = self.hook_attn_in(
83 repeat_along_head_dimension(resid_pre, n_heads=self.cfg.n_heads)
84 )
86 if self.cfg.use_split_qkv_input: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true
87 n_kv_heads = (
88 self.cfg.n_key_value_heads
89 if self.cfg.n_key_value_heads is not None
90 else self.cfg.n_heads
91 )
92 query_input = self.hook_q_input(
93 repeat_along_head_dimension(resid_pre, n_heads=self.cfg.n_heads)
94 )
95 key_input = self.hook_k_input(
96 repeat_along_head_dimension(resid_pre, n_heads=n_kv_heads)
97 )
98 value_input = self.hook_v_input(
99 repeat_along_head_dimension(resid_pre, n_heads=n_kv_heads)
100 )
101 else:
102 query_input = attn_in
103 key_input = attn_in
104 value_input = attn_in
106 attn_out = self.hook_attn_out(
107 # hook the residual stream states that are used to calculate the
108 # queries, keys and values, independently.
109 # Then take the layer norm of these inputs, and pass these to the attention module.
110 self.attn(
111 query_input=self.ln1(query_input),
112 key_input=self.ln1(key_input),
113 value_input=self.ln1(value_input),
114 past_kv_cache_entry=past_kv_cache_entry,
115 additive_attention_mask=additive_attention_mask,
116 position_bias=position_bias,
117 )
118 )
120 # [batch, pos, d_model]
122 resid_mid = self.hook_resid_mid(resid_pre + attn_out) # [batch, pos, d_model]
124 if self.is_decoder:
125 cross_attn_in = (
126 resid_mid
127 if not self.cfg.use_attn_in
128 else self.hook_cross_attn_in(resid_mid.clone())
129 )
131 if encoder_hidden_states is None: 131 ↛ 132line 131 didn't jump to line 132 because the condition on line 131 was never true
132 raise ValueError("Encoder hidden states must be provided for cross attention!")
134 cross_attn_out = self.hook_cross_attn_out(
135 self.cross_attn(
136 query_input=self.ln2(cross_attn_in),
137 key_input=encoder_hidden_states,
138 value_input=encoder_hidden_states,
139 additive_attention_mask=encoder_additive_attention_mask,
140 )
141 )
142 resid_mid_cross = self.hook_resid_mid_cross(resid_mid + cross_attn_out)
144 mlp_in = (
145 resid_mid_cross
146 if not self.cfg.use_hook_mlp_in
147 else self.hook_mlp_in(resid_mid_cross.clone())
148 )
150 normalized_resid_mid = self.ln3(mlp_in)
151 else:
152 mlp_in = (
153 resid_mid if not self.cfg.use_hook_mlp_in else self.hook_mlp_in(resid_mid.clone())
154 )
155 normalized_resid_mid = self.ln2(mlp_in)
157 mlp_out = self.hook_mlp_out(self.mlp(normalized_resid_mid)) # [batch, pos, d_model]
158 resid_post = self.hook_resid_post(mlp_in + mlp_out) # [batch, pos, d_model]
160 return resid_post