AndrewThompson1233 commited on
Commit
c54d56e
·
1 Parent(s): d319ab1
README.md ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: mit
5
+ library_name: transformers
6
+ tags:
7
+ - maba
8
+ - maba-v1.5
9
+ - recurrent
10
+ - dgda
11
+ - linear-attention
12
+ - sparse-attention
13
+ - maba-sa
14
+ - mla
15
+ - nope
16
+ pipeline_tag: text-generation
17
+ ---
18
+
19
+ # Maba v1.5 (103.5M) Trained Checkpoint
20
+
21
+ Pretrained checkpoint of the **Maba v1.5 Experimental Architecture** trained on 3,044 dialogue pairs on NVIDIA L4 (bfloat16).
22
+
23
+ * Base Architecture Specification: [AndrewThompson1233/maba-v1.5-exp-architecture](https://huggingface.co/AndrewThompson1233/maba-v1.5-exp-architecture)
24
+ * Parameters: **103,520,911 (103.5M)**
25
+ * Core Computation Ratio: **95.21%** (4.30% Vocab Tax)
26
+ * Macro-Stack: **3:1** (15 DGDA Recurrence : 5 MABA-SA Dynamic Sparse Attention)
27
+ * Positional Encoding: **Strict NoPE** (0 positional parameters)
28
+
29
+ ---
30
+
31
+ ## Empirical Benchmark vs Qwen3.8-Flash-Next (101.7M)
32
+
33
+ Evaluated under identical training budgets (3,044 dialogues, 15 epochs, bfloat16, NVIDIA L4):
34
+
35
+ | Metric | Maba v1.5-exp | Qwen3.8-Flash-Next | Delta / Advantage |
36
+ | :--- | :---: | :---: | :---: |
37
+ | **Parameters** | **103,520,911 (103.5M)** | 101,701,120 (101.7M) | 0.2% parity |
38
+ | **Architecture** | **75% DGDA + 25% MABA-SA** | 75% GDN + 25% QSA + MoE | Cyclic 3:1 |
39
+ | **Positional Encoding** | **Strict NoPE (0 params)** | 25% Partial RoPE | Zero positional overhead |
40
+ | **Contrastive Retrieval (MCQ)** | **87.5% (7/8)** | 75.0% (6/8) | **+12.5% accuracy** |
41
+ | **Validation Loss** | **0.0697** | 0.0778 | **-10.4% entropy** |
42
+ | **Validation Perplexity (PPL)** | **1.07** | 1.08 | **Maba wins** |
43
+ | **Decode Throughput (L4)** | **7.0 tok/s** | 5.5 tok/s | **+27.3% faster generation** |
44
+
45
+ <p align="center">
46
+ <img src="assets/empirical_benchmark.svg" width="920" alt="Maba v1.5 Empirical Benchmark" />
47
+ </p>
48
+
49
+ ---
50
+
51
+ ## Attention Ablation Proof
52
+
53
+ Empirical demonstration of the contribution of the 25% MABA-SA dynamic sparse attention layers against a pure linear recurrent baseline on the exact same checkpoint weights:
54
+
55
+ | Model Variant | Attention Mechanism | Validation Loss | Perplexity (PPL) | Error Reduction |
56
+ | :--- | :---: | :---: | :---: | :---: |
57
+ | **Pure DGDA (Ablation)** | None (100% Linear Recurrence) | 3.9360 | 51.21 | Baseline |
58
+ | **Qwen3.8-Flash-Next** | QSA (GQA + Micro-block Indexer) | 3.8772 | 48.29 | -5.7% vs Recurrence |
59
+ | **Maba v1.5 Full** | **MABA-SA (MLA + Top-32 + HCA)** | **3.5903** | **36.24** | **-29.2% error drop** |
60
+
61
+ ---
62
+
63
+ ## Needle-In-A-Haystack & Centroid Retrieval (512 to 4096 Tokens)
64
+
65
+ | Context Length | Needle Position | Needle Block | DG-Indexer (Hybrid Mean+Max) | Standard Pure Mean Pooling |
66
+ | :---: | :---: | :---: | :---: | :---: |
67
+ | **512 tokens** | 51 (10%) | Block #0 | **Retrieved (Top-32)** | Retrieved |
68
+ | **512 tokens** | 256 (50%) | Block #4 | **Retrieved (Top-32)** | Retrieved |
69
+ | **512 tokens** | 460 (90%) | Block #7 | **Retrieved (Top-32)** | Retrieved |
70
+ | **1024 tokens** | 102 (10%) | Block #1 | **Retrieved (Top-32)** | Retrieved |
71
+ | **1024 tokens** | 512 (50%) | Block #8 | **Retrieved (Top-32)** | Retrieved |
72
+ | **1024 tokens** | 921 (90%) | Block #14 | **Retrieved (Top-32)** | Retrieved |
73
+ | **2048 tokens** | 204 (10%) | Block #3 | **Retrieved (Top-32)** | Retrieved |
74
+ | **2048 tokens** | 1024 (50%) | Block #16 | **Retrieved (Top-32)** | Retrieved |
75
+ | **2048 tokens** | 1843 (90%) | Block #28 | **Retrieved (Top-32)** | Retrieved |
76
+ | **4096 tokens** | 2048 (50% Lost-in-Middle) | Block #32 | **Retrieved (Top-32)** | **Diluted to 0.0 (Failed)** |
77
+ | **4096 tokens** | 3686 (90%) | Block #57 | **Retrieved (Top-32)** | Retrieved |
78
+
79
+ ---
80
+
81
+ ## KV-Cache Footprint at 4k Context
82
+
83
+ | Context Length | Dense Attention (Baseline) | Qwen3.8-Flash-Next | Maba v1.5 (MLA + Top-32) | Memory Reduction vs Dense |
84
+ | :---: | :---: | :---: | :---: | :---: |
85
+ | **512 tokens** | 25.00 MB | 1.00 MB | **0.62 MB** | **-97.5%** |
86
+ | **1,024 tokens** | 50.00 MB | 2.00 MB | **1.25 MB** | **-97.5%** |
87
+ | **2,048 tokens** | 100.00 MB | 4.00 MB | **2.50 MB** | **-97.5%** |
88
+ | **4,096 tokens** | 200.00 MB | 8.00 MB | **2.50 MB** | **-98.8%** |
assets/empirical_benchmark.svg ADDED
config.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "dim": 640,
3
+ "d_model": 640,
4
+ "n_layers": 20,
5
+ "num_layers": 20,
6
+ "n_heads": 10,
7
+ "num_heads": 10,
8
+ "d_head": 64,
9
+ "d_k": 64,
10
+ "d_v": 64,
11
+ "vocab_size": 50257,
12
+ "max_seq_len": 2048,
13
+ "d_emb": 128,
14
+ "kernel_size": 4,
15
+ "conv_kernel_size": 4,
16
+ "chunk_size": 16,
17
+ "eps": 1e-06,
18
+ "inversion_method": "adaptive",
19
+ "inversion_threshold": 0.5,
20
+ "adaptive_tol": 7e-05,
21
+ "d_c": 128,
22
+ "d_idx": 64,
23
+ "block_size": 64,
24
+ "window_size": 128,
25
+ "top_k": 32,
26
+ "hca_pool_size": 64,
27
+ "dist_lambda": 0.5,
28
+ "intermediate_size": 1248,
29
+ "rms_norm_eps": 1e-06,
30
+ "residual_gate_bias": 2.0,
31
+ "mtp_depth": 2,
32
+ "architectures": [
33
+ "MabaSparseForCausalLM"
34
+ ],
35
+ "model_type": "maba_sparse",
36
+ "torch_dtype": "bfloat16",
37
+ "auto_map": {
38
+ "AutoConfig": "maba_sparse.config.MabaSparseConfig",
39
+ "AutoModelForCausalLM": "maba_sparse.model.MabaSparseForCausalLM"
40
+ }
41
+ }
maba_sparse/__init__.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from maba_sparse.config import MabaSparseConfig
2
+ from maba_sparse.layers.dgda import ConvState, DGDALayer, DecoupledGatedDeltaAttention
3
+ from maba_sparse.layers.indexer import DGIndexer, DeltaGuidedCentroidIndexer
4
+ from maba_sparse.layers.sparse_attention import MABASALayer, MabaSparseAttention
5
+
6
+ __version__ = "0.1.0"
7
+
8
+ __all__ = [
9
+ "MabaSparseConfig",
10
+ "ConvState",
11
+ "DGDALayer",
12
+ "DecoupledGatedDeltaAttention",
13
+ "DGIndexer",
14
+ "DeltaGuidedCentroidIndexer",
15
+ "MabaSparseAttention",
16
+ "MABASALayer",
17
+ "__version__",
18
+ ]
maba_sparse/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (635 Bytes). View file
 
maba_sparse/__pycache__/config.cpython-312.pyc ADDED
Binary file (4.3 kB). View file
 
maba_sparse/__pycache__/model.cpython-312.pyc ADDED
Binary file (15 kB). View file
 
maba_sparse/baselines/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from maba_sparse.baselines.dense_transformer import (
2
+ DenseAttention,
3
+ DenseTransformerBlock,
4
+ DenseTransformerForCausalLM,
5
+ DenseTransformerLM,
6
+ )
7
+
8
+ __all__ = [
9
+ "DenseAttention",
10
+ "DenseTransformerBlock",
11
+ "DenseTransformerForCausalLM",
12
+ "DenseTransformerLM",
13
+ ]
maba_sparse/baselines/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (374 Bytes). View file
 
maba_sparse/baselines/__pycache__/dense_transformer.cpython-312.pyc ADDED
Binary file (9.92 kB). View file
 
maba_sparse/baselines/dense_transformer.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from typing import Any, List, Optional, Tuple, Union
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+ from maba_sparse.model import FactorizedEmbeddings, MabaSparseOutput, RMSNorm, SwiGLUFFN
8
+
9
+
10
+ class DenseAttention(nn.Module):
11
+ def __init__(self, dim: int = 640, n_heads: int = 10, d_head: int = 64) -> None:
12
+ super().__init__()
13
+ self.dim = dim
14
+ self.n_heads = n_heads
15
+ self.d_head = d_head
16
+ self.scale = 1.0 / math.sqrt(d_head)
17
+
18
+ self.q_proj = nn.Linear(dim, n_heads * d_head, bias=False)
19
+ self.k_proj = nn.Linear(dim, n_heads * d_head, bias=False)
20
+ self.v_proj = nn.Linear(dim, n_heads * d_head, bias=False)
21
+ self.o_proj = nn.Linear(n_heads * d_head, dim, bias=False)
22
+
23
+ def forward(
24
+ self,
25
+ x: torch.Tensor,
26
+ kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
27
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
28
+ b, l, d = x.shape
29
+ q = self.q_proj(x).view(b, l, self.n_heads, self.d_head).transpose(1, 2)
30
+ k = self.k_proj(x).view(b, l, self.n_heads, self.d_head).transpose(1, 2)
31
+ v = self.v_proj(x).view(b, l, self.n_heads, self.d_head).transpose(1, 2)
32
+
33
+ if kv_cache is not None:
34
+ pk, pv = kv_cache
35
+ k = torch.cat([pk, k], dim=2)
36
+ v = torch.cat([pv, v], dim=2)
37
+
38
+ nkv = (k, v)
39
+ c = (kv_cache is None) and (l > 1)
40
+ o = F.scaled_dot_product_attention(q, k, v, is_causal=c)
41
+ o = o.transpose(1, 2).contiguous().view(b, l, self.n_heads * self.d_head)
42
+ return self.o_proj(o), nkv
43
+
44
+
45
+ class DenseTransformerBlock(nn.Module):
46
+ def __init__(
47
+ self,
48
+ dim: int = 640,
49
+ n_heads: int = 10,
50
+ d_head: int = 64,
51
+ intermediate_size: int = 1728,
52
+ eps: float = 1e-6,
53
+ residual_gate_bias: float = 2.0,
54
+ ) -> None:
55
+ super().__init__()
56
+ self.norm1 = RMSNorm(dim, eps=eps)
57
+ self.mixer = DenseAttention(dim, n_heads, d_head)
58
+ self.res_gate1 = nn.Parameter(torch.full((dim,), residual_gate_bias))
59
+
60
+ self.norm2 = RMSNorm(dim, eps=eps)
61
+ self.ffn = SwiGLUFFN(dim, intermediate_size)
62
+ self.res_gate2 = nn.Parameter(torch.full((dim,), residual_gate_bias))
63
+
64
+ def forward(
65
+ self,
66
+ x: torch.Tensor,
67
+ kv_cache: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
68
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
69
+ h = self.norm1(x)
70
+ ao, nkv = self.mixer(h, kv_cache=kv_cache)
71
+ x = x + torch.sigmoid(self.res_gate1) * ao
72
+ x = x + torch.sigmoid(self.res_gate2) * self.ffn(self.norm2(x))
73
+ return x, nkv
74
+
75
+
76
+ class DenseTransformerForCausalLM(nn.Module):
77
+ def __init__(
78
+ self,
79
+ vocab_size: int = 32768,
80
+ d_emb: int = 128,
81
+ dim: int = 640,
82
+ n_layers: int = 20,
83
+ n_heads: int = 10,
84
+ d_head: int = 64,
85
+ intermediate_size: int = 1728,
86
+ eps: float = 1e-6,
87
+ residual_gate_bias: float = 2.0,
88
+ ) -> None:
89
+ super().__init__()
90
+ self.vocab_size = vocab_size
91
+ self.dim = dim
92
+ self.n_layers = n_layers
93
+
94
+ self.embeddings = FactorizedEmbeddings(vocab_size, d_emb, dim)
95
+ self.layers = nn.ModuleList([
96
+ DenseTransformerBlock(
97
+ dim=dim,
98
+ n_heads=n_heads,
99
+ d_head=d_head,
100
+ intermediate_size=intermediate_size,
101
+ eps=eps,
102
+ residual_gate_bias=residual_gate_bias,
103
+ )
104
+ for _ in range(n_layers)
105
+ ])
106
+ self.final_norm = RMSNorm(dim, eps=eps)
107
+ self.head_proj = nn.Linear(dim, d_emb, bias=False)
108
+ self.lm_head = nn.Linear(d_emb, vocab_size, bias=False)
109
+ self.lm_head.weight = self.embeddings.in_emb.weight
110
+
111
+ def forward(
112
+ self,
113
+ input_ids: torch.Tensor,
114
+ targets: Optional[torch.Tensor] = None,
115
+ labels: Optional[torch.Tensor] = None,
116
+ past_states: Optional[List[Any]] = None,
117
+ ) -> MabaSparseOutput:
118
+ if targets is None and labels is not None:
119
+ targets = labels
120
+
121
+ x = self.embeddings(input_ids)
122
+ nps = []
123
+
124
+ for i, layer in enumerate(self.layers):
125
+ kv = past_states[i] if past_states is not None else None
126
+ x, nkv = layer(x, kv_cache=kv)
127
+ nps.append(nkv)
128
+
129
+ xn = self.final_norm(x)
130
+ logits = self.lm_head(self.head_proj(xn))
131
+
132
+ loss = None
133
+ if targets is not None:
134
+ loss = F.cross_entropy(logits.view(-1, self.vocab_size), targets.view(-1))
135
+
136
+ return MabaSparseOutput(
137
+ logits=logits,
138
+ loss=loss,
139
+ past_states=nps,
140
+ )
141
+
142
+ @torch.no_grad()
143
+ def generate(
144
+ self,
145
+ input_ids: torch.Tensor,
146
+ max_new_tokens: int = 32,
147
+ temperature: float = 1.0,
148
+ top_k: Optional[int] = 50,
149
+ ) -> torch.Tensor:
150
+ self.eval()
151
+ gen = input_ids.clone()
152
+ for _ in range(max_new_tokens):
153
+ out = self(gen)
154
+ nl = out.logits[:, -1, :]
155
+ if temperature > 0:
156
+ nl = nl / temperature
157
+ if top_k is not None:
158
+ v, _ = torch.topk(nl, min(top_k, nl.size(-1)))
159
+ nl[nl < v[:, [-1]]] = float("-inf")
160
+ p = F.softmax(nl, dim=-1)
161
+ tok = torch.multinomial(p, num_samples=1)
162
+ else:
163
+ tok = torch.argmax(nl, dim=-1, keepdim=True)
164
+ gen = torch.cat([gen, tok], dim=1)
165
+ return gen
166
+
167
+
168
+ DenseTransformerLM = DenseTransformerForCausalLM
maba_sparse/config.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import asdict, dataclass
2
+ from typing import Any, Dict
3
+
4
+
5
+ @dataclass
6
+ class MabaSparseConfig:
7
+ dim: int = 640
8
+ d_model: int = 640
9
+ n_layers: int = 16
10
+ num_layers: int = 16
11
+ n_heads: int = 10
12
+ num_heads: int = 10
13
+ d_head: int = 64
14
+ d_k: int = 64
15
+ d_v: int = 64
16
+ vocab_size: int = 32000
17
+ max_seq_len: int = 2048
18
+ d_emb: int = 320
19
+ kernel_size: int = 4
20
+ conv_kernel_size: int = 4
21
+ chunk_size: int = 16
22
+ eps: float = 1e-6
23
+ inversion_method: str = "adaptive"
24
+ inversion_threshold: float = 0.5
25
+ adaptive_tol: float = 7e-5
26
+ d_c: int = 128
27
+ d_idx: int = 64
28
+ block_size: int = 64
29
+ window_size: int = 128
30
+ top_k: int = 32
31
+ hca_pool_size: int = 64
32
+ dist_lambda: float = 0.5
33
+ intermediate_size: int = 1728
34
+ rms_norm_eps: float = 1e-6
35
+ residual_gate_bias: float = 2.0
36
+ mtp_depth: int = 2
37
+
38
+ def __post_init__(self) -> None:
39
+ if self.dim != 640 and self.d_model == 640:
40
+ self.d_model = self.dim
41
+ elif self.d_model != 640 and self.dim == 640:
42
+ self.dim = self.d_model
43
+
44
+ if self.n_heads != 10 and self.num_heads == 10:
45
+ self.num_heads = self.n_heads
46
+ elif self.num_heads != 10 and self.n_heads == 10:
47
+ self.n_heads = self.num_heads
48
+
49
+ if self.n_layers != 16 and self.num_layers == 16:
50
+ self.num_layers = self.n_layers
51
+ elif self.num_layers != 16 and self.n_layers == 16:
52
+ self.n_layers = self.num_layers
53
+
54
+ if self.kernel_size != 4 and self.conv_kernel_size == 4:
55
+ self.conv_kernel_size = self.kernel_size
56
+ elif self.conv_kernel_size != 4 and self.kernel_size == 4:
57
+ self.kernel_size = self.conv_kernel_size
58
+
59
+ if self.d_head == 64 and self.dim != 640:
60
+ self.d_head = self.dim // self.n_heads
61
+ self.d_k = self.d_head
62
+ self.d_v = self.d_head
63
+
64
+ valid_methods = {"adaptive", "neumann", "exact"}
65
+ if not isinstance(self.inversion_method, str) or self.inversion_method.lower() not in valid_methods:
66
+ raise ValueError(
67
+ f"Invalid inversion_method: '{self.inversion_method}'. "
68
+ f"Supported options: ['adaptive', 'neumann', 'exact']."
69
+ )
70
+ self.inversion_method = self.inversion_method.lower()
71
+
72
+ def to_dict(self) -> Dict[str, Any]:
73
+ return asdict(self)
74
+
75
+ @classmethod
76
+ def from_dict(cls, d: Dict[str, Any]) -> "MabaSparseConfig":
77
+ return cls(**d)
maba_sparse/layers/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from maba_sparse.layers.dgda import ConvState, DGDALayer, DecoupledGatedDeltaAttention
2
+ from maba_sparse.layers.indexer import DGIndexer, DeltaGuidedCentroidIndexer
3
+ from maba_sparse.layers.sparse_attention import MABASALayer, MabaSparseAttention
4
+
5
+ __all__ = [
6
+ "ConvState",
7
+ "DGDALayer",
8
+ "DecoupledGatedDeltaAttention",
9
+ "DGIndexer",
10
+ "DeltaGuidedCentroidIndexer",
11
+ "MABASALayer",
12
+ "MabaSparseAttention",
13
+ ]
maba_sparse/layers/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (543 Bytes). View file
 
maba_sparse/layers/__pycache__/dgda.cpython-312.pyc ADDED
Binary file (24.5 kB). View file
 
maba_sparse/layers/__pycache__/indexer.cpython-312.pyc ADDED
Binary file (4.19 kB). View file
 
maba_sparse/layers/__pycache__/sparse_attention.cpython-312.pyc ADDED
Binary file (12.2 kB). View file
 
maba_sparse/layers/dgda.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Optional, Tuple, Union
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+
8
+ class ConvState(tuple):
9
+ @property
10
+ def shape(self) -> torch.Size:
11
+ if len(self) == 0:
12
+ return torch.Size([0, 0, 0, 0])
13
+ f = self[0]
14
+ return torch.Size([f.shape[0], len(self), f.shape[1], f.shape[2]])
15
+
16
+ def as_tensor(self) -> torch.Tensor:
17
+ return torch.stack(self, dim=1)
18
+
19
+
20
+ class DGDALayer(nn.Module):
21
+ def __init__(
22
+ self,
23
+ config: Optional[Any] = None,
24
+ dim: int = 640,
25
+ n_heads: int = 10,
26
+ d_head: Optional[int] = None,
27
+ kernel_size: int = 4,
28
+ eps: float = 1e-6,
29
+ ) -> None:
30
+ super().__init__()
31
+ if config is not None:
32
+ dim = getattr(config, "dim", getattr(config, "d_model", dim))
33
+ n_heads = getattr(config, "n_heads", getattr(config, "num_heads", n_heads))
34
+ d_head = getattr(config, "d_head", d_head)
35
+ kernel_size = getattr(
36
+ config, "kernel_size", getattr(config, "conv_kernel_size", kernel_size)
37
+ )
38
+ eps = getattr(config, "eps", getattr(config, "rms_norm_eps", eps))
39
+
40
+ self.dim = dim
41
+ self.n_heads = n_heads
42
+ self.d_head = d_head if d_head is not None else (dim // n_heads)
43
+ self.d_k = self.d_head
44
+ self.d_v = self.d_head
45
+ self.kernel_size = kernel_size
46
+ self.k_size = kernel_size
47
+ self.eps = eps
48
+ self.chunk_size = getattr(config, "chunk_size", 16)
49
+ self.inversion_method = getattr(config, "inversion_method", "adaptive")
50
+ self.adaptive_tol = getattr(config, "adaptive_tol", 7e-5)
51
+
52
+ self.q_proj = nn.Linear(self.dim, self.n_heads * self.d_k, bias=False)
53
+ self.k_proj = nn.Linear(self.dim, self.n_heads * self.d_k, bias=False)
54
+ self.v_proj = nn.Linear(self.dim, self.n_heads * self.d_v, bias=False)
55
+
56
+ self.conv_q = nn.Conv1d(
57
+ self.dim, self.dim, self.kernel_size, groups=self.dim, bias=False, padding=0
58
+ )
59
+ self.conv_k = nn.Conv1d(
60
+ self.dim, self.dim, self.kernel_size, groups=self.dim, bias=False, padding=0
61
+ )
62
+ self.conv_v = nn.Conv1d(
63
+ self.dim, self.dim, self.kernel_size, groups=self.dim, bias=False, padding=0
64
+ )
65
+
66
+ self.gate_alpha = nn.Linear(self.dim, self.n_heads * self.d_k, bias=False)
67
+ self.gate_erase = nn.Linear(self.dim, self.n_heads * self.d_k, bias=False)
68
+ self.gate_write = nn.Linear(self.dim, self.n_heads * self.d_v, bias=False)
69
+
70
+ self.alpha_proj = self.gate_alpha
71
+ self.b_proj = self.gate_erase
72
+ self.w_proj = self.gate_write
73
+ self.o_proj = nn.Linear(self.n_heads * self.d_v, self.dim, bias=False)
74
+
75
+ self._reset_parameters()
76
+
77
+ def _reset_parameters(self) -> None:
78
+ nn.init.xavier_uniform_(self.q_proj.weight)
79
+ nn.init.xavier_uniform_(self.k_proj.weight)
80
+ nn.init.xavier_uniform_(self.v_proj.weight)
81
+ nn.init.xavier_uniform_(self.gate_alpha.weight)
82
+ nn.init.xavier_uniform_(self.gate_erase.weight)
83
+ nn.init.xavier_uniform_(self.gate_write.weight)
84
+ nn.init.xavier_uniform_(self.o_proj.weight)
85
+ nn.init.normal_(self.conv_q.weight, mean=0.0, std=0.02)
86
+ nn.init.normal_(self.conv_k.weight, mean=0.0, std=0.02)
87
+ nn.init.normal_(self.conv_v.weight, mean=0.0, std=0.02)
88
+
89
+ def _apply_conv(
90
+ self,
91
+ x: torch.Tensor,
92
+ conv: nn.Conv1d,
93
+ conv_state: Optional[torch.Tensor] = None,
94
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
95
+ k = self.kernel_size
96
+ xt = x.transpose(1, 2)
97
+ p = torch.cat([conv_state, xt], dim=2) if conv_state is not None else F.pad(xt, (k - 1, 0))
98
+ ns = p[:, :, -(k - 1):].contiguous()
99
+ y = F.silu(conv(p)).transpose(1, 2)
100
+ return y, ns
101
+
102
+ def _unpack_conv_state(
103
+ self,
104
+ conv_state: Optional[Union[ConvState, Tuple[torch.Tensor, ...], torch.Tensor]],
105
+ b_size: int,
106
+ device: torch.device,
107
+ dtype: torch.dtype,
108
+ ) -> Tuple[Optional[torch.Tensor], Optional[torch.Tensor], Optional[torch.Tensor]]:
109
+ if conv_state is None:
110
+ return None, None, None
111
+ if isinstance(conv_state, (tuple, list)):
112
+ if len(conv_state) == 3:
113
+ return conv_state[0], conv_state[1], conv_state[2]
114
+ if len(conv_state) == 1 and isinstance(conv_state[0], (tuple, list)):
115
+ return conv_state[0][0], conv_state[0][1], conv_state[0][2]
116
+ if isinstance(conv_state, torch.Tensor):
117
+ if conv_state.dim() == 4 and conv_state.shape[1] == 3:
118
+ return conv_state[:, 0], conv_state[:, 1], conv_state[:, 2]
119
+ if conv_state.dim() == 5 and conv_state.shape[1] == 3:
120
+ cs = conv_state.view(b_size, 3, self.dim, self.kernel_size - 1)
121
+ return cs[:, 0], cs[:, 1], cs[:, 2]
122
+ if conv_state.dim() == 4:
123
+ cs = conv_state.view(b_size, self.dim, self.kernel_size - 1)
124
+ return cs, cs, cs
125
+ if conv_state.dim() == 3:
126
+ return conv_state, conv_state, conv_state
127
+ raise ValueError(f"Unsupported conv_state shape or type: {type(conv_state)}")
128
+
129
+ def _chunk_neumann(
130
+ self,
131
+ q: torch.Tensor,
132
+ k: torch.Tensor,
133
+ v: torch.Tensor,
134
+ b: torch.Tensor,
135
+ w: torch.Tensor,
136
+ log_alpha: torch.Tensor,
137
+ S0: torch.Tensor,
138
+ inversion_method: Optional[str] = None,
139
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
140
+ t = q.shape[2]
141
+ cla = torch.cumsum(log_alpha, dim=-2)
142
+ diff = cla.unsqueeze(3) - cla.unsqueeze(2)
143
+ dec = torch.exp(torch.clamp(diff, max=0.0))
144
+
145
+ bk = (b * k).unsqueeze(3)
146
+ ks = k.unsqueeze(2)
147
+ l_mat = torch.tril((bk * dec * ks).sum(dim=-1), diagonal=-1)
148
+
149
+ lam = torch.exp(cla)
150
+ bh = (b * k) * lam
151
+ ve = (w * v) - torch.matmul(bh, S0)
152
+
153
+ eye = torch.eye(t, dtype=q.dtype, device=q.device).view(1, 1, t, t)
154
+ l2 = torch.matmul(l_mat, l_mat)
155
+ l3 = torch.matmul(l2, l_mat)
156
+ inv_l = eye - l_mat + l2 - l3
157
+ u_neu = torch.matmul(inv_l, ve)
158
+
159
+ m = inversion_method if inversion_method is not None else getattr(self, "inversion_method", "adaptive")
160
+ tol = getattr(self, "adaptive_tol", 7e-5)
161
+
162
+ if m == "neumann":
163
+ exact = False
164
+ elif m == "exact":
165
+ exact = True
166
+ elif m == "adaptive":
167
+ r = ve - u_neu - torch.matmul(l_mat, u_neu)
168
+ exact = r.abs().max() > tol or torch.isnan(u_neu).any() or torch.isinf(u_neu).any()
169
+ else:
170
+ raise ValueError(f"Unknown inversion_method: '{m}'")
171
+
172
+ if not exact:
173
+ u = u_neu
174
+ clae = cla[:, :, -1:, :]
175
+ dte = torch.exp(clae - cla)
176
+ kd = k * dte
177
+ sc = torch.matmul(kd.transpose(-1, -2), u)
178
+ ds0 = torch.exp(clae).transpose(-1, -2)
179
+ sf = ds0 * S0 + sc
180
+
181
+ oi = torch.matmul(q * lam, S0)
182
+ qs = q.unsqueeze(3)
183
+ a_mat = torch.tril((qs * dec * ks).sum(dim=-1), diagonal=0)
184
+ ot = torch.matmul(a_mat, u)
185
+ return oi + ot, sf
186
+ else:
187
+ orig_dt = q.dtype
188
+ if q.device.type == "cpu":
189
+ qd, kd, vd, bd, wd, lad, s0d = [x.double() for x in (q, k, v, b, w, log_alpha, S0)]
190
+ clad = torch.cumsum(lad, dim=-2)
191
+ diffd = clad.unsqueeze(3) - clad.unsqueeze(2)
192
+ decd = torch.exp(torch.clamp(diffd, max=0.0))
193
+ bkd = (bd * kd).unsqueeze(3)
194
+ ksd = kd.unsqueeze(2)
195
+ ld = torch.tril((bkd * decd * ksd).sum(dim=-1), diagonal=-1)
196
+ lamd = torch.exp(clad)
197
+ bhd = (bd * kd) * lamd
198
+ ved = (wd * vd) - torch.matmul(bhd, s0d)
199
+ eyed = torch.eye(t, dtype=torch.float64, device=q.device).view(1, 1, t, t)
200
+ ud = torch.linalg.solve_triangular(eyed + ld, ved, upper=False)
201
+
202
+ claed = clad[:, :, -1:, :]
203
+ dted = torch.exp(claed - clad)
204
+ kdd = kd * dted
205
+ scd = torch.matmul(kdd.transpose(-1, -2), ud)
206
+ ds0d = torch.exp(claed).transpose(-1, -2)
207
+ sfd = ds0d * s0d + scd
208
+
209
+ oid = torch.matmul(qd * lamd, s0d)
210
+ qsd = qd.unsqueeze(3)
211
+ ad = torch.tril((qsd * decd * ksd).sum(dim=-1), diagonal=0)
212
+ otd = torch.matmul(ad, ud)
213
+ return (oid + otd).to(orig_dt), sfd.to(orig_dt)
214
+ else:
215
+ cdt = torch.float32 if q.dtype in (torch.float16, torch.bfloat16) else q.dtype
216
+ u = torch.linalg.solve_triangular((eye + l_mat).to(cdt), ve.to(cdt), upper=False).to(orig_dt)
217
+ clae = cla[:, :, -1:, :]
218
+ dte = torch.exp(clae - cla)
219
+ kd = k * dte
220
+ sc = torch.matmul(kd.transpose(-1, -2), u)
221
+ ds0 = torch.exp(clae).transpose(-1, -2)
222
+ sf = ds0 * S0 + sc
223
+
224
+ oi = torch.matmul(q * lam, S0)
225
+ qs = q.unsqueeze(3)
226
+ a_mat = torch.tril((qs * dec * ks).sum(dim=-1), diagonal=0)
227
+ ot = torch.matmul(a_mat, u)
228
+ return oi + ot, sf
229
+
230
+ def forward(
231
+ self,
232
+ x: torch.Tensor,
233
+ state: Optional[torch.Tensor] = None,
234
+ conv_state: Optional[Union[torch.Tensor, Tuple[torch.Tensor, ...]]] = None,
235
+ chunk_size: int = 16,
236
+ inversion_method: Optional[str] = None,
237
+ ) -> Tuple[torch.Tensor, torch.Tensor, ConvState]:
238
+ b, l, d = x.shape
239
+ h, dk, dv = self.n_heads, self.d_k, self.d_v
240
+
241
+ if l == 0:
242
+ eo = torch.empty(b, 0, d, dtype=x.dtype, device=x.device)
243
+ es = state if state is not None else torch.zeros(b, h, dk, dv, dtype=x.dtype, device=x.device)
244
+ zc = torch.zeros(b, d, self.kernel_size - 1, dtype=x.dtype, device=x.device)
245
+ return eo, es, ConvState((zc, zc, zc))
246
+
247
+ cq, ck, cv = self._unpack_conv_state(conv_state, b, x.device, x.dtype)
248
+ q, nq = self._apply_conv(self.q_proj(x), self.conv_q, cq)
249
+ k, nk = self._apply_conv(self.k_proj(x), self.conv_k, ck)
250
+ v, nv = self._apply_conv(self.v_proj(x), self.conv_v, cv)
251
+ ncs = ConvState((nq, nk, nv))
252
+
253
+ eb = torch.sigmoid(self.gate_erase(x))
254
+ ew = torch.sigmoid(self.gate_write(x))
255
+ la = -F.softplus(self.gate_alpha(x))
256
+
257
+ q = q.view(b, l, h, dk).transpose(1, 2)
258
+ k = k.view(b, l, h, dk).transpose(1, 2)
259
+ v = v.view(b, l, h, dv).transpose(1, 2)
260
+ eb = eb.view(b, l, h, dk).transpose(1, 2)
261
+ ew = ew.view(b, l, h, dv).transpose(1, 2)
262
+ la = la.view(b, l, h, dk).transpose(1, 2)
263
+
264
+ k = k / (torch.linalg.vector_norm(k, dim=-1, keepdim=True) + self.eps)
265
+
266
+ cs = torch.zeros(b, h, dk, dv, dtype=x.dtype, device=x.device) if state is None else state.clone()
267
+
268
+ n_chunks = l // chunk_size
269
+ rem = l % chunk_size
270
+ outs = []
271
+
272
+ for i in range(n_chunks):
273
+ s = i * chunk_size
274
+ e = s + chunk_size
275
+ oc, cs = self._chunk_neumann(
276
+ q[:, :, s:e], k[:, :, s:e], v[:, :, s:e], eb[:, :, s:e], ew[:, :, s:e], la[:, :, s:e], cs, inversion_method=inversion_method
277
+ )
278
+ outs.append(oc)
279
+
280
+ if rem > 0:
281
+ s = n_chunks * chunk_size
282
+ oc, cs = self._chunk_neumann(
283
+ q[:, :, s:], k[:, :, s:], v[:, :, s:], eb[:, :, s:], ew[:, :, s:], la[:, :, s:], cs, inversion_method=inversion_method
284
+ )
285
+ outs.append(oc)
286
+
287
+ o = torch.cat(outs, dim=2).transpose(1, 2).contiguous().view(b, l, h * dv)
288
+ return self.o_proj(o), cs, ncs
289
+
290
+ def step(
291
+ self,
292
+ x: torch.Tensor,
293
+ state: Optional[torch.Tensor] = None,
294
+ conv_state: Optional[Union[torch.Tensor, Tuple[torch.Tensor, ...]]] = None,
295
+ ) -> Tuple[torch.Tensor, torch.Tensor, ConvState]:
296
+ b, l = x.shape[0], x.shape[1]
297
+ assert l == 1
298
+ h, dk, dv = self.n_heads, self.d_k, self.d_v
299
+
300
+ cq, ck, cv = self._unpack_conv_state(conv_state, b, x.device, x.dtype)
301
+ q, nq = self._apply_conv(self.q_proj(x), self.conv_q, cq)
302
+ k, nk = self._apply_conv(self.k_proj(x), self.conv_k, ck)
303
+ v, nv = self._apply_conv(self.v_proj(x), self.conv_v, cv)
304
+ ncs = ConvState((nq, nk, nv))
305
+
306
+ eb = torch.sigmoid(self.gate_erase(x)).view(b, 1, h, dk).transpose(1, 2)
307
+ ew = torch.sigmoid(self.gate_write(x)).view(b, 1, h, dv).transpose(1, 2)
308
+ la = -F.softplus(self.gate_alpha(x)).view(b, 1, h, dk).transpose(1, 2)
309
+ alpha = torch.exp(la)
310
+
311
+ q = q.view(b, 1, h, dk).transpose(1, 2)
312
+ k = k.view(b, 1, h, dk).transpose(1, 2)
313
+ v = v.view(b, 1, h, dv).transpose(1, 2)
314
+
315
+ k = k / (torch.linalg.vector_norm(k, dim=-1, keepdim=True) + self.eps)
316
+
317
+ sp = torch.zeros(b, h, dk, dv, dtype=x.dtype, device=x.device) if state is None else state
318
+ sd = alpha.transpose(-1, -2) * sp
319
+ beta = eb * k
320
+ bs = torch.matmul(beta, sd)
321
+ delta = (ew * v) - bs
322
+ st = sd + torch.matmul(k.transpose(-1, -2), delta)
323
+
324
+ oh = torch.matmul(q, st)
325
+ o = self.o_proj(oh.transpose(1, 2).reshape(b, 1, h * dv))
326
+ return o, st, ncs
327
+
328
+
329
+ DecoupledGatedDeltaAttention = DGDALayer
maba_sparse/layers/indexer.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from typing import Any, Optional, Tuple
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+
8
+ class DGIndexer(nn.Module):
9
+ def __init__(
10
+ self,
11
+ dim: int = 640,
12
+ d_idx: int = 64,
13
+ block_size: int = 64,
14
+ top_k: int = 32,
15
+ dist_lambda: float = 0.5,
16
+ config: Optional[Any] = None,
17
+ ) -> None:
18
+ super().__init__()
19
+ if config is not None:
20
+ dim = getattr(config, "dim", getattr(config, "d_model", dim))
21
+ d_idx = getattr(config, "d_idx", d_idx)
22
+ block_size = getattr(config, "block_size", block_size)
23
+ top_k = getattr(config, "top_k", top_k)
24
+ dist_lambda = getattr(config, "dist_lambda", dist_lambda)
25
+
26
+ self.dim = dim
27
+ self.d_idx = d_idx
28
+ self.block_size = block_size
29
+ self.top_k = top_k
30
+ self.dist_lambda = dist_lambda
31
+
32
+ self.q_idx_proj = nn.Linear(dim, d_idx, bias=False)
33
+ self.k_idx_proj = nn.Linear(dim, d_idx, bias=False)
34
+ self.scale = 1.0 / math.sqrt(d_idx)
35
+
36
+ def forward(
37
+ self,
38
+ x: torch.Tensor,
39
+ top_k: Optional[int] = None,
40
+ dist_lambda: Optional[float] = None,
41
+ return_scores: bool = False,
42
+ ) -> Tuple[torch.Tensor, ...]:
43
+ b, l, d = x.shape
44
+ k = self.top_k if top_k is None else top_k
45
+ lam = self.dist_lambda if dist_lambda is None else dist_lambda
46
+
47
+ qi = self.q_idx_proj(x) * self.scale
48
+ ki = self.k_idx_proj(x)
49
+
50
+ nb = (l + self.block_size - 1) // self.block_size
51
+ pad = nb * self.block_size - l
52
+ kp = F.pad(ki, (0, 0, 0, pad), value=0.0) if pad > 0 else ki
53
+
54
+ kb = kp.view(b, nb, self.block_size, self.d_idx)
55
+ c = 0.5 * (kb.mean(dim=2) + kb.max(dim=2)[0])
56
+
57
+ s = torch.einsum("bld,bnd->bln", qi, c)
58
+
59
+ qi_idx = torch.arange(l, device=x.device).unsqueeze(1) // self.block_size
60
+ ni_idx = torch.arange(nb, device=x.device).unsqueeze(0)
61
+ dist = (qi_idx - ni_idx).abs().float()
62
+ pen = lam * torch.log(1.0 + dist)
63
+ sc = s - pen.unsqueeze(0)
64
+
65
+ msk = ni_idx > qi_idx
66
+ sc = sc.masked_fill(msk.unsqueeze(0), float("-inf"))
67
+
68
+ ak = min(k, nb)
69
+ _, idx = torch.topk(sc, k=ak, dim=-1)
70
+
71
+ if return_scores:
72
+ return idx, c, sc
73
+ return idx, c
74
+
75
+
76
+ DeltaGuidedCentroidIndexer = DGIndexer
maba_sparse/layers/sparse_attention.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from typing import Any, Optional, Tuple
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+ from maba_sparse.layers.indexer import DGIndexer
8
+
9
+
10
+ class MabaSparseAttention(nn.Module):
11
+ def __init__(
12
+ self,
13
+ config: Optional[Any] = None,
14
+ dim: int = 640,
15
+ n_heads: int = 10,
16
+ d_head: int = 64,
17
+ d_c: int = 128,
18
+ window_size: int = 128,
19
+ block_size: int = 64,
20
+ top_k: int = 32,
21
+ hca_pool_size: int = 64,
22
+ dist_lambda: float = 0.5,
23
+ d_idx: int = 64,
24
+ ) -> None:
25
+ super().__init__()
26
+ if config is not None:
27
+ self.dim = getattr(config, "dim", getattr(config, "d_model", dim))
28
+ self.n_heads = getattr(config, "n_heads", getattr(config, "num_heads", n_heads))
29
+ self.d_head = getattr(config, "d_head", d_head)
30
+ self.d_c = getattr(config, "d_c", d_c)
31
+ self.window_size = getattr(config, "window_size", window_size)
32
+ self.block_size = getattr(config, "block_size", block_size)
33
+ self.top_k = getattr(config, "top_k", top_k)
34
+ self.hca_pool_size = getattr(config, "hca_pool_size", hca_pool_size)
35
+ self.dist_lambda = getattr(config, "dist_lambda", dist_lambda)
36
+ d_idx = getattr(config, "d_idx", d_idx)
37
+ else:
38
+ self.dim = dim
39
+ self.n_heads = n_heads
40
+ self.d_head = d_head
41
+ self.d_c = d_c
42
+ self.window_size = window_size
43
+ self.block_size = block_size
44
+ self.top_k = top_k
45
+ self.hca_pool_size = hca_pool_size
46
+ self.dist_lambda = dist_lambda
47
+
48
+ self.scale = 1.0 / math.sqrt(self.d_head)
49
+ self.q_proj = nn.Linear(self.dim, self.n_heads * self.d_head, bias=False)
50
+ self.kv_down_proj = nn.Linear(self.dim, self.d_c, bias=False)
51
+ self.k_up_proj = nn.Linear(self.d_c, self.n_heads * self.d_head, bias=False)
52
+ self.v_up_proj = nn.Linear(self.d_c, self.n_heads * self.d_head, bias=False)
53
+ self.o_proj = nn.Linear(self.n_heads * self.d_head, self.dim, bias=False)
54
+ self.stream_gate = nn.Linear(self.dim, 3, bias=True)
55
+ self.indexer = DGIndexer(
56
+ dim=self.dim,
57
+ d_idx=d_idx,
58
+ block_size=self.block_size,
59
+ top_k=self.top_k,
60
+ dist_lambda=self.dist_lambda,
61
+ )
62
+
63
+ def get_gate_weights(self, x: torch.Tensor) -> torch.Tensor:
64
+ return F.softmax(self.stream_gate(x), dim=-1)
65
+
66
+ def _compute_local_attention(
67
+ self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, L_full: int
68
+ ) -> torch.Tensor:
69
+ b, h, lq, _ = q.shape
70
+ lkv = k.shape[2]
71
+ a = torch.matmul(q, k.transpose(-1, -2)) * self.scale
72
+ qo = lkv - lq
73
+ i = (qo + torch.arange(lq, device=q.device)).unsqueeze(1)
74
+ j = torch.arange(lkv, device=q.device).unsqueeze(0)
75
+ c = j <= i
76
+ w = (i - j) < self.window_size
77
+ s = j < min(4, lkv)
78
+ m = c & (w | s)
79
+ a = a.masked_fill(~m.unsqueeze(0).unsqueeze(0), float("-inf"))
80
+ p = torch.nan_to_num(F.softmax(a, dim=-1), nan=0.0)
81
+ return torch.matmul(p, v)
82
+
83
+ def _compute_sparse_attention(
84
+ self,
85
+ q: torch.Tensor,
86
+ k: torch.Tensor,
87
+ v: torch.Tensor,
88
+ top_indices: torch.Tensor,
89
+ L_full: int,
90
+ ) -> torch.Tensor:
91
+ b, h, lq, _ = q.shape
92
+ lkv = k.shape[2]
93
+ nb = (lkv + self.block_size - 1) // self.block_size
94
+ bm = torch.zeros(b, lq, nb, device=q.device, dtype=torch.bool)
95
+ bm.scatter_(2, top_indices, True)
96
+ tbi = torch.arange(lkv, device=q.device) // self.block_size
97
+ tm = bm[:, :, tbi]
98
+ qo = lkv - lq
99
+ i = (qo + torch.arange(lq, device=q.device)).unsqueeze(1)
100
+ j = torch.arange(lkv, device=q.device).unsqueeze(0)
101
+ tm = tm & (j <= i).unsqueeze(0)
102
+ a = torch.matmul(q, k.transpose(-1, -2)) * self.scale
103
+ a = a.masked_fill(~tm.unsqueeze(1), float("-inf"))
104
+ a = torch.nan_to_num(a, nan=-1e9, neginf=-1e9)
105
+ p = torch.nan_to_num(F.softmax(a, dim=-1), nan=0.0)
106
+ return torch.matmul(p, v)
107
+
108
+ def _compute_hca_attention(
109
+ self, q: torch.Tensor, c_kv: torch.Tensor, L_full: int
110
+ ) -> torch.Tensor:
111
+ b, h, lq, dh = q.shape
112
+ lkv = c_kv.shape[1]
113
+ r = self.hca_pool_size
114
+ nt = (lkv + r - 1) // r
115
+ if nt == 0:
116
+ return torch.zeros(b, h, lq, dh, device=q.device, dtype=q.dtype)
117
+ pad = nt * r - lkv
118
+ cp = F.pad(c_kv, (0, 0, 0, pad)) if pad > 0 else c_kv
119
+ c_pool = cp.view(b, nt, r, self.d_c).mean(dim=2)
120
+ kh = self.k_up_proj(c_pool).view(b, nt, h, dh).transpose(1, 2)
121
+ vh = self.v_up_proj(c_pool).view(b, nt, h, dh).transpose(1, 2)
122
+ a = torch.matmul(q, kh.transpose(-1, -2)) * self.scale
123
+ qo = lkv - lq
124
+ qi = (qo + torch.arange(lq, device=q.device)).unsqueeze(1)
125
+ bs = torch.arange(nt, device=q.device) + 1
126
+ ei = (bs * r - 1).unsqueeze(0)
127
+ c = ei <= qi
128
+ a = a.masked_fill(~c.unsqueeze(0).unsqueeze(0), float("-inf"))
129
+ p = torch.nan_to_num(F.softmax(a, dim=-1), nan=0.0)
130
+ return torch.matmul(p, vh)
131
+
132
+ def forward(
133
+ self, x: torch.Tensor, past_c_kv: Optional[torch.Tensor] = None
134
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
135
+ b, l, d = x.shape
136
+ c_kv = self.kv_down_proj(x)
137
+ c_full = torch.cat([past_c_kv, c_kv], dim=1) if past_c_kv is not None else c_kv
138
+ lf = c_full.shape[1]
139
+
140
+ q = self.q_proj(x).view(b, l, self.n_heads, self.d_head).transpose(1, 2)
141
+ k = self.k_up_proj(c_full).view(b, lf, self.n_heads, self.d_head).transpose(1, 2)
142
+ v = self.v_up_proj(c_full).view(b, lf, self.n_heads, self.d_head).transpose(1, 2)
143
+
144
+ ol = self._compute_local_attention(q, k, v, lf)
145
+ idx, _ = self.indexer(x)
146
+ os = self._compute_sparse_attention(q, k, v, idx, lf)
147
+ oh = self._compute_hca_attention(q, c_full, lf)
148
+
149
+ g = F.softmax(self.stream_gate(x), dim=-1)
150
+ gl = g[:, :, 0:1].unsqueeze(1)
151
+ gs = g[:, :, 1:2].unsqueeze(1)
152
+ gh = g[:, :, 2:3].unsqueeze(1)
153
+
154
+ o = gl * ol + gs * os + gh * oh
155
+ o = o.transpose(1, 2).contiguous().view(b, l, self.n_heads * self.d_head)
156
+ return self.o_proj(o), c_full
157
+
158
+
159
+ MABASALayer = MabaSparseAttention
maba_sparse/model.py ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ import math
3
+ from typing import Any, List, Optional, Tuple, Union
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+
8
+ from maba_sparse.config import MabaSparseConfig
9
+ from maba_sparse.layers.dgda import DGDALayer
10
+ from maba_sparse.layers.sparse_attention import MabaSparseAttention
11
+
12
+
13
+ class RMSNorm(nn.Module):
14
+ def __init__(self, dim: int, eps: float = 1e-6) -> None:
15
+ super().__init__()
16
+ self.eps = eps
17
+ self.weight = nn.Parameter(torch.ones(dim))
18
+
19
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
20
+ v = x.pow(2).mean(-1, keepdim=True)
21
+ return x * torch.rsqrt(v + self.eps) * self.weight
22
+
23
+
24
+ class SwiGLUFFN(nn.Module):
25
+ def __init__(self, dim: int, intermediate_size: int) -> None:
26
+ super().__init__()
27
+ self.w_gate = nn.Linear(dim, intermediate_size, bias=False)
28
+ self.w_up = nn.Linear(dim, intermediate_size, bias=False)
29
+ self.w_down = nn.Linear(intermediate_size, dim, bias=False)
30
+
31
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
32
+ return self.w_down(F.silu(self.w_gate(x)) * self.w_up(x))
33
+
34
+
35
+ class FactorizedEmbeddings(nn.Module):
36
+ def __init__(self, vocab_size: int, d_emb: int, dim: int) -> None:
37
+ super().__init__()
38
+ self.vocab_size = vocab_size
39
+ self.d_emb = d_emb
40
+ self.dim = dim
41
+ self.in_emb = nn.Embedding(vocab_size, d_emb)
42
+ self.proj = nn.Linear(d_emb, dim, bias=False)
43
+
44
+ def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
45
+ return self.proj(self.in_emb(input_ids))
46
+
47
+
48
+ class MTPHead(nn.Module):
49
+ def __init__(self, dim: int, d_emb: int, lm_head: nn.Linear) -> None:
50
+ super().__init__()
51
+ self.proj = nn.Linear(dim, d_emb, bias=False)
52
+ self.lm_head = lm_head
53
+
54
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
55
+ return self.lm_head(self.proj(x))
56
+
57
+
58
+ class MabaBlock(nn.Module):
59
+ def __init__(
60
+ self,
61
+ config: MabaSparseConfig,
62
+ layer_idx: int,
63
+ ablation_mode: str = "full",
64
+ ) -> None:
65
+ super().__init__()
66
+ self.layer_idx = layer_idx
67
+ self.ablation_mode = ablation_mode
68
+
69
+ if ablation_mode == "pure_dgda":
70
+ self.is_attention = False
71
+ else:
72
+ self.is_attention = (layer_idx + 1) % 4 == 0
73
+
74
+ self.norm1 = RMSNorm(config.dim, eps=config.rms_norm_eps)
75
+ if self.is_attention:
76
+ self.mixer = MabaSparseAttention(config)
77
+ else:
78
+ self.mixer = DGDALayer(config)
79
+
80
+ self.norm2 = RMSNorm(config.dim, eps=config.rms_norm_eps)
81
+ inter = getattr(config, "intermediate_size", 1248)
82
+ self.ffn = SwiGLUFFN(config.dim, inter)
83
+
84
+ b = getattr(config, "residual_gate_bias", 2.0)
85
+ self.res_gate1 = nn.Parameter(torch.full((config.dim,), b))
86
+ self.res_gate2 = nn.Parameter(torch.full((config.dim,), b))
87
+
88
+ def forward(
89
+ self,
90
+ x: torch.Tensor,
91
+ state: Optional[torch.Tensor] = None,
92
+ conv_state: Optional[torch.Tensor] = None,
93
+ past_c_kv: Optional[torch.Tensor] = None,
94
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[torch.Tensor], Optional[torch.Tensor]]:
95
+ h = self.norm1(x)
96
+ if self.is_attention:
97
+ mo, nc = self.mixer(h, past_c_kv=past_c_kv)
98
+ ns, ncv = None, None
99
+ else:
100
+ mo, ns, ncv = self.mixer(h, state=state, conv_state=conv_state)
101
+ nc = None
102
+
103
+ x = x + torch.sigmoid(self.res_gate1) * mo
104
+ x = x + torch.sigmoid(self.res_gate2) * self.ffn(self.norm2(x))
105
+ return x, ns, ncv, nc
106
+
107
+
108
+ class MabaSparseOutput:
109
+ def __init__(
110
+ self,
111
+ logits: torch.Tensor,
112
+ loss: Optional[torch.Tensor] = None,
113
+ mtp_logits: Optional[torch.Tensor] = None,
114
+ past_states: Optional[List[Any]] = None,
115
+ ) -> None:
116
+ self.logits = logits
117
+ self.loss = loss
118
+ self.mtp_logits = mtp_logits
119
+ self.past_states = past_states
120
+
121
+ def __iter__(self):
122
+ return iter((self.logits, self.loss))
123
+
124
+ def __getitem__(self, idx: int) -> Any:
125
+ return (self.logits, self.loss, self.mtp_logits, self.past_states)[idx]
126
+
127
+ def __repr__(self) -> str:
128
+ return (
129
+ f"MabaSparseOutput(logits={tuple(self.logits.shape)}, "
130
+ f"loss={self.loss.item() if self.loss is not None else None}, "
131
+ f"mtp_logits={tuple(self.mtp_logits.shape) if self.mtp_logits is not None else None})"
132
+ )
133
+
134
+
135
+ def get_101m_config(
136
+ intermediate_size: int = 1248,
137
+ vocab_size: int = 32768,
138
+ d_emb: int = 128,
139
+ n_layers: int = 20,
140
+ ) -> MabaSparseConfig:
141
+ return MabaSparseConfig(
142
+ dim=640,
143
+ n_heads=10,
144
+ d_head=64,
145
+ n_layers=n_layers,
146
+ vocab_size=vocab_size,
147
+ d_emb=d_emb,
148
+ intermediate_size=intermediate_size,
149
+ residual_gate_bias=2.0,
150
+ )
151
+
152
+
153
+ class MabaSparseForCausalLM(nn.Module):
154
+ def __init__(
155
+ self,
156
+ config: Optional[MabaSparseConfig] = None,
157
+ ablation_mode: str = "full",
158
+ ) -> None:
159
+ super().__init__()
160
+ if config is None:
161
+ config = get_101m_config()
162
+ self.config = config
163
+ self.ablation_mode = ablation_mode
164
+
165
+ v = getattr(config, "vocab_size", 32768)
166
+ de = getattr(config, "d_emb", 128)
167
+ d = getattr(config, "dim", 640)
168
+ nl = getattr(config, "n_layers", 20)
169
+
170
+ self.embeddings = FactorizedEmbeddings(v, de, d)
171
+ self.layers = nn.ModuleList([
172
+ MabaBlock(config, i, ablation_mode=ablation_mode) for i in range(nl)
173
+ ])
174
+ self.final_norm = RMSNorm(d, eps=config.rms_norm_eps)
175
+ self.head_proj = nn.Linear(d, de, bias=False)
176
+ self.lm_head = nn.Linear(de, v, bias=False)
177
+ self.lm_head.weight = self.embeddings.in_emb.weight
178
+ self.mtp_head = MTPHead(d, de, self.lm_head)
179
+
180
+ def forward(
181
+ self,
182
+ input_ids: torch.Tensor,
183
+ targets: Optional[torch.Tensor] = None,
184
+ labels: Optional[torch.Tensor] = None,
185
+ past_states: Optional[List[Any]] = None,
186
+ ) -> MabaSparseOutput:
187
+ if targets is None and labels is not None:
188
+ targets = labels
189
+
190
+ b, l = input_ids.shape
191
+ x = self.embeddings(input_ids)
192
+
193
+ nps = []
194
+ for i, layer in enumerate(self.layers):
195
+ ls = past_states[i] if past_states is not None else None
196
+ st = ls[0] if ls else None
197
+ cv = ls[1] if ls else None
198
+ pk = ls[2] if ls else None
199
+
200
+ x, nst, ncv, nck = layer(x, state=st, conv_state=cv, past_c_kv=pk)
201
+ nps.append((nst, ncv, nck))
202
+
203
+ xn = self.final_norm(x)
204
+ logits = self.lm_head(self.head_proj(xn))
205
+
206
+ loss = None
207
+ mtp_logits = None
208
+ if targets is not None:
209
+ loss = F.cross_entropy(logits.view(-1, self.config.vocab_size), targets.view(-1))
210
+ if l > 2:
211
+ mtp_logits = self.mtp_head(xn[:, :-1, :])
212
+ ml = F.cross_entropy(
213
+ mtp_logits.contiguous().view(-1, self.config.vocab_size),
214
+ targets[:, 1:].contiguous().view(-1),
215
+ )
216
+ loss = loss + 0.3 * ml
217
+
218
+ return MabaSparseOutput(
219
+ logits=logits,
220
+ loss=loss,
221
+ mtp_logits=mtp_logits,
222
+ past_states=nps,
223
+ )
224
+
225
+ @torch.no_grad()
226
+ def generate(
227
+ self,
228
+ input_ids: torch.Tensor,
229
+ max_new_tokens: int = 32,
230
+ temperature: float = 1.0,
231
+ top_k: Optional[int] = 50,
232
+ ) -> torch.Tensor:
233
+ self.eval()
234
+ gen = input_ids.clone()
235
+ for _ in range(max_new_tokens):
236
+ out = self(gen)
237
+ nl = out.logits[:, -1, :]
238
+ if temperature > 0:
239
+ nl = nl / temperature
240
+ if top_k is not None:
241
+ v, _ = torch.topk(nl, min(top_k, nl.size(-1)))
242
+ nl[nl < v[:, [-1]]] = float("-inf")
243
+ p = F.softmax(nl, dim=-1)
244
+ tok = torch.multinomial(p, num_samples=1)
245
+ else:
246
+ tok = torch.argmax(nl, dim=-1, keepdim=True)
247
+ gen = torch.cat([gen, tok], dim=1)
248
+ return gen
249
+
250
+
251
+ MabaSparseLM = MabaSparseForCausalLM
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c8292a7bced66cd0c85bb45b1881ffabd0db2449b4ca5a446e38d46b52154cfd
3
+ size 269676430