Coverage for transformer_lens/model_bridge/supported_architectures/laguna.py: 85%
23 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"""Laguna architecture adapter.
3poolside's Laguna coding models (``LagunaForCausalLM``, remote code):
4Llama-shaped causal decoders with two first-of-kind mechanisms —
5heterogeneous per-layer attention head counts
6(``num_attention_heads_per_layer``) and per-head softplus output gating
7(``g_proj``) — over a batched-expert MoE (FlexOlmo-style 3D expert
8parameters, top-k router, always-on shared experts) with per-layer
9dense/sparse selection via ``mlp_layer_types``.
11Attention delegates to HF: the bridge reimplementation assumes one
12uniform head count, and the softplus gate has no reconstruction. The
13per-layer head heterogeneity also rules out uniform Q/K/V reshape
14conversions, so no HookedTransformer-format conversions ship and LN
15folding is disabled.
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 MoEBridge,
27 RMSNormalizationBridge,
28 RotaryEmbeddingBridge,
29 UnembeddingBridge,
30)
31from transformer_lens.model_bridge.generalized_components.base import (
32 GeneralizedComponent,
33)
36class LagunaArchitectureAdapter(ArchitectureAdapter):
37 """Architecture adapter for LagunaForCausalLM models."""
39 # Per-layer head counts: no uniform "(n h) m -> n m h" reshape exists.
40 supports_fold_ln = False
41 # Delegated attention computes rotary inside HF; nothing to wire.
42 _testing_eager = None
43 _testing_wire_rotary = False
45 def __init__(self, cfg: Any) -> None:
46 """Initialize the Laguna architecture adapter."""
47 super().__init__(cfg)
49 self._set_rms_rotary_defaults()
51 self.weight_processing_conversions = {}
53 self.component_mapping = {
54 "embed": EmbeddingBridge(name="model.embed_tokens"),
55 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb"),
56 "blocks": BlockBridge(
57 name="model.layers",
58 config=self.cfg,
59 submodules={
60 "ln1": RMSNormalizationBridge(name="input_layernorm", config=self.cfg),
61 "ln2": RMSNormalizationBridge(name="post_attention_layernorm", config=self.cfg),
62 # Heterogeneous head counts + softplus output gating:
63 # delegate; projections and the gate are hookable.
64 "attn": AttentionBridge(
65 name="self_attn",
66 config=self.cfg,
67 submodules={
68 "q": LinearBridge(name="q_proj"),
69 "k": LinearBridge(name="k_proj"),
70 "v": LinearBridge(name="v_proj"),
71 "o": LinearBridge(name="o_proj"),
72 "gate": LinearBridge(name="g_proj"),
73 "q_norm": RMSNormalizationBridge(name="q_norm", config=self.cfg),
74 "k_norm": RMSNormalizationBridge(name="k_norm", config=self.cfg),
75 },
76 maintain_native_attention=True,
77 ),
78 # Dense or sparse per mlp_layer_types; router and shared
79 # experts optional so dense layers skip them.
80 "mlp": MoEBridge(
81 name="mlp",
82 config=self.cfg,
83 sparse_required=("gate",),
84 submodules={
85 "gate": GeneralizedComponent(name="gate", optional=True),
86 "shared_experts": self._gated_mlp(name="shared_experts", optional=True),
87 # Dense-layer projections (absent on MoE layers).
88 "dense_gate": LinearBridge(name="gate_proj", optional=True),
89 "dense_in": LinearBridge(name="up_proj", optional=True),
90 "dense_out": LinearBridge(name="down_proj", optional=True),
91 },
92 ),
93 },
94 ),
95 "ln_final": RMSNormalizationBridge(name="model.norm", config=self.cfg),
96 "unembed": UnembeddingBridge(name="lm_head"),
97 }
99 def prepare_loading(self, model_name: str, model_kwargs: dict) -> None:
100 """User-register Laguna's native conversion mapping so the per-expert->batched
101 expert merge runs under remote code (transformers skips it for custom-code
102 modules, leaving the batched experts at random init)."""
103 try:
104 from transformers.conversion_mapping import (
105 USER_REGISTERED_MAPPINGS,
106 get_checkpoint_conversion_mapping,
107 register_checkpoint_conversion_mapping,
108 )
109 except ImportError:
110 pass # transformers predates the conversion-mapping API; nothing to register
111 else:
112 if "laguna" not in USER_REGISTERED_MAPPINGS: 112 ↛ 116line 112 didn't jump to line 116 because the condition on line 112 was always true
113 mapping = get_checkpoint_conversion_mapping("laguna")
114 if mapping: 114 ↛ 116line 114 didn't jump to line 116 because the condition on line 114 was always true
115 register_checkpoint_conversion_mapping("laguna", mapping, overwrite=True)
116 super().prepare_loading(model_name, model_kwargs)