Coverage for transformer_lens/model_bridge/supported_architectures/gidd.py: 64%
56 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-08-11 18:50 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-08-11 18:50 +0000
1"""Gidd architecture adapter.
3Dimitri von Rütte's GIDD (``GiddForDiffusionLM``, remote code): the only
4open uniform-noise (non-masked) diffusion LM at scale, with self-correction
5sampling. The decoder is bidirectional (config.is_causal=False) with
6softcap attention variants, optional per-head QK norms, ScaledLinear
7projections (weight-scaled at forward), per-layer scaled residual adds
8(resid_scale/num_layers), an ungated up/down MLP, and rotary positions
9held as a model-level buffer rather than a module.
11Everything nonstandard lives inside delegated modules: attention delegates
12wholesale (softcap + bidirectional), ScaledLinear wraps as plain hookable
13Linears, and generation is the model's own diffusion sampler, reached via
14``bridge.diffusion_generate`` — no autoregressive generation, no folding
15into scaled projections.
16"""
18from typing import Any
20from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
21from transformer_lens.model_bridge.generalized_components import (
22 AttentionBridge,
23 BlockBridge,
24 EmbeddingBridge,
25 LinearBridge,
26 RMSNormalizationBridge,
27 UnembeddingBridge,
28)
31def restore_frequencies(hf_model: Any) -> bool:
32 """Recompute GIDD's non-persistent ``frequencies`` rotary table; under v5's
33 meta-device load it materializes as uninitialized memory that silently corrupts
34 every forward (applied to both bridge and HF reference so they agree)."""
35 import sys
37 inner = getattr(hf_model, "model", None)
38 old = getattr(inner, "frequencies", None)
39 if inner is None or old is None:
40 return False
41 module = sys.modules.get(type(inner).__module__)
42 compute = getattr(module, "compute_basic_frequencies", None)
43 if compute is None: 43 ↛ 44line 43 didn't jump to line 44 because the condition on line 43 was never true
44 return False
45 config = hf_model.config
46 freqs = compute(
47 base=config.rope_theta,
48 rotary_dim=config.hidden_size // config.num_attention_heads,
49 max_position_embeddings=config.max_position_embeddings,
50 )
51 inner.frequencies = freqs.to(device=old.device, dtype=old.dtype)
52 return True
55class GiddArchitectureAdapter(ArchitectureAdapter):
56 """Architecture adapter for GiddForDiffusionLM models."""
58 applicable_phases: list[int] = [1, 2, 3, 4]
59 supports_generation: bool = False
60 # Block-wise denoising with self-correction, shipped on the model class.
61 native_sampler: str = "generate"
62 # ScaledLinear applies a runtime weight scale; folding norms into those
63 # projections (or centering through scaled residual adds) is unsound.
64 supports_fold_ln = False
66 def native_sampler_kwargs(self, max_new_tokens: int, prompt_len: int) -> dict:
67 """Gidd's max_length counts generated tokens: its windows start at
68 prompt_length and span max_length, so adding the prompt over-generates."""
69 return {
70 "max_length": max_new_tokens,
71 "block_length": min(128, max_new_tokens),
72 "steps": max_new_tokens,
73 }
75 def __init__(self, cfg: Any) -> None:
76 """Initialize the Gidd architecture adapter."""
77 super().__init__(cfg)
79 self.cfg.normalization_type = "RMS"
80 self.cfg.uses_rms_norm = True
81 self.cfg.positional_embedding_type = "rotary"
82 self.cfg.gated_mlp = False # ungated up/down MLP
83 self.cfg.attn_only = False
84 self.cfg.final_rms = True
86 self.weight_processing_conversions = {}
88 self.component_mapping = {
89 "embed": EmbeddingBridge(name="model.embed_tokens"),
90 "blocks": BlockBridge(
91 name="model.layers",
92 config=self.cfg,
93 submodules={
94 "ln1": RMSNormalizationBridge(name="attn_layernorm", config=self.cfg),
95 "ln2": RMSNormalizationBridge(name="mlp_layernorm", config=self.cfg),
96 # Bidirectional softcap attention: delegate; QK norms only
97 # exist when use_qk_norm is set.
98 "attn": AttentionBridge(
99 name="self_attn",
100 config=self.cfg,
101 submodules={
102 "q": LinearBridge(name="q_proj"),
103 "k": LinearBridge(name="k_proj"),
104 "v": LinearBridge(name="v_proj"),
105 "o": LinearBridge(name="o_proj"),
106 "q_norm": RMSNormalizationBridge(
107 name="q_norm", config=self.cfg, optional=True
108 ),
109 "k_norm": RMSNormalizationBridge(
110 name="k_norm", config=self.cfg, optional=True
111 ),
112 },
113 maintain_native_attention=True,
114 ),
115 "mlp": self._ungated_mlp(),
116 },
117 ),
118 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
119 "unembed": UnembeddingBridge(name="lm_head"),
120 }
122 def prepare_loading(self, model_name: str, model_kwargs: dict) -> None:
123 """Patch the remote class before from_pretrained runs.
125 Like BD3LM, the remote code's attribute handling raises on v5's
126 all_tied_weights_keys lookup (the checkpoint is untied anyway).
127 """
128 try:
129 from transformers.dynamic_module_utils import get_class_from_dynamic_module
131 model_class = get_class_from_dynamic_module(
132 "modeling_gidd.GiddForDiffusionLM", model_name
133 )
134 setattr(model_class, "all_tied_weights_keys", {})
135 # v5 walks _init_weights over every module post-materialization;
136 # the remote _init_weights assumes module.weight exists (crashes
137 # on containers) and would re-randomize loaded tensors anyway.
138 # Skip modules whose params are already real (internlm2 pattern).
139 pretrained_cls = model_class.__mro__[1]
140 if not getattr(pretrained_cls, "_tl_patched", False):
141 original_init_weights = getattr(pretrained_cls, "_init_weights")
143 def safe_init_weights(self, mod, _original=original_init_weights):
144 first_param = next(mod.parameters(), None)
145 if first_param is not None and first_param.device.type != "meta":
146 return
147 _original(self, mod)
149 setattr(pretrained_cls, "_init_weights", safe_init_weights)
150 setattr(pretrained_cls, "_tl_patched", True)
151 except Exception:
152 pass
153 super().prepare_loading(model_name, model_kwargs)
155 def prepare_model(self, hf_model: Any) -> None:
156 """Restore the rotary table lost to meta-device loading."""
157 super().prepare_model(hf_model)
158 restore_frequencies(hf_model)
160 def setup_component_testing(self, hf_model: Any, bridge_model: Any = None) -> None:
161 """Delegated attention reads the rotary buffer inside HF; nothing to wire."""