Commit ·
c54d56e
1
Parent(s): d319ab1
commit2
Browse files- README.md +88 -0
- assets/empirical_benchmark.svg +80 -0
- config.json +41 -0
- maba_sparse/__init__.py +18 -0
- maba_sparse/__pycache__/__init__.cpython-312.pyc +0 -0
- maba_sparse/__pycache__/config.cpython-312.pyc +0 -0
- maba_sparse/__pycache__/model.cpython-312.pyc +0 -0
- maba_sparse/baselines/__init__.py +13 -0
- maba_sparse/baselines/__pycache__/__init__.cpython-312.pyc +0 -0
- maba_sparse/baselines/__pycache__/dense_transformer.cpython-312.pyc +0 -0
- maba_sparse/baselines/dense_transformer.py +168 -0
- maba_sparse/config.py +77 -0
- maba_sparse/layers/__init__.py +13 -0
- maba_sparse/layers/__pycache__/__init__.cpython-312.pyc +0 -0
- maba_sparse/layers/__pycache__/dgda.cpython-312.pyc +0 -0
- maba_sparse/layers/__pycache__/indexer.cpython-312.pyc +0 -0
- maba_sparse/layers/__pycache__/sparse_attention.cpython-312.pyc +0 -0
- maba_sparse/layers/dgda.py +329 -0
- maba_sparse/layers/indexer.py +76 -0
- maba_sparse/layers/sparse_attention.py +159 -0
- maba_sparse/model.py +251 -0
- model.safetensors +3 -0
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
|