Taykhoom commited on
Commit
e2b4020
·
0 Parent(s):

Add model_max_length=8192 and max_seqlen=8192 (training context); note StripedHyena extension in README

Browse files
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - dna
4
+ library_name: transformers
5
+ tags:
6
+ - DNA
7
+ - language-model
8
+ - StripedHyena2
9
+ - Evo2
10
+ license: apache-2.0
11
+ ---
12
+
13
+ # Evo2-7B-8K
14
+
15
+ A clean, minimal HuggingFace port of [Evo 2 7B base](https://huggingface.co/arcinstitute/evo2_7b_base), the 8K-context StripedHyena2 DNA foundation model. Provides native support for layer-by-layer hidden state extraction, attention-weight extraction, and a runtime-switchable attention backend.
16
+
17
+ > **No Transformer Engine required.** This variant runs in pure bf16 on any
18
+ > CUDA-capable GPU (no FP8 / TE dependency).
19
+
20
+
21
+
22
+ ## Why this port?
23
+
24
+ [arcinstitute/evo2_7b_base](https://huggingface.co/arcinstitute/evo2_7b_base) ships a `.pt` checkpoint that requires the [evo2](https://github.com/ArcInstitute/evo2) and [vortex](https://github.com/Zymrael/vortex) Python packages just to instantiate the model. Even with both installed, common pain points remain:
25
+
26
+ 1. **Not a HuggingFace model.** No `from_pretrained`, no `AutoModel`, no `AutoModelForCausalLM` - the original ships a thin Python wrapper around a custom `nn.Module`.
27
+ 2. **No way to extract attention weights.** The reference uses flash-attn unconditionally and discards the `(B, H, T, T)` attention matrix; there is no official path to read it back.
28
+ 3. **`evo2` + `vortex` packages mandatory** even for inference.
29
+
30
+ This repo fixes all three. The math is **bit-exact** with the vortex reference (`max_abs_diff = 0.000e+00` at every layer; see [Parity Verification](#parity-verification)). Loads with `from_pretrained` and `trust_remote_code=True` - no `evo2` / `vortex` install needed.
31
+
32
+ ## Architecture
33
+
34
+ | Parameter | Value |
35
+ |---|---|
36
+ | Total parameters | ~6.5B |
37
+ | Architecture | StripedHyena 2 (interleaved Hyena cascade + MHA blocks) |
38
+ | Layers | 32 |
39
+ | Attention heads | 32 |
40
+ | Embedding dimension | 4096 |
41
+ | Inner MLP size | 11 008 |
42
+ | Vocabulary size | 512 (UTF-8 byte-level) |
43
+ | Attention block indices | 3, 10, 17, 24, 31 (5 blocks total) |
44
+ | Hyena block indices | all others (27 blocks: hcs / hcm / hcl pattern) |
45
+ | Positional encoding | RoPE (base = 10 000) |
46
+ | Max sequence length | 8 192 (training context; StripedHyena supports extension beyond this with adjusted FFT buffers) |
47
+ | Training dtype | bfloat16 (Hyena modal-form `log_poles` / `residues` and rotary `inv_freq` kept in fp32) |
48
+ | FP8 input projections | no |
49
+ | Weight format | `model.safetensors` (6.5B params, 3 files) |
50
+
51
+ ## Pretraining
52
+
53
+ - **Objective:** causal byte-level next-token prediction.
54
+ - **Data:** [OpenGenome2](https://huggingface.co/datasets/arcinstitute/opengenome2), 8.8 trillion tokens spanning all domains of life.
55
+ - **Source checkpoint:** `arcinstitute/evo2_7b_base` ([evo2_7b_base.pt](https://huggingface.co/arcinstitute/evo2_7b_base/blob/main/evo2_7b_base.pt)).
56
+
57
+ ## Parity Verification
58
+
59
+ Hidden-state representations verified **bit-exact** (`max_abs_diff = 0.000e+00`) to the vortex reference at every block output, using `attn_implementation="sdpa"` in bf16 (the same backend vortex's `SelfAttention` calls when `use_flash_attn=False`). Logits from `Evo2ForCausalLM` were also verified bit-exact (top-1 agreement: 128/128 positions on a 128-byte ACGT input). Verified on H100 with PyTorch 2.7 / CUDA 12.
60
+
61
+ Two non-obvious correctness fixes were required versus a naive port (see Implementation Notes for details):
62
+
63
+ 1. **`inv_freq` recomputation.** `from_pretrained(dtype=bf16)` casts buffers to bf16, which loses ~7 bits of mantissa in the rotary `inv_freq = 1 / base^(2i/dim)`. Our `to_bfloat16_except_poles_residues()` recomputes `inv_freq` in fp32 from `self.base` to match vortex's `to_bfloat16_except_pr_lc(to_float32=True)`.
64
+ 2. **SDPA backend used for parity.** Vortex's reference `SelfAttention` (`use_flash_attn=False`) calls `F.scaled_dot_product_attention`, not a textbook softmax loop. Parity is measured with `attn_implementation="sdpa"` on our side. Using `"eager"` (textbook einsum + softmax) is mathematically equivalent but not bit-exact in bf16; using `"flash_attention_2"` (the recommended runtime backend) is also not bit-exact but agrees within bf16 noise.
65
+
66
+ ## Related Models
67
+
68
+ See the full Evo 2 collection on the [Arc Institute HF org](https://huggingface.co/arcinstitute) for the original weights, or the [`Taykhoom/Evo2-*` collection](https://huggingface.co/collections/Taykhoom/evo2-6a24b06c05955a295025a006) for our minimal HF ports.
69
+
70
+ | Model | Size | Context | Notes |
71
+ |---|---|---|---|
72
+ | [Taykhoom/Evo2-1B-8K](https://huggingface.co/Taykhoom/Evo2-1B-8K) | 1B | 8 192 | |
73
+ | **[Taykhoom/Evo2-7B-8K](https://huggingface.co/Taykhoom/Evo2-7B-8K)** | 7B | 8 192 | <- this model |
74
+ | [Taykhoom/Evo2-7B-262K](https://huggingface.co/Taykhoom/Evo2-7B-262K) | 7B | 262 144 | |
75
+ | [Taykhoom/Evo2-7B-1M](https://huggingface.co/Taykhoom/Evo2-7B-1M) | 7B | 1 048 576 | |
76
+ | [Taykhoom/Evo2-20B-1M](https://huggingface.co/Taykhoom/Evo2-20B-1M) | 20B | 1 048 576 | |
77
+ | [Taykhoom/Evo2-40B-8K](https://huggingface.co/Taykhoom/Evo2-40B-8K) | 40B | 8 192 | |
78
+ | [Taykhoom/Evo2-40B-1M](https://huggingface.co/Taykhoom/Evo2-40B-1M) | 40B | 1 048 576 | |
79
+
80
+ ## Usage
81
+
82
+ > **Note on dtype.** Evo 2 was trained in bfloat16, with the Hyena `log_poles` / `residues` (modal-form filter parameters) and the rotary `inv_freq` kept in fp32 for numerical stability. Passing `dtype=...` to `from_pretrained` only affects the initial load precision - `Evo2Model.__init__` and `Evo2ForCausalLM.__init__` always call `to_bfloat16_except_poles_residues()`, so the model runs in bf16 with these fp32 invariants regardless. This is intentional: bf16 is the trained precision, and the fp32 islands are required for stability.
83
+
84
+ > **Note on attention backend.** By HuggingFace convention this model defaults to `attn_implementation="sdpa"` (`F.scaled_dot_product_attention`) since SDPA needs only `torch` and runs on any GPU. The original Arc Institute Evo 2 inference path uses **flash_attention_2**, which is faster on long sequences but requires a separate `flash-attn` install. All usage examples below opt in to `flash_attention_2` explicitly because most real users will want it. Drop the kwarg (or pass `"sdpa"` / `"eager"`) if you don't have `flash-attn` installed.
85
+
86
+ ### Embedding generation (no LM head)
87
+
88
+ ```python
89
+ import torch
90
+ from transformers import AutoTokenizer, AutoModel
91
+
92
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/Evo2-7B-8K", trust_remote_code=True)
93
+ model = AutoModel.from_pretrained(
94
+ "Taykhoom/Evo2-7B-8K",
95
+ trust_remote_code=True,
96
+ attn_implementation="flash_attention_2", # or "sdpa" (default) or "eager"
97
+ ).cuda().eval()
98
+
99
+ seqs = ["ACGTACGTACGT", "GGGTTTAAACCC"]
100
+ inputs = tokenizer(seqs, return_tensors="pt", padding=True).to(model.device)
101
+
102
+ with torch.no_grad():
103
+ out = model(**inputs, output_hidden_states=True)
104
+
105
+ last_hidden = out.last_hidden_state # (B, T, 4096)
106
+ all_layers = out.hidden_states # tuple of (B, T, 4096), len = 34
107
+ middle_layer = all_layers[16] # input to block 16 (= output of block 15)
108
+ ```
109
+
110
+ ### Recommended embedding: pre-norm of the middle block
111
+
112
+ The Evo 2 paper reports that intermediate representations work better than the final layer for downstream tasks - specifically the **pre-norm of a middle block**. For this variant the middle block is `blocks[16]`, so the recommended embedding is `blocks[16].pre_norm(hidden_states[16])`:
113
+
114
+ ```python
115
+ import torch
116
+ from transformers import AutoTokenizer, AutoModel
117
+
118
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/Evo2-7B-8K", trust_remote_code=True)
119
+ model = AutoModel.from_pretrained(
120
+ "Taykhoom/Evo2-7B-8K",
121
+ trust_remote_code=True,
122
+ attn_implementation="flash_attention_2",
123
+ ).cuda().eval()
124
+
125
+ inputs = tokenizer(["ACGTACGTACGT"], return_tensors="pt").to(model.device)
126
+ with torch.no_grad():
127
+ out = model(**inputs, output_hidden_states=True)
128
+ pre_norm_middle = model.backbone.blocks[16].pre_norm(
129
+ out.hidden_states[16]
130
+ ) # (B, T, 4096)
131
+ ```
132
+
133
+ HF has no built-in API for sub-block intermediates like pre-norm outputs (only block outputs via `output_hidden_states`). The pattern above applies the block's `pre_norm` submodule directly to the corresponding `hidden_states` entry; this gives a bit-identical result to registering a forward hook on `backbone.blocks[i].pre_norm` and is simpler than using PyTorch hooks. Note that it does require running the full forward pass and then re-applying `pre_norm`, so a forward hook is more efficient if you only need this single intermediate.
134
+
135
+ ### LM logits
136
+
137
+ ```python
138
+ import torch
139
+ from transformers import AutoTokenizer, AutoModelForCausalLM
140
+
141
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/Evo2-7B-8K", trust_remote_code=True)
142
+ model = AutoModelForCausalLM.from_pretrained(
143
+ "Taykhoom/Evo2-7B-8K", trust_remote_code=True,
144
+ attn_implementation="flash_attention_2",
145
+ ).cuda().eval()
146
+
147
+ inputs = tokenizer(["ACGT"], return_tensors="pt").to(model.device)
148
+ with torch.no_grad():
149
+ logits = model(**inputs).logits # (1, T, 512)
150
+ ```
151
+
152
+ ### Generation
153
+
154
+ ```python
155
+ import torch
156
+ from transformers import AutoTokenizer, AutoModelForCausalLM
157
+
158
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/Evo2-7B-8K", trust_remote_code=True)
159
+ model = AutoModelForCausalLM.from_pretrained(
160
+ "Taykhoom/Evo2-7B-8K", trust_remote_code=True,
161
+ attn_implementation="flash_attention_2",
162
+ ).cuda().eval()
163
+
164
+ inputs = tokenizer(["ACGT"], return_tensors="pt").to(model.device)
165
+ out = model.generate(**inputs, max_new_tokens=128, do_sample=True, top_k=4, temperature=1.0)
166
+ print(tokenizer.decode(out[0]))
167
+ ```
168
+
169
+ `generation_config.json` ships with `eos_token_id = 0` (the EOD byte) and `pad_token_id = 1` so `model.generate()` stops naturally at the trained end-of-document token.
170
+
171
+ ### Attention weights
172
+
173
+ ```python
174
+ import torch
175
+ from transformers import AutoTokenizer, AutoModel
176
+
177
+ tokenizer = AutoTokenizer.from_pretrained("Taykhoom/Evo2-7B-8K", trust_remote_code=True)
178
+ model = AutoModel.from_pretrained(
179
+ "Taykhoom/Evo2-7B-8K",
180
+ trust_remote_code=True,
181
+ attn_implementation="eager", # required for output_attentions to populate
182
+ ).cuda().eval()
183
+
184
+ inputs = tokenizer(["ACGTACGT"], return_tensors="pt").to(model.device)
185
+ with torch.no_grad():
186
+ out = model(**inputs, output_attentions=True)
187
+
188
+ # out.attentions is a tuple of length 32. Entries at indices not in
189
+ # [3, 10, 17, 24, 31] are None (Hyena blocks have no attention matrix).
190
+ # The 5 attention block(s) at those indices return a (B, num_heads, T, T) tensor.
191
+ attn_block_3 = out.attentions[3]
192
+ ```
193
+
194
+ ### Multi-GPU loading (optional)
195
+
196
+ For sharding across multiple GPUs (required for 40B, optional for smaller
197
+ variants), install [accelerate](https://github.com/huggingface/accelerate)
198
+ and pass `device_map="auto"`:
199
+
200
+ ```python
201
+ from transformers import AutoModelForCausalLM
202
+ # pip install accelerate
203
+ model = AutoModelForCausalLM.from_pretrained(
204
+ "Taykhoom/Evo2-7B-8K", trust_remote_code=True,
205
+ device_map="auto", # accelerate will shard across all visible GPUs
206
+ )
207
+ ```
208
+
209
+ ### Fine-tuning
210
+
211
+ This HuggingFace port has **not** been tested for fine-tuning - it's verified only for inference parity. For fine-tuning, follow the original Arc Institute guidance and use either [Savanna](https://github.com/Zymrael/savanna) (the framework Evo 2 was pretrained in) or [Nvidia BioNeMo](https://github.com/NVIDIA/bionemo-framework), which provides an official [Evo 2 fine-tuning recipe](https://github.com/NVIDIA-BioNeMo/bionemo-framework/tree/main/bionemo-recipes/recipes/evo2_megatron#fine-tuning-from-an-existing-checkpoint).
212
+
213
+ ## Implementation Notes
214
+
215
+ - **`inv_freq` kept in fp32 (critical for parity).** HF's `from_pretrained(dtype=bf16)` casts all buffers, including the rotary `inv_freq`, to bf16. The geometric series `inv_freq[i] = 1 / base^(2i/dim)` loses ~7 bits of mantissa in bf16, which shifts the cos/sin tables by ~5e-2 per cell at higher positions and contributes ~3e-2 of Q/K noise per attention layer. Our `to_bfloat16_except_poles_residues()` (called in each `__init__`) recomputes `inv_freq` in fp32 from the stored `self.base` and invalidates the cos/sin cache, mirroring vortex's `to_bfloat16_except_pr_lc(to_float32=True)`.
216
+ - **`log_poles` / `residues` kept in fp32 (critical for stability).** The Hyena cascade long (hcl) blocks parameterize an IIR filter via `log_poles` and `residues`; bf16 quantisation makes the recurrence numerically unstable. Both are stored as fp32 in the safetensors and restored to fp32 by `force_dtype()` after load.
217
+ - **`attn_implementation` switching (`attention.py`).** Three backends, selected via the standard HF `attn_implementation` kwarg to `from_pretrained` (default chosen by HF auto-detection - typically `"sdpa"`):
218
+ - `"sdpa"`: calls `F.scaled_dot_product_attention`. Bit-exact with vortex's reference path (when vortex uses `use_flash_attn=False`).
219
+ - `"flash_attention_2"`: calls `flash_attn.flash_attn_qkvpacked_func`. Matches the original Arc Institute inference path; faster on long sequences; requires `flash-attn` installed.
220
+ - `"eager"`: textbook einsum + softmax(QK^T) + einsum. Slowest, used internally when `output_attentions=True` so the attention matrix is materialized.
221
+ - **Block dispatch (`hyena.py`).** StripedHyena 2 has 4 block types, dispatched by `layer_idx` membership in four config lists: `attn_layer_idxs` (MHA + RoPE), `hcl_layer_idxs` (modal-form IIR via FFT), `hcm_layer_idxs` (medium FIR cascade, inner length 128), `hcs_layer_idxs` (short FIR cascade, inner length 7). The disjoint union must equal `range(num_layers)`.
222
+ - **`TELinear` with pure-PyTorch fallback (`layers.py`).** Hyena cascade blocks use a TransformerEngine-backed input projection (3x hidden_size output) that supports FP8 quantisation. When TE is not installed, a `TELinear` fallback class with the same state_dict layout (`weight`, `bias`) is used - checkpoints are cross-loadable.
223
+ - **Custom cache (`cache.py`).** `Evo2Cache` wraps four block-type-specific dataclasses: `InferenceParams` for MHA KV cache, `HyenaCascadeIIRInferenceParams` for hcl, and two `HyenaCascadeFIRInferenceParams` for hcm / hcs. Passed through `model.generate()` as `past_key_values` (we set `_supports_cache_class = False` so HF treats it as an opaque dict rather than wrapping it in a `DynamicCache`).
224
+ - **Tokenizer (`tokenization_evo2.py`).** Byte-level UTF-8, vocab_size = 512. Pad token = byte `\x01`. EOS = byte `\x00` (set as `eos_token_id` in `generation_config.json`). Tokenizer does not add EOS at encoding time - matches the original Evo 2 inference pipeline.
225
+ - **Dependencies.** `torch`, `transformers`, `numpy`, `safetensors`, `huggingface_hub`. `accelerate` is optional but recommended if you want to load with `device_map="auto"` for multi-GPU sharding. `flash_attn` is optional (only needed if you pass `attn_implementation="flash_attention_2"`).
226
+
227
+ ## Citation
228
+
229
+ ```bibtex
230
+ @article{brixi2026_evo2,
231
+ title = {Genome modelling and design across all domains of life with {Evo} 2},
232
+ author = {Brixi, Garyk and Durrant, Matthew G. and Ku, Jerome and Naghipourfar, Mohsen and Poli, Michael and Sun, Gwanggyu and Brockman, Greg and Chang, Daniel and Fanton, Alison and Gonzalez, Gabriel A. and King, Samuel H. and Li, David B. and Merchant, Aditi T. and Nguyen, Eric and Ricci-Tam, Chiara and Romero, David W. and Schmok, Jonathan C. and Taghibakhshi, Ali and Vorontsov, Anton and Yang, Brandon and Deng, Myra and Gorton, Liv and Nguyen, Nam and Wang, Nicholas K. and Pearce, Michael T. and Simon, Elana and Adams, Etowah and Amador, Zachary J. and Ashley, Euan A. and Baccus, Stephen A. and Dai, Haoyu and Dillmann, Steven and Ermon, Stefano and Guo, Daniel and Herschl, Michael H. and Ilango, Rajesh and Janik, Ken and Lu, Amy X. and Mehta, Reshma and Mofrad, Mohammad R. K. and Ng, Madelena Y. and Pannu, Jaspreet and {R{\'e}}, Christopher and St. John, John and Sullivan, Jeremy and Tey, Joseph and Viggiano, Ben and Zhu, Kevin and Zynda, Greg and Balsam, Daniel and Collison, Patrick and Costa, Anthony B. and Hernandez-Boussard, Tina and Ho, Eric and Liu, Ming-Yu and McGrath, Thomas and Powell, Kimberly and Pinglay, Sudarshan and Burke, Dave P. and Goodarzi, Hani and Hsu, Patrick D. and Hie, Brian L.},
233
+ journal = {Nature},
234
+ year = {2026},
235
+ doi = {10.1038/s41586-026-10176-5}
236
+ }
237
+ ```
238
+
239
+ ## Credits
240
+
241
+ Original Evo 2 model and code by Brixi et al. ([arcinstitute/evo2](https://github.com/arcinstitute/evo2), [Zymrael/vortex](https://github.com/Zymrael/vortex)). Source checkpoint: [arcinstitute/evo2_7b_base](https://huggingface.co/arcinstitute/evo2_7b_base).
242
+
243
+ The HuggingFace conversion code in this repo was authored primarily by [Claude](https://claude.ai/code) and reviewed manually by Taykhoom Dalal.
244
+
245
+ ## License
246
+
247
+ Apache 2.0, following the original Evo 2 release.
attention.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Multi-head attention for Evo2.
2
+
3
+ Causal self-attention with RoPE. Three backends dispatchable via the standard
4
+ HF attn_implementation kwarg:
5
+
6
+ * "eager" -- pure F.softmax(QK^T)V; returns weights on demand
7
+ * "sdpa" -- F.scaled_dot_product_attention; no weights
8
+ * "flash_attention_2" -- flash_attn.flash_attn_qkvpacked_func; no weights
9
+
10
+ Constructor signature is a strict subset of vortex's MHA so the
11
+ AttentionBlock instantiation site only changes the attn_implementation kwarg.
12
+ KV cache (used by Evo2 generation) goes through an SDPA path that handles
13
+ arbitrary sequence lengths.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import math
19
+
20
+ import torch
21
+ import torch.nn as nn
22
+ import torch.nn.functional as F
23
+
24
+ from .rotary import RotaryEmbedding
25
+
26
+
27
+ def _flash_attn_required():
28
+ try:
29
+ from flash_attn import flash_attn_qkvpacked_func # noqa: F401
30
+ except ImportError as exc:
31
+ raise ImportError(
32
+ "attn_implementation='flash_attention_2' requires the flash-attn "
33
+ "package. Install with `pip install flash-attn --no-build-isolation`."
34
+ ) from exc
35
+
36
+
37
+ def _update_kv_cache(kv: torch.Tensor, inference_params, layer_idx: int) -> torch.Tensor:
38
+ num_heads, head_dim = kv.shape[-2:]
39
+ if layer_idx not in inference_params.key_value_memory_dict:
40
+ kv_cache = torch.empty(
41
+ inference_params.max_batch_size,
42
+ inference_params.max_seqlen,
43
+ 2,
44
+ num_heads,
45
+ head_dim,
46
+ dtype=kv.dtype,
47
+ device=kv.device,
48
+ )
49
+ inference_params.key_value_memory_dict[layer_idx] = kv_cache
50
+ else:
51
+ kv_cache = inference_params.key_value_memory_dict[layer_idx]
52
+ batch_start = inference_params.batch_size_offset
53
+ batch_end = batch_start + kv.shape[0]
54
+ sequence_start = inference_params.seqlen_offset
55
+ sequence_end = sequence_start + kv.shape[1]
56
+ kv_cache[batch_start:batch_end, sequence_start:sequence_end, ...] = kv
57
+ return kv_cache[batch_start:batch_end, :sequence_end, ...]
58
+
59
+
60
+ class MHA(nn.Module):
61
+ """Multi-head self-attention with backend-dispatch."""
62
+
63
+ def __init__(
64
+ self,
65
+ embed_dim: int,
66
+ num_heads: int,
67
+ num_heads_kv: int | None = None,
68
+ cross_attn: bool = False,
69
+ qkv_proj_bias: bool = True,
70
+ out_proj_bias: bool = True,
71
+ dropout: float = 0.0,
72
+ softmax_scale: float | None = None,
73
+ causal: bool = False,
74
+ layer_idx: int | None = None,
75
+ rotary_emb_dim: int = 0,
76
+ rotary_emb_base: float = 10000.0,
77
+ rotary_emb_scale_base: float | None = None,
78
+ rotary_emb_interleaved: bool = False,
79
+ use_flash_attn: bool = False, # legacy kwarg kept for ctor compat
80
+ attn_implementation: str = "eager",
81
+ device=None,
82
+ dtype=None,
83
+ ) -> None:
84
+ super().__init__()
85
+ if cross_attn:
86
+ raise NotImplementedError("Cross-attention is not supported.")
87
+
88
+ factory_kwargs = {"device": device, "dtype": dtype}
89
+ self.embed_dim = embed_dim
90
+ self.num_heads = num_heads
91
+ self.num_heads_kv = num_heads_kv if num_heads_kv is not None else num_heads
92
+ if self.embed_dim % num_heads != 0:
93
+ raise ValueError("embed_dim must be divisible by num_heads")
94
+ if self.num_heads % self.num_heads_kv != 0:
95
+ raise ValueError("num_heads must be divisible by num_heads_kv")
96
+ self.head_dim = self.embed_dim // num_heads
97
+ self.causal = causal
98
+ self.softmax_scale = softmax_scale
99
+ self.layer_idx = layer_idx
100
+ self.rotary_emb_dim = rotary_emb_dim
101
+ self.attn_implementation = attn_implementation
102
+ self.dropout_p = dropout
103
+ self.cross_attn = cross_attn
104
+
105
+ if self.rotary_emb_dim > 0:
106
+ self.rotary_emb = RotaryEmbedding(
107
+ self.rotary_emb_dim,
108
+ base=rotary_emb_base,
109
+ interleaved=rotary_emb_interleaved,
110
+ scale_base=rotary_emb_scale_base,
111
+ device=device,
112
+ )
113
+
114
+ qkv_dim = self.head_dim * (self.num_heads + 2 * self.num_heads_kv)
115
+ self.Wqkv = nn.Linear(embed_dim, qkv_dim, bias=qkv_proj_bias, **factory_kwargs)
116
+ self.out_proj = nn.Linear(embed_dim, embed_dim, bias=out_proj_bias, **factory_kwargs)
117
+
118
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None):
119
+ dtype = self.out_proj.weight.dtype if dtype is None else dtype
120
+ device = self.out_proj.weight.device
121
+ return torch.empty(
122
+ batch_size, max_seqlen, 2, self.num_heads_kv, self.head_dim,
123
+ dtype=dtype, device=device,
124
+ )
125
+
126
+ def _project_qkv(self, x: torch.Tensor) -> torch.Tensor:
127
+ qkv = self.Wqkv(x)
128
+ if self.num_heads_kv == self.num_heads:
129
+ return qkv.view(*qkv.shape[:-1], 3, self.num_heads, self.head_dim)
130
+ q = qkv[..., : self.num_heads * self.head_dim]
131
+ kv = qkv[..., self.num_heads * self.head_dim:]
132
+ q = q.view(*q.shape[:-1], self.num_heads, self.head_dim)
133
+ kv = kv.view(*kv.shape[:-1], 2, self.num_heads_kv, self.head_dim)
134
+ return q, kv
135
+
136
+ def _forward_eager(
137
+ self,
138
+ qkv: torch.Tensor,
139
+ output_attentions: bool,
140
+ ) -> tuple[torch.Tensor, torch.Tensor | None]:
141
+ """Bit-identical port of flash_attn.modules.mha.SelfAttention.forward.
142
+
143
+ Key choices that must match vortex (which delegates to this class
144
+ when use_flash_attn=False):
145
+
146
+ * einsum (not matmul) for QK^T and PV: bf16 matmul vs bf16 einsum
147
+ use different accumulator orders, ~3e-2 per attention layer.
148
+ * -10000.0 causal mask (not -inf): vortex uses a finite mask value.
149
+ * softmax(scores, dim=-1, dtype=v.dtype) (not F.softmax(.float())):
150
+ PyTorch promotes to fp32 internally then casts to v.dtype.
151
+ Explicit .float() then .to(v.dtype) cast rounds differently.
152
+ * scale applied to K (k * scale), not Q. Same math, different
153
+ bf16 multiply target.
154
+ """
155
+ q, k, v = qkv.unbind(dim=2) # each (B, T, H, D)
156
+ softmax_scale = (
157
+ self.softmax_scale if self.softmax_scale is not None
158
+ else 1.0 / math.sqrt(self.head_dim)
159
+ )
160
+ scores = torch.einsum("bthd,bshd->bhts", q, k * softmax_scale)
161
+ T = q.shape[1]
162
+ if self.causal:
163
+ causal_mask = torch.triu(
164
+ torch.full((T, T), -10000.0, device=scores.device), 1
165
+ )
166
+ scores = scores + causal_mask.to(dtype=scores.dtype)
167
+ attention = torch.softmax(scores, dim=-1, dtype=v.dtype)
168
+ if self.training and self.dropout_p > 0:
169
+ attention = F.dropout(attention, p=self.dropout_p)
170
+ out = torch.einsum("bhts,bshd->bthd", attention, v)
171
+ return out, (attention if output_attentions else None)
172
+
173
+ def _forward_sdpa(self, qkv: torch.Tensor) -> torch.Tensor:
174
+ q, k, v = qkv.unbind(dim=2)
175
+ q = q.permute(0, 2, 1, 3)
176
+ k = k.permute(0, 2, 1, 3)
177
+ v = v.permute(0, 2, 1, 3)
178
+ scale = self.softmax_scale if self.softmax_scale is not None else None
179
+ out = F.scaled_dot_product_attention(
180
+ q, k, v,
181
+ attn_mask=None,
182
+ dropout_p=self.dropout_p if self.training else 0.0,
183
+ is_causal=self.causal,
184
+ scale=scale,
185
+ )
186
+ return out.permute(0, 2, 1, 3)
187
+
188
+ def _forward_flash(self, qkv: torch.Tensor) -> torch.Tensor:
189
+ _flash_attn_required()
190
+ from flash_attn import flash_attn_qkvpacked_func
191
+ out = flash_attn_qkvpacked_func(
192
+ qkv,
193
+ dropout_p=self.dropout_p if self.training else 0.0,
194
+ softmax_scale=self.softmax_scale,
195
+ causal=self.causal,
196
+ )
197
+ return out
198
+
199
+ def _forward_with_cache(
200
+ self,
201
+ qkv: torch.Tensor,
202
+ inference_params,
203
+ ) -> torch.Tensor:
204
+ if self.rotary_emb_dim > 0:
205
+ qkv = self.rotary_emb(
206
+ qkv,
207
+ seqlen_offset=inference_params.seqlen_offset,
208
+ max_seqlen=inference_params.max_seqlen,
209
+ )
210
+ q, k, v = qkv.unbind(dim=2)
211
+ kv = torch.stack((k, v), dim=2)
212
+ kv = _update_kv_cache(kv, inference_params, self.layer_idx)
213
+ k_full, v_full = kv.unbind(dim=2)
214
+
215
+ q = q.permute(0, 2, 1, 3)
216
+ k_full = k_full.permute(0, 2, 1, 3)
217
+ v_full = v_full.permute(0, 2, 1, 3)
218
+ scale = self.softmax_scale if self.softmax_scale is not None else None
219
+ is_causal = self.causal and q.shape[-2] == k_full.shape[-2]
220
+ out = F.scaled_dot_product_attention(
221
+ q, k_full, v_full, is_causal=is_causal, scale=scale,
222
+ )
223
+ return out.permute(0, 2, 1, 3)
224
+
225
+ def forward(
226
+ self,
227
+ x: torch.Tensor,
228
+ inference_params=None,
229
+ output_attentions: bool = False,
230
+ **_unused,
231
+ ) -> tuple[torch.Tensor, torch.Tensor | None]:
232
+ if self.num_heads_kv != self.num_heads:
233
+ raise NotImplementedError("GQA is not exercised by Evo2.")
234
+
235
+ qkv = self._project_qkv(x)
236
+
237
+ if inference_params is not None:
238
+ out_btd = self._forward_with_cache(qkv, inference_params)
239
+ attn_weights = None
240
+ else:
241
+ if self.rotary_emb_dim > 0:
242
+ qkv = self.rotary_emb(qkv, seqlen_offset=0, max_seqlen=qkv.shape[1])
243
+
244
+ backend = self.attn_implementation
245
+ if output_attentions and backend != "eager":
246
+ backend = "eager"
247
+
248
+ if backend == "eager":
249
+ out_btd, attn_weights = self._forward_eager(qkv, output_attentions=output_attentions)
250
+ elif backend == "sdpa":
251
+ out_btd = self._forward_sdpa(qkv)
252
+ attn_weights = None
253
+ elif backend == "flash_attention_2":
254
+ out_btd = self._forward_flash(qkv)
255
+ attn_weights = None
256
+ else:
257
+ raise ValueError(f"Unknown attn_implementation: {backend!r}")
258
+
259
+ B, T, H, D = out_btd.shape
260
+ out_flat = out_btd.reshape(B, T, H * D)
261
+ return self.out_proj(out_flat), attn_weights
cache.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Inference-time caches for Evo2 blocks.
2
+
3
+ StripedHyena2 has four block types with different caching needs:
4
+
5
+ * `attn` blocks -> InferenceParams (standard KV cache)
6
+ * `hcl` blocks -> HyenaCascadeIIRInferenceParams (FIR window + IIR state)
7
+ * `hcm` blocks -> HyenaCascadeFIRInferenceParams (outer FIR + inner FIR)
8
+ * `hcs` blocks -> HyenaCascadeFIRInferenceParams (outer FIR + inner FIR)
9
+
10
+ Layer outputs of these caches are wrapped together inside an HF Cache subclass
11
+ (`Evo2Cache`) so model.generate() can drive autoregressive decoding without
12
+ the user having to instantiate four separate caches by hand.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from dataclasses import dataclass, field
18
+ from typing import Optional
19
+
20
+ import torch
21
+ from torch import Tensor
22
+
23
+
24
+ @dataclass
25
+ class InferenceParams:
26
+ """Standard KV cache for attention blocks."""
27
+
28
+ max_seqlen: int
29
+ max_batch_size: int
30
+ seqlen_offset: int = 0
31
+ batch_size_offset: int = 0
32
+ key_value_memory_dict: dict = field(default_factory=dict)
33
+ lengths_per_sample: Optional[Tensor] = None
34
+
35
+ def reset(self, max_seqlen, max_batch_size):
36
+ self.max_seqlen = max_seqlen
37
+ self.max_batch_size = max_batch_size
38
+ self.seqlen_offset = 0
39
+ if self.lengths_per_sample is not None:
40
+ self.lengths_per_sample.zero_()
41
+
42
+
43
+ @dataclass
44
+ class HyenaCascadeIIRInferenceParams:
45
+ """Cache for `hcl` blocks: short FIR window + IIR modal state."""
46
+
47
+ fir_filter_length: int = 3
48
+ state_dim: int = 16
49
+ seqlen_offset: int = 0
50
+ fir_state_dict: dict = field(default_factory=dict)
51
+ state_dict: dict = field(default_factory=dict)
52
+
53
+ def reset(self):
54
+ self.seqlen_offset = 0
55
+
56
+
57
+ @dataclass
58
+ class HyenaCascadeFIRInferenceParams:
59
+ """Cache for `hcm` and `hcs` blocks: outer short FIR + inner FIR cascade."""
60
+
61
+ fir_filter_length: int = 3
62
+ fir_inner_filter_length: int = 4
63
+ seqlen_offset: int = 0
64
+ fir_inner_state_dict: dict = field(default_factory=dict)
65
+ fir_state_dict: dict = field(default_factory=dict)
66
+ state_dict: dict = field(default_factory=dict)
67
+
68
+ def reset(self):
69
+ self.seqlen_offset = 0
70
+
71
+
72
+ class Evo2Cache:
73
+ """Container for per-block-type inference params.
74
+
75
+ Not a transformers.Cache subclass (the new Cache API requires per-layer
76
+ dataclasses, which doesn't fit StripedHyena 2's 4 block-type-specific
77
+ state structures). Instead we set Evo2PreTrainedModel._supports_cache_class
78
+ = False so HF's generate() treats this as an opaque past_key_values dict.
79
+ """
80
+
81
+ is_compileable = False
82
+
83
+ def __init__(
84
+ self,
85
+ max_seqlen: int,
86
+ max_batch_size: int,
87
+ short_filter_length: int,
88
+ hcm_filter_length: int,
89
+ hcs_filter_length: int,
90
+ state_size: int,
91
+ ):
92
+ self.mha = InferenceParams(
93
+ max_seqlen=max_seqlen,
94
+ max_batch_size=max_batch_size,
95
+ )
96
+ self.hcl = HyenaCascadeIIRInferenceParams(
97
+ fir_filter_length=short_filter_length,
98
+ state_dim=state_size,
99
+ )
100
+ self.hcm = HyenaCascadeFIRInferenceParams(
101
+ fir_filter_length=short_filter_length,
102
+ fir_inner_filter_length=hcm_filter_length,
103
+ )
104
+ self.hcs = HyenaCascadeFIRInferenceParams(
105
+ fir_filter_length=short_filter_length,
106
+ fir_inner_filter_length=hcs_filter_length,
107
+ )
108
+
109
+ @property
110
+ def seqlen_offset(self) -> int:
111
+ return self.mha.seqlen_offset
112
+
113
+ def get_seq_length(self, layer_idx: int = 0) -> int:
114
+ return self.mha.seqlen_offset
115
+
116
+ def get_max_cache_shape(self) -> int:
117
+ return self.mha.max_seqlen
118
+
119
+ def get_max_length(self) -> int:
120
+ return self.mha.max_seqlen
121
+
122
+ def advance(self, n: int = 1) -> None:
123
+ self.mha.seqlen_offset += n
124
+ self.hcl.seqlen_offset += n
125
+ self.hcm.seqlen_offset += n
126
+ self.hcs.seqlen_offset += n
127
+
128
+ def set_offset(self, offset: int) -> None:
129
+ self.mha.seqlen_offset = offset
130
+ self.hcl.seqlen_offset = offset
131
+ self.hcm.seqlen_offset = offset
132
+ self.hcs.seqlen_offset = offset
133
+
134
+ def reset(self) -> None:
135
+ self.mha.reset(self.mha.max_seqlen, self.mha.max_batch_size)
136
+ self.hcl.reset()
137
+ self.hcm.reset()
138
+ self.hcs.reset()
139
+
140
+ def by_block_name(self, name: str):
141
+ return getattr(self, name)
config.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Evo2ForCausalLM"
4
+ ],
5
+ "attn_block_dtype": "bfloat16",
6
+ "attn_layer_idxs": [
7
+ 3,
8
+ 10,
9
+ 17,
10
+ 24,
11
+ 31
12
+ ],
13
+ "auto_map": {
14
+ "AutoConfig": "configuration_evo2.Evo2Config",
15
+ "AutoModel": "modeling_evo2.Evo2Model",
16
+ "AutoModelForCausalLM": "modeling_evo2.Evo2ForCausalLM"
17
+ },
18
+ "column_split": true,
19
+ "column_split_hyena": false,
20
+ "dtype": "bfloat16",
21
+ "eps": 1e-06,
22
+ "evo2_style_activations": true,
23
+ "final_norm": true,
24
+ "hcl_filter_groups": 4096,
25
+ "hcl_layer_idxs": [
26
+ 2,
27
+ 6,
28
+ 9,
29
+ 13,
30
+ 16,
31
+ 20,
32
+ 23,
33
+ 27,
34
+ 30
35
+ ],
36
+ "hcm_filter_groups": 256,
37
+ "hcm_filter_length": 128,
38
+ "hcm_layer_idxs": [
39
+ 1,
40
+ 5,
41
+ 8,
42
+ 12,
43
+ 15,
44
+ 19,
45
+ 22,
46
+ 26,
47
+ 29
48
+ ],
49
+ "hcs_filter_groups": 256,
50
+ "hcs_filter_length": 7,
51
+ "hcs_layer_idxs": [
52
+ 0,
53
+ 4,
54
+ 7,
55
+ 11,
56
+ 14,
57
+ 18,
58
+ 21,
59
+ 25,
60
+ 28
61
+ ],
62
+ "hidden_size": 4096,
63
+ "hyena_block_dtype": "bfloat16",
64
+ "hyena_filter_groups": 1,
65
+ "hyena_flip_x1x2": false,
66
+ "hyena_out_proj_bias": true,
67
+ "inference_mode": true,
68
+ "inner_mlp_size": 11008,
69
+ "inner_size_multiple_of": 16,
70
+ "interleave": true,
71
+ "log_intermediate_values": false,
72
+ "make_vocab_size_divisible_by": 8,
73
+ "max_batch_size": 1,
74
+ "max_seqlen": 8192,
75
+ "mha_out_proj_bias": true,
76
+ "mlp_activation": "gelu",
77
+ "mlp_dtype": "bfloat16",
78
+ "mlp_init_method": "torch.nn.init.zeros_",
79
+ "mlp_output_init_method": "torch.nn.init.zeros_",
80
+ "model_parallel_size": 1,
81
+ "model_type": "evo2",
82
+ "num_attention_heads": 32,
83
+ "num_filters": 4096,
84
+ "num_layers": 32,
85
+ "pipe_parallel_size": 1,
86
+ "prefill_style": "fft",
87
+ "print_activations": false,
88
+ "proj_groups": 1,
89
+ "qkv_proj_bias": false,
90
+ "rotary_emb_base": 10000,
91
+ "rotary_emb_scaling_factor": 1.0,
92
+ "short_filter_bias": false,
93
+ "short_filter_length": 3,
94
+ "smeared_gqa": false,
95
+ "state_size": 16,
96
+ "tie_embeddings": true,
97
+ "transformers_version": "4.57.6",
98
+ "use_cache": true,
99
+ "use_flash_attn": false,
100
+ "use_flash_depthwise": false,
101
+ "use_flash_rmsnorm": false,
102
+ "use_flashfft": false,
103
+ "use_fp8_input_projections": false,
104
+ "use_interpolated_rotary_pos_emb": false,
105
+ "use_laughing_hyena": false,
106
+ "vocab_size": 512,
107
+ "model_max_length": 8192
108
+ }
configuration_evo2.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Configuration for Evo2 (StripedHyena2)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import List
7
+
8
+ from transformers import PretrainedConfig
9
+
10
+
11
+ class Evo2Config(PretrainedConfig):
12
+ """Evo2 config.
13
+
14
+ Defaults match evo2_7b_base (32-layer, 4096-hidden). Per-variant overrides
15
+ are written into the config.json of each repo by convert_checkpoint.py.
16
+
17
+ Block dispatch is driven by four index lists:
18
+ attn_layer_idxs : transformer (MHA + RoPE) blocks
19
+ hcl_layer_idxs : Hyena Cascade Long (IIR via log_poles + residues)
20
+ hcm_layer_idxs : Hyena Cascade Medium (FIR, fir_inner_filter_length=128)
21
+ hcs_layer_idxs : Hyena Cascade Short (FIR, fir_inner_filter_length=7)
22
+ Their disjoint union must equal range(num_layers).
23
+ """
24
+
25
+ model_type = "evo2"
26
+
27
+ def __init__(
28
+ self,
29
+ # Architecture core
30
+ vocab_size: int = 512,
31
+ hidden_size: int = 4096,
32
+ num_filters: int = 4096,
33
+ inner_mlp_size: int = 11008,
34
+ num_layers: int = 32,
35
+ num_attention_heads: int = 32,
36
+ # Block dispatch
37
+ attn_layer_idxs: List[int] | None = None,
38
+ hcl_layer_idxs: List[int] | None = None,
39
+ hcm_layer_idxs: List[int] | None = None,
40
+ hcs_layer_idxs: List[int] | None = None,
41
+ # Filter geometry
42
+ hcm_filter_length: int = 128,
43
+ hcs_filter_length: int = 7,
44
+ hcl_filter_groups: int = 4096,
45
+ hcm_filter_groups: int = 256,
46
+ hcs_filter_groups: int = 256,
47
+ hyena_filter_groups: int = 1,
48
+ short_filter_length: int = 3,
49
+ short_filter_bias: bool = False,
50
+ state_size: int = 16,
51
+ # Channel-split conventions
52
+ column_split: bool = True,
53
+ column_split_hyena: bool = False,
54
+ interleave: bool = True,
55
+ hyena_flip_x1x2: bool = False,
56
+ # Norms / activations
57
+ eps: float = 1e-6,
58
+ final_norm: bool = True,
59
+ mlp_activation: str = "gelu",
60
+ evo2_style_activations: bool = True,
61
+ # Linear biases
62
+ mha_out_proj_bias: bool = True,
63
+ hyena_out_proj_bias: bool = True,
64
+ qkv_proj_bias: bool = False,
65
+ # MLP geometry
66
+ inner_size_multiple_of: int = 16,
67
+ make_vocab_size_divisible_by: int = 8,
68
+ # Embeddings
69
+ tie_embeddings: bool = True,
70
+ # Rotary / sequence
71
+ max_seqlen: int = 8192,
72
+ max_batch_size: int = 1,
73
+ rotary_emb_base: float = 10000.0,
74
+ use_interpolated_rotary_pos_emb: bool = False,
75
+ rotary_emb_scaling_factor: float = 1.0,
76
+ # Inference engine
77
+ prefill_style: str = "fft",
78
+ inference_mode: bool = True,
79
+ # Projection precision (TE FP8 - required for 1b / 20b / 40b)
80
+ use_fp8_input_projections: bool = False,
81
+ # Backend toggles
82
+ use_cache: bool = True,
83
+ # Vortex used this flag at runtime. Our HF port ignores it entirely
84
+ # (attention dispatch is driven by ``config._attn_implementation``,
85
+ # the standard HF mechanism). Default is False here so the config
86
+ # reflects what actually runs: SDPA by default unless the user passes
87
+ # ``attn_implementation="flash_attention_2"`` to from_pretrained.
88
+ use_flash_attn: bool = False,
89
+ use_flash_rmsnorm: bool = False,
90
+ use_flash_depthwise: bool = False,
91
+ use_flashfft: bool = False,
92
+ # Per-block dtypes (cast at module init)
93
+ attn_block_dtype: str = "bfloat16",
94
+ hyena_block_dtype: str = "bfloat16",
95
+ mlp_dtype: str = "bfloat16",
96
+ # Multi-tensor parallel knobs (kept for ParallelGatedMLP._compute_inner_size)
97
+ model_parallel_size: int = 1,
98
+ pipe_parallel_size: int = 1,
99
+ # GQA
100
+ proj_groups: int = 1,
101
+ smeared_gqa: bool = False,
102
+ **kwargs,
103
+ ):
104
+ if attn_layer_idxs is None:
105
+ attn_layer_idxs = [3, 10, 17, 24, 31]
106
+ if hcl_layer_idxs is None:
107
+ hcl_layer_idxs = [2, 6, 9, 13, 16, 20, 23, 27, 30]
108
+ if hcm_layer_idxs is None:
109
+ hcm_layer_idxs = [1, 5, 8, 12, 15, 19, 22, 26, 29]
110
+ if hcs_layer_idxs is None:
111
+ hcs_layer_idxs = [0, 4, 7, 11, 14, 18, 21, 25, 28]
112
+
113
+ self.vocab_size = vocab_size
114
+ self.hidden_size = hidden_size
115
+ self.num_filters = num_filters
116
+ self.inner_mlp_size = inner_mlp_size
117
+ self.num_layers = num_layers
118
+ self.num_attention_heads = num_attention_heads
119
+
120
+ self.attn_layer_idxs = attn_layer_idxs
121
+ self.hcl_layer_idxs = hcl_layer_idxs
122
+ self.hcm_layer_idxs = hcm_layer_idxs
123
+ self.hcs_layer_idxs = hcs_layer_idxs
124
+
125
+ self.hcm_filter_length = hcm_filter_length
126
+ self.hcs_filter_length = hcs_filter_length
127
+ self.hcl_filter_groups = hcl_filter_groups
128
+ self.hcm_filter_groups = hcm_filter_groups
129
+ self.hcs_filter_groups = hcs_filter_groups
130
+ self.hyena_filter_groups = hyena_filter_groups
131
+ self.short_filter_length = short_filter_length
132
+ self.short_filter_bias = short_filter_bias
133
+ self.state_size = state_size
134
+
135
+ self.column_split = column_split
136
+ self.column_split_hyena = column_split_hyena
137
+ self.interleave = interleave
138
+ self.hyena_flip_x1x2 = hyena_flip_x1x2
139
+
140
+ self.eps = eps
141
+ self.final_norm = final_norm
142
+ self.mlp_activation = mlp_activation
143
+ self.evo2_style_activations = evo2_style_activations
144
+
145
+ self.mha_out_proj_bias = mha_out_proj_bias
146
+ self.hyena_out_proj_bias = hyena_out_proj_bias
147
+ self.qkv_proj_bias = qkv_proj_bias
148
+
149
+ self.inner_size_multiple_of = inner_size_multiple_of
150
+ self.make_vocab_size_divisible_by = make_vocab_size_divisible_by
151
+
152
+ self.tie_embeddings = tie_embeddings
153
+
154
+ self.max_seqlen = max_seqlen
155
+ self.max_batch_size = max_batch_size
156
+ self.rotary_emb_base = rotary_emb_base
157
+ self.use_interpolated_rotary_pos_emb = use_interpolated_rotary_pos_emb
158
+ self.rotary_emb_scaling_factor = rotary_emb_scaling_factor
159
+
160
+ self.prefill_style = prefill_style
161
+ self.inference_mode = inference_mode
162
+
163
+ self.use_fp8_input_projections = use_fp8_input_projections
164
+
165
+ self.use_cache = use_cache
166
+ self.use_flash_attn = use_flash_attn
167
+ self.use_flash_rmsnorm = use_flash_rmsnorm
168
+ self.use_flash_depthwise = use_flash_depthwise
169
+ self.use_flashfft = use_flashfft
170
+
171
+ self.attn_block_dtype = attn_block_dtype
172
+ self.hyena_block_dtype = hyena_block_dtype
173
+ self.mlp_dtype = mlp_dtype
174
+
175
+ self.model_parallel_size = model_parallel_size
176
+ self.pipe_parallel_size = pipe_parallel_size
177
+
178
+ self.proj_groups = proj_groups
179
+ self.smeared_gqa = smeared_gqa
180
+
181
+ super().__init__(**kwargs)
182
+
183
+ # HF generation helpers expect `num_hidden_layers`.
184
+ @property
185
+ def num_hidden_layers(self) -> int:
186
+ return self.num_layers
187
+
188
+ # Internal blocks were originally written against a dotdict and call
189
+ # `config.get(key, default)` extensively; provide a dict-like getter.
190
+ def get(self, key, default=None):
191
+ return getattr(self, key, default)
192
+
193
+ @classmethod
194
+ def from_original_config(cls, config_path: str, **kwargs) -> "Evo2Config":
195
+ with open(config_path, "r") as f:
196
+ config = json.load(f)
197
+ return cls(**config, **kwargs)
engine.py ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Hyena inference engine for Evo2 (StripedHyena2).
2
+
3
+ Three operator families are exercised by Evo2 blocks:
4
+
5
+ * parallel_fir(gate=False) -- outer FIR used by all hyena blocks before any
6
+ channel split (input projection convolution).
7
+ * parallel_fir(gate=True) -- inner FIR cascade used by hcm/hcs blocks
8
+ (x1 * v gated, then convolved by `h`,
9
+ then multiplied by x2 postgate).
10
+ * parallel_iir -- modal-form IIR (long convolution via FFT)
11
+ used by hcl blocks; poles + residues parameterize
12
+ a stable, long-range linear filter.
13
+
14
+ Sequential step paths (step_fir / step_iir) are used during generation.
15
+
16
+ Layout conventions match vortex exactly so checkpoints are bit-identical.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import torch
22
+ import torch.nn.functional as F
23
+
24
+
25
+ IIR_PREFILL_MODES = ["recurrence", "modal-fft"]
26
+
27
+
28
+ def adjust_filter_shape_for_broadcast(u, h):
29
+ h = h.squeeze()
30
+ if len(u.shape) > len(h.shape):
31
+ h = h.unsqueeze(0)
32
+ if len(u.shape) > 3:
33
+ h = h.unsqueeze(1)
34
+ return h
35
+
36
+
37
+ def fftconv_func(u, k, D, dropout_mask, gelu=True, k_rev=None, bidirectional=False, **kwargs):
38
+ """FFT convolution for long FIR filters (length >= 128 path)."""
39
+ seqlen = u.shape[-1]
40
+ fft_size = 2 * seqlen
41
+
42
+ k_f = torch.fft.rfft(k, n=fft_size) / fft_size
43
+ k_f = adjust_filter_shape_for_broadcast(u, k_f)
44
+ k = k.squeeze()
45
+
46
+ if bidirectional:
47
+ u_f = torch.fft.rfft(u.to(dtype=k.dtype), n=fft_size)
48
+ k, k2 = k.split(k.shape[1] // 2, dim=1)
49
+ k2_f = torch.fft.rfft(k2, n=fft_size) / fft_size
50
+ y1 = u_f * k_f
51
+ y2 = u_f.conj() * k2_f.conj()
52
+ y = torch.fft.irfft(y1 + y2, n=fft_size, norm="forward")[..., :seqlen]
53
+ else:
54
+ if k_rev is not None:
55
+ k_rev_f = torch.fft.rfft(k_rev, n=fft_size) / fft_size
56
+ k_f = k_f + k_rev_f.conj()
57
+ u_f = torch.fft.rfft(u.to(dtype=k.dtype), n=fft_size)
58
+ y = torch.fft.irfft(u_f * k_f, n=fft_size, norm="forward")[..., :seqlen]
59
+
60
+ out = y + u * D.unsqueeze(-1)
61
+ return out.to(dtype=u.dtype)
62
+
63
+
64
+ def _column_split(x, num_heads, head_size):
65
+ """Compatibility helper for column_split_hyena=True (not used by Evo2)."""
66
+ x = x.reshape(x.shape[0], num_heads, 3 * head_size, x.shape[2])
67
+ x2 = x[:, :, :head_size].reshape(x.shape[0], -1, x.shape[-1])
68
+ x1 = x[:, :, head_size : 2 * head_size].reshape(x.shape[0], -1, x.shape[-1])
69
+ v = x[:, :, 2 * head_size :].reshape(x.shape[0], -1, x.shape[-1])
70
+ return x2, x1, v
71
+
72
+
73
+ class HyenaInferenceEngine:
74
+ def __init__(
75
+ self,
76
+ layer_idx: int | None = None,
77
+ iir_prefill_style: str = "modal-fft",
78
+ hyena_flip_x1x2: bool = False,
79
+ ) -> None:
80
+ assert iir_prefill_style in IIR_PREFILL_MODES, iir_prefill_style
81
+ self.iir_prefill_style = iir_prefill_style
82
+ self.layer_idx = layer_idx
83
+ self.low_mem_mode = False
84
+ self.hyena_flip_x1x2 = hyena_flip_x1x2
85
+
86
+ # ---------------------------------------------------------------- FIR
87
+ def parallel_fir(
88
+ self,
89
+ fir_fn,
90
+ u,
91
+ weight,
92
+ bias,
93
+ L,
94
+ dims,
95
+ groups=None,
96
+ gated_bias=False,
97
+ column_split_hyena=False,
98
+ dim_last=True,
99
+ fir_length=3,
100
+ gate=False,
101
+ inference_params=None,
102
+ padding_mask=None,
103
+ ):
104
+ L = u.shape[1] if dim_last else u.shape[2]
105
+ if gate:
106
+ hidden_size, num_attention_heads, hidden_size_per_attention_head, _, _ = dims
107
+ if column_split_hyena:
108
+ x2, x1, v = _column_split(u, num_attention_heads, hidden_size_per_attention_head)
109
+ else:
110
+ x2, x1, v = u.split([hidden_size, hidden_size, hidden_size], dim=1)
111
+ if self.hyena_flip_x1x2:
112
+ x1, x2 = x2, x1
113
+ u = x1 * v
114
+
115
+ if fir_length >= 128:
116
+ with torch.autocast("cuda"):
117
+ z = fftconv_func(
118
+ u.to(torch.float32),
119
+ weight[:, :, :L].to(torch.float32),
120
+ bias,
121
+ None,
122
+ gelu=False,
123
+ bidirectional=False,
124
+ groups=groups,
125
+ )
126
+ z = z.to(u.dtype)
127
+ else:
128
+ if dim_last:
129
+ u = u.permute(0, 2, 1) # B, D, L
130
+
131
+ z = fir_fn(
132
+ u.to(torch.float32),
133
+ weight.to(torch.float32),
134
+ bias=None,
135
+ stride=1,
136
+ padding=fir_length - 1,
137
+ groups=u.shape[1],
138
+ )[..., :L]
139
+
140
+ z = z.to(u.dtype)
141
+
142
+ if bias is not None:
143
+ if gated_bias:
144
+ z = z + bias[None, :, None] * u
145
+ else:
146
+ z = z + bias[None, :, None]
147
+
148
+ if isinstance(padding_mask, torch.Tensor):
149
+ z = z * padding_mask[:, None]
150
+
151
+ if gate:
152
+ z = x2 * z
153
+
154
+ if inference_params is not None:
155
+ fir_state = u[..., -fir_length + 1 :]
156
+ else:
157
+ fir_state = None
158
+
159
+ return z, fir_state
160
+
161
+ # ---------------------------------------------------------------- IIR
162
+ def parallel_iir(
163
+ self,
164
+ z_pre,
165
+ h,
166
+ D,
167
+ L,
168
+ poles,
169
+ residues,
170
+ t,
171
+ dims,
172
+ layer_idx,
173
+ inference_params=None,
174
+ prefill_style: str = "fft",
175
+ fftconv_fn=None,
176
+ padding_mask=None,
177
+ use_flashfft: bool = False,
178
+ column_split_hyena: bool = False,
179
+ long_fir_threshold: int | None = None,
180
+ ):
181
+ fft_size = 2 * L
182
+ hidden_size, num_attention_heads, hidden_size_per_attention_head, _, _ = dims
183
+ if column_split_hyena:
184
+ x2, x1, v = _column_split(z_pre, num_attention_heads, hidden_size_per_attention_head)
185
+ else:
186
+ x2, x1, v = z_pre.split([hidden_size, hidden_size, hidden_size], dim=1)
187
+
188
+ if self.hyena_flip_x1x2:
189
+ x1, x2 = x2, x1
190
+
191
+ x1v = x1 * v
192
+
193
+ X_s = None
194
+ if inference_params is not None and prefill_style == "recurrence":
195
+ y = self.prefill_via_direct_recurrence(
196
+ inference_params=inference_params, x1v=x1v, L=L,
197
+ poles=poles, residues=residues,
198
+ )
199
+ else:
200
+ if use_flashfft and (L % 2) == 0:
201
+ y = fftconv_fn(
202
+ x1v.to(dtype=torch.bfloat16).contiguous(),
203
+ h.to(dtype=torch.float32),
204
+ )
205
+ elif long_fir_threshold is None:
206
+ H = torch.fft.rfft(h.to(dtype=torch.float32), n=fft_size) / fft_size
207
+ X_s = torch.fft.fft(x1v.to(dtype=torch.float32), n=fft_size)
208
+ X = X_s[..., : H.shape[-1]]
209
+ if len(z_pre.shape) > 3:
210
+ H = H.unsqueeze(1)
211
+ y = torch.fft.irfft(X * H, n=fft_size, norm="forward")[..., :L]
212
+ else:
213
+ assert h.shape[0] == 1, "batch size must be 1 for long_fir_threshold"
214
+ h = h[0][:, None]
215
+ h = h[..., :long_fir_threshold]
216
+ y = F.conv1d(
217
+ x1v, h.to(dtype=x1v.dtype),
218
+ stride=1, groups=x1v.shape[1],
219
+ padding=h.shape[-1] - 1,
220
+ )[..., :L]
221
+
222
+ y = y.to(dtype=x1v.dtype)
223
+ y = (y + x1v * D.unsqueeze(-1)) * x2
224
+
225
+ if inference_params is not None and prefill_style == "fft":
226
+ self.prefill_via_modal_fft(
227
+ inference_params=inference_params, x1v=x1v, X_s=X_s, L=L,
228
+ t=t, poles=poles, dims=dims, layer_idx=layer_idx,
229
+ use_flashfft=use_flashfft, fftconv_fn=fftconv_fn,
230
+ )
231
+
232
+ return y.permute(0, 2, 1)
233
+
234
+ # --------------------------------------------------------- step (decode)
235
+ def step_fir(self, u, fir_state, weight, bias=None, gated_bias=False, flip_filter=False):
236
+ """Single-step FIR. fir_state holds the last (filter_len - 1) inputs."""
237
+ weight = weight.squeeze()
238
+ cache_size = fir_state.shape[-1]
239
+ filter_length = weight.shape[-1]
240
+ if flip_filter:
241
+ weight = weight.flip(-1)
242
+ weight = weight[..., -cache_size - 1 :].unsqueeze(0)
243
+ else:
244
+ weight = weight[..., : cache_size + 1].unsqueeze(0)
245
+
246
+ input_dtype = u.dtype
247
+ weight = weight.to(torch.float32)
248
+ u = u.to(torch.float32)
249
+ fir_state = fir_state.to(torch.float32)
250
+ bias = bias.to(torch.float32) if bias is not None else None
251
+
252
+ h0, h = weight[..., -1], weight[..., :-1]
253
+ y = h0 * u + torch.sum(fir_state * h, dim=-1)
254
+
255
+ if bias is not None:
256
+ if gated_bias:
257
+ y = y + bias * u
258
+ else:
259
+ y = y + bias
260
+
261
+ if cache_size < filter_length - 1:
262
+ fir_state = torch.cat([fir_state, u[..., None]], dim=-1)
263
+ else:
264
+ fir_state = torch.roll(fir_state, -1, dims=2)
265
+ fir_state[..., -1] = u
266
+
267
+ return y.to(input_dtype), fir_state
268
+
269
+ def step_iir(self, x2, x1, v, D, residues, poles, iir_state, iir_groups=1):
270
+ x1v = x1 * v
271
+ # `poles` arg contains log_poles (real, in modal form for evo2)
272
+ poles = torch.exp(poles)
273
+ poles = poles[..., 0][None]
274
+ residues = residues[None]
275
+ iir_state = poles * iir_state + x1v[..., None]
276
+ res_state = torch.sum(residues * iir_state, dim=-1)
277
+
278
+ if iir_groups > 1:
279
+ raise NotImplementedError
280
+ y = x2 * (res_state + D * x1v)
281
+ return y, iir_state
282
+
283
+ def prefill_via_direct_recurrence(self, inference_params, x1v, L, residues, poles, *args, **kwargs):
284
+ state_dim = poles.shape[1]
285
+ x1v_ = x1v[..., None, None]
286
+ x1v_ = x1v_.repeat(1, 1, 1, state_dim, 2)
287
+ x1v_[..., 1] = 0
288
+
289
+ state = 0 * x1v_[:, :, 0]
290
+ output = 0 * x1v_[:, :, :, 0, 0]
291
+
292
+ poles = poles[:, :, 0][None]
293
+ residues = residues[:, :, 0][None].repeat(x1v_.shape[0], 1, 1, 1)
294
+
295
+ for i in range(L):
296
+ state[..., 0] = poles[..., 0] * state[..., 0] - poles[..., 1] * state[..., 1] + x1v_[:, :, i, :, 0]
297
+ state[..., 1] = poles[..., 0] * state[..., 1] + poles[..., 1] * state[..., 0] + x1v_[:, :, i, :, 1]
298
+ output[:, :, i] = torch.sum(residues * state, dim=-2)[..., 0]
299
+
300
+ inference_params.state_dict[self.layer_idx] = state.to(dtype=torch.float32)
301
+ return output
302
+
303
+ def prefill_via_modal_fft(
304
+ self, inference_params, x1v, L, poles, t, dims, layer_idx,
305
+ X_s=None, use_flashfft=False, fftconv_fn=None,
306
+ state_dtype=torch.float32, *args, **kwargs,
307
+ ):
308
+ """Compute IIR state via a single FFT.
309
+
310
+ Evo2 uses *real* `log_poles` (not the complex view-as-real layout
311
+ that Evo1 uses), so the impulse-response IFFT is mathematically real;
312
+ the imaginary component is FFT round-off. We take ``.real`` explicitly
313
+ instead of relying on torch's lossy complex->real cast, which avoids
314
+ the "Casting complex values to real discards the imaginary part"
315
+ UserWarning at every decoded token.
316
+ """
317
+ hidden_size, _, _, state_size, hyena_filter_groups = dims
318
+
319
+ assert X_s is not None
320
+ bs = x1v.shape[0]
321
+ fft_size = 2 * L
322
+ state_s = (poles.to(torch.float32) * t).exp()
323
+ state_S = torch.fft.fft(state_s, n=fft_size).repeat(bs, 1, 1, 1)
324
+ if hyena_filter_groups > 1:
325
+ state_S = state_S.repeat_interleave(hidden_size // hyena_filter_groups, 1)
326
+ state = torch.fft.ifft(X_s[..., None, :] * state_S, n=fft_size)
327
+ inference_params.state_dict[layer_idx] = state[..., L - 1].real.to(dtype=state_dtype)
generation_config.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "eos_token_id": 0,
3
+ "pad_token_id": 1,
4
+ "_from_model_config": true
5
+ }
hyena.py ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """StripedHyena2 block definitions for Evo2.
2
+
3
+ Block types:
4
+
5
+ * AttentionBlock -- standard pre-norm transformer block with MHA + RoPE.
6
+ * ParallelGatedConvBlock -- pre-norm hyena block; the inner `filter` is a
7
+ HyenaCascade configured per block-type idx:
8
+ hcl: IIR via log_poles + residues
9
+ hcm: FIR cascade, fir_inner_filter_length=128
10
+ hcs: FIR cascade, fir_inner_filter_length=7
11
+
12
+ Inside ParallelGatedConvBlock, `projections` is a TELinear (3x hidden_size
13
+ output) -- the FP8-capable input projection. For 7B variants without TE,
14
+ the pure-PyTorch fallback in layers.py is used.
15
+
16
+ The `interleave` config flag (True for all Evo2 variants) reorders the
17
+ channel dim after the outer FIR before the channel-split / cascade.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from typing import Optional, Tuple
23
+
24
+ import torch
25
+ import torch.nn as nn
26
+ import torch.nn.functional as F
27
+
28
+ from .attention import MHA
29
+ from .engine import HyenaInferenceEngine
30
+ from .layers import ParallelGatedMLP, RMSNorm, TELinear
31
+ from .rotary import swap_mha_rope
32
+
33
+
34
+ def _interleave(z_pre: torch.Tensor) -> torch.Tensor:
35
+ """Deinterleave a [x1_0,x2_0,v_0,x1_1,x2_1,v_1,...] channel layout into
36
+ blocks of [x1_all | x2_all | v_all]. Matches vortex.model.utils.interleave."""
37
+ if len(z_pre.shape) == 3: # (B, C, L) non-cached path
38
+ x1 = z_pre[:, 0::3, :]
39
+ x2 = z_pre[:, 1::3, :]
40
+ v = z_pre[:, 2::3, :]
41
+ return torch.cat([x1, x2, v], dim=1)
42
+ x1 = z_pre[..., 0::3]
43
+ x2 = z_pre[..., 1::3]
44
+ v = z_pre[..., 2::3]
45
+ return torch.cat([x1, x2, v], dim=-1)
46
+
47
+
48
+ def _column_split_step(z_pre, num_heads, head_size):
49
+ """Per-step variant of column_split for sequential_forward (cache step)."""
50
+ x = z_pre.reshape(z_pre.shape[0], num_heads, 3 * head_size)
51
+ x2 = x[..., :head_size].reshape(z_pre.shape[0], -1)
52
+ x1 = x[..., head_size : 2 * head_size].reshape(z_pre.shape[0], -1)
53
+ v = x[..., 2 * head_size :].reshape(z_pre.shape[0], -1)
54
+ return x2, x1, v
55
+
56
+
57
+ # =============================================================================
58
+ # Attention block
59
+ # =============================================================================
60
+
61
+
62
+ class AttentionBlock(nn.Module):
63
+ def __init__(self, config, layer_idx: int) -> None:
64
+ super().__init__()
65
+ self.config = config
66
+ self.layer_idx = layer_idx
67
+ self.pre_norm = RMSNorm(config)
68
+ self.post_norm = RMSNorm(config)
69
+ self.proj_groups = config.get("proj_groups", 1)
70
+ dtype = self._resolve_dtype(config.get("attn_block_dtype", "bfloat16"))
71
+ mlp_dtype = self._resolve_dtype(config.get("mlp_dtype", "bfloat16"))
72
+ self.num_attention_heads = config.num_attention_heads
73
+ self.hidden_size = config.hidden_size
74
+ self.hidden_size_per_attention_head = config.hidden_size // config.num_attention_heads
75
+
76
+ attn_impl = getattr(config, "_attn_implementation", "eager")
77
+
78
+ self.inner_mha_cls = MHA(
79
+ embed_dim=config.hidden_size,
80
+ num_heads=config.num_attention_heads,
81
+ num_heads_kv=config.num_attention_heads // self.proj_groups,
82
+ rotary_emb_dim=config.hidden_size // config.num_attention_heads,
83
+ qkv_proj_bias=config.get("qkv_proj_bias", False),
84
+ rotary_emb_base=config.get("rotary_emb_base", 1000000),
85
+ causal=True,
86
+ layer_idx=layer_idx,
87
+ out_proj_bias=config.get("mha_out_proj_bias", True),
88
+ attn_implementation=attn_impl,
89
+ ).to(dtype=dtype)
90
+
91
+ if config.get("use_interpolated_rotary_pos_emb", False):
92
+ swap_mha_rope(
93
+ mha=self.inner_mha_cls,
94
+ kwargs_new_rope={
95
+ "scaling_factor": config.get("rotary_emb_scaling_factor", 1.0)
96
+ },
97
+ )
98
+
99
+ if self.config.get("smeared_gqa", False):
100
+ self.inner_mha_cls.num_heads_kv = self.inner_mha_cls.num_heads
101
+ # Round-trip inv_freq through state_dict for safety.
102
+ self.inner_mha_cls.rotary_emb.register_buffer(
103
+ "inv_freq", self.inner_mha_cls.rotary_emb.inv_freq
104
+ )
105
+
106
+ self.mlp = ParallelGatedMLP(config, layer_idx).to(dtype=mlp_dtype)
107
+
108
+ @staticmethod
109
+ def _resolve_dtype(name) -> torch.dtype:
110
+ if isinstance(name, torch.dtype):
111
+ return name
112
+ mapping = {
113
+ "bfloat16": torch.bfloat16,
114
+ "float16": torch.float16,
115
+ "float32": torch.float32,
116
+ }
117
+ return mapping.get(name, torch.bfloat16)
118
+
119
+ def forward(
120
+ self,
121
+ u: torch.Tensor,
122
+ inference_params=None,
123
+ padding_mask: Optional[torch.Tensor] = None,
124
+ output_attentions: bool = False,
125
+ *args,
126
+ **kwargs,
127
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
128
+ if isinstance(padding_mask, torch.Tensor):
129
+ # Zero attended values at pad positions (no qkv bias here).
130
+ u = u * padding_mask[..., None]
131
+
132
+ attn_out, attn_weights = self.inner_mha_cls(
133
+ self.pre_norm(u),
134
+ inference_params=inference_params,
135
+ output_attentions=output_attentions,
136
+ )
137
+ u = attn_out + u
138
+
139
+ if isinstance(padding_mask, torch.Tensor):
140
+ u = u * padding_mask[..., None]
141
+ u = self.mlp(self.post_norm(u)) + u
142
+ return u, attn_weights
143
+
144
+
145
+ # =============================================================================
146
+ # Hyena cascade (hcl / hcm / hcs)
147
+ # =============================================================================
148
+
149
+
150
+ class HyenaCascade(nn.Module):
151
+ """The inner mixer of a hyena block.
152
+
153
+ Two execution modes selected by `fir_inner_filter_length`:
154
+ * None -> hcl: outer FIR -> channel split -> parallel_iir
155
+ (modal-form long convolution)
156
+ * int (e.g. 7 or 128) -> hcm/hcs: outer FIR -> interleave -> inner FIR
157
+ cascade via parallel_fir(gate=True)
158
+ """
159
+
160
+ def __init__(
161
+ self,
162
+ config,
163
+ layer_idx: int,
164
+ hyena_filter_groups: int,
165
+ fir_inner_filter_length: int | None = None,
166
+ ) -> None:
167
+ super().__init__()
168
+ self.config = config
169
+ self.layer_idx = layer_idx
170
+ self.hyena_filter_groups = hyena_filter_groups
171
+
172
+ self.use_flashfft = config.get("use_flashfft", False)
173
+ self.state_size = config.state_size
174
+ self.hidden_size = config.hidden_size
175
+ self.num_filters = config.num_filters
176
+ self.inference_mode = config.get("inference_mode", True)
177
+ self.column_split_hyena = config.get("column_split_hyena", False)
178
+ self.hyena_flip_x1x2 = config.get("hyena_flip_x1x2", False)
179
+
180
+ assert self.hidden_size % self.num_filters == 0
181
+ assert self.num_filters <= self.hidden_size
182
+
183
+ self.num_attention_heads = config.num_attention_heads
184
+ self.hidden_size_per_attention_head = (
185
+ self.hidden_size // self.num_attention_heads
186
+ )
187
+
188
+ self.fir_inner_filter_length = fir_inner_filter_length
189
+ self.short_filter_length = config.short_filter_length
190
+ self.short_filter_weight = nn.Parameter(
191
+ torch.randn(3 * config.hidden_size, 1, config.short_filter_length)
192
+ )
193
+ self.short_filter_bias = (
194
+ nn.Parameter(torch.randn(3 * config.hidden_size))
195
+ if config.short_filter_bias else None
196
+ )
197
+
198
+ self.engine = HyenaInferenceEngine(
199
+ layer_idx=layer_idx,
200
+ hyena_flip_x1x2=config.get("hyena_flip_x1x2", False),
201
+ )
202
+ self.fir_fn = F.conv1d
203
+ self.fir_inner_fn = F.conv1d
204
+ self.fftconv_fn = None
205
+ self.long_fir_threshold = config.get("long_fir_threshold", None)
206
+ if self.long_fir_threshold is not None:
207
+ assert not self.use_flashfft, "long_fir_threshold incompatible with flashfft"
208
+
209
+ self.num_systems = self.hyena_filter_groups
210
+ self.channels_per_group = self.hidden_size // self.hyena_filter_groups
211
+
212
+ if self.fir_inner_filter_length:
213
+ # hcm / hcs: explicit FIR filter `h` of shape (groups, 1, inner_len)
214
+ self.h = nn.Parameter(
215
+ torch.randn(self.hyena_filter_groups, 1, fir_inner_filter_length)
216
+ )
217
+ if fir_inner_filter_length >= 128:
218
+ self.D = nn.Parameter(torch.zeros(self.hidden_size))
219
+ else:
220
+ self.D = None
221
+ else:
222
+ # hcl: modal-form IIR, log_poles in (num_systems, state_size, 1)
223
+ log_poles = torch.randn(self.num_systems, self.state_size, 1, dtype=torch.float32)
224
+ self.log_poles = nn.Parameter(log_poles)
225
+ self.residues = nn.Parameter(
226
+ torch.randn(self.num_systems, self.state_size, dtype=torch.float32)
227
+ )
228
+ self.D = nn.Parameter(torch.zeros(self.hidden_size))
229
+ self.h = None
230
+
231
+ self.t = None
232
+
233
+ def forward(self, u, inference_params=None, padding_mask=None, *args, **kwargs):
234
+ if (
235
+ inference_params is not None
236
+ and self.layer_idx in inference_params.fir_state_dict
237
+ ):
238
+ return self.sequential_forward(u, inference_params)
239
+ return self.parallel_forward(u, inference_params, padding_mask)
240
+
241
+ def parallel_forward(self, u, inference_params=None, padding_mask=None):
242
+ L = u.shape[1]
243
+ dims = (
244
+ self.hidden_size,
245
+ self.num_attention_heads,
246
+ self.hidden_size_per_attention_head,
247
+ self.state_size,
248
+ self.hyena_filter_groups,
249
+ )
250
+ z_pre, fir_state = self.engine.parallel_fir(
251
+ self.fir_fn, u,
252
+ self.short_filter_weight, self.short_filter_bias,
253
+ L, dims=dims, gate=False,
254
+ column_split_hyena=self.column_split_hyena,
255
+ fir_length=self.short_filter_length,
256
+ inference_params=inference_params,
257
+ padding_mask=padding_mask, dim_last=True,
258
+ )
259
+ if inference_params:
260
+ inference_params.fir_state_dict[self.layer_idx] = fir_state
261
+
262
+ if self.config.interleave:
263
+ z_pre = _interleave(z_pre)
264
+
265
+ if self.h is None:
266
+ # hcl path: compute IIR impulse response then convolve via FFT
267
+ h, _, _, _ = self.compute_filter(L, u.device)
268
+ else:
269
+ h = self.h
270
+
271
+ D = self.D
272
+ if self.hyena_filter_groups > 1:
273
+ h = h.repeat_interleave(self.hidden_size // self.hyena_filter_groups, 0)
274
+
275
+ if self.fir_inner_filter_length is not None:
276
+ # hcm / hcs: inner FIR cascade
277
+ y, fir_inner_state = self.engine.parallel_fir(
278
+ self.fir_inner_fn, z_pre, h, D, L,
279
+ dims=dims, gate=True,
280
+ gated_bias=self.fir_inner_filter_length >= 128,
281
+ dim_last=False,
282
+ column_split_hyena=self.column_split_hyena,
283
+ fir_length=self.fir_inner_filter_length,
284
+ inference_params=inference_params,
285
+ padding_mask=padding_mask,
286
+ groups=self.hyena_filter_groups,
287
+ )
288
+ y = y.permute(0, 2, 1)
289
+ if inference_params:
290
+ inference_params.fir_inner_state_dict[self.layer_idx] = fir_inner_state
291
+ else:
292
+ # hcl: parallel IIR via FFT
293
+ y = self.engine.parallel_iir(
294
+ z_pre, h, D, L, t=self.t,
295
+ poles=self.log_poles, residues=self.residues,
296
+ dims=dims, inference_params=inference_params,
297
+ layer_idx=self.layer_idx,
298
+ prefill_style=self.config.get("prefill_style", "fft"),
299
+ use_flashfft=self.use_flashfft,
300
+ fftconv_fn=self.fftconv_fn,
301
+ column_split_hyena=self.column_split_hyena,
302
+ long_fir_threshold=self.long_fir_threshold,
303
+ padding_mask=padding_mask,
304
+ )
305
+
306
+ return y, inference_params
307
+
308
+ def sequential_forward(self, u, inference_params):
309
+ if len(u.shape) > 2:
310
+ u = u[:, -1]
311
+ # Track input dtype so we can cast back at the end. step_iir produces
312
+ # fp32 output (log_poles / residues are fp32 for stability) which would
313
+ # otherwise dtype-mismatch the downstream bf16 Linear (out_filter_dense).
314
+ input_dtype = u.dtype
315
+
316
+ z_pre, fir_state = self.engine.step_fir(
317
+ u, inference_params.fir_state_dict[self.layer_idx],
318
+ weight=self.short_filter_weight, bias=self.short_filter_bias,
319
+ )
320
+ inference_params.fir_state_dict[self.layer_idx] = fir_state
321
+
322
+ if self.config.interleave:
323
+ # For a single step, dim-1 length is C and `_interleave` operates
324
+ # along the channel dim; reshape to (B, C, 1) so the dim==3 branch
325
+ # applies, then squeeze the last dim back.
326
+ z_pre = _interleave(z_pre.unsqueeze(-1)).squeeze(-1)
327
+
328
+ if self.column_split_hyena:
329
+ x2, x1, v = _column_split_step(
330
+ z_pre, self.num_attention_heads, self.hidden_size_per_attention_head
331
+ )
332
+ else:
333
+ x2, x1, v = z_pre.split([self.hidden_size, self.hidden_size, self.hidden_size], dim=1)
334
+
335
+ if self.hyena_flip_x1x2:
336
+ x1, x2 = x2, x1
337
+
338
+ if self.fir_inner_filter_length is not None:
339
+ if self.hyena_filter_groups > 1:
340
+ h = self.h.repeat_interleave(self.hidden_size // self.hyena_filter_groups, 0)
341
+ else:
342
+ h = self.h
343
+ y, fir_inner_state = self.engine.step_fir(
344
+ x1 * v,
345
+ inference_params.fir_inner_state_dict[self.layer_idx],
346
+ weight=h, bias=self.D,
347
+ flip_filter=self.fir_inner_filter_length >= 128,
348
+ gated_bias=self.fir_inner_filter_length >= 128,
349
+ )
350
+ y = y * x2
351
+ inference_params.fir_inner_state_dict[self.layer_idx] = fir_inner_state
352
+ else:
353
+ y, iir_state = self.engine.step_iir(
354
+ x2, x1, v, self.D,
355
+ self.residues, self.log_poles,
356
+ inference_params.state_dict[self.layer_idx],
357
+ iir_groups=1,
358
+ )
359
+ inference_params.state_dict[self.layer_idx] = iir_state
360
+
361
+ y = y.to(input_dtype)
362
+ return y[:, None], inference_params
363
+
364
+ def update_time(self, L, device):
365
+ if self.t is None:
366
+ self.t = torch.arange(L, device=device)[None, None]
367
+ elif self.t.shape[-1] < L:
368
+ self.t = torch.arange(L, device=device)[None, None]
369
+ else:
370
+ self.t = self.t[..., :L]
371
+
372
+ def compute_filter(self, L, device):
373
+ self.update_time(L, device)
374
+ filter_dtype = torch.float32
375
+ residues = self.residues.to(filter_dtype)
376
+ log_poles = self.log_poles.to(filter_dtype)
377
+ h = (residues[..., None] * (log_poles * self.t).exp()).sum(1)[None] # B, D, L
378
+ return h, filter_dtype, log_poles, residues
379
+
380
+
381
+ # =============================================================================
382
+ # Hyena block (wraps HyenaCascade with norms / projections / mlp)
383
+ # =============================================================================
384
+
385
+
386
+ class ParallelGatedConvBlock(nn.Module):
387
+ def __init__(
388
+ self,
389
+ config,
390
+ layer_idx: int,
391
+ hyena_filter_groups: int | None = None,
392
+ fir_inner_filter_length: int | None = None,
393
+ ) -> None:
394
+ super().__init__()
395
+ self.config = config
396
+ self.layer_idx = layer_idx
397
+ self.fir_inner_filter_length = fir_inner_filter_length
398
+ self.hyena_filter_groups = (
399
+ hyena_filter_groups if hyena_filter_groups is not None else config.hidden_size
400
+ )
401
+ dtype = AttentionBlock._resolve_dtype(config.get("hyena_block_dtype", "bfloat16"))
402
+ mlp_dtype = AttentionBlock._resolve_dtype(config.get("mlp_dtype", "bfloat16"))
403
+ self.pre_norm = RMSNorm(config).to(dtype=dtype)
404
+ self.post_norm = RMSNorm(config).to(dtype=dtype)
405
+ self.filter = HyenaCascade(
406
+ config, layer_idx,
407
+ hyena_filter_groups=self.hyena_filter_groups,
408
+ fir_inner_filter_length=fir_inner_filter_length,
409
+ ).to(dtype=dtype)
410
+
411
+ self.projections = TELinear(
412
+ config.hidden_size,
413
+ 3 * config.hidden_size,
414
+ bias=config.qkv_proj_bias,
415
+ init_method=torch.nn.init.xavier_uniform_,
416
+ use_fp8=config.get("use_fp8_input_projections", False),
417
+ )
418
+
419
+ self.out_filter_dense = nn.Linear(
420
+ config.hidden_size, config.hidden_size,
421
+ bias=config.hyena_out_proj_bias,
422
+ ).to(dtype)
423
+ self.mlp = ParallelGatedMLP(config, layer_idx).to(dtype=mlp_dtype)
424
+
425
+ def _pad_to_multiple(self, x: torch.Tensor, multiple: int = 16) -> torch.Tensor:
426
+ """Right-pad along seq dim to a multiple of `multiple` when FP8 input
427
+ projections are enabled. TE's FP8 path requires the product of all
428
+ dims except the last to be divisible by 8 (we use 16 to be safe).
429
+ No-op when FP8 is off."""
430
+ if not self.config.get("use_fp8_input_projections", False):
431
+ return x
432
+ seq_len = x.size(1)
433
+ pad_len = (multiple - (seq_len % multiple)) % multiple
434
+ if pad_len == 0:
435
+ return x
436
+ return F.pad(x, (0, 0, 0, pad_len))
437
+
438
+ def _proj_norm(self, x):
439
+ original_seq_len = x.size(1)
440
+ normalized = self.pre_norm(x)
441
+ normalized = self._pad_to_multiple(normalized)
442
+ with torch.cuda.device(x.device) if x.is_cuda else _nullctx():
443
+ projected = self.projections(normalized)
444
+ if isinstance(projected, tuple):
445
+ projected = projected[0]
446
+ # Slice back to original seq length if padding was added.
447
+ if projected.size(1) > original_seq_len:
448
+ projected = projected[:, :original_seq_len, :]
449
+ return projected
450
+
451
+ def forward(
452
+ self,
453
+ u: torch.Tensor,
454
+ inference_params=None,
455
+ padding_mask=None,
456
+ output_attentions: bool = False,
457
+ *args,
458
+ **kwargs,
459
+ ) -> Tuple[torch.Tensor, None]:
460
+ z = self._proj_norm(u)
461
+
462
+ if isinstance(padding_mask, torch.Tensor):
463
+ z = z * padding_mask[..., None]
464
+
465
+ z, inference_params = self.filter(
466
+ z, inference_params=inference_params, padding_mask=padding_mask,
467
+ )
468
+ z_in = self.out_filter_dense(z) + u
469
+
470
+ if isinstance(padding_mask, torch.Tensor):
471
+ z_in = z_in * padding_mask[..., None]
472
+
473
+ y = self.mlp(self.post_norm(z_in)) + z_in
474
+ # Hyena blocks have no attention matrix.
475
+ return y, None
476
+
477
+
478
+ class _nullctx:
479
+ def __enter__(self): return None
480
+ def __exit__(self, *a): return False
481
+
482
+
483
+ # =============================================================================
484
+ # Block dispatch
485
+ # =============================================================================
486
+
487
+
488
+ def get_block(config, layer_idx: int):
489
+ if layer_idx in config.attn_layer_idxs:
490
+ return AttentionBlock(config, layer_idx)
491
+ if layer_idx in config.hcl_layer_idxs:
492
+ return ParallelGatedConvBlock(
493
+ config, layer_idx,
494
+ hyena_filter_groups=config.hcl_filter_groups,
495
+ fir_inner_filter_length=None,
496
+ )
497
+ if layer_idx in config.hcm_layer_idxs:
498
+ return ParallelGatedConvBlock(
499
+ config, layer_idx,
500
+ hyena_filter_groups=config.hcm_filter_groups,
501
+ fir_inner_filter_length=config.hcm_filter_length,
502
+ )
503
+ if layer_idx in config.hcs_layer_idxs:
504
+ return ParallelGatedConvBlock(
505
+ config, layer_idx,
506
+ hyena_filter_groups=config.hcs_filter_groups,
507
+ fir_inner_filter_length=config.hcs_filter_length,
508
+ )
509
+ raise NotImplementedError(f"layer_idx {layer_idx} not in any block-type idxs")
510
+
511
+
512
+ def block_type_for_idx(config, layer_idx: int) -> str:
513
+ if layer_idx in config.attn_layer_idxs: return "mha"
514
+ if layer_idx in config.hcl_layer_idxs: return "hcl"
515
+ if layer_idx in config.hcm_layer_idxs: return "hcm"
516
+ if layer_idx in config.hcs_layer_idxs: return "hcs"
517
+ raise ValueError(f"block idx {layer_idx} not classified")
layers.py ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Basic layers for Evo2 (StripedHyena2).
2
+
3
+ * RMSNorm -- pre/post norm in each block
4
+ * ParallelGatedMLP -- GLU(act(l1(x)) * l2(x)) -> l3(...); evo2_style
5
+ activations replace `act` with Identity for layer > 0
6
+ * VocabParallelEmbedding -- single-process variant of vortex's
7
+ VocabParallelEmbedding so checkpoint keys match
8
+ * TELinear -- TransformerEngine FP8-capable Linear, with a
9
+ pure-PyTorch fallback when TE is not installed.
10
+ Used for the input QKV-like projections of
11
+ Hyena cascade blocks; required for 1B/20B/40B.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Callable
17
+
18
+ import torch
19
+ import torch.nn as nn
20
+ import torch.nn.functional as F
21
+ from torch import Tensor
22
+
23
+
24
+ try:
25
+ from transformer_engine.pytorch import Linear as _TELinearBase
26
+ from transformer_engine.common.recipe import Format, DelayedScaling
27
+ import transformer_engine.pytorch as te
28
+ HAS_TE = True
29
+ except ImportError:
30
+ HAS_TE = False
31
+
32
+
33
+ def grab_first_if_tuple(x):
34
+ if x.__class__.__name__ == "tuple":
35
+ return x[0]
36
+ return x
37
+
38
+
39
+ class RMSNorm(nn.Module):
40
+ def __init__(self, config):
41
+ super().__init__()
42
+ self.eps = config.eps
43
+ self.hidden_size = config.hidden_size
44
+ self.scale = nn.Parameter(torch.ones(self.hidden_size))
45
+ self.register_parameter("scale", self.scale)
46
+ self.use_flash_rmsnorm = config.get("use_flash_rmsnorm", False)
47
+ if self.use_flash_rmsnorm:
48
+ from flash_attn.ops.rms_norm import rms_norm as rmsnorm_func
49
+ self.rmsnorm_func = rmsnorm_func
50
+
51
+ def forward(self, x):
52
+ if self.use_flash_rmsnorm:
53
+ return self.rmsnorm_func(x, self.scale, self.eps)
54
+ y = x / (x.norm(2, dim=-1, keepdim=True) * self.hidden_size ** (-1.0 / 2) + self.eps)
55
+ return self.scale * y
56
+
57
+
58
+ class ParallelGatedMLP(nn.Module):
59
+ """GLU MLP. With evo2_style_activations=True, layer_idx > 0 uses Identity
60
+ in place of the gating activation; layer 0 keeps gelu."""
61
+
62
+ def __init__(self, config, layer_idx: int):
63
+ super().__init__()
64
+ self.layer_idx = layer_idx
65
+ multiple_of = config.get("inner_size_multiple_of", 64)
66
+ self.act_type = config.get("mlp_activation", "gelu")
67
+ if self.act_type == "gelu":
68
+ self.act = F.gelu
69
+ elif self.act_type == "silu":
70
+ self.act = F.silu
71
+ else:
72
+ raise NotImplementedError(f"Unknown mlp_activation: {self.act_type}")
73
+
74
+ if self.layer_idx > 0 and config.get("evo2_style_activations", False):
75
+ self.act = nn.Identity()
76
+
77
+ self.multiple_of = multiple_of * config.model_parallel_size
78
+ inner_size = int(2 * config.hidden_size * 4 / 3)
79
+ inner_size = self.multiple_of * ((inner_size + self.multiple_of - 1) // self.multiple_of)
80
+ if config.get("inner_mlp_size", None) is not None:
81
+ inner_size = config.inner_mlp_size
82
+
83
+ self.l1 = nn.Linear(config.hidden_size, inner_size, bias=False)
84
+ self.l2 = nn.Linear(config.hidden_size, inner_size, bias=False)
85
+ self.l3 = nn.Linear(inner_size, config.hidden_size, bias=False)
86
+
87
+ def forward(self, z):
88
+ z1, z2 = self.l1(z), self.l2(z)
89
+ z1, z2 = grab_first_if_tuple(z1), grab_first_if_tuple(z2)
90
+ y = self.l3(self.act(z1) * z2)
91
+ return grab_first_if_tuple(y)
92
+
93
+
94
+ class VocabParallelEmbedding(nn.Embedding):
95
+ """Single-process variant of vortex's VocabParallelEmbedding.
96
+
97
+ Drops distributed sharding so this minimal port runs on a single device
98
+ (HF/accelerate handles cross-device placement via device_map="auto").
99
+ """
100
+
101
+ def __init__(self, config):
102
+ vocab_size = config.vocab_size
103
+ padding_idx = config.get("padding_idx", None)
104
+ super().__init__(vocab_size, embedding_dim=config.hidden_size, padding_idx=padding_idx)
105
+
106
+ def embed(self, x: Tensor) -> Tensor:
107
+ return self.forward(x)
108
+
109
+ def unembed(self, u: Tensor) -> Tensor:
110
+ return u @ self.weight.T
111
+
112
+
113
+ if HAS_TE:
114
+
115
+ _TE_WORKSPACE_FIXUP_APPLIED = False
116
+
117
+ def fixup_te_workspace():
118
+ """Patch TE's Linear module to use per-device cuBLAS workspaces.
119
+
120
+ Vortex helper, ported verbatim. Without this, TE's Linear uses a single
121
+ workspace tensor allocated on whatever CUDA device was current at first
122
+ call, then fails ("cuBLAS Error: the function failed to launch on the
123
+ GPU") when called from layers on other devices -- which happens with
124
+ device_map="auto" sharding. Idempotent; safe to call multiple times.
125
+ No-op when TE is not installed (the import guard above gates it).
126
+ """
127
+ global _TE_WORKSPACE_FIXUP_APPLIED
128
+ if _TE_WORKSPACE_FIXUP_APPLIED:
129
+ return
130
+ from functools import lru_cache
131
+
132
+ @lru_cache
133
+ def te_cublas_get_workspace_per_device(device):
134
+ import transformer_engine.pytorch.module.base as tebase
135
+ with torch.cuda.device(device):
136
+ tebase._cublas_workspace = None # force get_workspace() to reallocate
137
+ return tebase.get_workspace()
138
+
139
+ def get_workspace():
140
+ return te_cublas_get_workspace_per_device(torch.cuda.current_device())
141
+
142
+ import transformer_engine.pytorch.module.linear as telinear
143
+ telinear.get_workspace = get_workspace
144
+ _TE_WORKSPACE_FIXUP_APPLIED = True
145
+
146
+ def set_format_recipe():
147
+ fp8_format = Format.HYBRID
148
+ fp8_recipe = DelayedScaling(fp8_format=fp8_format, amax_history_len=16, amax_compute_algo="max")
149
+ return fp8_format, fp8_recipe
150
+
151
+ class TELinear(_TELinearBase):
152
+ """Wrapper for Transformer-Engine's Linear, matching vortex's signature.
153
+
154
+ Returns (out, None) so callers can grab_first_if_tuple, matching vortex.
155
+ """
156
+
157
+ def __init__(
158
+ self,
159
+ input_size: int,
160
+ output_size: int,
161
+ init_method: Callable | None = None,
162
+ bias: bool = True,
163
+ skip_bias_add: bool = False,
164
+ use_fp8: bool = False,
165
+ **kwargs,
166
+ ):
167
+ params_dtype = torch.bfloat16
168
+ self.te_return_bias = skip_bias_add and bias
169
+ self.use_fp8_input_projections = use_fp8
170
+ if use_fp8:
171
+ self.fp8_format, self.fp8_recipe = set_format_recipe()
172
+
173
+ super().__init__(
174
+ in_features=input_size,
175
+ out_features=output_size,
176
+ sequence_parallel=False,
177
+ fuse_wgrad_accumulation=False,
178
+ tp_group=None,
179
+ tp_size=1,
180
+ init_method=init_method,
181
+ params_dtype=params_dtype,
182
+ parallel_mode=None,
183
+ bias=bias,
184
+ return_bias=self.te_return_bias,
185
+ **kwargs,
186
+ )
187
+
188
+ def forward(self, x):
189
+ if self.use_fp8_input_projections:
190
+ with te.fp8_autocast(enabled=True, fp8_recipe=self.fp8_recipe):
191
+ out = super().forward(x)
192
+ else:
193
+ out = super().forward(x)
194
+
195
+ if self.te_return_bias:
196
+ return out
197
+ return out, None
198
+
199
+ else:
200
+
201
+ def fixup_te_workspace():
202
+ """No-op when TransformerEngine is not installed."""
203
+ return
204
+
205
+ class TELinear(nn.Module):
206
+ """Pure-PyTorch fallback for TELinear (no FP8). Used by 7B variants
207
+ when TransformerEngine isn't installed.
208
+
209
+ Parameters are registered with names that match TE's state_dict layout
210
+ (`weight`, `bias`), so checkpoints saved from either path are
211
+ cross-loadable.
212
+ """
213
+
214
+ def __init__(
215
+ self,
216
+ input_size: int,
217
+ output_size: int,
218
+ init_method: Callable | None = None,
219
+ bias: bool = True,
220
+ skip_bias_add: bool = False,
221
+ use_fp8: bool = False,
222
+ **kwargs,
223
+ ):
224
+ super().__init__()
225
+ if use_fp8:
226
+ raise RuntimeError(
227
+ "FP8 requires Transformer Engine, which is not installed. "
228
+ "Install it with: pip install transformer_engine>=2.3.0"
229
+ )
230
+
231
+ self.te_return_bias = skip_bias_add and bias
232
+ self.use_fp8_input_projections = False
233
+ self.in_features = input_size
234
+ self.out_features = output_size
235
+ self.has_bias = bias
236
+
237
+ self.weight = nn.Parameter(torch.empty(output_size, input_size, dtype=torch.bfloat16))
238
+ if bias:
239
+ self.bias = nn.Parameter(torch.zeros(output_size, dtype=torch.bfloat16))
240
+ else:
241
+ self.register_parameter("bias", None)
242
+
243
+ if init_method is not None:
244
+ init_method(self.weight)
245
+ else:
246
+ nn.init.xavier_uniform_(self.weight)
247
+
248
+ def forward(self, x):
249
+ out = F.linear(x.to(self.weight.dtype), self.weight, self.bias)
250
+ if self.te_return_bias:
251
+ return out, self.bias
252
+ return out, None
model-00001-of-00003.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:732928a54e2e83dd48d6c6fa7ec5e9b16818fd077e3b0cdeadd9f8a3032cfe62
3
+ size 4998468704
model-00002-of-00003.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b4f8f67c709bc5138ecf266b7432c5e003368b1b6aad26b74af779a3b04d028
3
+ size 4950590512
model-00003-of-00003.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efb510480a47f798189d03d15fb86f2dbce53f07eb394c2dbe004a7cbcbb78fe
3
+ size 3015458472
model.safetensors.index.json ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "metadata": {
3
+ "total_parameters": 6481059584,
4
+ "total_size": 12964479104
5
+ },
6
+ "weight_map": {
7
+ "backbone.blocks.0.filter.h": "model-00001-of-00003.safetensors",
8
+ "backbone.blocks.0.filter.short_filter_weight": "model-00001-of-00003.safetensors",
9
+ "backbone.blocks.0.mlp.l1.weight": "model-00001-of-00003.safetensors",
10
+ "backbone.blocks.0.mlp.l2.weight": "model-00001-of-00003.safetensors",
11
+ "backbone.blocks.0.mlp.l3.weight": "model-00001-of-00003.safetensors",
12
+ "backbone.blocks.0.out_filter_dense.bias": "model-00001-of-00003.safetensors",
13
+ "backbone.blocks.0.out_filter_dense.weight": "model-00001-of-00003.safetensors",
14
+ "backbone.blocks.0.post_norm.scale": "model-00001-of-00003.safetensors",
15
+ "backbone.blocks.0.pre_norm.scale": "model-00001-of-00003.safetensors",
16
+ "backbone.blocks.0.projections.weight": "model-00001-of-00003.safetensors",
17
+ "backbone.blocks.1.filter.D": "model-00001-of-00003.safetensors",
18
+ "backbone.blocks.1.filter.h": "model-00001-of-00003.safetensors",
19
+ "backbone.blocks.1.filter.short_filter_weight": "model-00001-of-00003.safetensors",
20
+ "backbone.blocks.1.mlp.l1.weight": "model-00001-of-00003.safetensors",
21
+ "backbone.blocks.1.mlp.l2.weight": "model-00001-of-00003.safetensors",
22
+ "backbone.blocks.1.mlp.l3.weight": "model-00001-of-00003.safetensors",
23
+ "backbone.blocks.1.out_filter_dense.bias": "model-00001-of-00003.safetensors",
24
+ "backbone.blocks.1.out_filter_dense.weight": "model-00001-of-00003.safetensors",
25
+ "backbone.blocks.1.post_norm.scale": "model-00001-of-00003.safetensors",
26
+ "backbone.blocks.1.pre_norm.scale": "model-00001-of-00003.safetensors",
27
+ "backbone.blocks.1.projections.weight": "model-00001-of-00003.safetensors",
28
+ "backbone.blocks.10.inner_mha_cls.Wqkv.weight": "model-00001-of-00003.safetensors",
29
+ "backbone.blocks.10.inner_mha_cls.out_proj.bias": "model-00001-of-00003.safetensors",
30
+ "backbone.blocks.10.inner_mha_cls.out_proj.weight": "model-00001-of-00003.safetensors",
31
+ "backbone.blocks.10.inner_mha_cls.rotary_emb.inv_freq": "model-00001-of-00003.safetensors",
32
+ "backbone.blocks.10.mlp.l1.weight": "model-00001-of-00003.safetensors",
33
+ "backbone.blocks.10.mlp.l2.weight": "model-00001-of-00003.safetensors",
34
+ "backbone.blocks.10.mlp.l3.weight": "model-00001-of-00003.safetensors",
35
+ "backbone.blocks.10.post_norm.scale": "model-00001-of-00003.safetensors",
36
+ "backbone.blocks.10.pre_norm.scale": "model-00001-of-00003.safetensors",
37
+ "backbone.blocks.11.filter.h": "model-00001-of-00003.safetensors",
38
+ "backbone.blocks.11.filter.short_filter_weight": "model-00001-of-00003.safetensors",
39
+ "backbone.blocks.11.mlp.l1.weight": "model-00001-of-00003.safetensors",
40
+ "backbone.blocks.11.mlp.l2.weight": "model-00001-of-00003.safetensors",
41
+ "backbone.blocks.11.mlp.l3.weight": "model-00001-of-00003.safetensors",
42
+ "backbone.blocks.11.out_filter_dense.bias": "model-00001-of-00003.safetensors",
43
+ "backbone.blocks.11.out_filter_dense.weight": "model-00001-of-00003.safetensors",
44
+ "backbone.blocks.11.post_norm.scale": "model-00001-of-00003.safetensors",
45
+ "backbone.blocks.11.pre_norm.scale": "model-00001-of-00003.safetensors",
46
+ "backbone.blocks.11.projections.weight": "model-00001-of-00003.safetensors",
47
+ "backbone.blocks.12.filter.D": "model-00001-of-00003.safetensors",
48
+ "backbone.blocks.12.filter.h": "model-00001-of-00003.safetensors",
49
+ "backbone.blocks.12.filter.short_filter_weight": "model-00001-of-00003.safetensors",
50
+ "backbone.blocks.12.mlp.l1.weight": "model-00002-of-00003.safetensors",
51
+ "backbone.blocks.12.mlp.l2.weight": "model-00002-of-00003.safetensors",
52
+ "backbone.blocks.12.mlp.l3.weight": "model-00002-of-00003.safetensors",
53
+ "backbone.blocks.12.out_filter_dense.bias": "model-00001-of-00003.safetensors",
54
+ "backbone.blocks.12.out_filter_dense.weight": "model-00001-of-00003.safetensors",
55
+ "backbone.blocks.12.post_norm.scale": "model-00001-of-00003.safetensors",
56
+ "backbone.blocks.12.pre_norm.scale": "model-00001-of-00003.safetensors",
57
+ "backbone.blocks.12.projections.weight": "model-00001-of-00003.safetensors",
58
+ "backbone.blocks.13.filter.D": "model-00002-of-00003.safetensors",
59
+ "backbone.blocks.13.filter.log_poles": "model-00002-of-00003.safetensors",
60
+ "backbone.blocks.13.filter.residues": "model-00002-of-00003.safetensors",
61
+ "backbone.blocks.13.filter.short_filter_weight": "model-00002-of-00003.safetensors",
62
+ "backbone.blocks.13.mlp.l1.weight": "model-00002-of-00003.safetensors",
63
+ "backbone.blocks.13.mlp.l2.weight": "model-00002-of-00003.safetensors",
64
+ "backbone.blocks.13.mlp.l3.weight": "model-00002-of-00003.safetensors",
65
+ "backbone.blocks.13.out_filter_dense.bias": "model-00002-of-00003.safetensors",
66
+ "backbone.blocks.13.out_filter_dense.weight": "model-00002-of-00003.safetensors",
67
+ "backbone.blocks.13.post_norm.scale": "model-00002-of-00003.safetensors",
68
+ "backbone.blocks.13.pre_norm.scale": "model-00002-of-00003.safetensors",
69
+ "backbone.blocks.13.projections.weight": "model-00002-of-00003.safetensors",
70
+ "backbone.blocks.14.filter.h": "model-00002-of-00003.safetensors",
71
+ "backbone.blocks.14.filter.short_filter_weight": "model-00002-of-00003.safetensors",
72
+ "backbone.blocks.14.mlp.l1.weight": "model-00002-of-00003.safetensors",
73
+ "backbone.blocks.14.mlp.l2.weight": "model-00002-of-00003.safetensors",
74
+ "backbone.blocks.14.mlp.l3.weight": "model-00002-of-00003.safetensors",
75
+ "backbone.blocks.14.out_filter_dense.bias": "model-00002-of-00003.safetensors",
76
+ "backbone.blocks.14.out_filter_dense.weight": "model-00002-of-00003.safetensors",
77
+ "backbone.blocks.14.post_norm.scale": "model-00002-of-00003.safetensors",
78
+ "backbone.blocks.14.pre_norm.scale": "model-00002-of-00003.safetensors",
79
+ "backbone.blocks.14.projections.weight": "model-00002-of-00003.safetensors",
80
+ "backbone.blocks.15.filter.D": "model-00002-of-00003.safetensors",
81
+ "backbone.blocks.15.filter.h": "model-00002-of-00003.safetensors",
82
+ "backbone.blocks.15.filter.short_filter_weight": "model-00002-of-00003.safetensors",
83
+ "backbone.blocks.15.mlp.l1.weight": "model-00002-of-00003.safetensors",
84
+ "backbone.blocks.15.mlp.l2.weight": "model-00002-of-00003.safetensors",
85
+ "backbone.blocks.15.mlp.l3.weight": "model-00002-of-00003.safetensors",
86
+ "backbone.blocks.15.out_filter_dense.bias": "model-00002-of-00003.safetensors",
87
+ "backbone.blocks.15.out_filter_dense.weight": "model-00002-of-00003.safetensors",
88
+ "backbone.blocks.15.post_norm.scale": "model-00002-of-00003.safetensors",
89
+ "backbone.blocks.15.pre_norm.scale": "model-00002-of-00003.safetensors",
90
+ "backbone.blocks.15.projections.weight": "model-00002-of-00003.safetensors",
91
+ "backbone.blocks.16.filter.D": "model-00002-of-00003.safetensors",
92
+ "backbone.blocks.16.filter.log_poles": "model-00002-of-00003.safetensors",
93
+ "backbone.blocks.16.filter.residues": "model-00002-of-00003.safetensors",
94
+ "backbone.blocks.16.filter.short_filter_weight": "model-00002-of-00003.safetensors",
95
+ "backbone.blocks.16.mlp.l1.weight": "model-00002-of-00003.safetensors",
96
+ "backbone.blocks.16.mlp.l2.weight": "model-00002-of-00003.safetensors",
97
+ "backbone.blocks.16.mlp.l3.weight": "model-00002-of-00003.safetensors",
98
+ "backbone.blocks.16.out_filter_dense.bias": "model-00002-of-00003.safetensors",
99
+ "backbone.blocks.16.out_filter_dense.weight": "model-00002-of-00003.safetensors",
100
+ "backbone.blocks.16.post_norm.scale": "model-00002-of-00003.safetensors",
101
+ "backbone.blocks.16.pre_norm.scale": "model-00002-of-00003.safetensors",
102
+ "backbone.blocks.16.projections.weight": "model-00002-of-00003.safetensors",
103
+ "backbone.blocks.17.inner_mha_cls.Wqkv.weight": "model-00002-of-00003.safetensors",
104
+ "backbone.blocks.17.inner_mha_cls.out_proj.bias": "model-00002-of-00003.safetensors",
105
+ "backbone.blocks.17.inner_mha_cls.out_proj.weight": "model-00002-of-00003.safetensors",
106
+ "backbone.blocks.17.inner_mha_cls.rotary_emb.inv_freq": "model-00002-of-00003.safetensors",
107
+ "backbone.blocks.17.mlp.l1.weight": "model-00002-of-00003.safetensors",
108
+ "backbone.blocks.17.mlp.l2.weight": "model-00002-of-00003.safetensors",
109
+ "backbone.blocks.17.mlp.l3.weight": "model-00002-of-00003.safetensors",
110
+ "backbone.blocks.17.post_norm.scale": "model-00002-of-00003.safetensors",
111
+ "backbone.blocks.17.pre_norm.scale": "model-00002-of-00003.safetensors",
112
+ "backbone.blocks.18.filter.h": "model-00002-of-00003.safetensors",
113
+ "backbone.blocks.18.filter.short_filter_weight": "model-00002-of-00003.safetensors",
114
+ "backbone.blocks.18.mlp.l1.weight": "model-00002-of-00003.safetensors",
115
+ "backbone.blocks.18.mlp.l2.weight": "model-00002-of-00003.safetensors",
116
+ "backbone.blocks.18.mlp.l3.weight": "model-00002-of-00003.safetensors",
117
+ "backbone.blocks.18.out_filter_dense.bias": "model-00002-of-00003.safetensors",
118
+ "backbone.blocks.18.out_filter_dense.weight": "model-00002-of-00003.safetensors",
119
+ "backbone.blocks.18.post_norm.scale": "model-00002-of-00003.safetensors",
120
+ "backbone.blocks.18.pre_norm.scale": "model-00002-of-00003.safetensors",
121
+ "backbone.blocks.18.projections.weight": "model-00002-of-00003.safetensors",
122
+ "backbone.blocks.19.filter.D": "model-00002-of-00003.safetensors",
123
+ "backbone.blocks.19.filter.h": "model-00002-of-00003.safetensors",
124
+ "backbone.blocks.19.filter.short_filter_weight": "model-00002-of-00003.safetensors",
125
+ "backbone.blocks.19.mlp.l1.weight": "model-00002-of-00003.safetensors",
126
+ "backbone.blocks.19.mlp.l2.weight": "model-00002-of-00003.safetensors",
127
+ "backbone.blocks.19.mlp.l3.weight": "model-00002-of-00003.safetensors",
128
+ "backbone.blocks.19.out_filter_dense.bias": "model-00002-of-00003.safetensors",
129
+ "backbone.blocks.19.out_filter_dense.weight": "model-00002-of-00003.safetensors",
130
+ "backbone.blocks.19.post_norm.scale": "model-00002-of-00003.safetensors",
131
+ "backbone.blocks.19.pre_norm.scale": "model-00002-of-00003.safetensors",
132
+ "backbone.blocks.19.projections.weight": "model-00002-of-00003.safetensors",
133
+ "backbone.blocks.2.filter.D": "model-00001-of-00003.safetensors",
134
+ "backbone.blocks.2.filter.log_poles": "model-00001-of-00003.safetensors",
135
+ "backbone.blocks.2.filter.residues": "model-00001-of-00003.safetensors",
136
+ "backbone.blocks.2.filter.short_filter_weight": "model-00001-of-00003.safetensors",
137
+ "backbone.blocks.2.mlp.l1.weight": "model-00001-of-00003.safetensors",
138
+ "backbone.blocks.2.mlp.l2.weight": "model-00001-of-00003.safetensors",
139
+ "backbone.blocks.2.mlp.l3.weight": "model-00001-of-00003.safetensors",
140
+ "backbone.blocks.2.out_filter_dense.bias": "model-00001-of-00003.safetensors",
141
+ "backbone.blocks.2.out_filter_dense.weight": "model-00001-of-00003.safetensors",
142
+ "backbone.blocks.2.post_norm.scale": "model-00001-of-00003.safetensors",
143
+ "backbone.blocks.2.pre_norm.scale": "model-00001-of-00003.safetensors",
144
+ "backbone.blocks.2.projections.weight": "model-00001-of-00003.safetensors",
145
+ "backbone.blocks.20.filter.D": "model-00002-of-00003.safetensors",
146
+ "backbone.blocks.20.filter.log_poles": "model-00002-of-00003.safetensors",
147
+ "backbone.blocks.20.filter.residues": "model-00002-of-00003.safetensors",
148
+ "backbone.blocks.20.filter.short_filter_weight": "model-00002-of-00003.safetensors",
149
+ "backbone.blocks.20.mlp.l1.weight": "model-00002-of-00003.safetensors",
150
+ "backbone.blocks.20.mlp.l2.weight": "model-00002-of-00003.safetensors",
151
+ "backbone.blocks.20.mlp.l3.weight": "model-00002-of-00003.safetensors",
152
+ "backbone.blocks.20.out_filter_dense.bias": "model-00002-of-00003.safetensors",
153
+ "backbone.blocks.20.out_filter_dense.weight": "model-00002-of-00003.safetensors",
154
+ "backbone.blocks.20.post_norm.scale": "model-00002-of-00003.safetensors",
155
+ "backbone.blocks.20.pre_norm.scale": "model-00002-of-00003.safetensors",
156
+ "backbone.blocks.20.projections.weight": "model-00002-of-00003.safetensors",
157
+ "backbone.blocks.21.filter.h": "model-00002-of-00003.safetensors",
158
+ "backbone.blocks.21.filter.short_filter_weight": "model-00002-of-00003.safetensors",
159
+ "backbone.blocks.21.mlp.l1.weight": "model-00002-of-00003.safetensors",
160
+ "backbone.blocks.21.mlp.l2.weight": "model-00002-of-00003.safetensors",
161
+ "backbone.blocks.21.mlp.l3.weight": "model-00002-of-00003.safetensors",
162
+ "backbone.blocks.21.out_filter_dense.bias": "model-00002-of-00003.safetensors",
163
+ "backbone.blocks.21.out_filter_dense.weight": "model-00002-of-00003.safetensors",
164
+ "backbone.blocks.21.post_norm.scale": "model-00002-of-00003.safetensors",
165
+ "backbone.blocks.21.pre_norm.scale": "model-00002-of-00003.safetensors",
166
+ "backbone.blocks.21.projections.weight": "model-00002-of-00003.safetensors",
167
+ "backbone.blocks.22.filter.D": "model-00002-of-00003.safetensors",
168
+ "backbone.blocks.22.filter.h": "model-00002-of-00003.safetensors",
169
+ "backbone.blocks.22.filter.short_filter_weight": "model-00002-of-00003.safetensors",
170
+ "backbone.blocks.22.mlp.l1.weight": "model-00002-of-00003.safetensors",
171
+ "backbone.blocks.22.mlp.l2.weight": "model-00002-of-00003.safetensors",
172
+ "backbone.blocks.22.mlp.l3.weight": "model-00002-of-00003.safetensors",
173
+ "backbone.blocks.22.out_filter_dense.bias": "model-00002-of-00003.safetensors",
174
+ "backbone.blocks.22.out_filter_dense.weight": "model-00002-of-00003.safetensors",
175
+ "backbone.blocks.22.post_norm.scale": "model-00002-of-00003.safetensors",
176
+ "backbone.blocks.22.pre_norm.scale": "model-00002-of-00003.safetensors",
177
+ "backbone.blocks.22.projections.weight": "model-00002-of-00003.safetensors",
178
+ "backbone.blocks.23.filter.D": "model-00002-of-00003.safetensors",
179
+ "backbone.blocks.23.filter.log_poles": "model-00002-of-00003.safetensors",
180
+ "backbone.blocks.23.filter.residues": "model-00002-of-00003.safetensors",
181
+ "backbone.blocks.23.filter.short_filter_weight": "model-00002-of-00003.safetensors",
182
+ "backbone.blocks.23.mlp.l1.weight": "model-00002-of-00003.safetensors",
183
+ "backbone.blocks.23.mlp.l2.weight": "model-00002-of-00003.safetensors",
184
+ "backbone.blocks.23.mlp.l3.weight": "model-00002-of-00003.safetensors",
185
+ "backbone.blocks.23.out_filter_dense.bias": "model-00002-of-00003.safetensors",
186
+ "backbone.blocks.23.out_filter_dense.weight": "model-00002-of-00003.safetensors",
187
+ "backbone.blocks.23.post_norm.scale": "model-00002-of-00003.safetensors",
188
+ "backbone.blocks.23.pre_norm.scale": "model-00002-of-00003.safetensors",
189
+ "backbone.blocks.23.projections.weight": "model-00002-of-00003.safetensors",
190
+ "backbone.blocks.24.inner_mha_cls.Wqkv.weight": "model-00002-of-00003.safetensors",
191
+ "backbone.blocks.24.inner_mha_cls.out_proj.bias": "model-00002-of-00003.safetensors",
192
+ "backbone.blocks.24.inner_mha_cls.out_proj.weight": "model-00002-of-00003.safetensors",
193
+ "backbone.blocks.24.inner_mha_cls.rotary_emb.inv_freq": "model-00002-of-00003.safetensors",
194
+ "backbone.blocks.24.mlp.l1.weight": "model-00002-of-00003.safetensors",
195
+ "backbone.blocks.24.mlp.l2.weight": "model-00003-of-00003.safetensors",
196
+ "backbone.blocks.24.mlp.l3.weight": "model-00003-of-00003.safetensors",
197
+ "backbone.blocks.24.post_norm.scale": "model-00002-of-00003.safetensors",
198
+ "backbone.blocks.24.pre_norm.scale": "model-00002-of-00003.safetensors",
199
+ "backbone.blocks.25.filter.h": "model-00003-of-00003.safetensors",
200
+ "backbone.blocks.25.filter.short_filter_weight": "model-00003-of-00003.safetensors",
201
+ "backbone.blocks.25.mlp.l1.weight": "model-00003-of-00003.safetensors",
202
+ "backbone.blocks.25.mlp.l2.weight": "model-00003-of-00003.safetensors",
203
+ "backbone.blocks.25.mlp.l3.weight": "model-00003-of-00003.safetensors",
204
+ "backbone.blocks.25.out_filter_dense.bias": "model-00003-of-00003.safetensors",
205
+ "backbone.blocks.25.out_filter_dense.weight": "model-00003-of-00003.safetensors",
206
+ "backbone.blocks.25.post_norm.scale": "model-00003-of-00003.safetensors",
207
+ "backbone.blocks.25.pre_norm.scale": "model-00003-of-00003.safetensors",
208
+ "backbone.blocks.25.projections.weight": "model-00003-of-00003.safetensors",
209
+ "backbone.blocks.26.filter.D": "model-00003-of-00003.safetensors",
210
+ "backbone.blocks.26.filter.h": "model-00003-of-00003.safetensors",
211
+ "backbone.blocks.26.filter.short_filter_weight": "model-00003-of-00003.safetensors",
212
+ "backbone.blocks.26.mlp.l1.weight": "model-00003-of-00003.safetensors",
213
+ "backbone.blocks.26.mlp.l2.weight": "model-00003-of-00003.safetensors",
214
+ "backbone.blocks.26.mlp.l3.weight": "model-00003-of-00003.safetensors",
215
+ "backbone.blocks.26.out_filter_dense.bias": "model-00003-of-00003.safetensors",
216
+ "backbone.blocks.26.out_filter_dense.weight": "model-00003-of-00003.safetensors",
217
+ "backbone.blocks.26.post_norm.scale": "model-00003-of-00003.safetensors",
218
+ "backbone.blocks.26.pre_norm.scale": "model-00003-of-00003.safetensors",
219
+ "backbone.blocks.26.projections.weight": "model-00003-of-00003.safetensors",
220
+ "backbone.blocks.27.filter.D": "model-00003-of-00003.safetensors",
221
+ "backbone.blocks.27.filter.log_poles": "model-00003-of-00003.safetensors",
222
+ "backbone.blocks.27.filter.residues": "model-00003-of-00003.safetensors",
223
+ "backbone.blocks.27.filter.short_filter_weight": "model-00003-of-00003.safetensors",
224
+ "backbone.blocks.27.mlp.l1.weight": "model-00003-of-00003.safetensors",
225
+ "backbone.blocks.27.mlp.l2.weight": "model-00003-of-00003.safetensors",
226
+ "backbone.blocks.27.mlp.l3.weight": "model-00003-of-00003.safetensors",
227
+ "backbone.blocks.27.out_filter_dense.bias": "model-00003-of-00003.safetensors",
228
+ "backbone.blocks.27.out_filter_dense.weight": "model-00003-of-00003.safetensors",
229
+ "backbone.blocks.27.post_norm.scale": "model-00003-of-00003.safetensors",
230
+ "backbone.blocks.27.pre_norm.scale": "model-00003-of-00003.safetensors",
231
+ "backbone.blocks.27.projections.weight": "model-00003-of-00003.safetensors",
232
+ "backbone.blocks.28.filter.h": "model-00003-of-00003.safetensors",
233
+ "backbone.blocks.28.filter.short_filter_weight": "model-00003-of-00003.safetensors",
234
+ "backbone.blocks.28.mlp.l1.weight": "model-00003-of-00003.safetensors",
235
+ "backbone.blocks.28.mlp.l2.weight": "model-00003-of-00003.safetensors",
236
+ "backbone.blocks.28.mlp.l3.weight": "model-00003-of-00003.safetensors",
237
+ "backbone.blocks.28.out_filter_dense.bias": "model-00003-of-00003.safetensors",
238
+ "backbone.blocks.28.out_filter_dense.weight": "model-00003-of-00003.safetensors",
239
+ "backbone.blocks.28.post_norm.scale": "model-00003-of-00003.safetensors",
240
+ "backbone.blocks.28.pre_norm.scale": "model-00003-of-00003.safetensors",
241
+ "backbone.blocks.28.projections.weight": "model-00003-of-00003.safetensors",
242
+ "backbone.blocks.29.filter.D": "model-00003-of-00003.safetensors",
243
+ "backbone.blocks.29.filter.h": "model-00003-of-00003.safetensors",
244
+ "backbone.blocks.29.filter.short_filter_weight": "model-00003-of-00003.safetensors",
245
+ "backbone.blocks.29.mlp.l1.weight": "model-00003-of-00003.safetensors",
246
+ "backbone.blocks.29.mlp.l2.weight": "model-00003-of-00003.safetensors",
247
+ "backbone.blocks.29.mlp.l3.weight": "model-00003-of-00003.safetensors",
248
+ "backbone.blocks.29.out_filter_dense.bias": "model-00003-of-00003.safetensors",
249
+ "backbone.blocks.29.out_filter_dense.weight": "model-00003-of-00003.safetensors",
250
+ "backbone.blocks.29.post_norm.scale": "model-00003-of-00003.safetensors",
251
+ "backbone.blocks.29.pre_norm.scale": "model-00003-of-00003.safetensors",
252
+ "backbone.blocks.29.projections.weight": "model-00003-of-00003.safetensors",
253
+ "backbone.blocks.3.inner_mha_cls.Wqkv.weight": "model-00001-of-00003.safetensors",
254
+ "backbone.blocks.3.inner_mha_cls.out_proj.bias": "model-00001-of-00003.safetensors",
255
+ "backbone.blocks.3.inner_mha_cls.out_proj.weight": "model-00001-of-00003.safetensors",
256
+ "backbone.blocks.3.inner_mha_cls.rotary_emb.inv_freq": "model-00001-of-00003.safetensors",
257
+ "backbone.blocks.3.mlp.l1.weight": "model-00001-of-00003.safetensors",
258
+ "backbone.blocks.3.mlp.l2.weight": "model-00001-of-00003.safetensors",
259
+ "backbone.blocks.3.mlp.l3.weight": "model-00001-of-00003.safetensors",
260
+ "backbone.blocks.3.post_norm.scale": "model-00001-of-00003.safetensors",
261
+ "backbone.blocks.3.pre_norm.scale": "model-00001-of-00003.safetensors",
262
+ "backbone.blocks.30.filter.D": "model-00003-of-00003.safetensors",
263
+ "backbone.blocks.30.filter.log_poles": "model-00003-of-00003.safetensors",
264
+ "backbone.blocks.30.filter.residues": "model-00003-of-00003.safetensors",
265
+ "backbone.blocks.30.filter.short_filter_weight": "model-00003-of-00003.safetensors",
266
+ "backbone.blocks.30.mlp.l1.weight": "model-00003-of-00003.safetensors",
267
+ "backbone.blocks.30.mlp.l2.weight": "model-00003-of-00003.safetensors",
268
+ "backbone.blocks.30.mlp.l3.weight": "model-00003-of-00003.safetensors",
269
+ "backbone.blocks.30.out_filter_dense.bias": "model-00003-of-00003.safetensors",
270
+ "backbone.blocks.30.out_filter_dense.weight": "model-00003-of-00003.safetensors",
271
+ "backbone.blocks.30.post_norm.scale": "model-00003-of-00003.safetensors",
272
+ "backbone.blocks.30.pre_norm.scale": "model-00003-of-00003.safetensors",
273
+ "backbone.blocks.30.projections.weight": "model-00003-of-00003.safetensors",
274
+ "backbone.blocks.31.inner_mha_cls.Wqkv.weight": "model-00003-of-00003.safetensors",
275
+ "backbone.blocks.31.inner_mha_cls.out_proj.bias": "model-00003-of-00003.safetensors",
276
+ "backbone.blocks.31.inner_mha_cls.out_proj.weight": "model-00003-of-00003.safetensors",
277
+ "backbone.blocks.31.inner_mha_cls.rotary_emb.inv_freq": "model-00003-of-00003.safetensors",
278
+ "backbone.blocks.31.mlp.l1.weight": "model-00003-of-00003.safetensors",
279
+ "backbone.blocks.31.mlp.l2.weight": "model-00003-of-00003.safetensors",
280
+ "backbone.blocks.31.mlp.l3.weight": "model-00003-of-00003.safetensors",
281
+ "backbone.blocks.31.post_norm.scale": "model-00003-of-00003.safetensors",
282
+ "backbone.blocks.31.pre_norm.scale": "model-00003-of-00003.safetensors",
283
+ "backbone.blocks.4.filter.h": "model-00001-of-00003.safetensors",
284
+ "backbone.blocks.4.filter.short_filter_weight": "model-00001-of-00003.safetensors",
285
+ "backbone.blocks.4.mlp.l1.weight": "model-00001-of-00003.safetensors",
286
+ "backbone.blocks.4.mlp.l2.weight": "model-00001-of-00003.safetensors",
287
+ "backbone.blocks.4.mlp.l3.weight": "model-00001-of-00003.safetensors",
288
+ "backbone.blocks.4.out_filter_dense.bias": "model-00001-of-00003.safetensors",
289
+ "backbone.blocks.4.out_filter_dense.weight": "model-00001-of-00003.safetensors",
290
+ "backbone.blocks.4.post_norm.scale": "model-00001-of-00003.safetensors",
291
+ "backbone.blocks.4.pre_norm.scale": "model-00001-of-00003.safetensors",
292
+ "backbone.blocks.4.projections.weight": "model-00001-of-00003.safetensors",
293
+ "backbone.blocks.5.filter.D": "model-00001-of-00003.safetensors",
294
+ "backbone.blocks.5.filter.h": "model-00001-of-00003.safetensors",
295
+ "backbone.blocks.5.filter.short_filter_weight": "model-00001-of-00003.safetensors",
296
+ "backbone.blocks.5.mlp.l1.weight": "model-00001-of-00003.safetensors",
297
+ "backbone.blocks.5.mlp.l2.weight": "model-00001-of-00003.safetensors",
298
+ "backbone.blocks.5.mlp.l3.weight": "model-00001-of-00003.safetensors",
299
+ "backbone.blocks.5.out_filter_dense.bias": "model-00001-of-00003.safetensors",
300
+ "backbone.blocks.5.out_filter_dense.weight": "model-00001-of-00003.safetensors",
301
+ "backbone.blocks.5.post_norm.scale": "model-00001-of-00003.safetensors",
302
+ "backbone.blocks.5.pre_norm.scale": "model-00001-of-00003.safetensors",
303
+ "backbone.blocks.5.projections.weight": "model-00001-of-00003.safetensors",
304
+ "backbone.blocks.6.filter.D": "model-00001-of-00003.safetensors",
305
+ "backbone.blocks.6.filter.log_poles": "model-00001-of-00003.safetensors",
306
+ "backbone.blocks.6.filter.residues": "model-00001-of-00003.safetensors",
307
+ "backbone.blocks.6.filter.short_filter_weight": "model-00001-of-00003.safetensors",
308
+ "backbone.blocks.6.mlp.l1.weight": "model-00001-of-00003.safetensors",
309
+ "backbone.blocks.6.mlp.l2.weight": "model-00001-of-00003.safetensors",
310
+ "backbone.blocks.6.mlp.l3.weight": "model-00001-of-00003.safetensors",
311
+ "backbone.blocks.6.out_filter_dense.bias": "model-00001-of-00003.safetensors",
312
+ "backbone.blocks.6.out_filter_dense.weight": "model-00001-of-00003.safetensors",
313
+ "backbone.blocks.6.post_norm.scale": "model-00001-of-00003.safetensors",
314
+ "backbone.blocks.6.pre_norm.scale": "model-00001-of-00003.safetensors",
315
+ "backbone.blocks.6.projections.weight": "model-00001-of-00003.safetensors",
316
+ "backbone.blocks.7.filter.h": "model-00001-of-00003.safetensors",
317
+ "backbone.blocks.7.filter.short_filter_weight": "model-00001-of-00003.safetensors",
318
+ "backbone.blocks.7.mlp.l1.weight": "model-00001-of-00003.safetensors",
319
+ "backbone.blocks.7.mlp.l2.weight": "model-00001-of-00003.safetensors",
320
+ "backbone.blocks.7.mlp.l3.weight": "model-00001-of-00003.safetensors",
321
+ "backbone.blocks.7.out_filter_dense.bias": "model-00001-of-00003.safetensors",
322
+ "backbone.blocks.7.out_filter_dense.weight": "model-00001-of-00003.safetensors",
323
+ "backbone.blocks.7.post_norm.scale": "model-00001-of-00003.safetensors",
324
+ "backbone.blocks.7.pre_norm.scale": "model-00001-of-00003.safetensors",
325
+ "backbone.blocks.7.projections.weight": "model-00001-of-00003.safetensors",
326
+ "backbone.blocks.8.filter.D": "model-00001-of-00003.safetensors",
327
+ "backbone.blocks.8.filter.h": "model-00001-of-00003.safetensors",
328
+ "backbone.blocks.8.filter.short_filter_weight": "model-00001-of-00003.safetensors",
329
+ "backbone.blocks.8.mlp.l1.weight": "model-00001-of-00003.safetensors",
330
+ "backbone.blocks.8.mlp.l2.weight": "model-00001-of-00003.safetensors",
331
+ "backbone.blocks.8.mlp.l3.weight": "model-00001-of-00003.safetensors",
332
+ "backbone.blocks.8.out_filter_dense.bias": "model-00001-of-00003.safetensors",
333
+ "backbone.blocks.8.out_filter_dense.weight": "model-00001-of-00003.safetensors",
334
+ "backbone.blocks.8.post_norm.scale": "model-00001-of-00003.safetensors",
335
+ "backbone.blocks.8.pre_norm.scale": "model-00001-of-00003.safetensors",
336
+ "backbone.blocks.8.projections.weight": "model-00001-of-00003.safetensors",
337
+ "backbone.blocks.9.filter.D": "model-00001-of-00003.safetensors",
338
+ "backbone.blocks.9.filter.log_poles": "model-00001-of-00003.safetensors",
339
+ "backbone.blocks.9.filter.residues": "model-00001-of-00003.safetensors",
340
+ "backbone.blocks.9.filter.short_filter_weight": "model-00001-of-00003.safetensors",
341
+ "backbone.blocks.9.mlp.l1.weight": "model-00001-of-00003.safetensors",
342
+ "backbone.blocks.9.mlp.l2.weight": "model-00001-of-00003.safetensors",
343
+ "backbone.blocks.9.mlp.l3.weight": "model-00001-of-00003.safetensors",
344
+ "backbone.blocks.9.out_filter_dense.bias": "model-00001-of-00003.safetensors",
345
+ "backbone.blocks.9.out_filter_dense.weight": "model-00001-of-00003.safetensors",
346
+ "backbone.blocks.9.post_norm.scale": "model-00001-of-00003.safetensors",
347
+ "backbone.blocks.9.pre_norm.scale": "model-00001-of-00003.safetensors",
348
+ "backbone.blocks.9.projections.weight": "model-00001-of-00003.safetensors",
349
+ "backbone.embedding_layer.weight": "model-00001-of-00003.safetensors",
350
+ "backbone.norm.scale": "model-00003-of-00003.safetensors"
351
+ }
352
+ }
modeling_evo2.py ADDED
@@ -0,0 +1,425 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HuggingFace wrappers for Evo2 (StripedHyena2).
2
+
3
+ Two top-level model classes:
4
+
5
+ * Evo2Model -- bare backbone returning BaseModelOutputWithPast
6
+ (no LM head); the post-RMSNorm hidden state is the
7
+ last_hidden_state.
8
+ * Evo2ForCausalLM -- with the tied LM head + GenerationMixin so
9
+ model.generate() works out of the box.
10
+
11
+ Caching for autoregressive generation uses the custom Evo2Cache (see
12
+ cache.py): a dict-like container of four block-type-specific param objects
13
+ (mha, hcl, hcm, hcs) so all four StripedHyena2 block types can decode in
14
+ constant time per new token.
15
+
16
+ Per-block dtype: bfloat16 for everything except the modal-form filter
17
+ parameters (`log_poles`, `residues`) which must stay fp32 for stability.
18
+ This is enforced both at convert time (the safetensors store these as fp32)
19
+ and at runtime via `force_dtype()` (called from each model's __init__).
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from typing import Optional, Tuple, Union
25
+
26
+ import torch
27
+ import torch.nn as nn
28
+ import torch.nn.functional as F
29
+ from transformers import PreTrainedModel
30
+ from transformers.generation import GenerationMixin
31
+ from transformers.modeling_outputs import (
32
+ BaseModelOutputWithPast,
33
+ CausalLMOutputWithPast,
34
+ )
35
+ from transformers.utils import logging
36
+
37
+ from .cache import Evo2Cache
38
+ from .configuration_evo2 import Evo2Config
39
+ from .hyena import (
40
+ AttentionBlock,
41
+ ParallelGatedConvBlock,
42
+ block_type_for_idx,
43
+ get_block,
44
+ )
45
+ from .layers import RMSNorm, VocabParallelEmbedding
46
+ # Bundle the tokenizer file via trust_remote_code:
47
+ from .tokenization_evo2 import ByteTokenizer # noqa: F401
48
+ # Force HF's trust_remote_code loader to copy these transitive deps into its
49
+ # dynamic-module cache (it only walks top-level `from .X import Y` patterns
50
+ # of modeling_evo2.py, not `from . import X`, so we use the explicit form).
51
+ from .attention import MHA as _MHA # noqa: F401
52
+ from .engine import HyenaInferenceEngine as _HyenaInferenceEngine # noqa: F401
53
+ from .rotary import RotaryEmbedding as _RotaryEmbedding # noqa: F401
54
+
55
+ logger = logging.get_logger(__name__)
56
+
57
+
58
+ # =============================================================================
59
+ # Backbone
60
+ # =============================================================================
61
+
62
+
63
+ class StripedHyena2(nn.Module):
64
+ """Pure backbone: token embedding -> N blocks -> final RMSNorm."""
65
+
66
+ def __init__(self, config: Evo2Config):
67
+ super().__init__()
68
+ # Patch TE's cuBLAS workspace handling so multi-GPU device_map="auto"
69
+ # works (TE otherwise allocates a single workspace on the first device
70
+ # it sees, then fails on layers placed on other devices). No-op when
71
+ # TE isn't installed.
72
+ from .layers import fixup_te_workspace
73
+ fixup_te_workspace()
74
+
75
+ self.config = config
76
+ self.embedding_layer = VocabParallelEmbedding(config)
77
+ self.norm = RMSNorm(config) if config.get("final_norm", True) else None
78
+
79
+ if config.get("use_flashfft", False):
80
+ import importlib
81
+ FlashFFTConv = importlib.import_module("flashfftconv").FlashFFTConv
82
+ self.flash_fft = FlashFFTConv(2 * config.max_seqlen, dtype=torch.bfloat16)
83
+ else:
84
+ self.flash_fft = None
85
+
86
+ self.blocks = nn.ModuleList(
87
+ get_block(config, i) for i in range(config.num_layers)
88
+ )
89
+ # Wire fftconv_fn into the hcl filters when flashfft is on.
90
+ if self.flash_fft is not None:
91
+ for block in self.blocks:
92
+ if isinstance(block, ParallelGatedConvBlock) and block.filter.h is None:
93
+ block.filter.fftconv_fn = self.flash_fft
94
+
95
+ def forward(
96
+ self,
97
+ x: torch.Tensor,
98
+ inference_params_dict: Optional[Evo2Cache] = None,
99
+ padding_mask: Optional[torch.Tensor] = None,
100
+ output_hidden_states: bool = False,
101
+ output_attentions: bool = False,
102
+ ):
103
+ x = self.embedding_layer.embed(x)
104
+
105
+ all_hidden_states: list[torch.Tensor] = []
106
+ all_attentions: list[Optional[torch.Tensor]] = []
107
+ if output_hidden_states:
108
+ all_hidden_states.append(x)
109
+
110
+ if inference_params_dict is not None:
111
+ x, params_out = self._stateful_forward(
112
+ x, inference_params_dict,
113
+ all_hidden_states=all_hidden_states,
114
+ all_attentions=all_attentions,
115
+ output_hidden_states=output_hidden_states,
116
+ output_attentions=output_attentions,
117
+ )
118
+ else:
119
+ x, params_out = self._stateless_forward(
120
+ x, padding_mask=padding_mask,
121
+ all_hidden_states=all_hidden_states,
122
+ all_attentions=all_attentions,
123
+ output_hidden_states=output_hidden_states,
124
+ output_attentions=output_attentions,
125
+ )
126
+
127
+ if self.norm is not None:
128
+ x = self.norm(x)
129
+ if output_hidden_states:
130
+ all_hidden_states.append(x)
131
+
132
+ return x, params_out, all_hidden_states, all_attentions
133
+
134
+ def _stateful_forward(
135
+ self, x, cache: Evo2Cache,
136
+ all_hidden_states, all_attentions,
137
+ output_hidden_states, output_attentions,
138
+ ):
139
+ for block_idx, block in enumerate(self.blocks):
140
+ block_name = block_type_for_idx(self.config, block_idx)
141
+ inference_params = cache.by_block_name(block_name)
142
+ x, attn = block(
143
+ x, inference_params=inference_params,
144
+ output_attentions=output_attentions,
145
+ )
146
+ if output_hidden_states:
147
+ all_hidden_states.append(x)
148
+ if output_attentions:
149
+ all_attentions.append(attn)
150
+ return x, cache
151
+
152
+ def _stateless_forward(
153
+ self, x, padding_mask,
154
+ all_hidden_states, all_attentions,
155
+ output_hidden_states, output_attentions,
156
+ ):
157
+ if isinstance(padding_mask, torch.Tensor):
158
+ x = x * padding_mask[..., None]
159
+ for block in self.blocks:
160
+ x, attn = block(
161
+ x, inference_params=None, padding_mask=padding_mask,
162
+ output_attentions=output_attentions,
163
+ )
164
+ if output_hidden_states:
165
+ all_hidden_states.append(x)
166
+ if output_attentions:
167
+ all_attentions.append(attn)
168
+ return x, None
169
+
170
+ def initialize_inference_params(self, max_batch_size: int = 1) -> Evo2Cache:
171
+ return Evo2Cache(
172
+ max_seqlen=self.config.get("max_seqlen", 8192),
173
+ max_batch_size=max_batch_size,
174
+ short_filter_length=self.config.short_filter_length,
175
+ hcm_filter_length=self.config.hcm_filter_length,
176
+ hcs_filter_length=self.config.hcs_filter_length,
177
+ state_size=self.config.state_size,
178
+ )
179
+
180
+ def to_bfloat16_except_poles_residues(self):
181
+ """Cast params to bf16, restore fp32 invariants:
182
+
183
+ * log_poles / residues -- bf16 collapses the modal-form IIR (the
184
+ poles get rounded too aggressively, the recurrence blows up).
185
+ Mirrors vortex's ``to_bfloat16_except_pr_lc(to_float32=True)``
186
+ first-pass behaviour.
187
+
188
+ * rotary_emb.inv_freq -- HF ``from_pretrained(dtype=bf16)`` casts
189
+ ALL buffers to bf16. ``inv_freq = 1 / base^(2i/dim)`` loses ~7
190
+ bits of mantissa in bf16, which shifts cos/sin tables by ~5e-2
191
+ per cell at position 64+, causing each attention layer to add
192
+ ~4e-2 of noise on Q/K. We recompute inv_freq in fp32 here so
193
+ the cos/sin builder uses the precise stored value.
194
+ """
195
+ for k, p in self.named_parameters():
196
+ if "log_poles" in k or "residues" in k:
197
+ p.data = p.data.to(torch.float32)
198
+ else:
199
+ p.data = p.data.to(torch.bfloat16)
200
+ for module in self.modules():
201
+ if hasattr(module, "_compute_inv_freq") and hasattr(module, "inv_freq"):
202
+ fresh = module._compute_inv_freq(device=module.inv_freq.device)
203
+ module.inv_freq.data = fresh
204
+ # Invalidate any cached cos/sin so the next forward rebuilds
205
+ # them from the precise fp32 inv_freq.
206
+ module._seq_len_cached = 0
207
+ module._cos_cached = None
208
+ module._sin_cached = None
209
+
210
+
211
+ # =============================================================================
212
+ # HF wrappers
213
+ # =============================================================================
214
+
215
+
216
+ class Evo2PreTrainedModel(PreTrainedModel):
217
+ config_class = Evo2Config
218
+ base_model_prefix = "backbone"
219
+ supports_gradient_checkpointing = False
220
+ _no_split_modules = ["AttentionBlock", "ParallelGatedConvBlock"]
221
+ _skip_keys_device_placement = "past_key_values"
222
+ _keys_to_ignore_on_load_missing = [r"freq", r"\.t$"]
223
+ _keys_to_ignore_on_load_unexpected = [r"fftconv", r"twiddle_factors", r"_extra_state$"]
224
+ _supports_flash_attn_2 = True
225
+ _supports_sdpa = True
226
+ # Evo2 cache is a custom Evo2Cache (not a DynamicCache); tell HF not to wrap it.
227
+ _supports_cache_class = False
228
+ # log_poles / residues parameterize a modal long-range filter; bf16 collapses
229
+ # them. HF will keep these in fp32 even with dtype=bf16 at load time.
230
+ _keep_in_fp32_modules = ["log_poles", "residues"]
231
+
232
+ @classmethod
233
+ def from_pretrained(cls, *args, **kwargs):
234
+ if "dtype" not in kwargs and "torch_dtype" not in kwargs:
235
+ kwargs["dtype"] = torch.bfloat16
236
+ return super().from_pretrained(*args, **kwargs)
237
+
238
+
239
+ class Evo2Model(Evo2PreTrainedModel):
240
+ """Bare backbone returning BaseModelOutputWithPast."""
241
+
242
+ def __init__(self, config: Evo2Config):
243
+ super().__init__(config)
244
+ self.backbone = StripedHyena2(config)
245
+ self.config = config
246
+ self.post_init()
247
+ self.force_dtype()
248
+
249
+ def force_dtype(self):
250
+ self.backbone.to_bfloat16_except_poles_residues()
251
+
252
+ def get_input_embeddings(self):
253
+ return self.backbone.embedding_layer
254
+
255
+ def set_input_embeddings(self, value):
256
+ self.backbone.embedding_layer = value
257
+
258
+ def forward(
259
+ self,
260
+ input_ids: torch.LongTensor = None,
261
+ attention_mask: Optional[torch.LongTensor] = None,
262
+ past_key_values=None,
263
+ use_cache: Optional[bool] = None,
264
+ output_attentions: Optional[bool] = None,
265
+ output_hidden_states: Optional[bool] = None,
266
+ return_dict: Optional[bool] = None,
267
+ ) -> Union[Tuple, BaseModelOutputWithPast]:
268
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
269
+ output_attentions = (
270
+ output_attentions if output_attentions is not None else self.config.output_attentions
271
+ )
272
+ output_hidden_states = (
273
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
274
+ )
275
+ # Default to no caching for the bare backbone: caches have large
276
+ # per-layer memory cost with no benefit for embedding extraction.
277
+ use_cache = use_cache if use_cache is not None else False
278
+ if use_cache and self.training:
279
+ use_cache = False
280
+
281
+ inputs = input_ids
282
+ if use_cache and past_key_values is None:
283
+ past_key_values = self.backbone.initialize_inference_params(
284
+ max_batch_size=input_ids.shape[0]
285
+ )
286
+
287
+ last_hidden, past_kv, hidden_states, attentions = self.backbone(
288
+ inputs,
289
+ padding_mask=attention_mask,
290
+ inference_params_dict=past_key_values if use_cache else None,
291
+ output_hidden_states=output_hidden_states,
292
+ output_attentions=output_attentions,
293
+ )
294
+
295
+ if not return_dict:
296
+ outputs = (last_hidden,)
297
+ if use_cache: outputs += (past_kv,)
298
+ if output_hidden_states: outputs += (tuple(hidden_states),)
299
+ if output_attentions: outputs += (tuple(attentions),)
300
+ return outputs
301
+
302
+ return BaseModelOutputWithPast(
303
+ last_hidden_state=last_hidden,
304
+ past_key_values=past_kv if use_cache else None,
305
+ hidden_states=tuple(hidden_states) if output_hidden_states else None,
306
+ attentions=tuple(attentions) if output_attentions else None,
307
+ )
308
+
309
+
310
+ class Evo2ForCausalLM(Evo2PreTrainedModel, GenerationMixin):
311
+ """LM head wrapper. Tied to backbone.embedding_layer (Evo2 ties weights)."""
312
+
313
+ def __init__(self, config: Evo2Config, **kwargs):
314
+ super().__init__(config, **kwargs)
315
+ self.backbone = StripedHyena2(config)
316
+ self.config = config
317
+
318
+ vocab_size = config.vocab_size
319
+ if vocab_size % config.make_vocab_size_divisible_by != 0:
320
+ vocab_size += config.make_vocab_size_divisible_by - (
321
+ vocab_size % config.make_vocab_size_divisible_by
322
+ )
323
+ self.vocab_size = vocab_size
324
+ self.post_init()
325
+ self.force_dtype()
326
+
327
+ def force_dtype(self):
328
+ self.backbone.to_bfloat16_except_poles_residues()
329
+
330
+ def get_input_embeddings(self):
331
+ return self.backbone.embedding_layer
332
+
333
+ def set_input_embeddings(self, value):
334
+ self.backbone.embedding_layer = value
335
+
336
+ def get_output_embeddings(self):
337
+ return self.backbone.embedding_layer
338
+
339
+ def set_output_embeddings(self, value):
340
+ self.backbone.embedding_layer = value
341
+
342
+ def forward(
343
+ self,
344
+ input_ids: torch.LongTensor = None,
345
+ attention_mask: Optional[torch.LongTensor] = None,
346
+ labels: Optional[torch.LongTensor] = None,
347
+ past_key_values=None,
348
+ use_cache: Optional[bool] = None,
349
+ output_attentions: Optional[bool] = None,
350
+ output_hidden_states: Optional[bool] = None,
351
+ return_dict: Optional[bool] = None,
352
+ ) -> Union[Tuple, CausalLMOutputWithPast]:
353
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
354
+ output_attentions = (
355
+ output_attentions if output_attentions is not None else self.config.output_attentions
356
+ )
357
+ output_hidden_states = (
358
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
359
+ )
360
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
361
+
362
+ if use_cache and labels is not None:
363
+ logger.warning_once("use_cache=True is incompatible with loss computation; disabling.")
364
+ use_cache = False
365
+
366
+ inputs = input_ids
367
+ if use_cache:
368
+ if not isinstance(past_key_values, Evo2Cache):
369
+ past_key_values = self.backbone.initialize_inference_params(
370
+ max_batch_size=input_ids.shape[0]
371
+ )
372
+ else:
373
+ seqlen_offset = past_key_values.seqlen_offset
374
+ if seqlen_offset == 0:
375
+ past_key_values.set_offset(input_ids.shape[-1] - 1)
376
+ else:
377
+ past_key_values.advance(1)
378
+ inputs = input_ids[:, -1:]
379
+
380
+ last_hidden, past_kv, hidden_states, attentions = self.backbone(
381
+ inputs,
382
+ padding_mask=attention_mask,
383
+ inference_params_dict=past_key_values if use_cache else None,
384
+ output_hidden_states=output_hidden_states,
385
+ output_attentions=output_attentions,
386
+ )
387
+
388
+ logits = last_hidden @ self.backbone.embedding_layer.weight.T
389
+
390
+ loss = None
391
+ if labels is not None:
392
+ shift_logits = logits[..., :-1, :].contiguous()
393
+ shift_labels = labels[..., 1:].contiguous()
394
+ shift_logits = shift_logits.view(-1, self.config.vocab_size)
395
+ shift_labels = shift_labels.view(-1).to(shift_logits.device)
396
+ loss = F.cross_entropy(shift_logits, shift_labels)
397
+
398
+ if not return_dict:
399
+ outputs = (logits,)
400
+ if use_cache: outputs += (past_kv,)
401
+ if output_hidden_states: outputs += (tuple(hidden_states),)
402
+ if output_attentions: outputs += (tuple(attentions),)
403
+ if loss is not None: outputs = (loss,) + outputs
404
+ return outputs
405
+
406
+ return CausalLMOutputWithPast(
407
+ loss=loss,
408
+ logits=logits,
409
+ past_key_values=past_kv if use_cache else None,
410
+ hidden_states=tuple(hidden_states) if output_hidden_states else None,
411
+ attentions=tuple(attentions) if output_attentions else None,
412
+ )
413
+
414
+ @classmethod
415
+ def can_generate(cls) -> bool:
416
+ return True
417
+
418
+ def prepare_inputs_for_generation(
419
+ self, input_ids, attention_mask=None, past_key_values=None, **kwargs
420
+ ):
421
+ return {
422
+ "input_ids": input_ids,
423
+ "attention_mask": attention_mask,
424
+ "past_key_values": past_key_values,
425
+ }
rotary.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rotary embeddings for Evo2.
2
+
3
+ Mirrors models/evo/hf/rotary.py (same RoPE math): flash_attn fast path when
4
+ available, pure-PyTorch fallback otherwise. LinearlyScaledRotaryEmbedding
5
+ implements linear position-index interpolation (`t = t / scaling_factor`)
6
+ used by all the 1M / 262K context variants.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+
14
+
15
+ try:
16
+ from flash_attn.layers.rotary import RotaryEmbedding as _FlashRotaryEmbedding
17
+ _HAS_FLASH_ROTARY = True
18
+ except ImportError:
19
+ _FlashRotaryEmbedding = None
20
+ _HAS_FLASH_ROTARY = False
21
+
22
+
23
+ def _rotate_half(x: torch.Tensor) -> torch.Tensor:
24
+ x1, x2 = x.chunk(2, dim=-1)
25
+ return torch.cat((-x2, x1), dim=-1)
26
+
27
+
28
+ def _apply_rotary(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
29
+ # Compute the multiply in fp32 then cast back to x.dtype to match
30
+ # flash_attn's Triton kernel bit-exactly. Doing the multiply in bf16
31
+ # directly compounds rounding error of ~3e-2 per layer.
32
+ rot_dim = cos.shape[-1] * 2
33
+ x_rot = x[..., :rot_dim]
34
+ x_pass = x[..., rot_dim:]
35
+ orig_dtype = x.dtype
36
+ cos_full = torch.cat((cos, cos), dim=-1).float()
37
+ sin_full = torch.cat((sin, sin), dim=-1).float()
38
+ x_rot_f = x_rot.float()
39
+ rotated = (x_rot_f * cos_full) + (_rotate_half(x_rot_f) * sin_full)
40
+ rotated = rotated.to(orig_dtype)
41
+ return torch.cat((rotated, x_pass), dim=-1)
42
+
43
+
44
+ class _PureRotaryEmbedding(nn.Module):
45
+ """Pure-PyTorch fallback RoPE. Mirrors flash_attn.layers.rotary.RotaryEmbedding's surface."""
46
+
47
+ def __init__(
48
+ self,
49
+ dim: int,
50
+ base: float = 10000.0,
51
+ interleaved: bool = False,
52
+ scale_base: float | None = None,
53
+ pos_idx_in_fp32: bool = True,
54
+ device=None,
55
+ ):
56
+ super().__init__()
57
+ if interleaved:
58
+ raise NotImplementedError("Interleaved RoPE is not implemented.")
59
+ if scale_base is not None:
60
+ raise NotImplementedError("xPos scale_base is not implemented.")
61
+ self.dim = dim
62
+ self.base = float(base)
63
+ self.interleaved = interleaved
64
+ self.scale_base = scale_base
65
+ self.pos_idx_in_fp32 = pos_idx_in_fp32
66
+
67
+ inv_freq = self._compute_inv_freq(device=device)
68
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
69
+ self.scale = None # xPos slot kept for swap_mha_rope compatibility
70
+
71
+ self._seq_len_cached = 0
72
+ self._cos_cached: torch.Tensor | None = None
73
+ self._sin_cached: torch.Tensor | None = None
74
+
75
+ def _compute_inv_freq(self, device=None) -> torch.Tensor:
76
+ return 1.0 / (
77
+ self.base
78
+ ** (torch.arange(0, self.dim, 2, device=device, dtype=torch.float32) / self.dim)
79
+ )
80
+
81
+ def _update_cos_sin_cache(self, seqlen: int, device=None, dtype=None):
82
+ if (
83
+ seqlen > self._seq_len_cached
84
+ or self._cos_cached is None
85
+ or self._cos_cached.device != device
86
+ or self._cos_cached.dtype != dtype
87
+ or (self.training and self._cos_cached.is_inference())
88
+ ):
89
+ self._seq_len_cached = seqlen
90
+ if self.pos_idx_in_fp32:
91
+ t = torch.arange(seqlen, device=device, dtype=torch.float32)
92
+ if self.inv_freq.dtype != torch.float32:
93
+ inv_freq = self._compute_inv_freq(device=device)
94
+ else:
95
+ inv_freq = self.inv_freq
96
+ else:
97
+ t = torch.arange(seqlen, device=device, dtype=self.inv_freq.dtype)
98
+ inv_freq = self.inv_freq
99
+
100
+ freqs = torch.outer(t, inv_freq)
101
+ self._cos_cached = torch.cos(freqs).to(dtype)
102
+ self._sin_cached = torch.sin(freqs).to(dtype)
103
+
104
+ def forward(
105
+ self,
106
+ qkv: torch.Tensor,
107
+ seqlen_offset: int | torch.Tensor = 0,
108
+ max_seqlen: int | None = None,
109
+ ) -> torch.Tensor:
110
+ if isinstance(seqlen_offset, torch.Tensor):
111
+ seqlen_offset = int(seqlen_offset.max().item())
112
+ T = qkv.shape[1]
113
+ seqlen = max_seqlen if max_seqlen is not None else (T + seqlen_offset)
114
+ self._update_cos_sin_cache(seqlen, device=qkv.device, dtype=qkv.dtype)
115
+
116
+ cos = self._cos_cached[seqlen_offset : seqlen_offset + T]
117
+ sin = self._sin_cached[seqlen_offset : seqlen_offset + T]
118
+ q, k, v = qkv.unbind(dim=2)
119
+ cos_b = cos[None, :, None, :]
120
+ sin_b = sin[None, :, None, :]
121
+ q = _apply_rotary(q, cos_b, sin_b)
122
+ k = _apply_rotary(k, cos_b, sin_b)
123
+ return torch.stack((q, k, v), dim=2)
124
+
125
+
126
+ RotaryEmbedding: type = (
127
+ _FlashRotaryEmbedding if _HAS_FLASH_ROTARY else _PureRotaryEmbedding
128
+ )
129
+
130
+
131
+ class LinearlyScaledRotaryEmbedding(RotaryEmbedding):
132
+ """RoPE with linear interpolation of position indices.
133
+
134
+ Used for evo2_7b (1M), evo2_7b_262k, evo2_20b, evo2_40b. Positions are
135
+ divided by ``scaling_factor`` before cos/sin tables are computed.
136
+ """
137
+
138
+ def __init__(self, dim: int, scaling_factor: float = 1.0, **kwargs):
139
+ super().__init__(dim=dim, **kwargs)
140
+ self._linear_scaling_factor = float(scaling_factor)
141
+
142
+ def _update_cos_sin_cache(self, seqlen, device=None, dtype=None):
143
+ if (
144
+ seqlen <= self._seq_len_cached
145
+ and self._cos_cached is not None
146
+ and self._cos_cached.device == device
147
+ and self._cos_cached.dtype == dtype
148
+ and not (self.training and self._cos_cached.is_inference())
149
+ ):
150
+ return
151
+
152
+ self._seq_len_cached = seqlen
153
+ if self.pos_idx_in_fp32:
154
+ t = torch.arange(seqlen, device=device, dtype=torch.float32)
155
+ t = t / self._linear_scaling_factor
156
+ if self.inv_freq.dtype != torch.float32:
157
+ inv_freq = self._compute_inv_freq(device=device) \
158
+ if hasattr(self, "_compute_inv_freq") \
159
+ else self.inv_freq.float()
160
+ else:
161
+ inv_freq = self.inv_freq
162
+ else:
163
+ t = torch.arange(seqlen, device=device, dtype=self.inv_freq.dtype)
164
+ t = t / self._linear_scaling_factor
165
+ inv_freq = self.inv_freq
166
+
167
+ freqs = torch.outer(t, inv_freq)
168
+ if self.scale is None:
169
+ self._cos_cached = torch.cos(freqs).to(dtype)
170
+ self._sin_cached = torch.sin(freqs).to(dtype)
171
+ else:
172
+ from einops import rearrange
173
+ power = (
174
+ torch.arange(seqlen, dtype=self.scale.dtype, device=self.scale.device)
175
+ - seqlen // 2
176
+ ) / self.scale_base
177
+ scale = self.scale.to(device=power.device) ** rearrange(power, "s -> s 1")
178
+ self._cos_cached = (torch.cos(freqs) * scale).to(dtype)
179
+ self._sin_cached = (torch.sin(freqs) * scale).to(dtype)
180
+ self._cos_k_cached = (torch.cos(freqs) / scale).to(dtype)
181
+ self._sin_k_cached = (torch.sin(freqs) / scale).to(dtype)
182
+
183
+
184
+ def swap_mha_rope(mha, new_rope=LinearlyScaledRotaryEmbedding, kwargs_new_rope=None):
185
+ """Replace ``mha.rotary_emb`` with a freshly-constructed scaled RoPE."""
186
+ weight_attr = "Wq" if getattr(mha, "cross_attn", False) else "Wqkv"
187
+ weight = getattr(mha, weight_attr).weight
188
+ dtype = weight.dtype
189
+ kwargs_old_rope = dict(
190
+ dim=mha.rotary_emb.dim,
191
+ base=mha.rotary_emb.base,
192
+ interleaved=mha.rotary_emb.interleaved,
193
+ scale_base=mha.rotary_emb.scale_base,
194
+ pos_idx_in_fp32=mha.rotary_emb.pos_idx_in_fp32,
195
+ device=mha.rotary_emb.inv_freq.device,
196
+ )
197
+ del mha.rotary_emb
198
+ kwargs_new_rope = kwargs_new_rope or {"scaling_factor": 1.0}
199
+ scaled = new_rope(**kwargs_new_rope, **kwargs_old_rope).to(dtype)
200
+ mha.rotary_emb = scaled
201
+ return mha
special_tokens_map.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {}
tokenization_evo2.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ByteTokenizer for Evo2 (StripedHyena2).
2
+
3
+ Wraps raw UTF-8 byte values into a vocab of size 512 (only [0, 255] are real
4
+ bytes; the upper range pads out to match the model's vocab embedding size).
5
+ Mirrors vortex.model.tokenizer.CharLevelTokenizer exactly:
6
+
7
+ * eod / eos = byte 0 (chr(0))
8
+ * pad = byte 1 (chr(1))
9
+
10
+ No real special tokens are added at encoding time -- Evo2 is a pure byte-level
11
+ model and downstream pooling should treat every non-pad position as a real
12
+ token.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from os import PathLike
18
+ from typing import List, Tuple
19
+
20
+ import numpy as np
21
+
22
+ from transformers.tokenization_utils import PreTrainedTokenizer
23
+ from transformers.tokenization_utils_base import BatchEncoding, TruncationStrategy
24
+ from transformers.utils.generic import PaddingStrategy
25
+
26
+
27
+ EMPTY: str = ""
28
+
29
+
30
+ class ByteTokenizer(PreTrainedTokenizer):
31
+ """UTF-8 byte-level tokenizer for Evo2 (vocab_size = 512)."""
32
+
33
+ def __init__(self, byte_level: bool = True, **kwargs):
34
+ kwargs.setdefault("pad_token", chr(1))
35
+ super().__init__(byte_level=byte_level, **kwargs)
36
+ self.model_input_names = ["input_ids", "attention_mask"]
37
+
38
+ @property
39
+ def vocab_size(self) -> int:
40
+ return 512
41
+
42
+ @property
43
+ def byte_level(self) -> bool:
44
+ return self.init_kwargs.get("byte_level", True)
45
+
46
+ def get_vocab(self) -> dict:
47
+ return {chr(i): i for i in range(self.vocab_size)}
48
+
49
+ def __len__(self) -> int:
50
+ return self.vocab_size
51
+
52
+ def clamp(self, n: int) -> int:
53
+ # Matches vortex CharLevelTokenizer.clamp.
54
+ return max(32, min(n, self.vocab_size))
55
+
56
+ def _tokenize(self, text: str, **kwargs) -> List[str]:
57
+ return list(text)
58
+
59
+ def byte_tokenize(self, text: str) -> np.ndarray:
60
+ return np.frombuffer(text.encode("utf-8"), dtype=np.uint8)
61
+
62
+ def _convert_token_to_id(self, token: str) -> int:
63
+ return self.clamp(ord(token))
64
+
65
+ def _convert_id_to_token(self, index: int) -> str:
66
+ return chr(self.clamp(index))
67
+
68
+ def convert_tokens_to_string(self, tokens: List[str]) -> str:
69
+ return EMPTY.join(tokens)
70
+
71
+ def _decode(self, token_ids: List[int], **kwargs) -> str:
72
+ indices = np.asarray(token_ids, dtype=np.int16)
73
+ indices = indices.clip(min=32, max=255).astype(np.uint8)
74
+ return indices.tobytes().decode("utf-8", errors="replace")
75
+
76
+ def _encode_plus(self, text: str, **kwargs) -> BatchEncoding:
77
+ first_ids = self.byte_tokenize(text).tolist()
78
+ return self.prepare_for_model(
79
+ first_ids,
80
+ pair_ids=None,
81
+ add_special_tokens=kwargs.get("add_special_tokens", False),
82
+ padding=kwargs.get("padding_strategy", PaddingStrategy.DO_NOT_PAD).value,
83
+ truncation=kwargs.get("truncation_strategy", TruncationStrategy.DO_NOT_TRUNCATE).value,
84
+ max_length=kwargs.get("max_length"),
85
+ stride=kwargs.get("stride", 0),
86
+ pad_to_multiple_of=kwargs.get("pad_to_multiple_of"),
87
+ return_tensors=kwargs.get("return_tensors"),
88
+ prepend_batch_axis=True,
89
+ return_attention_mask=kwargs.get("return_attention_mask"),
90
+ return_token_type_ids=kwargs.get("return_token_type_ids"),
91
+ return_overflowing_tokens=kwargs.get("return_overflowing_tokens", False),
92
+ return_special_tokens_mask=kwargs.get("return_special_tokens_mask", False),
93
+ return_length=kwargs.get("return_length", False),
94
+ verbose=kwargs.get("verbose", True),
95
+ )
96
+
97
+ def _batch_encode_plus(self, batch_text_or_text_pairs, **kwargs) -> BatchEncoding:
98
+ input_ids = [(self.byte_tokenize(t).tolist(), None) for t in batch_text_or_text_pairs]
99
+ return self._batch_prepare_for_model(
100
+ input_ids,
101
+ add_special_tokens=kwargs.get("add_special_tokens", False),
102
+ padding_strategy=kwargs.get("padding_strategy", PaddingStrategy.DO_NOT_PAD),
103
+ truncation_strategy=kwargs.get("truncation_strategy", TruncationStrategy.DO_NOT_TRUNCATE),
104
+ max_length=kwargs.get("max_length"),
105
+ stride=kwargs.get("stride", 0),
106
+ pad_to_multiple_of=kwargs.get("pad_to_multiple_of"),
107
+ return_attention_mask=kwargs.get("return_attention_mask"),
108
+ return_token_type_ids=kwargs.get("return_token_type_ids"),
109
+ return_overflowing_tokens=kwargs.get("return_overflowing_tokens", False),
110
+ return_special_tokens_mask=kwargs.get("return_special_tokens_mask", False),
111
+ return_length=kwargs.get("return_length", False),
112
+ return_tensors=kwargs.get("return_tensors"),
113
+ verbose=kwargs.get("verbose", True),
114
+ )
115
+
116
+ def _save_pretrained(
117
+ self, save_directory: str | PathLike, file_names: Tuple[str], **kwargs
118
+ ) -> Tuple[str]:
119
+ return file_names
tokenizer_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "auto_map": {
3
+ "AutoTokenizer": [
4
+ "tokenization_evo2.ByteTokenizer",
5
+ null
6
+ ]
7
+ },
8
+ "tokenizer_class": "ByteTokenizer",
9
+ "model_max_length": 8192,
10
+ "pad_token": "\u0001",
11
+ "byte_level": true
12
+ }