Coverage for transformer_lens/utilities/attn_implementation.py: 100%
31 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-21 19:27 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-09-21 19:27 +0000
1"""attn_implementation.
3Shared helper for forcing eager attention on a loaded HuggingFace model.
4"""
6from __future__ import annotations
8from typing import Any, List
11def force_eager_attention(model: Any, *, per_layer: bool = False) -> None:
12 """Switch a pre-loaded model to eager attention so attention hooks can fire.
14 Prefers the public ``set_attn_implementation`` API; exotic wrapped models can
15 reject it, so failures fall back to writing ``config._attn_implementation``
16 (including nested multimodal ``text_config``). ``per_layer=True`` also stamps
17 every submodule's ``self_attn.config`` — some models keep per-layer config
18 copies that the top-level write never reaches.
20 Best-effort by design: never raises, silently no-ops on objects exposing
21 neither the public API nor a config.
22 """
23 handled = False
24 if hasattr(model, "set_attn_implementation"):
25 try:
26 model.set_attn_implementation("eager")
27 handled = True
28 except Exception:
29 pass # Exotic wrapped models can reject the public API; write the config instead.
30 if not handled:
31 config = getattr(model, "config", None)
32 if config is not None and hasattr(config, "_attn_implementation"):
33 config._attn_implementation = "eager"
34 # Nested multimodal configs carry their own attn implementation.
35 text_config = getattr(config, "text_config", None)
36 if text_config is not None:
37 text_config._attn_implementation = "eager"
38 if per_layer:
39 for layer in _layer_candidates(model):
40 if hasattr(layer, "self_attn") and hasattr(layer.self_attn, "config"):
41 layer.self_attn.config._attn_implementation = "eager"
44def _layer_candidates(model: Any) -> List[Any]:
45 """Modules that might own a per-layer attention config.
47 Real models walk ``modules()`` so nested stacks (``model.language_model``,
48 HRM's L/H modules) are covered; plain-object test fakes fall back to the
49 conventional ``model.model.layers`` chain.
50 """
51 modules = getattr(model, "modules", None)
52 if callable(modules):
53 try:
54 return list(modules())
55 except TypeError:
56 return [] # Mock-style modules() returning a non-iterable.
57 lm = getattr(model, "model", None)
58 layers = getattr(lm, "layers", None) if lm is not None else None
59 return list(layers) if layers is not None else []