Coverage for transformer_lens/model_bridge/generalized_components/pos_embed.py: 90%
30 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
1"""Positional embedding bridge component.
3This module contains the bridge component for positional embedding layers.
4"""
5from typing import Any, Dict, Optional
7import torch
9from transformer_lens.model_bridge.generalized_components.base import (
10 GeneralizedComponent,
11)
14class PosEmbedBridge(GeneralizedComponent):
15 """Positional embedding bridge that wraps transformer positional embedding layers.
17 This component provides standardized input/output hooks for positional embeddings.
18 """
20 property_aliases = {"W_pos": "weight"}
22 def __init__(
23 self,
24 name: str,
25 config: Optional[Any] = None,
26 submodules: Optional[Dict[str, GeneralizedComponent]] = {},
27 ):
28 """Initialize the positional embedding bridge.
30 Args:
31 name: The name of this component
32 config: Optional configuration (unused for PosEmbedBridge)
33 submodules: Dictionary of GeneralizedComponent submodules to register
34 """
35 super().__init__(name, config, submodules=submodules)
37 @property
38 def W_pos(self) -> torch.Tensor:
39 """Return the positional embedding weight matrix."""
40 if self.original_component is None: 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 raise RuntimeError(f"Original component not set for {self.name}")
42 # Sinusoidal nn.Module variants (e.g. M2M100) register the table as a
43 # "weights" buffer instead of an nn.Embedding "weight" parameter.
44 weight = getattr(self.original_component, "weight", None)
45 if weight is None:
46 weight = getattr(self.original_component, "weights", None)
47 assert isinstance(
48 weight, torch.Tensor
49 ), f"Component {self.name} has no weight/weights tensor"
50 return weight
52 def forward(self, *args: Any, **kwargs: Any) -> torch.Tensor:
53 """Forward pass through the positional embedding bridge.
55 This method accepts variable arguments to support different architectures:
56 - Standard models (GPT-2, GPT-Neo): (input_ids, position_ids=None)
57 - OPT models: (attention_mask, past_key_values_length=0, position_ids=None)
58 - Others may have different signatures
60 Args:
61 *args: Positional arguments forwarded to the original component
62 **kwargs: Keyword arguments forwarded to the original component
64 Returns:
65 Positional embeddings
66 """
67 if self.original_component is None: 67 ↛ 68line 67 didn't jump to line 68 because the condition on line 67 was never true
68 raise RuntimeError(
69 f"Original component not set for {self.name}. Call set_original_component() first."
70 )
71 # Sinusoidal variants (e.g. Marian) receive a torch.Size, not a tensor;
72 # there is nothing to hook in that case.
73 if args and isinstance(args[0], torch.Tensor):
74 first_arg = self.hook_in(args[0])
75 args = (first_arg,) + args[1:]
76 output = self.original_component(*args, **kwargs)
78 # Expand batch=1 pos embeddings to match actual batch size for hooks.
79 batch_size = getattr(self, "_current_batch_size", None)
81 # Read-and-clear to avoid stale values during generate() steps.
82 if batch_size is not None:
83 self._current_batch_size = None
84 if (
85 batch_size is not None
86 and batch_size > 1
87 and isinstance(output, torch.Tensor)
88 and output.ndim >= 1
89 and output.shape[0] == 1
90 ):
91 output = output.expand(batch_size, *[-1] * (output.ndim - 1))
93 output = self.hook_out(output)
94 return output