SeaWolf-AI commited on
Commit
09ac010
·
verified ·
1 Parent(s): 51128a5

Aether-6B-11Attn (open weights) — 11 sequence-mixing mechanisms on an 11x11 Latin square

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* 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
 
 
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
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ language:
4
+ - en
5
+ - ko
6
+ pipeline_tag: text-generation
7
+ library_name: transformers
8
+ tags:
9
+ - aether
10
+ - open-weights
11
+ - heterogeneous-attention
12
+ - mixture-of-experts
13
+ - mamba2
14
+ - state-space-model
15
+ - hyena
16
+ - mla
17
+ - korean
18
+ - vidraft
19
+ ---
20
+
21
+ # Aether-6B-11Attn
22
+
23
+ **A 121-layer network that places 11 different sequence-mixing mechanisms on an 11x11 Latin square.**
24
+
25
+ To our knowledge, this is the first model to integrate **11 heterogeneous sequence-mixing mechanisms** — attention, state-space, convolutional and linear families — inside a single network. Existing hybrids combine two or three (e.g. Mamba + Transformer).
26
+
27
+ > **Release scope: open weights.** This repository ships the weights plus the minimum code needed to load them. Unlike [Aether-7B-5Attn](https://huggingface.co/FINAL-Bench/Aether-7B-5Attn) — which is fully open (data recipe, training code, logs, checkpoints) — the training data recipe, training code, logs and intermediate checkpoints for this model are **not** released.
28
+
29
+ ## The 11 mechanisms
30
+
31
+ 121 layers = 11 x 11. Each mechanism occupies **exactly 11 layers**, one per row and column of the Latin square, so no mechanism concentrates at any depth.
32
+
33
+ | # | Mechanism | Family | Distinctive parameters (verifiable in the weights) |
34
+ |---|-----------|--------|---------------------------------------------------|
35
+ | 0 | `nsa` | sparse attention | `compress_mlp`, `gate_logit`, `select_score` |
36
+ | 1 | `differential` | attention | `lambda_q1/k1/q2/k2`, `subln` |
37
+ | 2 | `full` | attention | `q/k/v/o_proj` |
38
+ | 3 | `mla` | latent attention | `kv_a_proj`, `kv_b_proj`, `q_a_proj`, `q_b_proj` |
39
+ | 4 | `sliding` | attention | windowed masking over the full path |
40
+ | 5 | `compress` | attention | `full_attn.*` submodule |
41
+ | 6 | `hybrid` | attention | `nsa.*` + `diff.*` + `gate` + `merge_norm` |
42
+ | 7 | `linear` | linear attention | `gate`, `norm` |
43
+ | 8 | `mamba2` | **state-space** | `A_log`, `D`, `conv1d`, `dt_proj`, `B_proj`, `C_proj` |
44
+ | 9 | `gdn` | gated delta net | `conv1d_q`, `conv1d_k`, `gate_proj` |
45
+ | 10 | `hyena` | **convolutional** | `filter_dense` (implicit filter) |
46
+
47
+ *Precision matters here: `full` and `sliding` share the same parameters (sliding is masking over the full path), so the weights show **10 distinct parameter signatures for 11 labels**. And several of these are not "attention" in the strict sense — `mamba2`, `hyena`, `gdn` and `linear` are other sequence-mixing families, which is exactly the point of the experiment.*
48
+
49
+ ## Specifications
50
+
51
+ | | |
52
+ |---|---|
53
+ | Parameters | 5.79B total (MoE) |
54
+ | Layers | 121 (11 x 11 Latin square) |
55
+ | Hidden size | 1024 |
56
+ | Attention heads | 8 query / 2 key-value (GQA), head dim 128 |
57
+ | Experts | 25 routed (top-7) + 1 shared |
58
+ | Vocabulary | 151,936 |
59
+ | Precision | bfloat16 |
60
+ | Checkpoint | training step 174,000 |
61
+ | License | Apache-2.0 |
62
+
63
+ ## Provenance and honest caveats
64
+
65
+ This model was reconstructed from a sharded FSDP training checkpoint. **The exact training code was not archived**, so the architecture code shipped here was rebuilt and then validated two ways:
66
+
67
+ 1. **Exact parameter match** — all 11,047 checkpoint tensors load with **0 missing / 0 unexpected** keys, and the parameter count matches the checkpoint exactly (5.7885B).
68
+ 2. **Perplexity** — the loaded model predicts real text sensibly (PPL 11.8 English / 6.5 Korean on sample sentences). A mis-reconstructed architecture would produce perplexity orders of magnitude worse.
69
+
70
+ Treat this as a **research artifact**, not a polished product: it is a mid-training checkpoint of an architecture experiment, with no instruction tuning.
71
+
72
+ ## Usage
73
+
74
+ Custom architecture — load with the bundled `aether_pkg/`.
75
+
76
+ > **Run at batch_size = 1** (the NSA branches do not consume a padding mask), and run the forward under `torch.autocast(dtype=torch.bfloat16)` — several branches create fp32 intermediates.
77
+
78
+ ## Related
79
+
80
+ - **Fully-open sibling:** [Aether-7B-5Attn](https://huggingface.co/FINAL-Bench/Aether-7B-5Attn) (weights + data recipe + training code + logs + checkpoints)
81
+ - **Collection:** [Aether Foundation Model](https://huggingface.co/collections/FINAL-Bench/aether-foundation-model)
82
+
83
+ *Built by VIDRAFT. License: Apache-2.0*
aether_pkg/__init__.py ADDED
File without changes
aether_pkg/configuration_aether_v2_11attn.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ """AETHER-30B-11Attn — Configuration.
3
+
4
+ Prime Series (5/7/11/13/17/...) — 11×11 Latin Square × 11 attention types.
5
+
6
+ Family ecosystem:
7
+ hidden_size: 2048 (V2 family 통일, Qwen3 ecosystem 호환)
8
+ vocab_size: 151,936 (Qwen3 base)
9
+ num_layers: 121 (11×11 정통 Latin Square)
10
+ num_experts: 25 (top-7 active)
11
+
12
+ Attention types (11종):
13
+ Transformer 7종: NSA / Differential / Full / MLA / Sliding / Compress / Hybrid
14
+ Non-Transformer 4종: Linear / Mamba2 / GDN / DeltaNet (Hyena는 conv 계열)
15
+
16
+ 실제로는 11종으로 확장:
17
+ 0: nsa (DeepSeek 2502 NSA)
18
+ 1: differential (Microsoft 2410 Diff)
19
+ 2: full (Vaswani 2017 표준)
20
+ 3: mla (DeepSeek-V2/V3 Multi-head Latent)
21
+ 4: sliding (Window)
22
+ 5: compress (NSA 압축 only)
23
+ 6: hybrid (NSA + Diff)
24
+ 7: linear (Mamba-style linear)
25
+ 8: mamba2 (SSM)
26
+ 9: gdn (Gated Delta Network)
27
+ 10: hyena (Convolutional)
28
+ """
29
+ from transformers.configuration_utils import PretrainedConfig
30
+
31
+
32
+ class AETHERV211AttnConfig(PretrainedConfig):
33
+ """AETHER-30B-11Attn config.
34
+
35
+ 11×11 Latin Square × 121 layers
36
+ 25-expert MoE × top-7 active per token
37
+ 5-element cyclic FFN phase (오행)
38
+ """
39
+ model_type = "aether_v2_11attn"
40
+ keys_to_ignore_at_inference = ["past_key_values"]
41
+
42
+ def __init__(
43
+ self,
44
+ # Vocab
45
+ vocab_size: int = 151936,
46
+ pad_token_id: int = 151643,
47
+
48
+ # Model dimensions ⭐ V2 family 통일
49
+ hidden_size: int = 2048,
50
+ intermediate_size: int = 6144,
51
+ num_hidden_layers: int = 121, # 11×11 Latin Square
52
+
53
+ # Attention common
54
+ num_attention_heads: int = 16,
55
+ num_key_value_heads: int = 4, # GQA 4:1
56
+ head_dim: int = 128,
57
+ attention_dropout: float = 0.0,
58
+
59
+ # Attention type-specific
60
+ sliding_window_size: int = 1024,
61
+ compress_block_size: int = 32,
62
+ # NSA
63
+ nsa_compress_block_size: int = 32,
64
+ nsa_select_top_k: int = 16,
65
+ nsa_sliding_window: int = 512,
66
+ # Differential
67
+ diff_lambda_init: float = 0.8,
68
+ diff_lambda_layer_decay: float = 0.6,
69
+ # MLA (DeepSeek-V2/V3)
70
+ mla_kv_lora_rank: int = 256, # hidden=2048에 맞춰 축소 (Pilot 512)
71
+ mla_q_lora_rank: int = 768,
72
+ mla_qk_rope_head_dim: int = 64,
73
+ mla_qk_nope_head_dim: int = 64,
74
+ mla_v_head_dim: int = 128,
75
+ # Hybrid
76
+ hybrid_groupnorm_groups: int = 8,
77
+ # Linear (Mamba-style)
78
+ linear_d_state: int = 64,
79
+ linear_d_conv: int = 4,
80
+ linear_expand: int = 1,
81
+ # Mamba2
82
+ mamba2_d_state: int = 128,
83
+ mamba2_d_conv: int = 4,
84
+ mamba2_expand: int = 2,
85
+ mamba2_headdim: int = 64,
86
+ mamba2_chunk_size: int = 256,
87
+ # GDN
88
+ gdn_d_conv: int = 4,
89
+ gdn_expand: int = 1,
90
+ gdn_chunk_size: int = 64,
91
+ # DeltaNet
92
+ deltanet_d_state: int = 64,
93
+ deltanet_chunk_size: int = 128,
94
+ # Hyena
95
+ hyena_filter_order: int = 64,
96
+ hyena_dropout: float = 0.0,
97
+
98
+ # MoE
99
+ num_experts: int = 25,
100
+ num_experts_per_tok: int = 7,
101
+ expert_intermediate_size: int = 1280,
102
+ use_shared_expert: bool = True,
103
+ router_aux_loss_coef: float = 0.01,
104
+ z_loss_coef: float = 0.001,
105
+
106
+ # Oheng (5-phase cyclic FFN)
107
+ oheng_enable: bool = True,
108
+ oheng_num_phases: int = 5,
109
+
110
+ # Position
111
+ max_position_embeddings: int = 8192,
112
+ rope_theta: float = 1000000.0,
113
+
114
+ # Norm + activation
115
+ rms_norm_eps: float = 1e-6,
116
+ hidden_act: str = "silu",
117
+ initializer_range: float = 0.02,
118
+
119
+ # DeepNet / training stability (121-layer deep)
120
+ use_deepnet_init: bool = True,
121
+ rezero_alpha_init: float = 0.0,
122
+
123
+ # Training / inference
124
+ use_cache: bool = True,
125
+ output_router_logits: bool = False,
126
+ tie_word_embeddings: bool = True, # V2 family 동일
127
+
128
+ **kwargs,
129
+ ):
130
+ # Save all
131
+ self.vocab_size = vocab_size
132
+ self.hidden_size = hidden_size
133
+ self.intermediate_size = intermediate_size
134
+ self.num_hidden_layers = num_hidden_layers
135
+
136
+ self.num_attention_heads = num_attention_heads
137
+ self.num_key_value_heads = num_key_value_heads
138
+ self.head_dim = head_dim
139
+ self.attention_dropout = attention_dropout
140
+
141
+ self.sliding_window_size = sliding_window_size
142
+ self.compress_block_size = compress_block_size
143
+ self.nsa_compress_block_size = nsa_compress_block_size
144
+ self.nsa_select_top_k = nsa_select_top_k
145
+ self.nsa_sliding_window = nsa_sliding_window
146
+ self.diff_lambda_init = diff_lambda_init
147
+ self.diff_lambda_layer_decay = diff_lambda_layer_decay
148
+ self.mla_kv_lora_rank = mla_kv_lora_rank
149
+ self.mla_q_lora_rank = mla_q_lora_rank
150
+ self.mla_qk_rope_head_dim = mla_qk_rope_head_dim
151
+ self.mla_qk_nope_head_dim = mla_qk_nope_head_dim
152
+ self.mla_v_head_dim = mla_v_head_dim
153
+ self.hybrid_groupnorm_groups = hybrid_groupnorm_groups
154
+ self.linear_d_state = linear_d_state
155
+ self.linear_d_conv = linear_d_conv
156
+ self.linear_expand = linear_expand
157
+ self.mamba2_d_state = mamba2_d_state
158
+ self.mamba2_d_conv = mamba2_d_conv
159
+ self.mamba2_expand = mamba2_expand
160
+ self.mamba2_headdim = mamba2_headdim
161
+ self.mamba2_chunk_size = mamba2_chunk_size
162
+ self.gdn_d_conv = gdn_d_conv
163
+ self.gdn_expand = gdn_expand
164
+ self.gdn_chunk_size = gdn_chunk_size
165
+ self.deltanet_d_state = deltanet_d_state
166
+ self.deltanet_chunk_size = deltanet_chunk_size
167
+ self.hyena_filter_order = hyena_filter_order
168
+ self.hyena_dropout = hyena_dropout
169
+
170
+ self.num_experts = num_experts
171
+ self.num_experts_per_tok = num_experts_per_tok
172
+ self.expert_intermediate_size = expert_intermediate_size
173
+ self.use_shared_expert = use_shared_expert
174
+ self.router_aux_loss_coef = router_aux_loss_coef
175
+ self.z_loss_coef = z_loss_coef
176
+ self.oheng_enable = oheng_enable
177
+ self.oheng_num_phases = oheng_num_phases
178
+
179
+ self.max_position_embeddings = max_position_embeddings
180
+ self.rope_theta = rope_theta
181
+ self.rms_norm_eps = rms_norm_eps
182
+ self.hidden_act = hidden_act
183
+ self.initializer_range = initializer_range
184
+ self.use_deepnet_init = use_deepnet_init
185
+ self.rezero_alpha_init = rezero_alpha_init
186
+
187
+ self.use_cache = use_cache
188
+ self.output_router_logits = output_router_logits
189
+
190
+ super().__init__(
191
+ pad_token_id=pad_token_id,
192
+ tie_word_embeddings=tie_word_embeddings,
193
+ **kwargs,
194
+ )
195
+
196
+
197
+ # =============================================================================
198
+ # Pre-defined configs (nano / mini / full)
199
+ # =============================================================================
200
+
201
+ # Nano: forward test 검증용 (~150M total)
202
+ nano_11attn_cfg = AETHERV211AttnConfig(
203
+ hidden_size=512,
204
+ intermediate_size=1536,
205
+ expert_intermediate_size=192,
206
+ num_hidden_layers=121,
207
+ num_attention_heads=8,
208
+ num_key_value_heads=2,
209
+ head_dim=64,
210
+ sliding_window_size=128,
211
+ compress_block_size=16,
212
+ nsa_compress_block_size=16,
213
+ nsa_sliding_window=64,
214
+ mla_kv_lora_rank=128,
215
+ mla_q_lora_rank=384,
216
+ mla_qk_rope_head_dim=32,
217
+ mla_qk_nope_head_dim=32,
218
+ mla_v_head_dim=64,
219
+ linear_d_state=32,
220
+ mamba2_d_state=64,
221
+ mamba2_headdim=32,
222
+ deltanet_d_state=32,
223
+ hyena_filter_order=32,
224
+ )
225
+
226
+ # Mini: PoC 학습 (~3B total / 0.8B active)
227
+ mini_11attn_cfg = AETHERV211AttnConfig(
228
+ hidden_size=1024,
229
+ intermediate_size=3072,
230
+ expert_intermediate_size=512,
231
+ num_hidden_layers=121,
232
+ num_attention_heads=8,
233
+ num_key_value_heads=2,
234
+ head_dim=128,
235
+ )
236
+
237
+ # Full ⭐ AETHER-30B-11Attn target
238
+ full_11attn_cfg = AETHERV211AttnConfig(
239
+ hidden_size=2048,
240
+ intermediate_size=6144,
241
+ expert_intermediate_size=1536, # 30B target fit
242
+ num_hidden_layers=121,
243
+ num_attention_heads=16,
244
+ num_key_value_heads=4,
245
+ head_dim=128,
246
+ sliding_window_size=2048,
247
+ )
248
+
249
+
250
+ def estimate_params_11attn(cfg: AETHERV211AttnConfig) -> dict:
251
+ """Estimate AETHER-30B-11Attn parameter count."""
252
+ h = cfg.hidden_size
253
+ n_layers = cfg.num_hidden_layers
254
+ n_heads = cfg.num_attention_heads
255
+ n_kv = cfg.num_key_value_heads
256
+ head_dim = cfg.head_dim
257
+ n_experts = cfg.num_experts
258
+ e_inter = cfg.expert_intermediate_size
259
+ vocab = cfg.vocab_size
260
+
261
+ # Embed (tied with LM head)
262
+ embed = vocab * h
263
+
264
+ # Per-layer (average across 11 attention types)
265
+ norm = 2 * h
266
+
267
+ # Attention avg (대략):
268
+ # Full/Sliding: 4 × h² × heads/(heads+kv) ≈ h × (heads+2kv) × head_dim
269
+ # MLA: lower (low-rank), but not significantly
270
+ # Mamba2/GDN/Linear: smaller
271
+ attn_avg = h * (n_heads + 2 * n_kv) * head_dim + h * h # Q,K,V,O
272
+
273
+ # MoE
274
+ moe_gate = h * n_experts
275
+ moe_experts = n_experts * 3 * h * e_inter # gate_proj, up_proj, down_proj
276
+ moe_shared = 3 * h * e_inter
277
+
278
+ per_layer = norm + attn_avg + moe_gate + moe_experts + moe_shared
279
+
280
+ total = embed + n_layers * per_layer
281
+
282
+ # Active per token (top-k experts + shared)
283
+ active_per_layer = norm + attn_avg + moe_gate + cfg.num_experts_per_tok * 3 * h * e_inter + moe_shared
284
+ active_total = embed + n_layers * active_per_layer
285
+
286
+ return {
287
+ "total": total,
288
+ "total_M": total / 1e6,
289
+ "total_B": total / 1e9,
290
+ "active": active_total,
291
+ "active_M": active_total / 1e6,
292
+ "active_B": active_total / 1e9,
293
+ "per_layer_M": per_layer / 1e6,
294
+ }
295
+
296
+
297
+ __all__ = [
298
+ "AETHERV211AttnConfig",
299
+ "nano_11attn_cfg",
300
+ "mini_11attn_cfg",
301
+ "full_11attn_cfg",
302
+ "estimate_params_11attn",
303
+ ]
304
+
305
+
306
+ if __name__ == "__main__":
307
+ print("=" * 70)
308
+ print("AETHER-30B-11Attn Param Estimation")
309
+ print("=" * 70)
310
+ for name, cfg in [("nano", nano_11attn_cfg), ("mini", mini_11attn_cfg), ("full", full_11attn_cfg)]:
311
+ info = estimate_params_11attn(cfg)
312
+ print(f"\n[{name}]")
313
+ print(f" hidden: {cfg.hidden_size}")
314
+ print(f" layers: {cfg.num_hidden_layers}")
315
+ print(f" experts: {cfg.num_experts} (top-{cfg.num_experts_per_tok})")
316
+ print(f" expert_int: {cfg.expert_intermediate_size}")
317
+ print(f" Total: {info['total_B']:.2f}B ({info['total_M']:.0f}M)")
318
+ print(f" Active: {info['active_B']:.2f}B ({info['active_M']:.0f}M)")
319
+ print(f" Per layer: {info['per_layer_M']:.0f}M")
aether_pkg/modeling_aether_v2_11way.py ADDED
@@ -0,0 +1,842 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2026 VIDRAFT (비드래프트). All rights reserved.
3
+ #
4
+ # AETHER-V2-7way: 7-aware attention + 7×7 Latin Square 49-layer MoE
5
+ # Built upon HuggingFace Transformers conventions.
6
+ #
7
+ # Architecture:
8
+ # - 49 layers organized as 7×7 Latin Square
9
+ # - 7 distinct attention types (NSA, Differential, Full, Linear, Sliding, Compress, Hybrid)
10
+ # - 25 experts per layer, top-7 active per token
11
+ # - Each row of latin square = 1 cycle of 7 attention types
12
+ # - Each column = different ordering (Latin square property)
13
+ #
14
+ # Layer index → (row, col) → attention type via LATIN_SQUARE_7x7
15
+ #
16
+ """PyTorch AETHER-V2-7way model."""
17
+
18
+ from __future__ import annotations
19
+ import math
20
+ import warnings
21
+ from typing import List, Optional, Tuple, Union
22
+
23
+ import torch
24
+ import torch.nn as nn
25
+ import torch.nn.functional as F
26
+ from torch.nn import CrossEntropyLoss
27
+
28
+ from transformers.activations import ACT2FN
29
+ from transformers.cache_utils import Cache, DynamicCache
30
+ from transformers.modeling_outputs import (
31
+ BaseModelOutputWithPast,
32
+ CausalLMOutputWithPast,
33
+ MoeCausalLMOutputWithPast,
34
+ MoeModelOutputWithPast,
35
+ )
36
+ from transformers.modeling_utils import PreTrainedModel
37
+ from transformers.utils import logging
38
+
39
+ from .configuration_aether_v2_11attn import AETHERV211AttnConfig
40
+
41
+ # 7-aware attention modules (already authored, in v2_attentions/)
42
+ from .v2_attentions.nsa import NSAAttention
43
+ from .v2_attentions.differential import DifferentialAttention
44
+
45
+ logger = logging.get_logger(__name__)
46
+
47
+
48
+ # =============================================================================
49
+ # 7×7 Latin Square — Layer → (attention_type, ffn_phase) 매핑
50
+ # =============================================================================
51
+ # Latin Square property: each row & column has each of {0..6} exactly once.
52
+ # row = layer // 7 (0..6)
53
+ # col = layer % 7 (0..6)
54
+ # attention_type = LATIN_SQUARE_7x7[row][col]
55
+ #
56
+ # 5-element cyclic FFN phase (오행 상생 — Q2B OhengGate inspired):
57
+ # ffn_phase = layer % 5
58
+ #
59
+ # Cyclic Latin Square 11x11 (prime number — Prime Series)
60
+ LATIN_SQUARE_11x11 = [
61
+ [(i + j) % 11 for j in range(11)] for i in range(11)
62
+ ]
63
+
64
+ # Backward compat alias
65
+ LATIN_SQUARE_7x7 = LATIN_SQUARE_11x11 # for v2_7way imports
66
+
67
+ # Attention type names (0..6)
68
+ ATTN_TYPES = [
69
+ "nsa", # 0: Native Sparse Attention (3-branch) [Transformer]
70
+ "differential", # 1: Differential Attention (λ-gated) [Transformer]
71
+ "full", # 2: Full Attention (standard) [Transformer]
72
+ "mla", # 3: Multi-head Latent (DeepSeek-V2/V3) [Transformer]
73
+ "sliding", # 4: Sliding Window Attention [Transformer]
74
+ "compress", # 5: Compress-only (NSA subset) [Transformer]
75
+ "hybrid", # 6: NSA + Differential combined [Transformer]
76
+ "linear", # 7: Linear Attention (Mamba-style) [Non-Transformer]
77
+ "mamba2", # 8: Mamba2 (SSM) [Non-Transformer]
78
+ "gdn", # 9: Gated Delta Network [Non-Transformer]
79
+ "hyena", # 10: Hyena (Convolutional) [Non-Transformer]
80
+ ]
81
+
82
+
83
+ def get_attention_type(layer_idx: int) -> str:
84
+ """Layer index → attention type via 11x11 Latin Square."""
85
+ row = layer_idx // 11
86
+ col = layer_idx % 11
87
+ type_idx = LATIN_SQUARE_11x11[row][col]
88
+ return ATTN_TYPES[type_idx]
89
+
90
+
91
+ def get_ffn_phase(layer_idx: int) -> int:
92
+ """Layer index → 5-element cyclic phase (오행)."""
93
+ return layer_idx % 5
94
+
95
+
96
+ # =============================================================================
97
+ # Rotary Position Embedding (RoPE)
98
+ # =============================================================================
99
+ class AETHERV211AttnRotaryEmbedding(nn.Module):
100
+ def __init__(self, dim: int, max_pos: int = 4096, base: float = 10000.0, device=None):
101
+ super().__init__()
102
+ self.dim = dim
103
+ self.max_pos = max_pos
104
+ self.base = base
105
+ inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim))
106
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
107
+ self._build_cos_sin_cache(max_pos, device or torch.device("cpu"))
108
+
109
+ def _build_cos_sin_cache(self, seq_len: int, device, dtype=torch.float32):
110
+ t = torch.arange(seq_len, device=device, dtype=torch.float32)
111
+ freqs = torch.outer(t, self.inv_freq)
112
+ emb = torch.cat([freqs, freqs], dim=-1)
113
+ self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)
114
+ self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)
115
+
116
+ @torch.no_grad()
117
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor):
118
+ if position_ids.max() >= self.cos_cached.size(0):
119
+ self._build_cos_sin_cache(int(position_ids.max() + 1), x.device, x.dtype)
120
+ cos = self.cos_cached[position_ids].to(x.dtype)
121
+ sin = self.sin_cached[position_ids].to(x.dtype)
122
+ return cos, sin
123
+
124
+
125
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
126
+ x1, x2 = x.chunk(2, dim=-1)
127
+ return torch.cat([-x2, x1], dim=-1)
128
+
129
+
130
+ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
131
+ cos = cos.unsqueeze(unsqueeze_dim)
132
+ sin = sin.unsqueeze(unsqueeze_dim)
133
+ q_embed = (q * cos) + (rotate_half(q) * sin)
134
+ k_embed = (k * cos) + (rotate_half(k) * sin)
135
+ return q_embed, k_embed
136
+
137
+
138
+ # =============================================================================
139
+ # RMSNorm
140
+ # =============================================================================
141
+ class AETHERV211AttnRMSNorm(nn.Module):
142
+ def __init__(self, hidden_size: int, eps: float = 1e-6):
143
+ super().__init__()
144
+ self.weight = nn.Parameter(torch.ones(hidden_size))
145
+ self.eps = eps
146
+
147
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
148
+ in_dtype = hidden_states.dtype
149
+ hidden_states = hidden_states.to(torch.float32)
150
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
151
+ hidden_states = hidden_states * torch.rsqrt(variance + self.eps)
152
+ return self.weight * hidden_states.to(in_dtype)
153
+
154
+
155
+ # =============================================================================
156
+ # Standard Multi-Head Attention (Full Attention type)
157
+ # =============================================================================
158
+ class FullAttention(nn.Module):
159
+ """Standard multi-head attention with GQA support."""
160
+
161
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
162
+ super().__init__()
163
+ self.config = config
164
+ self.layer_idx = layer_idx
165
+ self.hidden_size = config.hidden_size
166
+ self.num_heads = config.num_attention_heads
167
+ self.num_kv_heads = getattr(config, "num_key_value_heads", config.num_attention_heads)
168
+ self.head_dim = config.head_dim
169
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
170
+
171
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
172
+ self.k_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
173
+ self.v_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
174
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
175
+
176
+ self.rotary = AETHERV211AttnRotaryEmbedding(
177
+ self.head_dim, config.max_position_embeddings, config.rope_theta,
178
+ )
179
+
180
+ def _repeat_kv(self, x: torch.Tensor) -> torch.Tensor:
181
+ if self.num_kv_groups == 1:
182
+ return x
183
+ bsz, n_kv, seq, dim = x.shape
184
+ return x[:, :, None, :, :].expand(bsz, n_kv, self.num_kv_groups, seq, dim).reshape(
185
+ bsz, n_kv * self.num_kv_groups, seq, dim,
186
+ )
187
+
188
+ def forward(
189
+ self,
190
+ hidden_states: torch.Tensor,
191
+ attention_mask: Optional[torch.Tensor] = None,
192
+ position_ids: Optional[torch.LongTensor] = None,
193
+ past_key_value: Optional[Cache] = None,
194
+ use_cache: bool = False,
195
+ **kwargs,
196
+ ) -> Tuple[torch.Tensor, Optional[Cache]]:
197
+ bsz, q_len, _ = hidden_states.size()
198
+
199
+ q = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
200
+ k = self.k_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
201
+ v = self.v_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
202
+
203
+ cos, sin = self.rotary(v, position_ids)
204
+ q, k = apply_rotary_pos_emb(q, k, cos, sin)
205
+
206
+ if past_key_value is not None:
207
+ k, v = past_key_value.update(k, v, self.layer_idx)
208
+
209
+ k = self._repeat_kv(k)
210
+ v = self._repeat_kv(v)
211
+
212
+ attn_out = F.scaled_dot_product_attention(
213
+ q, k, v,
214
+ attn_mask=(attention_mask.to(q.dtype) if attention_mask is not None else None),
215
+ dropout_p=0.0 if not self.training else self.config.attention_dropout,
216
+ is_causal=(attention_mask is None and q_len > 1),
217
+ )
218
+ attn_out = attn_out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
219
+ return self.o_proj(attn_out), past_key_value
220
+
221
+
222
+ # =============================================================================
223
+ # Linear Attention (Mamba-style, simplified)
224
+ # =============================================================================
225
+ class LinearAttention(nn.Module):
226
+ """Linear attention (Mamba/RWKV-inspired) for long-context efficiency."""
227
+
228
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
229
+ super().__init__()
230
+ self.config = config
231
+ self.layer_idx = layer_idx
232
+ self.hidden_size = config.hidden_size
233
+ self.num_heads = config.num_attention_heads
234
+ self.head_dim = config.head_dim
235
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
236
+ self.k_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
237
+ self.v_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
238
+ self.gate = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
239
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
240
+ self.norm = AETHERV211AttnRMSNorm(self.head_dim, eps=config.rms_norm_eps)
241
+
242
+ def forward(
243
+ self,
244
+ hidden_states: torch.Tensor,
245
+ attention_mask: Optional[torch.Tensor] = None,
246
+ position_ids: Optional[torch.LongTensor] = None,
247
+ past_key_value: Optional[Cache] = None,
248
+ use_cache: bool = False,
249
+ **kwargs,
250
+ ) -> Tuple[torch.Tensor, Optional[Cache]]:
251
+ bsz, q_len, _ = hidden_states.size()
252
+ q = F.elu(self.q_proj(hidden_states), alpha=1.0).view(bsz, q_len, self.num_heads, self.head_dim) + 1
253
+ k = F.elu(self.k_proj(hidden_states), alpha=1.0).view(bsz, q_len, self.num_heads, self.head_dim) + 1
254
+ v = self.v_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim)
255
+ g = self.gate(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).sigmoid()
256
+
257
+ # Linear attention: O(n*d^2) instead of O(n^2*d)
258
+ kv = torch.einsum("bnhd,bnhe->bhde", k, v) # (bsz, h, d, e)
259
+ out = torch.einsum("bnhd,bhde->bnhe", q, kv)
260
+ z = torch.einsum("bnhd,bhd->bnh", q, k.sum(dim=1)).unsqueeze(-1).clamp_min(1e-6)
261
+ out = (out / z) * g
262
+ out = self.norm(out).reshape(bsz, q_len, -1)
263
+ return self.o_proj(out), past_key_value
264
+
265
+
266
+ # =============================================================================
267
+ # Sliding Window Attention
268
+ # =============================================================================
269
+ class SlidingWindowAttention(FullAttention):
270
+ """Standard MHA but limited to local window for efficiency."""
271
+
272
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
273
+ super().__init__(config, layer_idx)
274
+ self.window_size = getattr(config, "sliding_window_size", 512)
275
+
276
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
277
+ past_key_value=None, use_cache=False, **kwargs):
278
+ bsz, q_len, _ = hidden_states.size()
279
+ if attention_mask is None and q_len > self.window_size:
280
+ mask = torch.ones(q_len, q_len, dtype=torch.bool, device=hidden_states.device)
281
+ mask = torch.tril(mask) & torch.triu(mask, diagonal=-self.window_size)
282
+ attention_mask = torch.where(mask, 0.0, float("-inf")).unsqueeze(0).unsqueeze(0)
283
+ return super().forward(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
284
+
285
+
286
+ # =============================================================================
287
+ # Compress Attention (NSA-subset, just compress branch)
288
+ # =============================================================================
289
+ class CompressAttention(nn.Module):
290
+ """Compress branch: reduce KV cache via local average, then full attention on compressed."""
291
+
292
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
293
+ super().__init__()
294
+ self.config = config
295
+ self.layer_idx = layer_idx
296
+ self.compress_block = getattr(config, "compress_block_size", 16)
297
+ self.full_attn = FullAttention(config, layer_idx)
298
+
299
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
300
+ past_key_value=None, use_cache=False, **kwargs):
301
+ bsz, q_len, dim = hidden_states.size()
302
+ # Compress along seq dim by averaging blocks
303
+ if q_len % self.compress_block == 0 and q_len > self.compress_block:
304
+ n_blocks = q_len // self.compress_block
305
+ x_comp = hidden_states.view(bsz, n_blocks, self.compress_block, dim).mean(dim=2)
306
+ pos_comp = position_ids[:, ::self.compress_block] if position_ids is not None else None
307
+ out_comp, kv = self.full_attn(x_comp, None, pos_comp, past_key_value, use_cache)
308
+ # Up-sample by repeat
309
+ out = out_comp.unsqueeze(2).expand(bsz, n_blocks, self.compress_block, dim).reshape(bsz, q_len, dim)
310
+ return out, kv
311
+ return self.full_attn(hidden_states, attention_mask, position_ids, past_key_value, use_cache)
312
+
313
+
314
+ # =============================================================================
315
+ # Hybrid Attention (NSA + Differential combined)
316
+ # =============================================================================
317
+ class HybridAttention(nn.Module):
318
+ """Combine NSA + Differential outputs via learnable gate + final norm (stable).
319
+
320
+ Fix v2 (2026-05-05): added post-merge GroupNorm + gate init=0 (sigmoid(0)=0.5 exact balance)
321
+ + lightly scaled output to prevent 49-layer cumulative divergence.
322
+ """
323
+
324
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
325
+ super().__init__()
326
+ self.nsa = NSAAttention(config, layer_idx)
327
+ self.diff = DifferentialAttention(config, layer_idx)
328
+ # Per-channel gate (richer than scalar), init to 0 → sigmoid(0)=0.5 exact balance
329
+ self.gate = nn.Parameter(torch.zeros(config.hidden_size))
330
+ # Post-merge GroupNorm to stabilize 49-layer stack
331
+ n_groups = 8 if config.hidden_size % 8 == 0 else 1
332
+ self.merge_norm = AETHERV211AttnRMSNorm(config.hidden_size, eps=getattr(config,'rms_norm_eps',1e-6))
333
+
334
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
335
+ past_key_value=None, use_cache=False, **kwargs):
336
+ nsa_out, kv1 = self.nsa(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
337
+ diff_out, kv2 = self.diff(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
338
+ # Per-channel learnable mix: g (sigmoid) per channel
339
+ g = torch.sigmoid(self.gate) # shape (hidden_size,)
340
+ out = g * nsa_out + (1.0 - g) * diff_out
341
+ # Stabilize via GroupNorm: (B, S, H) → (B, H, S) → norm → (B, S, H)
342
+ out = self.merge_norm(out)
343
+ return out, kv1 if kv1 is not None else kv2
344
+
345
+
346
+ # =============================================================================
347
+ # 7-aware Attention Dispatcher
348
+ # =============================================================================
349
+ def build_attention(config: AETHERV211AttnConfig, layer_idx: int) -> nn.Module:
350
+ """Pick attention type based on Latin Square index."""
351
+ attn_type = get_attention_type(layer_idx)
352
+ if attn_type == "nsa":
353
+ return NSAAttention(config, layer_idx)
354
+ elif attn_type == "differential":
355
+ return DifferentialAttention(config, layer_idx)
356
+ elif attn_type == "full":
357
+ return FullAttention(config, layer_idx)
358
+ elif attn_type == "linear":
359
+ return LinearAttention(config, layer_idx)
360
+ elif attn_type == "sliding":
361
+ return SlidingWindowAttention(config, layer_idx)
362
+ elif attn_type == "compress":
363
+ return CompressAttention(config, layer_idx)
364
+ elif attn_type == "hybrid":
365
+ return HybridAttention(config, layer_idx)
366
+ elif attn_type == "mla":
367
+ from aether_pkg.v2_attentions.mla import MLAAttention
368
+ return MLAAttention(config, layer_idx)
369
+ elif attn_type == "mamba2":
370
+ from aether_pkg.v2_attentions.mamba2 import Mamba2Attention
371
+ return Mamba2Attention(config, layer_idx)
372
+ elif attn_type == "gdn":
373
+ from aether_pkg.v2_attentions.gdn import GDNAttention
374
+ return GDNAttention(config, layer_idx)
375
+ elif attn_type == "hyena":
376
+ from aether_pkg.v2_attentions.hyena import HyenaAttention
377
+ return HyenaAttention(config, layer_idx)
378
+ raise ValueError(f"Unknown attention type: {attn_type}")
379
+
380
+
381
+ # =============================================================================
382
+ # MoE Block: 25 experts, top-7 active per token
383
+ # =============================================================================
384
+ class AETHERV211AttnMLP(nn.Module):
385
+ """Single expert MLP (SwiGLU)."""
386
+
387
+ def __init__(self, config: AETHERV211AttnConfig, intermediate_size: Optional[int] = None):
388
+ super().__init__()
389
+ self.hidden_size = config.hidden_size
390
+ self.intermediate_size = intermediate_size or config.expert_intermediate_size
391
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
392
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
393
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
394
+ self.act_fn = ACT2FN[config.hidden_act]
395
+
396
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
397
+ return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
398
+
399
+
400
+ class AETHERV211AttnSparseMoE(nn.Module):
401
+ """25-expert MoE with top-7 active routing.
402
+
403
+ Each layer has a 5-phase cyclic FFN bias to encode 오행 (Five Elements) cycle.
404
+ """
405
+
406
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
407
+ super().__init__()
408
+ self.config = config
409
+ self.layer_idx = layer_idx
410
+ self.hidden_size = config.hidden_size
411
+ self.num_experts = config.num_experts
412
+ self.top_k = config.num_experts_per_tok
413
+ self.ffn_phase = get_ffn_phase(layer_idx) # 0..4 (5-element cycle)
414
+
415
+ # Router: hidden → num_experts logits
416
+ self.gate = nn.Linear(self.hidden_size, self.num_experts, bias=False)
417
+
418
+ # 25 experts (each is a SwiGLU MLP)
419
+ self.experts = nn.ModuleList([
420
+ AETHERV211AttnMLP(config) for _ in range(self.num_experts)
421
+ ])
422
+
423
+ # 오행 cyclic phase bias (learnable, 5 phases)
424
+ self.phase_bias = nn.Parameter(torch.zeros(5, self.num_experts))
425
+
426
+ # Optional shared expert (always active, optional)
427
+ self.use_shared_expert = getattr(config, "use_shared_expert", True)
428
+ if self.use_shared_expert:
429
+ self.shared_expert = AETHERV211AttnMLP(
430
+ config, intermediate_size=config.expert_intermediate_size,
431
+ )
432
+ self.shared_expert_gate = nn.Linear(self.hidden_size, 1, bias=False)
433
+
434
+ def forward(self, hidden_states: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
435
+ bsz, seq_len, dim = hidden_states.shape
436
+ x = hidden_states.view(-1, dim) # (bsz*seq, dim)
437
+
438
+ # Routing
439
+ router_logits = self.gate(x) # (bsz*seq, num_experts)
440
+ # Add 5-phase cyclic bias (오행)
441
+ router_logits = router_logits + self.phase_bias[self.ffn_phase].unsqueeze(0)
442
+
443
+ # Top-k selection
444
+ routing_weights, selected_experts = torch.topk(router_logits, self.top_k, dim=-1)
445
+ routing_weights = F.softmax(routing_weights, dim=-1)
446
+
447
+ # Initialize output
448
+ final_out = torch.zeros_like(x)
449
+
450
+ # Per-expert dispatch (loop is OK for prototype; can be optimized with grouped GEMM later)
451
+ for e in range(self.num_experts):
452
+ mask = (selected_experts == e)
453
+ if not mask.any():
454
+ continue
455
+ token_idx, k_idx = mask.nonzero(as_tuple=True)
456
+ expert_in = x[token_idx]
457
+ expert_out = self.experts[e](expert_in)
458
+ weight = routing_weights[token_idx, k_idx].unsqueeze(-1).to(expert_out.dtype)
459
+ final_out.index_add_(0, token_idx, (expert_out * weight).to(final_out.dtype))
460
+
461
+ # Shared expert
462
+ if self.use_shared_expert:
463
+ shared_out = self.shared_expert(x)
464
+ shared_gate = torch.sigmoid(self.shared_expert_gate(x))
465
+ final_out = final_out + (shared_out * shared_gate).to(final_out.dtype)
466
+
467
+ final_out = final_out.view(bsz, seq_len, dim)
468
+ return final_out, router_logits.view(bsz, seq_len, self.num_experts)
469
+
470
+
471
+ # =============================================================================
472
+ # Decoder Layer: Attention + MoE FFN with 7-aware + 5-phase logic
473
+ # =============================================================================
474
+ class AETHERV211AttnDecoderLayer(nn.Module):
475
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
476
+ super().__init__()
477
+ self.config = config
478
+ self.layer_idx = layer_idx
479
+ self.hidden_size = config.hidden_size
480
+ self.attn_type = get_attention_type(layer_idx)
481
+ self.ffn_phase = get_ffn_phase(layer_idx)
482
+
483
+ # 7-aware attention (1 of 7 types based on Latin square)
484
+ self.self_attn = build_attention(config, layer_idx)
485
+
486
+ # MoE FFN with 5-phase cyclic bias
487
+ self.mlp = AETHERV211AttnSparseMoE(config, layer_idx)
488
+
489
+ # Norms
490
+ self.input_layernorm = AETHERV211AttnRMSNorm(self.hidden_size, eps=config.rms_norm_eps)
491
+ self.post_attention_layernorm = AETHERV211AttnRMSNorm(self.hidden_size, eps=config.rms_norm_eps)
492
+
493
+ def forward(
494
+ self,
495
+ hidden_states: torch.Tensor,
496
+ attention_mask: Optional[torch.Tensor] = None,
497
+ position_ids: Optional[torch.LongTensor] = None,
498
+ past_key_value: Optional[Cache] = None,
499
+ output_router_logits: bool = False,
500
+ use_cache: bool = False,
501
+ **kwargs,
502
+ ) -> Tuple[torch.Tensor, Optional[Cache], Optional[torch.Tensor]]:
503
+ # Self-attention with residual
504
+ residual = hidden_states
505
+ hidden_states = self.input_layernorm(hidden_states)
506
+ hidden_states, kv = self.self_attn(
507
+ hidden_states=hidden_states,
508
+ attention_mask=attention_mask,
509
+ position_ids=position_ids,
510
+ past_key_value=past_key_value,
511
+ use_cache=use_cache,
512
+ **kwargs,
513
+ )
514
+ hidden_states = residual + hidden_states
515
+
516
+ # MoE FFN with residual
517
+ residual = hidden_states
518
+ hidden_states = self.post_attention_layernorm(hidden_states)
519
+ hidden_states, router_logits = self.mlp(hidden_states)
520
+ hidden_states = residual + hidden_states
521
+
522
+ outputs = (hidden_states, kv)
523
+ if output_router_logits:
524
+ outputs = outputs + (router_logits,)
525
+ else:
526
+ outputs = outputs + (None,)
527
+ return outputs
528
+
529
+
530
+ # =============================================================================
531
+ # Pretrained base
532
+ # =============================================================================
533
+ class AETHERV211AttnPreTrainedModel(PreTrainedModel):
534
+ config_class = AETHERV211AttnConfig
535
+ base_model_prefix = "model"
536
+ supports_gradient_checkpointing = True
537
+ _no_split_modules = ["AETHERV211AttnDecoderLayer"]
538
+ _supports_cache_class = True
539
+ _supports_static_cache = False
540
+
541
+ def _init_weights(self, module):
542
+ std = self.config.initializer_range
543
+ if isinstance(module, nn.Linear):
544
+ module.weight.data.normal_(mean=0.0, std=std)
545
+ if module.bias is not None:
546
+ module.bias.data.zero_()
547
+ elif isinstance(module, nn.Embedding):
548
+ module.weight.data.normal_(mean=0.0, std=std)
549
+ if module.padding_idx is not None:
550
+ module.weight.data[module.padding_idx].zero_()
551
+ elif isinstance(module, AETHERV211AttnRMSNorm):
552
+ module.weight.data.fill_(1.0)
553
+
554
+
555
+ # =============================================================================
556
+ # Main Model
557
+ # =============================================================================
558
+ class AETHERV211AttnModel(AETHERV211AttnPreTrainedModel):
559
+ """49-layer decoder-only model with 7-aware attention + MoE."""
560
+
561
+ def __init__(self, config: AETHERV211AttnConfig):
562
+ super().__init__(config)
563
+ self.padding_idx = config.pad_token_id
564
+ self.vocab_size = config.vocab_size
565
+
566
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
567
+ self.layers = nn.ModuleList([
568
+ AETHERV211AttnDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)
569
+ ])
570
+ self.norm = AETHERV211AttnRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
571
+ self.gradient_checkpointing = False
572
+ self.post_init()
573
+
574
+ def get_input_embeddings(self):
575
+ return self.embed_tokens
576
+
577
+ def set_input_embeddings(self, value):
578
+ self.embed_tokens = value
579
+
580
+ def forward(
581
+ self,
582
+ input_ids: Optional[torch.LongTensor] = None,
583
+ attention_mask: Optional[torch.Tensor] = None,
584
+ position_ids: Optional[torch.LongTensor] = None,
585
+ past_key_values: Optional[Cache] = None,
586
+ inputs_embeds: Optional[torch.FloatTensor] = None,
587
+ use_cache: Optional[bool] = None,
588
+ output_attentions: Optional[bool] = None,
589
+ output_hidden_states: Optional[bool] = None,
590
+ output_router_logits: Optional[bool] = None,
591
+ return_dict: Optional[bool] = None,
592
+ **kwargs,
593
+ ) -> Union[Tuple, MoeModelOutputWithPast]:
594
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
595
+ output_hidden_states = output_hidden_states if output_hidden_states is not None else False
596
+ output_router_logits = output_router_logits if output_router_logits is not None else self.config.output_router_logits
597
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
598
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
599
+
600
+ if input_ids is not None and inputs_embeds is not None:
601
+ raise ValueError("Cannot specify both input_ids and inputs_embeds")
602
+ if input_ids is not None:
603
+ bsz, seq_len = input_ids.shape
604
+ elif inputs_embeds is not None:
605
+ bsz, seq_len, _ = inputs_embeds.shape
606
+ else:
607
+ raise ValueError("Either input_ids or inputs_embeds must be provided")
608
+
609
+ if inputs_embeds is None:
610
+ inputs_embeds = self.embed_tokens(input_ids)
611
+
612
+ if use_cache and past_key_values is None:
613
+ past_key_values = DynamicCache()
614
+
615
+ past_seen = past_key_values.get_seq_length() if past_key_values is not None else 0
616
+
617
+ if position_ids is None:
618
+ position_ids = torch.arange(
619
+ past_seen, past_seen + seq_len, device=inputs_embeds.device,
620
+ ).unsqueeze(0)
621
+
622
+ hidden_states = inputs_embeds
623
+
624
+ all_hidden_states = () if output_hidden_states else None
625
+ all_router_logits = () if output_router_logits else None
626
+
627
+ for layer_idx, decoder_layer in enumerate(self.layers):
628
+ if output_hidden_states:
629
+ all_hidden_states += (hidden_states,)
630
+
631
+ if self.gradient_checkpointing and self.training:
632
+ layer_out = self._gradient_checkpointing_func(
633
+ decoder_layer.__call__,
634
+ hidden_states, attention_mask, position_ids,
635
+ past_key_values, output_router_logits, use_cache,
636
+ )
637
+ else:
638
+ layer_out = decoder_layer(
639
+ hidden_states=hidden_states,
640
+ attention_mask=attention_mask,
641
+ position_ids=position_ids,
642
+ past_key_value=past_key_values,
643
+ output_router_logits=output_router_logits,
644
+ use_cache=use_cache,
645
+ )
646
+
647
+ hidden_states = layer_out[0]
648
+ if output_router_logits:
649
+ all_router_logits += (layer_out[2],)
650
+
651
+ hidden_states = self.norm(hidden_states)
652
+ if output_hidden_states:
653
+ all_hidden_states += (hidden_states,)
654
+
655
+ if not return_dict:
656
+ return tuple(v for v in [
657
+ hidden_states, past_key_values, all_hidden_states, None, all_router_logits,
658
+ ] if v is not None)
659
+
660
+ return MoeModelOutputWithPast(
661
+ last_hidden_state=hidden_states,
662
+ past_key_values=past_key_values,
663
+ hidden_states=all_hidden_states,
664
+ attentions=None,
665
+ router_logits=all_router_logits,
666
+ )
667
+
668
+
669
+ # =============================================================================
670
+ # Causal LM Wrapper
671
+ # =============================================================================
672
+ class AETHERV211AttnForCausalLM(AETHERV211AttnPreTrainedModel):
673
+ _tied_weights_keys = ["lm_head.weight"]
674
+
675
+ def __init__(self, config: AETHERV211AttnConfig):
676
+ super().__init__(config)
677
+ self.model = AETHERV211AttnModel(config)
678
+ self.vocab_size = config.vocab_size
679
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
680
+ self.router_aux_loss_coef = getattr(config, "router_aux_loss_coef", 0.001)
681
+ self.num_experts = config.num_experts
682
+ self.num_experts_per_tok = config.num_experts_per_tok
683
+ self.post_init()
684
+
685
+ def get_input_embeddings(self):
686
+ return self.model.embed_tokens
687
+
688
+ def set_input_embeddings(self, value):
689
+ self.model.embed_tokens = value
690
+
691
+ def get_output_embeddings(self):
692
+ return self.lm_head
693
+
694
+ def set_output_embeddings(self, new_embeddings):
695
+ self.lm_head = new_embeddings
696
+
697
+ def get_decoder(self):
698
+ return self.model
699
+
700
+ def forward(
701
+ self,
702
+ input_ids: Optional[torch.LongTensor] = None,
703
+ attention_mask: Optional[torch.Tensor] = None,
704
+ position_ids: Optional[torch.LongTensor] = None,
705
+ past_key_values: Optional[Cache] = None,
706
+ inputs_embeds: Optional[torch.FloatTensor] = None,
707
+ labels: Optional[torch.LongTensor] = None,
708
+ use_cache: Optional[bool] = None,
709
+ output_attentions: Optional[bool] = None,
710
+ output_hidden_states: Optional[bool] = None,
711
+ output_router_logits: Optional[bool] = None,
712
+ return_dict: Optional[bool] = None,
713
+ **kwargs,
714
+ ) -> Union[Tuple, MoeCausalLMOutputWithPast]:
715
+ output_router_logits = output_router_logits if output_router_logits is not None else self.config.output_router_logits
716
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
717
+
718
+ outputs = self.model(
719
+ input_ids=input_ids,
720
+ attention_mask=attention_mask,
721
+ position_ids=position_ids,
722
+ past_key_values=past_key_values,
723
+ inputs_embeds=inputs_embeds,
724
+ use_cache=use_cache,
725
+ output_hidden_states=output_hidden_states,
726
+ output_router_logits=output_router_logits,
727
+ return_dict=True,
728
+ )
729
+ hidden_states = outputs.last_hidden_state
730
+ logits = self.lm_head(hidden_states).float()
731
+
732
+ loss = None
733
+ aux_loss = None
734
+ if labels is not None:
735
+ shift_logits = logits[..., :-1, :].contiguous()
736
+ shift_labels = labels[..., 1:].contiguous()
737
+ loss = F.cross_entropy(
738
+ shift_logits.view(-1, self.vocab_size),
739
+ shift_labels.view(-1),
740
+ ignore_index=-100,
741
+ )
742
+
743
+ if output_router_logits and outputs.router_logits is not None:
744
+ aux_loss = self._compute_router_aux_loss(outputs.router_logits, attention_mask)
745
+ if loss is not None:
746
+ loss = loss + self.router_aux_loss_coef * aux_loss
747
+
748
+ if not return_dict:
749
+ output = (logits,) + tuple(v for v in [
750
+ outputs.past_key_values, outputs.hidden_states, None, outputs.router_logits, aux_loss,
751
+ ] if v is not None)
752
+ return (loss,) + output if loss is not None else output
753
+
754
+ return MoeCausalLMOutputWithPast(
755
+ loss=loss,
756
+ aux_loss=aux_loss,
757
+ logits=logits,
758
+ past_key_values=outputs.past_key_values,
759
+ hidden_states=outputs.hidden_states,
760
+ attentions=None,
761
+ router_logits=outputs.router_logits,
762
+ )
763
+
764
+ def _compute_router_aux_loss(self, router_logits: Tuple[torch.Tensor, ...], attention_mask=None):
765
+ """Standard switch-transformer auxiliary loss for load balancing."""
766
+ if router_logits is None or len(router_logits) == 0:
767
+ return None
768
+ # Each router_logits[i] shape: (bsz, seq, num_experts) → flatten to (n_tokens, num_experts)
769
+ flat = []
770
+ for r in router_logits:
771
+ if r is None:
772
+ continue
773
+ flat.append(r.reshape(-1, self.num_experts))
774
+ if not flat:
775
+ return None
776
+ all_router_logits = torch.cat(flat, dim=0) # (total_tokens, num_experts)
777
+
778
+ routing_weights = F.softmax(all_router_logits.float(), dim=-1)
779
+ _, selected_experts = torch.topk(routing_weights, self.num_experts_per_tok, dim=-1)
780
+
781
+ # Expert mask: (n_tokens, top_k, num_experts)
782
+ expert_mask = F.one_hot(selected_experts, num_classes=self.num_experts).float()
783
+ # Tokens-per-expert frequency: average over (n_tokens, top_k) dims → (num_experts,)
784
+ tokens_per_expert = expert_mask.mean(dim=(0, 1))
785
+ # Router prob per expert: (num_experts,)
786
+ router_prob_per_expert = routing_weights.mean(dim=0)
787
+ # aux_loss = num_experts * sum(token_freq * prob)
788
+ return self.num_experts * torch.sum(tokens_per_expert * router_prob_per_expert)
789
+
790
+ def prepare_inputs_for_generation(
791
+ self,
792
+ input_ids,
793
+ past_key_values=None,
794
+ attention_mask=None,
795
+ inputs_embeds=None,
796
+ **kwargs,
797
+ ):
798
+ if past_key_values is not None:
799
+ input_ids = input_ids[:, -1:]
800
+ position_ids = kwargs.get("position_ids", None)
801
+ if attention_mask is not None and position_ids is None:
802
+ position_ids = attention_mask.long().cumsum(-1) - 1
803
+ position_ids.masked_fill_(attention_mask == 0, 1)
804
+ if past_key_values is not None:
805
+ position_ids = position_ids[:, -input_ids.shape[1]:]
806
+ return {
807
+ "input_ids": input_ids,
808
+ "position_ids": position_ids,
809
+ "past_key_values": past_key_values,
810
+ "use_cache": kwargs.get("use_cache"),
811
+ "attention_mask": attention_mask,
812
+ }
813
+
814
+
815
+ # =============================================================================
816
+ # Helper: Latin Square Layer Map (for analysis / debugging)
817
+ # =============================================================================
818
+ def print_layer_map(num_layers: int = 49):
819
+ """Print the Latin Square attention type map."""
820
+ print(f"=== AETHER-V2-7way Layer Map ({num_layers} layers) ===")
821
+ for L in range(num_layers):
822
+ attn = get_attention_type(L)
823
+ phase = get_ffn_phase(L)
824
+ row = L // 7
825
+ col = L % 7
826
+ print(f" L{L:02d} (row={row} col={col}): attn={attn:12s} ffn_phase={phase}")
827
+
828
+
829
+ __all__ = [
830
+ "AETHERV211AttnConfig",
831
+ "AETHERV211AttnModel",
832
+ "AETHERV211AttnForCausalLM",
833
+ "AETHERV211AttnPreTrainedModel",
834
+ "AETHERV211AttnDecoderLayer",
835
+ "AETHERV211AttnSparseMoE",
836
+ "build_attention",
837
+ "get_attention_type",
838
+ "get_ffn_phase",
839
+ "LATIN_SQUARE_7x7",
840
+ "ATTN_TYPES",
841
+ "print_layer_map",
842
+ ]
aether_pkg/modeling_aether_v2_11way.py.groupnorm_backup ADDED
@@ -0,0 +1,842 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2026 VIDRAFT (비드래프트). All rights reserved.
3
+ #
4
+ # AETHER-V2-7way: 7-aware attention + 7×7 Latin Square 49-layer MoE
5
+ # Built upon HuggingFace Transformers conventions.
6
+ #
7
+ # Architecture:
8
+ # - 49 layers organized as 7×7 Latin Square
9
+ # - 7 distinct attention types (NSA, Differential, Full, Linear, Sliding, Compress, Hybrid)
10
+ # - 25 experts per layer, top-7 active per token
11
+ # - Each row of latin square = 1 cycle of 7 attention types
12
+ # - Each column = different ordering (Latin square property)
13
+ #
14
+ # Layer index → (row, col) → attention type via LATIN_SQUARE_7x7
15
+ #
16
+ """PyTorch AETHER-V2-7way model."""
17
+
18
+ from __future__ import annotations
19
+ import math
20
+ import warnings
21
+ from typing import List, Optional, Tuple, Union
22
+
23
+ import torch
24
+ import torch.nn as nn
25
+ import torch.nn.functional as F
26
+ from torch.nn import CrossEntropyLoss
27
+
28
+ from transformers.activations import ACT2FN
29
+ from transformers.cache_utils import Cache, DynamicCache
30
+ from transformers.modeling_outputs import (
31
+ BaseModelOutputWithPast,
32
+ CausalLMOutputWithPast,
33
+ MoeCausalLMOutputWithPast,
34
+ MoeModelOutputWithPast,
35
+ )
36
+ from transformers.modeling_utils import PreTrainedModel
37
+ from transformers.utils import logging
38
+
39
+ from .configuration_aether_v2_11attn import AETHERV211AttnConfig
40
+
41
+ # 7-aware attention modules (already authored, in v2_attentions/)
42
+ from .v2_attentions.nsa import NSAAttention
43
+ from .v2_attentions.differential import DifferentialAttention
44
+
45
+ logger = logging.get_logger(__name__)
46
+
47
+
48
+ # =============================================================================
49
+ # 7×7 Latin Square — Layer → (attention_type, ffn_phase) 매핑
50
+ # =============================================================================
51
+ # Latin Square property: each row & column has each of {0..6} exactly once.
52
+ # row = layer // 7 (0..6)
53
+ # col = layer % 7 (0..6)
54
+ # attention_type = LATIN_SQUARE_7x7[row][col]
55
+ #
56
+ # 5-element cyclic FFN phase (오행 상생 — Q2B OhengGate inspired):
57
+ # ffn_phase = layer % 5
58
+ #
59
+ # Cyclic Latin Square 11x11 (prime number — Prime Series)
60
+ LATIN_SQUARE_11x11 = [
61
+ [(i + j) % 11 for j in range(11)] for i in range(11)
62
+ ]
63
+
64
+ # Backward compat alias
65
+ LATIN_SQUARE_7x7 = LATIN_SQUARE_11x11 # for v2_7way imports
66
+
67
+ # Attention type names (0..6)
68
+ ATTN_TYPES = [
69
+ "nsa", # 0: Native Sparse Attention (3-branch) [Transformer]
70
+ "differential", # 1: Differential Attention (λ-gated) [Transformer]
71
+ "full", # 2: Full Attention (standard) [Transformer]
72
+ "mla", # 3: Multi-head Latent (DeepSeek-V2/V3) [Transformer]
73
+ "sliding", # 4: Sliding Window Attention [Transformer]
74
+ "compress", # 5: Compress-only (NSA subset) [Transformer]
75
+ "hybrid", # 6: NSA + Differential combined [Transformer]
76
+ "linear", # 7: Linear Attention (Mamba-style) [Non-Transformer]
77
+ "mamba2", # 8: Mamba2 (SSM) [Non-Transformer]
78
+ "gdn", # 9: Gated Delta Network [Non-Transformer]
79
+ "hyena", # 10: Hyena (Convolutional) [Non-Transformer]
80
+ ]
81
+
82
+
83
+ def get_attention_type(layer_idx: int) -> str:
84
+ """Layer index → attention type via 11x11 Latin Square."""
85
+ row = layer_idx // 11
86
+ col = layer_idx % 11
87
+ type_idx = LATIN_SQUARE_11x11[row][col]
88
+ return ATTN_TYPES[type_idx]
89
+
90
+
91
+ def get_ffn_phase(layer_idx: int) -> int:
92
+ """Layer index → 5-element cyclic phase (오행)."""
93
+ return layer_idx % 5
94
+
95
+
96
+ # =============================================================================
97
+ # Rotary Position Embedding (RoPE)
98
+ # =============================================================================
99
+ class AETHERV211AttnRotaryEmbedding(nn.Module):
100
+ def __init__(self, dim: int, max_pos: int = 4096, base: float = 10000.0, device=None):
101
+ super().__init__()
102
+ self.dim = dim
103
+ self.max_pos = max_pos
104
+ self.base = base
105
+ inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim))
106
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
107
+ self._build_cos_sin_cache(max_pos, device or torch.device("cpu"))
108
+
109
+ def _build_cos_sin_cache(self, seq_len: int, device, dtype=torch.float32):
110
+ t = torch.arange(seq_len, device=device, dtype=torch.float32)
111
+ freqs = torch.outer(t, self.inv_freq)
112
+ emb = torch.cat([freqs, freqs], dim=-1)
113
+ self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)
114
+ self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)
115
+
116
+ @torch.no_grad()
117
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor):
118
+ if position_ids.max() >= self.cos_cached.size(0):
119
+ self._build_cos_sin_cache(int(position_ids.max() + 1), x.device, x.dtype)
120
+ cos = self.cos_cached[position_ids].to(x.dtype)
121
+ sin = self.sin_cached[position_ids].to(x.dtype)
122
+ return cos, sin
123
+
124
+
125
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
126
+ x1, x2 = x.chunk(2, dim=-1)
127
+ return torch.cat([-x2, x1], dim=-1)
128
+
129
+
130
+ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
131
+ cos = cos.unsqueeze(unsqueeze_dim)
132
+ sin = sin.unsqueeze(unsqueeze_dim)
133
+ q_embed = (q * cos) + (rotate_half(q) * sin)
134
+ k_embed = (k * cos) + (rotate_half(k) * sin)
135
+ return q_embed, k_embed
136
+
137
+
138
+ # =============================================================================
139
+ # RMSNorm
140
+ # =============================================================================
141
+ class AETHERV211AttnRMSNorm(nn.Module):
142
+ def __init__(self, hidden_size: int, eps: float = 1e-6):
143
+ super().__init__()
144
+ self.weight = nn.Parameter(torch.ones(hidden_size))
145
+ self.eps = eps
146
+
147
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
148
+ in_dtype = hidden_states.dtype
149
+ hidden_states = hidden_states.to(torch.float32)
150
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
151
+ hidden_states = hidden_states * torch.rsqrt(variance + self.eps)
152
+ return self.weight * hidden_states.to(in_dtype)
153
+
154
+
155
+ # =============================================================================
156
+ # Standard Multi-Head Attention (Full Attention type)
157
+ # =============================================================================
158
+ class FullAttention(nn.Module):
159
+ """Standard multi-head attention with GQA support."""
160
+
161
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
162
+ super().__init__()
163
+ self.config = config
164
+ self.layer_idx = layer_idx
165
+ self.hidden_size = config.hidden_size
166
+ self.num_heads = config.num_attention_heads
167
+ self.num_kv_heads = getattr(config, "num_key_value_heads", config.num_attention_heads)
168
+ self.head_dim = config.head_dim
169
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
170
+
171
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
172
+ self.k_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
173
+ self.v_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
174
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
175
+
176
+ self.rotary = AETHERV211AttnRotaryEmbedding(
177
+ self.head_dim, config.max_position_embeddings, config.rope_theta,
178
+ )
179
+
180
+ def _repeat_kv(self, x: torch.Tensor) -> torch.Tensor:
181
+ if self.num_kv_groups == 1:
182
+ return x
183
+ bsz, n_kv, seq, dim = x.shape
184
+ return x[:, :, None, :, :].expand(bsz, n_kv, self.num_kv_groups, seq, dim).reshape(
185
+ bsz, n_kv * self.num_kv_groups, seq, dim,
186
+ )
187
+
188
+ def forward(
189
+ self,
190
+ hidden_states: torch.Tensor,
191
+ attention_mask: Optional[torch.Tensor] = None,
192
+ position_ids: Optional[torch.LongTensor] = None,
193
+ past_key_value: Optional[Cache] = None,
194
+ use_cache: bool = False,
195
+ **kwargs,
196
+ ) -> Tuple[torch.Tensor, Optional[Cache]]:
197
+ bsz, q_len, _ = hidden_states.size()
198
+
199
+ q = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
200
+ k = self.k_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
201
+ v = self.v_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
202
+
203
+ cos, sin = self.rotary(v, position_ids)
204
+ q, k = apply_rotary_pos_emb(q, k, cos, sin)
205
+
206
+ if past_key_value is not None:
207
+ k, v = past_key_value.update(k, v, self.layer_idx)
208
+
209
+ k = self._repeat_kv(k)
210
+ v = self._repeat_kv(v)
211
+
212
+ attn_out = F.scaled_dot_product_attention(
213
+ q, k, v,
214
+ attn_mask=(attention_mask.to(q.dtype) if attention_mask is not None else None),
215
+ dropout_p=0.0 if not self.training else self.config.attention_dropout,
216
+ is_causal=(attention_mask is None and q_len > 1),
217
+ )
218
+ attn_out = attn_out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
219
+ return self.o_proj(attn_out), past_key_value
220
+
221
+
222
+ # =============================================================================
223
+ # Linear Attention (Mamba-style, simplified)
224
+ # =============================================================================
225
+ class LinearAttention(nn.Module):
226
+ """Linear attention (Mamba/RWKV-inspired) for long-context efficiency."""
227
+
228
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
229
+ super().__init__()
230
+ self.config = config
231
+ self.layer_idx = layer_idx
232
+ self.hidden_size = config.hidden_size
233
+ self.num_heads = config.num_attention_heads
234
+ self.head_dim = config.head_dim
235
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
236
+ self.k_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
237
+ self.v_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
238
+ self.gate = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
239
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
240
+ self.norm = AETHERV211AttnRMSNorm(self.head_dim, eps=config.rms_norm_eps)
241
+
242
+ def forward(
243
+ self,
244
+ hidden_states: torch.Tensor,
245
+ attention_mask: Optional[torch.Tensor] = None,
246
+ position_ids: Optional[torch.LongTensor] = None,
247
+ past_key_value: Optional[Cache] = None,
248
+ use_cache: bool = False,
249
+ **kwargs,
250
+ ) -> Tuple[torch.Tensor, Optional[Cache]]:
251
+ bsz, q_len, _ = hidden_states.size()
252
+ q = F.elu(self.q_proj(hidden_states), alpha=1.0).view(bsz, q_len, self.num_heads, self.head_dim) + 1
253
+ k = F.elu(self.k_proj(hidden_states), alpha=1.0).view(bsz, q_len, self.num_heads, self.head_dim) + 1
254
+ v = self.v_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim)
255
+ g = self.gate(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).sigmoid()
256
+
257
+ # Linear attention: O(n*d^2) instead of O(n^2*d)
258
+ kv = torch.einsum("bnhd,bnhe->bhde", k, v) # (bsz, h, d, e)
259
+ out = torch.einsum("bnhd,bhde->bnhe", q, kv)
260
+ z = torch.einsum("bnhd,bhd->bnh", q, k.sum(dim=1)).unsqueeze(-1).clamp_min(1e-6)
261
+ out = (out / z) * g
262
+ out = self.norm(out).reshape(bsz, q_len, -1)
263
+ return self.o_proj(out), past_key_value
264
+
265
+
266
+ # =============================================================================
267
+ # Sliding Window Attention
268
+ # =============================================================================
269
+ class SlidingWindowAttention(FullAttention):
270
+ """Standard MHA but limited to local window for efficiency."""
271
+
272
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
273
+ super().__init__(config, layer_idx)
274
+ self.window_size = getattr(config, "sliding_window_size", 512)
275
+
276
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
277
+ past_key_value=None, use_cache=False, **kwargs):
278
+ bsz, q_len, _ = hidden_states.size()
279
+ if attention_mask is None and q_len > self.window_size:
280
+ mask = torch.ones(q_len, q_len, dtype=torch.bool, device=hidden_states.device)
281
+ mask = torch.tril(mask) & torch.triu(mask, diagonal=-self.window_size)
282
+ attention_mask = torch.where(mask, 0.0, float("-inf")).unsqueeze(0).unsqueeze(0)
283
+ return super().forward(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
284
+
285
+
286
+ # =============================================================================
287
+ # Compress Attention (NSA-subset, just compress branch)
288
+ # =============================================================================
289
+ class CompressAttention(nn.Module):
290
+ """Compress branch: reduce KV cache via local average, then full attention on compressed."""
291
+
292
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
293
+ super().__init__()
294
+ self.config = config
295
+ self.layer_idx = layer_idx
296
+ self.compress_block = getattr(config, "compress_block_size", 16)
297
+ self.full_attn = FullAttention(config, layer_idx)
298
+
299
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
300
+ past_key_value=None, use_cache=False, **kwargs):
301
+ bsz, q_len, dim = hidden_states.size()
302
+ # Compress along seq dim by averaging blocks
303
+ if q_len % self.compress_block == 0 and q_len > self.compress_block:
304
+ n_blocks = q_len // self.compress_block
305
+ x_comp = hidden_states.view(bsz, n_blocks, self.compress_block, dim).mean(dim=2)
306
+ pos_comp = position_ids[:, ::self.compress_block] if position_ids is not None else None
307
+ out_comp, kv = self.full_attn(x_comp, None, pos_comp, past_key_value, use_cache)
308
+ # Up-sample by repeat
309
+ out = out_comp.unsqueeze(2).expand(bsz, n_blocks, self.compress_block, dim).reshape(bsz, q_len, dim)
310
+ return out, kv
311
+ return self.full_attn(hidden_states, attention_mask, position_ids, past_key_value, use_cache)
312
+
313
+
314
+ # =============================================================================
315
+ # Hybrid Attention (NSA + Differential combined)
316
+ # =============================================================================
317
+ class HybridAttention(nn.Module):
318
+ """Combine NSA + Differential outputs via learnable gate + final norm (stable).
319
+
320
+ Fix v2 (2026-05-05): added post-merge GroupNorm + gate init=0 (sigmoid(0)=0.5 exact balance)
321
+ + lightly scaled output to prevent 49-layer cumulative divergence.
322
+ """
323
+
324
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
325
+ super().__init__()
326
+ self.nsa = NSAAttention(config, layer_idx)
327
+ self.diff = DifferentialAttention(config, layer_idx)
328
+ # Per-channel gate (richer than scalar), init to 0 → sigmoid(0)=0.5 exact balance
329
+ self.gate = nn.Parameter(torch.zeros(config.hidden_size))
330
+ # Post-merge GroupNorm to stabilize 49-layer stack
331
+ n_groups = 8 if config.hidden_size % 8 == 0 else 1
332
+ self.merge_norm = nn.GroupNorm(num_groups=n_groups, num_channels=config.hidden_size, eps=1e-5)
333
+
334
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
335
+ past_key_value=None, use_cache=False, **kwargs):
336
+ nsa_out, kv1 = self.nsa(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
337
+ diff_out, kv2 = self.diff(hidden_states, attention_mask, position_ids, past_key_value, use_cache, **kwargs)
338
+ # Per-channel learnable mix: g (sigmoid) per channel
339
+ g = torch.sigmoid(self.gate) # shape (hidden_size,)
340
+ out = g * nsa_out + (1.0 - g) * diff_out
341
+ # Stabilize via GroupNorm: (B, S, H) → (B, H, S) → norm → (B, S, H)
342
+ out = self.merge_norm(out.transpose(1, 2)).transpose(1, 2)
343
+ return out, kv1 if kv1 is not None else kv2
344
+
345
+
346
+ # =============================================================================
347
+ # 7-aware Attention Dispatcher
348
+ # =============================================================================
349
+ def build_attention(config: AETHERV211AttnConfig, layer_idx: int) -> nn.Module:
350
+ """Pick attention type based on Latin Square index."""
351
+ attn_type = get_attention_type(layer_idx)
352
+ if attn_type == "nsa":
353
+ return NSAAttention(config, layer_idx)
354
+ elif attn_type == "differential":
355
+ return DifferentialAttention(config, layer_idx)
356
+ elif attn_type == "full":
357
+ return FullAttention(config, layer_idx)
358
+ elif attn_type == "linear":
359
+ return LinearAttention(config, layer_idx)
360
+ elif attn_type == "sliding":
361
+ return SlidingWindowAttention(config, layer_idx)
362
+ elif attn_type == "compress":
363
+ return CompressAttention(config, layer_idx)
364
+ elif attn_type == "hybrid":
365
+ return HybridAttention(config, layer_idx)
366
+ elif attn_type == "mla":
367
+ from aether_pkg.v2_attentions.mla import MLAAttention
368
+ return MLAAttention(config, layer_idx)
369
+ elif attn_type == "mamba2":
370
+ from aether_pkg.v2_attentions.mamba2 import Mamba2Attention
371
+ return Mamba2Attention(config, layer_idx)
372
+ elif attn_type == "gdn":
373
+ from aether_pkg.v2_attentions.gdn import GDNAttention
374
+ return GDNAttention(config, layer_idx)
375
+ elif attn_type == "hyena":
376
+ from aether_pkg.v2_attentions.hyena import HyenaAttention
377
+ return HyenaAttention(config, layer_idx)
378
+ raise ValueError(f"Unknown attention type: {attn_type}")
379
+
380
+
381
+ # =============================================================================
382
+ # MoE Block: 25 experts, top-7 active per token
383
+ # =============================================================================
384
+ class AETHERV211AttnMLP(nn.Module):
385
+ """Single expert MLP (SwiGLU)."""
386
+
387
+ def __init__(self, config: AETHERV211AttnConfig, intermediate_size: Optional[int] = None):
388
+ super().__init__()
389
+ self.hidden_size = config.hidden_size
390
+ self.intermediate_size = intermediate_size or config.expert_intermediate_size
391
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
392
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
393
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
394
+ self.act_fn = ACT2FN[config.hidden_act]
395
+
396
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
397
+ return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
398
+
399
+
400
+ class AETHERV211AttnSparseMoE(nn.Module):
401
+ """25-expert MoE with top-7 active routing.
402
+
403
+ Each layer has a 5-phase cyclic FFN bias to encode 오행 (Five Elements) cycle.
404
+ """
405
+
406
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
407
+ super().__init__()
408
+ self.config = config
409
+ self.layer_idx = layer_idx
410
+ self.hidden_size = config.hidden_size
411
+ self.num_experts = config.num_experts
412
+ self.top_k = config.num_experts_per_tok
413
+ self.ffn_phase = get_ffn_phase(layer_idx) # 0..4 (5-element cycle)
414
+
415
+ # Router: hidden → num_experts logits
416
+ self.gate = nn.Linear(self.hidden_size, self.num_experts, bias=False)
417
+
418
+ # 25 experts (each is a SwiGLU MLP)
419
+ self.experts = nn.ModuleList([
420
+ AETHERV211AttnMLP(config) for _ in range(self.num_experts)
421
+ ])
422
+
423
+ # 오행 cyclic phase bias (learnable, 5 phases)
424
+ self.phase_bias = nn.Parameter(torch.zeros(5, self.num_experts))
425
+
426
+ # Optional shared expert (always active, optional)
427
+ self.use_shared_expert = getattr(config, "use_shared_expert", True)
428
+ if self.use_shared_expert:
429
+ self.shared_expert = AETHERV211AttnMLP(
430
+ config, intermediate_size=config.expert_intermediate_size,
431
+ )
432
+ self.shared_expert_gate = nn.Linear(self.hidden_size, 1, bias=False)
433
+
434
+ def forward(self, hidden_states: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
435
+ bsz, seq_len, dim = hidden_states.shape
436
+ x = hidden_states.view(-1, dim) # (bsz*seq, dim)
437
+
438
+ # Routing
439
+ router_logits = self.gate(x) # (bsz*seq, num_experts)
440
+ # Add 5-phase cyclic bias (오행)
441
+ router_logits = router_logits + self.phase_bias[self.ffn_phase].unsqueeze(0)
442
+
443
+ # Top-k selection
444
+ routing_weights, selected_experts = torch.topk(router_logits, self.top_k, dim=-1)
445
+ routing_weights = F.softmax(routing_weights, dim=-1)
446
+
447
+ # Initialize output
448
+ final_out = torch.zeros_like(x)
449
+
450
+ # Per-expert dispatch (loop is OK for prototype; can be optimized with grouped GEMM later)
451
+ for e in range(self.num_experts):
452
+ mask = (selected_experts == e)
453
+ if not mask.any():
454
+ continue
455
+ token_idx, k_idx = mask.nonzero(as_tuple=True)
456
+ expert_in = x[token_idx]
457
+ expert_out = self.experts[e](expert_in)
458
+ weight = routing_weights[token_idx, k_idx].unsqueeze(-1).to(expert_out.dtype)
459
+ final_out.index_add_(0, token_idx, (expert_out * weight).to(final_out.dtype))
460
+
461
+ # Shared expert
462
+ if self.use_shared_expert:
463
+ shared_out = self.shared_expert(x)
464
+ shared_gate = torch.sigmoid(self.shared_expert_gate(x))
465
+ final_out = final_out + (shared_out * shared_gate).to(final_out.dtype)
466
+
467
+ final_out = final_out.view(bsz, seq_len, dim)
468
+ return final_out, router_logits.view(bsz, seq_len, self.num_experts)
469
+
470
+
471
+ # =============================================================================
472
+ # Decoder Layer: Attention + MoE FFN with 7-aware + 5-phase logic
473
+ # =============================================================================
474
+ class AETHERV211AttnDecoderLayer(nn.Module):
475
+ def __init__(self, config: AETHERV211AttnConfig, layer_idx: int):
476
+ super().__init__()
477
+ self.config = config
478
+ self.layer_idx = layer_idx
479
+ self.hidden_size = config.hidden_size
480
+ self.attn_type = get_attention_type(layer_idx)
481
+ self.ffn_phase = get_ffn_phase(layer_idx)
482
+
483
+ # 7-aware attention (1 of 7 types based on Latin square)
484
+ self.self_attn = build_attention(config, layer_idx)
485
+
486
+ # MoE FFN with 5-phase cyclic bias
487
+ self.mlp = AETHERV211AttnSparseMoE(config, layer_idx)
488
+
489
+ # Norms
490
+ self.input_layernorm = AETHERV211AttnRMSNorm(self.hidden_size, eps=config.rms_norm_eps)
491
+ self.post_attention_layernorm = AETHERV211AttnRMSNorm(self.hidden_size, eps=config.rms_norm_eps)
492
+
493
+ def forward(
494
+ self,
495
+ hidden_states: torch.Tensor,
496
+ attention_mask: Optional[torch.Tensor] = None,
497
+ position_ids: Optional[torch.LongTensor] = None,
498
+ past_key_value: Optional[Cache] = None,
499
+ output_router_logits: bool = False,
500
+ use_cache: bool = False,
501
+ **kwargs,
502
+ ) -> Tuple[torch.Tensor, Optional[Cache], Optional[torch.Tensor]]:
503
+ # Self-attention with residual
504
+ residual = hidden_states
505
+ hidden_states = self.input_layernorm(hidden_states)
506
+ hidden_states, kv = self.self_attn(
507
+ hidden_states=hidden_states,
508
+ attention_mask=attention_mask,
509
+ position_ids=position_ids,
510
+ past_key_value=past_key_value,
511
+ use_cache=use_cache,
512
+ **kwargs,
513
+ )
514
+ hidden_states = residual + hidden_states
515
+
516
+ # MoE FFN with residual
517
+ residual = hidden_states
518
+ hidden_states = self.post_attention_layernorm(hidden_states)
519
+ hidden_states, router_logits = self.mlp(hidden_states)
520
+ hidden_states = residual + hidden_states
521
+
522
+ outputs = (hidden_states, kv)
523
+ if output_router_logits:
524
+ outputs = outputs + (router_logits,)
525
+ else:
526
+ outputs = outputs + (None,)
527
+ return outputs
528
+
529
+
530
+ # =============================================================================
531
+ # Pretrained base
532
+ # =============================================================================
533
+ class AETHERV211AttnPreTrainedModel(PreTrainedModel):
534
+ config_class = AETHERV211AttnConfig
535
+ base_model_prefix = "model"
536
+ supports_gradient_checkpointing = True
537
+ _no_split_modules = ["AETHERV211AttnDecoderLayer"]
538
+ _supports_cache_class = True
539
+ _supports_static_cache = False
540
+
541
+ def _init_weights(self, module):
542
+ std = self.config.initializer_range
543
+ if isinstance(module, nn.Linear):
544
+ module.weight.data.normal_(mean=0.0, std=std)
545
+ if module.bias is not None:
546
+ module.bias.data.zero_()
547
+ elif isinstance(module, nn.Embedding):
548
+ module.weight.data.normal_(mean=0.0, std=std)
549
+ if module.padding_idx is not None:
550
+ module.weight.data[module.padding_idx].zero_()
551
+ elif isinstance(module, AETHERV211AttnRMSNorm):
552
+ module.weight.data.fill_(1.0)
553
+
554
+
555
+ # =============================================================================
556
+ # Main Model
557
+ # =============================================================================
558
+ class AETHERV211AttnModel(AETHERV211AttnPreTrainedModel):
559
+ """49-layer decoder-only model with 7-aware attention + MoE."""
560
+
561
+ def __init__(self, config: AETHERV211AttnConfig):
562
+ super().__init__(config)
563
+ self.padding_idx = config.pad_token_id
564
+ self.vocab_size = config.vocab_size
565
+
566
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
567
+ self.layers = nn.ModuleList([
568
+ AETHERV211AttnDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)
569
+ ])
570
+ self.norm = AETHERV211AttnRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
571
+ self.gradient_checkpointing = False
572
+ self.post_init()
573
+
574
+ def get_input_embeddings(self):
575
+ return self.embed_tokens
576
+
577
+ def set_input_embeddings(self, value):
578
+ self.embed_tokens = value
579
+
580
+ def forward(
581
+ self,
582
+ input_ids: Optional[torch.LongTensor] = None,
583
+ attention_mask: Optional[torch.Tensor] = None,
584
+ position_ids: Optional[torch.LongTensor] = None,
585
+ past_key_values: Optional[Cache] = None,
586
+ inputs_embeds: Optional[torch.FloatTensor] = None,
587
+ use_cache: Optional[bool] = None,
588
+ output_attentions: Optional[bool] = None,
589
+ output_hidden_states: Optional[bool] = None,
590
+ output_router_logits: Optional[bool] = None,
591
+ return_dict: Optional[bool] = None,
592
+ **kwargs,
593
+ ) -> Union[Tuple, MoeModelOutputWithPast]:
594
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
595
+ output_hidden_states = output_hidden_states if output_hidden_states is not None else False
596
+ output_router_logits = output_router_logits if output_router_logits is not None else self.config.output_router_logits
597
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
598
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
599
+
600
+ if input_ids is not None and inputs_embeds is not None:
601
+ raise ValueError("Cannot specify both input_ids and inputs_embeds")
602
+ if input_ids is not None:
603
+ bsz, seq_len = input_ids.shape
604
+ elif inputs_embeds is not None:
605
+ bsz, seq_len, _ = inputs_embeds.shape
606
+ else:
607
+ raise ValueError("Either input_ids or inputs_embeds must be provided")
608
+
609
+ if inputs_embeds is None:
610
+ inputs_embeds = self.embed_tokens(input_ids)
611
+
612
+ if use_cache and past_key_values is None:
613
+ past_key_values = DynamicCache()
614
+
615
+ past_seen = past_key_values.get_seq_length() if past_key_values is not None else 0
616
+
617
+ if position_ids is None:
618
+ position_ids = torch.arange(
619
+ past_seen, past_seen + seq_len, device=inputs_embeds.device,
620
+ ).unsqueeze(0)
621
+
622
+ hidden_states = inputs_embeds
623
+
624
+ all_hidden_states = () if output_hidden_states else None
625
+ all_router_logits = () if output_router_logits else None
626
+
627
+ for layer_idx, decoder_layer in enumerate(self.layers):
628
+ if output_hidden_states:
629
+ all_hidden_states += (hidden_states,)
630
+
631
+ if self.gradient_checkpointing and self.training:
632
+ layer_out = self._gradient_checkpointing_func(
633
+ decoder_layer.__call__,
634
+ hidden_states, attention_mask, position_ids,
635
+ past_key_values, output_router_logits, use_cache,
636
+ )
637
+ else:
638
+ layer_out = decoder_layer(
639
+ hidden_states=hidden_states,
640
+ attention_mask=attention_mask,
641
+ position_ids=position_ids,
642
+ past_key_value=past_key_values,
643
+ output_router_logits=output_router_logits,
644
+ use_cache=use_cache,
645
+ )
646
+
647
+ hidden_states = layer_out[0]
648
+ if output_router_logits:
649
+ all_router_logits += (layer_out[2],)
650
+
651
+ hidden_states = self.norm(hidden_states)
652
+ if output_hidden_states:
653
+ all_hidden_states += (hidden_states,)
654
+
655
+ if not return_dict:
656
+ return tuple(v for v in [
657
+ hidden_states, past_key_values, all_hidden_states, None, all_router_logits,
658
+ ] if v is not None)
659
+
660
+ return MoeModelOutputWithPast(
661
+ last_hidden_state=hidden_states,
662
+ past_key_values=past_key_values,
663
+ hidden_states=all_hidden_states,
664
+ attentions=None,
665
+ router_logits=all_router_logits,
666
+ )
667
+
668
+
669
+ # =============================================================================
670
+ # Causal LM Wrapper
671
+ # =============================================================================
672
+ class AETHERV211AttnForCausalLM(AETHERV211AttnPreTrainedModel):
673
+ _tied_weights_keys = ["lm_head.weight"]
674
+
675
+ def __init__(self, config: AETHERV211AttnConfig):
676
+ super().__init__(config)
677
+ self.model = AETHERV211AttnModel(config)
678
+ self.vocab_size = config.vocab_size
679
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
680
+ self.router_aux_loss_coef = getattr(config, "router_aux_loss_coef", 0.001)
681
+ self.num_experts = config.num_experts
682
+ self.num_experts_per_tok = config.num_experts_per_tok
683
+ self.post_init()
684
+
685
+ def get_input_embeddings(self):
686
+ return self.model.embed_tokens
687
+
688
+ def set_input_embeddings(self, value):
689
+ self.model.embed_tokens = value
690
+
691
+ def get_output_embeddings(self):
692
+ return self.lm_head
693
+
694
+ def set_output_embeddings(self, new_embeddings):
695
+ self.lm_head = new_embeddings
696
+
697
+ def get_decoder(self):
698
+ return self.model
699
+
700
+ def forward(
701
+ self,
702
+ input_ids: Optional[torch.LongTensor] = None,
703
+ attention_mask: Optional[torch.Tensor] = None,
704
+ position_ids: Optional[torch.LongTensor] = None,
705
+ past_key_values: Optional[Cache] = None,
706
+ inputs_embeds: Optional[torch.FloatTensor] = None,
707
+ labels: Optional[torch.LongTensor] = None,
708
+ use_cache: Optional[bool] = None,
709
+ output_attentions: Optional[bool] = None,
710
+ output_hidden_states: Optional[bool] = None,
711
+ output_router_logits: Optional[bool] = None,
712
+ return_dict: Optional[bool] = None,
713
+ **kwargs,
714
+ ) -> Union[Tuple, MoeCausalLMOutputWithPast]:
715
+ output_router_logits = output_router_logits if output_router_logits is not None else self.config.output_router_logits
716
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
717
+
718
+ outputs = self.model(
719
+ input_ids=input_ids,
720
+ attention_mask=attention_mask,
721
+ position_ids=position_ids,
722
+ past_key_values=past_key_values,
723
+ inputs_embeds=inputs_embeds,
724
+ use_cache=use_cache,
725
+ output_hidden_states=output_hidden_states,
726
+ output_router_logits=output_router_logits,
727
+ return_dict=True,
728
+ )
729
+ hidden_states = outputs.last_hidden_state
730
+ logits = self.lm_head(hidden_states).float()
731
+
732
+ loss = None
733
+ aux_loss = None
734
+ if labels is not None:
735
+ shift_logits = logits[..., :-1, :].contiguous()
736
+ shift_labels = labels[..., 1:].contiguous()
737
+ loss = F.cross_entropy(
738
+ shift_logits.view(-1, self.vocab_size),
739
+ shift_labels.view(-1),
740
+ ignore_index=-100,
741
+ )
742
+
743
+ if output_router_logits and outputs.router_logits is not None:
744
+ aux_loss = self._compute_router_aux_loss(outputs.router_logits, attention_mask)
745
+ if loss is not None:
746
+ loss = loss + self.router_aux_loss_coef * aux_loss
747
+
748
+ if not return_dict:
749
+ output = (logits,) + tuple(v for v in [
750
+ outputs.past_key_values, outputs.hidden_states, None, outputs.router_logits, aux_loss,
751
+ ] if v is not None)
752
+ return (loss,) + output if loss is not None else output
753
+
754
+ return MoeCausalLMOutputWithPast(
755
+ loss=loss,
756
+ aux_loss=aux_loss,
757
+ logits=logits,
758
+ past_key_values=outputs.past_key_values,
759
+ hidden_states=outputs.hidden_states,
760
+ attentions=None,
761
+ router_logits=outputs.router_logits,
762
+ )
763
+
764
+ def _compute_router_aux_loss(self, router_logits: Tuple[torch.Tensor, ...], attention_mask=None):
765
+ """Standard switch-transformer auxiliary loss for load balancing."""
766
+ if router_logits is None or len(router_logits) == 0:
767
+ return None
768
+ # Each router_logits[i] shape: (bsz, seq, num_experts) → flatten to (n_tokens, num_experts)
769
+ flat = []
770
+ for r in router_logits:
771
+ if r is None:
772
+ continue
773
+ flat.append(r.reshape(-1, self.num_experts))
774
+ if not flat:
775
+ return None
776
+ all_router_logits = torch.cat(flat, dim=0) # (total_tokens, num_experts)
777
+
778
+ routing_weights = F.softmax(all_router_logits.float(), dim=-1)
779
+ _, selected_experts = torch.topk(routing_weights, self.num_experts_per_tok, dim=-1)
780
+
781
+ # Expert mask: (n_tokens, top_k, num_experts)
782
+ expert_mask = F.one_hot(selected_experts, num_classes=self.num_experts).float()
783
+ # Tokens-per-expert frequency: average over (n_tokens, top_k) dims → (num_experts,)
784
+ tokens_per_expert = expert_mask.mean(dim=(0, 1))
785
+ # Router prob per expert: (num_experts,)
786
+ router_prob_per_expert = routing_weights.mean(dim=0)
787
+ # aux_loss = num_experts * sum(token_freq * prob)
788
+ return self.num_experts * torch.sum(tokens_per_expert * router_prob_per_expert)
789
+
790
+ def prepare_inputs_for_generation(
791
+ self,
792
+ input_ids,
793
+ past_key_values=None,
794
+ attention_mask=None,
795
+ inputs_embeds=None,
796
+ **kwargs,
797
+ ):
798
+ if past_key_values is not None:
799
+ input_ids = input_ids[:, -1:]
800
+ position_ids = kwargs.get("position_ids", None)
801
+ if attention_mask is not None and position_ids is None:
802
+ position_ids = attention_mask.long().cumsum(-1) - 1
803
+ position_ids.masked_fill_(attention_mask == 0, 1)
804
+ if past_key_values is not None:
805
+ position_ids = position_ids[:, -input_ids.shape[1]:]
806
+ return {
807
+ "input_ids": input_ids,
808
+ "position_ids": position_ids,
809
+ "past_key_values": past_key_values,
810
+ "use_cache": kwargs.get("use_cache"),
811
+ "attention_mask": attention_mask,
812
+ }
813
+
814
+
815
+ # =============================================================================
816
+ # Helper: Latin Square Layer Map (for analysis / debugging)
817
+ # =============================================================================
818
+ def print_layer_map(num_layers: int = 49):
819
+ """Print the Latin Square attention type map."""
820
+ print(f"=== AETHER-V2-7way Layer Map ({num_layers} layers) ===")
821
+ for L in range(num_layers):
822
+ attn = get_attention_type(L)
823
+ phase = get_ffn_phase(L)
824
+ row = L // 7
825
+ col = L % 7
826
+ print(f" L{L:02d} (row={row} col={col}): attn={attn:12s} ffn_phase={phase}")
827
+
828
+
829
+ __all__ = [
830
+ "AETHERV211AttnConfig",
831
+ "AETHERV211AttnModel",
832
+ "AETHERV211AttnForCausalLM",
833
+ "AETHERV211AttnPreTrainedModel",
834
+ "AETHERV211AttnDecoderLayer",
835
+ "AETHERV211AttnSparseMoE",
836
+ "build_attention",
837
+ "get_attention_type",
838
+ "get_ffn_phase",
839
+ "LATIN_SQUARE_7x7",
840
+ "ATTN_TYPES",
841
+ "print_layer_map",
842
+ ]
aether_pkg/v2_attentions/__init__.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ """
3
+ V2 Attentions module — 7-aware attention implementations.
4
+
5
+ ⚠️ 동생 작성 placeholder
6
+ """
7
+ from .nsa import NSAAttention
8
+ from .differential import DifferentialAttention
9
+
10
+ __all__ = ["NSAAttention", "DifferentialAttention"]
aether_pkg/v2_attentions/differential.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Differential Transformer (PRODUCTION - causal-safe)
3
+ ====================================================
4
+
5
+ Microsoft 2410.05258 (ICLR 2025)
6
+ Cancels noise via dual-softmax attention map subtraction.
7
+
8
+ Core formula:
9
+ DiffAttn(X) = (softmax(Q1 K1^T / sqrt(d)) - λ × softmax(Q2 K2^T / sqrt(d))) V
10
+ λ = exp(λ_q1 · λ_k1) - exp(λ_q2 · λ_k2) + λ_init
11
+
12
+ 5/7 fixes applied to placeholder bugs:
13
+ - GroupNorm (sequence-spanning) → LayerNorm(head_dim) (per-token, causal-safe)
14
+ - Causal triu mask explicit (was relying on SDPA, but split + softmax direct now)
15
+ - forward signature: layer_idx kwarg + (Tensor, past_kv) tuple return for modeling compat
16
+
17
+ Hyperparameter (configuration_aether_v2_7way.py):
18
+ - diff_lambda_init = 0.8
19
+ """
20
+ from __future__ import annotations
21
+ import math
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
+
29
+ class DifferentialAttention(nn.Module):
30
+ """λ-gated dual-softmax differential attention with causal mask + LayerNorm."""
31
+
32
+ def __init__(self, config, layer_idx: int = 0):
33
+ super().__init__()
34
+ self.layer_idx = layer_idx
35
+ self.h = config.hidden_size
36
+ self.num_heads = config.num_attention_heads
37
+ self.num_kv_heads = config.num_key_value_heads
38
+ self.head_dim = config.head_dim
39
+ # Differential splits head_dim in half
40
+ self.diff_head_dim = self.head_dim // 2
41
+
42
+ # Layer-depth lambda init (paper Eq. 3): λ_init = 0.8 - 0.6 * exp(-0.3 * (depth - 1))
43
+ # Use config base + depth decay if provided.
44
+ base = getattr(config, "diff_lambda_init", 0.8)
45
+ decay = getattr(config, "diff_lambda_layer_decay", 0.6)
46
+ # Simple per-layer init (placeholder used 0.8 - 0.6*exp(-0.3*idx))
47
+ self.lambda_init = base - decay * math.exp(-0.3 * max(layer_idx - 1, 0))
48
+
49
+ # Q/K/V/O projections
50
+ self.q_proj = nn.Linear(self.h, self.num_heads * self.head_dim, bias=False)
51
+ self.k_proj = nn.Linear(self.h, self.num_kv_heads * self.head_dim, bias=False)
52
+ self.v_proj = nn.Linear(self.h, self.num_kv_heads * self.head_dim, bias=False)
53
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.h, bias=False)
54
+
55
+ # Lambda parameters per-head
56
+ self.lambda_q1 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
57
+ self.lambda_k1 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
58
+ self.lambda_q2 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
59
+ self.lambda_k2 = nn.Parameter(torch.zeros(self.num_heads, self.diff_head_dim).normal_(0, 0.1))
60
+
61
+ # ★ FIX 5/7: LayerNorm(head_dim) — per-token norm, causal-safe.
62
+ # Was nn.GroupNorm(num_groups=num_heads, num_channels=num_heads*head_dim) which
63
+ # normalized over sequence dim and leaked future info.
64
+ self.subln = nn.LayerNorm(self.head_dim, eps=getattr(config, "rms_norm_eps", 1e-6))
65
+
66
+ def forward(
67
+ self,
68
+ hidden_states: torch.Tensor,
69
+ attention_mask: Optional[torch.Tensor] = None,
70
+ position_ids: Optional[torch.LongTensor] = None,
71
+ past_key_value=None,
72
+ use_cache: bool = False,
73
+ **kwargs,
74
+ ) -> Tuple[torch.Tensor, Optional[object]]:
75
+ B, S, _ = hidden_states.shape
76
+
77
+ q = self.q_proj(hidden_states).view(B, S, self.num_heads, self.head_dim)
78
+ k = self.k_proj(hidden_states).view(B, S, self.num_kv_heads, self.head_dim)
79
+ v = self.v_proj(hidden_states).view(B, S, self.num_kv_heads, self.head_dim)
80
+
81
+ # Split Q, K halves
82
+ q1, q2 = q.split(self.diff_head_dim, dim=-1) # [B, S, H, d/2]
83
+ k1, k2 = k.split(self.diff_head_dim, dim=-1) # [B, S, kv_h, d/2]
84
+
85
+ # GQA repeat
86
+ repeat = self.num_heads // self.num_kv_heads
87
+ k1 = k1.repeat_interleave(repeat, dim=2)
88
+ k2 = k2.repeat_interleave(repeat, dim=2)
89
+ v = v.repeat_interleave(repeat, dim=2)
90
+
91
+ # Transpose to [B, H, S, d]
92
+ q1 = q1.transpose(1, 2)
93
+ q2 = q2.transpose(1, 2)
94
+ k1 = k1.transpose(1, 2)
95
+ k2 = k2.transpose(1, 2)
96
+ v = v.transpose(1, 2)
97
+
98
+ scale = 1.0 / math.sqrt(self.diff_head_dim)
99
+ scores1 = torch.matmul(q1, k1.transpose(-2, -1)) * scale
100
+ scores2 = torch.matmul(q2, k2.transpose(-2, -1)) * scale
101
+
102
+ # ★ FIX 5/7: causal mask (triu(1) blocks future)
103
+ causal = torch.ones(S, S, device=q1.device, dtype=torch.bool).triu(1)
104
+ scores1 = scores1.masked_fill(causal, float("-inf"))
105
+ scores2 = scores2.masked_fill(causal, float("-inf"))
106
+
107
+ attn1 = F.softmax(scores1, dim=-1)
108
+ attn2 = F.softmax(scores2, dim=-1)
109
+
110
+ # Lambda per-head (paper Eq. 3)
111
+ lam_q1k1 = (self.lambda_q1 * self.lambda_k1).sum(dim=-1) # [H]
112
+ lam_q2k2 = (self.lambda_q2 * self.lambda_k2).sum(dim=-1)
113
+ lam = torch.exp(lam_q1k1) - torch.exp(lam_q2k2) + self.lambda_init # [H]
114
+ lam = lam.view(1, -1, 1, 1)
115
+
116
+ diff_attn = attn1 - lam * attn2
117
+
118
+ out = torch.matmul(diff_attn, v) # [B, H, S, head_dim]
119
+ # ★ FIX 5/7: per-token LayerNorm (was sequence-spanning GroupNorm = leak)
120
+ out = self.subln(out)
121
+ out = out * (1 - self.lambda_init)
122
+
123
+ out = out.transpose(1, 2).reshape(B, S, -1)
124
+ return self.o_proj(out), past_key_value
125
+
126
+
127
+ __all__ = ["DifferentialAttention"]
aether_pkg/v2_attentions/gdn.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # AETHER-30B-11Attn — Auto-extracted from new_attentions.py
3
+ import math
4
+ from typing import Optional, Tuple
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+ # =============================================================================
10
+ # 1. MLA (Multi-head Latent Attention) — DeepSeek-V2/V3
11
+ # =============================================================================
12
+ class MLAAttention(nn.Module):
13
+ """Multi-head Latent Attention (low-rank Q/KV decomposition).
14
+
15
+ DeepSeek-V2 paper: Q/KV을 low-rank로 분해 → KV cache 1/14 절감.
16
+
17
+ Q: hidden → q_lora_rank → split (rope + nope) → multi-head
18
+ KV: hidden → kv_lora_rank → split (rope + nope) → K (rope+nope), V (nope)
19
+ """
20
+
21
+ def __init__(self, config, layer_idx: int = 0):
22
+ super().__init__()
23
+ self.config = config
24
+ self.layer_idx = layer_idx
25
+ self.hidden_size = config.hidden_size
26
+ self.num_heads = config.num_attention_heads
27
+ self.q_lora_rank = getattr(config, "mla_q_lora_rank", 768)
28
+ self.kv_lora_rank = getattr(config, "mla_kv_lora_rank", 256)
29
+ self.qk_rope_head_dim = getattr(config, "mla_qk_rope_head_dim", 64)
30
+ self.qk_nope_head_dim = getattr(config, "mla_qk_nope_head_dim", 64)
31
+ self.v_head_dim = getattr(config, "mla_v_head_dim", 128)
32
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
33
+
34
+ # Q low-rank
35
+ self.q_a_proj = nn.Linear(self.hidden_size, self.q_lora_rank, bias=False)
36
+ self.q_a_norm = nn.LayerNorm(self.q_lora_rank, eps=1e-5)
37
+ self.q_b_proj = nn.Linear(self.q_lora_rank, self.num_heads * qk_head_dim, bias=False)
38
+
39
+ # KV low-rank (compressed)
40
+ self.kv_a_proj = nn.Linear(self.hidden_size, self.kv_lora_rank + self.qk_rope_head_dim, bias=False)
41
+ self.kv_a_norm = nn.LayerNorm(self.kv_lora_rank, eps=1e-5)
42
+ self.kv_b_proj = nn.Linear(
43
+ self.kv_lora_rank,
44
+ self.num_heads * (self.qk_nope_head_dim + self.v_head_dim),
45
+ bias=False,
46
+ )
47
+
48
+ # Output
49
+ self.o_proj = nn.Linear(self.num_heads * self.v_head_dim, self.hidden_size, bias=False)
50
+
51
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
52
+ past_key_value=None, use_cache=False, **kwargs):
53
+ bsz, q_len, _ = hidden_states.shape
54
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
55
+
56
+ # Q
57
+ q = self.q_a_proj(hidden_states)
58
+ q = self.q_a_norm(q)
59
+ q = self.q_b_proj(q).view(bsz, q_len, self.num_heads, qk_head_dim).transpose(1, 2)
60
+
61
+ # KV
62
+ kv = self.kv_a_proj(hidden_states)
63
+ kv_compressed, k_rope = kv.split([self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)
64
+ kv_compressed = self.kv_a_norm(kv_compressed)
65
+ kv_b = self.kv_b_proj(kv_compressed).view(
66
+ bsz, q_len, self.num_heads, self.qk_nope_head_dim + self.v_head_dim
67
+ ).transpose(1, 2)
68
+ k_nope, v = kv_b.split([self.qk_nope_head_dim, self.v_head_dim], dim=-1)
69
+
70
+ # Combine k (broadcast k_rope to all heads)
71
+ k_rope_expanded = k_rope.view(bsz, q_len, 1, self.qk_rope_head_dim).expand(
72
+ -1, -1, self.num_heads, -1
73
+ ).transpose(1, 2)
74
+ k = torch.cat([k_nope, k_rope_expanded], dim=-1) # (bsz, n_h, seq, qk_head_dim)
75
+
76
+ # SDPA
77
+ attn_out = F.scaled_dot_product_attention(
78
+ q, k, v,
79
+ attn_mask=(attention_mask.to(q.dtype) if attention_mask is not None else None),
80
+ dropout_p=0.0, is_causal=(attention_mask is None and q_len > 1),
81
+ )
82
+ attn_out = attn_out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
83
+ return self.o_proj(attn_out), past_key_value
84
+
85
+
86
+ # =============================================================================
87
+ # 2. Mamba2 — State Space Model (placeholder simplification)
88
+ # =============================================================================
89
+ class Mamba2Attention(nn.Module):
90
+ """Mamba2 SSM placeholder (simplified S6 selective scan).
91
+
92
+ True Mamba2: selective_scan_fn from mamba_ssm package.
93
+ Here: simplified GRU-style mixing as placeholder.
94
+ """
95
+
96
+ def __init__(self, config, layer_idx: int = 0):
97
+ super().__init__()
98
+ self.config = config
99
+ self.layer_idx = layer_idx
100
+ self.hidden_size = config.hidden_size
101
+ self.d_state = getattr(config, "mamba2_d_state", 128)
102
+ self.d_conv = getattr(config, "mamba2_d_conv", 4)
103
+ self.expand = getattr(config, "mamba2_expand", 2)
104
+ self.d_inner = self.expand * self.hidden_size
105
+
106
+ self.in_proj = nn.Linear(self.hidden_size, 2 * self.d_inner, bias=False)
107
+ self.conv1d = nn.Conv1d(self.d_inner, self.d_inner, kernel_size=self.d_conv,
108
+ groups=self.d_inner, padding=self.d_conv - 1, bias=False)
109
+ # SSM params (simplified)
110
+ self.A_log = nn.Parameter(torch.zeros(self.d_inner, self.d_state))
111
+ self.D = nn.Parameter(torch.zeros(self.d_inner))
112
+ self.dt_proj = nn.Linear(self.d_inner, self.d_inner, bias=True)
113
+ self.B_proj = nn.Linear(self.d_inner, self.d_state, bias=False)
114
+ self.C_proj = nn.Linear(self.d_inner, self.d_state, bias=False)
115
+
116
+ self.out_proj = nn.Linear(self.d_inner, self.hidden_size, bias=False)
117
+ self.norm = nn.LayerNorm(self.d_inner, eps=1e-5)
118
+
119
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
120
+ past_key_value=None, use_cache=False, **kwargs):
121
+ bsz, seq, _ = hidden_states.shape
122
+ # Project
123
+ xz = self.in_proj(hidden_states)
124
+ x, z = xz.chunk(2, dim=-1) # (bsz, seq, d_inner) each
125
+
126
+ # 1D conv (causal)
127
+ x = x.transpose(1, 2) # (bsz, d_inner, seq)
128
+ x = self.conv1d(x)[:, :, :seq] # causal trim
129
+ x = F.silu(x).transpose(1, 2) # (bsz, seq, d_inner)
130
+
131
+ # Simplified SSM: scan as cumulative recurrent
132
+ # For placeholder, we use the simple gated linear approximation
133
+ dt = F.softplus(self.dt_proj(x)) # (bsz, seq, d_inner)
134
+ out = x * dt + self.D[None, None, :] * x # ultra-simplified
135
+ out = self.norm(out)
136
+ out = out * F.silu(z) # gating
137
+ out = self.out_proj(out)
138
+ return out, past_key_value
139
+
140
+
141
+ # =============================================================================
142
+ # 3. GDN (Gated Delta Network) — RWKV/RetNet style
143
+ # =============================================================================
144
+ class GDNAttention(nn.Module):
145
+ """Gated Delta Network — RWKV/RetNet style linear attention with delta gating.
146
+
147
+ Placeholder simplified: linear attention + gating.
148
+ """
149
+
150
+ def __init__(self, config, layer_idx: int = 0):
151
+ super().__init__()
152
+ self.config = config
153
+ self.layer_idx = layer_idx
154
+ self.hidden_size = config.hidden_size
155
+ self.expand = getattr(config, "gdn_expand", 1)
156
+ self.d_inner = self.expand * self.hidden_size
157
+ self.d_conv = getattr(config, "gdn_d_conv", 4)
158
+
159
+ self.q_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
160
+ self.k_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
161
+ self.v_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
162
+ self.gate_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
163
+
164
+ self.conv1d_q = nn.Conv1d(self.d_inner, self.d_inner, kernel_size=self.d_conv,
165
+ groups=self.d_inner, padding=self.d_conv - 1, bias=False)
166
+ self.conv1d_k = nn.Conv1d(self.d_inner, self.d_inner, kernel_size=self.d_conv,
167
+ groups=self.d_inner, padding=self.d_conv - 1, bias=False)
168
+
169
+ self.out_proj = nn.Linear(self.d_inner, self.hidden_size, bias=False)
170
+ self.norm = nn.LayerNorm(self.d_inner, eps=1e-5)
171
+
172
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
173
+ past_key_value=None, use_cache=False, **kwargs):
174
+ bsz, seq, _ = hidden_states.shape
175
+ q = self.q_proj(hidden_states)
176
+ k = self.k_proj(hidden_states)
177
+ v = self.v_proj(hidden_states)
178
+ g = F.silu(self.gate_proj(hidden_states))
179
+
180
+ # Causal conv on q, k
181
+ q = self.conv1d_q(q.transpose(1, 2))[:, :, :seq].transpose(1, 2)
182
+ k = self.conv1d_k(k.transpose(1, 2))[:, :, :seq].transpose(1, 2)
183
+
184
+ # Linear attention: (Q · K^T) → causal cumsum → · V
185
+ q = F.elu(q) + 1
186
+ k = F.elu(k) + 1
187
+
188
+ # Simplified linear attention (per-token)
189
+ # For truly causal: cumulative outer products. We use simplified scan.
190
+ kv = k * v # element-wise (placeholder)
191
+ kv_cum = torch.cumsum(kv, dim=1)
192
+ out = q * kv_cum
193
+ out = self.norm(out) * g
194
+ out = self.out_proj(out)
195
+ return out, past_key_value
196
+
197
+
198
+ # =============================================================================
199
+ # 4. Hyena — Convolutional alternative (no attention)
200
+
201
+ __all__ = ['GDNAttention']
aether_pkg/v2_attentions/hyena.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # AETHER-30B-11Attn — Auto-extracted from new_attentions.py
3
+ import math
4
+ from typing import Optional, Tuple
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+ class HyenaAttention(nn.Module):
10
+ """Hyena — convolutional sequence mixer (Stanford 2023).
11
+
12
+ Long-range attention replaced with implicit conv filters.
13
+ Placeholder simplified.
14
+ """
15
+
16
+ def __init__(self, config, layer_idx: int = 0):
17
+ super().__init__()
18
+ self.config = config
19
+ self.layer_idx = layer_idx
20
+ self.hidden_size = config.hidden_size
21
+ self.filter_order = getattr(config, "hyena_filter_order", 64)
22
+ self.dropout = getattr(config, "hyena_dropout", 0.0)
23
+
24
+ # Input projections (3 streams: u, v, x)
25
+ self.in_proj = nn.Linear(self.hidden_size, 3 * self.hidden_size, bias=False)
26
+
27
+ # Implicit filter (positional encoding-based)
28
+ self.filter_dense = nn.Sequential(
29
+ nn.Linear(1, self.filter_order),
30
+ nn.GELU(),
31
+ nn.Linear(self.filter_order, self.hidden_size),
32
+ )
33
+
34
+ # Output gate
35
+ self.out_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
36
+ self.norm = nn.LayerNorm(self.hidden_size, eps=1e-5)
37
+
38
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
39
+ past_key_value=None, use_cache=False, **kwargs):
40
+ bsz, seq, h = hidden_states.shape
41
+ # Project to 3 streams
42
+ proj = self.in_proj(hidden_states)
43
+ u, v, x = proj.chunk(3, dim=-1)
44
+
45
+ # Build implicit filter (length seq)
46
+ positions = torch.linspace(0, 1, seq, device=hidden_states.device).unsqueeze(-1) # (seq, 1)
47
+ filt = self.filter_dense(positions) # (seq, h)
48
+ filt = filt.transpose(0, 1).unsqueeze(0) # (1, h, seq)
49
+
50
+ # 1D depthwise conv with implicit filter (placeholder: simple multiply)
51
+ # True Hyena uses FFT-based long conv. Placeholder:
52
+ u_t = u.transpose(1, 2) # (bsz, h, seq)
53
+ # cumulative average + gate (simplified)
54
+ u_cum = torch.cumsum(u_t, dim=-1) / torch.arange(1, seq + 1, device=u.device, dtype=u.dtype).view(1, 1, -1)
55
+ out = u_cum.transpose(1, 2) * v + x
56
+ out = self.norm(out)
57
+ out = self.out_proj(out)
58
+ return out, past_key_value
59
+
60
+
61
+
62
+ __all__ = ['HyenaAttention']
aether_pkg/v2_attentions/mamba2.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # AETHER-30B-11Attn — Auto-extracted from new_attentions.py
3
+ import math
4
+ from typing import Optional, Tuple
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+ # =============================================================================
10
+ # 1. MLA (Multi-head Latent Attention) — DeepSeek-V2/V3
11
+ # =============================================================================
12
+ class MLAAttention(nn.Module):
13
+ """Multi-head Latent Attention (low-rank Q/KV decomposition).
14
+
15
+ DeepSeek-V2 paper: Q/KV을 low-rank로 분해 → KV cache 1/14 절감.
16
+
17
+ Q: hidden → q_lora_rank → split (rope + nope) → multi-head
18
+ KV: hidden → kv_lora_rank → split (rope + nope) → K (rope+nope), V (nope)
19
+ """
20
+
21
+ def __init__(self, config, layer_idx: int = 0):
22
+ super().__init__()
23
+ self.config = config
24
+ self.layer_idx = layer_idx
25
+ self.hidden_size = config.hidden_size
26
+ self.num_heads = config.num_attention_heads
27
+ self.q_lora_rank = getattr(config, "mla_q_lora_rank", 768)
28
+ self.kv_lora_rank = getattr(config, "mla_kv_lora_rank", 256)
29
+ self.qk_rope_head_dim = getattr(config, "mla_qk_rope_head_dim", 64)
30
+ self.qk_nope_head_dim = getattr(config, "mla_qk_nope_head_dim", 64)
31
+ self.v_head_dim = getattr(config, "mla_v_head_dim", 128)
32
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
33
+
34
+ # Q low-rank
35
+ self.q_a_proj = nn.Linear(self.hidden_size, self.q_lora_rank, bias=False)
36
+ self.q_a_norm = nn.LayerNorm(self.q_lora_rank, eps=1e-5)
37
+ self.q_b_proj = nn.Linear(self.q_lora_rank, self.num_heads * qk_head_dim, bias=False)
38
+
39
+ # KV low-rank (compressed)
40
+ self.kv_a_proj = nn.Linear(self.hidden_size, self.kv_lora_rank + self.qk_rope_head_dim, bias=False)
41
+ self.kv_a_norm = nn.LayerNorm(self.kv_lora_rank, eps=1e-5)
42
+ self.kv_b_proj = nn.Linear(
43
+ self.kv_lora_rank,
44
+ self.num_heads * (self.qk_nope_head_dim + self.v_head_dim),
45
+ bias=False,
46
+ )
47
+
48
+ # Output
49
+ self.o_proj = nn.Linear(self.num_heads * self.v_head_dim, self.hidden_size, bias=False)
50
+
51
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
52
+ past_key_value=None, use_cache=False, **kwargs):
53
+ bsz, q_len, _ = hidden_states.shape
54
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
55
+
56
+ # Q
57
+ q = self.q_a_proj(hidden_states)
58
+ q = self.q_a_norm(q)
59
+ q = self.q_b_proj(q).view(bsz, q_len, self.num_heads, qk_head_dim).transpose(1, 2)
60
+
61
+ # KV
62
+ kv = self.kv_a_proj(hidden_states)
63
+ kv_compressed, k_rope = kv.split([self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)
64
+ kv_compressed = self.kv_a_norm(kv_compressed)
65
+ kv_b = self.kv_b_proj(kv_compressed).view(
66
+ bsz, q_len, self.num_heads, self.qk_nope_head_dim + self.v_head_dim
67
+ ).transpose(1, 2)
68
+ k_nope, v = kv_b.split([self.qk_nope_head_dim, self.v_head_dim], dim=-1)
69
+
70
+ # Combine k (broadcast k_rope to all heads)
71
+ k_rope_expanded = k_rope.view(bsz, q_len, 1, self.qk_rope_head_dim).expand(
72
+ -1, -1, self.num_heads, -1
73
+ ).transpose(1, 2)
74
+ k = torch.cat([k_nope, k_rope_expanded], dim=-1) # (bsz, n_h, seq, qk_head_dim)
75
+
76
+ # SDPA
77
+ attn_out = F.scaled_dot_product_attention(
78
+ q, k, v,
79
+ attn_mask=(attention_mask.to(q.dtype) if attention_mask is not None else None),
80
+ dropout_p=0.0, is_causal=(attention_mask is None and q_len > 1),
81
+ )
82
+ attn_out = attn_out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
83
+ return self.o_proj(attn_out), past_key_value
84
+
85
+
86
+ # =============================================================================
87
+ # 2. Mamba2 — State Space Model (placeholder simplification)
88
+ # =============================================================================
89
+ class Mamba2Attention(nn.Module):
90
+ """Mamba2 SSM placeholder (simplified S6 selective scan).
91
+
92
+ True Mamba2: selective_scan_fn from mamba_ssm package.
93
+ Here: simplified GRU-style mixing as placeholder.
94
+ """
95
+
96
+ def __init__(self, config, layer_idx: int = 0):
97
+ super().__init__()
98
+ self.config = config
99
+ self.layer_idx = layer_idx
100
+ self.hidden_size = config.hidden_size
101
+ self.d_state = getattr(config, "mamba2_d_state", 128)
102
+ self.d_conv = getattr(config, "mamba2_d_conv", 4)
103
+ self.expand = getattr(config, "mamba2_expand", 2)
104
+ self.d_inner = self.expand * self.hidden_size
105
+
106
+ self.in_proj = nn.Linear(self.hidden_size, 2 * self.d_inner, bias=False)
107
+ self.conv1d = nn.Conv1d(self.d_inner, self.d_inner, kernel_size=self.d_conv,
108
+ groups=self.d_inner, padding=self.d_conv - 1, bias=False)
109
+ # SSM params (simplified)
110
+ self.A_log = nn.Parameter(torch.zeros(self.d_inner, self.d_state))
111
+ self.D = nn.Parameter(torch.zeros(self.d_inner))
112
+ self.dt_proj = nn.Linear(self.d_inner, self.d_inner, bias=True)
113
+ self.B_proj = nn.Linear(self.d_inner, self.d_state, bias=False)
114
+ self.C_proj = nn.Linear(self.d_inner, self.d_state, bias=False)
115
+
116
+ self.out_proj = nn.Linear(self.d_inner, self.hidden_size, bias=False)
117
+ self.norm = nn.LayerNorm(self.d_inner, eps=1e-5)
118
+
119
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
120
+ past_key_value=None, use_cache=False, **kwargs):
121
+ bsz, seq, _ = hidden_states.shape
122
+ # Project
123
+ xz = self.in_proj(hidden_states)
124
+ x, z = xz.chunk(2, dim=-1) # (bsz, seq, d_inner) each
125
+
126
+ # 1D conv (causal)
127
+ x = x.transpose(1, 2) # (bsz, d_inner, seq)
128
+ x = self.conv1d(x)[:, :, :seq] # causal trim
129
+ x = F.silu(x).transpose(1, 2) # (bsz, seq, d_inner)
130
+
131
+ # Simplified SSM: scan as cumulative recurrent
132
+ # For placeholder, we use the simple gated linear approximation
133
+ dt = F.softplus(self.dt_proj(x)) # (bsz, seq, d_inner)
134
+ out = x * dt + self.D[None, None, :] * x # ultra-simplified
135
+ out = self.norm(out)
136
+ out = out * F.silu(z) # gating
137
+ out = self.out_proj(out)
138
+ return out, past_key_value
139
+
140
+
141
+ # =============================================================================
142
+ # 3. GDN (Gated Delta Network) — RWKV/RetNet style
143
+
144
+ __all__ = ['Mamba2Attention']
aether_pkg/v2_attentions/mla.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # AETHER-30B-11Attn — Auto-extracted from new_attentions.py
3
+ import math
4
+ from typing import Optional, Tuple
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+
9
+ # =============================================================================
10
+ # 1. MLA (Multi-head Latent Attention) — DeepSeek-V2/V3
11
+ # =============================================================================
12
+ class MLAAttention(nn.Module):
13
+ """Multi-head Latent Attention (low-rank Q/KV decomposition).
14
+
15
+ DeepSeek-V2 paper: Q/KV을 low-rank로 분해 → KV cache 1/14 절감.
16
+
17
+ Q: hidden → q_lora_rank → split (rope + nope) → multi-head
18
+ KV: hidden → kv_lora_rank → split (rope + nope) → K (rope+nope), V (nope)
19
+ """
20
+
21
+ def __init__(self, config, layer_idx: int = 0):
22
+ super().__init__()
23
+ self.config = config
24
+ self.layer_idx = layer_idx
25
+ self.hidden_size = config.hidden_size
26
+ self.num_heads = config.num_attention_heads
27
+ self.q_lora_rank = getattr(config, "mla_q_lora_rank", 768)
28
+ self.kv_lora_rank = getattr(config, "mla_kv_lora_rank", 256)
29
+ self.qk_rope_head_dim = getattr(config, "mla_qk_rope_head_dim", 64)
30
+ self.qk_nope_head_dim = getattr(config, "mla_qk_nope_head_dim", 64)
31
+ self.v_head_dim = getattr(config, "mla_v_head_dim", 128)
32
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
33
+
34
+ # Q low-rank
35
+ self.q_a_proj = nn.Linear(self.hidden_size, self.q_lora_rank, bias=False)
36
+ self.q_a_norm = nn.LayerNorm(self.q_lora_rank, eps=1e-5)
37
+ self.q_b_proj = nn.Linear(self.q_lora_rank, self.num_heads * qk_head_dim, bias=False)
38
+
39
+ # KV low-rank (compressed)
40
+ self.kv_a_proj = nn.Linear(self.hidden_size, self.kv_lora_rank + self.qk_rope_head_dim, bias=False)
41
+ self.kv_a_norm = nn.LayerNorm(self.kv_lora_rank, eps=1e-5)
42
+ self.kv_b_proj = nn.Linear(
43
+ self.kv_lora_rank,
44
+ self.num_heads * (self.qk_nope_head_dim + self.v_head_dim),
45
+ bias=False,
46
+ )
47
+
48
+ # Output
49
+ self.o_proj = nn.Linear(self.num_heads * self.v_head_dim, self.hidden_size, bias=False)
50
+
51
+ def forward(self, hidden_states, attention_mask=None, position_ids=None,
52
+ past_key_value=None, use_cache=False, **kwargs):
53
+ bsz, q_len, _ = hidden_states.shape
54
+ qk_head_dim = self.qk_rope_head_dim + self.qk_nope_head_dim
55
+
56
+ # Q
57
+ q = self.q_a_proj(hidden_states)
58
+ q = self.q_a_norm(q)
59
+ q = self.q_b_proj(q).view(bsz, q_len, self.num_heads, qk_head_dim).transpose(1, 2)
60
+
61
+ # KV
62
+ kv = self.kv_a_proj(hidden_states)
63
+ kv_compressed, k_rope = kv.split([self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)
64
+ kv_compressed = self.kv_a_norm(kv_compressed)
65
+ kv_b = self.kv_b_proj(kv_compressed).view(
66
+ bsz, q_len, self.num_heads, self.qk_nope_head_dim + self.v_head_dim
67
+ ).transpose(1, 2)
68
+ k_nope, v = kv_b.split([self.qk_nope_head_dim, self.v_head_dim], dim=-1)
69
+
70
+ # Combine k (broadcast k_rope to all heads)
71
+ k_rope_expanded = k_rope.view(bsz, q_len, 1, self.qk_rope_head_dim).expand(
72
+ -1, -1, self.num_heads, -1
73
+ ).transpose(1, 2)
74
+ k = torch.cat([k_nope, k_rope_expanded], dim=-1) # (bsz, n_h, seq, qk_head_dim)
75
+
76
+ # SDPA
77
+ attn_out = F.scaled_dot_product_attention(
78
+ q, k, v,
79
+ attn_mask=(attention_mask.to(q.dtype) if attention_mask is not None else None),
80
+ dropout_p=0.0, is_causal=(attention_mask is None and q_len > 1),
81
+ )
82
+ attn_out = attn_out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
83
+ return self.o_proj(attn_out), past_key_value
84
+
85
+
86
+ # =============================================================================
87
+ # 2. Mamba2 — State Space Model (placeholder simplification)
88
+
89
+ __all__ = ['MLAAttention']
aether_pkg/v2_attentions/nsa.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ """
3
+ Native Sparse Attention (NSA) — 3-branch design.
4
+
5
+ ⚠️ 동생 작성 placeholder (사용자님 본 PC 정식 버전 도착 시 교체)
6
+
7
+ Branches:
8
+ 1. Compress: average over blocks → KV cache reduction
9
+ 2. Select: top-k token selection per query
10
+ 3. Sliding: local window attention
11
+ 4. Gate: learnable combination of 3 branches
12
+ """
13
+ import math
14
+ from typing import Optional, Tuple
15
+
16
+ import torch
17
+ import torch.nn as nn
18
+ import torch.nn.functional as F
19
+
20
+
21
+ class NSAAttention(nn.Module):
22
+ """3-branch Native Sparse Attention.
23
+
24
+ For testing purposes. Production version 사용자님 본 PC.
25
+ """
26
+
27
+ def __init__(self, config, layer_idx: int = 0):
28
+ super().__init__()
29
+ self.config = config
30
+ self.layer_idx = layer_idx
31
+ self.hidden_size = config.hidden_size
32
+ self.num_heads = config.num_attention_heads
33
+ self.num_kv_heads = getattr(config, "num_key_value_heads", config.num_attention_heads)
34
+ self.head_dim = config.head_dim
35
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
36
+ self.compress_block = getattr(config, "compress_block_size", 16)
37
+ self.sliding_window = getattr(config, "sliding_window_size", 256)
38
+ self.select_topk = getattr(config, "nsa_select_topk", 16)
39
+
40
+ # Shared Q/K/V projections (3 branches share base projections)
41
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=False)
42
+ self.k_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
43
+ self.v_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
44
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
45
+
46
+ # Compress branch: pooling MLP
47
+ self.compress_mlp = nn.Linear(self.head_dim, self.head_dim, bias=False)
48
+
49
+ # Select branch: scoring head (project to scalar score per token)
50
+ self.select_score = nn.Linear(self.head_dim, 1, bias=False)
51
+
52
+ # 3-branch gate (initialized at 0.5 each, will be normalized)
53
+ self.gate_logit = nn.Parameter(torch.zeros(3)) # sigmoid → ~0.5
54
+
55
+ def _repeat_kv(self, x: torch.Tensor) -> torch.Tensor:
56
+ """GQA: repeat KV heads to match Q heads."""
57
+ if self.num_kv_groups == 1:
58
+ return x
59
+ bsz, n_kv, seq, dim = x.shape
60
+ return (x[:, :, None, :, :]
61
+ .expand(bsz, n_kv, self.num_kv_groups, seq, dim)
62
+ .reshape(bsz, n_kv * self.num_kv_groups, seq, dim))
63
+
64
+ def _compress_branch(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
65
+ """Compress branch: average KV in blocks, then full attention on compressed."""
66
+ bsz, n_h, seq, dim = q.shape
67
+ if seq < self.compress_block * 2:
68
+ return self._full_attention(q, k, v)
69
+
70
+ n_blocks = seq // self.compress_block
71
+ # Compress K, V by averaging blocks (only complete blocks)
72
+ usable = n_blocks * self.compress_block
73
+ k_comp = k[:, :, :usable, :].view(bsz, n_h, n_blocks, self.compress_block, dim).mean(dim=3)
74
+ v_comp = v[:, :, :usable, :].view(bsz, n_h, n_blocks, self.compress_block, dim).mean(dim=3)
75
+ # Apply MLP to compressed K
76
+ k_comp = self.compress_mlp(k_comp)
77
+ # Full attention against compressed
78
+ return F.scaled_dot_product_attention(q, k_comp, v_comp, dropout_p=0.0, is_causal=False)
79
+
80
+ def _select_branch(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
81
+ """Select branch: top-k token selection per query position."""
82
+ bsz, n_h, seq, dim = q.shape
83
+ if seq <= self.select_topk:
84
+ return self._full_attention(q, k, v)
85
+
86
+ # Score each KV position via select_score on K
87
+ scores = self.select_score(k).squeeze(-1) # (bsz, n_h, seq)
88
+ topk = min(self.select_topk, seq)
89
+ _, top_idx = scores.topk(topk, dim=-1) # (bsz, n_h, topk)
90
+
91
+ # Gather top-k K, V (causal mask: only attend to past)
92
+ idx_expand = top_idx.unsqueeze(-1).expand(-1, -1, -1, dim)
93
+ k_sel = k.gather(2, idx_expand)
94
+ v_sel = v.gather(2, idx_expand)
95
+
96
+ return F.scaled_dot_product_attention(q, k_sel, v_sel, dropout_p=0.0, is_causal=False)
97
+
98
+ def _sliding_branch(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
99
+ """Sliding window: only attend to local window."""
100
+ bsz, n_h, seq, dim = q.shape
101
+ if seq <= self.sliding_window:
102
+ return self._full_attention(q, k, v)
103
+
104
+ # Build sliding window mask
105
+ idx = torch.arange(seq, device=q.device)
106
+ rel = idx.unsqueeze(0) - idx.unsqueeze(1) # (seq, seq)
107
+ mask = (rel >= 0) & (rel <= self.sliding_window) # local + causal
108
+ attn_mask = torch.where(mask, 0.0, float("-inf")).unsqueeze(0).unsqueeze(0).to(q.dtype)
109
+ return F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask, dropout_p=0.0)
110
+
111
+ def _full_attention(self, q, k, v):
112
+ return F.scaled_dot_product_attention(q, k, v, dropout_p=0.0, is_causal=True)
113
+
114
+ def forward(
115
+ self,
116
+ hidden_states: torch.Tensor,
117
+ attention_mask: Optional[torch.Tensor] = None,
118
+ position_ids: Optional[torch.LongTensor] = None,
119
+ past_key_value=None,
120
+ use_cache: bool = False,
121
+ **kwargs,
122
+ ) -> Tuple[torch.Tensor, Optional[object]]:
123
+ bsz, q_len, _ = hidden_states.size()
124
+
125
+ q = self.q_proj(hidden_states).view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
126
+ k = self.k_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
127
+ v = self.v_proj(hidden_states).view(bsz, q_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
128
+
129
+ # GQA: repeat KV to match Q heads
130
+ k = self._repeat_kv(k)
131
+ v = self._repeat_kv(v)
132
+
133
+ # 3 branches
134
+ out_compress = self._compress_branch(q, k, v)
135
+ out_select = self._select_branch(q, k, v)
136
+ out_sliding = self._sliding_branch(q, k, v)
137
+
138
+ # Gate (softmax over 3 branches)
139
+ gate = F.softmax(self.gate_logit, dim=0)
140
+ out = (gate[0] * out_compress
141
+ + gate[1] * out_select
142
+ + gate[2] * out_sliding)
143
+
144
+ # Reshape and project
145
+ out = out.transpose(1, 2).contiguous().view(bsz, q_len, -1)
146
+ return self.o_proj(out), past_key_value
147
+
148
+
149
+ __all__ = ["NSAAttention"]
config.json ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "attention_dropout": 0.0,
3
+ "compress_block_size": 32,
4
+ "deltanet_chunk_size": 128,
5
+ "deltanet_d_state": 64,
6
+ "diff_lambda_init": 0.8,
7
+ "diff_lambda_layer_decay": 0.6,
8
+ "expert_intermediate_size": 512,
9
+ "gdn_chunk_size": 64,
10
+ "gdn_d_conv": 4,
11
+ "gdn_expand": 1,
12
+ "head_dim": 128,
13
+ "hidden_act": "silu",
14
+ "hidden_size": 1024,
15
+ "hybrid_groupnorm_groups": 8,
16
+ "hyena_dropout": 0.0,
17
+ "hyena_filter_order": 64,
18
+ "initializer_range": 0.02,
19
+ "intermediate_size": 512,
20
+ "linear_d_conv": 4,
21
+ "linear_d_state": 64,
22
+ "linear_expand": 1,
23
+ "mamba2_chunk_size": 256,
24
+ "mamba2_d_conv": 4,
25
+ "mamba2_d_state": 128,
26
+ "mamba2_expand": 2,
27
+ "mamba2_headdim": 64,
28
+ "max_position_embeddings": 8192,
29
+ "mla_kv_lora_rank": 256,
30
+ "mla_q_lora_rank": 768,
31
+ "mla_qk_nope_head_dim": 64,
32
+ "mla_qk_rope_head_dim": 64,
33
+ "mla_v_head_dim": 128,
34
+ "model_type": "aether_v2_11attn",
35
+ "nsa_compress_block_size": 32,
36
+ "nsa_select_top_k": 16,
37
+ "nsa_sliding_window": 512,
38
+ "num_attention_heads": 8,
39
+ "num_experts": 25,
40
+ "num_experts_per_tok": 7,
41
+ "num_hidden_layers": 121,
42
+ "num_key_value_heads": 2,
43
+ "oheng_enable": true,
44
+ "oheng_num_phases": 5,
45
+ "output_router_logits": false,
46
+ "pad_token_id": 151643,
47
+ "rezero_alpha_init": 0.0,
48
+ "rms_norm_eps": 1e-06,
49
+ "rope_theta": 1000000.0,
50
+ "router_aux_loss_coef": 0.01,
51
+ "sliding_window_size": 1024,
52
+ "tie_word_embeddings": false,
53
+ "transformers_version": "5.3.0",
54
+ "use_cache": false,
55
+ "use_deepnet_init": true,
56
+ "use_shared_expert": true,
57
+ "vocab_size": 151936,
58
+ "z_loss_coef": 0.001
59
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6181fbdcf6df034880135bcd7f697aa01563727e1a75b43b51a1f2c2be2264d
3
+ size 11578322830
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
3
+ size 11422650
tokenizer_config.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": null,
5
+ "clean_up_tokenization_spaces": false,
6
+ "eos_token": "<|im_end|>",
7
+ "errors": "replace",
8
+ "extra_special_tokens": [
9
+ "<|im_start|>",
10
+ "<|im_end|>",
11
+ "<|object_ref_start|>",
12
+ "<|object_ref_end|>",
13
+ "<|box_start|>",
14
+ "<|box_end|>",
15
+ "<|quad_start|>",
16
+ "<|quad_end|>",
17
+ "<|vision_start|>",
18
+ "<|vision_end|>",
19
+ "<|vision_pad|>",
20
+ "<|image_pad|>",
21
+ "<|video_pad|>"
22
+ ],
23
+ "is_local": false,
24
+ "model_max_length": 131072,
25
+ "pad_token": "<|endoftext|>",
26
+ "split_special_tokens": false,
27
+ "tokenizer_class": "Qwen2Tokenizer",
28
+ "unk_token": null
29
+ }