Coverage for transformer_lens/model_bridge/supported_architectures/hyenadna.py: 100%
25 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"""HyenaDNA architecture adapter.
3HazyResearch/Stanford's HyenaDNA (``HyenaDNAForCausalLM``, remote code):
4genomic language models built on the Hyena operator — attention-free
5long-convolution mixing (in_proj -> short conv + implicit modulated
6filters -> gated multiplicative recombination -> out_proj). Blocks are
7otherwise transformer-shaped (pre-LN, gelu fc1/fc2 MLP), stacked under
8``hyena.backbone`` with LayerNorms and single-character DNA vocab.
10The mixer delegates to HF wholesale (the implicit filter has no
11attention-shaped reconstruction); in_proj/out_proj are wrapped for
12hooks. The HF port ships no generate() (not a GenerationMixin), so
13generation phases are excluded.
14"""
16from typing import Any
18from transformer_lens.model_bridge.architecture_adapter import ArchitectureAdapter
19from transformer_lens.model_bridge.generalized_components import (
20 BlockBridge,
21 EmbeddingBridge,
22 LinearBridge,
23 NormalizationBridge,
24 UnembeddingBridge,
25)
26from transformer_lens.model_bridge.generalized_components.base import (
27 GeneralizedComponent,
28)
31class _HyenaBlockBridge(BlockBridge):
32 """Bare-tensor block whose backbone call mimics a standalone call, so
33 tuple-normalization is disabled; aliases drop attention (none here) and expose the mixer."""
35 hook_aliases = {
36 "hook_resid_pre": "hook_in",
37 "hook_resid_mid": "ln2.hook_in",
38 "hook_resid_post": "hook_out",
39 "hook_mixer_in": "mixer.hook_in",
40 "hook_mixer_out": "mixer.hook_out",
41 "hook_mlp_in": "mlp.in.hook_in",
42 "hook_mlp_out": "mlp.out.hook_out",
43 }
45 @staticmethod
46 def _is_standalone_hidden_state_call(args: tuple, kwargs: dict) -> bool:
47 return False
50class HyenaDNAArchitectureAdapter(ArchitectureAdapter):
51 """Architecture adapter for HyenaDNAForCausalLM models."""
53 applicable_phases: list[int] = [1, 2, 3, 4]
54 supports_generation: bool = True
55 # The Hyena FFT convolution has no incremental form (none upstream either);
56 # generation recomputes the full prefix per step.
57 supports_kv_cache: bool = False
58 # The remote forward takes no attention_mask/position_ids kwargs at all.
59 supports_batched_generation: bool = False
60 # Attention-free (Hyena convolutions): no q/k/v projections to fold into,
61 # matching the other delegated-mixer adapters (rwkv, gidd, llada2_moe).
62 supports_fold_ln: bool = False
64 def __init__(self, cfg: Any) -> None:
65 """Initialize the HyenaDNA architecture adapter."""
66 super().__init__(cfg)
68 self.cfg.normalization_type = "LN"
69 self.cfg.uses_rms_norm = False
70 self.cfg.positional_embedding_type = "none"
71 self.cfg.gated_mlp = False
72 self.cfg.attn_only = False
73 self.cfg.final_rms = False
75 # No attention weights to rearrange.
76 self.weight_processing_conversions = {}
78 self.component_mapping = {
79 "embed": EmbeddingBridge(name="hyena.backbone.embeddings.word_embeddings"),
80 "blocks": _HyenaBlockBridge(
81 name="hyena.backbone.layers",
82 config=self.cfg,
83 submodules={
84 "ln1": NormalizationBridge(
85 name="norm1", config=self.cfg, use_native_layernorm_autograd=True
86 ),
87 # Hyena long-conv mixer: delegated (implicit filters have no
88 # attention-shaped reconstruction); projections hookable.
89 "mixer": GeneralizedComponent(
90 name="mixer",
91 submodules={
92 "in_proj": LinearBridge(name="in_proj"),
93 "out_proj": LinearBridge(name="out_proj"),
94 },
95 ),
96 "ln2": NormalizationBridge(
97 name="norm2", config=self.cfg, use_native_layernorm_autograd=True
98 ),
99 "mlp": self._ungated_mlp(up="fc1", down="fc2"),
100 },
101 ),
102 "ln_final": NormalizationBridge(
103 name="hyena.backbone.ln_f", config=self.cfg, use_native_layernorm_autograd=True
104 ),
105 "unembed": UnembeddingBridge(name="lm_head"),
106 }