SeaWolf-AI commited on
Commit
01b945d
·
verified ·
1 Parent(s): 9d3fe9c

fix: make model loadable via AutoModelForCausalLM (add auto_map, flatten module files to repo root, inherit GenerationMixin)

Browse files
Files changed (1) hide show
  1. mamba2.py +144 -0
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']