Coverage for transformer_lens/model_bridge/supported_architectures/nemotron.py: 100%
17 statements
« prev ^ index » next coverage.py v7.10.1, created at 2026-10-10 05:10 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2026-10-10 05:10 +0000
1"""Nemotron architecture adapter.
3NVIDIA's dense Nemotron-3/4 and Minitron families (``NemotronForCausalLM``):
4llama-shaped GQA decoder with three quirks — LayerNorm1P normalization
5(zero-centered gamma, applied as ``weight + 1``), a non-gated squared-ReLU
6MLP (``up_proj``/``down_proj`` only), and partial rotary embeddings
7(rotary factor 0.5).
8"""
10from typing import Any
12from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
13from transformer_lens.model_bridge.generalized_components import (
14 BlockBridge,
15 EmbeddingBridge,
16 LinearBridge,
17 NormalizationBridge,
18 PositionEmbeddingsAttentionBridge,
19 RotaryEmbeddingBridge,
20 UnembeddingBridge,
21)
24class NemotronArchitectureAdapter(ArchitectureAdapter):
25 """Architecture adapter for NemotronForCausalLM models."""
27 _testing_eager = "config"
29 def __init__(self, cfg: Any) -> None:
30 """Initialize the Nemotron architecture adapter."""
31 super().__init__(cfg)
33 self.cfg.normalization_type = "LN"
34 self.cfg.positional_embedding_type = "rotary"
35 self.cfg.final_rms = False
36 self.cfg.gated_mlp = False
37 self.cfg.attn_only = False
39 # LayerNorm1P applies gamma as (weight + 1); standard LN folding would
40 # fold the stored weight without the offset. Keep raw weights.
41 self.supports_fold_ln = False
42 self.supports_center_writing_weights = False
43 # The bridge's own norm paths (hook edits, backward hooks, LN-rule) need the offset too.
44 self.cfg.rmsnorm_uses_offset = True
46 self.weight_processing_conversions = {
47 **self._qkvo_weight_conversions(),
48 }
50 self.component_mapping = {
51 "embed": EmbeddingBridge(name="model.embed_tokens"),
52 "rotary_emb": RotaryEmbeddingBridge(name="model.rotary_emb", config=self.cfg),
53 "blocks": BlockBridge(
54 name="model.layers",
55 submodules={
56 # LayerNorm1P applies gamma as (weight + 1); delegate to the
57 # native module rather than reimplementing LN without the offset.
58 "ln1": NormalizationBridge(
59 name="input_layernorm",
60 config=self.cfg,
61 use_native_layernorm_autograd=True,
62 ),
63 "attn": PositionEmbeddingsAttentionBridge(
64 name="self_attn",
65 config=self.cfg,
66 submodules={
67 "q": LinearBridge(name="q_proj"),
68 "k": LinearBridge(name="k_proj"),
69 "v": LinearBridge(name="v_proj"),
70 "o": LinearBridge(name="o_proj"),
71 },
72 requires_attention_mask=True,
73 requires_position_embeddings=True,
74 ),
75 "ln2": NormalizationBridge(
76 name="post_attention_layernorm",
77 config=self.cfg,
78 use_native_layernorm_autograd=True,
79 ),
80 "mlp": self._ungated_mlp(),
81 },
82 ),
83 "ln_final": NormalizationBridge(
84 name="model.norm", config=self.cfg, use_native_layernorm_autograd=True
85 ),
86 "unembed": UnembeddingBridge(name="lm_head", config=self.cfg),
87 }