eyad-silx commited on
Commit
4ef119f
·
verified ·
1 Parent(s): 08258cc

Add fixed FLA folder for Quasar generation

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +2 -3
  2. fla/__init__.py +8 -0
  3. fla/__pycache__/__init__.cpython-312.pyc +0 -0
  4. fla/__pycache__/utils.cpython-312.pyc +0 -0
  5. fla/distributed_compat.py +57 -0
  6. fla/layers/__init__.py +3 -0
  7. fla/layers/__pycache__/__init__.cpython-312.pyc +0 -0
  8. fla/layers/__pycache__/attn.cpython-312.pyc +0 -0
  9. fla/layers/__pycache__/quasar.cpython-312.pyc +0 -0
  10. fla/layers/__pycache__/utils.cpython-312.pyc +0 -0
  11. fla/layers/abc.py +231 -0
  12. fla/layers/attn.py +176 -0
  13. fla/layers/based.py +93 -0
  14. fla/layers/bitattn.py +162 -0
  15. fla/layers/comba.py +328 -0
  16. fla/layers/delta_net.py +287 -0
  17. fla/layers/deltaformer.py +152 -0
  18. fla/layers/forgetting_attn.py +133 -0
  19. fla/layers/gated_deltanet.py +316 -0
  20. fla/layers/gated_deltaproduct.py +287 -0
  21. fla/layers/gla.py +304 -0
  22. fla/layers/gsa.py +237 -0
  23. fla/layers/hgrn.py +174 -0
  24. fla/layers/hgrn2.py +210 -0
  25. fla/layers/kda.py +277 -0
  26. fla/layers/lightnet.py +238 -0
  27. fla/layers/linear_attn.py +196 -0
  28. fla/layers/log_linear_mamba2.py +684 -0
  29. fla/layers/mamba.py +395 -0
  30. fla/layers/mamba2.py +649 -0
  31. fla/layers/mesa_net.py +221 -0
  32. fla/layers/mla.py +225 -0
  33. fla/layers/mom.py +831 -0
  34. fla/layers/multiscale_retention.py +303 -0
  35. fla/layers/nsa.py +137 -0
  36. fla/layers/path_attn.py +216 -0
  37. fla/layers/quasar.py +439 -0
  38. fla/layers/rebased.py +144 -0
  39. fla/layers/rodimus.py +397 -0
  40. fla/layers/rwkv6.py +360 -0
  41. fla/layers/rwkv7.py +347 -0
  42. fla/layers/simple_gla.py +273 -0
  43. fla/layers/utils.py +218 -0
  44. fla/models/__init__.py +3 -0
  45. fla/models/__pycache__/__init__.cpython-312.pyc +0 -0
  46. fla/models/__pycache__/utils.cpython-312.pyc +0 -0
  47. fla/models/abc/__init__.py +12 -0
  48. fla/models/abc/configuration_abc.py +105 -0
  49. fla/models/abc/modeling_abc.py +371 -0
  50. fla/models/bitnet/__init__.py +12 -0
README.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  Repo-local Raven dependency and Quasar-Preview runner used with `silx-ai/Quasar-Preview` revision `48d9dc1d2dcdb2eeb087c7b79c89300d3e46a70b`.
4
 
5
- This packages the Raven implementation from `goombalab/raven` under `raven/` plus a simple script that wires it for Quasar greedy generation.
6
 
7
  ## Run
8
 
@@ -20,8 +20,7 @@ The runner handles:
20
  - restoring `experts_w3` tensors that Transformers may leave as meta tensors
21
  - running direct `model.generate()`
22
 
23
- The Raven/FLA generation-cache fix lives in `silx-ai/Quasar-Preview` under
24
- `fla/ops/gsa/fused_recurrent.py`.
25
 
26
  ## Simpler script
27
 
 
2
 
3
  Repo-local Raven dependency and Quasar-Preview runner used with `silx-ai/Quasar-Preview` revision `48d9dc1d2dcdb2eeb087c7b79c89300d3e46a70b`.
4
 
5
+ This packages the Raven implementation from `goombalab/raven` under `raven/`, the fixed Quasar FLA folder under `fla/`, plus a simple script that wires them for Quasar greedy generation.
6
 
7
  ## Run
8
 
 
20
  - restoring `experts_w3` tensors that Transformers may leave as meta tensors
21
  - running direct `model.generate()`
22
 
23
+ The Raven/FLA generation-cache fix is included here under `fla/ops/gsa/fused_recurrent.py` and has also been pushed to `silx-ai/Quasar-Preview`.
 
24
 
25
  ## Simpler script
26
 
fla/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Lightweight package initializer for the vendored FLA subset used by Quasar.
2
+ #
3
+ # The upstream file eagerly imports every layer and model, which is slow and can
4
+ # hang on fresh training containers while optional kernels are being resolved.
5
+ # Import concrete modules directly, e.g. `from fla.layers.quasar import ...`.
6
+
7
+ __version__ = "0.1.0"
8
+ __all__ = []
fla/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (203 Bytes). View file
 
fla/__pycache__/utils.cpython-312.pyc ADDED
Binary file (26.6 kB). View file
 
fla/distributed_compat.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+ """
3
+ Centralized compatibility module for torch.distributed imports.
4
+ All distributed-related imports should go through here to handle environments
5
+ where distributed tensor APIs are not available.
6
+ """
7
+
8
+ import torch
9
+
10
+ # DeviceMesh
11
+ try:
12
+ from torch.distributed import DeviceMesh
13
+ except ImportError:
14
+ try:
15
+ from torch.distributed.device_mesh import DeviceMesh
16
+ except ImportError:
17
+ DeviceMesh = None
18
+
19
+ # DTensor
20
+ try:
21
+ from torch.distributed.tensor import DTensor
22
+ except (ImportError, AttributeError):
23
+ DTensor = None
24
+
25
+ # Replicate, Shard, distribute_module, Placement
26
+ try:
27
+ from torch.distributed.tensor import Placement, Replicate, Shard, distribute_module
28
+ except (ImportError, AttributeError):
29
+ Placement = Replicate = Shard = distribute_module = None
30
+
31
+ # ParallelStyle
32
+ try:
33
+ from torch.distributed.tensor.parallel import ParallelStyle
34
+ except (ImportError, AttributeError):
35
+ ParallelStyle = None
36
+
37
+ # Convenience flag
38
+ HAS_DISTRIBUTED = all([
39
+ DeviceMesh is not None,
40
+ DTensor is not None,
41
+ Placement is not None,
42
+ Replicate is not None,
43
+ Shard is not None,
44
+ distribute_module is not None,
45
+ ParallelStyle is not None,
46
+ ])
47
+
48
+ __all__ = [
49
+ 'DeviceMesh',
50
+ 'DTensor',
51
+ 'Placement',
52
+ 'Replicate',
53
+ 'Shard',
54
+ 'distribute_module',
55
+ 'ParallelStyle',
56
+ 'HAS_DISTRIBUTED',
57
+ ]
fla/layers/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Keep layer package imports lazy. Import specific layer modules directly.
2
+
3
+ __all__ = []
fla/layers/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (181 Bytes). View file
 
fla/layers/__pycache__/attn.cpython-312.pyc ADDED
Binary file (7.97 kB). View file
 
fla/layers/__pycache__/quasar.cpython-312.pyc ADDED
Binary file (20.1 kB). View file
 
fla/layers/__pycache__/utils.cpython-312.pyc ADDED
Binary file (10.2 kB). View file
 
fla/layers/abc.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+
12
+ from fla.layers.utils import get_layer_cache, update_layer_cache
13
+ from fla.modules import FusedRMSNormGated, RMSNorm, RotaryEmbedding, ShortConvolution
14
+ from fla.modules.activations import swiglu, swish
15
+ from fla.ops.abc.chunk import chunk_abc
16
+
17
+ if TYPE_CHECKING:
18
+ from fla.models.utils import Cache
19
+
20
+
21
+ class ABCAttention(nn.Module):
22
+
23
+ def __init__(
24
+ self,
25
+ hidden_size: int = 1024,
26
+ expand_k: float = 0.5,
27
+ expand_v: float = 1.0,
28
+ num_heads: int = 4,
29
+ use_short_conv: bool = False,
30
+ conv_size: int = 4,
31
+ conv_bias: bool = False,
32
+ num_slots: int | None = None,
33
+ elementwise_affine: bool | None = True,
34
+ norm_eps: float = 1e-5,
35
+ gate_low_rank_dim: int = 16,
36
+ gate_logit_normalizer: int = 16,
37
+ use_rope: bool = True,
38
+ use_input_gate: bool = False,
39
+ use_output_gate: bool = True,
40
+ use_norm: bool = True,
41
+ clamp_min: float | None = -32,
42
+ clamp_max: float | None = 32,
43
+ layer_idx: int | None = None,
44
+ **kwargs,
45
+ ) -> ABCAttention:
46
+ super().__init__()
47
+
48
+ self.hidden_size = hidden_size
49
+ self.expand_k = expand_k
50
+ self.expand_v = expand_v
51
+ self.num_heads = num_heads
52
+ self.key_dim = int(self.hidden_size * self.expand_k)
53
+ self.value_dim = int(self.hidden_size * self.expand_v)
54
+ self.head_k_dim = self.key_dim // self.num_heads
55
+ self.head_v_dim = self.value_dim // self.num_heads
56
+
57
+ self.use_short_conv = use_short_conv
58
+ self.conv_size = conv_size
59
+ self.conv_bias = conv_bias
60
+
61
+ self.gate_low_rank_dim = gate_low_rank_dim
62
+ self.gate_logit_normalizer = gate_logit_normalizer
63
+
64
+ self.use_rope = use_rope
65
+ self.use_input_gate = use_input_gate
66
+ self.use_output_gate = use_output_gate
67
+ self.use_norm = use_norm
68
+
69
+ if num_slots is None:
70
+ num_slots = self.head_k_dim
71
+ self.num_slots = num_slots
72
+
73
+ self.norm_eps = norm_eps
74
+
75
+ self.clamp_min = clamp_min
76
+ self.clamp_max = clamp_max
77
+ self.layer_idx = layer_idx
78
+
79
+ if layer_idx is None:
80
+ warnings.warn(
81
+ f"Instantiating {self.__class__.__name__} without passing `layer_idx` is not recommended and will "
82
+ "to errors during the forward call, if caching is used. Please make sure to provide a `layer_idx` "
83
+ "when creating this class.",
84
+ )
85
+
86
+ self.q_proj = nn.Linear(self.hidden_size, self.key_dim, bias=False)
87
+ self.k_proj = nn.Linear(self.hidden_size, self.key_dim, bias=False)
88
+ self.v_proj = nn.Linear(self.hidden_size, self.value_dim, bias=False)
89
+
90
+ if use_output_gate:
91
+ self.g_proj = nn.Linear(self.hidden_size, self.value_dim, bias=False)
92
+ self.s_proj = nn.Linear(self.hidden_size, self.num_heads * self.num_slots, bias=False)
93
+ self.o_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False)
94
+
95
+ if use_short_conv:
96
+ self.conv_size = conv_size
97
+ self.q_conv1d = ShortConvolution(
98
+ hidden_size=self.key_dim,
99
+ kernel_size=conv_size,
100
+ bias=conv_bias,
101
+ activation='silu',
102
+ )
103
+ self.k_conv1d = ShortConvolution(
104
+ hidden_size=self.key_dim,
105
+ kernel_size=conv_size,
106
+ bias=conv_bias,
107
+ activation='silu',
108
+ )
109
+ self.v_conv1d = ShortConvolution(
110
+ hidden_size=self.value_dim,
111
+ kernel_size=conv_size,
112
+ bias=conv_bias,
113
+ activation='silu',
114
+ )
115
+
116
+ if self.use_norm:
117
+ if self.use_output_gate:
118
+ self.g_norm = FusedRMSNormGated(
119
+ hidden_size=self.head_v_dim,
120
+ elementwise_affine=elementwise_affine,
121
+ eps=norm_eps,
122
+ )
123
+ else:
124
+ self.g_norm = RMSNorm(
125
+ hidden_size=self.head_v_dim,
126
+ elementwise_affine=elementwise_affine,
127
+ eps=norm_eps,
128
+ dtype=torch.float32,
129
+ )
130
+
131
+ if self.use_rope:
132
+ self.rotary = RotaryEmbedding(self.head_k_dim)
133
+
134
+ def forward(
135
+ self,
136
+ hidden_states: torch.Tensor,
137
+ attention_mask: torch.Tensor | None = None,
138
+ past_key_values: Cache | None = None,
139
+ use_cache: bool | None = False,
140
+ output_attentions: bool | None = False,
141
+ **kwargs,
142
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
143
+ if attention_mask is not None:
144
+ assert len(attention_mask.shape) == 2, (
145
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
146
+ "for padding purposes (0 indicating padding). "
147
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
148
+ )
149
+
150
+ last_state = get_layer_cache(self, past_key_values)
151
+
152
+ cu_seqlens = kwargs.get('cu_seqlens')
153
+ if cu_seqlens is not None:
154
+ raise NotImplementedError("Training with cu_seqlens is not supported yet for ABCAttention")
155
+ if self.use_short_conv:
156
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
157
+ if last_state is not None:
158
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
159
+ conv_mask = attention_mask[:, -hidden_states.shape[1]:] if attention_mask is not None else None
160
+ q, conv_state_q = self.q_conv1d(
161
+ x=self.q_proj(hidden_states),
162
+ mask=conv_mask,
163
+ cache=conv_state_q,
164
+ output_final_state=use_cache,
165
+ cu_seqlens=cu_seqlens,
166
+ )
167
+ k, conv_state_k = self.k_conv1d(
168
+ x=self.k_proj(hidden_states),
169
+ mask=conv_mask,
170
+ cache=conv_state_k,
171
+ output_final_state=use_cache,
172
+ cu_seqlens=cu_seqlens,
173
+ )
174
+ v, conv_state_v = self.v_conv1d(
175
+ x=self.v_proj(hidden_states),
176
+ mask=conv_mask,
177
+ cache=conv_state_v,
178
+ output_final_state=use_cache,
179
+ cu_seqlens=cu_seqlens,
180
+ )
181
+ else:
182
+ q = self.q_proj(hidden_states)
183
+ k = self.k_proj(hidden_states)
184
+ v = self.v_proj(hidden_states)
185
+
186
+ if self.use_input_gate:
187
+ q, k, v = map(lambda x: swish(x), (q, k, v))
188
+ # dealing with left-padding
189
+ if attention_mask is not None:
190
+ v = v.mul_(attention_mask[:, -v.shape[-2]:, None])
191
+
192
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
193
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
194
+ if self.use_rope:
195
+ seqlen_offset = 0
196
+ if past_key_values is not None:
197
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
198
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset)
199
+
200
+ s = rearrange(self.s_proj(hidden_states), '... (h m) -> ... h m', m=self.num_slots)
201
+ s = s.clamp_(self.clamp_min, self.clamp_max)
202
+
203
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
204
+ o, recurrent_state = chunk_abc(
205
+ q=q,
206
+ k=k,
207
+ v=v,
208
+ s=s,
209
+ initial_state=recurrent_state,
210
+ output_final_state=use_cache,
211
+ )
212
+ update_layer_cache(
213
+ self,
214
+ past_key_values,
215
+ recurrent_state=recurrent_state,
216
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
217
+ offset=q.shape[1],
218
+ )
219
+
220
+ if self.use_norm and not self.use_output_gate:
221
+ o = self.g_norm(o)
222
+ elif self.use_output_gate:
223
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
224
+ o = self.g_norm(o, g) if self.use_norm else swiglu(g, o)
225
+ o = rearrange(o, '... h d -> ... (h d)')
226
+ o = self.o_proj(o)
227
+
228
+ return o, None, past_key_values
229
+
230
+ def state_size(self, seq_len: int = 2048):
231
+ return 2 * self.num_slots * self.hidden_size
fla/layers/attn.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+ from transformers.utils import logging
12
+
13
+ from fla.layers.utils import pad_input, unpad_input
14
+ from fla.modules import RMSNorm, RotaryEmbedding
15
+ from fla.ops.utils.index import prepare_lens_from_mask
16
+
17
+ if TYPE_CHECKING:
18
+ from fla.models.utils import Cache
19
+
20
+ try:
21
+ from flash_attn import flash_attn_func, flash_attn_varlen_func
22
+ except ImportError:
23
+ warnings.warn(
24
+ "Flash Attention is not installed. Please install it via `pip install flash-attn --no-build-isolation`",
25
+ category=ImportWarning,
26
+ )
27
+ flash_attn_func = None
28
+
29
+ logger = logging.get_logger(__name__)
30
+
31
+
32
+ class Attention(nn.Module):
33
+
34
+ def __init__(
35
+ self,
36
+ hidden_size: int = 2048,
37
+ num_heads: int = 32,
38
+ num_kv_heads: int | None = None,
39
+ qkv_bias: bool = False,
40
+ qk_norm: bool = False,
41
+ window_size: int | None = None,
42
+ rope_theta: float | None = 10000.,
43
+ max_position_embeddings: int | None = None,
44
+ use_nope: bool = False,
45
+ layer_idx: int = None,
46
+ ):
47
+ super().__init__()
48
+
49
+ self.hidden_size = hidden_size
50
+ self.num_heads = num_heads
51
+ if num_kv_heads is None:
52
+ self.num_kv_heads = self.num_heads
53
+ else:
54
+ self.num_kv_heads = num_kv_heads
55
+ self.num_kv_groups = num_heads // self.num_kv_heads
56
+ self.head_dim = self.hidden_size // self.num_heads
57
+ self.kv_dim = self.num_kv_heads * self.head_dim
58
+ self.qkv_bias = qkv_bias
59
+ self.qk_norm = qk_norm
60
+
61
+ self.window_size = window_size
62
+ self.rope_theta = rope_theta
63
+ self.max_position_embeddings = max_position_embeddings
64
+ self.use_nope = use_nope
65
+ self.layer_idx = layer_idx
66
+
67
+ if flash_attn_func is None:
68
+ raise ImportError("Please install Flash Attention via `pip install flash-attn --no-build-isolation` first")
69
+
70
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias)
71
+ self.k_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
72
+ self.v_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
73
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
74
+
75
+ if qk_norm:
76
+ self.q_norm = RMSNorm(self.head_dim, dtype=torch.float32)
77
+ self.k_norm = RMSNorm(self.head_dim, dtype=torch.float32)
78
+
79
+ self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta)
80
+
81
+ def forward(
82
+ self,
83
+ hidden_states: torch.Tensor,
84
+ attention_mask: torch.LongTensor | None = None,
85
+ past_key_values: Cache | None = None,
86
+ output_attentions: bool = False,
87
+ use_cache: bool = False,
88
+ **kwargs,
89
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
90
+ if attention_mask is not None:
91
+ assert len(attention_mask.shape) == 2, (
92
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
93
+ "for padding purposes (0 indicating padding). "
94
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
95
+ )
96
+
97
+ batch_size, q_len, _ = hidden_states.size()
98
+
99
+ q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
100
+ k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
101
+ v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
102
+
103
+ if self.qk_norm:
104
+ q, k = self.q_norm(q), self.k_norm(k)
105
+
106
+ # equivalent to cu_seqlens in `flash_attn`
107
+ cu_seqlens = kwargs.get('cu_seqlens')
108
+
109
+ seqlen_offset, max_seqlen = 0, q_len
110
+ if past_key_values is not None:
111
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
112
+ max_seqlen = q.shape[1] + seqlen_offset
113
+
114
+ if attention_mask is not None:
115
+ # to deliminate the offsets of padding tokens
116
+ seqlen_offset = seqlen_offset + prepare_lens_from_mask(attention_mask) - attention_mask.shape[-1]
117
+ max_seqlen = q.shape[1] + max(seqlen_offset)
118
+
119
+ if self.max_position_embeddings is not None:
120
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
121
+ if not self.use_nope:
122
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens)
123
+
124
+ if past_key_values is not None:
125
+ cache_has_content = past_key_values.get_seq_length(self.layer_idx) > 0
126
+ k_cached, v_cached = past_key_values.update(
127
+ attn_state=(k.flatten(-2, -1), v.flatten(-2, -1)),
128
+ layer_idx=self.layer_idx,
129
+ offset=q_len,
130
+ cache_kwargs=dict(window_size=self.window_size),
131
+ )['attn_state']
132
+ if cache_has_content:
133
+ k, v = k_cached, v_cached
134
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
135
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
136
+
137
+ # Contains at least one padding token in the sequence
138
+ if attention_mask is not None:
139
+ if q.shape[1] == 1 and self.window_size is not None:
140
+ attention_mask = attention_mask[:, -self.window_size:]
141
+ q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input(q, (k, v), attention_mask, q_len)
142
+ cu_seqlens_q, cu_seqlens_k = cu_seqlens
143
+ max_seqlen_q, max_seqlen_k = max_seq_lens
144
+ o = flash_attn_varlen_func(
145
+ q, k, v,
146
+ cu_seqlens_q=cu_seqlens_q,
147
+ cu_seqlens_k=cu_seqlens_k,
148
+ max_seqlen_q=max_seqlen_q,
149
+ max_seqlen_k=max_seqlen_k,
150
+ causal=True,
151
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
152
+ )
153
+ o = pad_input(o, indices_q, batch_size, q_len)
154
+ elif cu_seqlens is not None:
155
+ o = flash_attn_varlen_func(
156
+ q.squeeze(0), k.squeeze(0), v.squeeze(0),
157
+ cu_seqlens_q=cu_seqlens,
158
+ cu_seqlens_k=cu_seqlens,
159
+ max_seqlen_q=max_seqlen,
160
+ max_seqlen_k=max_seqlen,
161
+ causal=True,
162
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
163
+ ).unsqueeze(0)
164
+ else:
165
+ o = flash_attn_func(
166
+ q, k, v,
167
+ causal=True,
168
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
169
+ )
170
+ o = o.reshape(batch_size, q_len, -1)
171
+ o = self.o_proj(o)
172
+
173
+ if not output_attentions:
174
+ attentions = None
175
+
176
+ return o, attentions, past_key_values
fla/layers/based.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ """
4
+ Linear attention in Based.
5
+ https://github.com/HazyResearch/zoology/blob/main/zoology/mixers/based.py
6
+ """
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+
12
+ from fla.modules.feature_map import TaylorFeatureMap
13
+ from fla.ops.based import parallel_based
14
+ from fla.ops.linear_attn import chunk_linear_attn, fused_chunk_linear_attn
15
+
16
+
17
+ class BasedLinearAttention(nn.Module):
18
+
19
+ def __init__(
20
+ self,
21
+ hidden_size: int,
22
+ feature_dim: int = 16,
23
+ num_key_value_heads: int = 12,
24
+ num_heads: int = 12,
25
+ feature_name: str = "taylor_exp",
26
+ eps: float = 1e-12,
27
+ causal: bool = True,
28
+ mode: str = "parallel",
29
+ ):
30
+ super().__init__()
31
+
32
+ self.hidden_size = hidden_size
33
+ self.mode = mode
34
+ self.feature_name = feature_name
35
+ self.feature_dim = feature_dim
36
+ self.num_key_value_heads = num_key_value_heads
37
+ self.num_heads = num_heads
38
+ self.head_dim = self.hidden_size // self.num_key_value_heads
39
+ assert self.hidden_size % self.head_dim == 0
40
+ self.causal = causal
41
+
42
+ self.q_proj = nn.Linear(self.hidden_size, self.feature_dim * self.num_heads, bias=False)
43
+ self.k_proj = nn.Linear(self.hidden_size, self.feature_dim * self.num_heads, bias=False)
44
+ self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=False)
45
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
46
+ self.dropout = nn.Identity()
47
+ self.feature_map = TaylorFeatureMap(feature_dim)
48
+ self.eps = eps
49
+
50
+ def forward(self, hidden_states: torch.Tensor, **kwargs):
51
+ mode = self.mode
52
+ q, k, v = self.q_proj(hidden_states), self.k_proj(hidden_states), self.v_proj(hidden_states)
53
+ q, k, v = map(lambda x: rearrange(x, "... (h d) -> ... h d", d=self.head_dim), [q, k, v])
54
+ if mode == "fused_chunk":
55
+ q, k = self.feature_map(q), self.feature_map(k)
56
+ o, _ = fused_chunk_linear_attn(q, k, v, normalize=True, scale=1)
57
+ elif mode == 'chunk':
58
+ q, k = self.feature_map(q), self.feature_map(k)
59
+ o, _ = chunk_linear_attn(q, k, v, normalize=True, scale=1)
60
+ elif mode == 'parallel':
61
+ assert q.shape[-1] <= 128
62
+ o = parallel_based(q, k, v, scale=1, use_norm=True)
63
+ o = rearrange(o, 'b t h d -> b t (h d)')
64
+ o = self.o_proj(o)
65
+ o = self.dropout(o)
66
+ return o
67
+
68
+ def forward_reference(self, hidden_states: torch.Tensor, **kwargs):
69
+ """
70
+ x (torch.Tensor): tensor of shape (b, d, t)
71
+ y (torch.Tensor): tensor of shape (b, d, t)
72
+ """
73
+ # hidden_states = hidden_states.transpose(1, 2)
74
+ b, t, _ = hidden_states.size()
75
+ q, k, v = self.q_proj(hidden_states), self.k_proj(hidden_states), self.v_proj(hidden_states)
76
+
77
+ q = q.view(b, t, self.num_heads, self.feature_dim).transpose(1, 2)
78
+ k = k.view(b, t, self.num_key_value_heads, self.feature_dim).transpose(1, 2)
79
+ v = v.view(b, t, self.num_key_value_heads, self.head_dim).transpose(1, 2)
80
+
81
+ # Linear attention
82
+ q, k = self.feature_map(q), self.feature_map(k)
83
+ q, k, v = q.unsqueeze(-2), k.unsqueeze(-2), v.unsqueeze(-1)
84
+
85
+ # Compute attention
86
+ if self.causal:
87
+ y = ((q * (k * v).cumsum(2)).sum(-1) / ((q * k.cumsum(2)).sum(-1) + self.eps))
88
+ else:
89
+ y = ((q * (k * v).sum(2, True)).sum(-1) / ((q * k.sum(2, True)).sum(-1) + self.eps))
90
+ y = rearrange(y, 'b h t d -> b t (h d)')
91
+ y = self.o_proj(y.to(hidden_states.dtype))
92
+ y = self.dropout(y)
93
+ return y.to(hidden_states.dtype)
fla/layers/bitattn.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+ from transformers.utils import logging
12
+
13
+ from fla.layers.utils import pad_input, unpad_input
14
+ from fla.modules import RotaryEmbedding
15
+ from fla.modules.fused_bitlinear import FusedBitLinear
16
+ from fla.ops.utils.index import prepare_lens_from_mask
17
+
18
+ if TYPE_CHECKING:
19
+ from fla.models.utils import Cache
20
+
21
+ try:
22
+ from flash_attn import flash_attn_func, flash_attn_varlen_func
23
+ except ImportError:
24
+ warnings.warn(
25
+ "Flash Attention is not installed. Please install it via `pip install flash-attn --no-build-isolation`",
26
+ category=ImportWarning,
27
+ )
28
+ flash_attn_func = None
29
+
30
+ logger = logging.get_logger(__name__)
31
+
32
+
33
+ class BitAttention(nn.Module):
34
+
35
+ def __init__(
36
+ self,
37
+ hidden_size: int = 2048,
38
+ num_heads: int = 32,
39
+ num_kv_heads: int | None = None,
40
+ window_size: int | None = None,
41
+ rope_theta: float | None = 10000.,
42
+ max_position_embeddings: int | None = None,
43
+ norm_eps: float = 1e-5,
44
+ layer_idx: int = None,
45
+ ):
46
+ super().__init__()
47
+
48
+ self.num_heads = num_heads
49
+ if num_kv_heads is None:
50
+ self.num_kv_heads = self.num_heads
51
+ else:
52
+ self.num_kv_heads = num_kv_heads
53
+ self.num_kv_groups = num_heads // self.num_kv_heads
54
+ self.hidden_size = hidden_size
55
+ self.head_dim = self.hidden_size // self.num_heads
56
+ self.kv_dim = self.num_kv_heads * self.head_dim
57
+ self.kv_dim = self.num_kv_heads * self.head_dim
58
+ self.window_size = window_size
59
+ self.rope_theta = rope_theta
60
+ self.max_position_embeddings = max_position_embeddings
61
+ self.layer_idx = layer_idx
62
+
63
+ self.q_proj = FusedBitLinear(self.hidden_size, self.hidden_size, bias=False)
64
+ self.k_proj = FusedBitLinear(self.hidden_size, self.kv_dim, bias=False)
65
+ self.v_proj = FusedBitLinear(self.hidden_size, self.kv_dim, bias=False)
66
+ self.o_proj = FusedBitLinear(self.hidden_size, self.hidden_size, bias=False)
67
+
68
+ self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta)
69
+
70
+ def forward(
71
+ self,
72
+ hidden_states: torch.Tensor,
73
+ attention_mask: torch.LongTensor | None = None,
74
+ past_key_values: Cache | None = None,
75
+ output_attentions: bool = False,
76
+ use_cache: bool = False,
77
+ **kwargs,
78
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
79
+ if attention_mask is not None:
80
+ assert len(attention_mask.shape) == 2, (
81
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
82
+ "for padding purposes (0 indicating padding). "
83
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
84
+ )
85
+
86
+ batch_size, q_len, _ = hidden_states.size()
87
+
88
+ q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
89
+ k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
90
+ v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
91
+
92
+ # equivalent to cu_seqlens in `flash_attn`
93
+ cu_seqlens = kwargs.get('cu_seqlens')
94
+
95
+ seqlen_offset, max_seqlen = 0, q_len
96
+ if past_key_values is not None:
97
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
98
+ max_seqlen = q.shape[1] + seqlen_offset
99
+
100
+ if attention_mask is not None:
101
+ # to deliminate the offsets of padding tokens
102
+ seqlen_offset = seqlen_offset + prepare_lens_from_mask(attention_mask) - attention_mask.shape[-1]
103
+ max_seqlen = q.shape[1] + max(seqlen_offset)
104
+
105
+ if self.max_position_embeddings is not None:
106
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
107
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens)
108
+
109
+ if past_key_values is not None:
110
+ cache_has_content = past_key_values.get_seq_length(self.layer_idx) > 0
111
+ k_cached, v_cached = past_key_values.update(
112
+ attn_state=(k.flatten(-2, -1), v.flatten(-2, -1)),
113
+ layer_idx=self.layer_idx,
114
+ offset=q_len,
115
+ cache_kwargs=dict(window_size=self.window_size),
116
+ )['attn_state']
117
+ if cache_has_content:
118
+ k, v = k_cached, v_cached
119
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
120
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
121
+
122
+ if flash_attn_func is None:
123
+ raise ImportError("Please install Flash Attention via `pip install flash-attn --no-build-isolation` first")
124
+
125
+ # Contains at least one padding token in the sequence
126
+ if attention_mask is not None:
127
+ q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input(q, (k, v), attention_mask, q_len)
128
+ cu_seqlens_q, cu_seqlens_k = cu_seqlens
129
+ max_seqlen_q, max_seqlen_k = max_seq_lens
130
+ o = flash_attn_varlen_func(
131
+ q, k, v,
132
+ cu_seqlens_q=cu_seqlens_q,
133
+ cu_seqlens_k=cu_seqlens_k,
134
+ max_seqlen_q=max_seqlen_q,
135
+ max_seqlen_k=max_seqlen_k,
136
+ causal=True,
137
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
138
+ )
139
+ o = pad_input(o, indices_q, batch_size, q_len)
140
+ elif cu_seqlens is not None:
141
+ o = flash_attn_varlen_func(
142
+ q.squeeze(0), k.squeeze(0), v.squeeze(0),
143
+ cu_seqlens_q=cu_seqlens,
144
+ cu_seqlens_k=cu_seqlens,
145
+ max_seqlen_q=max_seqlen,
146
+ max_seqlen_k=max_seqlen,
147
+ causal=True,
148
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
149
+ ).unsqueeze(0)
150
+ else:
151
+ o = flash_attn_func(
152
+ q, k, v,
153
+ causal=True,
154
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
155
+ )
156
+ o = o.reshape(batch_size, q_len, -1)
157
+ o = self.o_proj(o)
158
+
159
+ if not output_attentions:
160
+ attentions = None
161
+
162
+ return o, attentions, past_key_values
fla/layers/comba.py ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import warnings
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from einops import rearrange, repeat
12
+ from torch.nn import functional as F
13
+
14
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
15
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
16
+ from fla.ops.comba import chunk_comba, fused_recurrent_comba
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ class Comba(nn.Module):
25
+ """
26
+ The layer implementaion for [Comba: Improving Bilinear RNNs with Closed-loop Control](https://arxiv.org/abs/2506.02475).
27
+
28
+ Similar to Mamba2 and Gated-DeltaNet, each layer contains around 6*hidden_size*hidden_size parameters.
29
+
30
+ Parameter alloation when use_output_gate=True:
31
+ - 0.75 * hidden_size * hidden_size for the q_proj and k_proj each
32
+ - 1.5 * hidden_size * hidden_size for the v_proj, g_proj and o_proj each
33
+ - Others are ignorably small.
34
+ - In total = 0.75 * 2 + 1.5 * 3 = 6 * hidden_size * hidden_size
35
+ NOTE: num_heads * head_dim = 0.75 * hidden_size, please make sure to set the correct num_heads and head_dim.
36
+
37
+ Parameter allocation when use_output_gate=False:
38
+ - 1 * hidden_size * hidden_size for the q_proj and k_proj each
39
+ - 2 * hidden_size * hidden_size for the v_proj and o_proj each
40
+ - Others are ignorably small.
41
+ - In total = 1 * 2 + 2 * 2 = 6 * hidden_size * hidden_size
42
+
43
+ Args:
44
+ hidden_size (int, Optional):
45
+ The hidden size of the input. Default: 2048.
46
+ expand_v (float, Optional):
47
+ The expansion ratio for the value dim. Default: 2.0.
48
+ head_dim (int, Optional):
49
+ The dimension of each head. Default: 256.
50
+ num_heads (int, Optional):
51
+ The number of heads. Default: 4.
52
+ num_v_heads (int, Optional):
53
+ The number of heads for the value projection, equal to `num_heads` if `None`.
54
+ GVA is applied if `num_v_heads` > `num_heads`. Default: `None`.
55
+ mode (str, Optional):
56
+ Which Gated DeltaNet kernel to use.
57
+ Currently available: `chunk` and `fused_recurrent`.
58
+ Default: `chunk`.
59
+ use_beta (bool, Optional):
60
+ Whether to use beta. Default: `True`.
61
+ use_output_gate (bool, Optional):
62
+ Whether to use output gate. Default: `True`.
63
+ use_output_correction (bool, Optional):
64
+ Whether to use <q-dk>. Default: `True`.
65
+ use_short_conv (bool, Optional):
66
+ Whether to use short convolutions. Default: `True`.
67
+ conv_size (int, Optional):
68
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
69
+ conv_bias (bool, Optional):
70
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
71
+ layer_idx (int, Optional):
72
+ The index of the layer. Default: None.
73
+ norm_eps (float, Optional):
74
+ The epsilon value for the normalization layer. Default: 1e-5.
75
+ """
76
+
77
+ def __init__(
78
+ self,
79
+ hidden_size: int = 2048,
80
+ expand_v: float = 2,
81
+ head_dim: int = 256,
82
+ num_heads: int = 6,
83
+ num_v_heads: int = None,
84
+ mode: str = 'chunk',
85
+ use_short_conv: bool = True,
86
+ use_output_gate: bool = True,
87
+ use_output_correction: bool = True,
88
+ use_inner_decay: bool = True,
89
+ correction_factor: float = 1.,
90
+ conv_size: int = 4,
91
+ conv_bias: bool = False,
92
+ layer_idx: int = None,
93
+ norm_eps: float = 1e-5,
94
+ **kwargs,
95
+ ) -> Comba:
96
+ super().__init__()
97
+
98
+ self.mode = mode
99
+
100
+ self.hidden_size = hidden_size
101
+ self.expand_v = expand_v
102
+
103
+ self.use_short_conv = use_short_conv
104
+ self.use_output_gate = use_output_gate
105
+ self.use_output_correction = use_output_correction
106
+ self.use_inner_decay = use_inner_decay
107
+ self.conv_size = conv_size
108
+ self.conv_bias = conv_bias
109
+
110
+ self.head_dim = head_dim
111
+ self.num_heads = num_heads
112
+ self.num_v_heads = num_v_heads if num_v_heads is not None else num_heads
113
+
114
+ self.head_k_dim = head_dim
115
+ self.head_v_dim = int(self.head_dim * self.expand_v)
116
+ self.key_dim = int(self.num_heads * self.head_k_dim)
117
+ self.value_dim = int(self.num_v_heads * self.head_v_dim)
118
+ self.layer_idx = layer_idx
119
+
120
+ # Consistency check: Ensure expand_v produces integer values
121
+ if not math.isclose(self.num_v_heads * self.head_dim * expand_v, self.value_dim, rel_tol=1e-5):
122
+ raise ValueError(
123
+ f"expand_v={expand_v} does not produce an integer value when multiplied by key_dim={self.key_dim}. "
124
+ f"Resulting value_dim would be {self.num_v_heads * self.head_dim * expand_v}, which is invalid for nn.Linear.",
125
+ )
126
+ if self.num_v_heads > self.num_heads and self.num_v_heads % self.num_heads != 0:
127
+ raise ValueError(
128
+ f"num_v_heads={self.num_v_heads} must be divisible by num_heads={self.num_heads}.",
129
+ )
130
+
131
+ if not math.isclose(head_dim * expand_v, self.head_v_dim, rel_tol=1e-5):
132
+ raise ValueError(
133
+ f"expand_v={expand_v} does not produce an integer value when multiplied by head_dim={head_dim}. "
134
+ f"Resulting head_v_dim would be {head_dim * expand_v}, which is invalid for FusedRMSNormGated.",
135
+ )
136
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
137
+
138
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
139
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
140
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
141
+ self.a_proj = nn.Linear(hidden_size, self.num_v_heads, bias=False)
142
+ self.b_proj = nn.Linear(hidden_size, self.num_v_heads, bias=False)
143
+
144
+ if use_inner_decay:
145
+ self.decay = nn.Parameter(torch.ones(self.num_heads))
146
+
147
+ if use_output_correction:
148
+ warnings.warn(
149
+ "The correction_factor is set to 1 by default similar to Mamba2. "
150
+ "However, we find that sometimes correction_factor = 0.02 works better for small-scale models. "
151
+ "In practice, we recommend trying both settings. ",
152
+ )
153
+ self.D = nn.Parameter(torch.ones(self.num_heads) * correction_factor)
154
+ self.D._no_weight_decay = True
155
+
156
+ A = torch.empty(self.num_v_heads, dtype=torch.float32).uniform_(0, 16)
157
+ self.A_log = nn.Parameter(torch.log(A))
158
+ self.A_log._no_weight_decay = True
159
+ # hard coded for now
160
+ dt_min = 0.001
161
+ dt_max = 0.1
162
+ dt_init_floor = 1e-4
163
+ dt = torch.exp(
164
+ torch.rand(self.num_v_heads) * (math.log(dt_max) - math.log(dt_min))
165
+ + math.log(dt_min),
166
+ )
167
+ dt = torch.clamp(dt, min=dt_init_floor)
168
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
169
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
170
+ self.dt_bias = nn.Parameter(inv_dt)
171
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
172
+ # name.endswith("bias") in param_grouping.py
173
+ self.dt_bias._no_weight_decay = True
174
+
175
+ if use_short_conv:
176
+ self.conv_size = conv_size
177
+ self.q_conv1d = ShortConvolution(
178
+ hidden_size=self.key_dim,
179
+ kernel_size=conv_size,
180
+ bias=conv_bias,
181
+ activation='silu',
182
+ )
183
+ self.k_conv1d = ShortConvolution(
184
+ hidden_size=self.key_dim,
185
+ kernel_size=conv_size,
186
+ bias=conv_bias,
187
+ activation='silu',
188
+ )
189
+ self.v_conv1d = ShortConvolution(
190
+ hidden_size=self.value_dim,
191
+ kernel_size=conv_size,
192
+ bias=conv_bias,
193
+ activation='silu',
194
+ )
195
+ else:
196
+ warnings.warn(
197
+ "ShortConvolution is crucial to the performance. "
198
+ "Do not turn it off, i.e., setting `use_short_conv=False` unless you know what you are doing.",
199
+ )
200
+ if use_output_gate:
201
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
202
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, activation='sigmoid', eps=norm_eps)
203
+ else:
204
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
205
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
206
+
207
+ def forward(
208
+ self,
209
+ hidden_states: torch.Tensor,
210
+ attention_mask: torch.Tensor | None = None,
211
+ past_key_values: Cache | None = None,
212
+ use_cache: bool | None = False,
213
+ output_attentions: bool | None = False,
214
+ **kwargs: Unpack[dict],
215
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
216
+ if attention_mask is not None:
217
+ assert len(attention_mask.shape) == 2, (
218
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
219
+ "for padding purposes (0 indicating padding). "
220
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
221
+ )
222
+
223
+ batch_size, q_len, _ = hidden_states.shape
224
+ # change to inference mode.
225
+ mode = 'fused_recurrent' if (q_len <= 64 and not self.training) else self.mode
226
+ if self.training:
227
+ assert mode == 'chunk', "Only chunk mode is supported in training."
228
+ last_state = get_layer_cache(self, past_key_values)
229
+
230
+ cu_seqlens = kwargs.get('cu_seqlens')
231
+ if attention_mask is not None:
232
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
233
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
234
+
235
+ if self.use_short_conv:
236
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
237
+ if last_state is not None:
238
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
239
+ q, conv_state_q = self.q_conv1d(
240
+ x=self.q_proj(hidden_states),
241
+ cache=conv_state_q,
242
+ output_final_state=use_cache,
243
+ cu_seqlens=cu_seqlens,
244
+ )
245
+ k, conv_state_k = self.k_conv1d(
246
+ x=self.k_proj(hidden_states),
247
+ cache=conv_state_k,
248
+ output_final_state=use_cache,
249
+ cu_seqlens=cu_seqlens,
250
+ )
251
+ v, conv_state_v = self.v_conv1d(
252
+ x=self.v_proj(hidden_states),
253
+ cache=conv_state_v,
254
+ output_final_state=use_cache,
255
+ cu_seqlens=cu_seqlens,
256
+ )
257
+ else:
258
+ q = F.silu(self.q_proj(hidden_states))
259
+ k = F.silu(self.k_proj(hidden_states))
260
+ v = F.silu(self.v_proj(hidden_states))
261
+
262
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
263
+
264
+ if self.use_inner_decay:
265
+ p = k * self.decay[None, None, :, None].sigmoid()
266
+ else:
267
+ p = k
268
+
269
+ if self.use_output_correction:
270
+ q = q - self.D[None, None, :, None] * p
271
+
272
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
273
+
274
+ if self.num_v_heads > self.num_heads:
275
+ q, k = map(lambda x: repeat(x, '... h d -> ... (h g) d', g=self.num_v_heads // self.num_heads), (q, k))
276
+
277
+ beta = self.b_proj(hidden_states).sigmoid()
278
+ g = -self.A_log.float().exp() * F.softplus(self.a_proj(hidden_states).float() + self.dt_bias)
279
+
280
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
281
+ if mode == 'chunk':
282
+ o, recurrent_state = chunk_comba(
283
+ q=q,
284
+ k=k,
285
+ v=v,
286
+ p=p,
287
+ g=g,
288
+ beta=beta,
289
+ initial_state=recurrent_state,
290
+ output_final_state=use_cache,
291
+ cu_seqlens=cu_seqlens,
292
+ use_qk_l2norm_in_kernel=True,
293
+ )
294
+ elif mode == 'fused_recurrent':
295
+ o, recurrent_state = fused_recurrent_comba(
296
+ q=q,
297
+ k=k,
298
+ v=v,
299
+ p=p,
300
+ g=g,
301
+ beta=beta,
302
+ initial_state=recurrent_state,
303
+ output_final_state=use_cache,
304
+ cu_seqlens=cu_seqlens,
305
+ use_qk_l2norm_in_kernel=True,
306
+ )
307
+ else:
308
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
309
+
310
+ update_layer_cache(
311
+ self,
312
+ past_key_values,
313
+ recurrent_state=recurrent_state,
314
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
315
+ offset=q_len,
316
+ )
317
+
318
+ if self.use_output_gate:
319
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
320
+ o = self.o_norm(o, g)
321
+ else:
322
+ o = self.o_norm(o)
323
+ o = rearrange(o, 'b t h d -> b t (h d)')
324
+ o = self.o_proj(o)
325
+ if attention_mask is not None:
326
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
327
+
328
+ return o, None, past_key_values
fla/layers/delta_net.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+ from torch.nn import functional as F
12
+
13
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
14
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
15
+ from fla.ops.delta_rule import chunk_delta_rule, fused_recurrent_delta_rule
16
+
17
+ if TYPE_CHECKING:
18
+ from transformers.processing_utils import Unpack
19
+
20
+ from fla.models.utils import Cache
21
+
22
+
23
+ def elu_p1(x):
24
+ return (F.elu(x, 1., False) + 1.).to(x)
25
+
26
+
27
+ def sum_norm(x):
28
+ return (x / x.sum(-1, keepdim=True)).to(x)
29
+
30
+
31
+ class DeltaNet(nn.Module):
32
+ r"""
33
+ The layer implementaion for [Parallelizing Linear Transformers with the Delta Rule over Sequence Length](https://arxiv.org/abs/2406.06484). # noqa:
34
+ DeltaNet was originally proposed in [Linear Transformers Are Secretly Fast Weight Programmers](https://arxiv.org/abs/2102.11174). # noqa
35
+
36
+ Args:
37
+ mode (str, Optional):
38
+ Which DeltaNet kernel to use.
39
+ Currently available: `chunk`, `fused_recurrent`, and `fused_chunk`.
40
+ Default: `chunk`.
41
+ hidden_size (int, Optional):
42
+ The hidden size of the input. Default: 1024.
43
+ expand_k (float, Optional):
44
+ The expansion ratio for the key dim. Default: 1.0.
45
+ expand_v (float, Optional):
46
+ The expansion ratio for the value dim. Default: 1.0.
47
+ num_heads (int, Optional):
48
+ The number of heads. Default: 4.
49
+ use_beta (bool, Optional):
50
+ Whether to use beta. Default: `True`.
51
+ use_gate (bool, Optional):
52
+ Whether to use output gate. Default: `False`.
53
+ use_short_conv (bool, Optional):
54
+ Whether to use short convolutions. Default: `True`.
55
+ conv_size (int, Optional):
56
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
57
+ conv_bias (bool, Optional):
58
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
59
+ allow_neg_eigval (bool, Optional):
60
+ Allow negative eigenvalues. Default: `False`. If set to `True`, the beta will be multiplied by 2.
61
+ See reference: [Unlocking State-Tracking in Linear RNNs Through Negative Eigenvalues](https://arxiv.org/abs/2411.12537)
62
+ layer_idx (int, Optional):
63
+ The index of the layer. Default: None.
64
+ norm_eps (float, Optional):
65
+ The epsilon value for the layernorm/rmsnorm layer. Default: 1e-5.
66
+ qk_activation (str, Optional):
67
+ The activation function for the query and key. Default: `silu`.
68
+ qk_norm (str, Optional):
69
+ The normalization method for the query and key. Default: `l2`.
70
+ """
71
+
72
+ def __init__(
73
+ self,
74
+ mode: str = 'chunk',
75
+ d_model: int = None,
76
+ hidden_size: int = 1024,
77
+ expand_k: float = 1.0,
78
+ expand_v: float = 1.0,
79
+ num_heads: int = 4,
80
+ use_beta: bool = True,
81
+ use_gate: bool = False,
82
+ use_short_conv: bool = True,
83
+ conv_size: int = 4,
84
+ conv_bias: bool = False,
85
+ allow_neg_eigval: bool = False,
86
+ layer_idx: int = None,
87
+ qk_activation: str = 'silu',
88
+ qk_norm: str = 'l2',
89
+ norm_eps: float = 1e-5,
90
+ **kwargs,
91
+ ) -> DeltaNet:
92
+ super().__init__()
93
+
94
+ self.mode = mode
95
+ self.qk_activation = qk_activation
96
+ self.qk_norm = qk_norm
97
+
98
+ assert self.qk_activation in ['silu', 'relu', 'elu', 'identity']
99
+ assert self.qk_norm in ['l2', 'sum']
100
+
101
+ if d_model is not None:
102
+ hidden_size = d_model
103
+ self.hidden_size = hidden_size
104
+ self.expand_k = expand_k
105
+ self.expand_v = expand_v
106
+ self.num_heads = num_heads
107
+ self.use_gate = use_gate
108
+ self.use_short_conv = use_short_conv
109
+ self.conv_size = conv_size
110
+ self.conv_bias = conv_bias
111
+ self.allow_neg_eigval = allow_neg_eigval
112
+
113
+ self.key_dim = int(hidden_size * expand_k)
114
+ self.value_dim = int(hidden_size * expand_v)
115
+ self.head_k_dim = self.key_dim // num_heads
116
+ self.head_v_dim = self.value_dim // num_heads
117
+ self.layer_idx = layer_idx
118
+
119
+ if mode == 'fused_chunk':
120
+ raise NotImplementedError("fused_chunk_delta_rule is now deprecated. Please use `chunk_delta_rule` instead.")
121
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
122
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
123
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
124
+
125
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
126
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
127
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
128
+
129
+ self.use_beta = use_beta
130
+ if self.use_beta:
131
+ self.b_proj = nn.Linear(hidden_size, self.num_heads, bias=False)
132
+ if use_short_conv:
133
+ self.conv_size = conv_size
134
+ self.q_conv1d = ShortConvolution(
135
+ hidden_size=self.key_dim,
136
+ kernel_size=conv_size,
137
+ bias=conv_bias,
138
+ activation='silu' if qk_activation == 'silu' else None,
139
+ )
140
+ self.k_conv1d = ShortConvolution(
141
+ hidden_size=self.key_dim,
142
+ kernel_size=conv_size,
143
+ bias=conv_bias,
144
+ activation='silu' if qk_activation == 'silu' else None,
145
+ )
146
+ self.v_conv1d = ShortConvolution(
147
+ hidden_size=self.value_dim,
148
+ kernel_size=conv_size,
149
+ bias=conv_bias,
150
+ activation='silu',
151
+ )
152
+ else:
153
+ warnings.warn(
154
+ "ShortConvolution is crucial to the performance. "
155
+ "Do not turn it off, i.e., setting `use_short_conv=False` unless you know what you are doing.",
156
+ )
157
+ if use_gate:
158
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
159
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, eps=norm_eps)
160
+ else:
161
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
162
+
163
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
164
+
165
+ def forward(
166
+ self,
167
+ hidden_states: torch.Tensor,
168
+ attention_mask: torch.Tensor | None = None,
169
+ past_key_values: Cache | None = None,
170
+ use_cache: bool | None = False,
171
+ output_attentions: bool | None = False,
172
+ **kwargs: Unpack[dict],
173
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
174
+ if attention_mask is not None:
175
+ assert len(attention_mask.shape) == 2, (
176
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
177
+ "for padding purposes (0 indicating padding). "
178
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
179
+ )
180
+
181
+ batch_size, q_len, _ = hidden_states.shape
182
+ # change to inference mode.
183
+ mode = 'fused_recurrent' if q_len <= 64 else self.mode
184
+
185
+ last_state = get_layer_cache(self, past_key_values)
186
+
187
+ cu_seqlens = kwargs.get('cu_seqlens')
188
+ if attention_mask is not None:
189
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
190
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
191
+
192
+ if self.use_short_conv:
193
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
194
+ if last_state is not None:
195
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
196
+ q, conv_state_q = self.q_conv1d(
197
+ x=self.q_proj(hidden_states),
198
+ cache=conv_state_q,
199
+ output_final_state=use_cache,
200
+ cu_seqlens=cu_seqlens,
201
+ )
202
+ k, conv_state_k = self.k_conv1d(
203
+ x=self.k_proj(hidden_states),
204
+ cache=conv_state_k,
205
+ output_final_state=use_cache,
206
+ cu_seqlens=cu_seqlens,
207
+ )
208
+ v, conv_state_v = self.v_conv1d(
209
+ x=self.v_proj(hidden_states),
210
+ cache=conv_state_v,
211
+ output_final_state=use_cache,
212
+ cu_seqlens=cu_seqlens,
213
+ )
214
+ else:
215
+ q = self.q_proj(hidden_states)
216
+ k = self.k_proj(hidden_states)
217
+ if self.qk_activation == 'silu':
218
+ q, k = F.silu(q), F.silu(k)
219
+ v = F.silu(self.v_proj(hidden_states))
220
+
221
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
222
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
223
+ if self.qk_activation != 'silu':
224
+ if self.qk_activation == 'relu':
225
+ q, k = q.relu(), k.relu()
226
+ elif self.qk_activation == 'elu':
227
+ q, k = elu_p1(q), elu_p1(k)
228
+ elif self.qk_activation != 'identity':
229
+ raise NotImplementedError
230
+
231
+ if self.qk_norm == 'sum':
232
+ q = sum_norm(q).to(q)
233
+ k = sum_norm(k).to(k)
234
+
235
+ if self.use_beta:
236
+ beta = self.b_proj(hidden_states).sigmoid()
237
+ else:
238
+ beta = torch.ones_like(q[..., 0])
239
+
240
+ if self.allow_neg_eigval:
241
+ beta = beta * 2.
242
+
243
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
244
+ if mode == 'fused_recurrent':
245
+ o, recurrent_state = fused_recurrent_delta_rule(
246
+ q=q,
247
+ k=k,
248
+ v=v,
249
+ beta=beta,
250
+ initial_state=recurrent_state,
251
+ output_final_state=use_cache,
252
+ cu_seqlens=cu_seqlens,
253
+ use_qk_l2norm_in_kernel=(self.qk_norm == 'l2'),
254
+ )
255
+ elif mode == 'chunk':
256
+ o, recurrent_state = chunk_delta_rule(
257
+ q=q,
258
+ k=k,
259
+ v=v,
260
+ beta=beta,
261
+ initial_state=recurrent_state,
262
+ output_final_state=use_cache,
263
+ cu_seqlens=cu_seqlens,
264
+ use_qk_l2norm_in_kernel=(self.qk_norm == 'l2'),
265
+ )
266
+ else:
267
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
268
+
269
+ update_layer_cache(
270
+ self,
271
+ past_key_values,
272
+ recurrent_state=recurrent_state,
273
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
274
+ offset=q_len,
275
+ )
276
+
277
+ if self.use_gate:
278
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
279
+ o = self.o_norm(o, g)
280
+ else:
281
+ o = self.o_norm(o)
282
+ o = rearrange(o, 'b t h d -> b t (h d)')
283
+ o = self.o_proj(o)
284
+ if attention_mask is not None:
285
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
286
+
287
+ return o, None, past_key_values
fla/layers/deltaformer.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from einops import rearrange
10
+ from transformers.utils import logging
11
+
12
+ from fla.modules import RMSNorm, RotaryEmbedding
13
+ from fla.ops.deltaformer import deltaformer_attn
14
+ from fla.ops.utils.index import prepare_lens_from_mask
15
+
16
+ if TYPE_CHECKING:
17
+ from fla.models.utils import Cache
18
+
19
+ logger = logging.get_logger(__name__)
20
+
21
+
22
+ class DeltaFormerAttention(nn.Module):
23
+
24
+ r"""
25
+ The layer implementation for DeltaFormer,
26
+ [Understanding Transformer from the Perspective of Associative Memory]
27
+ (https://arxiv.org/pdf/2505.19488).
28
+
29
+ Notes
30
+ - DeltaFormer attention is implemented with Triton kernels in `fla.ops.deltaformer` and is tuned
31
+ for typical head dimensions (e.g., 64/128). It currently supports fixed-length inputs.
32
+ - For variable-length inputs (padding masks), the deltaformer computation falls back to using the
33
+ fixed-length path, while the second stage (softmax attention over U) uses FlashAttention's
34
+ varlen path when an attention mask is provided.
35
+ - K/V grouping (GQA) is supported natively by FlashAttention via `num_kv_heads`.
36
+ - Uses K-K similarity in deltaformer computation instead of Q-K similarity for better performance.
37
+
38
+ Args:
39
+ hidden_size (int, Optional):
40
+ The hidden size of the input. Default: 2048.
41
+ num_heads (int, Optional):
42
+ The number of attention heads. Default: 32.
43
+ num_kv_heads (int, Optional):
44
+ The number of key/value heads for grouped-query attention. If None, equals `num_heads`.
45
+ Default: None.
46
+ qkv_bias (bool, Optional):
47
+ Whether to use bias for Q/K/V projections. Default: False.
48
+ qk_norm (bool, Optional):
49
+ Whether to apply per-head RMSNorm to Q and K before attention. Default: False.
50
+ rope_theta (float, Optional):
51
+ The base frequency for rotary position embedding. Default: 10000.
52
+ max_position_embeddings (int, Optional):
53
+ The maximum position embeddings. Default: None.
54
+ layer_idx (int, Optional):
55
+ The index of the layer (used for cache compatibility). Default: None.
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ hidden_size: int = 2048,
61
+ num_heads: int = 32,
62
+ num_kv_heads: int | None = None,
63
+ qkv_bias: bool = False,
64
+ qk_norm: bool = False,
65
+ rope_theta: float = 10000.,
66
+ max_position_embeddings: int | None = None,
67
+ layer_idx: int | None = None,
68
+ ):
69
+ super().__init__()
70
+
71
+ self.hidden_size = hidden_size
72
+ self.num_heads = num_heads
73
+ self.num_kv_heads = num_kv_heads if num_kv_heads is not None else num_heads
74
+ self.num_kv_groups = num_heads // self.num_kv_heads
75
+ self.head_dim = self.hidden_size // self.num_heads
76
+ self.kv_dim = self.num_kv_heads * self.head_dim
77
+ self.qkv_bias = qkv_bias
78
+ self.qk_norm = qk_norm
79
+ self.rope_theta = rope_theta
80
+ self.max_position_embeddings = max_position_embeddings
81
+ self.layer_idx = layer_idx
82
+
83
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias)
84
+ self.k_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
85
+ self.v_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
86
+ self.b_proj = nn.Linear(self.hidden_size, self.num_heads, bias=True)
87
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
88
+
89
+ if qk_norm:
90
+ self.q_norm = RMSNorm(self.head_dim, dtype=torch.float32)
91
+ self.k_norm = RMSNorm(self.head_dim, dtype=torch.float32)
92
+
93
+ self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta)
94
+
95
+ def forward(
96
+ self,
97
+ hidden_states: torch.Tensor,
98
+ attention_mask: torch.LongTensor | None = None,
99
+ past_key_values: Cache | None = None,
100
+ output_attentions: bool = False,
101
+ use_cache: bool = False,
102
+ **kwargs,
103
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
104
+ attentions = None
105
+ if attention_mask is not None:
106
+ assert len(attention_mask.shape) == 2, (
107
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
108
+ "for padding purposes (0 indicating padding). "
109
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
110
+ )
111
+
112
+ batch_size, q_len, _ = hidden_states.size()
113
+
114
+ q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
115
+ k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
116
+ v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
117
+ beta = self.b_proj(hidden_states)
118
+
119
+ if self.qk_norm:
120
+ q, k = self.q_norm(q), self.k_norm(k)
121
+
122
+ cu_seqlens_kw = kwargs.get('cu_seqlens')
123
+ seqlen_offset, max_seqlen = 0, q_len
124
+ if past_key_values is not None:
125
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
126
+ max_seqlen = q_len + seqlen_offset
127
+
128
+ if attention_mask is not None:
129
+ seqlen_offset = seqlen_offset + prepare_lens_from_mask(attention_mask) - attention_mask.shape[-1]
130
+ max_seqlen = q_len + max(seqlen_offset)
131
+
132
+ if self.max_position_embeddings is not None:
133
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
134
+
135
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens_kw)
136
+
137
+ o = deltaformer_attn(
138
+ q=q,
139
+ k=k,
140
+ v=v,
141
+ beta=beta,
142
+ attention_mask=attention_mask,
143
+ cu_seqlens=cu_seqlens_kw,
144
+ )
145
+
146
+ o = o.reshape(batch_size, q_len, -1)
147
+ o = self.o_proj(o)
148
+
149
+ if not output_attentions:
150
+ attentions = None
151
+
152
+ return o, attentions, past_key_values
fla/layers/forgetting_attn.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ import torch.utils.checkpoint
11
+ from einops import rearrange
12
+ from transformers.utils import logging
13
+
14
+ from fla.layers.utils import pad_input, unpad_input
15
+ from fla.modules import GroupNorm
16
+ from fla.ops.attn.decoding import attn_decoding_one_step
17
+ from fla.ops.forgetting_attn.parallel import parallel_forgetting_attn
18
+
19
+ if TYPE_CHECKING:
20
+ from fla.models.utils import Cache
21
+
22
+ logger = logging.get_logger(__name__)
23
+
24
+
25
+ class ForgettingAttention(nn.Module):
26
+
27
+ def __init__(
28
+ self,
29
+ hidden_size: int = 2048,
30
+ num_heads: int = 32,
31
+ num_kv_heads: int | None = None,
32
+ qkv_bias: bool = False,
33
+ qk_norm: bool = False,
34
+ window_size: int | None = None,
35
+ use_output_gate: bool = False,
36
+ layer_idx: int = None,
37
+ ):
38
+ super().__init__()
39
+
40
+ self.hidden_size = hidden_size
41
+ self.num_heads = num_heads
42
+ if num_kv_heads is None:
43
+ self.num_kv_heads = self.num_heads
44
+ else:
45
+ self.num_kv_heads = num_kv_heads
46
+ self.num_kv_groups = num_heads // self.num_kv_heads
47
+ self.head_dim = self.hidden_size // self.num_heads
48
+ self.kv_dim = self.num_kv_heads * self.head_dim
49
+ self.qkv_bias = qkv_bias
50
+ self.qk_norm = qk_norm
51
+
52
+ self.window_size = window_size
53
+ self.use_output_gate = use_output_gate
54
+ self.layer_idx = layer_idx
55
+
56
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias)
57
+ self.k_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
58
+ self.v_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
59
+ self.f_proj = nn.Linear(self.hidden_size, self.num_heads, bias=True)
60
+
61
+ if use_output_gate:
62
+ self.g_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
63
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
64
+
65
+ if qk_norm:
66
+ self.q_norm = GroupNorm(
67
+ num_groups=self.num_heads,
68
+ hidden_size=self.hidden_size,
69
+ is_rms_norm=True,
70
+ )
71
+ self.k_norm = GroupNorm(
72
+ num_groups=self.num_kv_heads,
73
+ hidden_size=self.kv_dim,
74
+ is_rms_norm=True,
75
+ )
76
+
77
+ def forward(
78
+ self,
79
+ hidden_states: torch.Tensor,
80
+ attention_mask: torch.LongTensor | None = None,
81
+ past_key_values: Cache | None = None,
82
+ output_attentions: bool = False,
83
+ use_cache: bool = False,
84
+ **kwargs,
85
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
86
+ if attention_mask is not None:
87
+ assert len(attention_mask.shape) == 2, (
88
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
89
+ "for padding purposes (0 indicating padding). "
90
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
91
+ )
92
+
93
+ batch_size, q_len, _ = hidden_states.size()
94
+
95
+ q, k, v = self.q_proj(hidden_states), self.k_proj(hidden_states), self.v_proj(hidden_states)
96
+ f = F.logsigmoid(self.f_proj(hidden_states).float())
97
+ if self.qk_norm:
98
+ q, k = self.q_norm(q), self.k_norm(k)
99
+
100
+ cu_seqlens = kwargs.get('cu_seqlens')
101
+ if past_key_values is not None:
102
+ assert cu_seqlens is None, "cu_seqlens should not be provided when past_key_values is not None"
103
+ state = past_key_values.update(
104
+ attn_state=(k, v, f),
105
+ layer_idx=self.layer_idx,
106
+ offset=q_len,
107
+ cache_kwargs=dict(window_size=self.window_size),
108
+ )
109
+ k, v, f = state['attn_state']
110
+
111
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_dim)
112
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
113
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
114
+
115
+ if attention_mask is not None:
116
+ q, (k, v, f), indices_q, cu_seqlens, max_seq_lens = unpad_input(q, (k, v, f), attention_mask, q_len, keepdim=True)
117
+ _, cu_seqlens_k = cu_seqlens
118
+ cu_seqlens = cu_seqlens_k
119
+ max_seqlen_q, max_seqlen_k = max_seq_lens
120
+ if max_seqlen_q != max_seqlen_k:
121
+ assert max_seqlen_q == 1, "only support q_len == 1 for decoding"
122
+ o = attn_decoding_one_step(q, k, v, f, cu_seqlens=cu_seqlens)
123
+ else:
124
+ o = parallel_forgetting_attn(q, k, v, f, cu_seqlens=cu_seqlens)
125
+ else:
126
+ o = parallel_forgetting_attn(q, k, v, f, cu_seqlens=cu_seqlens)
127
+ if attention_mask is not None:
128
+ o = pad_input(o.squeeze(0), indices_q, batch_size, q_len)
129
+ o = rearrange(o, '... h d -> ... (h d)')
130
+ if self.use_output_gate:
131
+ o = self.g_proj(hidden_states).sigmoid() * o
132
+ o = self.o_proj(o)
133
+ return o, None, past_key_values
fla/layers/gated_deltanet.py ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import warnings
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from einops import rearrange, repeat
12
+ from torch.nn import functional as F
13
+
14
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
15
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
16
+ from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ @torch.compile
25
+ def elu_p1(x):
26
+ return (F.elu(x, 1., False) + 1.).to(x)
27
+
28
+
29
+ @torch.compile
30
+ def sum_norm(x):
31
+ return (x / x.sum(-1, keepdim=True)).to(x)
32
+
33
+
34
+ class GatedDeltaNet(nn.Module):
35
+ """
36
+ The layer implementaion for [Gated Delta Networks: Improving Mamba2 with Delta Rule](https://arxiv.org/abs/2412.06464). # noqa
37
+
38
+ Similar to Mamba2, each layer contains around 6*hidden_size*hidden_size parameters.
39
+
40
+ Parameter alloation when use_gate=True:
41
+ - 0.75 * hidden_size * hidden_size for the q_proj and k_proj each
42
+ - 1.5 * hidden_size * hidden_size for the v_proj, g_proj and o_proj each
43
+ - Others are ignorably small.
44
+ - In total = 0.75 * 2 + 1.5 * 3 = 6 * hidden_size * hidden_size
45
+ NOTE: num_heads * head_dim = 0.75 * hidden_size, please make sure to set the correct num_heads and head_dim.
46
+
47
+ Parameter allocation when use_gate=False:
48
+ - 1 * hidden_size * hidden_size for the q_proj and k_proj each
49
+ - 2 * hidden_size * hidden_size for the v_proj and o_proj each
50
+ - Others are ignorably small.
51
+ - In total = 1 * 2 + 2 * 2 = 6 * hidden_size * hidden_size
52
+
53
+ Args:
54
+ hidden_size (int, Optional):
55
+ The hidden size of the input. Default: 2048.
56
+ expand_v (float, Optional):
57
+ The expansion ratio for the value dim. Default: 2.0.
58
+ head_dim (int, Optional):
59
+ The dimension of each head. Default: 256.
60
+ num_heads (int, Optional):
61
+ The number of heads. Default: 4.
62
+ num_v_heads (int, Optional):
63
+ The number of heads for the value projection, equal to `num_heads` if `None`.
64
+ GVA is applied if `num_v_heads` > `num_heads`. Default: `None`.
65
+ mode (str, Optional):
66
+ Which Gated DeltaNet kernel to use.
67
+ Currently available: `chunk` and `fused_recurrent`.
68
+ Default: `chunk`.
69
+ use_beta (bool, Optional):
70
+ Whether to use beta. Default: `True`.
71
+ use_gate (bool, Optional):
72
+ Whether to use output gate. Default: `True`.
73
+ use_short_conv (bool, Optional):
74
+ Whether to use short convolutions. Default: `True`.
75
+ allow_neg_eigval (bool, Optional):
76
+ Allow negative eigenvalues. Default: `False`. If set to `True`, the beta will be multiplied by 2.
77
+ See reference: [Unlocking State-Tracking in Linear RNNs Through Negative Eigenvalues](https://arxiv.org/abs/2411.12537)
78
+ conv_size (int, Optional):
79
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
80
+ conv_bias (bool, Optional):
81
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
82
+ layer_idx (int, Optional):
83
+ The index of the layer. Default: None.
84
+ norm_eps (float, Optional):
85
+ The epsilon value for the normalization layer. Default: 1e-5.
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ hidden_size: int = 2048,
91
+ expand_v: float = 2,
92
+ head_dim: int = 256,
93
+ num_heads: int = 6,
94
+ num_v_heads: int = None,
95
+ mode: str = 'chunk',
96
+ use_gate: bool = True,
97
+ use_short_conv: bool = True,
98
+ allow_neg_eigval: bool = False,
99
+ conv_size: int = 4,
100
+ conv_bias: bool = False,
101
+ layer_idx: int = None,
102
+ norm_eps: float = 1e-5,
103
+ **kwargs,
104
+ ) -> GatedDeltaNet:
105
+ super().__init__()
106
+
107
+ self.mode = mode
108
+ self.allow_neg_eigval = allow_neg_eigval
109
+ self.hidden_size = hidden_size
110
+ self.expand_v = expand_v
111
+
112
+ self.use_gate = use_gate
113
+ self.use_short_conv = use_short_conv
114
+ self.conv_size = conv_size
115
+ self.conv_bias = conv_bias
116
+
117
+ self.head_dim = head_dim
118
+ self.num_heads = num_heads
119
+ self.num_v_heads = num_v_heads if num_v_heads is not None else num_heads
120
+
121
+ self.head_k_dim = head_dim
122
+ self.head_v_dim = int(self.head_dim * self.expand_v)
123
+ self.key_dim = int(self.num_heads * self.head_k_dim)
124
+ self.value_dim = int(self.num_v_heads * self.head_v_dim)
125
+ self.layer_idx = layer_idx
126
+
127
+ # Consistency check: Ensure expand_v produces integer values
128
+ if not math.isclose(self.num_v_heads * self.head_dim * expand_v, self.value_dim, rel_tol=1e-5):
129
+ raise ValueError(
130
+ f"expand_v={expand_v} does not produce an integer value when multiplied by key_dim={self.key_dim}. "
131
+ f"Resulting value_dim would be {self.num_v_heads * self.head_dim * expand_v}, which is invalid for nn.Linear.",
132
+ )
133
+ if self.num_v_heads > self.num_heads and self.num_v_heads % self.num_heads != 0:
134
+ raise ValueError(
135
+ f"num_v_heads={self.num_v_heads} must be divisible by num_heads={self.num_heads}.",
136
+ )
137
+
138
+ if not math.isclose(head_dim * expand_v, self.head_v_dim, rel_tol=1e-5):
139
+ raise ValueError(
140
+ f"expand_v={expand_v} does not produce an integer value when multiplied by head_dim={head_dim}. "
141
+ f"Resulting head_v_dim would be {head_dim * expand_v}, which is invalid for FusedRMSNormGated.",
142
+ )
143
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
144
+
145
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
146
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
147
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
148
+ self.a_proj = nn.Linear(hidden_size, self.num_v_heads, bias=False)
149
+ self.b_proj = nn.Linear(hidden_size, self.num_v_heads, bias=False)
150
+
151
+ A = torch.empty(self.num_v_heads, dtype=torch.float32).uniform_(0, 16)
152
+ self.A_log = nn.Parameter(torch.log(A))
153
+ self.A_log._no_weight_decay = True
154
+ # hard coded for now
155
+ dt_min = 0.001
156
+ dt_max = 0.1
157
+ dt_init_floor = 1e-4
158
+ dt = torch.exp(
159
+ torch.rand(self.num_v_heads) * (math.log(dt_max) - math.log(dt_min))
160
+ + math.log(dt_min),
161
+ )
162
+ dt = torch.clamp(dt, min=dt_init_floor)
163
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
164
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
165
+ self.dt_bias = nn.Parameter(inv_dt)
166
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
167
+ # name.endswith("bias") in param_grouping.py
168
+ self.dt_bias._no_weight_decay = True
169
+
170
+ if use_short_conv:
171
+ self.conv_size = conv_size
172
+ self.q_conv1d = ShortConvolution(
173
+ hidden_size=self.key_dim,
174
+ kernel_size=conv_size,
175
+ bias=conv_bias,
176
+ activation='silu',
177
+ )
178
+ self.k_conv1d = ShortConvolution(
179
+ hidden_size=self.key_dim,
180
+ kernel_size=conv_size,
181
+ bias=conv_bias,
182
+ activation='silu',
183
+ )
184
+ self.v_conv1d = ShortConvolution(
185
+ hidden_size=self.value_dim,
186
+ kernel_size=conv_size,
187
+ bias=conv_bias,
188
+ activation='silu',
189
+ )
190
+ else:
191
+ warnings.warn(
192
+ "ShortConvolution is crucial to the performance. "
193
+ "Do not turn it off, i.e., setting `use_short_conv=False` unless you know what you are doing.",
194
+ )
195
+ if use_gate:
196
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
197
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, eps=norm_eps)
198
+ else:
199
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
200
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
201
+
202
+ def forward(
203
+ self,
204
+ hidden_states: torch.Tensor,
205
+ attention_mask: torch.Tensor | None = None,
206
+ past_key_values: Cache | None = None,
207
+ use_cache: bool | None = False,
208
+ output_attentions: bool | None = False,
209
+ **kwargs: Unpack[dict],
210
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
211
+ if attention_mask is not None:
212
+ assert len(attention_mask.shape) == 2, (
213
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
214
+ "for padding purposes (0 indicating padding). "
215
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
216
+ )
217
+
218
+ batch_size, q_len, _ = hidden_states.shape
219
+ # change to inference mode.
220
+ mode = 'fused_recurrent' if (q_len <= 64 and not self.training) else self.mode
221
+ if self.training:
222
+ assert mode == 'chunk', "Only chunk mode is supported in training."
223
+
224
+ last_state = get_layer_cache(self, past_key_values)
225
+
226
+ cu_seqlens = kwargs.get('cu_seqlens')
227
+ if attention_mask is not None:
228
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
229
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
230
+
231
+ if self.use_short_conv:
232
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
233
+ if last_state is not None:
234
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
235
+ q, conv_state_q = self.q_conv1d(
236
+ x=self.q_proj(hidden_states),
237
+ cache=conv_state_q,
238
+ output_final_state=use_cache,
239
+ cu_seqlens=cu_seqlens,
240
+ )
241
+ k, conv_state_k = self.k_conv1d(
242
+ x=self.k_proj(hidden_states),
243
+ cache=conv_state_k,
244
+ output_final_state=use_cache,
245
+ cu_seqlens=cu_seqlens,
246
+ )
247
+ v, conv_state_v = self.v_conv1d(
248
+ x=self.v_proj(hidden_states),
249
+ cache=conv_state_v,
250
+ output_final_state=use_cache,
251
+ cu_seqlens=cu_seqlens,
252
+ )
253
+ else:
254
+ q = F.silu(self.q_proj(hidden_states))
255
+ k = F.silu(self.k_proj(hidden_states))
256
+ v = F.silu(self.v_proj(hidden_states))
257
+
258
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
259
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
260
+
261
+ if self.num_v_heads > self.num_heads:
262
+ q, k = map(lambda x: repeat(x, '... h d -> ... (h g) d', g=self.num_v_heads // self.num_heads), (q, k))
263
+
264
+ beta = self.b_proj(hidden_states).sigmoid()
265
+ if self.allow_neg_eigval:
266
+ beta = beta * 2.
267
+
268
+ g = -self.A_log.float().exp() * F.softplus(self.a_proj(hidden_states).float() + self.dt_bias)
269
+
270
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
271
+ if mode == 'chunk':
272
+ o, recurrent_state = chunk_gated_delta_rule(
273
+ q=q,
274
+ k=k,
275
+ v=v,
276
+ g=g,
277
+ beta=beta,
278
+ initial_state=recurrent_state,
279
+ output_final_state=use_cache,
280
+ cu_seqlens=cu_seqlens,
281
+ use_qk_l2norm_in_kernel=True,
282
+ )
283
+ elif mode == 'fused_recurrent':
284
+ o, recurrent_state = fused_recurrent_gated_delta_rule(
285
+ q=q,
286
+ k=k,
287
+ v=v,
288
+ g=g,
289
+ beta=beta,
290
+ initial_state=recurrent_state,
291
+ output_final_state=use_cache,
292
+ cu_seqlens=cu_seqlens,
293
+ use_qk_l2norm_in_kernel=True,
294
+ )
295
+ else:
296
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
297
+
298
+ update_layer_cache(
299
+ self,
300
+ past_key_values,
301
+ recurrent_state=recurrent_state,
302
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
303
+ offset=q_len,
304
+ )
305
+
306
+ if self.use_gate:
307
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
308
+ o = self.o_norm(o, g)
309
+ else:
310
+ o = self.o_norm(o)
311
+ o = rearrange(o, 'b t h d -> b t (h d)')
312
+ o = self.o_proj(o)
313
+ if attention_mask is not None:
314
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
315
+
316
+ return o, None, past_key_values
fla/layers/gated_deltaproduct.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import warnings
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from einops import rearrange, repeat
12
+ from torch.nn import functional as F
13
+
14
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
15
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
16
+ from fla.ops.gated_delta_product import chunk_gated_delta_product
17
+ from fla.ops.gated_delta_rule import fused_recurrent_gated_delta_rule
18
+
19
+ if TYPE_CHECKING:
20
+ from transformers.processing_utils import Unpack
21
+
22
+ from fla.models.utils import Cache
23
+
24
+
25
+ class GatedDeltaProduct(nn.Module):
26
+ """
27
+ Generalized version of GatedDoubleDeltaNet that supports arbitrary number of householder transformations.
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ hidden_size: int = 2048,
33
+ expand_v: float = 2,
34
+ head_dim: int = 256,
35
+ num_heads: int = 6,
36
+ num_v_heads: int = None,
37
+ mode: str = 'chunk',
38
+ use_output_gate: bool = True,
39
+ use_short_conv: bool = True,
40
+ conv_size: int = 4,
41
+ conv_bias: bool = False,
42
+ layer_idx: int = None,
43
+ norm_eps: float = 1e-5,
44
+ use_forget_gate: bool = True,
45
+ allow_neg_eigval: bool = True,
46
+ num_householder: int = 2,
47
+ **kwargs,
48
+ ) -> GatedDeltaProduct:
49
+ super().__init__()
50
+
51
+ self.mode = mode
52
+
53
+ self.hidden_size = hidden_size
54
+ self.expand_v = expand_v
55
+
56
+ self.use_forget_gate = use_forget_gate
57
+ self.allow_neg_eigval = allow_neg_eigval
58
+ self.num_householder = num_householder
59
+ self.use_output_gate = use_output_gate
60
+ self.use_short_conv = use_short_conv
61
+ self.conv_size = conv_size
62
+ self.conv_bias = conv_bias
63
+
64
+ self.head_dim = head_dim
65
+ self.num_heads = num_heads
66
+ self.num_v_heads = num_v_heads if num_v_heads is not None else num_heads
67
+
68
+ self.head_k_dim = head_dim
69
+ self.head_v_dim = int(self.head_dim * self.expand_v)
70
+ self.key_dim = int(self.num_heads * self.head_k_dim)
71
+ self.value_dim = int(self.num_v_heads * self.head_v_dim)
72
+ self.layer_idx = layer_idx
73
+
74
+ # Consistency check: Ensure expand_v produces integer values
75
+ if not math.isclose(self.num_v_heads * self.head_dim * expand_v, self.value_dim, rel_tol=1e-5):
76
+ raise ValueError(
77
+ f"expand_v={expand_v} does not produce an integer value when multiplied by key_dim={self.key_dim}. "
78
+ f"Resulting value_dim would be {self.num_v_heads * self.head_dim * expand_v}, which is invalid for nn.Linear.",
79
+ )
80
+ if self.num_v_heads > self.num_heads and self.num_v_heads % self.num_heads != 0:
81
+ raise ValueError(
82
+ f"num_v_heads={self.num_v_heads} must be divisible by num_heads={self.num_heads}.",
83
+ )
84
+
85
+ if not math.isclose(head_dim * expand_v, self.head_v_dim, rel_tol=1e-5):
86
+ raise ValueError(
87
+ f"expand_v={expand_v} does not produce an integer value when multiplied by head_dim={head_dim}. "
88
+ f"Resulting head_v_dim would be {head_dim * expand_v}, which is invalid for FusedRMSNormGated.",
89
+ )
90
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
91
+
92
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
93
+ self.k_proj = nn.Linear(hidden_size, self.key_dim * num_householder, bias=False)
94
+ self.v_proj = nn.Linear(hidden_size, self.value_dim * num_householder, bias=False)
95
+ self.b_proj = nn.Linear(hidden_size, self.num_v_heads * num_householder, bias=False)
96
+
97
+ if self.use_forget_gate:
98
+ self.a_proj = nn.Linear(hidden_size, self.num_v_heads, bias=False)
99
+ A = torch.empty(self.num_v_heads, dtype=torch.float32).uniform_(0, 16)
100
+ self.A_log = nn.Parameter(torch.log(A))
101
+ self.A_log._no_weight_decay = True
102
+ # hard coded for now
103
+ dt_min = 0.001
104
+ dt_max = 0.1
105
+ dt_init_floor = 1e-4
106
+ dt = torch.exp(
107
+ torch.rand(self.num_v_heads) * (math.log(dt_max) - math.log(dt_min))
108
+ + math.log(dt_min),
109
+ )
110
+ dt = torch.clamp(dt, min=dt_init_floor)
111
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
112
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
113
+ self.dt_bias = nn.Parameter(inv_dt)
114
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
115
+ # name.endswith("bias") in param_grouping.py
116
+ self.dt_bias._no_weight_decay = True
117
+
118
+ if use_short_conv:
119
+ self.conv_size = conv_size
120
+ self.q_conv1d = ShortConvolution(
121
+ hidden_size=self.key_dim,
122
+ kernel_size=conv_size,
123
+ bias=conv_bias,
124
+ activation='silu',
125
+ )
126
+ self.k_conv1d = ShortConvolution(
127
+ hidden_size=self.key_dim * num_householder,
128
+ kernel_size=conv_size,
129
+ bias=conv_bias,
130
+ activation='silu',
131
+ )
132
+ self.v_conv1d = ShortConvolution(
133
+ hidden_size=self.value_dim * num_householder,
134
+ kernel_size=conv_size,
135
+ bias=conv_bias,
136
+ activation='silu',
137
+ )
138
+ else:
139
+ warnings.warn(
140
+ "ShortConvolution is crucial to the performance. "
141
+ "Do not turn it off, i.e., setting `use_short_conv=False` unless you know what you are doing.",
142
+ )
143
+ if use_output_gate:
144
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
145
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, eps=norm_eps)
146
+ else:
147
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
148
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
149
+
150
+ def _initialize_weights(self, module: nn.Module):
151
+ if getattr(module, "_is_hf_initialized", False):
152
+ return
153
+ if isinstance(module, nn.Linear):
154
+ nn.init.xavier_uniform_(module.weight, gain=2 ** -2.5)
155
+ if module.bias is not None:
156
+ nn.init.zeros_(module.bias)
157
+ module._is_hf_initialized = True
158
+
159
+ def forward(
160
+ self,
161
+ hidden_states: torch.Tensor,
162
+ attention_mask: torch.Tensor | None = None,
163
+ past_key_values: Cache | None = None,
164
+ use_cache: bool | None = False,
165
+ output_attentions: bool | None = False,
166
+ **kwargs: Unpack[dict],
167
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
168
+ if attention_mask is not None:
169
+ assert len(attention_mask.shape) == 2, (
170
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
171
+ "for padding purposes (0 indicating padding). "
172
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
173
+ )
174
+
175
+ batch_size, q_len, _ = hidden_states.shape
176
+ # change to inference mode.
177
+ mode = 'fused_recurrent' if (q_len <= 64 and not self.training) else self.mode
178
+ if self.training:
179
+ assert mode == 'chunk', "Only chunk mode is supported in training."
180
+
181
+ last_state = get_layer_cache(self, past_key_values)
182
+
183
+ cu_seqlens = kwargs.get('cu_seqlens')
184
+ if attention_mask is not None:
185
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
186
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
187
+
188
+ if self.use_short_conv:
189
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
190
+ if last_state is not None:
191
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
192
+ q, conv_state_q = self.q_conv1d(
193
+ x=self.q_proj(hidden_states),
194
+ cache=conv_state_q,
195
+ output_final_state=use_cache,
196
+ cu_seqlens=cu_seqlens,
197
+ )
198
+ k, conv_state_k = self.k_conv1d(
199
+ x=self.k_proj(hidden_states),
200
+ cache=conv_state_k,
201
+ output_final_state=use_cache,
202
+ cu_seqlens=cu_seqlens,
203
+ )
204
+ v, conv_state_v = self.v_conv1d(
205
+ x=self.v_proj(hidden_states),
206
+ cache=conv_state_v,
207
+ output_final_state=use_cache,
208
+ cu_seqlens=cu_seqlens,
209
+ )
210
+ else:
211
+ q = F.silu(self.q_proj(hidden_states))
212
+ k = F.silu(self.k_proj(hidden_states))
213
+ v = F.silu(self.v_proj(hidden_states))
214
+
215
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_k_dim)
216
+ k = rearrange(k, '... t (n h d) -> ... (t n) h d', n=self.num_householder, d=self.head_k_dim)
217
+ v = rearrange(v, '... t (n h d) -> ... (t n) h d', n=self.num_householder, d=self.head_v_dim)
218
+
219
+ if self.num_v_heads > self.num_heads:
220
+ q, k = map(lambda x: repeat(x, '... h d -> ... (h g) d', g=self.num_v_heads // self.num_heads), (q, k))
221
+
222
+ beta = self.b_proj(hidden_states).sigmoid()
223
+ if self.allow_neg_eigval:
224
+ beta = beta * 2.
225
+
226
+ beta = rearrange(beta, '... t (n h) -> ... (t n) h', n=self.num_householder)
227
+ if self.use_forget_gate:
228
+ g = -self.A_log.float().exp() * F.softplus(self.a_proj(hidden_states).float() + self.dt_bias)
229
+ else:
230
+ g = None
231
+
232
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
233
+ if mode == 'chunk':
234
+ o, recurrent_state = chunk_gated_delta_product(
235
+ q=q,
236
+ k=k,
237
+ v=v,
238
+ g=g,
239
+ beta=beta,
240
+ initial_state=recurrent_state,
241
+ output_final_state=use_cache,
242
+ cu_seqlens=cu_seqlens,
243
+ num_householder=self.num_householder,
244
+ use_qk_l2norm_in_kernel=True,
245
+ )
246
+
247
+ elif mode == 'fused_recurrent':
248
+ if self.use_forget_gate:
249
+ g_new = g.new_zeros(g.shape[0], g.shape[1], self.num_householder, g.shape[2])
250
+ g_new[:, :, 0] = g
251
+ g = rearrange(g_new, '... t n h -> ... (t n) h')
252
+
253
+ q_new = q.new_zeros(q.shape[0], q.shape[1], self.num_householder, q.shape[2], q.shape[3])
254
+ q_new[:, :, -1] = q
255
+ q = rearrange(q_new, '... t n h d-> ... (t n) h d')
256
+ o, recurrent_state = fused_recurrent_gated_delta_rule(
257
+ q=q,
258
+ k=k,
259
+ v=v,
260
+ g=g,
261
+ beta=beta,
262
+ initial_state=recurrent_state,
263
+ output_final_state=use_cache,
264
+ cu_seqlens=cu_seqlens * self.num_householder if cu_seqlens is not None else None,
265
+ use_qk_l2norm_in_kernel=True,
266
+ )
267
+ o = rearrange(o, '... (t n) h d -> ... t n h d', n=self.num_householder)[..., -1, :, :].contiguous()
268
+
269
+ update_layer_cache(
270
+ self,
271
+ past_key_values,
272
+ recurrent_state=recurrent_state,
273
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
274
+ offset=q_len,
275
+ )
276
+
277
+ if self.use_output_gate:
278
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
279
+ o = self.o_norm(o, g)
280
+ else:
281
+ o = self.o_norm(o)
282
+ o = rearrange(o, 'b t h d -> b t (h d)')
283
+ o = self.o_proj(o)
284
+ if attention_mask is not None:
285
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
286
+
287
+ return o, None, past_key_values
fla/layers/gla.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ from einops import rearrange, repeat
12
+
13
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
14
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
15
+ from fla.modules.activations import ACT2FN
16
+ from fla.ops.gla import chunk_gla, fused_chunk_gla, fused_recurrent_gla
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ class GatedLinearAttention(nn.Module):
25
+ r"""
26
+ The layer implementaion for [Gated Linear Attention Transformers with Hardware-Efficient Training](https://arxiv.org/abs/2312.06635). # noqa
27
+
28
+ Args:
29
+ mode (str, Optional):
30
+ Which GLA kernel to use.
31
+ Currently available: `chunk`, `fused_recurrent`, and `fused_chunk`.
32
+ Default: `chunk`.
33
+ hidden_size (int, Optional):
34
+ The hidden size of the input. Default: 1024.
35
+ expand_k (float, Optional):
36
+ The expansion ratio for the key dim. Default: 0.5.
37
+ expand_v (float, Optional):
38
+ The expansion ratio for the value dim. Default: 1.0.
39
+ num_heads (int, Optional):
40
+ The number of heads. Default: 4.
41
+ num_kv_heads (int, Optional):
42
+ The number of key/value heads, used for MQA. Default: None.
43
+ feature_map (str, Optional):
44
+ Feature map function applied to queries/keys. Default: None.
45
+ use_short_conv (bool, Optional):
46
+ Whether to use short convolutions. Default: `False`.
47
+ conv_size (int, Optional):
48
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
49
+ conv_bias (bool, Optional):
50
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
51
+ use_output_gate (bool, Optional):
52
+ Whether to use output gate. Default: `True`.
53
+ gate_fn (str, Optional):
54
+ The activation function for the output gate. Default: `swish`.
55
+ elementwise_affine (bool, Optional):
56
+ If `True`, applies elementwise affine to LayerNorm with learnable parameters. Default: `True`.
57
+ norm_eps (float, Optional):
58
+ The epsilon value for the layernorm/rmsnorm layer. Default: 1e-5.
59
+ gate_logit_normalizer (int, Optional):
60
+ The normalizer for the gate logits, appied after `logsigmoid`. Default: 16.
61
+ gate_low_rank_dim (int, Optional):
62
+ The low rank dim for the gate projection. Default: 16.
63
+ clamp_min (float, Optional):
64
+ The minimum value for the gate logits. Default: None.
65
+ fuse_norm (bool, Optional):
66
+ Whether to fuse the norm and the output gate for better memory footprint. Default: `True`.
67
+ layer_idx (int, Optional):
68
+ The index of the layer. Default: None.
69
+ """
70
+
71
+ def __init__(
72
+ self,
73
+ mode: str = 'chunk',
74
+ hidden_size: int = 1024,
75
+ expand_k: float = 0.5,
76
+ expand_v: float = 1.0,
77
+ num_heads: int = 4,
78
+ num_kv_heads: int | None = None,
79
+ feature_map: str | None = None,
80
+ use_short_conv: bool = False,
81
+ conv_size: int = 4,
82
+ conv_bias: bool = False,
83
+ use_output_gate: bool = True,
84
+ gate_fn: str = 'swish',
85
+ elementwise_affine: bool | None = True,
86
+ norm_eps: float = 1e-5,
87
+ gate_logit_normalizer: int = 16,
88
+ gate_low_rank_dim: int = 16,
89
+ clamp_min: float | None = None,
90
+ fuse_norm: bool = True,
91
+ layer_idx: int = None,
92
+ ) -> GatedLinearAttention:
93
+ super().__init__()
94
+
95
+ self.mode = mode
96
+ self.hidden_size = hidden_size
97
+ self.expand_k = expand_k
98
+ self.expand_v = expand_v
99
+ self.num_heads = num_heads
100
+ self.num_kv_heads = num_kv_heads if num_kv_heads is not None else num_heads
101
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
102
+ self.feature_map_fn = ACT2FN[feature_map] if feature_map is not None else None
103
+
104
+ self.use_short_conv = use_short_conv
105
+ self.conv_size = conv_size
106
+ self.conv_bias = conv_bias
107
+ self.use_output_gate = use_output_gate
108
+
109
+ self.key_dim = int(hidden_size * expand_k)
110
+ self.value_dim = int(hidden_size * expand_v)
111
+ self.key_dim_per_group = self.key_dim // self.num_kv_groups
112
+ self.value_dim_per_group = self.value_dim // self.num_kv_groups
113
+ self.clamp_min = clamp_min
114
+ self.layer_idx = layer_idx
115
+
116
+ assert mode in ['chunk', 'fused_recurrent', 'fused_chunk'], f"Not supported mode `{mode}`."
117
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
118
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
119
+
120
+ self.head_k_dim = self.key_dim // num_heads
121
+ self.head_v_dim = self.value_dim // num_heads
122
+
123
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
124
+ self.k_proj = nn.Linear(hidden_size, self.key_dim_per_group, bias=False)
125
+ self.v_proj = nn.Linear(hidden_size, self.value_dim_per_group, bias=False)
126
+ if self.use_output_gate:
127
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
128
+
129
+ if use_short_conv:
130
+ self.conv_size = conv_size
131
+ self.q_conv1d = ShortConvolution(
132
+ hidden_size=self.key_dim,
133
+ kernel_size=conv_size,
134
+ bias=conv_bias,
135
+ activation='silu',
136
+ )
137
+ self.k_conv1d = ShortConvolution(
138
+ hidden_size=self.key_dim_per_group,
139
+ kernel_size=conv_size,
140
+ bias=conv_bias,
141
+ activation='silu',
142
+ )
143
+ self.v_conv1d = ShortConvolution(
144
+ hidden_size=self.value_dim_per_group,
145
+ kernel_size=conv_size,
146
+ bias=conv_bias,
147
+ activation='silu',
148
+ )
149
+
150
+ self.gk_proj = nn.Sequential(nn.Linear(hidden_size, gate_low_rank_dim, bias=False),
151
+ nn.Linear(gate_low_rank_dim, self.key_dim_per_group, bias=True))
152
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
153
+
154
+ if gate_fn == 'swish' and fuse_norm and use_output_gate:
155
+ self.g_norm_swish_gate = FusedRMSNormGated(
156
+ hidden_size=self.head_v_dim,
157
+ elementwise_affine=elementwise_affine,
158
+ eps=norm_eps,
159
+ )
160
+ self.fuse_norm_and_gate = True
161
+ else:
162
+ self.fuse_norm_and_gate = False
163
+ self.g_norm = RMSNorm(
164
+ hidden_size=self.head_v_dim,
165
+ elementwise_affine=elementwise_affine,
166
+ eps=norm_eps,
167
+ dtype=torch.float32
168
+ )
169
+ self.gate_fn = ACT2FN[gate_fn]
170
+
171
+ self.gate_logit_normalizer = gate_logit_normalizer
172
+
173
+ def reset_parameters(self) -> None:
174
+ for module in self.children():
175
+ reset = getattr(module, "reset_parameters", None)
176
+ if callable(reset):
177
+ reset()
178
+
179
+ def forward(
180
+ self,
181
+ hidden_states: torch.Tensor,
182
+ attention_mask: torch.Tensor | None = None,
183
+ past_key_values: Cache | None = None,
184
+ use_cache: bool | None = False,
185
+ output_attentions: bool | None = False,
186
+ **kwargs: Unpack[dict],
187
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
188
+ if attention_mask is not None:
189
+ assert len(attention_mask.shape) == 2, (
190
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
191
+ "for padding purposes (0 indicating padding). "
192
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
193
+ )
194
+
195
+ batch_size, q_len, _ = hidden_states.shape
196
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
197
+
198
+ last_state = get_layer_cache(self, past_key_values)
199
+
200
+ cu_seqlens = kwargs.get('cu_seqlens')
201
+ if attention_mask is not None:
202
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
203
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
204
+
205
+ if self.use_short_conv:
206
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
207
+ if last_state is not None:
208
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
209
+ q, conv_state_q = self.q_conv1d(
210
+ x=self.q_proj(hidden_states),
211
+ cache=conv_state_q,
212
+ output_final_state=use_cache,
213
+ cu_seqlens=cu_seqlens,
214
+ )
215
+ k, conv_state_k = self.k_conv1d(
216
+ x=self.k_proj(hidden_states),
217
+ cache=conv_state_k,
218
+ output_final_state=use_cache,
219
+ cu_seqlens=cu_seqlens,
220
+ )
221
+ v, conv_state_v = self.v_conv1d(
222
+ x=self.v_proj(hidden_states),
223
+ cache=conv_state_v,
224
+ output_final_state=use_cache,
225
+ cu_seqlens=cu_seqlens,
226
+ )
227
+ else:
228
+ q = self.q_proj(hidden_states)
229
+ k = self.k_proj(hidden_states)
230
+ v = self.v_proj(hidden_states)
231
+ gk = self.gk_proj(hidden_states)
232
+
233
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_k_dim)
234
+ if self.num_kv_groups > 1:
235
+ k, gk = (repeat(x, '... (h d) -> ... (h g) d', g=self.num_kv_groups, d=self.head_k_dim) for x in (k, gk))
236
+ v = repeat(v, '... (h d) -> ... (h g) d', g=self.num_kv_groups, d=self.head_v_dim)
237
+ else:
238
+ k, gk = (rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim) for x in (k, gk))
239
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
240
+
241
+ gk = F.logsigmoid(gk) / self.gate_logit_normalizer
242
+ if self.clamp_min is not None:
243
+ gk = torch.clamp_min(gk, self.clamp_min)
244
+
245
+ if self.feature_map_fn is not None:
246
+ q, k = map(self.feature_map_fn, (q, k))
247
+
248
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
249
+ if mode == 'fused_recurrent':
250
+ o, recurrent_state = fused_recurrent_gla(
251
+ q=q,
252
+ k=k,
253
+ v=v,
254
+ gk=gk,
255
+ initial_state=recurrent_state,
256
+ output_final_state=use_cache,
257
+ cu_seqlens=cu_seqlens,
258
+ )
259
+ elif mode == 'fused_chunk':
260
+ o, recurrent_state = fused_chunk_gla(
261
+ q=q,
262
+ k=k,
263
+ v=v,
264
+ g=gk,
265
+ initial_state=recurrent_state,
266
+ output_final_state=use_cache,
267
+ )
268
+ elif mode == 'chunk':
269
+ o, recurrent_state = chunk_gla(
270
+ q=q,
271
+ k=k,
272
+ v=v,
273
+ g=gk,
274
+ initial_state=recurrent_state,
275
+ output_final_state=use_cache,
276
+ cu_seqlens=cu_seqlens,
277
+ )
278
+ else:
279
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
280
+
281
+ update_layer_cache(
282
+ self,
283
+ past_key_values,
284
+ recurrent_state=recurrent_state,
285
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
286
+ offset=q_len,
287
+ )
288
+
289
+ if self.use_output_gate:
290
+ g = self.g_proj(hidden_states)
291
+ if self.fuse_norm_and_gate:
292
+ g = rearrange(g, '... (h d) -> ... h d', d=self.head_v_dim)
293
+ o = self.g_norm_swish_gate(o, g)
294
+ o = rearrange(o, '... h d -> ... (h d)')
295
+ else:
296
+ o = rearrange(self.g_norm(o), '... h d -> ... (h d)')
297
+ o = o * self.gate_fn(g)
298
+ else:
299
+ o = rearrange(self.g_norm(o), '... h d -> ... (h d)')
300
+ o = self.o_proj(o)
301
+ if attention_mask is not None:
302
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
303
+
304
+ return o, None, past_key_values
fla/layers/gsa.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ from einops import rearrange, repeat
12
+
13
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
14
+ from fla.modules import RMSNorm, ShortConvolution
15
+ from fla.modules.feature_map import ReLUFeatureMap, SwishFeatureMap, T2RFeatureMap
16
+ from fla.modules.layernorm import rms_norm_linear
17
+ from fla.ops.gsa import chunk_gsa, fused_recurrent_gsa
18
+
19
+ if TYPE_CHECKING:
20
+ from transformers.processing_utils import Unpack
21
+
22
+ from fla.models.utils import Cache
23
+
24
+
25
+ class GatedSlotAttention(nn.Module):
26
+
27
+ def __init__(
28
+ self,
29
+ mode: str = 'chunk',
30
+ hidden_size: int = 1024,
31
+ expand_k: float = 1.,
32
+ expand_v: float = 1.,
33
+ num_heads: int = 4,
34
+ num_kv_heads: int | None = None,
35
+ use_short_conv: bool = False,
36
+ conv_size: int = 4,
37
+ conv_bias: bool = False,
38
+ num_slots: int | None = None,
39
+ elementwise_affine: bool | None = True,
40
+ norm_eps: float = 1e-5,
41
+ gate_logit_normalizer: int = 8,
42
+ feature_map: str = 'swish',
43
+ use_output_gate: bool = False,
44
+ use_norm: bool = True,
45
+ layer_idx: int | None = None,
46
+ scale: float | None = 1.,
47
+ **kwargs,
48
+ ) -> GatedSlotAttention:
49
+ super().__init__()
50
+
51
+ self.mode = mode
52
+ self.hidden_size = hidden_size
53
+ self.expand_k = expand_k
54
+ self.expand_v = expand_v
55
+ self.num_heads = num_heads
56
+ self.num_kv_heads = num_heads if num_kv_heads is None else num_kv_heads
57
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
58
+ self.key_dim = int(hidden_size * expand_k)
59
+ self.value_dim = int(hidden_size * expand_v)
60
+ self.key_dim_per_group = self.key_dim // self.num_kv_groups
61
+ self.value_dim_per_group = self.value_dim // self.num_kv_groups
62
+ self.head_k_dim = self.key_dim // self.num_heads
63
+ self.head_v_dim = self.value_dim // self.num_heads
64
+
65
+ self.use_short_conv = use_short_conv
66
+ self.conv_size = conv_size
67
+ self.conv_bias = conv_bias
68
+
69
+ self.gate_logit_normalizer = gate_logit_normalizer
70
+
71
+ self.use_output_gate = use_output_gate
72
+ self.use_norm = use_norm
73
+ self.scale = scale
74
+
75
+ if num_slots is None:
76
+ num_slots = self.head_k_dim
77
+ self.num_slots = num_slots
78
+
79
+ self.layer_idx = layer_idx
80
+
81
+ if layer_idx is None:
82
+ warnings.warn(
83
+ f"Instantiating {self.__class__.__name__} without passing `layer_idx` is not recommended and will "
84
+ "to errors during the forward call, if caching is used. Please make sure to provide a `layer_idx` "
85
+ "when creating this class.",
86
+ )
87
+
88
+ self.register_module('feature_map', None)
89
+ if feature_map == 'swish':
90
+ self.feature_map = SwishFeatureMap()
91
+ elif feature_map == 'relu':
92
+ self.feature_map = ReLUFeatureMap()
93
+ elif feature_map == 't2r':
94
+ self.feature_map = T2RFeatureMap(self.head_k_dim, self.head_k_dim)
95
+ else:
96
+ raise NotImplementedError(f"Feature map `{feature_map}` is not supported now.")
97
+
98
+ self.q_proj = nn.Linear(self.hidden_size, self.key_dim, bias=False)
99
+ self.k_proj = nn.Linear(self.hidden_size, self.key_dim_per_group, bias=False)
100
+ self.v_proj = nn.Linear(self.hidden_size, self.value_dim_per_group, bias=False)
101
+ self.f_proj = nn.Linear(self.hidden_size, self.num_kv_heads * self.num_slots, bias=False)
102
+
103
+ if use_short_conv:
104
+ self.conv_size = conv_size
105
+ self.q_conv1d = ShortConvolution(
106
+ hidden_size=self.key_dim,
107
+ kernel_size=conv_size,
108
+ bias=conv_bias,
109
+ activation='silu',
110
+ )
111
+ self.k_conv1d = ShortConvolution(
112
+ hidden_size=self.key_dim_per_group,
113
+ kernel_size=conv_size,
114
+ bias=conv_bias,
115
+ activation='silu',
116
+ )
117
+ self.v_conv1d = ShortConvolution(
118
+ hidden_size=self.value_dim_per_group,
119
+ kernel_size=conv_size,
120
+ bias=conv_bias,
121
+ activation='silu',
122
+ )
123
+
124
+ self.g_norm = RMSNorm(self.hidden_size, elementwise_affine, eps=norm_eps, dtype=torch.float32)
125
+ self.o_proj = nn.Linear(self.value_dim, self.hidden_size, bias=False)
126
+
127
+ def forward(
128
+ self,
129
+ hidden_states: torch.Tensor,
130
+ attention_mask: torch.Tensor | None = None,
131
+ past_key_values: Cache | None = None,
132
+ use_cache: bool | None = False,
133
+ output_attentions: bool | None = False,
134
+ **kwargs: Unpack[dict],
135
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
136
+ if attention_mask is not None:
137
+ assert len(attention_mask.shape) == 2, (
138
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
139
+ "for padding purposes (0 indicating padding). "
140
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
141
+ )
142
+
143
+ batch_size, q_len, _ = hidden_states.shape
144
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
145
+
146
+ last_state = get_layer_cache(self, past_key_values)
147
+
148
+ cu_seqlens = kwargs.get('cu_seqlens')
149
+ if attention_mask is not None:
150
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
151
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
152
+
153
+ if self.use_short_conv:
154
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
155
+ if last_state is not None:
156
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
157
+ q, conv_state_q = self.q_conv1d(
158
+ x=self.q_proj(hidden_states),
159
+ cache=conv_state_q,
160
+ output_final_state=use_cache,
161
+ cu_seqlens=cu_seqlens,
162
+ )
163
+ k, conv_state_k = self.k_conv1d(
164
+ x=self.k_proj(hidden_states),
165
+ cache=conv_state_k,
166
+ output_final_state=use_cache,
167
+ cu_seqlens=cu_seqlens,
168
+ )
169
+ v, conv_state_v = self.v_conv1d(
170
+ x=self.v_proj(hidden_states),
171
+ cache=conv_state_v,
172
+ output_final_state=use_cache,
173
+ cu_seqlens=cu_seqlens,
174
+ )
175
+ else:
176
+ q = self.q_proj(hidden_states)
177
+ k = self.k_proj(hidden_states)
178
+ v = self.v_proj(hidden_states)
179
+ f = self.f_proj(hidden_states)
180
+
181
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_k_dim)
182
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_k_dim)
183
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
184
+ f = rearrange(f, '... (h m) -> ... h m', m=self.num_slots)
185
+
186
+ if self.feature_map is not None:
187
+ q, k = map(lambda x: self.feature_map(x), (q, k))
188
+ v = F.silu(v)
189
+
190
+ f = F.logsigmoid(f) / self.gate_logit_normalizer
191
+ s = (1 - f.exp()).to(f.dtype)
192
+
193
+ if self.num_kv_groups > 1:
194
+ k, v, f, s = map(lambda x: repeat(x, '... h d -> ... (h g) d', g=self.num_kv_groups), (k, v, f, s))
195
+
196
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
197
+ if mode == 'fused_recurrent':
198
+ o, recurrent_state = fused_recurrent_gsa(
199
+ q=q,
200
+ k=k,
201
+ v=v,
202
+ s=s,
203
+ g=f,
204
+ initial_state=recurrent_state,
205
+ output_final_state=use_cache,
206
+ scale=self.scale,
207
+ cu_seqlens=cu_seqlens,
208
+ )
209
+ elif mode == 'chunk':
210
+ o, recurrent_state = chunk_gsa(
211
+ q=q,
212
+ k=k,
213
+ v=v,
214
+ s=s,
215
+ g=f,
216
+ initial_state=recurrent_state,
217
+ output_final_state=use_cache,
218
+ scale=self.scale,
219
+ cu_seqlens=cu_seqlens,
220
+ )
221
+ else:
222
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
223
+
224
+ update_layer_cache(
225
+ self,
226
+ past_key_values,
227
+ recurrent_state=recurrent_state,
228
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
229
+ offset=q_len,
230
+ )
231
+
232
+ o = rearrange(o, '... h d -> ... (h d)')
233
+ o = rms_norm_linear(F.silu(o), self.g_norm.weight, self.g_norm.bias, self.o_proj.weight, self.o_proj.bias)
234
+ if attention_mask is not None:
235
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
236
+
237
+ return o, None, past_key_values
fla/layers/hgrn.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ # "Hierarchically Gated Recurrent Neural Network for Sequence Modeling" [https://arxiv.org/abs/2311.04823]
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+
13
+ from fla.layers.utils import get_layer_cache, update_layer_cache
14
+ from fla.modules import FusedRMSNormGated, ShortConvolution
15
+ from fla.modules.activations import swiglu
16
+ from fla.ops.hgrn import chunk_hgrn, fused_recurrent_hgrn
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ class HGRNAttention(nn.Module):
25
+
26
+ def __init__(
27
+ self,
28
+ mode: str = 'chunk',
29
+ hidden_size: int = 1024,
30
+ expand_ratio: int | None = 1,
31
+ use_short_conv: bool = False,
32
+ conv_size: int = 4,
33
+ conv_bias: bool = False,
34
+ elementwise_affine: bool | None = True,
35
+ norm_eps: float = 1e-5,
36
+ layer_idx: int = None,
37
+ ) -> HGRNAttention:
38
+ super().__init__()
39
+
40
+ self.mode = mode
41
+ self.hidden_size = hidden_size
42
+ self.expand_ratio = expand_ratio
43
+ self.input_dim = int(hidden_size * expand_ratio)
44
+
45
+ self.use_short_conv = use_short_conv
46
+ self.conv_size = conv_size
47
+ self.conv_bias = conv_bias
48
+
49
+ self.layer_idx = layer_idx
50
+
51
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
52
+
53
+ self.i_proj = nn.Linear(hidden_size, self.input_dim, bias=False)
54
+ self.f_proj = nn.Linear(hidden_size, self.input_dim, bias=False)
55
+ self.g_proj = nn.Linear(hidden_size, self.input_dim, bias=False)
56
+
57
+ if use_short_conv:
58
+ self.conv_size = conv_size
59
+ self.f_conv1d = ShortConvolution(
60
+ hidden_size=self.input_dim,
61
+ kernel_size=conv_size,
62
+ bias=conv_bias,
63
+ activation=None,
64
+ )
65
+ self.i_conv1d = ShortConvolution(
66
+ hidden_size=self.input_dim,
67
+ kernel_size=conv_size,
68
+ bias=conv_bias,
69
+ activation=None,
70
+ )
71
+
72
+ self.g_norm = FusedRMSNormGated(
73
+ hidden_size=self.input_dim,
74
+ elementwise_affine=elementwise_affine,
75
+ eps=norm_eps,
76
+ )
77
+ self.o_proj = nn.Linear(self.input_dim, hidden_size, bias=False)
78
+
79
+ def forward(
80
+ self,
81
+ hidden_states: torch.Tensor,
82
+ attention_mask: torch.Tensor | None = None,
83
+ past_key_values: Cache | None = None,
84
+ use_cache: bool | None = False,
85
+ output_attentions: bool | None = False,
86
+ lower_bound: torch.Tensor | None = None,
87
+ **kwargs: Unpack[dict],
88
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
89
+ if attention_mask is not None:
90
+ assert len(attention_mask.shape) == 2, (
91
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
92
+ "for padding purposes (0 indicating padding). "
93
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
94
+ )
95
+
96
+ # launching the triton kernel for just one token will actually be slower
97
+ mode = 'fused_recurrent' if not self.training and hidden_states.shape[1] <= 64 else self.mode
98
+
99
+ last_state = get_layer_cache(self, past_key_values)
100
+
101
+ cu_seqlens = kwargs.get('cu_seqlens')
102
+ if self.use_short_conv:
103
+ conv_state_i, conv_state_f = None, None
104
+ if last_state is not None:
105
+ conv_state_i, conv_state_f = last_state['conv_state']
106
+ conv_mask = attention_mask[:, -hidden_states.shape[1]:] if attention_mask is not None else None
107
+ i, conv_state_i = self.i_conv1d(
108
+ x=self.i_proj(hidden_states),
109
+ mask=conv_mask,
110
+ cache=conv_state_i,
111
+ output_final_state=use_cache,
112
+ cu_seqlens=cu_seqlens,
113
+ )
114
+ f, conv_state_f = self.f_conv1d(
115
+ x=self.f_proj(hidden_states),
116
+ mask=conv_mask,
117
+ cache=conv_state_f,
118
+ output_final_state=use_cache,
119
+ cu_seqlens=cu_seqlens,
120
+ )
121
+ else:
122
+ i = self.i_proj(hidden_states)
123
+ f = self.f_proj(hidden_states)
124
+
125
+ f = F.logsigmoid(f)
126
+ # the lower bound for the first layer is zero
127
+ if lower_bound is not None and self.layer_idx > 0:
128
+ f = torch.logaddexp(lower_bound.log(), torch.log1p(-lower_bound) + f).to(f)
129
+ i = swiglu(i, 1 - f.exp())
130
+
131
+ # dealing with left-padding
132
+ if attention_mask is not None:
133
+ i = i.mul(attention_mask[:, -i.shape[-2]:, None])
134
+
135
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
136
+ if mode == 'chunk':
137
+ if cu_seqlens is not None:
138
+ raise NotImplementedError("Chunk mode does not support variable-length sequences.")
139
+ o, recurrent_state = chunk_hgrn(
140
+ x=i,
141
+ g=f,
142
+ initial_state=recurrent_state,
143
+ output_final_state=use_cache,
144
+ )
145
+ elif mode == 'fused_recurrent':
146
+ o, recurrent_state = fused_recurrent_hgrn(
147
+ x=i,
148
+ g=f,
149
+ initial_state=recurrent_state,
150
+ output_final_state=use_cache,
151
+ cu_seqlens=cu_seqlens,
152
+ )
153
+ else:
154
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
155
+
156
+ update_layer_cache(
157
+ self,
158
+ past_key_values,
159
+ recurrent_state=recurrent_state,
160
+ conv_state=(conv_state_i, conv_state_f) if self.use_short_conv else None,
161
+ offset=i.shape[1],
162
+ )
163
+
164
+ o = self.g_norm(o, self.g_proj(hidden_states))
165
+ o = self.o_proj(o)
166
+
167
+ return o, None, past_key_values
168
+
169
+ def state_size(self, **kwargs) -> int:
170
+ state_size = self.hidden_size
171
+ for module in self.children():
172
+ if isinstance(module, ShortConvolution):
173
+ state_size += module.state_size
174
+ return state_size
fla/layers/hgrn2.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ # "HGRN2: Gated Linear RNNs with State Expansion"[https://arxiv.org/abs/2404.07904]
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from einops import rearrange
13
+
14
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
15
+ from fla.modules import RMSNorm, ShortConvolution
16
+ from fla.modules.activations import swish
17
+ from fla.modules.layernorm import rms_norm_linear
18
+ from fla.ops.gla import chunk_gla, fused_chunk_gla, fused_recurrent_gla
19
+
20
+ if TYPE_CHECKING:
21
+ from transformers.processing_utils import Unpack
22
+
23
+ from fla.models.utils import Cache
24
+
25
+
26
+ class HGRN2Attention(nn.Module):
27
+
28
+ def __init__(
29
+ self,
30
+ mode: str = 'chunk',
31
+ hidden_size: int = 1024,
32
+ num_heads: int | None = None,
33
+ expand_ratio: int | None = 128,
34
+ use_short_conv: bool = False,
35
+ conv_size: int = 4,
36
+ conv_bias: bool = False,
37
+ elementwise_affine: bool | None = True,
38
+ norm_eps: float = 1e-5,
39
+ layer_idx: int = None,
40
+ ) -> HGRN2Attention:
41
+ super().__init__()
42
+
43
+ self.mode = mode
44
+ self.hidden_size = hidden_size
45
+
46
+ if expand_ratio is not None:
47
+ num_heads = hidden_size // expand_ratio
48
+ elif expand_ratio is None and num_heads is not None:
49
+ expand_ratio = hidden_size // num_heads
50
+ elif expand_ratio is None and num_heads is None:
51
+ raise RuntimeError("One of `expand_ratio` or `num_heads` should be provided.")
52
+ self.num_heads = num_heads
53
+ self.expand_ratio = expand_ratio
54
+
55
+ self.use_short_conv = use_short_conv
56
+ self.conv_size = conv_size
57
+ self.conv_bias = conv_bias
58
+
59
+ self.forget_dim = int(self.num_heads * self.expand_ratio)
60
+ self.input_dim = hidden_size
61
+ self.layer_idx = layer_idx
62
+
63
+ assert mode in ['chunk', 'fused_recurrent', 'fused_chunk'], f"Not supported mode `{mode}`."
64
+ assert self.forget_dim % num_heads == 0, f"forget dim must be divisible by num_heads of {num_heads}"
65
+ assert self.input_dim % num_heads == 0, f"input dim must be divisible by num_heads of {num_heads}"
66
+
67
+ self.head_f_dim = self.expand_ratio
68
+ self.head_i_dim = self.hidden_size // num_heads
69
+
70
+ self.q_proj = nn.Linear(hidden_size, self.forget_dim, bias=False)
71
+ self.f_proj = nn.Linear(hidden_size, self.forget_dim, bias=False)
72
+ self.i_proj = nn.Linear(hidden_size, self.input_dim, bias=False)
73
+
74
+ if use_short_conv:
75
+ self.conv_size = conv_size
76
+ self.q_conv1d = ShortConvolution(
77
+ hidden_size=self.forget_dim,
78
+ kernel_size=conv_size,
79
+ bias=conv_bias,
80
+ activation=None,
81
+ )
82
+ self.f_conv1d = ShortConvolution(
83
+ hidden_size=self.forget_dim,
84
+ kernel_size=conv_size,
85
+ bias=conv_bias,
86
+ activation=None,
87
+ )
88
+ self.i_conv1d = ShortConvolution(
89
+ hidden_size=self.input_dim,
90
+ kernel_size=conv_size,
91
+ bias=conv_bias,
92
+ activation=None,
93
+ )
94
+
95
+ self.g_norm = RMSNorm(hidden_size=self.hidden_size, elementwise_affine=elementwise_affine,
96
+ eps=norm_eps, dtype=torch.float32)
97
+ self.o_proj = nn.Linear(self.input_dim, hidden_size, bias=False)
98
+
99
+ def forward(
100
+ self,
101
+ hidden_states: torch.Tensor,
102
+ attention_mask: torch.Tensor | None = None,
103
+ past_key_values: Cache | None = None,
104
+ use_cache: bool | None = False,
105
+ output_attentions: bool | None = False,
106
+ lower_bound: torch.Tensor | None = None,
107
+ **kwargs: Unpack[dict],
108
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
109
+ if attention_mask is not None:
110
+ assert len(attention_mask.shape) == 2, (
111
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
112
+ "for padding purposes (0 indicating padding). "
113
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
114
+ )
115
+
116
+ batch_size, q_len, _ = hidden_states.shape
117
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
118
+
119
+ last_state = get_layer_cache(self, past_key_values)
120
+
121
+ cu_seqlens = kwargs.get('cu_seqlens')
122
+ if attention_mask is not None:
123
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
124
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
125
+
126
+ if self.use_short_conv:
127
+ conv_state_q, conv_state_f, conv_state_i = None, None, None
128
+ if last_state is not None:
129
+ conv_state_q, conv_state_f, conv_state_i = last_state['conv_state']
130
+ q, conv_state_q = self.q_conv1d(
131
+ x=self.q_proj(hidden_states),
132
+ cache=conv_state_q,
133
+ output_final_state=use_cache,
134
+ cu_seqlens=cu_seqlens,
135
+ )
136
+ f, conv_state_f = self.f_conv1d(
137
+ x=self.f_proj(hidden_states),
138
+ cache=conv_state_f,
139
+ output_final_state=use_cache,
140
+ cu_seqlens=cu_seqlens,
141
+ )
142
+ i, conv_state_i = self.i_conv1d(
143
+ x=self.i_proj(hidden_states),
144
+ cache=conv_state_i,
145
+ output_final_state=use_cache,
146
+ cu_seqlens=cu_seqlens,
147
+ )
148
+ else:
149
+ q = self.q_proj(hidden_states)
150
+ f = self.f_proj(hidden_states)
151
+ i = self.i_proj(hidden_states)
152
+
153
+ q = swish(q)
154
+
155
+ g = F.logsigmoid(f)
156
+ # the lower bound for the first layer is zero
157
+ if lower_bound is not None and self.layer_idx > 0:
158
+ g = torch.logaddexp(lower_bound.log(), torch.log1p(-lower_bound) + g)
159
+ k = 1 - g.exp()
160
+
161
+ q, k, g = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_f_dim), (q, k.to(i), g))
162
+ i = rearrange(i, '... (h d) -> ... h d', d=self.head_i_dim)
163
+
164
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
165
+ if mode == 'fused_recurrent':
166
+ o, recurrent_state = fused_recurrent_gla(
167
+ q=q,
168
+ k=k,
169
+ v=i,
170
+ gk=g,
171
+ initial_state=recurrent_state,
172
+ output_final_state=use_cache,
173
+ cu_seqlens=cu_seqlens,
174
+ )
175
+ elif mode == 'fused_chunk':
176
+ o, recurrent_state = fused_chunk_gla(
177
+ q=q,
178
+ k=k,
179
+ v=i,
180
+ g=g,
181
+ initial_state=recurrent_state,
182
+ output_final_state=use_cache,
183
+ )
184
+ elif mode == 'chunk':
185
+ o, recurrent_state = chunk_gla(
186
+ q=q,
187
+ k=k,
188
+ v=i,
189
+ g=g,
190
+ initial_state=recurrent_state,
191
+ output_final_state=use_cache,
192
+ cu_seqlens=cu_seqlens,
193
+ )
194
+ else:
195
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
196
+
197
+ update_layer_cache(
198
+ self,
199
+ past_key_values,
200
+ recurrent_state=recurrent_state,
201
+ conv_state=(conv_state_q, conv_state_f, conv_state_i) if self.use_short_conv else None,
202
+ offset=q_len,
203
+ )
204
+
205
+ o = rearrange(o, '... h d -> ... (h d)')
206
+ o = rms_norm_linear(o, self.g_norm.weight, self.g_norm.bias, self.o_proj.weight, self.o_proj.bias)
207
+ if attention_mask is not None:
208
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
209
+
210
+ return o, None, past_key_values
fla/layers/kda.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange, repeat
11
+ from torch.nn import functional as F
12
+
13
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
14
+ from fla.modules import FusedRMSNormGated, ShortConvolution
15
+ from fla.ops.kda import chunk_kda, fused_recurrent_kda
16
+ from fla.ops.kda.gate import fused_kda_gate
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ class KimiDeltaAttention(nn.Module):
25
+ """
26
+ Kimi Delta Attention (KDA) layer implementation.
27
+
28
+ Args:
29
+ hidden_size (int, Optional):
30
+ The hidden size of the input. Default: 2048.
31
+ expand_v (float, Optional):
32
+ The expansion ratio for the value dimension. Default: 1.0.
33
+ head_dim (int, Optional):
34
+ The dimension of each head. Default: 128.
35
+ num_heads (int, Optional):
36
+ The number of heads. Default: 16.
37
+ num_v_heads (int, Optional):
38
+ The number of heads for the value projection, equal to `num_heads` if `None`.
39
+ GVA (Grouped Value Attention) is applied if `num_v_heads` > `num_heads`. Default: `None`.
40
+ mode (str, Optional):
41
+ Which Kimi Delta Attention kernel to use.
42
+ Currently available: `chunk` and `fused_recurrent`.
43
+ Default: `chunk`.
44
+ use_short_conv (bool, Optional):
45
+ Whether to use short convolutions. Default: `True`.
46
+ allow_neg_eigval (bool, Optional):
47
+ Allow negative eigenvalues. Default: `False`. If set to `True`, the beta will be multiplied by 2.
48
+ See reference:
49
+ [Unlocking State-Tracking in Linear RNNs Through Negative Eigenvalues](https://arxiv.org/abs/2411.12537)
50
+ conv_size (int, Optional):
51
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
52
+ conv_bias (bool, Optional):
53
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
54
+ layer_idx (int, Optional):
55
+ The index of the layer. Default: None.
56
+ norm_eps (float, Optional):
57
+ The epsilon value for the normalization layer. Default: 1e-5.
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ hidden_size: int = 2048,
63
+ expand_v: float = 1,
64
+ head_dim: int = 128,
65
+ num_heads: int = 16,
66
+ num_v_heads: int = None,
67
+ mode: str = "chunk",
68
+ use_short_conv: bool = True,
69
+ allow_neg_eigval: bool = False,
70
+ conv_size: int = 4,
71
+ conv_bias: bool = False,
72
+ layer_idx: int = None,
73
+ norm_eps: float = 1e-5,
74
+ **kwargs,
75
+ ) -> KimiDeltaAttention:
76
+ super().__init__()
77
+
78
+ self.mode = mode
79
+ self.allow_neg_eigval = allow_neg_eigval
80
+ self.hidden_size = hidden_size
81
+ self.expand_v = expand_v
82
+
83
+ self.use_short_conv = use_short_conv
84
+ self.conv_size = conv_size
85
+ self.conv_bias = conv_bias
86
+
87
+ self.head_dim = head_dim
88
+ self.num_heads = num_heads
89
+ self.num_v_heads = num_v_heads if num_v_heads is not None else num_heads
90
+
91
+ self.head_k_dim = head_dim
92
+ self.head_v_dim = int(self.head_dim * self.expand_v)
93
+ self.key_dim = int(self.num_heads * self.head_k_dim)
94
+ self.value_dim = int(self.num_v_heads * self.head_v_dim)
95
+ self.layer_idx = layer_idx
96
+
97
+ # Consistency check: Ensure expand_v produces integer values
98
+ if not math.isclose(self.num_v_heads * self.head_dim * expand_v, self.value_dim, rel_tol=1e-5):
99
+ raise ValueError(
100
+ f"expand_v={expand_v} does not produce an integer value when multiplied by key_dim={self.key_dim}. "
101
+ f"Resulting value_dim would be {self.num_v_heads * self.head_dim * expand_v}, which is invalid for nn.Linear.",
102
+ )
103
+ if self.num_v_heads > self.num_heads and self.num_v_heads % self.num_heads != 0:
104
+ raise ValueError(
105
+ f"num_v_heads={self.num_v_heads} must be divisible by num_heads={self.num_heads}.",
106
+ )
107
+
108
+ if not math.isclose(head_dim * expand_v, self.head_v_dim, rel_tol=1e-5):
109
+ raise ValueError(
110
+ f"expand_v={expand_v} does not produce an integer value when multiplied by head_dim={head_dim}. "
111
+ f"Resulting head_v_dim would be {head_dim * expand_v}, which is invalid for FusedRMSNormGated.",
112
+ )
113
+ assert mode in ["chunk", "fused_recurrent"], f"Not supported mode `{mode}`."
114
+
115
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
116
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
117
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
118
+
119
+ if use_short_conv:
120
+ self.q_conv1d = ShortConvolution(
121
+ hidden_size=self.key_dim,
122
+ kernel_size=conv_size,
123
+ bias=conv_bias,
124
+ activation="silu",
125
+ )
126
+ self.k_conv1d = ShortConvolution(
127
+ hidden_size=self.key_dim,
128
+ kernel_size=conv_size,
129
+ bias=conv_bias,
130
+ activation="silu",
131
+ )
132
+ self.v_conv1d = ShortConvolution(
133
+ hidden_size=self.value_dim,
134
+ kernel_size=conv_size,
135
+ bias=conv_bias,
136
+ activation="silu",
137
+ )
138
+
139
+ self.f_proj = nn.Sequential(
140
+ nn.Linear(hidden_size, self.head_v_dim, bias=False),
141
+ nn.Linear(self.head_v_dim, self.key_dim, bias=False),
142
+ )
143
+ self.b_proj = nn.Linear(hidden_size, self.num_heads, bias=False)
144
+
145
+ self.A_log = nn.Parameter(torch.log(torch.empty(self.num_heads, dtype=torch.float32).uniform_(1, 16)))
146
+ self.A_log._no_weight_decay = True
147
+ dt = torch.exp(
148
+ torch.rand(self.key_dim, dtype=torch.float32) * (math.log(0.1) - math.log(0.001)) + math.log(0.001)
149
+ ).clamp(min=1e-4)
150
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
151
+ self.dt_bias = nn.Parameter(inv_dt)
152
+ self.dt_bias._no_weight_decay = True
153
+
154
+ self.g_proj = nn.Sequential(
155
+ nn.Linear(hidden_size, self.head_v_dim, bias=False),
156
+ nn.Linear(self.head_v_dim, self.value_dim, bias=True),
157
+ )
158
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, activation="sigmoid", eps=norm_eps)
159
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
160
+
161
+ def forward(
162
+ self,
163
+ hidden_states: torch.Tensor,
164
+ attention_mask: torch.Tensor | None = None,
165
+ past_key_values: Cache | None = None,
166
+ use_cache: bool | None = False,
167
+ output_attentions: bool | None = False,
168
+ **kwargs: Unpack[dict],
169
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
170
+ if attention_mask is not None:
171
+ assert len(attention_mask.shape) == 2, (
172
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
173
+ "for padding purposes (0 indicating padding). "
174
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
175
+ )
176
+
177
+ batch_size, q_len, _ = hidden_states.shape
178
+ # change to inference mode.
179
+ mode = "fused_recurrent" if (q_len <= 64 and not self.training) else self.mode
180
+ if self.training:
181
+ assert mode == "chunk", "Only chunk mode is supported in training."
182
+
183
+ last_state = get_layer_cache(self, past_key_values)
184
+
185
+ cu_seqlens = kwargs.get("cu_seqlens")
186
+ if attention_mask is not None:
187
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
188
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
189
+
190
+ if self.use_short_conv:
191
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
192
+ if last_state is not None:
193
+ conv_state_q, conv_state_k, conv_state_v = last_state["conv_state"]
194
+ q, conv_state_q = self.q_conv1d(
195
+ x=self.q_proj(hidden_states),
196
+ cache=conv_state_q,
197
+ output_final_state=use_cache,
198
+ cu_seqlens=cu_seqlens,
199
+ )
200
+ k, conv_state_k = self.k_conv1d(
201
+ x=self.k_proj(hidden_states),
202
+ cache=conv_state_k,
203
+ output_final_state=use_cache,
204
+ cu_seqlens=cu_seqlens,
205
+ )
206
+ v, conv_state_v = self.v_conv1d(
207
+ x=self.v_proj(hidden_states),
208
+ cache=conv_state_v,
209
+ output_final_state=use_cache,
210
+ cu_seqlens=cu_seqlens,
211
+ )
212
+ else:
213
+ q = F.silu(self.q_proj(hidden_states))
214
+ k = F.silu(self.k_proj(hidden_states))
215
+ v = F.silu(self.v_proj(hidden_states))
216
+
217
+ g = self.f_proj(hidden_states)
218
+ beta = self.b_proj(hidden_states).sigmoid()
219
+
220
+ q, k, g = (rearrange(x, "... (h d) -> ... h d", d=self.head_k_dim) for x in (q, k, g))
221
+ v = rearrange(v, "... (h d) -> ... h d", d=self.head_v_dim)
222
+
223
+ # for multi-value attention, we repeat the inputs for simplicity.
224
+ if self.num_v_heads > self.num_heads:
225
+ q, k, g = (repeat(x, "... h d -> ... (h g) d", g=self.num_v_heads // self.num_heads) for x in (q, k, g))
226
+ beta = repeat(beta, "... h -> ... (h g)", g=self.num_v_heads // self.num_heads)
227
+
228
+ if self.allow_neg_eigval:
229
+ beta = beta * 2.0
230
+
231
+ recurrent_state = last_state["recurrent_state"] if last_state is not None else None
232
+ if mode == "chunk":
233
+ o, recurrent_state = chunk_kda(
234
+ q=q,
235
+ k=k,
236
+ v=v,
237
+ g=g,
238
+ beta=beta,
239
+ A_log=self.A_log,
240
+ dt_bias=self.dt_bias,
241
+ initial_state=recurrent_state,
242
+ output_final_state=use_cache,
243
+ use_qk_l2norm_in_kernel=True,
244
+ use_gate_in_kernel=True,
245
+ cu_seqlens=cu_seqlens,
246
+ )
247
+ elif mode == "fused_recurrent":
248
+ g = fused_kda_gate(g=g, A_log=self.A_log, dt_bias=self.dt_bias)
249
+ o, recurrent_state = fused_recurrent_kda(
250
+ q=q,
251
+ k=k,
252
+ v=v,
253
+ g=g,
254
+ beta=beta,
255
+ initial_state=recurrent_state,
256
+ output_final_state=use_cache,
257
+ use_qk_l2norm_in_kernel=True,
258
+ cu_seqlens=cu_seqlens,
259
+ )
260
+ else:
261
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
262
+
263
+ update_layer_cache(
264
+ self,
265
+ past_key_values,
266
+ recurrent_state=recurrent_state,
267
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
268
+ offset=q_len,
269
+ )
270
+
271
+ o = self.o_norm(o, rearrange(self.g_proj(hidden_states), "... (h d) -> ... h d", d=self.head_v_dim))
272
+ o = rearrange(o, "b t h d -> b t (h d)")
273
+ o = self.o_proj(o)
274
+ if attention_mask is not None:
275
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
276
+
277
+ return o, None, past_key_values
fla/layers/lightnet.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ # ["You Only Scan Once: Efficient Multi-dimension Sequential Modeling with LightNet"](https://arxiv.org/abs/2405.21022)
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from einops import rearrange
13
+
14
+ from fla.layers.utils import get_layer_cache, update_layer_cache
15
+ from fla.modules import FusedRMSNormGated, ShortConvolution
16
+ from fla.modules.fused_norm_gate import rms_norm_swish_gate_linear
17
+ from fla.ops.gla import chunk_gla, fused_recurrent_gla
18
+
19
+ if TYPE_CHECKING:
20
+ from transformers.processing_utils import Unpack
21
+
22
+ from fla.models.utils import Cache
23
+
24
+
25
+ class LightNetAttention(nn.Module):
26
+
27
+ def __init__(
28
+ self,
29
+ mode: str = 'chunk',
30
+ hidden_size: int = 1024,
31
+ num_heads: int | None = None,
32
+ expand_ratio: int | None = 128,
33
+ use_short_conv: bool = False,
34
+ conv_size: int = 4,
35
+ conv_bias: bool = False,
36
+ gate_low_rank_dim: int = 128,
37
+ elementwise_affine: bool | None = True,
38
+ norm_eps: float = 1e-5,
39
+ layer_idx: int = None,
40
+ ) -> LightNetAttention:
41
+ super().__init__()
42
+
43
+ self.mode = mode
44
+ self.hidden_size = hidden_size
45
+
46
+ if expand_ratio is None and num_heads is not None:
47
+ expand_ratio = hidden_size // num_heads
48
+ elif expand_ratio is not None and num_heads is None:
49
+ num_heads = hidden_size // expand_ratio
50
+ elif expand_ratio is None and num_heads is None:
51
+ raise RuntimeError("One of `expand_ratio` or `num_heads` should be provided.")
52
+ self.num_heads = num_heads
53
+ self.expand_ratio = expand_ratio
54
+
55
+ self.use_short_conv = use_short_conv
56
+ self.conv_size = conv_size
57
+ self.conv_bias = conv_bias
58
+
59
+ self.key_dim = int(self.num_heads * self.expand_ratio)
60
+ self.value_dim = hidden_size
61
+ self.gate_low_rank_dim = gate_low_rank_dim
62
+ self.layer_idx = layer_idx
63
+
64
+ assert mode in ['chunk', 'fused_chunk'], f"Not supported mode `{mode}`."
65
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
66
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
67
+
68
+ self.head_f_dim = self.expand_ratio
69
+ self.head_i_dim = self.hidden_size // num_heads
70
+
71
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
72
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
73
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
74
+
75
+ if use_short_conv:
76
+ self.conv_size = conv_size
77
+ self.q_conv1d = ShortConvolution(
78
+ hidden_size=self.key_dim,
79
+ kernel_size=conv_size,
80
+ bias=conv_bias,
81
+ activation=None,
82
+ )
83
+ self.k_conv1d = ShortConvolution(
84
+ hidden_size=self.key_dim,
85
+ kernel_size=conv_size,
86
+ bias=conv_bias,
87
+ activation=None,
88
+ )
89
+ self.v_conv1d = ShortConvolution(
90
+ hidden_size=self.value_dim,
91
+ kernel_size=conv_size,
92
+ bias=conv_bias,
93
+ activation=None,
94
+ )
95
+
96
+ self.g_proj = nn.Sequential(
97
+ nn.Linear(hidden_size, gate_low_rank_dim, bias=False),
98
+ nn.Linear(gate_low_rank_dim, hidden_size, bias=False),
99
+ )
100
+ self.g_norm = FusedRMSNormGated(
101
+ hidden_size=hidden_size,
102
+ elementwise_affine=elementwise_affine,
103
+ eps=norm_eps,
104
+ )
105
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
106
+
107
+ def forward(
108
+ self,
109
+ hidden_states: torch.Tensor,
110
+ attention_mask: torch.Tensor | None = None,
111
+ past_key_values: Cache | None = None,
112
+ use_cache: bool | None = False,
113
+ output_attentions: bool | None = False,
114
+ **kwargs: Unpack[dict],
115
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
116
+ if attention_mask is not None:
117
+ assert len(attention_mask.shape) == 2, (
118
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
119
+ "for padding purposes (0 indicating padding). "
120
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
121
+ )
122
+
123
+ # launching the triton kernel for just one token will actually be slower
124
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
125
+
126
+ last_state = get_layer_cache(self, past_key_values)
127
+
128
+ cu_seqlens = kwargs.get('cu_seqlens')
129
+ if self.use_short_conv:
130
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
131
+ if last_state is not None:
132
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
133
+ conv_mask = attention_mask[:, -hidden_states.shape[1]:] if attention_mask is not None else None
134
+ q, conv_state_q = self.q_conv1d(
135
+ x=self.q_proj(hidden_states),
136
+ mask=conv_mask,
137
+ cache=conv_state_q,
138
+ output_final_state=use_cache,
139
+ cu_seqlens=cu_seqlens,
140
+ )
141
+ k, conv_state_k = self.k_conv1d(
142
+ x=self.k_proj(hidden_states),
143
+ mask=conv_mask,
144
+ cache=conv_state_k,
145
+ output_final_state=use_cache,
146
+ cu_seqlens=cu_seqlens,
147
+ )
148
+ v, conv_state_v = self.v_conv1d(
149
+ x=self.v_proj(hidden_states),
150
+ mask=conv_mask,
151
+ cache=conv_state_v,
152
+ output_final_state=use_cache,
153
+ cu_seqlens=cu_seqlens,
154
+ )
155
+ else:
156
+ q = self.q_proj(hidden_states)
157
+ k = self.k_proj(hidden_states)
158
+ v = self.v_proj(hidden_states)
159
+
160
+ # dealing with left-padding
161
+ if attention_mask is not None:
162
+ v = v.mul(attention_mask[:, -v.shape[-2]:, None])
163
+
164
+ q = F.silu(q)
165
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_f_dim), (q, k))
166
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_i_dim)
167
+ # TODO: this 2 steps took huge amount of time, which should be optimized
168
+ last_z = last_state['ffn_state'] if last_state is not None and last_state.get('ffn_state') is not None else None
169
+ if last_z is not None:
170
+ # Decode path: continue logcumsumexp from cached state
171
+ z = torch.logaddexp(last_z, k.float())
172
+ k, g = torch.exp(k - z).to(k.dtype), (last_z - z).to(k.dtype)
173
+ else:
174
+ # Prefill path: mask padding positions to -inf so they don't affect logcumsumexp
175
+ if cu_seqlens is not None:
176
+ raise NotImplementedError("LightNet does not support variable-length sequences for now.")
177
+ k_float = k.float()
178
+ if attention_mask is not None:
179
+ pad_mask = attention_mask[:, -k.shape[1]:, None, None] # (B, T, 1, 1)
180
+ k_for_z = k_float.masked_fill(pad_mask == 0, float('-inf'))
181
+ else:
182
+ k_for_z = k_float
183
+ z = k_for_z.logcumsumexp(1)
184
+ k_new = torch.exp(k_float - z)
185
+ g_new = torch.cat((z[:, :1], z[:, :-1]), 1) - z
186
+ # NaN/inf arise at fully-masked positions (-inf - (-inf)), zero them out
187
+ k = torch.nan_to_num(k_new, nan=0.0, posinf=0.0).to(k.dtype)
188
+ g = torch.nan_to_num(g_new, nan=0.0, posinf=0.0, neginf=0.0).to(k.dtype)
189
+
190
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
191
+ if mode == 'fused_recurrent':
192
+ o, recurrent_state = fused_recurrent_gla(
193
+ q=q,
194
+ k=k,
195
+ v=v,
196
+ gk=g,
197
+ initial_state=recurrent_state,
198
+ output_final_state=use_cache,
199
+ cu_seqlens=cu_seqlens,
200
+ )
201
+ elif mode == 'chunk':
202
+ o, recurrent_state = chunk_gla(
203
+ q=q,
204
+ k=k,
205
+ v=v,
206
+ g=g,
207
+ initial_state=recurrent_state,
208
+ output_final_state=use_cache,
209
+ cu_seqlens=cu_seqlens,
210
+ )
211
+ else:
212
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
213
+
214
+ update_layer_cache(
215
+ self,
216
+ past_key_values,
217
+ recurrent_state=recurrent_state,
218
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
219
+ ffn_state=z[:, -1:],
220
+ offset=q.shape[1],
221
+ )
222
+
223
+ o = rms_norm_swish_gate_linear(
224
+ rearrange(o, 'b t h d -> b t (h d)'),
225
+ self.g_proj(hidden_states),
226
+ self.g_norm.weight,
227
+ self.g_norm.bias,
228
+ self.o_proj.weight,
229
+ self.o_proj.bias,
230
+ )
231
+ return o, None, past_key_values
232
+
233
+ def state_size(self, **kwargs) -> int:
234
+ state_size = self.key_dim * self.head_i_dim
235
+ for module in self.children():
236
+ if isinstance(module, ShortConvolution):
237
+ state_size += module.state_size
238
+ return state_size
fla/layers/linear_attn.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ from einops import rearrange, repeat
11
+
12
+ from fla.layers.utils import get_layer_cache, update_layer_cache
13
+ from fla.modules import RMSNorm
14
+ from fla.modules.feature_map import DPFPFeatureMap, HadamardFeatureMap, HedgehogFeatureMap, T2RFeatureMap
15
+ from fla.ops.linear_attn import chunk_linear_attn, fused_chunk_linear_attn, fused_recurrent_linear_attn
16
+
17
+ if TYPE_CHECKING:
18
+ from fla.models.utils import Cache
19
+
20
+
21
+ class LinearAttention(nn.Module):
22
+
23
+ def __init__(
24
+ self,
25
+ mode: str = 'chunk',
26
+ hidden_size: str = 1024,
27
+ expand_k: float = 1.0,
28
+ expand_v: float = 1.0,
29
+ num_heads: int = 8,
30
+ num_kv_heads: int | None = None,
31
+ feature_map: str = 'elementwise_product',
32
+ tie_feature_map_qk: bool = False,
33
+ output_norm: str = 'rmsnorm',
34
+ norm_q: bool = False,
35
+ norm_k: bool = False,
36
+ do_feature_map_norm: bool = False,
37
+ elementwise_affine: bool = True,
38
+ norm_eps: float = 1e-5,
39
+ layer_idx: int | None = None,
40
+ **kwargs,
41
+ ):
42
+ super().__init__()
43
+
44
+ self.hidden_size = hidden_size
45
+ self.mode = mode
46
+ self.num_heads = num_heads
47
+ self.num_kv_heads = num_kv_heads if num_kv_heads is not None else num_heads
48
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
49
+ self.key_dim = int(hidden_size * expand_k)
50
+ self.value_dim = int(hidden_size * expand_v)
51
+ self.key_dim_per_group = self.key_dim // self.num_kv_groups
52
+ self.value_dim_per_group = self.value_dim // self.num_kv_groups
53
+
54
+ assert mode in ['chunk', 'fused_chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
55
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
56
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
57
+
58
+ self.head_k_dim = self.key_dim // num_heads
59
+ self.head_v_dim = self.value_dim // num_heads
60
+ self.do_feature_map_norm = do_feature_map_norm
61
+ self.layer_idx = layer_idx
62
+
63
+ if feature_map == 'hedgehog':
64
+ if tie_feature_map_qk:
65
+ self.feature_map_q = self.feature_map_k = HedgehogFeatureMap(head_dim=self.head_k_dim)
66
+ else:
67
+ self.feature_map_q = HedgehogFeatureMap(head_dim=self.head_k_dim)
68
+ self.feature_map_k = HedgehogFeatureMap(head_dim=self.head_k_dim)
69
+
70
+ elif feature_map == 't2r':
71
+ if tie_feature_map_qk:
72
+ self.feature_map_q = self.feature_map_k = T2RFeatureMap(head_dim=self.head_k_dim)
73
+ else:
74
+ self.feature_map_q = T2RFeatureMap(head_dim=self.head_k_dim)
75
+ self.feature_map_k = T2RFeatureMap(head_dim=self.head_k_dim)
76
+
77
+ elif feature_map == 'elementwise_product':
78
+ if tie_feature_map_qk:
79
+ self.feature_map_q = self.feature_map_k = HadamardFeatureMap(head_dim=self.head_k_dim)
80
+ else:
81
+ self.feature_map_q = HadamardFeatureMap(head_dim=self.head_k_dim)
82
+ self.feature_map_k = HadamardFeatureMap(head_dim=self.head_k_dim)
83
+
84
+ elif feature_map == 'dpfp':
85
+ self.feature_map_q = DPFPFeatureMap(head_dim=self.head_k_dim)
86
+ self.feature_map_k = DPFPFeatureMap(head_dim=self.head_k_dim)
87
+
88
+ elif feature_map == 'elu':
89
+ def elu(x):
90
+ return F.elu(x) + 1
91
+ self.feature_map_q = elu
92
+ self.feature_map_k = elu
93
+
94
+ elif feature_map == 'relu':
95
+ self.feature_map_q = nn.ReLU()
96
+ self.feature_map_k = nn.ReLU()
97
+
98
+ elif feature_map == 'identity':
99
+ self.feature_map_q = nn.Identity()
100
+ self.feature_map_k = nn.Identity()
101
+ else:
102
+ raise NotImplementedError(f"Not supported feature map `{feature_map}`.")
103
+
104
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
105
+ self.k_proj = nn.Linear(hidden_size, self.key_dim_per_group, bias=False)
106
+ self.v_proj = nn.Linear(hidden_size, self.value_dim_per_group, bias=False)
107
+
108
+ if output_norm == 'rmsnorm':
109
+ self.norm = RMSNorm(hidden_size=self.head_v_dim, elementwise_affine=elementwise_affine,
110
+ eps=norm_eps, dtype=torch.float32)
111
+ elif output_norm == 'identity':
112
+ self.norm = nn.Identity()
113
+ else:
114
+ raise NotImplementedError(f"Not supported output norm `{output_norm}`.")
115
+
116
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
117
+
118
+ self.norm_q = norm_q
119
+ self.norm_k = norm_k
120
+
121
+ def forward(
122
+ self,
123
+ hidden_states: torch.Tensor,
124
+ attention_mask: torch.Tensor | None = None,
125
+ past_key_values: Cache | None = None,
126
+ use_cache: bool | None = False,
127
+ output_attentions: bool | None = False,
128
+ **kwargs,
129
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
130
+ # Match other recurrent layers: use the recurrent kernel for decode/small chunks.
131
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
132
+ last_state = get_layer_cache(self, past_key_values)
133
+
134
+ q = self.q_proj(hidden_states)
135
+ k = self.k_proj(hidden_states)
136
+ v = self.v_proj(hidden_states)
137
+
138
+ if attention_mask is not None:
139
+ v = v.mul(attention_mask[:, -v.shape[-2]:, None])
140
+
141
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_k_dim)
142
+ if self.num_kv_groups > 1:
143
+ k = repeat(k, '... (h d) -> ... (h g) d', d=self.head_k_dim, g=self.num_kv_groups)
144
+ v = repeat(v, '... (h d) -> ... (h g) d', d=self.head_v_dim, g=self.num_kv_groups)
145
+ else:
146
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_k_dim)
147
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
148
+
149
+ q = self.feature_map_q(q)
150
+ k = self.feature_map_k(k)
151
+
152
+ if self.norm_q:
153
+ q = q / (q.sum(-1, True) + 1e-4)
154
+ if self.norm_k:
155
+ k = k / (k.sum(-1, True) + 1e-4)
156
+
157
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
158
+ if mode == 'chunk':
159
+ o, final_state = chunk_linear_attn(
160
+ q=q,
161
+ k=k,
162
+ v=v,
163
+ initial_state=recurrent_state,
164
+ output_final_state=use_cache,
165
+ normalize=self.do_feature_map_norm,
166
+ )
167
+ elif mode == 'fused_chunk':
168
+ o, final_state = fused_chunk_linear_attn(
169
+ q=q,
170
+ k=k,
171
+ v=v,
172
+ initial_state=recurrent_state,
173
+ output_final_state=use_cache,
174
+ normalize=self.do_feature_map_norm,
175
+ )
176
+ elif mode == 'fused_recurrent':
177
+ o, final_state = fused_recurrent_linear_attn(
178
+ q=q,
179
+ k=k,
180
+ v=v,
181
+ initial_state=recurrent_state,
182
+ output_final_state=use_cache,
183
+ normalize=self.do_feature_map_norm,
184
+ )
185
+ else:
186
+ raise NotImplementedError
187
+ update_layer_cache(
188
+ self,
189
+ past_key_values,
190
+ recurrent_state=final_state,
191
+ offset=q.shape[1],
192
+ )
193
+ o = self.norm(o)
194
+ o = rearrange(o, '... h d -> ... (h d)')
195
+ o = self.o_proj(o)
196
+ return o, None, past_key_values
fla/layers/log_linear_mamba2.py ADDED
@@ -0,0 +1,684 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from typing import TYPE_CHECKING
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ from einops import rearrange
9
+ from transformers.activations import ACT2FN
10
+ from transformers.utils import logging
11
+
12
+ from fla.layers.mamba2 import apply_mask_to_padding_states, causal_conv1d_fn, causal_conv1d_update, is_fast_path_available
13
+ from fla.layers.utils import get_layer_cache, update_layer_cache
14
+ from fla.modules.layernorm_gated import RMSNormGated, rmsnorm_fn
15
+ from fla.ops.log_linear_attn.chunk import LogLinearAttentionState, chunk_log_linear_attn
16
+
17
+ if TYPE_CHECKING:
18
+ from fla.models.utils import Cache
19
+
20
+ logger = logging.get_logger(__name__)
21
+
22
+
23
+ def ceil_log(x: int, b: int) -> int:
24
+ return math.ceil(math.log(x, b))
25
+
26
+
27
+ def get_num_levels(length: int, base: int) -> int:
28
+ return ceil_log(length, base) + 1
29
+
30
+
31
+ MAX_SEQUENCE_LENGTH = 2048 * 8
32
+ LAMBDA_LEVEL_BASE = 2
33
+ MAX_NUM_LEVELS = get_num_levels(length=MAX_SEQUENCE_LENGTH, base=LAMBDA_LEVEL_BASE)
34
+
35
+
36
+ def hmamba_chunk_scan_combined(
37
+ x: torch.Tensor,
38
+ dt: torch.Tensor,
39
+ A: torch.Tensor,
40
+ B: torch.Tensor,
41
+ C: torch.Tensor,
42
+ dl: torch.Tensor,
43
+ L: torch.Tensor,
44
+ chunk_size: int,
45
+ D: torch.Tensor | None = None,
46
+ z: torch.Tensor | None = None,
47
+ dt_bias: torch.Tensor | None = None,
48
+ initial_states: LogLinearAttentionState | None = None,
49
+ seq_idx: torch.Tensor | None = None,
50
+ cu_seqlens: torch.Tensor | None = None,
51
+ dt_softplus: bool = False,
52
+ dt_limit: tuple[float, float] = (0.0, float("inf")),
53
+ return_final_states: bool = False,
54
+ ):
55
+ if z is not None:
56
+ raise NotImplementedError
57
+ if seq_idx is not None:
58
+ raise NotImplementedError
59
+ if cu_seqlens is not None:
60
+ raise NotImplementedError
61
+ if dt_softplus is not True:
62
+ raise NotImplementedError
63
+ if tuple(dt_limit) != (0.0, float("inf")):
64
+ raise NotImplementedError
65
+ if chunk_size != 64:
66
+ raise NotImplementedError
67
+ if not B.shape == C.shape:
68
+ raise ValueError("B and C must have the same shape")
69
+
70
+ if D is not None:
71
+ if D.dim() != 1:
72
+ raise ValueError
73
+ D = rearrange(D, "h -> 1 1 h 1")
74
+ D_residual = x * D
75
+
76
+ if dt_bias is not None:
77
+ dt = dt + rearrange(dt_bias, "h -> 1 1 h")
78
+ if dt_softplus:
79
+ dt = torch.nn.functional.softplus(dt)
80
+ if dt_limit != (0.0, float("inf")):
81
+ dt = torch.clamp(dt, min=dt_limit[0], max=dt_limit[1])
82
+ x = (x * rearrange(dt, "b l h -> b l h 1")).to(x.dtype)
83
+ A = rearrange(A, "h -> 1 1 h") * dt
84
+
85
+ L = torch.nn.functional.softplus(rearrange(L, "h ell -> 1 1 h ell") * dl).to(L.dtype)
86
+
87
+ y, state = chunk_log_linear_attn(
88
+ q=C,
89
+ k=B,
90
+ v=x,
91
+ g=A,
92
+ level_scales=L,
93
+ initial_state=initial_states,
94
+ output_final_state=return_final_states,
95
+ cu_seqlens=cu_seqlens,
96
+ )
97
+
98
+ if D is not None:
99
+ y = y + D_residual
100
+
101
+ return y, state
102
+
103
+
104
+ def hmamba_split_conv1d_scan_combined(
105
+ zxbcdtdl: torch.Tensor,
106
+ conv1d_weight: torch.Tensor,
107
+ conv1d_bias: torch.Tensor,
108
+ dt_bias: torch.Tensor,
109
+ A: torch.Tensor,
110
+ L: torch.Tensor,
111
+ D: torch.Tensor,
112
+ chunk_size: int,
113
+ initial_states: torch.Tensor | None = None,
114
+ seq_idx: torch.Tensor | None = None,
115
+ dt_limit: tuple[float, float] = (0.0, float("inf")),
116
+ return_final_states: bool = False,
117
+ activation: str = "silu",
118
+ rmsnorm_weight: torch.Tensor | None = None,
119
+ rmsnorm_eps: float = 1e-6,
120
+ outproj_weight: torch.Tensor | None = None,
121
+ outproj_bias: torch.Tensor | None = None,
122
+ headdim: int | None = None,
123
+ ngroups: int = 1,
124
+ norm_before_gate: bool = True,
125
+ conv1d_fn=None,
126
+ conv_backend: str = "cuda",
127
+ ) -> torch.Tensor:
128
+ """
129
+ Argument:
130
+ zxbcdtdl: (batch, seqlen, 2 * dim + 2 * ngroups * dstate + nheads) where dim == nheads * headdim
131
+ conv1d_weight: (dim + 2 * ngroups * dstate, width)
132
+ conv1d_bias: (dim + 2 * ngroups * dstate,)
133
+ dt_bias: (nheads,)
134
+ A: (nheads)
135
+ L: (nheads, nlevels)
136
+ D: (nheads, headdim) or (nheads,)
137
+ initial_states: (batch, nheads, headdim, dstate)
138
+ seq_idx: (batch, seqlen), int32
139
+ rmsnorm_weight: (dim,)
140
+ outproj_weight: (out_dim, dim)
141
+ outproj_bias: (out_dim,)
142
+ headdim: if D is 1D, headdim must be passed in
143
+ norm_before_gate: if True, we do RMSNorm(x) * F.silu(z). If False, we do RMSNorm(x * F.silu(z))
144
+ Return:
145
+ out: (batch, seqlen, dim)
146
+ """
147
+ if initial_states is not None:
148
+ raise NotImplementedError
149
+ if seq_idx is not None:
150
+ raise NotImplementedError
151
+ if dt_limit != (0.0, float("inf")):
152
+ raise NotImplementedError
153
+ if return_final_states is not False:
154
+ raise NotImplementedError
155
+ if norm_before_gate is not False:
156
+ raise NotImplementedError
157
+ if rmsnorm_weight is None:
158
+ raise NotImplementedError
159
+ if activation not in ["silu", "swish"]:
160
+ raise NotImplementedError
161
+
162
+ batch, seqlen, _ = zxbcdtdl.shape
163
+ dlambda = L.shape[-1]
164
+ (nheads,) = D.shape
165
+ dim = nheads * headdim
166
+ dstate = (zxbcdtdl.shape[-1] - 2 * dim - nheads - nheads * dlambda) // ngroups // 2
167
+
168
+ if D.dim() != 1:
169
+ raise ValueError
170
+ if headdim is None:
171
+ raise ValueError
172
+ if nheads % ngroups != 0:
173
+ raise ValueError
174
+ if zxbcdtdl.shape != (
175
+ batch,
176
+ seqlen,
177
+ 2 * dim + 2 * ngroups * dstate + nheads + nheads * dlambda,
178
+ ):
179
+ raise ValueError
180
+ if dt_bias.shape != (nheads,):
181
+ raise ValueError
182
+ if A.shape != (nheads,):
183
+ raise ValueError
184
+ if L.shape != (nheads, dlambda):
185
+ raise ValueError
186
+ if D.shape != (nheads,):
187
+ raise ValueError
188
+ if rmsnorm_weight is None:
189
+ raise ValueError
190
+
191
+ zxBCdtl_splits = [dim, dim + 2 * ngroups * dstate, nheads, nheads * dlambda]
192
+ xBC_splits = [dim, ngroups * dstate, ngroups * dstate]
193
+ z, xBC, dt, dl = torch.split(zxbcdtdl, zxBCdtl_splits, dim=-1)
194
+ _conv_fn = conv1d_fn if conv1d_fn is not None else causal_conv1d_fn
195
+ _conv_out = _conv_fn(
196
+ rearrange(xBC, "b s d -> b d s"),
197
+ conv1d_weight,
198
+ bias=conv1d_bias,
199
+ activation=activation,
200
+ seq_idx=seq_idx,
201
+ )
202
+ if conv_backend == 'triton':
203
+ _conv_out = _conv_out[0]
204
+ xBC = rearrange(_conv_out, "b d s -> b s d")
205
+ x, B, C = torch.split(xBC, xBC_splits, dim=-1)
206
+ x = rearrange(x, "b l (h p) -> b l h p", h=nheads, p=headdim)
207
+ B = rearrange(B, "b l (g n) -> b l g n", g=ngroups, n=dstate)
208
+ C = rearrange(C, "b l (g n) -> b l g n", g=ngroups, n=dstate)
209
+ dl = rearrange(dl, "b l (h ell) -> b l h ell", h=nheads, ell=dlambda)
210
+ y, _ = hmamba_chunk_scan_combined(
211
+ x=x,
212
+ dt=dt,
213
+ A=A,
214
+ B=B,
215
+ C=C,
216
+ dl=dl,
217
+ L=L,
218
+ chunk_size=chunk_size,
219
+ D=D,
220
+ z=z if rmsnorm_weight is None else None,
221
+ dt_bias=dt_bias,
222
+ dt_softplus=True,
223
+ seq_idx=seq_idx,
224
+ cu_seqlens=None,
225
+ dt_limit=dt_limit,
226
+ return_final_states=return_final_states,
227
+ )
228
+
229
+ y = rearrange(y, "b l h p -> b l (h p)")
230
+ if rmsnorm_weight is not None:
231
+ y = rmsnorm_fn(
232
+ x=y,
233
+ weight=rmsnorm_weight,
234
+ bias=None,
235
+ z=z,
236
+ eps=rmsnorm_eps,
237
+ group_size=None,
238
+ norm_before_gate=False,
239
+ )
240
+ out = torch.nn.functional.linear(y, outproj_weight, outproj_bias)
241
+ return out
242
+
243
+
244
+ class LogLinearMamba2(nn.Module):
245
+ """
246
+ Compute ∆, A, B, C, and D the state space parameters and compute the `contextualized_states`.
247
+ A, D are input independent (see Mamba paper [1] Section 3.5.2 "Interpretation of A" for why A isn't selective)
248
+ ∆, B, C are input-dependent (this is a key difference between Mamba and the linear time invariant S4,
249
+ and is why Mamba is called **selective** state spaces)
250
+ """
251
+
252
+ def __init__(
253
+ self,
254
+ num_heads: int,
255
+ head_dim: int = 64,
256
+ hidden_size: int = 2048,
257
+ state_size: int = 128,
258
+ expand: int = 2,
259
+ n_groups: int = 1,
260
+ conv_kernel: int = 4,
261
+ use_conv_bias: bool = False,
262
+ hidden_act: str = "silu",
263
+ rms_norm: bool = True,
264
+ chunk_size: int = 64,
265
+ time_step_rank: float = 256,
266
+ time_step_limit: tuple[float, float] = (0.0, float("inf")),
267
+ time_step_min: float = 0.001,
268
+ time_step_max: float = 0.1,
269
+ use_bias: bool = True,
270
+ norm_eps: float = 1e-5,
271
+ layer_idx: int = None,
272
+ backend: str = "cuda",
273
+ ):
274
+ super().__init__()
275
+ self.num_heads = num_heads
276
+ self.hidden_size = hidden_size
277
+ self.ssm_state_size = state_size
278
+ self.conv_kernel_size = conv_kernel
279
+ self.intermediate_size = int(expand * self.hidden_size)
280
+ self.time_step_rank = int(time_step_rank)
281
+ self.layer_idx = layer_idx
282
+ self.use_conv_bias = use_conv_bias
283
+ self.activation = hidden_act
284
+ self.act = ACT2FN[hidden_act]
285
+
286
+ self.layer_norm_epsilon = norm_eps
287
+ self.rms_norm = rms_norm
288
+
289
+ self.n_groups = n_groups
290
+ self.head_dim = head_dim
291
+ self.chunk_size = chunk_size
292
+
293
+ self.time_step_limit = time_step_limit
294
+ self.time_step_min = time_step_min
295
+ self.time_step_max = time_step_max
296
+
297
+ self.conv_dim = self.intermediate_size + 2 * self.n_groups * self.ssm_state_size
298
+ self.conv1d = nn.Conv1d(
299
+ in_channels=self.conv_dim,
300
+ out_channels=self.conv_dim,
301
+ bias=use_conv_bias,
302
+ kernel_size=conv_kernel,
303
+ groups=self.conv_dim,
304
+ padding=conv_kernel - 1,
305
+ )
306
+
307
+ self.num_lambda_dims = MAX_NUM_LEVELS
308
+ self.lambda_level_module = None
309
+
310
+ # projection of the input hidden states
311
+ projection_size = (
312
+ self.intermediate_size
313
+ + self.conv_dim
314
+ + self.num_heads * (self.num_lambda_dims + 1)
315
+ )
316
+ self.in_proj = nn.Linear(
317
+ self.hidden_size,
318
+ projection_size,
319
+ bias=use_bias,
320
+ )
321
+ # selective projection used to make dt, B and C input dependant
322
+
323
+ # time step projection (discretization)
324
+ # instantiate once and copy inv_dt in init_weights of PretrainedModel
325
+ self.dt_bias = nn.Parameter(torch.ones(self.num_heads))
326
+
327
+ # S4D real initialization. These are not discretized!
328
+ # The core is to load them, compute the discrete states, then write the updated state. Keeps the memory bounded
329
+ A = torch.arange(1, self.num_heads + 1)
330
+ self.A_log = nn.Parameter(torch.log(A))
331
+ self.A_log._no_weight_decay = True
332
+
333
+ self.lambda_mode = "positive"
334
+ L = torch.ones(self.num_heads, self.num_lambda_dims)
335
+ self.L = nn.Parameter(L)
336
+ self.L._no_weight_decay = True
337
+
338
+ self.norm = RMSNormGated(
339
+ self.intermediate_size, eps=self.layer_norm_epsilon, norm_before_gate=False,
340
+ )
341
+ self.D = nn.Parameter(torch.ones(self.num_heads))
342
+ self.D._no_weight_decay = True
343
+
344
+ self.out_proj = nn.Linear(
345
+ self.intermediate_size, self.hidden_size, bias=use_bias,
346
+ )
347
+ self.use_bias = use_bias
348
+
349
+ if not is_fast_path_available:
350
+ logger.warning_once(
351
+ "The fast path is not available because one of "
352
+ "`(selective_state_update, causal_conv1d_fn, causal_conv1d_update)` is None. "
353
+ "Falling back to the naive implementation. "
354
+ "To install follow https://github.com/state-spaces/mamba/#installation and"
355
+ "https://github.com/Dao-AILab/causal-conv1d",
356
+ )
357
+ import os
358
+ backend = os.environ.get('FLA_CONV_BACKEND', backend)
359
+ assert backend in ['cuda', 'triton'], f"Unsupported backend: {backend}"
360
+ if backend == 'cuda' and causal_conv1d_fn is None:
361
+ logger.warning_once(
362
+ "The CUDA backend is not available because `causal_conv1d` is None. "
363
+ "Falling back to the Triton backend. "
364
+ "To install follow https://github.com/Dao-AILab/causal-conv1d",
365
+ )
366
+ backend = 'triton'
367
+ if backend == 'triton':
368
+ from fla.modules.convolution import causal_conv1d as causal_conv1d_triton
369
+ from fla.modules.convolution import causal_conv1d_update as causal_conv1d_update_triton
370
+ self.causal_conv1d_fn = causal_conv1d_triton
371
+ self.causal_conv1d_update = causal_conv1d_update_triton
372
+ logger.warning(
373
+ "LogLinearMamba2 does not recommend using Triton's conv1d backend, "
374
+ "as it is untested and may contain bugs.",
375
+ )
376
+ else:
377
+ self.causal_conv1d_fn = causal_conv1d_fn
378
+ self.causal_conv1d_update = causal_conv1d_update
379
+ self.backend = backend
380
+
381
+ def cuda_kernels_forward(
382
+ self,
383
+ hidden_states: torch.Tensor,
384
+ last_state: dict | None = None,
385
+ use_cache: bool = False,
386
+ attention_mask: torch.Tensor | None = None,
387
+ ):
388
+ if self.activation not in ["silu", "swish"]:
389
+ raise ValueError
390
+
391
+ # 1. Gated MLP's linear projection
392
+ # Only apply padding mask during prefill (last_state is None).
393
+ # During decode, attention_mask has shape (B, accumulated_len) which
394
+ # mismatches hidden_states (B, 1, D).
395
+ hidden_states = apply_mask_to_padding_states(
396
+ hidden_states=hidden_states,
397
+ attention_mask=attention_mask if last_state is None else None,
398
+ )
399
+ projected_states = self.in_proj(hidden_states)
400
+
401
+ # Set up dimensions for reshapes later
402
+ batch_size, seq_len, _ = hidden_states.shape
403
+ groups_time_state_size = self.n_groups * self.ssm_state_size
404
+ d_mlp = (
405
+ projected_states.shape[-1]
406
+ - 2 * self.intermediate_size
407
+ - 2 * self.n_groups * self.ssm_state_size
408
+ - self.num_heads * (self.num_lambda_dims + 1)
409
+ ) // 2
410
+ if d_mlp != 0:
411
+ raise ValueError
412
+
413
+ # Single step calculations via cache
414
+ if last_state is not None:
415
+ if hidden_states.shape[1] != 1:
416
+ raise ValueError("LogLinearMamba2 cached decoding only supports a single new token per step.")
417
+
418
+ gate, xBC, dt, dl = torch.split(
419
+ projected_states.squeeze(1),
420
+ [
421
+ self.intermediate_size,
422
+ self.conv_dim,
423
+ self.num_heads,
424
+ self.num_heads * self.num_lambda_dims,
425
+ ],
426
+ dim=-1,
427
+ )
428
+
429
+ # 2. Convolution sequence transformation
430
+ conv_state = last_state['conv_state']
431
+ xBC = self.causal_conv1d_update(
432
+ xBC,
433
+ conv_state,
434
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
435
+ self.conv1d.bias,
436
+ self.activation,
437
+ )
438
+
439
+ x, B, C = torch.split(
440
+ xBC,
441
+ [
442
+ self.intermediate_size,
443
+ groups_time_state_size,
444
+ groups_time_state_size,
445
+ ],
446
+ dim=-1,
447
+ )
448
+
449
+ # 3. SSM transformation
450
+ A = -torch.exp(self.A_log.float()) # (nheads,)
451
+ B = rearrange(
452
+ B,
453
+ "b (g n) -> b g n",
454
+ b=batch_size,
455
+ g=self.n_groups,
456
+ n=self.ssm_state_size,
457
+ )
458
+ C = rearrange(
459
+ C,
460
+ "b (g n) -> b g n",
461
+ b=batch_size,
462
+ g=self.n_groups,
463
+ n=self.ssm_state_size,
464
+ )
465
+ x_reshaped = rearrange(
466
+ x,
467
+ "b (h p) -> b h p",
468
+ b=batch_size,
469
+ h=self.num_heads,
470
+ p=self.head_dim,
471
+ )
472
+ dl_reshaped = rearrange(
473
+ dl,
474
+ "b (h ell) -> b h ell",
475
+ b=batch_size,
476
+ h=self.num_heads,
477
+ ell=self.num_lambda_dims,
478
+ )
479
+ y, hssm_state = hmamba_chunk_scan_combined(
480
+ x_reshaped,
481
+ dt=dt,
482
+ A=A,
483
+ B=B,
484
+ C=C,
485
+ dl=dl_reshaped,
486
+ L=self.L,
487
+ D=self.D,
488
+ z=None,
489
+ dt_bias=self.dt_bias,
490
+ dt_softplus=True,
491
+ initial_states=last_state['recurrent_state'],
492
+ return_final_states=True,
493
+ )
494
+ y = rearrange(
495
+ y,
496
+ "b h p -> b (h p)",
497
+ b=batch_size,
498
+ h=self.num_heads,
499
+ p=self.head_dim,
500
+ )
501
+ y = self.norm(y, gate)
502
+
503
+ # 4. Final linear projection
504
+ out = self.out_proj(y)[:, None, ...]
505
+ return out, conv_state, hssm_state
506
+
507
+ # Fused calculations or step by step if no initialized cache is found
508
+ else:
509
+ A = -torch.exp(
510
+ self.A_log.float(),
511
+ ) # (num_heads) or (intermediate_size, state_size)
512
+ dt_limit_kwargs = (
513
+ {}
514
+ if self.time_step_limit == (0.0, float("inf"))
515
+ else {"dt_limit": self.time_step_limit}
516
+ )
517
+
518
+ # 2-4. Fused kernel for conv1d, SSM, and the final projection
519
+ if self.training and not use_cache:
520
+ out = torch.utils.checkpoint.checkpoint(
521
+ hmamba_split_conv1d_scan_combined,
522
+ use_reentrant=False,
523
+ # function arguments
524
+ zxbcdtdl=projected_states,
525
+ conv1d_weight=rearrange(self.conv1d.weight, "d 1 w -> d w"),
526
+ conv1d_bias=self.conv1d.bias,
527
+ dt_bias=self.dt_bias,
528
+ A=A,
529
+ L=self.L,
530
+ D=self.D,
531
+ chunk_size=self.chunk_size,
532
+ conv1d_fn=self.causal_conv1d_fn,
533
+ conv_backend=self.backend,
534
+ seq_idx=None, # was seq_idx
535
+ activation=self.activation,
536
+ rmsnorm_weight=self.norm.weight,
537
+ rmsnorm_eps=self.norm.eps,
538
+ outproj_weight=self.out_proj.weight,
539
+ outproj_bias=self.out_proj.bias,
540
+ headdim=self.head_dim,
541
+ ngroups=self.n_groups,
542
+ norm_before_gate=False,
543
+ return_final_states=False,
544
+ **dt_limit_kwargs,
545
+ )
546
+ return out, None, None
547
+
548
+ else:
549
+ gate, xBC, dt, dl = torch.split(
550
+ projected_states,
551
+ [
552
+ self.intermediate_size,
553
+ self.conv_dim,
554
+ self.num_heads,
555
+ self.num_heads * self.num_lambda_dims,
556
+ ],
557
+ dim=-1,
558
+ )
559
+
560
+ # 2. Convolution sequence transformation
561
+ # Init cache
562
+ masked_xBC = apply_mask_to_padding_states(xBC, attention_mask)
563
+ new_conv_state = None
564
+ if use_cache:
565
+ xBC_t = rearrange(masked_xBC, "b l d -> b d l")
566
+ new_conv_state = torch.nn.functional.pad(
567
+ xBC_t,
568
+ (self.conv_kernel_size - xBC_t.shape[-1], 0),
569
+ )
570
+
571
+ _conv1d_output = self.causal_conv1d_fn(
572
+ x=xBC.transpose(1, 2),
573
+ weight=rearrange(self.conv1d.weight, "d 1 w -> d w"),
574
+ bias=self.conv1d.bias,
575
+ activation=self.activation,
576
+ )
577
+ if self.backend == 'cuda':
578
+ xBC = _conv1d_output.transpose(1, 2)
579
+ elif self.backend == 'triton':
580
+ xBC = _conv1d_output[0].transpose(1, 2).contiguous()
581
+ else:
582
+ raise ValueError(f"Unsupported backend: {self.backend}")
583
+
584
+ xBC = apply_mask_to_padding_states(
585
+ hidden_states=xBC,
586
+ attention_mask=attention_mask,
587
+ )
588
+
589
+ x, B, C = torch.split(
590
+ xBC,
591
+ [
592
+ self.intermediate_size,
593
+ groups_time_state_size,
594
+ groups_time_state_size,
595
+ ],
596
+ dim=-1,
597
+ )
598
+
599
+ # 3. SSM transformation
600
+ y, hssm_state = hmamba_chunk_scan_combined(
601
+ rearrange(
602
+ x,
603
+ "b l (h p) -> b l h p",
604
+ b=batch_size,
605
+ l=seq_len,
606
+ p=self.head_dim,
607
+ ),
608
+ dt=dt,
609
+ A=A,
610
+ B=rearrange(
611
+ B,
612
+ "b l (g n) -> b l g n",
613
+ b=batch_size,
614
+ l=seq_len,
615
+ g=self.n_groups,
616
+ ),
617
+ C=rearrange(
618
+ C,
619
+ "b l (g n) -> b l g n",
620
+ b=batch_size,
621
+ l=seq_len,
622
+ g=self.n_groups,
623
+ ),
624
+ dl=rearrange(
625
+ dl,
626
+ "b l (h ell) -> b l h ell",
627
+ b=batch_size,
628
+ h=self.num_heads,
629
+ ell=self.num_lambda_dims,
630
+ ),
631
+ L=self.L,
632
+ chunk_size=self.chunk_size,
633
+ D=self.D,
634
+ z=None,
635
+ seq_idx=None,
636
+ return_final_states=True,
637
+ dt_bias=self.dt_bias,
638
+ dt_softplus=True,
639
+ **dt_limit_kwargs,
640
+ )
641
+
642
+ y = rearrange(
643
+ y,
644
+ "b l h p -> b l (h p)",
645
+ b=batch_size,
646
+ l=seq_len,
647
+ h=self.num_heads,
648
+ p=self.head_dim,
649
+ )
650
+ # Multiply "gate" branch and apply extra normalization layer
651
+ y = self.norm(y, gate)
652
+
653
+ # 4. Final linear projection
654
+ out = self.out_proj(y)
655
+
656
+ return out, new_conv_state, hssm_state
657
+
658
+ def forward(
659
+ self,
660
+ hidden_states: torch.Tensor,
661
+ attention_mask: torch.Tensor | None = None,
662
+ past_key_values: Cache | None = None,
663
+ use_cache: bool | None = False,
664
+ output_attentions: bool | None = False,
665
+ **kwargs,
666
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
667
+ last_state = get_layer_cache(self, past_key_values)
668
+
669
+ if "cuda" in self.in_proj.weight.device.type:
670
+ output, conv_state, hssm_state = self.cuda_kernels_forward(
671
+ hidden_states, last_state, use_cache, attention_mask
672
+ )
673
+ else:
674
+ raise NotImplementedError
675
+
676
+ update_layer_cache(
677
+ self,
678
+ past_key_values,
679
+ recurrent_state=hssm_state,
680
+ conv_state=conv_state,
681
+ offset=hidden_states.shape[1],
682
+ )
683
+
684
+ return output, None, past_key_values
fla/layers/mamba.py ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from transformers.utils import logging
11
+
12
+ from fla.layers.utils import get_layer_cache, update_layer_cache
13
+ from fla.modules.activations import ACT2FN
14
+
15
+ with warnings.catch_warnings():
16
+ warnings.simplefilter('ignore')
17
+ try:
18
+ from mamba_ssm.ops.selective_scan_interface import mamba_inner_fn, selective_scan_fn
19
+ from mamba_ssm.ops.triton.selective_state_update import selective_state_update
20
+ except ImportError:
21
+ selective_state_update, selective_scan_fn, mamba_inner_fn = None, None, None
22
+
23
+ try:
24
+ from causal_conv1d import causal_conv1d_fn, causal_conv1d_update
25
+ except ImportError:
26
+ causal_conv1d_update, causal_conv1d_fn = None, None
27
+ is_fast_path_available = all((
28
+ selective_state_update,
29
+ selective_scan_fn,
30
+ mamba_inner_fn,
31
+ ))
32
+ if TYPE_CHECKING:
33
+ from transformers.processing_utils import Unpack
34
+
35
+ from fla.models.utils import Cache
36
+
37
+ logger = logging.get_logger(__name__)
38
+
39
+
40
+ class Mamba(nn.Module):
41
+ """
42
+ Compute ∆, A, B, C, and D the state space parameters and compute the `contextualized_states`.
43
+ A, D are input independent (see Mamba paper [1] Section 3.5.2 "Interpretation of A" for why A isn't selective)
44
+ ∆, B, C are input-dependent (this is a key difference between Mamba and the linear time invariant S4,
45
+ and is why Mamba is called **selective** state spaces)
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ hidden_size: int = 2048,
51
+ state_size: int = 16,
52
+ conv_kernel: int = 4,
53
+ use_conv_bias: bool = True,
54
+ intermediate_size: int = 2048,
55
+ time_step_rank: int = 256,
56
+ use_bias: bool = True,
57
+ hidden_act: str = "silu",
58
+ layer_idx: int = None,
59
+ backend: str = "cuda",
60
+ ):
61
+ super().__init__()
62
+
63
+ self.hidden_size = hidden_size
64
+ self.ssm_state_size = state_size
65
+ self.conv_kernel_size = conv_kernel
66
+ self.use_conv_bias = use_conv_bias
67
+ self.intermediate_size = intermediate_size
68
+ self.time_step_rank = time_step_rank
69
+ self.use_bias = use_bias
70
+
71
+ self.conv1d = nn.Conv1d(
72
+ in_channels=self.intermediate_size,
73
+ out_channels=self.intermediate_size,
74
+ bias=use_conv_bias,
75
+ kernel_size=conv_kernel,
76
+ groups=self.intermediate_size,
77
+ padding=conv_kernel - 1,
78
+ )
79
+
80
+ self.activation = hidden_act
81
+ self.act = ACT2FN[hidden_act]
82
+
83
+ self.layer_idx = layer_idx
84
+
85
+ # projection of the input hidden states
86
+ self.in_proj = nn.Linear(self.hidden_size, self.intermediate_size * 2, bias=use_bias)
87
+ # selective projection used to make dt, B and C input dependant
88
+ self.x_proj = nn.Linear(self.intermediate_size, self.time_step_rank + self.ssm_state_size * 2, bias=False)
89
+ # time step projection (discretization)
90
+ self.dt_proj = nn.Linear(self.time_step_rank, self.intermediate_size, bias=True)
91
+
92
+ # S4D real initialization. These are not discretized!
93
+ # The core is to load them, compute the discrete states, then write the updated state. Keeps the memory bounded
94
+ A = torch.arange(1, self.ssm_state_size + 1, dtype=torch.float32)[None, :]
95
+ A = A.expand(self.intermediate_size, -1).contiguous()
96
+
97
+ self.A_log = nn.Parameter(torch.log(A))
98
+ self.D = nn.Parameter(torch.ones(self.intermediate_size))
99
+ self.out_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=use_bias)
100
+
101
+ if not is_fast_path_available:
102
+ logger.warning_once(
103
+ "The fast path is not available because on of "
104
+ "`(selective_state_update, selective_scan_fn, causal_conv1d_fn, causal_conv1d_update, mamba_inner_fn)`"
105
+ " is None. Falling back to the naive implementation. "
106
+ "To install follow https://github.com/state-spaces/mamba/#installation and"
107
+ " https://github.com/Dao-AILab/causal-conv1d",
108
+ )
109
+ import os
110
+ backend = os.environ.get('FLA_CONV_BACKEND', backend)
111
+ assert backend in ['cuda', 'triton'], f"Unsupported backend: {backend}"
112
+ if backend == 'cuda' and causal_conv1d_fn is None:
113
+ logger.warning_once(
114
+ "The CUDA backend is not available because `causal_conv1d` is None. "
115
+ "Falling back to the Triton backend. "
116
+ "To install follow https://github.com/Dao-AILab/causal-conv1d",
117
+ )
118
+ backend = 'triton'
119
+ if backend == 'triton':
120
+ from fla.modules.convolution import causal_conv1d as causal_conv1d_triton
121
+ from fla.modules.convolution import causal_conv1d_update as causal_conv1d_update_triton
122
+ self.causal_conv1d_fn = causal_conv1d_triton
123
+ self.causal_conv1d_update = causal_conv1d_update_triton
124
+ else:
125
+ self.causal_conv1d_fn = causal_conv1d_fn
126
+ self.causal_conv1d_update = causal_conv1d_update
127
+ self.backend = backend
128
+
129
+ def _to_causal_conv_layout(self, hidden_states: torch.Tensor) -> torch.Tensor:
130
+ return hidden_states.transpose(1, 2).contiguous()
131
+
132
+ def _from_causal_conv_layout(self, hidden_states: torch.Tensor) -> torch.Tensor:
133
+ return hidden_states.transpose(1, 2).contiguous()
134
+
135
+ def _build_conv_state(self, hidden_states: torch.Tensor) -> torch.Tensor:
136
+ seq_len = hidden_states.shape[-1]
137
+ if seq_len >= self.conv_kernel_size:
138
+ return hidden_states[..., -self.conv_kernel_size:].contiguous()
139
+ return nn.functional.pad(hidden_states, (self.conv_kernel_size - seq_len, 0)).contiguous()
140
+
141
+ def cuda_kernels_forward(
142
+ self,
143
+ hidden_states: torch.Tensor,
144
+ last_state: dict | None = None,
145
+ use_cache: bool | None = False,
146
+ attention_mask: torch.LongTensor | None = None,
147
+ **kwargs: Unpack[dict],
148
+ ):
149
+ if last_state is not None and hidden_states.shape[1] != 1:
150
+ raise ValueError("Mamba cached decoding only supports a single new token per step.")
151
+
152
+ # 1. Gated MLP's linear projection
153
+ projected_states = self.in_proj(hidden_states).transpose(1, 2)
154
+
155
+ if self.training and not use_cache:
156
+ contextualized_states = mamba_inner_fn(
157
+ projected_states,
158
+ self.conv1d.weight,
159
+ self.conv1d.bias if self.use_conv_bias else None,
160
+ self.x_proj.weight,
161
+ self.dt_proj.weight,
162
+ self.out_proj.weight,
163
+ self.out_proj.bias.float() if self.use_bias else None,
164
+ -torch.exp(self.A_log.float()),
165
+ None, # input-dependent B
166
+ None, # input-dependent C
167
+ self.D.float(),
168
+ delta_bias=self.dt_proj.bias.float(),
169
+ delta_softplus=True,
170
+ )
171
+ return contextualized_states, None, None
172
+
173
+ hidden_states, gate = projected_states.chunk(2, dim=1)
174
+
175
+ if attention_mask is not None and last_state is None:
176
+ # Mask before the depthwise conv so cached/prefill conv inputs do not keep pad tokens.
177
+ hidden_states = hidden_states * attention_mask.unsqueeze(1)
178
+
179
+ # 2. Convolution sequence transformation
180
+ conv_inputs = hidden_states
181
+ conv_weights = self.conv1d.weight.view(self.conv1d.weight.size(0), self.conv1d.weight.size(2))
182
+ if last_state is not None:
183
+ conv_state = last_state['conv_state']
184
+ ssm_state = last_state['recurrent_state']
185
+
186
+ if self.backend == 'triton':
187
+ hidden_states, conv_state = self.causal_conv1d_update(
188
+ x=self._to_causal_conv_layout(conv_inputs),
189
+ cache=conv_state,
190
+ weight=conv_weights,
191
+ bias=self.conv1d.bias,
192
+ activation=self.activation,
193
+ )
194
+ hidden_states = self._from_causal_conv_layout(hidden_states)
195
+ else:
196
+ hidden_states = self.causal_conv1d_update(
197
+ conv_inputs.squeeze(-1),
198
+ conv_state,
199
+ conv_weights,
200
+ self.conv1d.bias,
201
+ self.activation,
202
+ )
203
+ hidden_states = hidden_states.unsqueeze(-1)
204
+ else:
205
+ conv_state = None
206
+ ssm_state = None
207
+ if self.backend == 'triton':
208
+ hidden_states, conv_state = self.causal_conv1d_fn(
209
+ x=self._to_causal_conv_layout(conv_inputs),
210
+ weight=conv_weights,
211
+ bias=self.conv1d.bias,
212
+ activation=self.activation,
213
+ output_final_state=bool(use_cache),
214
+ )
215
+ hidden_states = self._from_causal_conv_layout(hidden_states)
216
+ else:
217
+ if use_cache:
218
+ conv_state = self._build_conv_state(conv_inputs)
219
+ hidden_states = self.causal_conv1d_fn(
220
+ conv_inputs, conv_weights, self.conv1d.bias, activation=self.activation,
221
+ )
222
+
223
+ if attention_mask is not None and last_state is None:
224
+ # Re-mask after the conv: causal kernels can regenerate non-zero values at masked positions,
225
+ # and those values would otherwise leak into x_proj and the SSM recurrence.
226
+ hidden_states = hidden_states * attention_mask.unsqueeze(1)
227
+
228
+ # 3. State Space Model sequence transformation
229
+ # 3.a. input varying initialization of time_step, B and C
230
+ ssm_parameters = self.x_proj(hidden_states.transpose(1, 2))
231
+ time_step, B, C = torch.split(
232
+ ssm_parameters, [self.time_step_rank, self.ssm_state_size, self.ssm_state_size], dim=-1,
233
+ )
234
+ discrete_time_step = self.dt_proj.weight @ time_step.transpose(1, 2)
235
+
236
+ A = -torch.exp(self.A_log.float())
237
+ # 3.c perform the recurrence y ← SSM(A, B, C)(x)
238
+ time_proj_bias = self.dt_proj.bias.float() if hasattr(self.dt_proj, "bias") else None
239
+ if last_state is not None:
240
+ scan_outputs = selective_state_update(
241
+ ssm_state,
242
+ hidden_states[..., 0],
243
+ discrete_time_step[..., 0],
244
+ A,
245
+ B[:, 0],
246
+ C[:, 0],
247
+ self.D,
248
+ gate[..., 0],
249
+ time_proj_bias,
250
+ dt_softplus=True,
251
+ ).unsqueeze(-1)
252
+ else:
253
+ scan_outputs, ssm_state = selective_scan_fn(
254
+ hidden_states,
255
+ discrete_time_step,
256
+ A,
257
+ B.transpose(1, 2),
258
+ C.transpose(1, 2),
259
+ self.D.float(),
260
+ gate,
261
+ time_proj_bias,
262
+ delta_softplus=True,
263
+ return_last_state=True,
264
+ )
265
+
266
+ # 4. Final linear projection
267
+ contextualized_states = self.out_proj(scan_outputs.transpose(1, 2))
268
+ return contextualized_states, conv_state, ssm_state
269
+
270
+ def slow_forward(
271
+ self,
272
+ input_states,
273
+ last_state: dict | None = None,
274
+ use_cache: bool | None = False,
275
+ attention_mask: torch.LongTensor | None = None,
276
+ **kwargs: Unpack[dict],
277
+ ):
278
+ if last_state is not None and input_states.shape[1] != 1:
279
+ raise ValueError("Mamba cached decoding only supports a single new token per step.")
280
+
281
+ batch_size, seq_len, _ = input_states.shape
282
+ dtype = input_states.dtype
283
+ # 1. Gated MLP's linear projection
284
+ # [batch, 2 * intermediate_size, seq_len]
285
+ projected_states = self.in_proj(input_states).transpose(1, 2)
286
+ hidden_states, gate = projected_states.chunk(2, dim=1)
287
+
288
+ if attention_mask is not None and last_state is None:
289
+ # Mask before the depthwise conv so cached/prefill conv inputs do not keep pad tokens.
290
+ hidden_states = hidden_states * attention_mask.unsqueeze(1)
291
+
292
+ # 2. Convolution sequence transformation
293
+ if last_state is not None:
294
+ conv_state = last_state['conv_state']
295
+ ssm_state = last_state['recurrent_state'].clone().to(hidden_states.device)
296
+
297
+ # decode path: single token
298
+ conv_state = conv_state.roll(shifts=-1, dims=-1)
299
+ conv_state[:, :, -1] = hidden_states[:, :, 0].to(conv_state.device)
300
+ hidden_states = torch.sum(conv_state * self.conv1d.weight[:, 0, :], dim=-1)
301
+ if self.use_conv_bias:
302
+ hidden_states += self.conv1d.bias
303
+ # [batch, intermediate_size, 1] : decoding
304
+ hidden_states = self.act(hidden_states).to(dtype).unsqueeze(-1)
305
+ elif use_cache:
306
+ ssm_state = torch.zeros(
307
+ (batch_size, self.intermediate_size, self.ssm_state_size),
308
+ device=hidden_states.device, dtype=dtype,
309
+ )
310
+ conv_state = self._build_conv_state(hidden_states)
311
+ # [batch, intermediate_size, seq_len]
312
+ hidden_states = self.act(self.conv1d(hidden_states)[..., :seq_len])
313
+ else:
314
+ ssm_state = torch.zeros(
315
+ (batch_size, self.intermediate_size, self.ssm_state_size),
316
+ device=hidden_states.device, dtype=dtype,
317
+ )
318
+ conv_state = None
319
+ # [batch, intermediate_size, seq_len]
320
+ hidden_states = self.act(self.conv1d(hidden_states)[..., :seq_len])
321
+
322
+ if attention_mask is not None and last_state is None:
323
+ # Re-mask after the conv: causal kernels can regenerate non-zero values at masked positions,
324
+ # and those values would otherwise leak into x_proj and the SSM recurrence.
325
+ hidden_states = hidden_states * attention_mask.unsqueeze(1)
326
+
327
+ # 3. State Space Model sequence transformation
328
+ # 3.a. Selection: [batch, seq_len, self.time_step_rank + self.ssm_state_size * 2]
329
+ ssm_parameters = self.x_proj(hidden_states.transpose(1, 2))
330
+ time_step, B, C = torch.split(
331
+ ssm_parameters, [self.time_step_rank, self.ssm_state_size, self.ssm_state_size], dim=-1,
332
+ )
333
+ # [batch, seq_len, intermediate_size]
334
+ discrete_time_step = self.dt_proj(time_step)
335
+ # [batch, intermediate_size, seq_len]
336
+ discrete_time_step = nn.functional.softplus(discrete_time_step).transpose(1, 2)
337
+
338
+ # 3.b. Discretization: B and C to [batch, seq_len, intermediate_size, ssm_state_size] (SRAM)
339
+ # [intermediate_size, ssm_state_size]
340
+ A = -torch.exp(self.A_log.float())
341
+ # [batch, intermediate_size, seq_len, ssm_state_size]
342
+ discrete_A = torch.exp(A[None, :, None, :] * discrete_time_step[:, :, :, None])
343
+ # [batch, intermediate_size, seq_len, ssm_state_size]
344
+ discrete_B = discrete_time_step[:, :, :, None] * B[:, None, :, :].float()
345
+ deltaB_u = discrete_B * hidden_states[:, :, :, None].float()
346
+
347
+ # 3.c perform the recurrence y ← SSM(A, B, C)(x)
348
+ scan_outputs = []
349
+ for i in range(hidden_states.shape[-1]):
350
+ # [batch, intermediade_size, ssm_state]
351
+ ssm_state = discrete_A[:, :, i, :] * ssm_state + deltaB_u[:, :, i, :]
352
+ # [batch, intermediade_size, 1]
353
+ scan_output = torch.matmul(ssm_state.to(dtype), C[:, i, :].unsqueeze(-1))
354
+ scan_outputs.append(scan_output[:, :, 0])
355
+ # [batch, seq_len, intermediade_size]
356
+ scan_output = torch.stack(scan_outputs, dim=-1)
357
+ scan_output = scan_output + (hidden_states * self.D[None, :, None])
358
+ scan_output = (scan_output * self.act(gate))
359
+
360
+ # 4. Final linear projection
361
+ # [batch, seq_len, hidden_size]
362
+ contextualized_states = self.out_proj(scan_output.transpose(1, 2))
363
+ return contextualized_states, conv_state, ssm_state
364
+ # fmt: on
365
+
366
+ def forward(
367
+ self,
368
+ hidden_states: torch.Tensor,
369
+ attention_mask: torch.LongTensor | None = None,
370
+ past_key_values: Cache | None = None,
371
+ use_cache: bool | None = False,
372
+ output_attentions: bool | None = False,
373
+ **kwargs: Unpack[dict],
374
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
375
+ last_state = get_layer_cache(self, past_key_values)
376
+
377
+ if is_fast_path_available and "cuda" in self.x_proj.weight.device.type:
378
+ output, conv_state, ssm_state = self.cuda_kernels_forward(
379
+ hidden_states, last_state, use_cache, attention_mask, **kwargs
380
+ )
381
+ else:
382
+ output, conv_state, ssm_state = self.slow_forward(
383
+ hidden_states, last_state, use_cache, attention_mask, **kwargs
384
+ )
385
+
386
+ if use_cache and past_key_values is not None:
387
+ update_layer_cache(
388
+ self,
389
+ past_key_values,
390
+ recurrent_state=ssm_state,
391
+ conv_state=conv_state,
392
+ offset=hidden_states.shape[1],
393
+ )
394
+
395
+ return output, None, past_key_values
fla/layers/mamba2.py ADDED
@@ -0,0 +1,649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import warnings
7
+ from typing import TYPE_CHECKING
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from transformers.utils import logging
12
+
13
+ from fla.layers.utils import get_layer_cache, update_layer_cache
14
+ from fla.modules.activations import ACT2FN
15
+ from fla.modules.layernorm_gated import RMSNormGated
16
+
17
+ with warnings.catch_warnings():
18
+ warnings.simplefilter('ignore')
19
+ try:
20
+ from mamba_ssm.ops.triton.selective_state_update import selective_state_update
21
+ from mamba_ssm.ops.triton.ssd_combined import mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
22
+ except ImportError:
23
+ selective_state_update, mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined = None, None, None
24
+ try:
25
+ from causal_conv1d import causal_conv1d_fn, causal_conv1d_update
26
+ except ImportError:
27
+ causal_conv1d_update, causal_conv1d_fn = None, None
28
+ is_fast_path_available = selective_state_update is not None
29
+
30
+ if TYPE_CHECKING:
31
+ from fla.models.utils import Cache
32
+
33
+ logger = logging.get_logger(__name__)
34
+
35
+
36
+ def apply_mask_to_padding_states(hidden_states, attention_mask):
37
+ """
38
+ Tunes out the hidden states for padding tokens, see https://github.com/state-spaces/mamba/issues/66
39
+ """
40
+ if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1:
41
+ dtype = hidden_states.dtype
42
+ hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
43
+
44
+ return hidden_states
45
+
46
+
47
+ def pad_tensor_by_size(input_tensor: torch.Tensor, pad_size: int):
48
+ """
49
+ Padding x tensor with `pad_size` on the seq_len dim (dim=1)
50
+
51
+ Assumes that we only have tensors of either size 4 or 3
52
+ """
53
+ pad_shape = (0, 0, 0, 0, 0, pad_size, 0, 0) if len(input_tensor.shape) == 4 else (0, 0, 0, pad_size, 0, 0)
54
+
55
+ return torch.nn.functional.pad(input_tensor, pad_shape, mode="constant", value=0)
56
+
57
+
58
+ def reshape_into_chunks(input_tensor, pad_size, chunk_size):
59
+ """
60
+ Padding input_tensor with `pad_size` on the seq_len dim (dim=1) and
61
+ simultaneously splitting it into chunk sequences.
62
+
63
+ Assumes that we only have tensors of either size 4 or 3
64
+ """
65
+ # [bsz, seq_len, ...] -> [bsz, seq_len multiple of chunk_size, ...]
66
+ input_tensor = pad_tensor_by_size(input_tensor, pad_size)
67
+
68
+ if len(input_tensor.shape) == 3:
69
+ # [bsz, seq_len multiple of chunk_size, num_heads] -> [bsz, -1, chunk_size, num_heads]
70
+ return input_tensor.reshape(input_tensor.shape[0], -1, chunk_size, input_tensor.shape[2])
71
+ else:
72
+ # [bsz, seq_len multiple of chunk_size, num_heads, head_dim or state_size] ->
73
+ # [bsz, -1, chunk_size, num_heads, head_dim or state_size]
74
+ return input_tensor.reshape(
75
+ input_tensor.shape[0], -1, chunk_size, input_tensor.shape[2], input_tensor.shape[3],
76
+ )
77
+
78
+
79
+ def segment_sum(input_tensor):
80
+ """
81
+ More stable segment sum calculation. Uses cumulative sums and masking instead of direct subtractions.
82
+ """
83
+ chunk_size = input_tensor.size(-1)
84
+ # 1. expand input tensor to have an additional dimension and repeat along that dimension
85
+ # [..., chunk_size] -> [..., chunk_size, chunk_size]
86
+ input_tensor = input_tensor[..., None].expand(*input_tensor.size(), chunk_size)
87
+ # 2. create a lower triangular mask with the diagonal set to 0 to 0 out elements above diag
88
+ mask = torch.tril(torch.ones(chunk_size, chunk_size, device=input_tensor.device, dtype=torch.bool), diagonal=-1)
89
+ input_tensor = input_tensor.masked_fill(~mask, 0)
90
+ # 3. compute actual cumsum
91
+ tensor_segsum = torch.cumsum(input_tensor, dim=-2)
92
+
93
+ # 4. apply mask to keep only the lower triangular part of the cumulative sum result (incl diagonal this time)
94
+ mask = torch.tril(torch.ones(chunk_size, chunk_size, device=input_tensor.device, dtype=torch.bool), diagonal=0)
95
+ tensor_segsum = tensor_segsum.masked_fill(~mask, -torch.inf)
96
+ return tensor_segsum
97
+
98
+
99
+ class Mamba2(nn.Module):
100
+ """
101
+ Compute ∆, A, B, C, and D the state space parameters and compute the `contextualized_states`.
102
+ A, D are input independent (see Mamba paper [1] Section 3.5.2 "Interpretation of A" for why A isn't selective)
103
+ ∆, B, C are input-dependent (this is a key difference between Mamba and the linear time invariant S4,
104
+ and is why Mamba is called **selective** state spaces)
105
+ """
106
+
107
+ def __init__(
108
+ self,
109
+ num_heads: int,
110
+ head_dim: int = 64,
111
+ hidden_size: int = 2048,
112
+ state_size: int = 128,
113
+ expand: int = 2,
114
+ n_groups: int = 1,
115
+ conv_kernel: int = 4,
116
+ use_conv_bias: bool = False,
117
+ hidden_act: str = "silu",
118
+ rms_norm: bool = True,
119
+ chunk_size: int = 256,
120
+ time_step_rank: float = 256,
121
+ time_step_limit: tuple[float, float] = (0.0, float("inf")),
122
+ time_step_min: float = 0.001,
123
+ time_step_max: float = 0.1,
124
+ use_bias: bool = True,
125
+ norm_eps: float = 1e-5,
126
+ layer_idx: int = None,
127
+ backend: str = "cuda",
128
+ ) -> Mamba2:
129
+ super().__init__()
130
+
131
+ self.num_heads = num_heads
132
+ self.head_dim = head_dim
133
+ self.hidden_size = hidden_size
134
+ self.ssm_state_size = state_size
135
+ self.expand = expand
136
+ self.intermediate_size = int(expand * hidden_size)
137
+ self.n_groups = n_groups
138
+
139
+ self.conv_kernel_size = conv_kernel
140
+ self.use_conv_bias = use_conv_bias
141
+ self.activation = hidden_act
142
+ self.act = ACT2FN[hidden_act]
143
+
144
+ self.rms_norm = rms_norm
145
+ self.norm_eps = norm_eps
146
+
147
+ self.chunk_size = chunk_size
148
+
149
+ self.time_step_rank = int(time_step_rank)
150
+ self.time_step_limit = time_step_limit
151
+ self.time_step_min = time_step_min
152
+ self.time_step_max = time_step_max
153
+
154
+ self.conv_dim = self.intermediate_size + 2 * self.n_groups * self.ssm_state_size
155
+ self.conv1d = nn.Conv1d(
156
+ in_channels=self.conv_dim,
157
+ out_channels=self.conv_dim,
158
+ bias=use_conv_bias,
159
+ kernel_size=conv_kernel,
160
+ groups=self.conv_dim,
161
+ padding=conv_kernel - 1,
162
+ )
163
+
164
+ # projection of the input hidden states
165
+ projection_size = self.intermediate_size + self.conv_dim + self.num_heads
166
+ self.in_proj = nn.Linear(
167
+ self.hidden_size,
168
+ projection_size,
169
+ bias=use_bias,
170
+ )
171
+ # selective projection used to make dt, B and C input dependant
172
+
173
+ # time step projection (discretization)
174
+ # instantiate once and copy inv_dt in init_weights of PretrainedModel
175
+ # hard coded for now
176
+ dt_init_floor = 1e-4
177
+ dt = torch.exp(
178
+ torch.rand(self.num_heads) * (
179
+ math.log(self.time_step_max) - math.log(self.time_step_min)
180
+ ) + math.log(self.time_step_min)
181
+ )
182
+ dt = torch.clamp(dt, min=dt_init_floor)
183
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
184
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
185
+ self.dt_bias = nn.Parameter(inv_dt)
186
+
187
+ # S4D real initialization. These are not discretized!
188
+ # The core is to load them, compute the discrete states, then write the updated state. Keeps the memory bounded
189
+ A = torch.empty(self.num_heads, dtype=torch.float32).uniform_(0, 16)
190
+ self.A_log = nn.Parameter(torch.log(A))
191
+ self.A_log._no_weight_decay = True
192
+ self.norm = RMSNormGated(
193
+ self.intermediate_size, eps=self.norm_eps, norm_before_gate=False,
194
+ )
195
+ self.D = nn.Parameter(torch.ones(self.num_heads))
196
+ self.D._no_weight_decay = True
197
+
198
+ self.out_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=use_bias)
199
+ self.use_bias = use_bias
200
+
201
+ self.layer_idx = layer_idx
202
+
203
+ if not is_fast_path_available:
204
+ logger.warning_once(
205
+ "The fast path is not available because one of "
206
+ "`(selective_state_update)` is None. "
207
+ "Falling back to the naive implementation. "
208
+ "To install follow https://github.com/state-spaces/mamba/#installation",
209
+ )
210
+ import os
211
+ backend = os.environ.get('FLA_CONV_BACKEND', backend)
212
+ assert backend in ['cuda', 'triton'], f"Unsupported backend: {backend}"
213
+ if backend == 'cuda' and causal_conv1d_fn is None:
214
+ logger.warning_once(
215
+ "The CUDA backend is not available because `causal_conv1d` is None. "
216
+ "Falling back to the Triton backend. "
217
+ "To install follow https://github.com/Dao-AILab/causal-conv1d",
218
+ )
219
+ backend = 'triton'
220
+ if backend == 'triton':
221
+ from fla.modules.convolution import causal_conv1d as causal_conv1d_triton
222
+ from fla.modules.convolution import causal_conv1d_update as causal_conv1d_update_triton
223
+ self.causal_conv1d_fn = causal_conv1d_triton
224
+ self.causal_conv1d_update = causal_conv1d_update_triton
225
+ logger.warning(
226
+ "Mamba2 does not recommend using Triton's conv1d backend, "
227
+ "as it is untested and may contain bugs.",
228
+ )
229
+ else:
230
+ self.causal_conv1d_fn = causal_conv1d_fn
231
+ self.causal_conv1d_update = causal_conv1d_update
232
+ self.backend = backend
233
+
234
+ def cuda_kernels_forward(
235
+ self,
236
+ hidden_states: torch.Tensor,
237
+ last_state: dict | None = None,
238
+ use_cache: bool = False,
239
+ attention_mask: torch.Tensor | None = None,
240
+ ):
241
+ # 1. Gated MLP's linear projection
242
+ projected_states = self.in_proj(hidden_states)
243
+
244
+ # Set up dimensions for reshapes later
245
+ batch_size, seq_len, _ = hidden_states.shape
246
+ groups_time_state_size = self.n_groups * self.ssm_state_size
247
+ d_mlp = (
248
+ projected_states.shape[-1]
249
+ - 2 * self.intermediate_size
250
+ - 2 * self.n_groups * self.ssm_state_size
251
+ - self.num_heads
252
+ ) // 2
253
+
254
+ # Single step calculations via cache (decode)
255
+ if last_state is not None:
256
+ if hidden_states.shape[1] != 1:
257
+ raise ValueError("Mamba2 cached decoding only supports a single new token per step.")
258
+ conv_state = last_state['conv_state']
259
+ ssm_state = last_state['recurrent_state']
260
+
261
+ _, _, gate, hidden_states_B_C, dt = projected_states.squeeze(1).split(
262
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1,
263
+ )
264
+
265
+ # 2. Convolution sequence transformation
266
+ hidden_states_B_C = self.causal_conv1d_update(
267
+ hidden_states_B_C.contiguous(),
268
+ conv_state,
269
+ self.conv1d.weight.squeeze(1),
270
+ self.conv1d.bias,
271
+ self.activation,
272
+ )
273
+
274
+ hidden_states, B, C = torch.split(
275
+ hidden_states_B_C,
276
+ [
277
+ self.intermediate_size,
278
+ groups_time_state_size,
279
+ groups_time_state_size,
280
+ ],
281
+ dim=-1,
282
+ )
283
+
284
+ # 3. SSM transformation
285
+ A = -torch.exp(self.A_log.float()) # (nheads,)
286
+ A = A[:, None, ...][:, :, None].expand(-1, self.head_dim, self.ssm_state_size).to(dtype=torch.float32)
287
+ dt = dt[:, :, None].expand(-1, -1, self.head_dim)
288
+ dt_bias = self.dt_bias[:, None, ...].expand(-1, self.head_dim)
289
+ D = self.D[:, None, ...].expand(-1, self.head_dim)
290
+ B = B.view(batch_size, self.n_groups, B.shape[1] // self.n_groups)
291
+ C = C.view(batch_size, self.n_groups, C.shape[1] // self.n_groups)
292
+ hidden_states_reshaped = hidden_states.view(batch_size, self.num_heads, self.head_dim)
293
+
294
+ hidden_states = selective_state_update(
295
+ ssm_state,
296
+ hidden_states_reshaped,
297
+ dt,
298
+ A,
299
+ B,
300
+ C,
301
+ D,
302
+ z=None,
303
+ dt_bias=dt_bias,
304
+ dt_softplus=True,
305
+ )
306
+ hidden_states = hidden_states.view(batch_size, self.num_heads * self.head_dim)
307
+ hidden_states = self.norm(hidden_states, gate)
308
+
309
+ # 4. Final linear projection
310
+ out = self.out_proj(hidden_states)[:, None, ...]
311
+
312
+ # conv_state is updated in-place by causal_conv1d_update
313
+ # ssm_state is updated in-place by selective_state_update
314
+ return out, conv_state, ssm_state
315
+
316
+ # Fused calculations or step by step if no initialized cache is found (prefill)
317
+ else:
318
+ A = -torch.exp(self.A_log.float()) # (num_heads) or (intermediate_size, state_size)
319
+ dt_limit_kwargs = {} if self.time_step_limit == (0.0, float("inf")) else {"dt_limit": self.time_step_limit}
320
+
321
+ # 2-4. Fused kernel for conv1d, SSM, and the final projection
322
+ if self.training and not use_cache:
323
+ out = mamba_split_conv1d_scan_combined(
324
+ projected_states,
325
+ self.conv1d.weight.squeeze(1),
326
+ self.conv1d.bias,
327
+ self.dt_bias,
328
+ A,
329
+ D=self.D,
330
+ chunk_size=self.chunk_size,
331
+ seq_idx=None, # was seq_idx
332
+ activation=self.activation,
333
+ rmsnorm_weight=self.norm.weight,
334
+ rmsnorm_eps=self.norm.eps,
335
+ outproj_weight=self.out_proj.weight,
336
+ outproj_bias=self.out_proj.bias,
337
+ headdim=self.head_dim,
338
+ ngroups=self.n_groups,
339
+ norm_before_gate=False,
340
+ return_final_states=False,
341
+ **dt_limit_kwargs,
342
+ )
343
+ return out, None, None
344
+
345
+ else:
346
+ _, _, gate, hidden_states_B_C, dt = projected_states.split(
347
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1,
348
+ )
349
+
350
+ # 2. Convolution sequence transformation
351
+ hidden_states_B_C = apply_mask_to_padding_states(hidden_states_B_C, attention_mask)
352
+ # Compute conv_state for cache
353
+ new_conv_state = None
354
+ if use_cache:
355
+ hidden_states_B_C_transposed = hidden_states_B_C.transpose(1, 2)
356
+ new_conv_state = nn.functional.pad(
357
+ hidden_states_B_C_transposed,
358
+ (self.conv_kernel_size - hidden_states_B_C_transposed.shape[-1], 0),
359
+ )
360
+
361
+ if self.activation not in ["silu", "swish"]:
362
+ hidden_states_B_C = self.act(
363
+ self.conv1d(hidden_states_B_C.transpose(1, 2))[..., :seq_len].transpose(1, 2),
364
+ )
365
+ else:
366
+ _conv1d_output = self.causal_conv1d_fn(
367
+ x=hidden_states_B_C.transpose(1, 2).contiguous(),
368
+ weight=self.conv1d.weight.squeeze(1),
369
+ bias=self.conv1d.bias,
370
+ activation=self.activation,
371
+ )
372
+ if self.backend == 'cuda':
373
+ hidden_states_B_C = _conv1d_output
374
+ hidden_states_B_C = hidden_states_B_C.transpose(1, 2)
375
+ elif self.backend == 'triton':
376
+ hidden_states_B_C, _ = _conv1d_output
377
+ hidden_states_B_C = hidden_states_B_C.transpose(1, 2).contiguous()
378
+ else:
379
+ raise ValueError(f"Unsupported backend: {self.backend}")
380
+
381
+ hidden_states_B_C = (hidden_states_B_C * attention_mask[:, :, None]).to(hidden_states_B_C.dtype) \
382
+ if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1 \
383
+ else hidden_states_B_C
384
+ hidden_states, B, C = torch.split(
385
+ hidden_states_B_C,
386
+ [self.intermediate_size, groups_time_state_size, groups_time_state_size],
387
+ dim=-1,
388
+ )
389
+
390
+ # 3. SSM transformation
391
+ scan_output, ssm_state = mamba_chunk_scan_combined(
392
+ hidden_states.view(batch_size, seq_len, -1, self.head_dim),
393
+ dt,
394
+ A,
395
+ B.view(batch_size, seq_len, self.n_groups, -1),
396
+ C.view(batch_size, seq_len, self.n_groups, -1),
397
+ chunk_size=self.chunk_size,
398
+ D=self.D,
399
+ z=None,
400
+ seq_idx=None,
401
+ return_final_states=True,
402
+ dt_bias=self.dt_bias,
403
+ dt_softplus=True,
404
+ **dt_limit_kwargs,
405
+ )
406
+
407
+ scan_output = scan_output.view(batch_size, seq_len, -1)
408
+ # Multiply "gate" branch and apply extra normalization layer
409
+ scan_output = self.norm(scan_output, gate)
410
+
411
+ # 4. Final linear projection
412
+ out = self.out_proj(scan_output)
413
+
414
+ return out, new_conv_state, ssm_state
415
+
416
+ # fmt: off
417
+ def torch_forward(
418
+ self,
419
+ input_states,
420
+ last_state: dict | None = None,
421
+ use_cache: bool = False,
422
+ attention_mask: torch.Tensor | None = None,
423
+ ):
424
+ batch_size, seq_len, _ = input_states.shape
425
+ dtype = input_states.dtype
426
+
427
+ # 1. Gated MLP's linear projection
428
+ projected_states = self.in_proj(input_states)
429
+ d_mlp = (projected_states.shape[-1] - 2 * self.intermediate_size -
430
+ 2 * self.n_groups * self.ssm_state_size - self.num_heads) // 2
431
+ _, _, gate, hidden_states_B_C, dt = projected_states.split(
432
+ [d_mlp, d_mlp, self.intermediate_size, self.conv_dim, self.num_heads], dim=-1,
433
+ )
434
+
435
+ # 2. Convolution sequence transformation
436
+ if last_state is not None:
437
+ if input_states.shape[1] != 1:
438
+ raise ValueError("Mamba2 cached decoding only supports a single new token per step.")
439
+ # Decode path: single-step update
440
+ conv_state = last_state['conv_state']
441
+ ssm_state = last_state['recurrent_state']
442
+
443
+ conv_state = conv_state.roll(shifts=-1, dims=-1)
444
+ conv_state[:, :, -1] = hidden_states_B_C[:, 0, :].to(conv_state.device)
445
+
446
+ # We need to guarantee that anything regarding the cache is on the same device
447
+ conv_states_for_compute = conv_state.to(device=self.conv1d.weight.device)
448
+
449
+ hidden_states_B_C = torch.sum(
450
+ conv_states_for_compute * self.conv1d.weight.squeeze(1), dim=-1,
451
+ )
452
+ if self.use_conv_bias:
453
+ hidden_states_B_C = hidden_states_B_C + self.conv1d.bias
454
+ hidden_states_B_C = self.act(hidden_states_B_C)
455
+ else:
456
+ # Prefill path
457
+ hidden_states_B_C = apply_mask_to_padding_states(hidden_states_B_C, attention_mask)
458
+ new_conv_state = None
459
+ if use_cache:
460
+ hidden_states_B_C_transposed = hidden_states_B_C.transpose(1, 2)
461
+ new_conv_state = nn.functional.pad(
462
+ hidden_states_B_C_transposed, (self.conv_kernel_size - hidden_states_B_C_transposed.shape[-1], 0),
463
+ )
464
+
465
+ hidden_states_B_C = self.act(self.conv1d(hidden_states_B_C.transpose(1, 2))[..., :seq_len].transpose(1, 2))
466
+
467
+ if last_state is None:
468
+ hidden_states_B_C = (hidden_states_B_C * attention_mask[:, :, None]).to(hidden_states_B_C.dtype) \
469
+ if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1 \
470
+ else hidden_states_B_C
471
+ hidden_states, B, C = torch.split(
472
+ hidden_states_B_C,
473
+ [self.intermediate_size, self.n_groups * self.ssm_state_size, self.n_groups * self.ssm_state_size],
474
+ dim=-1,
475
+ )
476
+
477
+ # 3. SSM transformation
478
+ A = -torch.exp(self.A_log.float()) # [num_heads]
479
+ if last_state is not None:
480
+ # Decode path
481
+ cache_device = ssm_state.device
482
+
483
+ # Note: there is no need to pad parameter matrices here, as there is just one new token
484
+ # for batched generation
485
+ dt = dt[:, 0, :][:, None, ...]
486
+ dt = dt.transpose(1, 2).expand(batch_size, dt.shape[-1], self.head_dim)
487
+ # [num_heads] -> [num_heads, head_dim]
488
+ dt_bias = self.dt_bias[..., None].expand(self.dt_bias.shape[0], self.head_dim)
489
+
490
+ dt = torch.nn.functional.softplus(dt + dt_bias.to(dt.dtype))
491
+ dt = torch.clamp(dt, self.time_step_limit[0], self.time_step_limit[1])
492
+ A = A[..., None, None].expand(self.num_heads, self.head_dim, self.ssm_state_size).to(dtype=torch.float32)
493
+ # [bsz, num_heads, head_dim, state_size]
494
+ dA = (torch.exp(dt[..., None] * A)).to(device=cache_device)
495
+
496
+ # Discretize B
497
+ # [bsz, n_groups * state_size] -> [bsz, n_groups, 1, state_size] ->
498
+ # -> [bsz, n_groups, group to head repetition factor, state_size] -> [bsz, num_heads, state_size]
499
+ B = B.reshape(batch_size, self.n_groups, -1)[..., None, :]
500
+ B = B.expand(batch_size, self.n_groups, self.num_heads // self.n_groups, B.shape[-1]).contiguous()
501
+ B = B.reshape(batch_size, -1, B.shape[-1])
502
+ # [bsz, num_heads, head_dim, state_size]
503
+ dB = dt[..., None] * B[..., None, :]
504
+
505
+ # Discretize x into dB
506
+ # [bsz, intermediate_size] -> [bsz, num_heads, head_dim]
507
+ hidden_states = hidden_states.reshape(batch_size, -1, self.head_dim)
508
+ dBx = (dB * hidden_states[..., None]).to(device=cache_device)
509
+
510
+ # State calculation
511
+ ssm_state = ssm_state * dA + dBx
512
+
513
+ # Subsequent output
514
+ # [bsz, n_groups * state_size] -> [bsz, num_heads, state_size]
515
+ C = C.reshape(batch_size, self.n_groups, -1)[..., None, :]
516
+ C = C.expand(batch_size, self.n_groups, self.num_heads // self.n_groups, C.shape[-1]).contiguous()
517
+ C = C.reshape(batch_size, -1, C.shape[-1])
518
+ # [bsz, num_heads, head_dim]
519
+
520
+ ssm_states_for_compute = ssm_state.to(device=C.device, dtype=C.dtype) # Shape: [b, h, d, n]
521
+ # Reshape ssm_states to merge the first two dimensions
522
+ # Shape: [b*h, d, n]
523
+ ssm_states_reshaped = ssm_states_for_compute.view(batch_size * self.num_heads, self.head_dim, self.ssm_state_size)
524
+ C_reshaped = C.view(batch_size * self.num_heads, self.ssm_state_size, 1) # Shape: [b*h, n, 1]
525
+ y = torch.bmm(ssm_states_reshaped, C_reshaped)
526
+ y = y.view(batch_size, self.num_heads, self.head_dim)
527
+
528
+ # D skip connection
529
+ # [num_heads] -> [num_heads, head_dim]
530
+ D = self.D[..., None].expand(self.D.shape[0], self.head_dim)
531
+ y = (y + hidden_states * D).to(y.dtype)
532
+
533
+ # [bsz, num_heads, head_dim] -> [bsz, 1, intermediate_size]
534
+ y = y.reshape(batch_size, -1)[:, None, ...]
535
+
536
+ scan_output = self.norm(y, gate)
537
+ contextualized_states = self.out_proj(scan_output.to(dtype))
538
+ return contextualized_states, conv_state, ssm_state
539
+ else:
540
+ # Prefill path
541
+ # begin ssd naive implementation without einsums
542
+ dt = nn.functional.softplus(dt + self.dt_bias)
543
+ dt = torch.clamp(dt, self.time_step_limit[0], self.time_step_limit[1])
544
+ hidden_states = hidden_states.reshape(batch_size, seq_len, -1, self.head_dim).float()
545
+ B = B.reshape(batch_size, seq_len, -1, self.ssm_state_size).float()
546
+ C = C.reshape(batch_size, seq_len, -1, self.ssm_state_size).float()
547
+ B = B.repeat(1, 1, self.num_heads // self.n_groups, 1)
548
+ C = C.repeat(1, 1, self.num_heads // self.n_groups, 1)
549
+ pad_size = (self.chunk_size - seq_len % self.chunk_size) % self.chunk_size
550
+
551
+ D_residual = self.D[..., None] * pad_tensor_by_size(hidden_states, pad_size)
552
+
553
+ # Discretize x and A
554
+ hidden_states = hidden_states * dt[..., None]
555
+ A = A.to(hidden_states.dtype) * dt
556
+
557
+ # Rearrange into blocks/chunks
558
+ hidden_states, A, B, C = [reshape_into_chunks(t, pad_size, self.chunk_size) for t in (hidden_states, A, B, C)]
559
+
560
+ # [bsz, -1, chunk_size, num_heads] -> [bsz, num_heads, -1, chunk_size]
561
+ A = A.permute(0, 3, 1, 2)
562
+ A_cumsum = torch.cumsum(A, dim=-1)
563
+
564
+ # 1. Compute the output for each intra-chunk (diagonal blocks)
565
+ # This is the analog of a causal mask
566
+ L = torch.exp(segment_sum(A))
567
+
568
+ # Contraction of C and B to get G (attention-weights like)
569
+ # shape: (b, c, l, s, h, n)
570
+ G_intermediate = C[:, :, :, None, :, :] * B[:, :, None, :, :, :]
571
+ G = G_intermediate.sum(dim=-1) # shape: (b, c, l, s, h)
572
+
573
+ # Compute M, equivalent to applying attention mask to weights
574
+ M_intermediate = G[..., None] * L.permute(0, 2, 3, 4, 1)[..., None]
575
+ M = M_intermediate.sum(dim=-1)
576
+
577
+ # Compute Y_diag (apply to values)
578
+ Y_diag = (M[..., None] * hidden_states[:, :, None]).sum(dim=3)
579
+
580
+ # 2. Compute the state for each intra-chunk
581
+ # (right term of low-rank factorization of off-diagonal blocks; B terms)
582
+ decay_states = torch.exp(A_cumsum[:, :, :, -1:] - A_cumsum)
583
+ B_decay = B * decay_states.permute(0, -2, -1, 1)[..., None]
584
+ states = (B_decay[..., None, :] * hidden_states[..., None]).sum(dim=2)
585
+
586
+ # 3. Compute the inter-chunk SSM recurrence; produces correct SSM states at chunk boundaries
587
+ # (middle term of factorization of off-diag blocks; A terms)
588
+ previous_states = torch.zeros_like(states[:, :1])
589
+ states = torch.cat([previous_states, states], dim=1)
590
+ decay_chunk = torch.exp(segment_sum(nn.functional.pad(A_cumsum[:, :, :, -1], (1, 0))))
591
+ decay_chunk = decay_chunk.transpose(1, 3)
592
+ new_states = (decay_chunk[..., None, None] * states[:, :, None, ...]).sum(dim=1)
593
+ states, ssm_state = new_states[:, :-1], new_states[:, -1]
594
+
595
+ # 4. Compute state -> output conversion per chunk
596
+ # (left term of low-rank factorization of off-diagonal blocks; C terms)
597
+ state_decay_out = torch.exp(A_cumsum)
598
+ C_times_states = (C[..., None, :] * states[:, :, None, ...])
599
+ state_decay_out_permuted = state_decay_out.permute(0, 2, 3, 1)
600
+ Y_off = (C_times_states.sum(-1) * state_decay_out_permuted[..., None])
601
+
602
+ # Add output of intra-chunk and inter-chunk terms (diagonal and off-diagonal blocks)
603
+ y = Y_diag + Y_off
604
+ # [bsz, -1, self.chunk_size, num_heads, head_dim] -> [bsz, (padded) seq_len, num_heads, head_dim]
605
+ y = y.reshape(batch_size, -1, self.num_heads, self.head_dim)
606
+
607
+ y = y + D_residual
608
+ # Cutting off padded chunks
609
+ if pad_size > 0:
610
+ y = y[:, :seq_len, :, :]
611
+ y = y.reshape(batch_size, seq_len, -1)
612
+
613
+ scan_output = self.norm(y, gate)
614
+
615
+ # end ssd naive
616
+
617
+ # 4. Final linear projection
618
+ contextualized_states = self.out_proj(scan_output.to(dtype)) # [batch, seq_len, hidden_size]
619
+ return contextualized_states, new_conv_state if use_cache else None, ssm_state
620
+ # fmt: on
621
+
622
+ def forward(
623
+ self,
624
+ hidden_states: torch.Tensor,
625
+ attention_mask: torch.Tensor | None = None,
626
+ past_key_values: Cache | None = None,
627
+ use_cache: bool | None = False,
628
+ output_attentions: bool | None = False,
629
+ **kwargs,
630
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
631
+ last_state = get_layer_cache(self, past_key_values)
632
+
633
+ if is_fast_path_available and "cuda" in self.in_proj.weight.device.type:
634
+ output, conv_state, ssm_state = self.cuda_kernels_forward(hidden_states, last_state, use_cache, attention_mask)
635
+ else:
636
+ dtype = hidden_states.dtype
637
+ if last_state is None and attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1:
638
+ hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
639
+ output, conv_state, ssm_state = self.torch_forward(hidden_states, last_state, use_cache, attention_mask)
640
+
641
+ update_layer_cache(
642
+ self,
643
+ past_key_values,
644
+ recurrent_state=ssm_state,
645
+ conv_state=conv_state,
646
+ offset=hidden_states.shape[1],
647
+ )
648
+
649
+ return output, None, past_key_values
fla/layers/mesa_net.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from einops import rearrange
10
+ from torch.nn import functional as F
11
+
12
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
13
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
14
+ from fla.modules.l2norm import l2_norm
15
+ from fla.ops.mesa_net import chunk_mesa_net, mesa_net_decoding_one_step
16
+
17
+ if TYPE_CHECKING:
18
+ from transformers.processing_utils import Unpack
19
+
20
+ from fla.models.utils import Cache
21
+
22
+
23
+ class MesaNet(nn.Module):
24
+ """
25
+ The layer implementaion for [MesaNet: Sequence Modeling by Locally Optimal Test-Time Training]. # noqa
26
+
27
+ Args:
28
+ hidden_size (int, Optional):
29
+ The hidden size of the input. Default: 2048.
30
+ expand_v (float, Optional):
31
+ The expansion ratio for the value dim. Default: 1.
32
+ num_heads (int, Optional):
33
+ The number of heads. Default: 16.
34
+ mode (str, Optional):
35
+ Which MesaNet kernel to use.
36
+ Currently available: `chunk`.
37
+ Default: `chunk`.
38
+ use_output_gate (bool, Optional):
39
+ Whether to use output gate. Default: `False`.
40
+ conv_size (int):
41
+ The kernel size of the short convolution. Default: 4.
42
+ layer_idx (int, Optional):
43
+ The index of the layer. Default: None.
44
+ norm_eps (float, Optional):
45
+ The epsilon value for the normalization layer. Default: 1e-5.
46
+ lambda_lower_bound (float):
47
+ The lower bound for the lambda parameter. Default: 0.25.
48
+ max_cg_step_training (int):
49
+ The maximum number of CG steps for training. Default: 30.
50
+ max_cg_step_decoding (int):
51
+ The maximum number of CG steps for decoding. Default: 30.
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ hidden_size: int = 2048,
57
+ num_heads: int = 16,
58
+ head_dim: int = 128,
59
+ mode: str = 'chunk',
60
+ use_output_gate: bool = False,
61
+ use_short_conv: bool = True,
62
+ conv_size: int = 4,
63
+ conv_bias: bool = False,
64
+ layer_idx: int = None,
65
+ norm_eps: float = 1e-5,
66
+ lambda_lower_bound: float = 0.25,
67
+ max_cg_step_training: int = 30,
68
+ max_cg_step_decoding: int = 30,
69
+ **kwargs,
70
+ ) -> MesaNet:
71
+ super().__init__()
72
+
73
+ self.mode = mode
74
+ self.hidden_size = hidden_size
75
+ self.use_output_gate = use_output_gate
76
+ self.use_short_conv = use_short_conv
77
+ self.conv_size = conv_size
78
+ self.conv_bias = conv_bias
79
+ self.num_heads = num_heads
80
+ self.head_dim = head_dim
81
+ self.key_dim = self.num_heads * self.head_dim
82
+ self.value_dim = self.key_dim
83
+ self.head_k_dim = self.head_dim
84
+ self.head_v_dim = self.head_dim
85
+ self.layer_idx = layer_idx
86
+ self.lambda_lower_bound = lambda_lower_bound
87
+ self.max_cg_step_training = max_cg_step_training
88
+ self.max_cg_step_decoding = max_cg_step_decoding
89
+
90
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
91
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
92
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
93
+ self.a_proj = nn.Linear(hidden_size, self.num_heads, bias=True)
94
+ self.b_proj = nn.Linear(hidden_size, self.num_heads, bias=True)
95
+
96
+ lambda_initial_value = 1.0
97
+ init_lamb_value = torch.log(torch.exp(torch.tensor(lambda_initial_value - lambda_lower_bound)) - 1.0)
98
+ init_lamb_params = torch.empty(self.key_dim, dtype=torch.float32).fill_(init_lamb_value)
99
+
100
+ self.lambda_params = nn.Parameter(init_lamb_params)
101
+ self.lambda_params._no_weight_decay = True
102
+
103
+ self.conv_size = conv_size
104
+ self.q_conv1d = ShortConvolution(
105
+ hidden_size=self.key_dim,
106
+ kernel_size=conv_size,
107
+ bias=self.conv_bias,
108
+ activation='silu',
109
+ )
110
+ self.k_conv1d = ShortConvolution(
111
+ hidden_size=self.key_dim,
112
+ kernel_size=conv_size,
113
+ bias=self.conv_bias,
114
+ activation='silu',
115
+ )
116
+ if use_output_gate:
117
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
118
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, eps=norm_eps)
119
+ else:
120
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
121
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
122
+
123
+ def forward(
124
+ self,
125
+ hidden_states: torch.Tensor,
126
+ attention_mask: torch.Tensor | None = None,
127
+ past_key_values: Cache | None = None,
128
+ use_cache: bool | None = False,
129
+ output_attentions: bool | None = False,
130
+ **kwargs: Unpack[dict],
131
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
132
+ if attention_mask is not None:
133
+ assert len(attention_mask.shape) == 2, (
134
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
135
+ "for padding purposes (0 indicating padding). "
136
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
137
+ )
138
+
139
+ batch_size, q_len, _ = hidden_states.shape
140
+ last_state = get_layer_cache(self, past_key_values)
141
+
142
+ cu_seqlens = kwargs.get('cu_seqlens')
143
+ if attention_mask is not None:
144
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
145
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
146
+
147
+ conv_state_q, conv_state_k = None, None
148
+ if last_state is not None:
149
+ conv_state_q, conv_state_k = last_state['conv_state']
150
+ q, conv_state_q = self.q_conv1d(
151
+ x=self.q_proj(hidden_states),
152
+ cache=conv_state_q,
153
+ output_final_state=use_cache,
154
+ cu_seqlens=cu_seqlens,
155
+ )
156
+ k, conv_state_k = self.k_conv1d(
157
+ x=self.k_proj(hidden_states),
158
+ cache=conv_state_k,
159
+ output_final_state=use_cache,
160
+ cu_seqlens=cu_seqlens,
161
+ )
162
+ v = self.v_proj(hidden_states)
163
+
164
+ q, k = map(lambda x: rearrange(x, '... (h d) -> ... h d', d=self.head_k_dim), (q, k))
165
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
166
+ beta = self.b_proj(hidden_states).float().sigmoid()
167
+ g = F.logsigmoid(self.a_proj(hidden_states).float())
168
+ lamb = F.softplus(self.lambda_params.float()) + self.lambda_lower_bound
169
+ lamb = lamb.reshape(self.num_heads, -1)
170
+
171
+ last_h_kk, last_h_kv = last_state['recurrent_state'] if last_state is not None else (None, None)
172
+
173
+ # prefilling or training
174
+ # Note that QK will be normalized inside the kernel to avoid saving the activations, thereby reducing the memory usage.
175
+ if last_state is None:
176
+ o, h_kk, h_kv = chunk_mesa_net(
177
+ q=q,
178
+ k=k,
179
+ v=v,
180
+ g=g,
181
+ beta=beta,
182
+ lamb=lamb,
183
+ output_final_state=use_cache,
184
+ max_CG_iteration=self.max_cg_step_training,
185
+ use_qk_l2norm_in_kernel=True,
186
+ cu_seqlens=cu_seqlens,
187
+ )
188
+ # decoding
189
+ else:
190
+ q = l2_norm(q)
191
+ k = l2_norm(k)
192
+ o, h_kk, h_kv = mesa_net_decoding_one_step(
193
+ q=q.squeeze(0),
194
+ k=k.squeeze(0),
195
+ v=v.squeeze(0),
196
+ g=g.squeeze(0),
197
+ beta=beta.squeeze(0),
198
+ lamb=lamb,
199
+ prev_h_kk=last_h_kk,
200
+ prev_h_kv=last_h_kv,
201
+ max_CG_iteration=self.max_cg_step_decoding,
202
+ )
203
+ o = o.unsqueeze(0).to(q)
204
+
205
+ update_layer_cache(
206
+ self,
207
+ past_key_values,
208
+ recurrent_state=(h_kk, h_kv),
209
+ conv_state=(conv_state_q, conv_state_k),
210
+ offset=q_len,
211
+ )
212
+ if self.use_output_gate:
213
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
214
+ o = self.o_norm(o, g)
215
+ else:
216
+ o = self.o_norm(o)
217
+ o = rearrange(o, 'b t h d -> b t (h d)')
218
+ o = self.o_proj(o)
219
+ if attention_mask is not None:
220
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
221
+ return o, None, past_key_values
fla/layers/mla.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ """ Implementing the Deepseek Multi Latent Attention (MLA) module. Reference:
4
+
5
+ https://github.com/huggingface/transformers/blob/main/src/transformers/models/deepseek_v3/modeling_deepseek_v3.py#L328
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import math
11
+ import warnings
12
+ from typing import TYPE_CHECKING
13
+
14
+ import torch
15
+ import torch.nn as nn
16
+ import torch.nn.functional as F
17
+ from einops import rearrange, repeat
18
+ from transformers.utils import logging
19
+
20
+ from fla.layers.utils import pad_input, unpad_input
21
+ from fla.modules import RMSNorm, RotaryEmbedding
22
+ from fla.ops.utils.index import prepare_lens_from_mask
23
+
24
+ if TYPE_CHECKING:
25
+ from fla.models.utils import Cache
26
+
27
+ try:
28
+ from flash_attn import flash_attn_func, flash_attn_varlen_func
29
+ except ImportError:
30
+ warnings.warn(
31
+ "Flash Attention is not installed. Please install it via `pip install flash-attn --no-build-isolation`",
32
+ category=ImportWarning,
33
+ )
34
+ flash_attn_func = None
35
+
36
+ logger = logging.get_logger(__name__)
37
+
38
+
39
+ def yarn_get_mscale(scale=1, mscale=1):
40
+ if scale <= 1:
41
+ return 1.0
42
+ return 0.1 * mscale * math.log(scale) + 1.0
43
+
44
+
45
+ class MultiheadLatentAttention(nn.Module):
46
+ r"""
47
+ Multi-headed attention from [Deepseek V2](https://arxiv.org/abs/2405.04434)
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ hidden_size: int = 2048,
53
+ num_heads: int = 16,
54
+ q_lora_rank: int | None = 1536, # q lora rank is optional, None indicates no q lora
55
+ qk_rope_head_dim: int = 64,
56
+ kv_lora_rank: int = 512, # following the original Deepseek paper
57
+ v_head_dim: int = 128,
58
+ qk_nope_head_dim: int = 128,
59
+ qk_head_dim: int | None = 192, # qk_nope_head_dim + qk_rope_head_dim
60
+ window_size: int | None = None,
61
+ rope_theta: float = 10000.,
62
+ max_position_embeddings: int | None = None,
63
+ rope_scaling: dict | None = None,
64
+ layer_idx: int = None,
65
+ ) -> MultiheadLatentAttention:
66
+ super().__init__()
67
+
68
+ # sanity check
69
+ if qk_head_dim is not None:
70
+ assert qk_head_dim == qk_nope_head_dim + qk_rope_head_dim, \
71
+ f"qk_head_dim {qk_head_dim} != qk_nope_head_dim {qk_nope_head_dim} + qk_rope_head_dim {qk_rope_head_dim}"
72
+ else:
73
+ qk_head_dim = qk_nope_head_dim + qk_rope_head_dim
74
+
75
+ # attention params info
76
+ self.hidden_size = hidden_size
77
+ self.num_heads = num_heads
78
+ self.q_lora_rank = q_lora_rank
79
+ self.qk_rope_head_dim = qk_rope_head_dim
80
+ self.kv_lora_rank = kv_lora_rank
81
+ self.v_head_dim = v_head_dim
82
+ self.qk_nope_head_dim = qk_nope_head_dim
83
+ self.qk_head_dim = qk_head_dim
84
+
85
+ self.window_size = window_size
86
+ self.rope_theta = rope_theta
87
+ self.max_position_embeddings = max_position_embeddings
88
+ self.layer_idx = layer_idx
89
+
90
+ if flash_attn_func is None:
91
+ raise ImportError("Please install Flash Attention via `pip install flash-attn --no-build-isolation` first")
92
+
93
+ if q_lora_rank is not None:
94
+ self.q_proj = nn.Sequential(
95
+ nn.Linear(hidden_size, q_lora_rank, bias=False),
96
+ RMSNorm(q_lora_rank, dtype=torch.float32),
97
+ nn.Linear(q_lora_rank, self.num_heads * self.qk_head_dim, bias=False),
98
+ )
99
+ else:
100
+ self.q_proj = nn.Linear(hidden_size, self.num_heads * self.qk_head_dim, bias=False)
101
+
102
+ self.k_rope = nn.Linear(hidden_size, self.qk_rope_head_dim, bias=False)
103
+ self.kv_proj = nn.Sequential(
104
+ nn.Linear(hidden_size, self.kv_lora_rank, bias=False),
105
+ RMSNorm(self.kv_lora_rank, dtype=torch.float32),
106
+ nn.Linear(self.kv_lora_rank, self.num_heads * (self.qk_nope_head_dim + self.v_head_dim), bias=False),
107
+ )
108
+
109
+ self.o_proj = nn.Linear(self.num_heads * self.v_head_dim, hidden_size, bias=False)
110
+
111
+ self.scaling = self.qk_head_dim ** (-0.5)
112
+ if rope_scaling is not None and rope_scaling.get("rope_type", "default") != "default":
113
+ mscale_all_dim = rope_scaling.get("mscale_all_dim", 0)
114
+ scaling_factor = rope_scaling["factor"]
115
+ if mscale_all_dim:
116
+ mscale = yarn_get_mscale(scaling_factor, mscale_all_dim)
117
+ self.scaling = self.scaling * mscale * mscale
118
+
119
+ self.rotary = RotaryEmbedding(dim=self.qk_rope_head_dim, base=self.rope_theta)
120
+
121
+ def forward(
122
+ self,
123
+ hidden_states: torch.Tensor,
124
+ attention_mask: torch.Tensor | None,
125
+ past_key_values: Cache | None = None,
126
+ output_attentions: bool = False,
127
+ use_cache: bool = False,
128
+ **kwargs,
129
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
130
+ # if attention_mask is not None, this is doing inference
131
+ if attention_mask is not None:
132
+ assert len(attention_mask.shape) == 2, (
133
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
134
+ "for padding purposes (0 indicating padding). "
135
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
136
+ )
137
+
138
+ # prepare q, k, v
139
+ batch_size, q_len, _ = hidden_states.shape
140
+
141
+ q_states = self.q_proj(hidden_states)
142
+ q_states = rearrange(q_states, '... (h d) -> ... h d', d=self.qk_head_dim)
143
+ q_pass, q_rot = torch.split(q_states, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1)
144
+ k_pass, k_rot = self.kv_proj(hidden_states), self.k_rope(hidden_states)
145
+
146
+ k_rot = rearrange(k_rot, 'b t d -> b t 1 d')
147
+ k_pass = rearrange(k_pass, '... (h d) -> ... h d', d=self.qk_nope_head_dim + self.v_head_dim)
148
+ k_pass, v = torch.split(k_pass, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
149
+
150
+ # apply rotary position embedding
151
+ seqlen_offset, max_seqlen = 0, q_len
152
+ if past_key_values is not None:
153
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
154
+ max_seqlen = q_len + seqlen_offset
155
+
156
+ if attention_mask is not None:
157
+ seqlen_offset = seqlen_offset + prepare_lens_from_mask(attention_mask) - attention_mask.shape[-1]
158
+ max_seqlen = q_len + max(seqlen_offset)
159
+
160
+ if self.max_position_embeddings is not None:
161
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
162
+ cu_seqlens = kwargs.get("cu_seqlens")
163
+ q_rot, k_rot = self.rotary(
164
+ q_rot, k_rot, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens,
165
+ )
166
+
167
+ k_rot = repeat(k_rot, 'b t 1 d -> b t h d', h=self.num_heads)
168
+ q = torch.cat((q_pass, q_rot), dim=-1)
169
+ k = torch.cat((k_pass, k_rot), dim=-1)
170
+
171
+ # TODO: instead of caching the full k, v, we can actually only cache the compressed_kv and k_rot
172
+ # and recover the full k, v from compressed_kv and k_rot
173
+ if past_key_values is not None:
174
+ cache_has_content = past_key_values.get_seq_length(self.layer_idx) > 0
175
+ k_cached, v_cached = past_key_values.update(
176
+ attn_state=(k, v),
177
+ layer_idx=self.layer_idx,
178
+ offset=q_len,
179
+ )['attn_state']
180
+ if cache_has_content:
181
+ k, v = k_cached, v_cached
182
+
183
+ # Head dim match to use flash-attn
184
+ if self.qk_head_dim != self.v_head_dim:
185
+ v = F.pad(v, [0, self.qk_head_dim - self.v_head_dim])
186
+
187
+ # Contains at least one padding token in the sequence
188
+ if attention_mask is not None:
189
+ if q.shape[1] == 1 and self.window_size is not None:
190
+ attention_mask = attention_mask[:, -self.window_size:]
191
+ q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input(q, (k, v), attention_mask, q_len)
192
+ cu_seqlens_q, cu_seqlens_k = cu_seqlens
193
+ max_seqlen_q, max_seqlen_k = max_seq_lens
194
+ o = flash_attn_varlen_func(
195
+ q, k, v,
196
+ cu_seqlens_q=cu_seqlens_q,
197
+ cu_seqlens_k=cu_seqlens_k,
198
+ max_seqlen_q=max_seqlen_q,
199
+ max_seqlen_k=max_seqlen_k,
200
+ causal=True,
201
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
202
+ )
203
+ o = pad_input(o, indices_q, batch_size, q_len)
204
+ elif cu_seqlens is not None:
205
+ o = flash_attn_varlen_func(
206
+ q.squeeze(0), k.squeeze(0), v.squeeze(0),
207
+ cu_seqlens_q=cu_seqlens,
208
+ cu_seqlens_k=cu_seqlens,
209
+ max_seqlen_q=max_seqlen,
210
+ max_seqlen_k=max_seqlen,
211
+ causal=True,
212
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
213
+ ).unsqueeze(0)
214
+ else:
215
+ o = flash_attn_func(
216
+ q, k, v,
217
+ causal=True,
218
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
219
+ )
220
+
221
+ if self.qk_head_dim != self.v_head_dim:
222
+ o = o[:, :, :, :self.v_head_dim]
223
+ o = o.reshape(batch_size, q_len, -1)
224
+ o = self.o_proj(o)
225
+ return o, None, past_key_values
fla/layers/mom.py ADDED
@@ -0,0 +1,831 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from __future__ import annotations
3
+
4
+ import math
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from einops import rearrange
10
+ from torch.nn import functional as F
11
+
12
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
13
+ from fla.ops.gated_delta_rule import chunk_gated_delta_rule, fused_recurrent_gated_delta_rule
14
+
15
+ if TYPE_CHECKING:
16
+ from transformers.processing_utils import Unpack
17
+
18
+ from fla.models.utils import Cache
19
+
20
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, unpad_input, update_layer_cache
21
+
22
+
23
+ def _upad_input(
24
+ query_layer: torch.Tensor,
25
+ key_layer: torch.Tensor,
26
+ value_layer: torch.Tensor,
27
+ gate_layer: torch.Tensor,
28
+ beta_layer: torch.Tensor,
29
+ attention_mask: torch.Tensor,
30
+ ):
31
+ """
32
+ Unpads query, key, and values tensors, using a single dimension for all tokens even though they belong to
33
+ different batches.
34
+
35
+ This function is used instead of `flash_attn.bert_padding.unpad_input` in order to avoid the recomputation
36
+ of the same intermediary
37
+ tensors for query, key, value tensors.
38
+
39
+ Arguments:
40
+ query_layer (`torch.Tensor`):
41
+ Query state with padding. Shape: (batch_size, query_length, num_heads, head_dim).
42
+ key_layer (`torch.Tensor`):
43
+ Key state with padding. Shape: (batch_size, kv_seq_len, num_key_value_heads, head_dim).
44
+ value_layer (`torch.Tensor`):
45
+ Value state with padding. Shape: (batch_size, kv_seq_len, num_key_value_heads, head_dim).
46
+ attention_mask (`torch.Tensor`):
47
+ Boolean or int tensor of shape (batch_size, sequence_length), 1 means valid and 0 means not valid.
48
+ query_length (`int`):
49
+ Target length.
50
+
51
+ Return:
52
+ query_layer (`torch.Tensor`):
53
+ Query state without padding. Shape: (total_target_length, num_heads, head_dim).
54
+ key_layer (`torch.Tensor`):
55
+ Key state with padding. Shape: (total_source_length, num_key_value_heads, head_dim).
56
+ value_layer (`torch.Tensor`):
57
+ Value state with padding. Shape: (total_source_length, num_key_value_heads, head_dim).
58
+ indices_q (`torch.Tensor`):
59
+ The indices of non-masked tokens from the flattened input target sequence.
60
+ (cu_seqlens_q, cu_seqlens_k) (`Tuple[int]`):
61
+ The cumulative sequence lengths for the target (query) and source (key, value), used to index
62
+ into ragged (unpadded) tensors. `cu_seqlens` shape is (batch_size + 1,).
63
+ (max_seqlen_in_batch_q, max_seqlen_in_batch_k) (`Tuple[int]`):
64
+ Maximum sequence length in batch (`max_seqlen_in_batch_q` for the target sequence i.e. query,
65
+ `max_seqlen_in_batch_k` for the source sequence i.e. key/value).
66
+ """
67
+ query_length = query_layer.shape[1]
68
+ indices_k, cu_seqlens_k, max_seqlen_in_batch_k = get_unpad_data(attention_mask)
69
+ batch_size, kv_seq_len, dim = key_layer.shape
70
+ v_dim = value_layer.shape[-1]
71
+
72
+ key_layer = index_first_axis(key_layer.reshape(batch_size * kv_seq_len, dim), indices_k)
73
+ value_layer = index_first_axis(
74
+ value_layer.reshape(batch_size * kv_seq_len, v_dim), indices_k,
75
+ )
76
+ gate_layer = index_first_axis(gate_layer.reshape(batch_size * kv_seq_len, -1), indices_k)
77
+ beta_layer = index_first_axis(beta_layer.reshape(batch_size * kv_seq_len, -1), indices_k)
78
+ if query_length == kv_seq_len:
79
+ query_layer = index_first_axis(query_layer.reshape(batch_size * kv_seq_len, dim), indices_k)
80
+ cu_seqlens_q = cu_seqlens_k
81
+ max_seqlen_in_batch_q = max_seqlen_in_batch_k
82
+ indices_q = indices_k
83
+ elif query_length == 1:
84
+ max_seqlen_in_batch_q = 1
85
+ cu_seqlens_q = torch.arange(
86
+ batch_size + 1, dtype=torch.int32, device=query_layer.device,
87
+ ) # There is a memcpy here, that is very bad.
88
+ indices_q = cu_seqlens_q[:-1]
89
+ query_layer = query_layer.squeeze(1)
90
+ else:
91
+ # The -q_len: slice assumes left padding.
92
+ attention_mask = attention_mask[:, -query_length:]
93
+ query_layer, indices_q, cu_seqlens_q, max_seqlen_in_batch_q = unpad_input(query_layer, attention_mask)
94
+
95
+ return (
96
+ query_layer,
97
+ key_layer,
98
+ value_layer,
99
+ gate_layer,
100
+ beta_layer,
101
+ indices_q,
102
+ (cu_seqlens_q, cu_seqlens_k),
103
+ (max_seqlen_in_batch_q, max_seqlen_in_batch_k),
104
+ )
105
+
106
+
107
+ def transform(
108
+ x: torch.Tensor,
109
+ routing_mask: torch.Tensor,
110
+ num_memories: int,
111
+ selected_memories: torch.Tensor,
112
+ attention_mask: torch.Tensor,
113
+ ):
114
+ """
115
+ Reorganize token embeddings into memory-aligned chunks.
116
+
117
+ Steps:
118
+ - Expand for top-k routing if needed.
119
+ - Mask out padded tokens via `attention_mask`.
120
+ - Sort tokens by (batch, memory).
121
+ - Gather and pad tokens per memory slot.
122
+
123
+ Args:
124
+ x: (batch, seq, hidden) input embeddings.
125
+ routing_mask: (batch, seq, num_memories) binary routing mask.
126
+ num_memories: number of memory slots.
127
+ selected_memories: memory indices per token,
128
+ (batch, seq) if k=1 else (batch, seq, topk).
129
+ attention_mask: (batch, seq) valid-token mask.
130
+
131
+ Returns:
132
+ transformed_x: (num_memories, batch, max_len, hidden) reorganized tokens.
133
+ truncation_indices: (batch*num_memories, max_len) gather indices.
134
+ sorted_indices: (batch*seq*topk,) global sort order.
135
+ max_len: int, max tokens per memory.
136
+ mask: (batch*num_memories, max_len) validity mask.
137
+ mask_2: (num_memories, batch, max_len) validity mask reshaped.
138
+ """
139
+ if selected_memories.dim() == 3:
140
+ # (batch, seq, topk)
141
+ topk = selected_memories.shape[2]
142
+ # x (batch, seq, hidden)
143
+ x = x.repeat_interleave(topk, dim=1)
144
+ # x (batch, seq * topk, hidden)
145
+ # (batch, seq, topk)
146
+ selected_memories = selected_memories.reshape(selected_memories.shape[0], -1)
147
+ # (batch, seq * topk)
148
+
149
+ if attention_mask is not None:
150
+ attention_mask = attention_mask[:, -routing_mask.shape[1]:]
151
+ # mask out the masked tokens
152
+ routing_mask[attention_mask.bitwise_not().unsqueeze(-1).expand(-1, -1, num_memories)] = 0
153
+
154
+ b, s, d = x.shape
155
+ x_flat = x.reshape(b * s, d) # [b*s, d]
156
+
157
+ with torch.no_grad():
158
+ batch_indices = torch.arange(b, device=x.device).unsqueeze(-1)
159
+ batch_indices = batch_indices.repeat(1, s).reshape(-1)
160
+ if attention_mask is not None:
161
+ # sort the masked tokens to the end
162
+ batch_indices[attention_mask.repeat_interleave(topk, dim=1).bitwise_not().flatten()] = b
163
+ # (b * s)
164
+ memories_flat = selected_memories.reshape(-1) # [b*s]
165
+
166
+ combined = batch_indices * (memories_flat.max() + 1) + memories_flat
167
+ sorted_indices = combined.argsort()
168
+
169
+ x_sorted = x_flat[sorted_indices] # [b*s, d]
170
+ # (b*s, hidden) -> (b, s, hidd)
171
+ with torch.no_grad():
172
+ # routing_mask (b, s, num_memories)
173
+ batch_memory_tokens = routing_mask.sum(dim=1)
174
+ # (b, num_memories)
175
+ flatten_offset = batch_memory_tokens.flatten().cumsum(dim=0)
176
+ max_len = batch_memory_tokens.max()
177
+ indices = (
178
+ torch.arange(max_len, device=flatten_offset.device).unsqueeze(0).expand(b * num_memories, -1)
179
+ + torch.cat([torch.tensor([0], device=flatten_offset.device), flatten_offset[:-1]], dim=0).unsqueeze(1)
180
+ )
181
+ mask = indices < flatten_offset.unsqueeze(-1)
182
+ truncation_indices = torch.where(mask, indices, torch.zeros_like(indices))
183
+
184
+ gathered_x = torch.gather(x_sorted, 0, truncation_indices.reshape(-1).unsqueeze(-1).expand(-1, d))
185
+ transformed_x = gathered_x.reshape(b * num_memories, -1, d).reshape((b, num_memories, max_len, d)).transpose(0, 1)
186
+ # transformed_x = transformed_x * mask.unsqueeze(-1).expand_as(transformed_x)
187
+ # pad_x = torch.zeros((b * num_memories, capacity_len-max_len, d), dtype=transformed_x.dtype, device=transformed_x.device)
188
+ # pad_mask = torch.zeros((b * num_memories, capacity_len-max_len), dtype=transformed_x.dtype, device=transformed_x.device)
189
+ # left pad
190
+ # transformed_x = torch.cat((pad_x, transformed_x), dim=1).reshape((b, num_memories, capacity_len, d)).transpose(0, 1)
191
+ mask_2 = mask.reshape((b, num_memories, max_len)).transpose(0, 1)
192
+ # truncation_indices += capacity_len-max_len
193
+ # if attention_mask is not None:
194
+ # mask_2
195
+
196
+ return transformed_x, truncation_indices, sorted_indices, max_len, mask, mask_2
197
+
198
+
199
+ def reconstruct(
200
+ transformed_x,
201
+ indices: torch.Tensor,
202
+ sorted_indices: torch.Tensor,
203
+ batch_size: int,
204
+ seq_len: int,
205
+ topk: int,
206
+ routing_weights: torch.Tensor,
207
+ mask: torch.Tensor,
208
+ ):
209
+ '''
210
+ Reconstruct and mix transformed outputs back into the original input sequence shape.
211
+
212
+ Key operations:
213
+ 1. Reshapes and transposes `transformed_x` to prepare for scattering.
214
+ 2. Applies the `mask` to zero out invalid positions.
215
+ 3. Uses `torch.scatter_add_` to scatter and sum the transformed outputs back to their original positions
216
+ based on `indices`.
217
+ 4. Rearranges the scattered outputs using `sorted_indices` to ensure correct ordering.
218
+ 5. Applies the `routing_weights` to weight the outputs.
219
+ 6. Sums over the `topk` dimension to produce the final reconstructed output.
220
+
221
+ Args:
222
+ transformed_x (torch.Tensor):
223
+ The transformed output tensor from memory units or experts.
224
+ Shape: (num_memories, batch_size, capacity_len, hidden_size)
225
+ indices (torch.Tensor):
226
+ Indices used for scattering the transformed outputs back to their corresponding positions.
227
+ Shape: (batch*num_memories, max_len)
228
+ sorted_indices (torch.Tensor):
229
+ Sorting indices used to rearrange the scattered outputs back into the original sequence order.
230
+ Shape: (batch_size*seq_len*topk)
231
+ batch_size (int):
232
+ The size of the batch.
233
+ seq_len (int):
234
+ The length of the input sequence.
235
+ topk (int):
236
+ The number of top elements selected (`topk`) per token during the selection process.
237
+ routing_weights (torch.Tensor):
238
+ Routing weights assigned to the top-k selected outputs when reconstructing the final output.
239
+ Shape: (batch_size, seq_len, topk)
240
+ mask (torch.Tensor):
241
+ Boolean mask indicating valid positions in the sequence.
242
+ Shape: (batch*num_memories, max_len)
243
+
244
+ Returns:
245
+ restored_x (torch.Tensor):
246
+ The reconstructed output tensor in the original input sequence shape.
247
+ Shape: (batch_size, seq_len, hidden_size)
248
+ '''
249
+ transformed_x = transformed_x.transpose(0, 1).reshape(
250
+ (-1, transformed_x.shape[2], transformed_x.shape[3]))
251
+ b, s, k, d = batch_size, seq_len, topk, transformed_x.shape[2]
252
+ gathered_x = transformed_x.reshape(
253
+ (transformed_x.shape[0] * transformed_x.shape[1], transformed_x.shape[2]))
254
+ mask_expanded = mask.reshape(-1).unsqueeze(-1).expand_as(gathered_x)
255
+ gathered_x = gathered_x * mask_expanded
256
+
257
+ assert (indices >= 0).all(), "Indices should be non-negative"
258
+
259
+ resortd_x = torch.zeros((b * s * k, d), device=gathered_x.device, dtype=gathered_x.dtype).scatter_add_(
260
+ 0,
261
+ indices.reshape(-1).unsqueeze(-1).expand(-1, d),
262
+ gathered_x,
263
+ )
264
+ assert (indices < resortd_x.size(0)).all(), "Indices should be less than resortd_x size"
265
+
266
+ inverse_indices = sorted_indices.argsort()
267
+ rearranged_x_flat = resortd_x[inverse_indices]
268
+ restored_x = rearranged_x_flat.reshape((b, s * k, d))
269
+ restored_x = restored_x.reshape(b, s, k, d) * routing_weights.reshape(b, s, k).unsqueeze(-1)
270
+ restored_x = restored_x.sum(dim=2)
271
+ return restored_x
272
+
273
+
274
+ class MomAttention(nn.Module):
275
+ """
276
+ The layer implementaion for [MoM: Linear Sequence Modeling with Mixture-of-Memories](https://arxiv.org/abs/2502.13685).
277
+ """
278
+
279
+ def __init__(
280
+ self,
281
+ hidden_size: int = 2048,
282
+ head_dim: int = 256,
283
+ num_heads: int = 4,
284
+ expand_v: float = 2,
285
+ mode: str = 'chunk',
286
+ use_output_gate: bool = True,
287
+ use_short_conv: bool = True,
288
+ conv_size: int = 4,
289
+ conv_bias: bool = False,
290
+ layer_idx: int = None,
291
+ norm_eps: float = 1e-5,
292
+ num_memories: int = 8,
293
+ topk: int = 2,
294
+ capacity: float = 1.0,
295
+ shared_mem: bool = False,
296
+ single_kv_proj: bool = False,
297
+ **kwargs,
298
+ ) -> MomAttention:
299
+ super().__init__()
300
+ self.num_memories = num_memories
301
+ self.topk = topk
302
+ self.capacity = capacity
303
+ self.shared_mem = shared_mem
304
+ self.single_kv_proj = single_kv_proj
305
+
306
+ self.mode = mode
307
+
308
+ self.hidden_size = hidden_size
309
+ self.expand_v = expand_v
310
+
311
+ self.use_output_gate = use_output_gate
312
+ self.use_short_conv = use_short_conv
313
+ self.conv_size = conv_size
314
+ self.conv_bias = conv_bias
315
+
316
+ self.head_dim = head_dim
317
+ self.num_heads = num_heads
318
+
319
+ self.key_dim = int(self.num_heads * self.head_dim)
320
+ self.value_dim = int(self.key_dim * self.expand_v)
321
+ self.head_qk_dim = head_dim
322
+ self.head_v_dim = int(head_dim * self.expand_v)
323
+ self.layer_idx = layer_idx
324
+ self.silu = nn.SiLU()
325
+
326
+ assert mode in ['chunk', 'fused_recurrent'], f"Not suppoerted mode `{mode}`."
327
+
328
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
329
+ self.gate = nn.Linear(self.hidden_size, self.num_memories, bias=False)
330
+ if self.single_kv_proj:
331
+ self.shared_k = nn.Linear(hidden_size, self.key_dim, bias=False)
332
+ self.shared_v = nn.Linear(hidden_size, self.value_dim, bias=False)
333
+ self.shared_b = nn.Linear(hidden_size, self.num_heads, bias=False)
334
+ self.shared_a = nn.Linear(hidden_size, self.num_heads, bias=False)
335
+ else:
336
+ self.k_proj = nn.ModuleList([
337
+ nn.Linear(self.hidden_size, self.key_dim, bias=False)
338
+ for _ in range(self.num_memories)
339
+ ])
340
+ self.v_proj = nn.ModuleList([
341
+ nn.Linear(self.hidden_size, self.value_dim, bias=False)
342
+ for _ in range(self.num_memories)
343
+ ])
344
+ self.b_proj = nn.ModuleList([
345
+ nn.Linear(self.hidden_size, self.num_heads, bias=False)
346
+ for _ in range(self.num_memories)
347
+ ])
348
+ self.a_proj = nn.ModuleList([
349
+ nn.Linear(self.hidden_size, self.num_heads, bias=False)
350
+ for _ in range(self.num_memories)
351
+ ])
352
+ if self.shared_mem:
353
+ self.shared_k = nn.Linear(hidden_size, self.key_dim, bias=False)
354
+ self.shared_v = nn.Linear(hidden_size, self.value_dim, bias=False)
355
+ self.shared_b = nn.Linear(hidden_size, self.num_heads, bias=False)
356
+ self.shared_a = nn.Linear(hidden_size, self.num_heads, bias=False)
357
+
358
+ A = torch.empty(self.num_heads, dtype=torch.float32).uniform_(0, 16)
359
+ self.A_log = nn.Parameter(torch.log(A))
360
+ self.A_log._no_weight_decay = True
361
+ # hard coded for now
362
+ dt_min = 0.001
363
+ dt_max = 0.1
364
+ dt_init_floor = 1e-4
365
+ dt = torch.exp(
366
+ torch.rand(self.num_heads) * (math.log(dt_max) - math.log(dt_min))
367
+ + math.log(dt_min),
368
+ )
369
+ dt = torch.clamp(dt, min=dt_init_floor)
370
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
371
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
372
+ self.dt_bias = nn.Parameter(inv_dt)
373
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
374
+ # name.endswith("bias") in param_grouping.py
375
+ self.dt_bias._no_weight_decay = True
376
+
377
+ if use_short_conv:
378
+ self.conv_size = conv_size
379
+ self.q_conv1d = ShortConvolution(
380
+ hidden_size=self.key_dim,
381
+ kernel_size=conv_size,
382
+ bias=conv_bias,
383
+ activation='silu',
384
+ )
385
+ self.k_conv1d = ShortConvolution(
386
+ hidden_size=self.key_dim,
387
+ kernel_size=conv_size,
388
+ bias=conv_bias,
389
+ activation='silu',
390
+ )
391
+ self.v_conv1d = ShortConvolution(
392
+ hidden_size=self.value_dim,
393
+ kernel_size=conv_size,
394
+ bias=conv_bias,
395
+ activation='silu',
396
+ )
397
+ else:
398
+ raise UserWarning(
399
+ "ShortConvolution is crucial to the performance. "
400
+ "Do not turn it off, i.e., setting `use_short_conv=False` unless you know what you are doing.",
401
+ )
402
+ if use_output_gate:
403
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
404
+ self.o_norm = FusedRMSNormGated(self.head_v_dim, eps=norm_eps)
405
+ else:
406
+ self.o_norm = RMSNorm(self.head_v_dim, eps=norm_eps, dtype=torch.float32)
407
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
408
+ self.apply(self._initialize_weights)
409
+
410
+ def _initialize_weights(self, module: nn.Module):
411
+ if getattr(module, "_is_hf_initialized", False):
412
+ return
413
+ if isinstance(module, nn.Linear):
414
+ nn.init.xavier_uniform_(module.weight, gain=2 ** -2.5)
415
+ if module.bias is not None:
416
+ nn.init.zeros_(module.bias)
417
+ module._is_hf_initialized = True
418
+
419
+ def forward(
420
+ self,
421
+ hidden_states: torch.Tensor,
422
+ attention_mask: torch.Tensor | None = None,
423
+ past_key_values: Cache | None = None,
424
+ use_cache: bool | None = False,
425
+ output_attentions: bool | None = False,
426
+ **kwargs: Unpack[dict],
427
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
428
+ if attention_mask is not None:
429
+ attention_mask = (attention_mask == 1)
430
+ assert len(attention_mask.shape) == 2, (
431
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
432
+ "for padding purposes (0 indicating padding). "
433
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
434
+ )
435
+
436
+ origin_cu_seqlens = kwargs.get('cu_seqlens')
437
+ if origin_cu_seqlens is not None:
438
+ hidden_states, attention_mask = self.cu2pad(hidden_states, origin_cu_seqlens)
439
+
440
+ mode = 'fused_recurrent' if (hidden_states.shape[1] <= 64 and not self.training) else self.mode
441
+ if self.training:
442
+ assert mode == 'chunk', "Only chunk mode is supported in training."
443
+
444
+ last_state = get_layer_cache(self, past_key_values)
445
+ # _, q_len = hidden_states.shape[0], hidden_states.shape[1]
446
+
447
+ # 🔍 topk gating
448
+ router_logits = self.gate(hidden_states) # (bsz, q_len, num_memories)
449
+ scores = F.softmax(router_logits, dim=2, dtype=torch.float)
450
+ routing_weights, selected_memories = torch.topk(scores, self.topk, dim=-1) # (bsz, seq, topk)
451
+ routing_weights /= routing_weights.sum(dim=-1, keepdim=True)
452
+ routing_weights = routing_weights.to(hidden_states.dtype) # we cast back to the input dtype
453
+ routing_weights_full = torch.zeros(
454
+ routing_weights.shape[0],
455
+ routing_weights.shape[1],
456
+ self.num_memories,
457
+ dtype=routing_weights.dtype,
458
+ device=routing_weights.device,
459
+ ).scatter(-1, selected_memories, routing_weights)
460
+ routing_mask = routing_weights_full.bool().int()
461
+
462
+ # if self.use_output_gate:
463
+ # o_g = self.g_proj(hidden_states)
464
+
465
+ batch_size, seq_len = hidden_states.shape[0], hidden_states.shape[1]
466
+
467
+ shared_hidden_states = hidden_states
468
+ hidden_states, indices, sorted_indices, max_len, mask, mask_2 = transform(
469
+ hidden_states, routing_mask, self.num_memories, selected_memories, attention_mask)
470
+
471
+ q = self.q_proj(hidden_states)
472
+ if self.single_kv_proj:
473
+ k = self.shared_k(hidden_states)
474
+ v = self.shared_v(hidden_states)
475
+ beta = self.shared_b(hidden_states).sigmoid()
476
+ g = -self.A_log.float().exp() * F.softplus(self.shared_a(hidden_states).float() + self.dt_bias)
477
+ else:
478
+ k = torch.stack([k_expert(hidden_states[i]) for i, k_expert in enumerate(self.k_proj)], dim=0)
479
+ v = torch.stack([v_expert(hidden_states[i]) for i, v_expert in enumerate(self.v_proj)], dim=0)
480
+ beta = torch.stack([b_expert(hidden_states[i]).sigmoid() for i, b_expert in enumerate(self.b_proj)], dim=0)
481
+ g = torch.stack([-self.A_log.float().exp() * F.softplus(a_expert(hidden_states[i]).float() + self.dt_bias)
482
+ for i, a_expert in enumerate(self.a_proj)], dim=0)
483
+
484
+ q, k, v, g, beta, mask_2 = (rearrange(x, 'e b l ... -> (e b) l ...') for x in (q, k, v, g, beta, mask_2))
485
+ cu_q, cu_k, cu_v, cu_g, cu_beta, indices_q, cu_seqlen_all, max_seq_lens = _upad_input(q, k, v, g, beta, mask_2)
486
+ cu_seqlens, reverse_indices = cu_seqlen_all[0].to(torch.long).unique(return_inverse=True)
487
+ cu_q, cu_k, cu_v, cu_g, cu_beta = (x.unsqueeze(0).contiguous() for x in (cu_q, cu_k, cu_v, cu_g, cu_beta))
488
+
489
+ if self.use_short_conv:
490
+ conv_state_q, conv_state_k, conv_state_v = [None, None], [None, None], [None, None]
491
+ if last_state is not None:
492
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
493
+
494
+ conv_cu_seqlens = cu_seqlens
495
+ padded = False
496
+ if self.training:
497
+ conv_cu_seqlens = None
498
+ elif seq_len != 1 and (cu_seqlens[1:] - cu_seqlens[:-1]).min().item() < self.conv_size:
499
+ padded = True
500
+ conv_cu_seqlens, cu_q, cu_k, cu_v, pad_lengths = self.pad_for_conv(cu_seqlens, cu_q, cu_k, cu_v)
501
+
502
+ conv_q = self.prepare_recurrent_state(
503
+ conv_state_q[0],
504
+ conv_cu_seqlens,
505
+ cu_seqlen_all[0],
506
+ reverse_indices,
507
+ batch_size,
508
+ )
509
+ cu_q, conv_q_new = self.q_conv1d(
510
+ x=cu_q,
511
+ cache=conv_q,
512
+ output_final_state=use_cache,
513
+ cu_seqlens=conv_cu_seqlens,
514
+ )
515
+ conv_state_q[0] = self.handle_recurrent_state(
516
+ conv_state_q[0],
517
+ conv_q_new,
518
+ conv_cu_seqlens,
519
+ cu_seqlen_all[0],
520
+ reverse_indices,
521
+ )
522
+ conv_k = self.prepare_recurrent_state(
523
+ conv_state_k[0],
524
+ conv_cu_seqlens,
525
+ cu_seqlen_all[0],
526
+ reverse_indices,
527
+ batch_size,
528
+ )
529
+ cu_k, conv_k_new = self.k_conv1d(
530
+ x=cu_k,
531
+ cache=conv_k,
532
+ output_final_state=use_cache,
533
+ cu_seqlens=conv_cu_seqlens,
534
+ )
535
+ conv_state_k[0] = self.handle_recurrent_state(
536
+ conv_state_k[0],
537
+ conv_k_new,
538
+ conv_cu_seqlens,
539
+ cu_seqlen_all[0],
540
+ reverse_indices,
541
+ )
542
+ conv_v = self.prepare_recurrent_state(
543
+ conv_state_v[0],
544
+ conv_cu_seqlens,
545
+ cu_seqlen_all[0],
546
+ reverse_indices,
547
+ batch_size,
548
+ )
549
+ cu_v, conv_v_new = self.v_conv1d(
550
+ x=cu_v,
551
+ cache=conv_v,
552
+ output_final_state=use_cache,
553
+ cu_seqlens=conv_cu_seqlens,
554
+ )
555
+ conv_state_v[0] = self.handle_recurrent_state(
556
+ conv_state_v[0],
557
+ conv_v_new, conv_cu_seqlens,
558
+ cu_seqlen_all[0],
559
+ reverse_indices,
560
+ )
561
+
562
+ if padded:
563
+ cu_q, cu_k, cu_v = self.unpad_after_conv(conv_cu_seqlens, cu_seqlens, cu_q, cu_k, cu_v, pad_lengths)
564
+
565
+ else:
566
+ q, k, v = self.silu(q), self.silu(k), self.silu(v)
567
+
568
+ cu_q, cu_k, cu_v = map(lambda x: rearrange(x, 'b t (h d) -> b t h d', h=self.num_heads), (cu_q, cu_k, cu_v))
569
+
570
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else [
571
+ None for _ in range(1 + self.shared_mem)]
572
+ if mode == 'chunk':
573
+ o, recurrent_state_ = chunk_gated_delta_rule(
574
+ q=cu_q,
575
+ k=cu_k,
576
+ v=cu_v,
577
+ g=cu_g,
578
+ beta=cu_beta,
579
+ initial_state=recurrent_state[0],
580
+ output_final_state=use_cache,
581
+ use_qk_l2norm_in_kernel=True,
582
+ cu_seqlens=cu_seqlens,
583
+ )
584
+ recurrent_state[0] = self.handle_recurrent_state(
585
+ recurrent_state[0],
586
+ recurrent_state_,
587
+ cu_seqlens,
588
+ cu_seqlen_all[0],
589
+ reverse_indices,
590
+ )
591
+
592
+ elif mode == 'fused_recurrent':
593
+ memories = self.prepare_recurrent_state(
594
+ recurrent_state[0],
595
+ cu_seqlens, cu_seqlen_all[0],
596
+ reverse_indices, batch_size,
597
+ )
598
+ o, recurrent_state_ = fused_recurrent_gated_delta_rule(
599
+ q=cu_q,
600
+ k=cu_k,
601
+ v=cu_v,
602
+ g=cu_g,
603
+ beta=cu_beta,
604
+ initial_state=memories,
605
+ output_final_state=use_cache,
606
+ use_qk_l2norm_in_kernel=True,
607
+ cu_seqlens=cu_seqlens,
608
+ )
609
+ recurrent_state[0] = self.handle_recurrent_state(
610
+ recurrent_state[0],
611
+ recurrent_state_,
612
+ cu_seqlens,
613
+ cu_seqlen_all[0],
614
+ reverse_indices,
615
+ )
616
+
617
+ o = o.squeeze(0).contiguous()
618
+ o = pad_input(o, indices_q, batch_size*self.num_memories, max_len)
619
+ o = rearrange(o, '(e b) l h d -> e b l (h d)', b=batch_size)
620
+ o = reconstruct(o, indices=indices, sorted_indices=sorted_indices, batch_size=batch_size,
621
+ seq_len=seq_len, topk=self.topk, routing_weights=routing_weights, mask=mask)
622
+ o = rearrange(o, 'b l (h d) -> b l h d', h=self.num_heads)
623
+
624
+ if self.shared_mem:
625
+ shared_o = self.shared_o(shared_hidden_states, attention_mask, recurrent_state,
626
+ use_cache, conv_state_q, conv_state_k, conv_state_v)
627
+ o += shared_o
628
+
629
+ update_layer_cache(
630
+ self,
631
+ past_key_values,
632
+ recurrent_state=recurrent_state,
633
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
634
+ offset=q.shape[2],
635
+ )
636
+
637
+ if self.use_output_gate:
638
+ g = rearrange(self.g_proj(shared_hidden_states), '... (h d) -> ... h d', d=self.head_v_dim)
639
+ o = self.o_norm(o, g)
640
+ else:
641
+ o = self.o_norm(o)
642
+ o = rearrange(o, 'b t h d -> b t (h d)')
643
+ o = self.o_proj(o)
644
+
645
+ if origin_cu_seqlens is not None:
646
+ indices, _, _ = get_unpad_data(attention_mask[:, -seq_len:])
647
+ o = index_first_axis(rearrange(o, "b s ... -> (b s) ..."), indices).unsqueeze(0)
648
+
649
+ return o, None, past_key_values, router_logits.view(-1, self.num_memories)
650
+
651
+ def shared_o(
652
+ self,
653
+ hidden_states: torch.Tensor,
654
+ attention_mask: torch.Tensor | None = None,
655
+ recurrent_state=None,
656
+ use_cache: bool | None = False,
657
+ conv_state_q=[None, None],
658
+ conv_state_k=[None, None],
659
+ conv_state_v=[None, None],
660
+ **kwargs,
661
+ ) -> torch.Tensor:
662
+ if attention_mask is not None:
663
+ assert len(attention_mask.shape) == 2, (
664
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
665
+ "for padding purposes (0 indicating padding). "
666
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
667
+ )
668
+
669
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
670
+ if self.training:
671
+ assert mode == 'chunk', "Only chunk mode is supported in training."
672
+
673
+ cu_seqlens = None
674
+ if attention_mask is not None:
675
+ batch_size, q_len = hidden_states.shape[0], hidden_states.shape[1]
676
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
677
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
678
+
679
+ if self.use_short_conv:
680
+ q, conv_state_q[1] = self.q_conv1d(
681
+ x=self.q_proj(hidden_states),
682
+ cache=conv_state_q[1],
683
+ output_final_state=use_cache,
684
+ cu_seqlens=cu_seqlens,
685
+ )
686
+ k, conv_state_k[1] = self.k_conv1d(
687
+ x=self.shared_k(hidden_states),
688
+ cache=conv_state_k[1],
689
+ output_final_state=use_cache,
690
+ cu_seqlens=cu_seqlens,
691
+ )
692
+ v, conv_state_v[1] = self.v_conv1d(
693
+ x=self.shared_v(hidden_states),
694
+ cache=conv_state_v[1],
695
+ output_final_state=use_cache,
696
+ cu_seqlens=cu_seqlens,
697
+ )
698
+ else:
699
+ q = self.silu(self.q_proj(hidden_states))
700
+ k = self.silu(self.shared_k(hidden_states))
701
+ v = self.silu(self.shared_v(hidden_states))
702
+
703
+ q, k, v = map(lambda x: rearrange(x, 'b t (h d) -> b t h d', h=self.num_heads), (q, k, v))
704
+ beta = self.shared_b(hidden_states).sigmoid()
705
+ g = -self.A_log.float().exp() * F.softplus(self.shared_a(hidden_states).float() + self.dt_bias)
706
+
707
+ if mode == 'chunk':
708
+ o, recurrent_state[-1] = chunk_gated_delta_rule(
709
+ q=q,
710
+ k=k,
711
+ v=v,
712
+ g=g,
713
+ beta=beta,
714
+ initial_state=recurrent_state[-1],
715
+ output_final_state=use_cache,
716
+ cu_seqlens=cu_seqlens,
717
+ use_qk_l2norm_in_kernel=True,
718
+ )
719
+ elif mode == 'fused_recurrent':
720
+ o, recurrent_state[-1] = fused_recurrent_gated_delta_rule(
721
+ q=q,
722
+ k=k,
723
+ v=v,
724
+ g=g,
725
+ beta=beta,
726
+ initial_state=recurrent_state[-1],
727
+ output_final_state=use_cache,
728
+ cu_seqlens=cu_seqlens,
729
+ use_qk_l2norm_in_kernel=True,
730
+ )
731
+ else:
732
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
733
+
734
+ if attention_mask is not None:
735
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
736
+ return o
737
+
738
+ def cu2pad(self, x, cu_seqlens):
739
+ batch_size = cu_seqlens.shape[0] - 1
740
+ max_len = (cu_seqlens[1:] - cu_seqlens[:-1]).max().item()
741
+ indices = torch.tensor([], dtype=torch.long, device=x.device)
742
+ attention_mask = torch.ones((batch_size, max_len), dtype=torch.bool, device=x.device)
743
+ for i in range(batch_size):
744
+ seq_len = cu_seqlens[i+1] - cu_seqlens[i]
745
+ pad_len = max_len - seq_len
746
+ batch_indices = torch.arange(pad_len, max_len, device=x.device)
747
+ batch_indices = batch_indices + i * max_len
748
+ indices = torch.cat([indices, batch_indices])
749
+ attention_mask[i, :pad_len] = False
750
+ x = pad_input(x.squeeze(0), indices, batch_size, max_len)
751
+ return x, attention_mask
752
+
753
+ def pad_for_conv(self, cu_seqlens, cu_q, cu_k, cu_v):
754
+ lengths = cu_seqlens[1:] - cu_seqlens[:-1]
755
+ pad_lengths = torch.clamp(self.conv_size - lengths, min=0)
756
+ new_lengths = lengths + pad_lengths
757
+ new_cu_seqlens = torch.cat([
758
+ torch.tensor([0], device=cu_seqlens.device, dtype=cu_seqlens.dtype),
759
+ torch.cumsum(new_lengths, dim=0),
760
+ ])
761
+ final_total_len = new_cu_seqlens[-1].item()
762
+ new_q = torch.zeros((1, final_total_len, cu_q.shape[-1]), dtype=cu_q.dtype, device=cu_q.device)
763
+ new_k = torch.zeros((1, final_total_len, cu_k.shape[-1]), dtype=cu_k.dtype, device=cu_k.device)
764
+ new_v = torch.zeros((1, final_total_len, cu_v.shape[-1]), dtype=cu_v.dtype, device=cu_v.device)
765
+ num_sequences = len(lengths)
766
+ for i in range(num_sequences):
767
+ src_start = cu_seqlens[i]
768
+ src_end = cu_seqlens[i+1]
769
+ dest_start = new_cu_seqlens[i] + pad_lengths[i]
770
+ dest_end = new_cu_seqlens[i+1]
771
+ new_q[:, dest_start:dest_end, ...] = cu_q[:, src_start:src_end, ...]
772
+ new_k[:, dest_start:dest_end, ...] = cu_k[:, src_start:src_end, ...]
773
+ new_v[:, dest_start:dest_end, ...] = cu_v[:, src_start:src_end, ...]
774
+
775
+ return new_cu_seqlens, new_q, new_k, new_v, pad_lengths
776
+
777
+ def unpad_after_conv(self, conv_cu_seqlens, cu_seqlens, cu_q, cu_k, cu_v, pad_lengths):
778
+ original_total_len = cu_seqlens[-1].item()
779
+ orig_q = torch.empty((1, original_total_len, cu_q.shape[-1]), dtype=cu_q.dtype, device=cu_q.device)
780
+ orig_k = torch.empty((1, original_total_len, cu_k.shape[-1]), dtype=cu_k.dtype, device=cu_k.device)
781
+ orig_v = torch.empty((1, original_total_len, cu_v.shape[-1]), dtype=cu_v.dtype, device=cu_v.device)
782
+
783
+ num_sequences = len(pad_lengths)
784
+ for i in range(num_sequences):
785
+ dest_start = cu_seqlens[i]
786
+ dest_end = cu_seqlens[i+1]
787
+ src_start = conv_cu_seqlens[i] + pad_lengths[i]
788
+ src_end = conv_cu_seqlens[i+1]
789
+
790
+ orig_q[:, dest_start:dest_end, ...] = cu_q[:, src_start:src_end, ...]
791
+ orig_k[:, dest_start:dest_end, ...] = cu_k[:, src_start:src_end, ...]
792
+ orig_v[:, dest_start:dest_end, ...] = cu_v[:, src_start:src_end, ...]
793
+ return orig_q, orig_k, orig_v
794
+
795
+ def prepare_recurrent_state(self, recurrent_state, cu_seqlens, cu_seqlen_all, reverse_indices, batch_size):
796
+ if recurrent_state is None:
797
+ return None
798
+
799
+ if cu_seqlens is None:
800
+ return recurrent_state
801
+
802
+ total_len = len(cu_seqlen_all)
803
+ if len(cu_seqlens) != total_len:
804
+ # select memories that are activated
805
+ memories = torch.zeros_like(recurrent_state[:self.topk*batch_size])
806
+ mem_id = 0
807
+ for i in range(total_len-1):
808
+ if cu_seqlen_all[i] != cu_seqlen_all[i+1]:
809
+ memories[mem_id] = recurrent_state[i]
810
+ mem_id += 1
811
+ assert mem_id == self.topk * batch_size, f"The number of memories {mem_id} is not correct."
812
+ else:
813
+ memories = recurrent_state
814
+
815
+ return memories
816
+
817
+ def handle_recurrent_state(self, recurrent_state, recurrent_state_new, cu_seqlens, cu_seqlen_all, reverse_indices):
818
+ if recurrent_state_new is None:
819
+ return None
820
+ if cu_seqlens is None:
821
+ return recurrent_state_new
822
+ if recurrent_state is None:
823
+ recurrent_state = torch.zeros_like(recurrent_state_new[reverse_indices[1:]-1])
824
+ total_len = len(cu_seqlen_all)
825
+ if len(cu_seqlens) != total_len:
826
+ for i in range(total_len-1):
827
+ if cu_seqlen_all[i] != cu_seqlen_all[i+1]:
828
+ recurrent_state[i] = recurrent_state_new[reverse_indices[i+1]-1]
829
+ else:
830
+ recurrent_state = recurrent_state_new
831
+ return recurrent_state
fla/layers/multiscale_retention.py ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from einops import rearrange, repeat
10
+ from transformers.activations import ACT2FN
11
+
12
+ from fla.layers.utils import get_layer_cache, get_unpad_data, index_first_axis, pad_input, update_layer_cache
13
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
14
+ from fla.modules.rotary import RotaryEmbedding
15
+ from fla.ops.retention import chunk_retention, fused_chunk_retention, fused_recurrent_retention, parallel_retention
16
+ from fla.ops.utils.index import prepare_lens_from_mask
17
+
18
+ if TYPE_CHECKING:
19
+ from transformers.processing_utils import Unpack
20
+
21
+ from fla.models.utils import Cache
22
+
23
+
24
+ class MultiScaleRetention(nn.Module):
25
+ r"""
26
+ The layer implementaion for [Retentive Network: A Successor to Transformer for Large Language Models](https://arxiv.org/pdf/2307.08621.pdf). # noqa
27
+
28
+ Args:
29
+ mode (str, Optional):
30
+ Which Retention kernel to use.
31
+ Currently available: `chunk`, `fused_recurrent`, `parallel`, and `fused_chunk`.
32
+ Default: `chunk`.
33
+ hidden_size (int, Optional):
34
+ The hidden size of the input. Default: 1024.
35
+ expand_k (float, Optional):
36
+ The expansion ratio for the key dim. Default: 1.0.
37
+ expand_v (float, Optional):
38
+ The expansion ratio for the value dim. Default: 2.0.
39
+ num_heads (int, Optional):
40
+ The number of heads. Default: 8.
41
+ num_kv_heads (int, Optional):
42
+ The number of key/value heads, used for MQA. Default: None.
43
+ feature_map (str, Optional):
44
+ Feature map function applied to queries/keys. Default: None.
45
+ use_short_conv (bool, Optional):
46
+ Whether to use short convolutions. Default: `False`.
47
+ conv_size (int, Optional):
48
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
49
+ conv_bias (bool, Optional):
50
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
51
+ use_output_gate (bool, Optional):
52
+ Whether to use output gate. Default: `True`.
53
+ gate_fn (str, Optional):
54
+ The activation function for the output gate. Default: `swish`.
55
+ elementwise_affine (bool, Optional):
56
+ If `True`, applies elementwise affine to LayerNorm with learnable parameters. Default: `True`.
57
+ norm_eps (float, Optional):
58
+ The epsilon value for the layernorm/rmsnorm layer. Default: 1e-5.
59
+ fuse_norm (bool, Optional):
60
+ Whether to fuse the norm and the output gate for better memory footprint. Default: `True`.
61
+ layer_idx (int, Optional):
62
+ The index of the layer. Default: None.
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ mode: str = 'chunk',
68
+ hidden_size: int = 1024,
69
+ expand_k: float = 1.0,
70
+ expand_v: float = 2.0,
71
+ num_heads: int = 8,
72
+ num_kv_heads: int | None = None,
73
+ feature_map: str | None = None,
74
+ use_short_conv: bool = False,
75
+ conv_size: int = 4,
76
+ conv_bias: bool = False,
77
+ use_output_gate: bool = True,
78
+ gate_fn: str = 'swish',
79
+ elementwise_affine: bool | None = True,
80
+ norm_eps: float = 1e-5,
81
+ fuse_norm: bool = True,
82
+ layer_idx: int = None,
83
+ **kwargs,
84
+ ) -> MultiScaleRetention:
85
+ super().__init__()
86
+
87
+ self.mode = mode
88
+ self.hidden_size = hidden_size
89
+ self.expand_k = expand_k
90
+ self.expand_v = expand_v
91
+ self.num_heads = num_heads
92
+ self.num_kv_heads = num_kv_heads if num_kv_heads is not None else num_heads
93
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
94
+ self.feature_map_fn = ACT2FN[feature_map] if feature_map is not None else None
95
+
96
+ self.use_short_conv = use_short_conv
97
+ self.conv_size = conv_size
98
+ self.conv_bias = conv_bias
99
+ self.use_output_gate = use_output_gate
100
+
101
+ self.key_dim = int(hidden_size * expand_k)
102
+ self.value_dim = int(hidden_size * expand_v)
103
+ self.key_dim_per_group = self.key_dim // self.num_kv_groups
104
+ self.value_dim_per_group = self.value_dim // self.num_kv_groups
105
+ self.layer_idx = layer_idx
106
+
107
+ assert mode in ['chunk', 'fused_chunk', 'parallel', 'fused_recurrent'], f"Not supported mode `{mode}`."
108
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
109
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
110
+
111
+ self.head_k_dim = self.key_dim // num_heads
112
+ self.head_v_dim = self.value_dim // num_heads
113
+
114
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
115
+ self.k_proj = nn.Linear(hidden_size, self.key_dim_per_group, bias=False)
116
+ self.v_proj = nn.Linear(hidden_size, self.value_dim_per_group, bias=False)
117
+ if self.use_output_gate:
118
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
119
+
120
+ if use_short_conv:
121
+ self.conv_size = conv_size
122
+ self.q_conv1d = ShortConvolution(
123
+ hidden_size=self.key_dim,
124
+ kernel_size=conv_size,
125
+ bias=conv_bias,
126
+ activation='silu',
127
+ )
128
+ self.k_conv1d = ShortConvolution(
129
+ hidden_size=self.key_dim_per_group,
130
+ kernel_size=conv_size,
131
+ bias=conv_bias,
132
+ activation='silu',
133
+ )
134
+ self.v_conv1d = ShortConvolution(
135
+ hidden_size=self.value_dim_per_group,
136
+ kernel_size=conv_size,
137
+ bias=conv_bias,
138
+ activation='silu',
139
+ )
140
+
141
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
142
+
143
+ if gate_fn == 'swish' and fuse_norm and use_output_gate:
144
+ self.g_norm_swish_gate = FusedRMSNormGated(
145
+ hidden_size=self.head_v_dim,
146
+ elementwise_affine=elementwise_affine,
147
+ eps=norm_eps,
148
+ )
149
+ self.fuse_norm_and_gate = True
150
+ else:
151
+ self.fuse_norm_and_gate = False
152
+ self.g_norm = RMSNorm(
153
+ hidden_size=self.head_v_dim,
154
+ elementwise_affine=elementwise_affine,
155
+ eps=norm_eps,
156
+ dtype=torch.float32
157
+ )
158
+ self.gate_fn = ACT2FN[gate_fn]
159
+
160
+ # TODO: fix this issue
161
+ # https://github.com/Dao-AILab/flash-attention/blob/main/flash_attn/ops/triton/rotary.py#L180
162
+ # Ideally, we would want to support arbitrary d_head_qk
163
+ assert self.head_k_dim <= 256, "head_k_dim must be less than or equal to 256"
164
+ self.rotary = RotaryEmbedding(dim=self.head_k_dim)
165
+
166
+ def forward(
167
+ self,
168
+ hidden_states: torch.Tensor,
169
+ attention_mask: torch.Tensor | None = None,
170
+ past_key_values: Cache | None = None,
171
+ use_cache: bool | None = False,
172
+ output_attentions: bool | None = False,
173
+ **kwargs: Unpack[dict],
174
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
175
+ if attention_mask is not None:
176
+ assert len(attention_mask.shape) == 2, (
177
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
178
+ "for padding purposes (0 indicating padding). "
179
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
180
+ )
181
+
182
+ batch_size, q_len, _ = hidden_states.shape
183
+ mode = 'fused_recurrent' if q_len <= 64 else self.mode
184
+
185
+ last_state = get_layer_cache(self, past_key_values)
186
+
187
+ cu_seqlens = kwargs.get('cu_seqlens')
188
+ if attention_mask is not None:
189
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
190
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
191
+
192
+ if self.use_short_conv:
193
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
194
+ if last_state is not None:
195
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
196
+ q, conv_state_q = self.q_conv1d(
197
+ x=self.q_proj(hidden_states),
198
+ cache=conv_state_q,
199
+ output_final_state=use_cache,
200
+ cu_seqlens=cu_seqlens,
201
+ )
202
+ k, conv_state_k = self.k_conv1d(
203
+ x=self.k_proj(hidden_states),
204
+ cache=conv_state_k,
205
+ output_final_state=use_cache,
206
+ cu_seqlens=cu_seqlens,
207
+ )
208
+ v, conv_state_v = self.v_conv1d(
209
+ x=self.v_proj(hidden_states),
210
+ cache=conv_state_v,
211
+ output_final_state=use_cache,
212
+ cu_seqlens=cu_seqlens,
213
+ )
214
+ else:
215
+ q = self.q_proj(hidden_states)
216
+ k = self.k_proj(hidden_states)
217
+ v = self.v_proj(hidden_states)
218
+
219
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_k_dim)
220
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_k_dim)
221
+ if self.feature_map_fn is not None:
222
+ q, k = map(self.feature_map_fn, (q, k))
223
+
224
+ seqlen_offset, max_seqlen = 0, q.shape[1]
225
+ if past_key_values is not None:
226
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
227
+ max_seqlen = q.shape[1] + seqlen_offset
228
+
229
+ if attention_mask is not None and seqlen_offset > 0:
230
+ # to deliminate the offsets of padding tokens
231
+ seqlen_offset = prepare_lens_from_mask(attention_mask) - q_len
232
+ max_seqlen = q.shape[1] + seqlen_offset.max().item()
233
+
234
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens)
235
+
236
+ if self.num_kv_groups > 1:
237
+ k = repeat(k, '... h d -> ... (h g) d', g=self.num_kv_groups)
238
+ v = repeat(v, '... (h d) -> ... (h g) d', d=self.head_v_dim, g=self.num_kv_groups)
239
+ else:
240
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_v_dim)
241
+
242
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
243
+ if mode == 'chunk':
244
+ o, recurrent_state = chunk_retention(
245
+ q=q,
246
+ k=k,
247
+ v=v,
248
+ initial_state=recurrent_state,
249
+ output_final_state=use_cache,
250
+ cu_seqlens=cu_seqlens,
251
+ )
252
+ elif mode == 'fused_chunk':
253
+ o, recurrent_state = fused_chunk_retention(
254
+ q=q,
255
+ k=k,
256
+ v=v,
257
+ initial_state=recurrent_state,
258
+ output_final_state=use_cache,
259
+ cu_seqlens=cu_seqlens,
260
+ )
261
+ elif mode == 'parallel':
262
+ o, recurrent_state = parallel_retention(
263
+ q=q,
264
+ k=k,
265
+ v=v,
266
+ cu_seqlens=cu_seqlens,
267
+ )
268
+ elif mode == 'fused_recurrent':
269
+ o, recurrent_state = fused_recurrent_retention(
270
+ q=q,
271
+ k=k,
272
+ v=v,
273
+ initial_state=recurrent_state,
274
+ output_final_state=use_cache,
275
+ cu_seqlens=cu_seqlens,
276
+ )
277
+ else:
278
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
279
+
280
+ update_layer_cache(
281
+ self,
282
+ past_key_values,
283
+ recurrent_state=recurrent_state,
284
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
285
+ offset=q_len,
286
+ )
287
+
288
+ if self.use_output_gate:
289
+ g = self.g_proj(hidden_states)
290
+ if self.fuse_norm_and_gate:
291
+ g = rearrange(g, '... (h d) -> ... h d', d=self.head_v_dim)
292
+ o = self.g_norm_swish_gate(o, g)
293
+ o = rearrange(o, '... h d -> ... (h d)')
294
+ else:
295
+ o = rearrange(self.g_norm(o), '... h d -> ... (h d)')
296
+ o = o * self.gate_fn(g)
297
+ else:
298
+ o = rearrange(self.g_norm(o), '... h d -> ... (h d)')
299
+ o = self.o_proj(o)
300
+ if attention_mask is not None:
301
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
302
+
303
+ return o, None, past_key_values
fla/layers/nsa.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from einops import rearrange
10
+ from transformers.utils import logging
11
+
12
+ from fla.modules import RotaryEmbedding
13
+ from fla.ops.nsa.parallel import parallel_nsa
14
+ from fla.ops.utils.index import prepare_lens_from_mask
15
+
16
+ if TYPE_CHECKING:
17
+ from fla.models.utils import Cache
18
+
19
+ logger = logging.get_logger(__name__)
20
+
21
+
22
+ class NativeSparseAttention(nn.Module):
23
+
24
+ def __init__(
25
+ self,
26
+ hidden_size: int = 2048,
27
+ num_heads: int = 64,
28
+ num_kv_heads: int | None = 4,
29
+ head_dim: int = 64,
30
+ qkv_bias: bool = False,
31
+ block_size: int | None = 64,
32
+ block_counts: torch.LongTensor | int | None = 16,
33
+ window_size: int | None = 512,
34
+ rope_theta: float | None = 10000.,
35
+ max_position_embeddings: int | None = None,
36
+ layer_idx: int = None,
37
+ ):
38
+ super().__init__()
39
+
40
+ self.hidden_size = hidden_size
41
+ self.num_heads = num_heads
42
+ if num_kv_heads is None:
43
+ self.num_kv_heads = self.num_heads
44
+ else:
45
+ self.num_kv_heads = num_kv_heads
46
+ self.num_kv_groups = num_heads // self.num_kv_heads
47
+ self.head_dim = head_dim
48
+ self.kv_dim = self.num_kv_heads * self.head_dim
49
+ self.qkv_bias = qkv_bias
50
+
51
+ self.block_size = block_size
52
+ self.block_counts = block_counts
53
+ self.window_size = window_size
54
+ self.rope_theta = rope_theta
55
+ self.max_position_embeddings = max_position_embeddings
56
+ self.layer_idx = layer_idx
57
+
58
+ self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=self.qkv_bias)
59
+ self.k_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
60
+ self.v_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=self.qkv_bias)
61
+ self.g_proj = nn.Linear(self.hidden_size, self.num_heads * 3, bias=False)
62
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
63
+
64
+ self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta)
65
+
66
+ def forward(
67
+ self,
68
+ hidden_states: torch.Tensor,
69
+ attention_mask: torch.LongTensor | None = None,
70
+ past_key_values: Cache | None = None,
71
+ output_attentions: bool = False,
72
+ use_cache: bool = False,
73
+ **kwargs,
74
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
75
+ if attention_mask is not None:
76
+ assert len(attention_mask.shape) == 2, (
77
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
78
+ "for padding purposes (0 indicating padding). "
79
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
80
+ )
81
+
82
+ batch_size, seq_len, _ = hidden_states.size()
83
+
84
+ q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
85
+ k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
86
+ v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
87
+ g = rearrange(self.g_proj(hidden_states), '... (h d) -> ... h d', d=3)
88
+ g_cmp, g_slc, g_swa = g.sigmoid().unbind(-1)
89
+
90
+ cu_seqlens = kwargs.get('cu_seqlens')
91
+
92
+ seqlen_offset, max_seqlen = 0, seq_len
93
+ if past_key_values is not None:
94
+ seqlen_offset = past_key_values.get_seq_length(self.layer_idx)
95
+ max_seqlen = q.shape[1] + seqlen_offset
96
+
97
+ if attention_mask is not None:
98
+ # to deliminate the offsets of padding tokens
99
+ seqlen_offset = seqlen_offset + prepare_lens_from_mask(attention_mask) - attention_mask.shape[-1]
100
+ max_seqlen = q.shape[1] + max(seqlen_offset)
101
+
102
+ if self.max_position_embeddings is not None:
103
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
104
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens)
105
+
106
+ if past_key_values is not None:
107
+ cache_has_content = past_key_values.get_seq_length(self.layer_idx) > 0
108
+ k_cached, v_cached = past_key_values.update(
109
+ attn_state=(k.flatten(-2, -1), v.flatten(-2, -1)),
110
+ layer_idx=self.layer_idx,
111
+ offset=seq_len,
112
+ cache_kwargs=dict(window_size=self.window_size),
113
+ )['attn_state']
114
+ if cache_has_content:
115
+ k, v = k_cached, v_cached
116
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
117
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
118
+
119
+ o = parallel_nsa(
120
+ q=q,
121
+ k=k,
122
+ v=v,
123
+ g_cmp=g_cmp,
124
+ g_slc=g_slc,
125
+ g_swa=g_swa,
126
+ block_size=self.block_size,
127
+ block_counts=self.block_counts,
128
+ window_size=self.window_size,
129
+ cu_seqlens=cu_seqlens,
130
+ )
131
+ o = o.reshape(batch_size, seq_len, -1)
132
+ o = self.o_proj(o)
133
+
134
+ if not output_attentions:
135
+ attentions = None
136
+
137
+ return o, attentions, past_key_values
fla/layers/path_attn.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ from einops import rearrange
11
+ from transformers.utils import logging
12
+
13
+ from fla.layers.utils import pad_input, unpad_input
14
+ from fla.modules import RMSNorm, ShortConvolution
15
+ from fla.modules.l2norm import l2_norm
16
+ from fla.ops.attn.decoding import attn_decoding_one_step
17
+ from fla.ops.path_attn.parallel import parallel_path_attn
18
+
19
+ if TYPE_CHECKING:
20
+ from fla.models.utils import Cache
21
+
22
+ logger = logging.get_logger(__name__)
23
+
24
+
25
+ class PaTHAttention(nn.Module):
26
+ def __init__(
27
+ self,
28
+ hidden_size: int = 2048,
29
+ num_heads: int = 32,
30
+ num_kv_heads: int | None = None,
31
+ use_forget_gate: bool = False,
32
+ use_qk_norm: bool = False,
33
+ layer_idx: int = None,
34
+ use_low_rank_w: bool = True,
35
+ use_w_shortconv: bool = True,
36
+ conv_size: int = 3,
37
+ conv_bias: bool = False,
38
+ ):
39
+ super().__init__()
40
+
41
+ self.hidden_size = hidden_size
42
+ self.num_heads = num_heads
43
+ if num_kv_heads is None:
44
+ self.num_kv_heads = self.num_heads
45
+ else:
46
+ self.num_kv_heads = num_kv_heads
47
+ self.head_dim = self.hidden_size // self.num_heads
48
+ self.kv_dim = self.num_kv_heads * self.head_dim
49
+
50
+ self.layer_idx = layer_idx
51
+
52
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
53
+ self.k_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=False)
54
+ self.v_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=False)
55
+
56
+ # We use low-rank parameterization for the w_proj to reduce parameters in MHA settings.
57
+ if use_low_rank_w:
58
+ self.w_proj = nn.Sequential(
59
+ nn.Linear(self.hidden_size, 32, bias=False),
60
+ nn.Linear(32, self.kv_dim, bias=False),
61
+ )
62
+ # In MQA/GQA settings, key/value heads are shared, so we use a standard linear projection
63
+ # which doesn't introduce too many parameters
64
+ else:
65
+ self.w_proj = nn.Linear(self.hidden_size, self.kv_dim, bias=False)
66
+
67
+ # per head norm
68
+ if use_qk_norm:
69
+ self.maybe_q_norm = RMSNorm(self.head_dim, dtype=torch.float32)
70
+ self.maybe_k_norm = RMSNorm(self.head_dim, dtype=torch.float32)
71
+ else:
72
+ self.maybe_q_norm = nn.Identity()
73
+ self.maybe_k_norm = nn.Identity()
74
+
75
+ if use_w_shortconv:
76
+ self.w_conv1d = ShortConvolution(hidden_size=self.kv_dim, kernel_size=conv_size, bias=conv_bias, activation='silu')
77
+ self.use_w_shortconv = use_w_shortconv
78
+ self.bt_proj = nn.Linear(self.hidden_size, self.num_kv_heads, bias=True)
79
+ self.use_forget_gate = use_forget_gate
80
+ if use_forget_gate:
81
+ self.g_proj = nn.Linear(self.hidden_size, self.num_heads, bias=True)
82
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
83
+
84
+ def forward(
85
+ self,
86
+ hidden_states: torch.Tensor,
87
+ attention_mask: torch.LongTensor | None = None,
88
+ past_key_values: Cache | None = None,
89
+ output_attentions: bool = False,
90
+ use_cache: bool = False,
91
+ **kwargs,
92
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
93
+ if use_cache:
94
+ assert past_key_values is not None, "past_key_values must be provided when use_cache is True"
95
+ if attention_mask is not None:
96
+ assert len(attention_mask.shape) == 2, (
97
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
98
+ "for padding purposes (0 indicating padding). "
99
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
100
+ )
101
+ batch_size, q_len, _ = hidden_states.size()
102
+ q = self.q_proj(hidden_states)
103
+ k = self.k_proj(hidden_states)
104
+ v = self.v_proj(hidden_states)
105
+ w = self.w_proj(hidden_states)
106
+ beta = self.bt_proj(hidden_states).float().sigmoid() * 2 # allowing negative eigenvalues
107
+ g = F.logsigmoid(self.g_proj(hidden_states).float()) if self.use_forget_gate else None
108
+ cu_seqlens = kwargs.get('cu_seqlens')
109
+ assert not (cu_seqlens is not None and attention_mask is not None), (
110
+ "cu_seqlens should not be provided when attention_mask is not None"
111
+ )
112
+ # Training
113
+ if attention_mask is None:
114
+ assert use_cache is False, "use_cache should be False in training"
115
+ if self.use_w_shortconv:
116
+ w, _ = self.w_conv1d(w, cache=None, output_final_state=False, cu_seqlens=cu_seqlens)
117
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_dim)
118
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
119
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
120
+ w = rearrange(w, '... (h d) -> ... h d', d=self.head_dim)
121
+ q, k = self.maybe_q_norm(q), self.maybe_k_norm(k)
122
+ w = l2_norm(w, output_dtype=torch.float32)
123
+ o, _ = parallel_path_attn(q=q, k=k, v=v, w=w, beta=beta, g=g, cu_seqlens=cu_seqlens)
124
+
125
+ # Prefilling or decoding
126
+ else:
127
+ assert self.training is False, "attention mask is not supported in training. Please use variable length input."
128
+ try:
129
+ last_state = past_key_values[self.layer_idx]
130
+ except KeyError:
131
+ last_state = None
132
+ # Decoding
133
+ if last_state is not None:
134
+ if g is not None:
135
+ past_k, past_v, past_g = last_state['attn_state']
136
+ else:
137
+ past_k, past_v = last_state['attn_state']
138
+ past_g = None
139
+ w_conv_state = last_state['conv_state']
140
+ past_k = rearrange(past_k, '... (h d) -> ... h d', d=self.head_dim)
141
+ if self.use_w_shortconv:
142
+ w, w_conv_state = self.w_conv1d(w, cache=w_conv_state, output_final_state=use_cache, cu_seqlens=cu_seqlens)
143
+ w = rearrange(w, '... (h d) -> ... h d', d=self.head_dim)
144
+ w = l2_norm(w, output_dtype=torch.float32)
145
+
146
+ @torch.compile
147
+ def rank_one_update(k, w, beta):
148
+ original_dtype = k.dtype
149
+ k = k.float()
150
+ w = w.float()
151
+ beta = beta.float()
152
+ k = k - beta[..., None].float() * (k * w).sum(-1, keepdim=True) * w
153
+ return k.to(original_dtype)
154
+
155
+ past_k = rank_one_update(past_k, w, beta)
156
+ past_k = rearrange(past_k, '... h d -> ... (h d)')
157
+ k = torch.cat([past_k, k], dim=1)
158
+ v = torch.cat([past_v, v], dim=1)
159
+ g = torch.cat([past_g, g], dim=1) if g is not None else None
160
+ past_key_values[self.layer_idx]['attn_state'] = (k, v, g) if g is not None else (k, v)
161
+ past_key_values.update(
162
+ conv_state=w_conv_state,
163
+ layer_idx=self.layer_idx,
164
+ offset=q_len,
165
+ )
166
+ if g is not None:
167
+ q, (k, v, g), indices_q, cu_seqlens, max_seq_lens = unpad_input(
168
+ q, (k, v, g), attention_mask, q_len, keepdim=True)
169
+ max_seqlen_q, max_seqlen_k = max_seq_lens
170
+ else:
171
+ q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input(
172
+ q, (k, v), attention_mask, q_len, keepdim=True)
173
+ max_seqlen_q, max_seqlen_k = max_seq_lens
174
+ _, cu_seqlens = cu_seqlens
175
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_dim)
176
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
177
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
178
+ assert max_seqlen_q == 1, "only support q_len == 1 for decoding"
179
+ o = attn_decoding_one_step(q, k, v, g, cu_seqlens=cu_seqlens, do_gate_scale=True) # reduced to fox's decoding
180
+ # Prefilling
181
+ else:
182
+ v_cache = v.clone()
183
+ g_cache = g.clone() if g is not None else None
184
+ if g is None:
185
+ q, (k, v, w, beta), indices_q, cu_seqlens, max_seq_lens = unpad_input(
186
+ q, (k, v, w, beta), attention_mask, q_len, keepdim=True)
187
+ else:
188
+ q, (k, v, w, beta, g), indices_q, cu_seqlens, max_seq_lens = unpad_input(
189
+ q, (k, v, w, beta, g), attention_mask, q_len, keepdim=True)
190
+ max_seqlen_q, max_seqlen_k = max_seq_lens
191
+ assert max_seqlen_q == max_seqlen_k, "max_seqlen_q should be equal to max_seqlen_k in prefilling"
192
+ _, cu_seqlens = cu_seqlens
193
+ if self.use_w_shortconv:
194
+ w, w_conv_state = self.w_conv1d(w, cache=None, output_final_state=use_cache, cu_seqlens=cu_seqlens)
195
+ else:
196
+ w_conv_state = None
197
+ q = rearrange(q, '... (h d) -> ... h d', d=self.head_dim)
198
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
199
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
200
+ w = rearrange(w, '... (h d) -> ... h d', d=self.head_dim)
201
+ w = l2_norm(w, output_dtype=torch.float32)
202
+ o, k_cache = parallel_path_attn(q=q, k=k, v=v, w=w, beta=beta, g=g,
203
+ cu_seqlens=cu_seqlens, use_cache=use_cache)
204
+ if use_cache:
205
+ k_cache = pad_input(k_cache.squeeze(0), indices_q, batch_size, q_len)
206
+ k_cache = rearrange(k_cache, '... h d -> ... (h d)')
207
+ past_key_values.update(
208
+ attn_state=(k_cache, v_cache, g_cache) if g_cache is not None else (k_cache, v_cache),
209
+ conv_state=w_conv_state,
210
+ layer_idx=self.layer_idx,
211
+ offset=q_len,
212
+ )
213
+ o = pad_input(o.squeeze(0), indices_q, batch_size, q_len)
214
+ o = rearrange(o, '... h d -> ... (h d)')
215
+ o = self.o_proj(o)
216
+ return o, None, past_key_values
fla/layers/quasar.py ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+ # Modified for QuasarAttention
3
+
4
+ from __future__ import annotations
5
+
6
+ import contextlib
7
+ import math
8
+ import os
9
+ from typing import TYPE_CHECKING
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ from einops import rearrange, repeat
14
+ from torch.nn import functional as F
15
+
16
+ from fla.layers.utils import get_unpad_data, index_first_axis, pad_input
17
+
18
+
19
+ def _quasar_debug_tensor(name: str, tensor: torch.Tensor, layer_idx: int | None) -> None:
20
+ if os.environ.get("QUASAR_DEBUG_FINITE", "0") != "1":
21
+ return
22
+ if tensor is None or torch.isfinite(tensor).all():
23
+ return
24
+ with torch.no_grad():
25
+ t = torch.nan_to_num(tensor.detach().float(), nan=0.0, posinf=0.0, neginf=0.0)
26
+ nonfinite = int((~torch.isfinite(tensor)).sum().item())
27
+ print(
28
+ f"[QUASAR DEBUG] layer={layer_idx} stage={name} nonfinite={nonfinite} "
29
+ f"min={float(t.min())} max={float(t.max())} mean={float(t.mean())}",
30
+ flush=True,
31
+ )
32
+
33
+
34
+ class _TorchRMSNormGated(nn.Module):
35
+ def __init__(self, hidden_size: int, activation: str = "sigmoid", eps: float = 1e-5):
36
+ super().__init__()
37
+ self.weight = nn.Parameter(torch.ones(hidden_size))
38
+ self.activation = activation
39
+ self.eps = eps
40
+
41
+ def reset_parameters(self) -> None:
42
+ self.weight.data.fill_(1.0)
43
+
44
+ def forward(self, x: torch.Tensor, gate: torch.Tensor) -> torch.Tensor:
45
+ dtype = x.dtype
46
+ y = torch.nan_to_num(
47
+ x.float(),
48
+ nan=0.0,
49
+ posinf=1e4,
50
+ neginf=-1e4,
51
+ ).clamp_(min=-1e4, max=1e4)
52
+ y = y * torch.rsqrt(y.square().mean(dim=-1, keepdim=True) + self.eps)
53
+ weight = torch.nan_to_num(
54
+ self.weight.float(),
55
+ nan=1.0,
56
+ posinf=1.0,
57
+ neginf=1.0,
58
+ ).clamp_(min=0.0, max=4.0)
59
+ y = y.to(dtype) * weight.to(dtype=dtype, device=x.device)
60
+ gate = torch.nan_to_num(
61
+ gate.float(),
62
+ nan=0.0,
63
+ posinf=30.0,
64
+ neginf=-30.0,
65
+ ).clamp_(min=-30.0, max=30.0)
66
+ if self.activation in {"swish", "silu"}:
67
+ gate = gate * torch.sigmoid(gate)
68
+ elif self.activation == "sigmoid":
69
+ gate = torch.sigmoid(gate)
70
+ return y * gate.to(dtype=dtype, device=x.device)
71
+
72
+
73
+ def rotate_half(x):
74
+ """Rotates half the hidden dims of the input."""
75
+ x1 = x[..., : x.shape[-1] // 2]
76
+ x2 = x[..., x.shape[-1] // 2 :]
77
+ return torch.cat((-x2, x1), dim=-1)
78
+
79
+ def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None):
80
+ """Applies Rotary Position Embedding to the query and key tensors."""
81
+ # cos, sin: [1, 1, seq_len, rotary_dim]
82
+ # q, k: [batch_size, seq_len, n_heads, head_dim]
83
+ rotary_dim = cos.shape[-1]
84
+ q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:]
85
+ k_rot, k_pass = k[..., :rotary_dim], k[..., rotary_dim:]
86
+ cos = cos.transpose(1, 2) # [1, seq_len, 1, rotary_dim]
87
+ sin = sin.transpose(1, 2) # [1, seq_len, 1, rotary_dim]
88
+ q_embed = (q_rot * cos) + (rotate_half(q_rot) * sin)
89
+ k_embed = (k_rot * cos) + (rotate_half(k_rot) * sin)
90
+ return torch.cat([q_embed, q_pass], dim=-1), torch.cat([k_embed, k_pass], dim=-1)
91
+
92
+ if TYPE_CHECKING:
93
+ from transformers.processing_utils import Unpack
94
+
95
+ from fla.models.utils import Cache
96
+
97
+
98
+ class QuasarAttention(nn.Module):
99
+ """
100
+ QuasarAttention layer implementation.
101
+
102
+ Args:
103
+ hidden_size (int, Optional):
104
+ The hidden size of the input. Default: 2048.
105
+ head_dim (int, Optional):
106
+ The dimension of each head. Default: 128.
107
+ num_heads (int, Optional):
108
+ The number of heads. Default: 16.
109
+ mode (str, Optional):
110
+ Which QuasarAttention kernel to use.
111
+ Currently available: `chunk` and `fused_recurrent`.
112
+ Default: `chunk`.
113
+ use_short_conv (bool, Optional):
114
+ Whether to use short convolutions. Default: `True`.
115
+ conv_size (int, Optional):
116
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
117
+ conv_bias (bool, Optional):
118
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
119
+ layer_idx (int, Optional):
120
+ The index of the layer. Default: None.
121
+ norm_eps (float, Optional):
122
+ The epsilon value for the normalization layer. Default: 1e-5.
123
+ """
124
+
125
+ def __init__(
126
+ self,
127
+ hidden_size: int = 2048,
128
+ head_dim: int = 128,
129
+ num_heads: int = 16,
130
+ mode: str = "chunk",
131
+ use_short_conv: bool = True,
132
+ conv_size: int = 4,
133
+ conv_bias: bool = False,
134
+ layer_idx: int = None,
135
+ norm_eps: float = 1e-5,
136
+ **kwargs,
137
+ ) -> QuasarAttention:
138
+ super().__init__()
139
+
140
+ self.mode = mode
141
+ self.hidden_size = hidden_size
142
+
143
+ self.use_short_conv = use_short_conv
144
+ self.conv_size = conv_size
145
+ self.conv_bias = conv_bias
146
+
147
+ self.head_dim = head_dim
148
+ self.num_heads = num_heads
149
+ self.key_dim = int(self.num_heads * self.head_dim)
150
+ self.value_dim = int(self.num_heads * self.head_dim)
151
+ self.layer_idx = layer_idx
152
+
153
+ assert mode in ["chunk", "fused_recurrent"], f"Not supported mode `{mode}`."
154
+
155
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
156
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
157
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
158
+
159
+ # KDA matching: Use SiLU on q, k, v for better learning if not using short conv
160
+ # (Short conv already has its own activation)
161
+ self.q_act = nn.SiLU()
162
+ self.k_act = nn.SiLU()
163
+ self.v_act = nn.SiLU()
164
+
165
+ if use_short_conv:
166
+ from fla.modules.convolution import ShortConvolution
167
+
168
+ self.q_conv1d = ShortConvolution(
169
+ hidden_size=self.key_dim,
170
+ kernel_size=conv_size,
171
+ bias=conv_bias,
172
+ activation="silu",
173
+ )
174
+ self.k_conv1d = ShortConvolution(
175
+ hidden_size=self.key_dim,
176
+ kernel_size=conv_size,
177
+ bias=conv_bias,
178
+ activation="silu",
179
+ )
180
+ self.v_conv1d = ShortConvolution(
181
+ hidden_size=self.value_dim,
182
+ kernel_size=conv_size,
183
+ bias=conv_bias,
184
+ activation="silu",
185
+ )
186
+
187
+ # Data-dependent Beta (Adaptive Decay)
188
+ # Instead of a static per-head parameter, we use a linear projection
189
+ # to allow the model to learn contextual importance (read/write sharpness).
190
+ self.b_proj = nn.Linear(hidden_size, self.num_heads, bias=False)
191
+
192
+ # Learnable state decay (like KDA/Mamba A matrix)
193
+ self.A_log = nn.Parameter(torch.log(torch.empty(self.num_heads, dtype=torch.float32).uniform_(1, 16)))
194
+ self.A_log._no_weight_decay = True
195
+ self.dt_bias = nn.Parameter(torch.zeros(self.key_dim, dtype=torch.float32))
196
+ self.dt_bias._no_weight_decay = True
197
+
198
+ # KIMI matches: separate f_proj for kernel and g_proj for final output gating
199
+ self.f_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
200
+ self.g_proj = nn.Sequential(
201
+ nn.Linear(hidden_size, self.head_dim, bias=False),
202
+ nn.Linear(self.head_dim, self.value_dim, bias=True),
203
+ )
204
+
205
+ self.o_norm = _TorchRMSNormGated(self.head_dim, activation="sigmoid", eps=norm_eps)
206
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
207
+
208
+ def reset_parameters(self) -> None:
209
+ for module in self.children():
210
+ reset = getattr(module, "reset_parameters", None)
211
+ if callable(reset):
212
+ reset()
213
+
214
+ def forward(
215
+ self,
216
+ hidden_states: torch.Tensor,
217
+ attention_mask: torch.Tensor | None = None,
218
+ past_key_values: Cache | None = None,
219
+ use_cache: bool | None = False,
220
+ output_attentions: bool | None = False,
221
+ **kwargs: Unpack[dict],
222
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
223
+ if attention_mask is not None:
224
+ assert len(attention_mask.shape) == 2, (
225
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
226
+ "for padding purposes (0 indicating padding). "
227
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
228
+ )
229
+
230
+ batch_size, q_len, _ = hidden_states.shape
231
+ mode = self.mode
232
+ if self.training and mode == "fused_recurrent":
233
+ # The fused recurrent Quasar path is forward-only in this tree.
234
+ # Training must use the chunk kernel until its backward exists.
235
+ mode = "chunk"
236
+
237
+ # Bailing hidden states can be very large after MoE/FSDP checkpoint
238
+ # restore. Quasar's delta-rule triangular solve is much more sensitive
239
+ # to projection scale than GQA/GLA, so sanitize and RMS-normalize only
240
+ # the Quasar branch input. The residual model path remains untouched.
241
+ input_dtype = hidden_states.dtype
242
+ hidden_states = torch.nan_to_num(
243
+ hidden_states.float(),
244
+ nan=0.0,
245
+ posinf=60.0,
246
+ neginf=-60.0,
247
+ ).clamp_(min=-60.0, max=60.0)
248
+ hidden_states = hidden_states * torch.rsqrt(
249
+ hidden_states.square().mean(dim=-1, keepdim=True) + 1e-6
250
+ )
251
+ hidden_states = hidden_states.to(dtype=input_dtype)
252
+ _quasar_debug_tensor("input_normed", hidden_states, self.layer_idx)
253
+
254
+ last_state = None
255
+ recurrent_state = None
256
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
257
+
258
+ if past_key_values is not None and self.layer_idx is not None:
259
+ if hasattr(past_key_values, "recurrent_states") and self.layer_idx in past_key_values.recurrent_states:
260
+ recurrent_state = past_key_values.recurrent_states[self.layer_idx]
261
+ if hasattr(past_key_values, "conv_states") and self.layer_idx in past_key_values.conv_states:
262
+ conv_state_q, conv_state_k, conv_state_v = past_key_values.conv_states[self.layer_idx]
263
+ else:
264
+ try:
265
+ # Standard list/tuple cache (FLA style fallback)
266
+ if len(past_key_values) > self.layer_idx:
267
+ last_state = past_key_values[self.layer_idx]
268
+ if isinstance(last_state, dict):
269
+ recurrent_state = last_state.get("recurrent_state", None)
270
+ convs = last_state.get("conv_state", None)
271
+ if convs is not None:
272
+ conv_state_q, conv_state_k, conv_state_v = convs
273
+ except TypeError:
274
+ pass
275
+
276
+ cu_seqlens = kwargs.get("cu_seqlens")
277
+ if attention_mask is not None:
278
+ # Optimization: Skip unpadding if all tokens are valid (common in packed distillation)
279
+ if attention_mask.all():
280
+ indices, cu_seqlens = None, None
281
+ else:
282
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
283
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
284
+ else:
285
+ indices = None
286
+
287
+ if self.use_short_conv:
288
+ q, conv_state_q = self.q_conv1d(
289
+ x=self.q_proj(hidden_states),
290
+ cache=conv_state_q,
291
+ output_final_state=use_cache,
292
+ cu_seqlens=cu_seqlens,
293
+ )
294
+ k, conv_state_k = self.k_conv1d(
295
+ x=self.k_proj(hidden_states),
296
+ cache=conv_state_k,
297
+ output_final_state=use_cache,
298
+ cu_seqlens=cu_seqlens,
299
+ )
300
+ v, conv_state_v = self.v_conv1d(
301
+ x=self.v_proj(hidden_states),
302
+ cache=conv_state_v,
303
+ output_final_state=use_cache,
304
+ cu_seqlens=cu_seqlens,
305
+ )
306
+ else:
307
+ q = self.q_act(self.q_proj(hidden_states))
308
+ k = self.k_act(self.k_proj(hidden_states))
309
+ v = self.v_act(self.v_proj(hidden_states))
310
+ _quasar_debug_tensor("q_proj", q, self.layer_idx)
311
+ _quasar_debug_tensor("k_proj", k, self.layer_idx)
312
+ _quasar_debug_tensor("v_proj", v, self.layer_idx)
313
+
314
+ q = rearrange(q, "... (h d) -> ... h d", d=self.head_dim)
315
+ k = rearrange(k, "... (h d) -> ... h d", d=self.head_dim)
316
+ v = rearrange(v, "... (h d) -> ... h d", d=self.head_dim)
317
+
318
+ # Apply RoPE if provided
319
+ cos = kwargs.get("cos")
320
+ sin = kwargs.get("sin")
321
+ if cos is not None and sin is not None:
322
+ if attention_mask is not None:
323
+ # Unpad cos/sin using the same indices
324
+ # cos/sin shape is [1, 1, seq_len, head_dim] or [batch_size, seq_len, head_dim]
325
+ if cos.shape[0] == 1 and cos.shape[1] == 1:
326
+ # Broadcastable/Shared RoPE [1, 1, seq_len, head_dim]
327
+ # We need to expand to [batch_size, seq_len, head_dim] before unpadding
328
+ cos_expanded = cos.squeeze(1).expand(batch_size, -1, -1)
329
+ sin_expanded = sin.squeeze(1).expand(batch_size, -1, -1)
330
+ cos = index_first_axis(rearrange(cos_expanded, "b s d -> (b s) d"), indices).unsqueeze(0).unsqueeze(1)
331
+ sin = index_first_axis(rearrange(sin_expanded, "b s d -> (b s) d"), indices).unsqueeze(0).unsqueeze(1)
332
+ else:
333
+ # Already [batch_size, 1, seq_len, head_dim] or [batch_size, seq_len, head_dim]
334
+ if cos.dim() == 4:
335
+ cos = cos.squeeze(1)
336
+ sin = sin.squeeze(1)
337
+ cos = index_first_axis(rearrange(cos, "b s d -> (b s) d"), indices).unsqueeze(0).unsqueeze(1)
338
+ sin = index_first_axis(rearrange(sin, "b s d -> (b s) d"), indices).unsqueeze(0).unsqueeze(1)
339
+
340
+ q, k = apply_rotary_pos_emb(q, k, cos, sin)
341
+
342
+ # QK Normalization AFTER RoPE — ensures kernel receives unit-norm vectors
343
+ # regardless of any precision drift introduced by the rotation
344
+ q = F.normalize(q, p=2, dim=-1)
345
+ k = F.normalize(k, p=2, dim=-1)
346
+ _quasar_debug_tensor("q_norm", q, self.layer_idx)
347
+ _quasar_debug_tensor("k_norm", k, self.layer_idx)
348
+
349
+ # Adaptive Beta: Sigmoid(b_proj(x)) is bounded to (0, 1) to prevent explosions.
350
+ beta = self.b_proj(hidden_states).sigmoid()
351
+ _quasar_debug_tensor("beta", beta, self.layer_idx)
352
+
353
+ if mode == "chunk":
354
+ from fla.ops.quasar.chunk import chunk_quasar
355
+
356
+ o, recurrent_state = chunk_quasar(
357
+ q=q,
358
+ k=k,
359
+ v=v,
360
+ beta=beta,
361
+ A_log=self.A_log,
362
+ dt_bias=self.dt_bias,
363
+ initial_state=recurrent_state,
364
+ output_final_state=use_cache,
365
+ cu_seqlens=cu_seqlens,
366
+ use_qk_l2norm_in_kernel=True,
367
+ )
368
+ _quasar_debug_tensor("chunk_kernel_o", o, self.layer_idx)
369
+ elif mode == "fused_recurrent":
370
+ from fla.ops.quasar.fused_recurrent import fused_recurrent_quasar
371
+
372
+ # Use f_proj for kernel gate in fused mode
373
+ f_gate = self.f_proj(hidden_states)
374
+ f_gate = rearrange(f_gate, "... (h d) -> ... h d", d=self.head_dim)
375
+ o, recurrent_state = fused_recurrent_quasar(
376
+ q=q,
377
+ k=k,
378
+ v=v,
379
+ g=f_gate,
380
+ beta=beta,
381
+ A_log=self.A_log,
382
+ dt_bias=self.dt_bias,
383
+ initial_state=recurrent_state,
384
+ output_final_state=use_cache,
385
+ use_qk_l2norm_in_kernel=True,
386
+ )
387
+ _quasar_debug_tensor("fused_kernel_o", o, self.layer_idx)
388
+ else:
389
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
390
+
391
+ o = torch.nan_to_num(
392
+ o.float(),
393
+ nan=0.0,
394
+ posinf=1e4,
395
+ neginf=-1e4,
396
+ ).clamp_(min=-1e4, max=1e4).to(dtype=v.dtype)
397
+ _quasar_debug_tensor("kernel_o_clamped", o, self.layer_idx)
398
+
399
+ if past_key_values is not None:
400
+ if hasattr(past_key_values, "update_quasar_state"):
401
+ past_key_values.update_quasar_state(
402
+ self.layer_idx,
403
+ recurrent_state,
404
+ (conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None
405
+ )
406
+ else:
407
+ with contextlib.suppress(TypeError):
408
+ past_key_values.update(
409
+ recurrent_state=recurrent_state,
410
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
411
+ layer_idx=self.layer_idx,
412
+ offset=q_len,
413
+ )
414
+
415
+ # Final output gating using g_proj
416
+ # Handle flattened inputs (unpadded) from FSDP/Flash-Linear-Attention
417
+ if hidden_states.dim() == 2:
418
+ # (N, D) -> (N, H, D/H)
419
+ g = self.g_proj(hidden_states)
420
+ g = rearrange(g, "n (h d) -> n h d", d=self.head_dim)
421
+ _quasar_debug_tensor("output_gate", g, self.layer_idx)
422
+ o = self.o_norm(o, g)
423
+ o = rearrange(o, "n h d -> n (h d)")
424
+ else:
425
+ # (B, S, D) -> (B, S, H, D/H)
426
+ g = self.g_proj(hidden_states)
427
+ g = rearrange(g, "b s (h d) -> b s h d", d=self.head_dim)
428
+ _quasar_debug_tensor("output_gate", g, self.layer_idx)
429
+ o = self.o_norm(o, g)
430
+ o = rearrange(o, "b s h d -> b s (h d)")
431
+ _quasar_debug_tensor("post_norm_gate", o, self.layer_idx)
432
+
433
+ o = self.o_proj(o)
434
+ _quasar_debug_tensor("o_proj", o, self.layer_idx)
435
+ if attention_mask is not None:
436
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
437
+
438
+ # LFM2 expects 2 return values (hidden_states, _)
439
+ return o, None
fla/layers/rebased.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ """
4
+ https://github.com/corl-team/rebased/blob/main/flash_linear_attention/fla/layers/rebased_fast.py
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from einops import rearrange
12
+
13
+ from fla.modules.feature_map import RebasedFeatureMap
14
+ from fla.ops.linear_attn import chunk_linear_attn, fused_chunk_linear_attn
15
+ from fla.ops.rebased import parallel_rebased
16
+
17
+
18
+ class ReBasedLinearAttention(nn.Module):
19
+
20
+ def __init__(
21
+ self,
22
+ hidden_size: int,
23
+ l_max: int = 2048,
24
+ feature_dim: int = 16,
25
+ num_key_value_heads: int = 16,
26
+ num_heads: int = 16,
27
+ use_gamma: bool | None = True,
28
+ use_beta: bool | None = True,
29
+ normalize: bool | None = True,
30
+ causal: bool = True,
31
+ eps: float = 1e-5,
32
+ mode: str = "parallel",
33
+ layer_idx: int | None = None,
34
+ **kwargs,
35
+ ) -> ReBasedLinearAttention:
36
+ super().__init__()
37
+ self.hidden_size = hidden_size
38
+ self.l_max = l_max
39
+ self.mode = mode
40
+ assert self.mode in ["fused_chunk", "parallel", 'chunk']
41
+
42
+ self.feature_dim = feature_dim
43
+ self.num_key_value_heads = num_key_value_heads
44
+ self.num_heads = num_heads
45
+ self.head_dim = self.hidden_size // self.num_key_value_heads
46
+ self.use_gamma = use_gamma
47
+ self.use_beta = use_beta
48
+ self.normalize = normalize
49
+ self.causal = causal
50
+ self.eps = eps
51
+ self.mode = mode
52
+ self.layer_idx = layer_idx
53
+
54
+ self.feature_map = RebasedFeatureMap(self.feature_dim, use_gamma, use_beta, normalize)
55
+ self.q_proj = nn.Linear(self.hidden_size, self.feature_dim * self.num_heads, bias=False)
56
+ self.k_proj = nn.Linear(self.hidden_size, self.feature_dim * self.num_heads, bias=False)
57
+ self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=False)
58
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
59
+ self.dropout = nn.Identity()
60
+
61
+ def forward(self, hidden_states: torch.Tensor, **kwargs):
62
+ mode = self.mode
63
+ q = rearrange(
64
+ self.q_proj(hidden_states),
65
+ "... (h d) -> ... h d",
66
+ h=self.num_heads,
67
+ d=self.feature_dim,
68
+ )
69
+ k = rearrange(
70
+ self.k_proj(hidden_states),
71
+ "... (h d) -> ... h d",
72
+ h=self.num_heads,
73
+ d=self.feature_dim,
74
+ )
75
+ v = rearrange(
76
+ self.v_proj(hidden_states),
77
+ "... (h d) -> ... h d",
78
+ h=self.num_key_value_heads,
79
+ d=self.head_dim,
80
+ )
81
+ q, k = self.feature_map(q, flatten=(mode != 'parallel')), self.feature_map(k, flatten=(mode != 'parallel'))
82
+ if mode == "fused_chunk":
83
+ o = fused_chunk_linear_attn(
84
+ q=q,
85
+ k=k,
86
+ v=v,
87
+ normalize=True,
88
+ scale=1,
89
+ )
90
+ elif mode == 'chunk':
91
+ o = chunk_linear_attn(
92
+ q=q,
93
+ k=k,
94
+ v=v,
95
+ normalize=True,
96
+ scale=1,
97
+ )
98
+ elif mode == 'parallel':
99
+ assert q.shape[-1] <= 128
100
+ o = parallel_rebased(
101
+ q=q,
102
+ k=k,
103
+ v=v,
104
+ eps=self.eps,
105
+ use_scale=True,
106
+ use_normalize=True,
107
+ )
108
+ o = rearrange(o, "... h d -> ... (h d)")
109
+ o = self.o_proj(o)
110
+ o = self.dropout(o)
111
+ return o
112
+
113
+ # https://github.com/HazyResearch/zoology/blob/main/zoology/mixers/based.py#L119
114
+ def forward_reference(
115
+ self,
116
+ hidden_states: torch.Tensor,
117
+ filters: torch.Tensor = None,
118
+ *args,
119
+ **kwargs,
120
+ ):
121
+ """
122
+ x (torch.Tensor): tensor of shape (b, d, t)
123
+ y (torch.Tensor): tensor of shape (b, d, t)
124
+ """
125
+ b, t, _ = hidden_states.size()
126
+ q, k, v = self.q_proj(hidden_states), self.k_proj(hidden_states), self.v_proj(hidden_states)
127
+
128
+ q = q.view(b, t, -1, self.feature_dim).transpose(1, 2)
129
+ k = k.view(b, t, -1, self.feature_dim).transpose(1, 2)
130
+ v = v.view(b, t, -1, self.head_dim).transpose(1, 2)
131
+
132
+ # Linear attention
133
+ q, k = self.feature_map(q), self.feature_map(k)
134
+ q, k, v = q.unsqueeze(-2), k.unsqueeze(-2), v.unsqueeze(-1)
135
+
136
+ # Compute attention
137
+ if self.causal:
138
+ y = ((q * (k * v).cumsum(2)).sum(-1) / ((q * k.cumsum(2)).sum(-1) + self.eps))
139
+ else:
140
+ y = ((q * (k * v).sum(2, True)).sum(-1) / ((q * k.sum(2, True)).sum(-1) + self.eps))
141
+ y = rearrange(y, 'b h t d -> b t (h d)')
142
+ y = self.o_proj(y.to(hidden_states.dtype))
143
+ y = self.dropout(y)
144
+ return y.to(hidden_states.dtype)
fla/layers/rodimus.py ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ import torch.utils.checkpoint
12
+ from einops import rearrange, repeat
13
+ from transformers.utils import logging
14
+
15
+ from fla.layers.utils import (
16
+ get_layer_cache,
17
+ get_unpad_data,
18
+ index_first_axis,
19
+ pad_input,
20
+ require_cache_layer_idx,
21
+ unpad_input,
22
+ update_layer_cache,
23
+ )
24
+ from fla.modules import RMSNorm, RotaryEmbedding, ShortConvolution
25
+ from fla.modules.layernorm_gated import RMSNormGated
26
+ from fla.ops.gla import chunk_gla, fused_chunk_gla, fused_recurrent_gla
27
+
28
+ if TYPE_CHECKING:
29
+ from transformers.processing_utils import Unpack
30
+
31
+ from fla.models.utils import Cache
32
+
33
+ try:
34
+ from flash_attn import flash_attn_func, flash_attn_varlen_func
35
+ except ImportError:
36
+ warnings.warn(
37
+ "Flash Attention is not installed. Please install it via `pip install flash-attn --no-build-isolation`",
38
+ category=ImportWarning,
39
+ )
40
+ flash_attn_func = None
41
+
42
+ logger = logging.get_logger(__name__)
43
+
44
+
45
+ def align_multiple(value, multiple_size=8):
46
+ if value % multiple_size != 0:
47
+ value += multiple_size - (value % multiple_size)
48
+ return value
49
+
50
+
51
+ def autocast_to_fp16(x):
52
+ if x.dtype not in {torch.float16, torch.bfloat16}:
53
+ return x.to(dtype=torch.bfloat16)
54
+ else:
55
+ return x
56
+
57
+
58
+ class RodimusAttention(nn.Module):
59
+ def __init__(
60
+ self,
61
+ block_type: str = 'rodimus',
62
+ mode: str = 'chunk',
63
+ hidden_size: int = 1024,
64
+ input_gate_low_rank: float | str | None = 'auto',
65
+ expand_ratio: int = 64,
66
+ use_short_conv: bool = True,
67
+ conv_size: int = 4,
68
+ conv_bias: bool = True,
69
+ norm_eps: float = 1e-5,
70
+ k_norm_eps: float | None = None,
71
+ residual_in_fp32: bool = True,
72
+ layer_idx: int = None,
73
+ ):
74
+ super().__init__()
75
+
76
+ self.block_type = block_type
77
+ self.mode = mode
78
+ self.hidden_size = hidden_size
79
+ self.d_inner = align_multiple(int(self.hidden_size * 2), 8)
80
+
81
+ self.expand_ratio = expand_ratio
82
+ self.input_gate_low_rank = max(self.hidden_size // 64, 16) if input_gate_low_rank == "auto" else input_gate_low_rank
83
+
84
+ self.use_short_conv = use_short_conv
85
+ self.conv_size = conv_size
86
+ self.conv_bias = conv_bias
87
+
88
+ self.norm_eps = norm_eps
89
+ self.k_norm_eps = k_norm_eps if k_norm_eps is not None else 1e-12
90
+ self.mem_size = expand_ratio
91
+
92
+ self.residual_in_fp32 = residual_in_fp32
93
+ self.layer_idx = layer_idx
94
+
95
+ assert mode in ['chunk', 'fused_recurrent', 'fused_chunk'], f"Not supported mode `{mode}`."
96
+
97
+ self.gate_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
98
+ self.up_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False)
99
+ self.activation_norm = RMSNormGated(hidden_size=self.d_inner, eps=norm_eps, norm_before_gate=False)
100
+ self.down_proj = nn.Linear(self.d_inner, self.hidden_size, bias=False)
101
+
102
+ if use_short_conv:
103
+ self.short_conv = ShortConvolution(
104
+ hidden_size=self.d_inner,
105
+ kernel_size=conv_size,
106
+ bias=conv_bias,
107
+ activation='silu',
108
+ )
109
+
110
+ self.residual_weight = nn.Parameter(torch.ones(
111
+ (self.d_inner, ), dtype=torch.float32 if self.residual_in_fp32 else None), requires_grad=True)
112
+
113
+ self.k_proj = nn.Linear(self.d_inner, self.mem_size, bias=False)
114
+ self.q_proj = nn.Linear(self.d_inner, self.mem_size, bias=False)
115
+
116
+ self.g_gate_proj = nn.Linear(self.d_inner, self.mem_size, bias=True)
117
+ self.tau_gate_proj = nn.Linear(self.d_inner, self.mem_size, bias=True)
118
+ self.i_gate_proj = nn.Sequential(
119
+ nn.Linear(self.d_inner, self.input_gate_low_rank, bias=False),
120
+ nn.Linear(self.input_gate_low_rank, self.d_inner, bias=True),
121
+ nn.Sigmoid(),
122
+ )
123
+
124
+ def forward(
125
+ self,
126
+ hidden_states: torch.Tensor,
127
+ attention_mask: torch.Tensor | None = None,
128
+ past_key_values: Cache | None = None,
129
+ use_cache: bool | None = False,
130
+ output_attentions: bool | None = False,
131
+ **kwargs: Unpack[dict],
132
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
133
+ if attention_mask is not None:
134
+ assert len(attention_mask.shape) == 2, (
135
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
136
+ "for padding purposes (0 indicating padding). "
137
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
138
+ )
139
+
140
+ batch_size, q_len, _ = hidden_states.shape
141
+ # mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
142
+ mode = 'fused_recurrent' if hidden_states.shape[1] == 1 else self.mode
143
+
144
+ last_state = get_layer_cache(self, past_key_values)
145
+
146
+ cu_seqlens = kwargs.get('cu_seqlens')
147
+ if attention_mask is not None:
148
+ indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:])
149
+ hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0)
150
+
151
+ hidden_states, final_gate = self.up_proj(hidden_states), self.gate_proj(hidden_states)
152
+
153
+ if self.use_short_conv:
154
+ conv_state = None
155
+ if last_state is not None:
156
+ conv_state = last_state['conv_state']
157
+ shift_hidden_states, conv_state = self.short_conv(
158
+ x=hidden_states,
159
+ cache=conv_state,
160
+ output_final_state=use_cache,
161
+ cu_seqlens=cu_seqlens,
162
+ )
163
+ else:
164
+ shift_hidden_states = hidden_states
165
+
166
+ q = self.q_proj(shift_hidden_states)
167
+ k = self.k_proj(shift_hidden_states)
168
+ v = self.i_gate_proj(hidden_states) * hidden_states
169
+
170
+ g_gate = F.linear(shift_hidden_states, self.g_gate_proj.weight) + self.g_gate_proj.bias.float()
171
+ tau_gate = F.linear(shift_hidden_states, self.tau_gate_proj.weight) + self.tau_gate_proj.bias.float()
172
+
173
+ g_gate = F.softplus(g_gate)
174
+ it_gate = g_gate
175
+ rt_gate_log = -g_gate
176
+
177
+ tau_gate = F.sigmoid(tau_gate)
178
+ it_gate = it_gate ** tau_gate
179
+ rt_gate_log = rt_gate_log * tau_gate
180
+
181
+ k = F.normalize(k.float(), dim=-1, eps=self.k_norm_eps) * it_gate
182
+ q, k, v, rt_gate_log = map(lambda x: x.unsqueeze(1).transpose(1, 2), (q, k, v, rt_gate_log))
183
+
184
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
185
+ if mode == 'fused_recurrent':
186
+ o, recurrent_state = fused_recurrent_gla(
187
+ q=q,
188
+ k=k,
189
+ v=v,
190
+ gk=rt_gate_log,
191
+ initial_state=recurrent_state,
192
+ output_final_state=use_cache,
193
+ cu_seqlens=cu_seqlens,
194
+ head_first=False,
195
+ )
196
+ elif mode == 'fused_chunk':
197
+ o, recurrent_state = fused_chunk_gla(
198
+ q=q,
199
+ k=k,
200
+ v=v,
201
+ g=rt_gate_log,
202
+ initial_state=recurrent_state,
203
+ output_final_state=use_cache,
204
+ head_first=False,
205
+ )
206
+ elif mode == 'chunk':
207
+ q, k, rt_gate_log = map(lambda x: x.to(v.dtype), (q, k, rt_gate_log))
208
+ o, recurrent_state = chunk_gla(
209
+ q=q,
210
+ k=k,
211
+ v=v,
212
+ g=rt_gate_log,
213
+ initial_state=recurrent_state,
214
+ output_final_state=use_cache,
215
+ cu_seqlens=cu_seqlens,
216
+ head_first=False,
217
+ )
218
+ else:
219
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
220
+
221
+ rodimus_caches = None
222
+ if past_key_values is not None:
223
+ if self.block_type == 'rodimus':
224
+ update_layer_cache(
225
+ self,
226
+ past_key_values,
227
+ recurrent_state=recurrent_state,
228
+ conv_state=conv_state if self.use_short_conv else None,
229
+ offset=q_len,
230
+ )
231
+ else:
232
+ rodimus_caches = (recurrent_state, conv_state if self.use_short_conv else None)
233
+
234
+ o = (o.transpose(1, 2).squeeze(1) + (shift_hidden_states.float()
235
+ if self.residual_in_fp32 else shift_hidden_states) * self.residual_weight).to(o.dtype)
236
+
237
+ o = self.activation_norm(o, final_gate)
238
+ o = self.down_proj(o)
239
+
240
+ if attention_mask is not None:
241
+ o = pad_input(o.squeeze(0), indices, batch_size, q_len)
242
+
243
+ if self.block_type == 'rodimus':
244
+ return o, None, past_key_values
245
+ else:
246
+ return o, None, (past_key_values, rodimus_caches)
247
+
248
+
249
+ class SlidingWindowSharedKeyAttention(nn.Module):
250
+ def __init__(
251
+ self,
252
+ hidden_size: int = 2048,
253
+ num_heads: int = 32,
254
+ qkv_bias: bool = False,
255
+ qk_norm: bool = False,
256
+ window_size: int = 2048,
257
+ rope_theta: float | None = 10000.,
258
+ max_position_embeddings: int | None = None,
259
+ layer_idx: int = None,
260
+ ):
261
+ super().__init__()
262
+
263
+ self.hidden_size = hidden_size
264
+ self.num_heads = num_heads
265
+ self.head_dim = self.hidden_size // self.num_heads
266
+ self.qkv_bias = qkv_bias
267
+ self.qk_norm = qk_norm
268
+
269
+ self.window_size = window_size
270
+ self.rope_theta = rope_theta
271
+ self.max_position_embeddings = max_position_embeddings
272
+ self.layer_idx = layer_idx
273
+
274
+ self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias)
275
+ self.k_proj = nn.Linear(self.hidden_size, self.head_dim, bias=self.qkv_bias)
276
+ self.v_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias)
277
+ self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
278
+
279
+ if qk_norm:
280
+ self.q_norm = RMSNorm(self.head_dim, dtype=torch.float32)
281
+ self.k_norm = RMSNorm(self.head_dim, dtype=torch.float32)
282
+
283
+ self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta)
284
+
285
+ def forward(
286
+ self,
287
+ hidden_states: torch.Tensor,
288
+ attention_mask: torch.LongTensor | None = None,
289
+ past_key_values: Cache | None = None,
290
+ output_attentions: bool = False,
291
+ use_cache: bool = False,
292
+ **kwargs,
293
+ ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
294
+ rodimus_caches = kwargs.get('rodimus_caches')
295
+
296
+ if attention_mask is not None:
297
+ assert len(attention_mask.shape) == 2, (
298
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
299
+ "for padding purposes (0 indicating padding). "
300
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
301
+ )
302
+
303
+ batch_size, q_len, _ = hidden_states.size()
304
+
305
+ q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
306
+ k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
307
+ v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim)
308
+
309
+ if self.qk_norm:
310
+ q, k = self.q_norm(q), self.k_norm(k)
311
+
312
+ # equivalent to cu_seqlens in `flash_attn`
313
+ cu_seqlens = kwargs.get('cu_seqlens')
314
+
315
+ layer_idx = require_cache_layer_idx(self, past_key_values)
316
+ seqlen_offset, max_seqlen = 0, q.shape[1]
317
+ if past_key_values is not None:
318
+ seqlen_offset = past_key_values.get_seq_length(layer_idx)
319
+ max_seqlen = q.shape[1] + seqlen_offset
320
+
321
+ if attention_mask is not None:
322
+ # to deliminate the offsets of padding tokens
323
+ seqlen_offset = seqlen_offset + attention_mask.sum(-1) - attention_mask.shape[-1]
324
+ max_seqlen = q.shape[1] + max(seqlen_offset)
325
+
326
+ if self.max_position_embeddings is not None:
327
+ max_seqlen = max(max_seqlen, self.max_position_embeddings)
328
+ q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens)
329
+
330
+ if past_key_values is not None:
331
+ if rodimus_caches is not None:
332
+ recurrent_state, conv_state = rodimus_caches
333
+ else:
334
+ recurrent_state, conv_state = None, None
335
+
336
+ cache_has_content = past_key_values.get_seq_length(layer_idx) > 0
337
+ k_cached, v_cached = past_key_values.update(
338
+ recurrent_state=recurrent_state,
339
+ conv_state=conv_state,
340
+ attn_state=[k.flatten(-2, -1), v.flatten(-2, -1)],
341
+ layer_idx=layer_idx,
342
+ offset=q_len,
343
+ cache_kwargs=dict(window_size=self.window_size),
344
+ )['attn_state']
345
+ if cache_has_content:
346
+ k, v = k_cached, v_cached
347
+ k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim)
348
+ v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim)
349
+
350
+ if flash_attn_func is None:
351
+ raise ImportError("Please install Flash Attention via `pip install flash-attn --no-build-isolation` first")
352
+
353
+ q, k, v = map(autocast_to_fp16, (q, k, v))
354
+ k = repeat(k, "... h d -> ... (n h) d", n=self.num_heads)
355
+ # Contains at least one padding token in the sequence
356
+ if attention_mask is not None:
357
+ q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input(
358
+ q=q,
359
+ states=(k, v),
360
+ attention_mask=attention_mask[:, -max(self.window_size, q_len):],
361
+ q_len=q_len,
362
+ )
363
+ cu_seqlens_q, cu_seqlens_k = cu_seqlens
364
+ max_seqlen_q, max_seqlen_k = max_seq_lens
365
+ o = flash_attn_varlen_func(
366
+ q, k, v,
367
+ cu_seqlens_q=cu_seqlens_q,
368
+ cu_seqlens_k=cu_seqlens_k,
369
+ max_seqlen_q=max_seqlen_q,
370
+ max_seqlen_k=max_seqlen_k,
371
+ causal=True,
372
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
373
+ )
374
+ o = pad_input(o, indices_q, batch_size, q_len)
375
+ elif cu_seqlens is not None:
376
+ o = flash_attn_varlen_func(
377
+ q.squeeze(0), k.squeeze(0), v.squeeze(0),
378
+ cu_seqlens_q=cu_seqlens,
379
+ cu_seqlens_k=cu_seqlens,
380
+ max_seqlen_q=max_seqlen,
381
+ max_seqlen_k=max_seqlen,
382
+ causal=True,
383
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
384
+ ).unsqueeze(0)
385
+ else:
386
+ o = flash_attn_func(
387
+ q, k, v,
388
+ causal=True,
389
+ window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0),
390
+ )
391
+ o = o.reshape(batch_size, q_len, -1)
392
+ o = self.o_proj(o.to(dtype=self.o_proj.weight.dtype))
393
+
394
+ if not output_attentions:
395
+ attentions = None
396
+
397
+ return o, attentions, past_key_values
fla/layers/rwkv6.py ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ # "Eagle and Finch: RWKV with Matrix-Valued States and Dynamic Recurrence"[https://arxiv.org/abs/2404.05892]
4
+
5
+ from __future__ import annotations
6
+
7
+ import math
8
+ import warnings
9
+ from typing import TYPE_CHECKING
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ from einops import rearrange
14
+
15
+ from fla.layers.utils import get_layer_cache, update_layer_cache
16
+ from fla.modules import GroupNorm
17
+ from fla.modules.activations import ACT2FN
18
+ from fla.modules.token_shift import token_shift
19
+ from fla.ops.rwkv6 import chunk_rwkv6, fused_recurrent_rwkv6
20
+
21
+ if TYPE_CHECKING:
22
+ from fla.models.utils import Cache
23
+
24
+
25
+ class RWKV6Attention(nn.Module):
26
+
27
+ def __init__(
28
+ self,
29
+ mode: str = 'chunk',
30
+ hidden_size: int = 1024,
31
+ expand_k: float = 0.5,
32
+ expand_v: float = 1.0,
33
+ num_heads: int = 4,
34
+ gate_fn: str = 'swish',
35
+ proj_low_rank_dim: int = 32,
36
+ gate_low_rank_dim: int = 64,
37
+ fuse_norm: bool = True,
38
+ elementwise_affine: bool | None = True,
39
+ norm_eps: float = 1e-5,
40
+ layer_idx: int = None,
41
+ **kwargs,
42
+ ) -> RWKV6Attention:
43
+ super().__init__()
44
+
45
+ self.mode = mode
46
+ self.hidden_size = hidden_size
47
+ self.expand_k = expand_k
48
+ self.expand_v = expand_v
49
+ self.num_heads = num_heads
50
+ self.proj_low_rank_dim = proj_low_rank_dim
51
+ self.gate_low_rank_dim = gate_low_rank_dim
52
+
53
+ self.key_dim = int(hidden_size * expand_k)
54
+ self.value_dim = int(hidden_size * expand_v)
55
+ self.layer_idx = layer_idx
56
+
57
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
58
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
59
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
60
+
61
+ self.head_k_dim = self.key_dim // num_heads
62
+ self.head_v_dim = self.value_dim // num_heads
63
+
64
+ self.time_shift = nn.ZeroPad2d((0, 0, 1, -1))
65
+ self.x_proj = nn.Sequential(
66
+ LerpLinear(hidden_size, proj_low_rank_dim * 5),
67
+ nn.Tanh(),
68
+ nn.Linear(proj_low_rank_dim * 5, hidden_size, bias=False),
69
+ )
70
+ self.x_bias = nn.Parameter(torch.zeros(5, hidden_size))
71
+
72
+ self.r_proj = DDLerpLinear(hidden_size, self.key_dim)
73
+ self.w_proj = DDLerpLinear(hidden_size, self.key_dim, low_rank_dim=gate_low_rank_dim)
74
+ self.k_proj = DDLerpLinear(hidden_size, self.key_dim)
75
+ self.v_proj = DDLerpLinear(hidden_size, self.value_dim)
76
+ self.g_proj = DDLerpLinear(hidden_size, self.value_dim)
77
+ self.bonus = nn.Parameter(torch.zeros(num_heads, self.head_k_dim))
78
+
79
+ # TODO: fuse GroupNorm and output gate
80
+ self.g_norm = GroupNorm(self.num_heads, self.value_dim, elementwise_affine=elementwise_affine, bias=True, eps=norm_eps)
81
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
82
+ self.gate_fn = ACT2FN[gate_fn]
83
+
84
+ try:
85
+ from transformers.modeling_utils import _init_weights
86
+ except ImportError:
87
+ _init_weights = True
88
+ if _init_weights:
89
+ self.apply(self._initialize_weights)
90
+
91
+ warnings.warn(
92
+ "According to Bo, you are using a potentially buggy FLA implementation of RWKV. "
93
+ "If you plan to report any numbers based on this implementation, we strongly recommend "
94
+ "cross-checking with the official repo: https://github.com/BlinkDL/RWKV-LM. "
95
+ "Bo may disagree with results reported from this version.",
96
+ )
97
+
98
+ def _initialize_weights(self, module: nn.Module):
99
+ if getattr(module, "_is_hf_initialized", False):
100
+ return
101
+ if isinstance(module, nn.Linear):
102
+ nn.init.xavier_uniform_(module.weight, gain=2 ** -2.5)
103
+ if module.bias is not None:
104
+ nn.init.zeros_(module.bias)
105
+ if isinstance(module, nn.Parameter):
106
+ nn.init.xavier_uniform_(module, gain=2 ** -2.5)
107
+ module._is_hf_initialized = True
108
+
109
+ def forward(
110
+ self,
111
+ hidden_states: torch.Tensor,
112
+ attention_mask: torch.Tensor | None = None,
113
+ past_key_values: Cache | None = None,
114
+ use_cache: bool | None = False,
115
+ output_attentions: bool | None = False,
116
+ cu_seqlens: torch.LongTensor | None = None,
117
+ **kwargs,
118
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
119
+ if attention_mask is not None:
120
+ assert len(attention_mask.shape) == 2, (
121
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
122
+ "for padding purposes (0 indicating padding). "
123
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
124
+ )
125
+
126
+ batch_size, seq_len, hidden_size = hidden_states.shape
127
+ # launching the triton kernel for just one token will actually be slower
128
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
129
+
130
+ last_state = get_layer_cache(self, past_key_values)
131
+
132
+ if attention_mask is not None:
133
+ hidden_states = hidden_states.mul(attention_mask[:, -hidden_states.shape[-2]:, None])
134
+
135
+ if hidden_states.shape[1] == 1 and last_state is not None:
136
+ shifted = last_state['conv_state'].unsqueeze(1)
137
+ delta = shifted - hidden_states
138
+ elif last_state is None:
139
+ delta = token_shift(hidden_states, cu_seqlens)
140
+ else:
141
+ shifted = self.time_shift(hidden_states)
142
+ shifted[:, 0] = last_state['conv_state']
143
+ delta = shifted - hidden_states
144
+
145
+ x = self.x_proj[0](hidden_states, delta, cu_seqlens).view(batch_size, seq_len, -1, self.proj_low_rank_dim)
146
+ x = torch.einsum('b t n r, h n r-> b t n h', self.x_proj[1](x), self.x_proj[2].weight.view(hidden_size, 5, -1))
147
+
148
+ r, w, k, v, g = x.add_(self.x_bias).unbind(-2)
149
+ r = self.r_proj(hidden_states, r, delta, cu_seqlens)
150
+ w = self.w_proj(hidden_states, w, delta, cu_seqlens)
151
+ k = self.k_proj(hidden_states, k, delta, cu_seqlens)
152
+ v = self.v_proj(hidden_states, v, delta, cu_seqlens)
153
+ g = self.g_proj(hidden_states, g, delta, cu_seqlens)
154
+
155
+ # dealing with left-padding
156
+ if attention_mask is not None:
157
+ v = v.mul(attention_mask[:, -v.shape[-2]:, None])
158
+ r, w, k = map(lambda x: rearrange(x, 'b t (h d) -> b t h d', d=self.head_k_dim), (r, w, k))
159
+ v = rearrange(v, 'b t (h d) -> b t h d', d=self.head_v_dim)
160
+ w = -torch.exp(w)
161
+ u = self.bonus
162
+
163
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
164
+
165
+ if mode == 'fused_recurrent':
166
+ o, recurrent_state = fused_recurrent_rwkv6(
167
+ r=r,
168
+ k=k,
169
+ v=v,
170
+ w=w,
171
+ u=u,
172
+ scale=1.,
173
+ initial_state=recurrent_state,
174
+ output_final_state=use_cache,
175
+ cu_seqlens=cu_seqlens,
176
+ )
177
+ elif mode == 'chunk':
178
+ o, recurrent_state = chunk_rwkv6(
179
+ r=r,
180
+ k=k,
181
+ v=v,
182
+ w=w,
183
+ u=u,
184
+ scale=1.,
185
+ initial_state=recurrent_state,
186
+ output_final_state=use_cache,
187
+ cu_seqlens=cu_seqlens,
188
+ )
189
+ else:
190
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
191
+
192
+ update_layer_cache(
193
+ self,
194
+ past_key_values,
195
+ recurrent_state=recurrent_state,
196
+ conv_state=hidden_states[:, -1],
197
+ offset=seq_len,
198
+ )
199
+
200
+ o = self.g_norm(rearrange(o, '... h d -> ... (h d)')) * self.gate_fn(g)
201
+ o = self.o_proj(o)
202
+
203
+ return o, None, past_key_values
204
+
205
+
206
+ class LoRA(nn.Module):
207
+
208
+ def __init__(
209
+ self,
210
+ input_dim: int,
211
+ output_dim: int,
212
+ low_rank_dim: int,
213
+ bias: bool | None = True,
214
+ activation: str | None = 'tanh',
215
+ ):
216
+ super().__init__()
217
+
218
+ self.input_dim = input_dim
219
+ self.output_dim = output_dim
220
+ self.low_rank_dim = low_rank_dim
221
+ self.bias = bias
222
+
223
+ if activation is None:
224
+ self.activation = nn.Identity()
225
+ elif activation == 'sigmoid':
226
+ self.activation = nn.Sigmoid()
227
+ elif activation == 'tanh':
228
+ self.activation = nn.Tanh()
229
+ elif activation == 'relu':
230
+ self.activation = nn.ReLU()
231
+ else:
232
+ raise ValueError(f"Not supported activation `{activation}`.")
233
+
234
+ self.lora = nn.Sequential(
235
+ nn.Linear(input_dim, low_rank_dim, bias=False),
236
+ self.activation,
237
+ nn.Linear(low_rank_dim, output_dim, bias=bias),
238
+ )
239
+ try:
240
+ from transformers.modeling_utils import _init_weights
241
+ except ImportError:
242
+ _init_weights = True
243
+ if _init_weights:
244
+ self.apply(self._initialize_weights)
245
+
246
+ def __repr__(self) -> str:
247
+ s = f"{self.__class__.__name__}("
248
+ s += f"input_dim={self.input_dim}, low_rank_dim={self.low_rank_dim}, output_dim={self.output_dim}"
249
+ if not self.bias:
250
+ s += f", bias={self.bias}"
251
+ s += ")"
252
+ return s
253
+
254
+ def _initialize_weights(self, module: nn.Module):
255
+ if getattr(module, "_is_hf_initialized", False):
256
+ return
257
+
258
+ # Initialize weights to zero as in original code
259
+ nn.init.zeros_(self.lora[0].weight)
260
+ original_dtype = self.lora[2].weight.dtype
261
+ shape = self.lora[2].weight.shape
262
+ # Convert to float32 for numerical stability in orthogonal init
263
+ weight_fp32 = self.lora[2].weight.float()
264
+
265
+ # Calculate gain based on dimensions
266
+ gain = math.sqrt(shape[1] / shape[0]) if shape[1] > shape[0] else 1
267
+
268
+ # Apply orthogonal initialization with scaling factor 0.1
269
+ nn.init.orthogonal_(weight_fp32, gain=gain * 0.1)
270
+
271
+ # Convert back to original dtype
272
+ self.lora[2].weight.data.copy_(weight_fp32.to(original_dtype))
273
+ # Set Lora[2] bias to zero
274
+ if self.lora[2].bias is not None:
275
+ nn.init.zeros_(self.lora[2].bias)
276
+
277
+ module._is_hf_initialized = True
278
+
279
+ def set_bias_value(self, value):
280
+ """Set bias to a specific value (for v0, w0 etc.)"""
281
+ if self.bias and self.lora[2].bias is not None:
282
+ if isinstance(value, torch.Tensor):
283
+ # Handle tensor values
284
+ self.lora[2].bias.data.copy_(value.to(self.lora[2].bias.dtype))
285
+ else:
286
+ # Handle scalar values
287
+ nn.init.constant_(self.lora[2].bias, value)
288
+
289
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
290
+ return self.lora(x)
291
+
292
+
293
+ class LerpLinear(nn.Module):
294
+
295
+ def __init__(
296
+ self,
297
+ input_dim: int,
298
+ output_dim: int,
299
+ low_rank_dim: int | None = None,
300
+ ):
301
+ super().__init__()
302
+
303
+ self.input_dim = input_dim
304
+ self.output_dim = output_dim
305
+ self.low_rank_dim = low_rank_dim
306
+
307
+ self.time_shift = nn.ZeroPad2d((0, 0, 1, -1))
308
+ if low_rank_dim is None:
309
+ self.linear = nn.Linear(input_dim, output_dim, bias=False)
310
+ else:
311
+ self.linear = LoRA(input_dim, output_dim, low_rank_dim)
312
+ self.mu = nn.Parameter(torch.zeros(input_dim))
313
+
314
+ def __repr__(self) -> str:
315
+ s = f"{self.__class__.__name__}({self.input_dim}, {self.output_dim}"
316
+ if self.low_rank_dim is not None:
317
+ s += f", low_rank_dim={self.low_rank_dim}"
318
+ s += ")"
319
+ return s
320
+
321
+ def forward(self, x: torch.Tensor, delta: torch.Tensor | None = None,
322
+ cu_seqlens: torch.LongTensor | None = None) -> torch.Tensor:
323
+ if delta is None:
324
+ delta = token_shift(x, cu_seqlens)
325
+ return self.linear(x + delta * self.mu)
326
+
327
+
328
+ class DDLerpLinear(nn.Module):
329
+
330
+ def __init__(
331
+ self,
332
+ input_dim: int,
333
+ output_dim: int,
334
+ low_rank_dim: int | None = None,
335
+ ):
336
+ super().__init__()
337
+
338
+ self.input_dim = input_dim
339
+ self.output_dim = output_dim
340
+ self.low_rank_dim = low_rank_dim
341
+
342
+ self.time_shift = nn.ZeroPad2d((0, 0, 1, -1))
343
+ if low_rank_dim is None:
344
+ self.linear = nn.Linear(input_dim, output_dim, bias=False)
345
+ else:
346
+ self.linear = LoRA(input_dim, output_dim, low_rank_dim)
347
+
348
+ def __repr__(self) -> str:
349
+ s = f"{self.__class__.__name__}({self.input_dim}, {self.output_dim}"
350
+ if self.low_rank_dim is not None:
351
+ s += f", low_rank_dim={self.low_rank_dim}"
352
+ s += ")"
353
+ return s
354
+
355
+ def forward(self, x: torch.Tensor, mu: torch.Tensor,
356
+ delta: torch.Tensor | None = None,
357
+ cu_seqlens: torch.LongTensor | None = None) -> torch.Tensor:
358
+ if delta is None:
359
+ delta = token_shift(x, cu_seqlens)
360
+ return self.linear(x + delta * mu)
fla/layers/rwkv7.py ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from einops import rearrange
11
+ from torch.nn import functional as F
12
+
13
+ from fla.layers.rwkv6 import LoRA
14
+ from fla.layers.utils import get_layer_cache, update_layer_cache
15
+ from fla.modules import GroupNorm
16
+ from fla.modules.l2norm import l2_norm
17
+ from fla.modules.token_shift import token_shift
18
+ from fla.ops.rwkv7 import chunk_rwkv7, fused_mul_recurrent_rwkv7
19
+ from fla.ops.rwkv7.fused_addcmul import fused_addcmul_rwkv7
20
+ from fla.ops.rwkv7.fused_k_update import fused_k_rwkv7
21
+ from fla.ops.rwkv7.gate_output_correction import gate_output_correction
22
+
23
+ if TYPE_CHECKING:
24
+ from fla.models.utils import Cache
25
+
26
+
27
+ class RWKV7Attention(nn.Module):
28
+
29
+ def __init__(
30
+ self,
31
+ mode: str = 'chunk',
32
+ hidden_size: int = 1024,
33
+ head_dim: int | None = 64,
34
+ num_heads: int | None = None,
35
+ decay_low_rank_dim: int | None = None,
36
+ gate_low_rank_dim: int | None = None,
37
+ a_low_rank_dim: int | None = None,
38
+ v_low_rank_dim: int | None = None,
39
+ elementwise_affine: bool | None = True,
40
+ norm_eps: float = 1e-5,
41
+ layer_idx: int = None,
42
+ fuse_norm: bool = False,
43
+ value_dim: int = None,
44
+ num_hidden_layers: int = None,
45
+ **kwargs,
46
+ ) -> RWKV7Attention:
47
+ super().__init__()
48
+
49
+ self.mode = mode
50
+ assert mode in ['chunk', 'fused_recurrent'], f"Not supported mode `{mode}`."
51
+ self.hidden_size = hidden_size
52
+
53
+ self.key_dim = hidden_size
54
+ self.value_dim = value_dim if value_dim is not None else hidden_size
55
+ if head_dim is None and num_heads is None:
56
+ raise ValueError("Either `head_dim` or `num_heads` must be specified.")
57
+ elif head_dim is not None:
58
+ self.head_dim = head_dim
59
+ self.num_heads = int(hidden_size // head_dim)
60
+ elif num_heads is not None:
61
+ self.head_dim = int(hidden_size // num_heads)
62
+ self.num_heads = num_heads
63
+ self.head_v_dim = int(self.value_dim // self.num_heads)
64
+
65
+ # Increase lora dimension for headdim>64
66
+ factor = self.head_dim / 64
67
+ if decay_low_rank_dim is None:
68
+ decay_low_rank_dim = max(32, int(round((2.5 * (hidden_size**0.5)) * factor / 32) * 32))
69
+ self.decay_low_rank_dim = decay_low_rank_dim
70
+ else:
71
+ self.decay_low_rank_dim = decay_low_rank_dim
72
+
73
+ if gate_low_rank_dim is None:
74
+ gate_low_rank_dim = max(32, int(round((5 * (hidden_size**0.5)) / 32) * 32))
75
+ self.gate_low_rank_dim = gate_low_rank_dim
76
+ else:
77
+ self.gate_low_rank_dim = gate_low_rank_dim
78
+
79
+ if a_low_rank_dim is None:
80
+ a_low_rank_dim = max(32, int(round((2.5 * (hidden_size**0.5)) * factor / 32) * 32))
81
+ self.a_low_rank_dim = a_low_rank_dim
82
+ else:
83
+ self.a_low_rank_dim = a_low_rank_dim
84
+
85
+ if v_low_rank_dim is None:
86
+ v_low_rank_dim = max(32, int(round((1.7 * (hidden_size**0.5)) * factor / 32) * 32))
87
+ self.v_low_rank_dim = v_low_rank_dim
88
+ else:
89
+ self.v_low_rank_dim = v_low_rank_dim
90
+
91
+ self.layer_idx = layer_idx
92
+ self.num_hidden_layers = num_hidden_layers
93
+ self.fuse_norm = fuse_norm
94
+
95
+ self.time_shift = nn.ZeroPad2d((0, 0, 1, -1))
96
+ self.x_r = nn.Parameter(torch.zeros(1, 1, hidden_size))
97
+ self.x_w = nn.Parameter(torch.zeros(1, 1, hidden_size))
98
+ self.x_k = nn.Parameter(torch.zeros(1, 1, hidden_size))
99
+ self.x_v = nn.Parameter(torch.zeros(1, 1, hidden_size))
100
+ self.x_a = nn.Parameter(torch.zeros(1, 1, hidden_size))
101
+ self.x_g = nn.Parameter(torch.zeros(1, 1, hidden_size))
102
+
103
+ self.k_k = nn.Parameter(torch.zeros(self.key_dim))
104
+ self.k_a = nn.Parameter(torch.zeros(self.key_dim))
105
+ self.r_k = nn.Parameter(torch.zeros(self.num_heads, self.head_dim))
106
+
107
+ self.r_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
108
+ self.k_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
109
+ self.v_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
110
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
111
+
112
+ self.w_lora = LoRA(hidden_size, self.key_dim, low_rank_dim=decay_low_rank_dim, activation='tanh')
113
+ if self.layer_idx != 0:
114
+ self.v_lora = LoRA(hidden_size, self.value_dim, low_rank_dim=v_low_rank_dim, activation=None)
115
+ self.a_lora = LoRA(hidden_size, self.key_dim, low_rank_dim=a_low_rank_dim, activation=None)
116
+ self.g_lora = LoRA(hidden_size, self.value_dim, low_rank_dim=gate_low_rank_dim, activation='sigmoid', bias=False)
117
+
118
+ if self.fuse_norm:
119
+ self.g_norm = GroupNorm(
120
+ num_groups=self.num_heads,
121
+ hidden_size=self.value_dim,
122
+ elementwise_affine=elementwise_affine,
123
+ eps=self.head_dim*norm_eps,
124
+ bias=True,
125
+ )
126
+ else:
127
+ self.g_norm = nn.GroupNorm(
128
+ num_groups=self.num_heads,
129
+ num_channels=self.value_dim,
130
+ eps=self.head_dim*norm_eps,
131
+ affine=elementwise_affine,
132
+ )
133
+
134
+ try:
135
+ from transformers.modeling_utils import _init_weights
136
+ except ImportError:
137
+ _init_weights = True
138
+ if _init_weights:
139
+ self.apply(self._initialize_weights)
140
+ for name, module in self.named_modules():
141
+ module._in_rwkv_module = True
142
+
143
+ warnings.warn(
144
+ "According to Bo, you are using a potentially buggy FLA implementation of RWKV. "
145
+ "If you plan to report any numbers based on this implementation, we strongly recommend "
146
+ "cross-checking with the official repo: https://github.com/BlinkDL/RWKV-LM. "
147
+ "Bo may disagree with results reported from this version.",
148
+ )
149
+
150
+ @torch.no_grad()
151
+ @torch.compiler.disable
152
+ def _initialize_weights(self, module: nn.Module):
153
+ if getattr(module, "_is_hf_initialized", False):
154
+ return
155
+
156
+ # Initialize only when we're processing the RWKV7Attention module itself
157
+ if isinstance(module, RWKV7Attention) and self.layer_idx is not None:
158
+ ratio_0_to_1 = self.layer_idx / (self.num_hidden_layers - 1) # 0 to 1
159
+ ratio_1_to_almost0 = 1.0 - (self.layer_idx / self.num_hidden_layers) # 1 to ~0
160
+
161
+ # Create position-based initialization tensor
162
+ ddd = torch.ones(1, 1, self.hidden_size, device=self.x_r.device)
163
+ www = torch.zeros(self.hidden_size, device=self.x_r.device)
164
+ zigzag = torch.zeros(self.hidden_size, device=self.x_r.device)
165
+ linear = torch.zeros(self.hidden_size, device=self.x_r.device)
166
+ for n in range(self.hidden_size):
167
+ linear[n] = n / (self.hidden_size-1) - 0.5
168
+ zigzag[n] = ((n % self.head_dim) - ((self.head_dim-1) / 2)) / ((self.head_dim-1) / 2)
169
+ zigzag[n] = zigzag[n] * abs(zigzag[n])
170
+ www[n] = -6 + 6 * (n / (self.hidden_size - 1)) ** (1 + 1 * ratio_0_to_1 ** 0.3)
171
+ ddd[0, 0, n] = n / self.hidden_size
172
+
173
+ # Initialize x_* parameters directly
174
+ self.x_r.data = (1.0 - torch.pow(ddd, 0.2 * ratio_1_to_almost0)).to(self.x_r.dtype)
175
+ self.x_w.data = (1.0 - torch.pow(ddd, 0.9 * ratio_1_to_almost0)).to(self.x_w.dtype)
176
+ self.x_k.data = (1.0 - torch.pow(ddd, 0.7 * ratio_1_to_almost0)).to(self.x_k.dtype)
177
+ self.x_v.data = (1.0 - torch.pow(ddd, 0.7 * ratio_1_to_almost0)).to(self.x_v.dtype)
178
+ self.x_a.data = (1.0 - torch.pow(ddd, 0.9 * ratio_1_to_almost0)).to(self.x_a.dtype)
179
+ self.x_g.data = (1.0 - torch.pow(ddd, 0.2 * ratio_1_to_almost0)).to(self.x_g.dtype)
180
+
181
+ # Initialize k_k, k_a, r_k
182
+ nn.init.constant_(self.k_a, 1.02)
183
+ nn.init.constant_(self.r_k, -0.04)
184
+ self.k_k.data.copy_((torch.zeros(self.hidden_size, device=self.k_k.device) +
185
+ 0.71 - linear*0.1).to(self.k_k.dtype))
186
+ # Set specific bias values for LoRA modules
187
+ # 0.5 comes from F.softplus
188
+ self.w_lora.set_bias_value(www + 0.5 + zigzag*2.5)
189
+ self.a_lora.set_bias_value(-0.19 + zigzag*0.3 + linear*0.4)
190
+
191
+ # v0 initialization - ones (for non-first layers)
192
+ if self.layer_idx != 0:
193
+ self.v_lora._initialize_weights(self.v_lora)
194
+ self.v_lora.set_bias_value(0.73 - linear*0.4)
195
+
196
+ # Initialize GroupNorm
197
+ self.g_norm.weight.data[:] = ((self.layer_idx + 1) / self.num_hidden_layers) ** 0.7
198
+
199
+ # Initialize Linear projections
200
+ self._orthogonal_init(self.r_proj.weight)
201
+ self._orthogonal_init(self.k_proj.weight, gain=0.1)
202
+ self._orthogonal_init(self.v_proj.weight)
203
+ self.o_proj.weight.data.zero_()
204
+
205
+ # Clean up temporary tensors to free memory
206
+ del ddd, www, zigzag, linear
207
+
208
+ module._is_hf_initialized = True
209
+
210
+ @staticmethod
211
+ def _orthogonal_init(weight, gain=1.0):
212
+ oringinal_dtype = weight.dtype
213
+ weight = weight.float()
214
+ nn.init.orthogonal_(weight, gain=gain)
215
+ weight = weight.to(oringinal_dtype)
216
+
217
+ def forward(
218
+ self,
219
+ hidden_states: torch.Tensor,
220
+ attention_mask: torch.Tensor | None = None,
221
+ past_key_values: Cache | None = None,
222
+ use_cache: bool | None = False,
223
+ output_attentions: bool | None = False,
224
+ v_first: torch.Tensor = None,
225
+ cu_seqlens: torch.LongTensor | None = None,
226
+ **kwargs,
227
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
228
+ batch_size, seq_len, _ = hidden_states.shape
229
+ if attention_mask is not None:
230
+ assert len(attention_mask.shape) == 2, (
231
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
232
+ "for padding purposes (0 indicating padding). "
233
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
234
+ )
235
+ am = attention_mask.narrow(1, attention_mask.size(1) - seq_len, seq_len).unsqueeze(-1)
236
+
237
+ last_state = get_layer_cache(self, past_key_values)
238
+
239
+ if attention_mask is not None:
240
+ hidden_states = hidden_states.mul(am)
241
+
242
+ # delta [batch_size, seq_len, hidden_size]
243
+ # conv_cache [N, D]
244
+ if last_state is None:
245
+ conv_cache = None
246
+ recurrent_state = None
247
+ else:
248
+ conv_cache = last_state['conv_state']
249
+ recurrent_state = last_state['recurrent_state']
250
+
251
+ delta, conv_state = token_shift(
252
+ hidden_states, cu_seqlens, output_cache=True, cache=conv_cache,
253
+ )
254
+ xr, xw, xk, xv, xa, xg = fused_addcmul_rwkv7(hidden_states, delta, self.x_r, self.x_w,
255
+ self.x_k, self.x_v, self.x_a, self.x_g)
256
+
257
+ r = self.r_proj(xr)
258
+ # Using bf16 for LoRA computation is numerically safe here because:
259
+ # 1. After sigmoid activation:
260
+ # - Max absolute error (vs float32): 0.003
261
+ # - Mean absolute error: 0.0004
262
+ # 2. Subsequent scaling by -0.6065 will further reduce relative error
263
+ # (error scales linearly with constant multiplication)
264
+ # 3. Final compounded error remains within acceptable bounds for bf16 precision
265
+ # Empirical observation confirms bf16 introduces no practical degradation
266
+ w = -0.6065306597126334 * self.w_lora(xw).sigmoid()
267
+
268
+ k = self.k_proj(xk)
269
+ v = self.v_proj(xv)
270
+
271
+ if self.layer_idx == 0:
272
+ v_first = v
273
+ else:
274
+ v = torch.lerp(v, v_first, self.v_lora(xv).sigmoid())
275
+ a = self.a_lora(xa).sigmoid()
276
+ g = self.g_lora(xg)
277
+
278
+ if self.fuse_norm:
279
+ kk = l2_norm(rearrange(k * self.k_k, 'b t (h d) -> b t h d', d=self.head_dim))
280
+ else:
281
+ kk = F.normalize(rearrange(k * self.k_k, 'b t (h d) -> b t h d', d=self.head_dim), dim=-1, p=2.0)
282
+
283
+ # Prefer addcmul over expanded form for numerical stability in bf16:
284
+ # 1. Fused Multiply-Add (FMA) in addcmul reduces intermediate rounding:
285
+ # - Single op vs original 3 ops (mul, sub, mul)
286
+ # - 1 less intermediate value storage (bf16 write->read overhead)
287
+ # 2. Mathematically equivalent to k*(1 + (a-1)*self.k_a)
288
+ # but with better precision preservation
289
+ # 3. Particularly crucial for bf16 where intermediate values easily lose precision
290
+ # 4. Pytorch method: k = k.addcmul(k * (a - 1), self.k_a)
291
+ k = fused_k_rwkv7(k, a, self.k_a)
292
+
293
+ # dealing with left-padding
294
+ if attention_mask is not None:
295
+ v = v * am
296
+
297
+ r, w, k, a = map(lambda x: rearrange(x, 'b t (h d) -> b t h d', d=self.head_dim), (r, w, k, a))
298
+ v = rearrange(v, 'b t (h d) -> b t h d', d=self.head_v_dim)
299
+
300
+ if self.training or seq_len >= 64:
301
+ # if training, use chunk mode no matter how short the sequence is
302
+ # launching the triton kernel for just one token will actually be slower
303
+ o, recurrent_state = chunk_rwkv7(
304
+ r=r,
305
+ w=w,
306
+ k=k,
307
+ v=v,
308
+ a=-kk,
309
+ b=kk * a,
310
+ scale=1.,
311
+ initial_state=recurrent_state,
312
+ output_final_state=use_cache,
313
+ cu_seqlens=cu_seqlens,
314
+ safe_gate=True,
315
+ chunk_size=64,
316
+ )
317
+ else:
318
+ o, recurrent_state = fused_mul_recurrent_rwkv7(
319
+ r=r,
320
+ w=w,
321
+ k=k,
322
+ v=v,
323
+ kk=kk,
324
+ a=a,
325
+ scale=1.,
326
+ initial_state=recurrent_state,
327
+ output_final_state=use_cache,
328
+ cu_seqlens=cu_seqlens,
329
+ )
330
+
331
+ update_layer_cache(
332
+ self,
333
+ past_key_values,
334
+ recurrent_state=recurrent_state,
335
+ conv_state=conv_state,
336
+ offset=r.shape[1],
337
+ )
338
+
339
+ if self.fuse_norm:
340
+ o = self.g_norm(rearrange(o, '... h d -> ... (h d)'))
341
+ else:
342
+ o = self.g_norm(rearrange(o, 'b t h d -> (b t) (h d)')).view(batch_size, seq_len, -1)
343
+
344
+ o = gate_output_correction(o, r, k, self.r_k, v, g)
345
+ o = self.o_proj(o)
346
+
347
+ return o, None, past_key_values, v_first
fla/layers/simple_gla.py ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ from einops import rearrange, repeat
11
+
12
+ from fla.layers.utils import get_layer_cache, update_layer_cache
13
+ from fla.modules import FusedRMSNormGated, RMSNorm, ShortConvolution
14
+ from fla.modules.activations import ACT2FN
15
+ from fla.ops.simple_gla import chunk_simple_gla, fused_recurrent_simple_gla
16
+
17
+ if TYPE_CHECKING:
18
+ from fla.models.utils import Cache
19
+
20
+
21
+ class SimpleGatedLinearAttention(nn.Module):
22
+ r"""
23
+ The layer implementaion for [Gated Linear Attention Transformers with Hardware-Efficient Training](https://arxiv.org/abs/2312.06635). # noqa
24
+ This layer calls the simplified GLA kernel in which the gating is head-wise instead of elementwise.
25
+
26
+ Args:
27
+ mode (str, Optional):
28
+ Which GLA kernel to use.
29
+ Currently available: `chunk`.
30
+ Default: `chunk`.
31
+ hidden_size (int, Optional):
32
+ The hidden size of the input. Default: 1024.
33
+ expand_k (float, Optional):
34
+ The expansion ratio for the key dim. Default: 1.0.
35
+ expand_v (float, Optional):
36
+ The expansion ratio for the value dim. Default: 1.0.
37
+ num_heads (int, Optional):
38
+ The number of heads. Default: 4.
39
+ num_kv_heads (int, Optional):
40
+ The number of key/value heads, used for MQA. Default: None.
41
+ feature_map (str, Optional):
42
+ Feature map function applied to queries/keys. Default: None.
43
+ use_short_conv (bool, Optional):
44
+ Whether to use short convolutions. Default: `False`.
45
+ conv_size (int, Optional):
46
+ The kernel size of the short convolution, only used when `use_short_conv` is `True`. Default: 4.
47
+ conv_bias (bool, Optional):
48
+ Whether to use bias in the short convolution, only used when `use_short_conv` is `True`. Default: `False`.
49
+ gate_fn (str, Optional):
50
+ The activation function for the output gate. Default: `swish`.
51
+ elementwise_affine (bool, Optional):
52
+ If `True`, applies elementwise affine to LayerNorm with learnable parameters. Default: `True`.
53
+ norm_eps (float, Optional):
54
+ The epsilon value for the layernorm/rmsnorm layer. Default: 1e-5.
55
+ gate_logit_normalizer (int, Optional):
56
+ The normalizer for the gate logits, appied after `logsigmoid`. Default: 16.
57
+ fuse_norm (bool, Optional):
58
+ Whether to fuse the norm and the output gate for better memory footprint. Default: `True`.
59
+ layer_idx (int, Optional):
60
+ The index of the layer. Default: None.
61
+ """
62
+
63
+ def __init__(
64
+ self,
65
+ mode: str = 'chunk',
66
+ hidden_size: int = 1024,
67
+ expand_k: float = 1.,
68
+ expand_v: float = 1.,
69
+ num_heads: int = 4,
70
+ num_kv_heads: int | None = None,
71
+ feature_map: str | None = None,
72
+ use_short_conv: bool = True,
73
+ conv_size: int = 4,
74
+ conv_bias: bool = False,
75
+ gate_fn: str = 'swish',
76
+ elementwise_affine: bool | None = True,
77
+ norm_eps: float = 1e-5,
78
+ gate_logit_normalizer: int = 16,
79
+ fuse_norm: bool = True,
80
+ layer_idx: int = None,
81
+ ) -> SimpleGatedLinearAttention:
82
+ super().__init__()
83
+
84
+ self.mode = mode
85
+ self.hidden_size = hidden_size
86
+ self.expand_k = expand_k
87
+ self.expand_v = expand_v
88
+ self.num_heads = num_heads
89
+ self.num_kv_heads = num_kv_heads if num_kv_heads is not None else num_heads
90
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
91
+ self.feature_map_fn = ACT2FN[feature_map] if feature_map is not None else None
92
+
93
+ self.use_short_conv = use_short_conv
94
+ self.conv_size = conv_size
95
+ self.conv_bias = conv_bias
96
+
97
+ self.key_dim = int(hidden_size * expand_k)
98
+ self.value_dim = int(hidden_size * expand_v)
99
+ self.key_dim_per_group = self.key_dim // self.num_kv_groups
100
+ self.value_dim_per_group = self.value_dim // self.num_kv_groups
101
+ self.layer_idx = layer_idx
102
+
103
+ assert mode in ['chunk', "fused_recurrent"], f"Not supported mode `{mode}`."
104
+ assert self.key_dim % num_heads == 0, f"key dim must be divisible by num_heads of {num_heads}"
105
+ assert self.value_dim % num_heads == 0, f"value dim must be divisible by num_heads of {num_heads}"
106
+
107
+ self.head_k_dim = self.key_dim // num_heads
108
+ self.head_v_dim = self.value_dim // num_heads
109
+
110
+ self.q_proj = nn.Linear(hidden_size, self.key_dim, bias=False)
111
+ self.k_proj = nn.Linear(hidden_size, self.key_dim_per_group, bias=False)
112
+ self.v_proj = nn.Linear(hidden_size, self.value_dim_per_group, bias=False)
113
+ self.g_proj = nn.Linear(hidden_size, self.value_dim, bias=False)
114
+
115
+ if use_short_conv:
116
+ self.conv_size = conv_size
117
+ self.q_conv1d = ShortConvolution(
118
+ hidden_size=self.key_dim,
119
+ kernel_size=conv_size,
120
+ bias=conv_bias,
121
+ activation='silu',
122
+ )
123
+ self.k_conv1d = ShortConvolution(
124
+ hidden_size=self.key_dim_per_group,
125
+ kernel_size=conv_size,
126
+ bias=conv_bias,
127
+ activation='silu',
128
+ )
129
+ self.v_conv1d = ShortConvolution(
130
+ hidden_size=self.value_dim_per_group,
131
+ kernel_size=conv_size,
132
+ bias=conv_bias,
133
+ activation='silu',
134
+ )
135
+
136
+ self.gk_proj = nn.Linear(hidden_size, self.num_heads)
137
+
138
+ if gate_fn == 'swish' and fuse_norm:
139
+ self.g_norm_swish_gate = FusedRMSNormGated(
140
+ hidden_size=self.head_v_dim,
141
+ elementwise_affine=elementwise_affine,
142
+ eps=norm_eps,
143
+ )
144
+ self.fuse_norm_and_gate = True
145
+ else:
146
+ self.fuse_norm_and_gate = False
147
+ self.g_norm = RMSNorm(
148
+ hidden_size=self.head_v_dim,
149
+ elementwise_affine=elementwise_affine,
150
+ eps=norm_eps,
151
+ dtype=torch.float32
152
+ )
153
+ self.gate_fn = ACT2FN[gate_fn]
154
+ self.o_proj = nn.Linear(self.value_dim, hidden_size, bias=False)
155
+
156
+ self.gate_logit_normalizer = gate_logit_normalizer
157
+
158
+ def forward(
159
+ self,
160
+ hidden_states: torch.Tensor,
161
+ attention_mask: torch.Tensor | None = None,
162
+ past_key_values: Cache | None = None,
163
+ use_cache: bool | None = False,
164
+ output_attentions: bool | None = False,
165
+ **kwargs,
166
+ ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]:
167
+ if attention_mask is not None:
168
+ assert len(attention_mask.shape) == 2, (
169
+ "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] "
170
+ "for padding purposes (0 indicating padding). "
171
+ "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed."
172
+ )
173
+
174
+ # launching the triton kernel for just one token will actually be slower
175
+ mode = 'fused_recurrent' if hidden_states.shape[1] <= 64 else self.mode
176
+
177
+ last_state = get_layer_cache(self, past_key_values)
178
+
179
+ cu_seqlens = kwargs.get('cu_seqlens')
180
+ if self.use_short_conv:
181
+ conv_state_q, conv_state_k, conv_state_v = None, None, None
182
+ if last_state is not None:
183
+ conv_state_q, conv_state_k, conv_state_v = last_state['conv_state']
184
+ conv_mask = attention_mask[:, -hidden_states.shape[1]:] if attention_mask is not None else None
185
+ q, conv_state_q = self.q_conv1d(
186
+ x=self.q_proj(hidden_states),
187
+ mask=conv_mask,
188
+ cache=conv_state_q,
189
+ output_final_state=use_cache,
190
+ cu_seqlens=cu_seqlens,
191
+ )
192
+ k, conv_state_k = self.k_conv1d(
193
+ x=self.k_proj(hidden_states),
194
+ mask=conv_mask,
195
+ cache=conv_state_k,
196
+ output_final_state=use_cache,
197
+ cu_seqlens=cu_seqlens,
198
+ )
199
+ v, conv_state_v = self.v_conv1d(
200
+ x=self.v_proj(hidden_states),
201
+ mask=conv_mask,
202
+ cache=conv_state_v,
203
+ output_final_state=use_cache,
204
+ cu_seqlens=cu_seqlens,
205
+ )
206
+ else:
207
+ q = self.q_proj(hidden_states)
208
+ k = self.k_proj(hidden_states)
209
+ v = self.v_proj(hidden_states)
210
+ gk = self.gk_proj(hidden_states)
211
+
212
+ if self.feature_map_fn is not None:
213
+ q, k = map(self.feature_map_fn, (q, k))
214
+ # dealing with left-padding
215
+ if attention_mask is not None:
216
+ v = v.mul_(attention_mask[:, -v.shape[-2]:, None])
217
+ q = rearrange(q, '... (h d) -> ... h d', h=self.num_heads)
218
+ if self.num_kv_groups > 1:
219
+ k, v = (repeat(x, '... (h d) -> ... (h g) d', h=self.num_kv_heads, g=self.num_kv_groups) for x in (k, v))
220
+ else:
221
+ k, v = (rearrange(x, '... (h d) -> ... h d', h=self.num_kv_heads) for x in (k, v))
222
+ gk = F.logsigmoid(gk) / self.gate_logit_normalizer
223
+
224
+ recurrent_state = last_state['recurrent_state'] if last_state is not None else None
225
+ if mode == 'chunk':
226
+ o, recurrent_state = chunk_simple_gla(
227
+ q=q,
228
+ k=k,
229
+ v=v,
230
+ g=gk,
231
+ initial_state=recurrent_state,
232
+ output_final_state=use_cache,
233
+ cu_seqlens=cu_seqlens,
234
+ )
235
+ elif mode == 'fused_recurrent':
236
+ o, recurrent_state = fused_recurrent_simple_gla(
237
+ q=q,
238
+ k=k,
239
+ v=v,
240
+ g=gk,
241
+ initial_state=recurrent_state,
242
+ output_final_state=use_cache,
243
+ cu_seqlens=cu_seqlens,
244
+ )
245
+ else:
246
+ raise NotImplementedError(f"Not supported mode `{mode}`.")
247
+
248
+ update_layer_cache(
249
+ self,
250
+ past_key_values,
251
+ recurrent_state=recurrent_state,
252
+ conv_state=(conv_state_q, conv_state_k, conv_state_v) if self.use_short_conv else None,
253
+ offset=q.shape[1],
254
+ )
255
+
256
+ g = self.g_proj(hidden_states)
257
+ if self.fuse_norm_and_gate:
258
+ g = rearrange(g, 'b t (h d) -> b t h d', h=self.num_heads)
259
+ o = self.g_norm_swish_gate(o, g)
260
+ o = rearrange(o, 'b t h d -> b t (h d)')
261
+ else:
262
+ o = rearrange(self.g_norm(o), 'b t h d -> b t (h d)')
263
+ o = o * self.gate_fn(g)
264
+ o = self.o_proj(o)
265
+
266
+ return o, None, past_key_values
267
+
268
+ def state_size(self, **kwargs) -> int:
269
+ state_size = self.key_dim * self.head_v_dim
270
+ for module in self.children():
271
+ if isinstance(module, ShortConvolution):
272
+ state_size += module.state_size
273
+ return state_size
fla/layers/utils.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023-2025, Songlin Yang, Yu Zhang
2
+
3
+ # Code is adapted from flash-attn.bert_padding.py
4
+
5
+
6
+ import torch
7
+ from einops import rearrange, repeat
8
+
9
+ from fla.ops.utils.index import prepare_cu_seqlens_from_mask, prepare_lens_from_mask
10
+ from fla.utils import tensor_cache
11
+
12
+ _LAYER_IDX_REQUIRED_MSG = "{cls} requires `layer_idx` when `past_key_values` is provided."
13
+
14
+
15
+ class IndexFirstAxis(torch.autograd.Function):
16
+
17
+ @staticmethod
18
+ def forward(ctx, x, indices):
19
+ ctx.save_for_backward(indices)
20
+ assert x.ndim >= 2
21
+ ctx.first_axis_dim, other_shape = x.shape[0], x.shape[1:]
22
+ second_dim = other_shape.numel()
23
+ # TD [2022-03-04] For some reason torch.gather is a bit faster than indexing.
24
+ # return x[indices]
25
+ return torch.gather(
26
+ rearrange(x, "b ... -> b (...)"), 0, repeat(indices, "z -> z d", d=second_dim),
27
+ ).reshape(-1, *other_shape)
28
+
29
+ @staticmethod
30
+ def backward(ctx, do):
31
+ (indices,) = ctx.saved_tensors
32
+ assert do.ndim >= 2
33
+ other_shape = do.shape[1:]
34
+ do = rearrange(do, "b ... -> b (...)")
35
+ dx = torch.zeros(
36
+ [ctx.first_axis_dim, do.shape[1]],
37
+ device=do.device,
38
+ dtype=do.dtype,
39
+ )
40
+ # TD [2022-03-04] For some reason torch.scatter is a bit faster than indexing.
41
+ # dx[indices] = do
42
+ dx.scatter_(0, repeat(indices, "z -> z d", d=do.shape[1]), do)
43
+ return dx.reshape(ctx.first_axis_dim, *other_shape), None
44
+
45
+
46
+ index_first_axis = IndexFirstAxis.apply
47
+
48
+
49
+ class IndexPutFirstAxis(torch.autograd.Function):
50
+
51
+ @staticmethod
52
+ def forward(ctx, x, indices, first_axis_dim):
53
+ ctx.save_for_backward(indices)
54
+ assert indices.ndim == 1
55
+ assert x.ndim >= 2
56
+ y = torch.zeros(first_axis_dim, *x.shape[1:], device=x.device, dtype=x.dtype)
57
+ # TODO [2022-03-04] For some reason torch.scatter is a bit faster than indexing.
58
+ y[indices] = x
59
+ # y.scatter_(0, repeat(indices, 'z -> z d', d=x.shape[1]), x)
60
+ return y
61
+
62
+ @staticmethod
63
+ def backward(ctx, do):
64
+ (indices,) = ctx.saved_tensors
65
+ # TODO [2022-03-04] For some reason torch.gather is a bit faster than indexing.
66
+ dx = do[indices]
67
+ # dx = torch.gather(do, 0, repeat(indices, 'z -> z d', d=do.shape[1]))
68
+ return dx, None, None
69
+
70
+
71
+ index_put_first_axis = IndexPutFirstAxis.apply
72
+
73
+
74
+ @tensor_cache
75
+ def get_unpad_data(
76
+ attention_mask: torch.Tensor,
77
+ ) -> tuple[torch.Tensor, torch.Tensor, int]:
78
+ """
79
+ Retrieves indexing data required to repad unpadded (ragged) tensors.
80
+
81
+ Args:
82
+ attention_mask (`torch.Tensor`):
83
+ Boolean or int tensor of shape (batch_size, sequence_length), 1 means valid and 0 means not valid.
84
+
85
+ Return:
86
+ indices (`torch.Tensor`):
87
+ The indices of non-masked tokens from the flattened input sequence.
88
+ cu_seqlens (`torch.Tensor`):
89
+ The cumulative sequence lengths, used to index into ragged (unpadded) tensors.
90
+ `cu_seqlens` shape is [batch_size + 1].
91
+ max_seqlen_in_batch (`int`):
92
+ Maximum sequence length in batch.
93
+ """
94
+ lens = prepare_lens_from_mask(attention_mask)
95
+ indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten()
96
+ max_seqlen_in_batch = lens.max().item()
97
+ cu_seqlens = prepare_cu_seqlens_from_mask(attention_mask)
98
+ return indices, cu_seqlens, max_seqlen_in_batch
99
+
100
+
101
+ def unpad_input(
102
+ q: torch.Tensor,
103
+ states: tuple[torch.Tensor],
104
+ attention_mask: torch.Tensor,
105
+ q_len: int,
106
+ keepdim: bool = False,
107
+ ):
108
+ """
109
+ Unpads query, key, and values tensors, using a single dimension for all tokens
110
+ even though they belong to different batches.
111
+
112
+
113
+ Arguments:
114
+ q (`torch.Tensor`):
115
+ Query state with padding. Shape: [batch_size, q_len, ...].
116
+ states (`Tuple[torch.Tensor]`):
117
+ Attention state with padding. Shape: [batch_size, seq_len, ...].
118
+ attention_mask (`torch.Tensor`):
119
+ Boolean or int tensor of shape [batch_size, sequence_length], 1 means valid and 0 means not valid.
120
+ q_len (`int`):
121
+ Target length.
122
+ keepdim (`bool`):
123
+ Whether to keep the batch dimension. Default: `False`.
124
+
125
+ Return:
126
+ q (`torch.Tensor`):
127
+ Query state without padding.
128
+ Shape: [1, total_target_length, ...] if `keepdim=True` else [total_target_length, ...].
129
+ states (`Tuple[torch.Tensor]`):
130
+ Attention state without padding.
131
+ Shape: [1, total_source_length, ...] if `keepdim=True` else [total_source_length, ...].
132
+ indices_q (`torch.Tensor`):
133
+ The indices of non-masked tokens from the flattened input target sequence.
134
+ (cu_seqlens_q, cu_seqlens_k) (`Tuple[int]`):
135
+ The cumulative sequence lengths for the target (query) and source (key, value),
136
+ used to index into ragged (unpadded) tensors.
137
+ `cu_seqlens` shape is [batch_size + 1].
138
+ (max_seqlen_in_batch_q, max_seqlen_in_batch_k) (`Tuple[int]`):
139
+ Maximum sequence length in batch (`max_seqlen_in_batch_q` for the target sequence
140
+ i.e. query, `max_seqlen_in_batch_k` for the source sequence i.e. key/value).
141
+ """
142
+ indices_k, cu_seqlens_k, max_seqlen_in_batch_k = get_unpad_data(attention_mask)
143
+ batch_size, seq_len, *_ = states[0].shape
144
+
145
+ state = tuple(
146
+ index_first_axis(rearrange(s, "b s ... -> (b s) ..."), indices_k)
147
+ for s in states
148
+ )
149
+
150
+ if q_len == seq_len:
151
+ q = index_first_axis(rearrange(q, "b s ... -> (b s) ..."), indices_k)
152
+ cu_seqlens_q = cu_seqlens_k
153
+ max_seqlen_in_batch_q = max_seqlen_in_batch_k
154
+ indices_q = indices_k
155
+ elif q_len == 1:
156
+ max_seqlen_in_batch_q = 1
157
+ cu_seqlens_q = torch.arange(batch_size + 1, dtype=torch.int32, device=q.device)
158
+ indices_q = cu_seqlens_q[:-1]
159
+ q = q.squeeze(1)
160
+ else:
161
+ raise NotImplementedError("We only support either q_len == k_len (prefilling) or q_len == 1 (decoding)")
162
+
163
+ if keepdim:
164
+ q = q.unsqueeze(0)
165
+ state = tuple(s.unsqueeze(0) for s in state)
166
+
167
+ return (
168
+ q,
169
+ state,
170
+ indices_q,
171
+ (cu_seqlens_q, cu_seqlens_k),
172
+ (max_seqlen_in_batch_q, max_seqlen_in_batch_k),
173
+ )
174
+
175
+
176
+ def pad_input(
177
+ hidden_states: torch.Tensor,
178
+ indices: torch.LongTensor,
179
+ batch_size: int,
180
+ seq_len: int,
181
+ ) -> torch.Tensor:
182
+ """
183
+ Args:
184
+ hidden_states ([total_tokens, ...]):
185
+ where total_tokens denotes the number of tokens in selected in attention_mask.
186
+ indices ([total_tokens]):
187
+ the indices that represent the non-masked tokens of the original padded input sequence.
188
+ batch_size (int):
189
+ batch_size size for the padded sequence.
190
+ seq_len (int):
191
+ maximum sequence length for the padded sequence.
192
+
193
+ Return:
194
+ hidden_states of shape [batch_size, seq_len, ...]
195
+ """
196
+ output = index_put_first_axis(hidden_states, indices, batch_size * seq_len)
197
+ return rearrange(output, "(b s) ... -> b s ...", b=batch_size)
198
+
199
+
200
+ def require_cache_layer_idx(module, past_key_values):
201
+ layer_idx = getattr(module, "layer_idx", None)
202
+ if past_key_values is not None and layer_idx is None:
203
+ raise ValueError(_LAYER_IDX_REQUIRED_MSG.format(cls=module.__class__.__name__))
204
+ return layer_idx
205
+
206
+
207
+ def get_layer_cache(module, past_key_values):
208
+ layer_idx = require_cache_layer_idx(module, past_key_values)
209
+ if past_key_values is not None and len(past_key_values) > layer_idx:
210
+ return past_key_values[layer_idx]
211
+ return None
212
+
213
+
214
+ def update_layer_cache(module, past_key_values, **kwargs):
215
+ layer_idx = require_cache_layer_idx(module, past_key_values)
216
+ if past_key_values is not None:
217
+ return past_key_values.update(layer_idx=layer_idx, **kwargs)
218
+ return None
fla/models/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Keep model package imports lazy.
2
+ __all__ = []
3
+
fla/models/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (179 Bytes). View file
 
fla/models/__pycache__/utils.cpython-312.pyc ADDED
Binary file (23.1 kB). View file
 
fla/models/abc/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
3
+
4
+ from fla.models.abc.configuration_abc import ABCConfig
5
+ from fla.models.abc.modeling_abc import ABCForCausalLM, ABCModel
6
+
7
+ AutoConfig.register(ABCConfig.model_type, ABCConfig, exist_ok=True)
8
+ AutoModel.register(ABCConfig, ABCModel, exist_ok=True)
9
+ AutoModelForCausalLM.register(ABCConfig, ABCForCausalLM, exist_ok=True)
10
+
11
+
12
+ __all__ = ['ABCConfig', 'ABCForCausalLM', 'ABCModel']
fla/models/abc/configuration_abc.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import warnings
3
+
4
+ from transformers.configuration_utils import PretrainedConfig
5
+
6
+
7
+ class ABCConfig(PretrainedConfig):
8
+
9
+ model_type = 'abc'
10
+ keys_to_ignore_at_inference = ['past_key_values']
11
+
12
+ def __init__(
13
+ self,
14
+ hidden_size: int = 2048,
15
+ gate_low_rank_dim: int = 16,
16
+ clamp_min: float = -32,
17
+ clamp_max: float = 32,
18
+ hidden_ratio: int | None = 4,
19
+ intermediate_size: int | None = None,
20
+ num_hidden_layers: int = 24,
21
+ num_heads: int = 4,
22
+ num_slots: int | None = 64,
23
+ use_short_conv: bool = False,
24
+ conv_size: int = 4,
25
+ exapnd_k: float = 0.5,
26
+ exapnd_v: float = 1,
27
+ hidden_act: str = "swish",
28
+ max_position_embeddings: int = 2048,
29
+ elementwise_affine: bool | None = True,
30
+ norm_eps: float = 1e-6,
31
+ use_rope: bool = True,
32
+ attn: dict | None = None,
33
+ use_cache: bool = True,
34
+ pad_token_id: int | None = None,
35
+ bos_token_id: int = 1,
36
+ eos_token_id: int = 2,
37
+ tie_word_embeddings: bool = False,
38
+ initializer_range: float = 0.02,
39
+ fuse_norm: bool = True,
40
+ fuse_swiglu: bool = True,
41
+ fuse_cross_entropy: bool = True,
42
+ fuse_linear_cross_entropy: bool = False,
43
+ use_l2warp: bool = False,
44
+ vocab_size: int = 32000,
45
+ **kwargs,
46
+ ):
47
+ self.hidden_size = hidden_size
48
+ self.gate_low_rank_dim = gate_low_rank_dim
49
+ self.clamp_min = clamp_min
50
+ self.clamp_max = clamp_max
51
+ self.hidden_ratio = hidden_ratio
52
+ self.intermediate_size = intermediate_size
53
+ self.num_hidden_layers = num_hidden_layers
54
+ self.num_heads = num_heads
55
+ self.num_slots = num_slots
56
+ self.use_short_conv = use_short_conv
57
+ self.conv_size = conv_size
58
+ self.expand_k = exapnd_k
59
+ self.expand_v = exapnd_v
60
+ self.hidden_act = hidden_act
61
+ self.max_position_embeddings = max_position_embeddings
62
+ self.elementwise_affine = elementwise_affine
63
+ self.norm_eps = norm_eps
64
+ self.use_rope = use_rope
65
+ self.attn = attn
66
+ self.use_cache = use_cache
67
+ self.initializer_range = initializer_range
68
+
69
+ self.fuse_norm = fuse_norm
70
+ self.fuse_swiglu = fuse_swiglu
71
+ self.fuse_cross_entropy = fuse_cross_entropy
72
+ self.fuse_linear_cross_entropy = fuse_linear_cross_entropy
73
+ self.use_l2warp = use_l2warp
74
+ self.vocab_size = vocab_size
75
+
76
+ if fuse_cross_entropy and fuse_linear_cross_entropy:
77
+ raise ValueError(
78
+ "`fuse_cross_entropy` and `fuse_linear_cross_entropy` cannot be True at the same time.",
79
+ )
80
+ if fuse_linear_cross_entropy:
81
+ warnings.warn(
82
+ "`fuse_linear_cross_entropy` is enabled, which can improves memory efficiency "
83
+ "at the potential cost of reduced precision. "
84
+ "If you observe issues like loss divergence, consider disabling this setting.",
85
+ )
86
+
87
+ if attn is not None:
88
+ if not isinstance(attn, dict):
89
+ raise ValueError("attn must be a dictionary")
90
+ if 'layers' not in attn:
91
+ raise ValueError("Layer indices must be provided to initialize hybrid attention layers")
92
+ if 'num_heads' not in attn:
93
+ raise ValueError("Number of heads must be provided to initialize hybrid attention layers")
94
+ attn['num_kv_heads'] = attn.get('num_kv_heads', attn['num_heads'])
95
+ attn['qkv_bias'] = attn.get('qkv_bias', False)
96
+ attn['window_size'] = attn.get('window_size', None)
97
+ attn['rope_theta'] = attn.get('rope_theta', 10000.)
98
+
99
+ super().__init__(
100
+ pad_token_id=pad_token_id,
101
+ bos_token_id=bos_token_id,
102
+ eos_token_id=eos_token_id,
103
+ tie_word_embeddings=tie_word_embeddings,
104
+ **kwargs,
105
+ )
fla/models/abc/modeling_abc.py ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import warnings
5
+ from typing import TYPE_CHECKING, Optional
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast
10
+ from transformers.modeling_utils import PreTrainedModel
11
+ from transformers.utils import logging
12
+ from transformers.utils.deprecation import deprecate_kwarg
13
+
14
+ from fla.layers.abc import ABCAttention
15
+ from fla.layers.attn import Attention
16
+ from fla.models.abc.configuration_abc import ABCConfig
17
+ from fla.models.utils import Cache, FLAGenerationMixin
18
+ from fla.modules import FusedCrossEntropyLoss, FusedLinearCrossEntropyLoss, RMSNorm
19
+ from fla.modules import GatedMLP as ABCMLP
20
+ from fla.modules.l2warp import l2_warp
21
+
22
+ try:
23
+ from transformers.modeling_layers import GradientCheckpointingLayer
24
+ except ImportError:
25
+ from fla.models.modeling_layers import GradientCheckpointingLayer
26
+
27
+ logger = logging.get_logger(__name__)
28
+
29
+ if TYPE_CHECKING:
30
+ from transformers.processing_utils import Unpack
31
+
32
+
33
+ class ABCBlock(GradientCheckpointingLayer):
34
+
35
+ def __init__(self, config: ABCConfig, layer_idx: int):
36
+ super().__init__()
37
+
38
+ self.config = config
39
+ self.layer_idx = layer_idx
40
+
41
+ self.attn_norm = (RMSNorm if config.fuse_norm else nn.RMSNorm)(config.hidden_size, eps=config.norm_eps)
42
+ if config.attn is not None and layer_idx in config.attn['layers']:
43
+ self.attn = Attention(
44
+ hidden_size=config.hidden_size,
45
+ num_heads=config.attn['num_heads'],
46
+ num_kv_heads=config.attn['num_kv_heads'],
47
+ qkv_bias=config.attn['qkv_bias'],
48
+ window_size=config.attn['window_size'],
49
+ rope_theta=config.attn['rope_theta'],
50
+ max_position_embeddings=config.max_position_embeddings,
51
+ layer_idx=layer_idx,
52
+ )
53
+ else:
54
+ self.attn = ABCAttention(
55
+ hidden_size=config.hidden_size,
56
+ expand_k=config.expand_k,
57
+ expand_v=config.expand_v,
58
+ num_heads=config.num_heads,
59
+ num_slots=config.num_slots,
60
+ use_short_conv=config.use_short_conv,
61
+ conv_size=config.conv_size,
62
+ gate_fn=config.hidden_act,
63
+ elementwise_affine=config.elementwise_affine,
64
+ norm_eps=config.norm_eps,
65
+ use_rope=config.use_rope,
66
+ clamp_min=config.clamp_min,
67
+ clamp_max=config.clamp_max,
68
+ fuse_norm=config.fuse_norm,
69
+ layer_idx=layer_idx,
70
+ )
71
+ self.mlp_norm = (RMSNorm if config.fuse_norm else nn.RMSNorm)(config.hidden_size, eps=config.norm_eps)
72
+ self.mlp = ABCMLP(
73
+ hidden_size=config.hidden_size,
74
+ hidden_ratio=config.hidden_ratio,
75
+ intermediate_size=config.intermediate_size,
76
+ hidden_act=config.hidden_act,
77
+ fuse_swiglu=config.fuse_swiglu,
78
+ )
79
+
80
+ def forward(
81
+ self,
82
+ hidden_states: torch.Tensor,
83
+ attention_mask: torch.Tensor | None = None,
84
+ past_key_values: Cache | list[torch.FloatTensor] | None = None,
85
+ use_cache: bool | None = False,
86
+ output_attentions: bool | None = False,
87
+ **kwargs: Unpack[dict],
88
+ ) -> tuple[torch.FloatTensor, tuple[torch.FloatTensor, torch.FloatTensor] | None]:
89
+
90
+ residual = hidden_states
91
+
92
+ hidden_states = self.attn_norm(hidden_states)
93
+ hidden_states, attentions, past_key_values = self.attn(
94
+ hidden_states=hidden_states,
95
+ attention_mask=attention_mask,
96
+ past_key_values=past_key_values,
97
+ use_cache=use_cache,
98
+ output_attentions=output_attentions,
99
+ **kwargs,
100
+ )
101
+ if self.config.fuse_norm:
102
+ hidden_states, residual = self.mlp_norm(hidden_states, residual, True)
103
+ else:
104
+ hidden_states = residual + hidden_states
105
+ residual = hidden_states
106
+ hidden_states = self.mlp_norm(hidden_states)
107
+ hidden_states = self.mlp(hidden_states)
108
+ hidden_states = residual + hidden_states
109
+
110
+ outputs = (hidden_states, attentions, past_key_values)
111
+
112
+ return outputs
113
+
114
+
115
+ class ABCPreTrainedModel(PreTrainedModel):
116
+
117
+ config_class = ABCConfig
118
+ base_model_prefix = 'model'
119
+ supports_gradient_checkpointing = True
120
+ _no_split_modules = ['ABCBlock']
121
+ _supports_cache_class = True
122
+
123
+ def __init__(self, *inputs, **kwargs):
124
+ super().__init__(*inputs, **kwargs)
125
+
126
+ def _init_weights(
127
+ self,
128
+ module: nn.Module,
129
+ prenorm_residual_strategy: str | None = None,
130
+ num_residuals_per_layer: int = 2,
131
+ ):
132
+ if isinstance(module, (nn.Linear, nn.Conv1d)):
133
+ # Slightly different from the TF version which uses truncated_normal for initialization
134
+ # cf https://github.com/pytorch/pytorch/pull/5617
135
+ nn.init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
136
+ if module.bias is not None:
137
+ nn.init.zeros_(module.bias)
138
+ elif isinstance(module, nn.Embedding):
139
+ nn.init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
140
+ elif hasattr(module, 'reset_parameters'):
141
+ module.reset_parameters()
142
+
143
+ if prenorm_residual_strategy is not None:
144
+ # Reinitialize selected weights subject to the OpenAI GPT-2 Paper Scheme:
145
+ # > A modified initialization which accounts for the accumulation on the residual path with model depth. Scale
146
+ # > the weights of residual layers at initialization by a factor of 1/√N where N is the # of residual layers.
147
+ # > -- GPT-2 :: https://openai.com/blog/better-language-models/
148
+ #
149
+ # Reference (Megatron-LM): https://github.com/NVIDIA/Megatron-LM/blob/main/megatron/model/gpt_model.py
150
+ p = None
151
+ if hasattr(module, 'o_proj'):
152
+ p = module.o_proj.weight
153
+ elif hasattr(module, 'down_proj'):
154
+ p = module.down_proj.weight
155
+ if p is not None:
156
+ # Special Scaled Initialization --> There are 2 Layer Norms per Transformer Block
157
+ # Following Pytorch init, except scale by 1/sqrt(2 * n_layer)
158
+ # We need to reinit p since this code could be called multiple times
159
+ # Having just p *= scale would repeatedly scale it down
160
+ if prenorm_residual_strategy == 'rescale':
161
+ nn.init.kaiming_uniform_(p, a=math.sqrt(5))
162
+ with torch.no_grad():
163
+ p /= math.sqrt(num_residuals_per_layer * self.config.num_hidden_layers)
164
+ elif prenorm_residual_strategy == 'zero':
165
+ nn.init.zeros_(p)
166
+ else:
167
+ raise ValueError(f"Invalid prenorm_residual_strategy: {prenorm_residual_strategy}")
168
+
169
+
170
+ class ABCModel(ABCPreTrainedModel):
171
+
172
+ def __init__(self, config: ABCConfig):
173
+ super().__init__(config)
174
+ self.padding_idx = config.pad_token_id
175
+ self.vocab_size = config.vocab_size
176
+
177
+ self.embeddings = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
178
+ self.layers = nn.ModuleList([ABCBlock(config, layer_idx) for layer_idx in range(config.num_hidden_layers)])
179
+ self.norm = (RMSNorm if config.fuse_norm else nn.RMSNorm)(config.hidden_size, eps=config.norm_eps)
180
+
181
+ self.gradient_checkpointing = False
182
+
183
+ self.post_init()
184
+
185
+ def get_input_embeddings(self):
186
+ return self.embeddings
187
+
188
+ def set_input_embeddings(self, value):
189
+ self.embeddings = value
190
+
191
+ def forward(
192
+ self,
193
+ input_ids: torch.LongTensor | None = None,
194
+ attention_mask: Optional[torch.Tensor] = None, # noqa
195
+ inputs_embeds: torch.FloatTensor | None = None,
196
+ past_key_values: Cache | list[torch.FloatTensor] | None = None,
197
+ use_cache: bool | None = None,
198
+ output_attentions: bool | None = None,
199
+ output_hidden_states: bool | None = None,
200
+ return_dict: bool | None = None,
201
+ **kwargs: Unpack[dict],
202
+ ) -> tuple | BaseModelOutputWithPast:
203
+ if output_attentions:
204
+ warnings.warn("`ABCModel` does not `output_attentions` now, setting it to `False`.")
205
+ output_attentions = False
206
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
207
+ output_hidden_states = output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
208
+ use_cache = use_cache if use_cache is not None else (self.config.use_cache if not self.training else False)
209
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
210
+
211
+ # retrieve input_ids and inputs_embeds
212
+ if input_ids is not None and inputs_embeds is not None:
213
+ raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
214
+ if input_ids is None and inputs_embeds is None:
215
+ raise ValueError("You have to specify either input_ids or inputs_embeds")
216
+
217
+ if inputs_embeds is None:
218
+ inputs_embeds = self.embeddings(input_ids)
219
+ hidden_states = inputs_embeds
220
+
221
+ if use_cache and not isinstance(past_key_values, Cache):
222
+ past_key_values = Cache.from_legacy_cache(past_key_values)
223
+
224
+ all_hidden_states = () if output_hidden_states else None
225
+ all_attns = () if output_attentions else None
226
+ for layer in self.layers:
227
+ if output_hidden_states:
228
+ all_hidden_states += (hidden_states,)
229
+
230
+ hidden_states, attentions, past_key_values = layer(
231
+ hidden_states,
232
+ attention_mask,
233
+ past_key_values=past_key_values,
234
+ use_cache=use_cache,
235
+ output_attentions=output_attentions,
236
+ **kwargs,
237
+ )
238
+
239
+ if output_attentions:
240
+ all_attns += (attentions,)
241
+
242
+ hidden_states = self.norm(hidden_states)
243
+
244
+ # add hidden states from the last decoder layer
245
+ if output_hidden_states:
246
+ all_hidden_states += (hidden_states,)
247
+
248
+ if not return_dict:
249
+ return tuple(i for i in [hidden_states, past_key_values, all_hidden_states, all_attns] if i is not None)
250
+ return BaseModelOutputWithPast(
251
+ last_hidden_state=hidden_states,
252
+ past_key_values=past_key_values,
253
+ hidden_states=all_hidden_states,
254
+ attentions=all_attns,
255
+ )
256
+
257
+
258
+ class ABCForCausalLM(ABCPreTrainedModel, FLAGenerationMixin):
259
+
260
+ _tied_weights_keys = ["lm_head.weight"]
261
+
262
+ def __init__(self, config):
263
+ super().__init__(config)
264
+ self.model = ABCModel(config)
265
+ self.vocab_size = config.vocab_size
266
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
267
+ self.criterion = None
268
+
269
+ # Initialize weights and apply final processing
270
+ self.post_init()
271
+
272
+ def get_input_embeddings(self):
273
+ return self.model.embeddings
274
+
275
+ def set_input_embeddings(self, value):
276
+ self.model.embeddings = value
277
+
278
+ def get_output_embeddings(self):
279
+ return self.lm_head
280
+
281
+ def set_output_embeddings(self, new_embeddings):
282
+ self.lm_head = new_embeddings
283
+
284
+ def set_decoder(self, decoder):
285
+ self.model = decoder
286
+
287
+ def get_decoder(self):
288
+ return self.model
289
+
290
+ def generate(self, *args, **kwargs):
291
+ try:
292
+ return super().generate(*args, **kwargs)
293
+ except AttributeError as exception:
294
+ if 'past_key_values' in str(exception):
295
+ raise AttributeError(
296
+ f"You tried to call `generate` with a decoding strategy that manipulates `past_key_values`, "
297
+ f"which is not supported for {self.__class__.__name__}. "
298
+ f"Try another generation strategy instead. "
299
+ f"For the available generation strategies, check this doc: "
300
+ f"https://huggingface.co/docs/transformers/en/generation_strategies#decoding-strategies",
301
+ )
302
+ else:
303
+ raise exception
304
+
305
+ @deprecate_kwarg("num_logits_to_keep", version="4.50", new_name="logits_to_keep")
306
+ def forward(
307
+ self,
308
+ input_ids: torch.LongTensor = None,
309
+ attention_mask: torch.Tensor | None = None,
310
+ inputs_embeds: torch.Tensor | None = None,
311
+ past_key_values: Cache | list[torch.FloatTensor] | None = None,
312
+ labels: torch.LongTensor | None = None,
313
+ use_cache: bool | None = None,
314
+ output_attentions: bool | None = None,
315
+ output_hidden_states: bool | None = None,
316
+ return_dict: bool | None = None,
317
+ logits_to_keep: int | None = 0,
318
+ **kwargs: Unpack[dict],
319
+ ) -> tuple | CausalLMOutputWithPast:
320
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
321
+ output_hidden_states = (
322
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
323
+ )
324
+ return_dict = return_dict if return_dict is not None else self.config.use_return_dict
325
+
326
+ outputs = self.model(
327
+ input_ids=input_ids,
328
+ attention_mask=attention_mask,
329
+ inputs_embeds=inputs_embeds,
330
+ past_key_values=past_key_values,
331
+ use_cache=use_cache,
332
+ output_attentions=output_attentions,
333
+ output_hidden_states=output_hidden_states,
334
+ return_dict=return_dict,
335
+ **kwargs,
336
+ )
337
+
338
+ hidden_states = outputs[0]
339
+
340
+ loss, logits = None, None
341
+ if not self.config.fuse_linear_cross_entropy or labels is None:
342
+ logits = self.lm_head(hidden_states if logits_to_keep is None else hidden_states[:, -logits_to_keep:])
343
+ if labels is not None:
344
+ if getattr(self, 'criterion', None) is None:
345
+ if self.config.fuse_linear_cross_entropy:
346
+ criterion = FusedLinearCrossEntropyLoss(use_l2warp=self.config.use_l2warp)
347
+ elif self.config.fuse_cross_entropy:
348
+ criterion = FusedCrossEntropyLoss(inplace_backward=True)
349
+ else:
350
+ criterion = nn.CrossEntropyLoss()
351
+ else:
352
+ criterion = self.criterion
353
+ labels = labels.to(hidden_states.device)
354
+ labels = torch.cat((labels[..., 1:], torch.full_like(labels[:, :1], criterion.ignore_index)), 1)
355
+ if self.config.fuse_linear_cross_entropy:
356
+ loss = criterion(hidden_states, labels, self.lm_head.weight, self.lm_head.bias)
357
+ else:
358
+ loss = criterion(logits.view(labels.numel(), -1), labels.view(-1))
359
+ loss = l2_warp(loss, logits) if self.config.use_l2warp else loss
360
+
361
+ if not return_dict:
362
+ output = (logits,) + outputs[1:]
363
+ return (loss,) + output if loss is not None else output
364
+
365
+ return CausalLMOutputWithPast(
366
+ loss=loss,
367
+ logits=logits,
368
+ past_key_values=outputs.past_key_values,
369
+ hidden_states=outputs.hidden_states,
370
+ attentions=outputs.attentions,
371
+ )
fla/models/bitnet/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
3
+
4
+ from fla.models.bitnet.configuration_bitnet import BitNetConfig
5
+ from fla.models.bitnet.modeling_bitnet import BitNetForCausalLM, BitNetModel
6
+
7
+ AutoConfig.register(BitNetConfig.model_type, BitNetConfig, exist_ok=True)
8
+ AutoModel.register(BitNetConfig, BitNetModel, exist_ok=True)
9
+ AutoModelForCausalLM.register(BitNetConfig, BitNetForCausalLM, exist_ok=True)
10
+
11
+
12
+ __all__ = ['BitNetConfig', 'BitNetForCausalLM', 'BitNetModel']