Coverage for transformer_lens/model_bridge/supported_architectures/exaone.py: 48%
27 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"""EXAONE architecture adapter.
3Supports LG AI Research's EXAONE-3.0 / 3.5 / Deep families
4(``ExaoneForCausalLM``, trust_remote_code checkpoints). Llama-style RMSNorm +
5RoPE + GQA + gated MLP under GPT-2-flavored module names: ``transformer.wte``,
6``transformer.h[i]``, ``transformer.ln_f``, and a double-nested attention
7(``attn.attention``). EXAONE-4.0 is a separate native-transformers
8architecture (Exaone4ForCausalLM) and is not covered here.
9"""
11from typing import Any
13from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
14from transformer_lens.model_bridge.generalized_components import (
15 BlockBridge,
16 EmbeddingBridge,
17 LinearBridge,
18 PositionEmbeddingsAttentionBridge,
19 RMSNormalizationBridge,
20 RotaryEmbeddingBridge,
21 UnembeddingBridge,
22)
25class ExaoneArchitectureAdapter(ArchitectureAdapter):
26 """Architecture adapter for ExaoneForCausalLM (EXAONE-3.x) models.
28 The remote modeling code follows current HF conventions (Cache API,
29 position_embeddings tuples), so the standard bridges delegate cleanly.
30 Naming quirks: attention projections live one level deeper than usual
31 (``attn.attention.q_proj``), the gated MLP uses ``c_fc_0`` (gate) /
32 ``c_fc_1`` (up) / ``c_proj`` (down), and rotary sits at
33 ``transformer.rotary``.
34 """
36 _testing_lm_attr = "transformer"
37 _testing_rotary_attr = "rotary"
38 _testing_eager = "config"
40 def __init__(self, cfg: Any) -> None:
41 """Initialize the EXAONE architecture adapter."""
42 super().__init__(cfg)
44 self._set_rms_rotary_defaults()
45 # Verified against LGAI-EXAONE/EXAONE-3.5-2.4B-Instruct: no BOS prepended.
46 self.cfg.default_prepend_bos = False
48 self.weight_processing_conversions = {
49 **self._qkvo_weight_conversions(),
50 }
52 self.component_mapping = {
53 "embed": EmbeddingBridge(name="transformer.wte"),
54 "rotary_emb": RotaryEmbeddingBridge(name="transformer.rotary", config=self.cfg),
55 "blocks": BlockBridge(
56 name="transformer.h",
57 submodules={
58 "ln1": RMSNormalizationBridge(name="ln_1", config=self.cfg),
59 "ln2": RMSNormalizationBridge(name="ln_2", config=self.cfg),
60 "attn": PositionEmbeddingsAttentionBridge(
61 name="attn.attention",
62 config=self.cfg,
63 submodules={
64 "q": LinearBridge(name="q_proj"),
65 "k": LinearBridge(name="k_proj"),
66 "v": LinearBridge(name="v_proj"),
67 "o": LinearBridge(name="out_proj"),
68 },
69 requires_attention_mask=True,
70 requires_position_embeddings=True,
71 ),
72 "mlp": self._gated_mlp(gate="c_fc_0", up="c_fc_1", down="c_proj"),
73 },
74 ),
75 "ln_final": RMSNormalizationBridge(name="transformer.ln_f", config=self.cfg),
76 "unembed": UnembeddingBridge(name="lm_head", config=self.cfg),
77 }
79 def prepare_model(self, hf_model: Any) -> Any:
80 """Shim the EXAONE-3.x remote module for transformers >= 5.13, which renamed
81 create_causal_mask's ``input_embeds`` kwarg to ``inputs_embeds``."""
82 result = super().prepare_model(hf_model)
83 model = result if result is not None else hf_model
85 import sys
87 from transformers.masking_utils import create_causal_mask
89 module = sys.modules.get(type(model).__module__)
90 if module is not None and hasattr(module, "create_causal_mask"):
92 def _shim(*args: Any, **kwargs: Any) -> Any:
93 if "input_embeds" in kwargs:
94 kwargs["inputs_embeds"] = kwargs.pop("input_embeds")
95 kwargs.pop("cache_position", None)
96 return create_causal_mask(*args, **kwargs)
98 setattr(module, "create_causal_mask", _shim)
99 return result