kernels-bot commited on
Commit
d64d667
·
verified ·
1 Parent(s): 1aae018

Uploaded using `kernel-builder` (batch 2/2).

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. build/torch213-cxx11-xpu20260-x86_64-linux/modules/mha.py +341 -0
  2. build/torch213-cxx11-xpu20260-x86_64-linux/modules/mlp.py +34 -0
  3. build/torch213-cxx11-xpu20260-x86_64-linux/modules/ssd_minimal.py +111 -0
  4. build/torch213-cxx11-xpu20260-x86_64-linux/ops/__init__.py +1 -0
  5. build/torch213-cxx11-xpu20260-x86_64-linux/ops/selective_scan_interface.py +708 -0
  6. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/__init__.py +2 -0
  7. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/k_activations.py +171 -0
  8. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/layer_norm.py +1115 -0
  9. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/layernorm_gated.py +439 -0
  10. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/selective_state_update.py +290 -0
  11. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/softplus.py +15 -0
  12. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_bmm.py +264 -0
  13. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_chunk_scan.py +0 -0
  14. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_chunk_state.py +1003 -0
  15. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_combined.py +1908 -0
  16. build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_state_passing.py +350 -0
  17. build/torch213-cxx11-xpu20260-x86_64-linux/utils/__init__.py +0 -0
  18. build/torch213-cxx11-xpu20260-x86_64-linux/utils/device.py +24 -0
  19. build/torch213-cxx11-xpu20260-x86_64-linux/utils/generation.py +389 -0
  20. build/torch213-cxx11-xpu20260-x86_64-linux/utils/hf.py +23 -0
  21. build/torch213-cxx11-xpu20260-x86_64-linux/utils/torch.py +21 -0
  22. build/torch214-cxx11-xpu20261-x86_64-linux/__init__.py +17 -0
  23. build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/__init__.py +29 -0
  24. build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/causal_conv1d_interface.py +242 -0
  25. build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/causal_conv1d_varlen.py +88 -0
  26. build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/cpp_functions.py +92 -0
  27. build/torch214-cxx11-xpu20261-x86_64-linux/_mamba_ssm_xpu_81e0711.abi3.so +3 -0
  28. build/torch214-cxx11-xpu20261-x86_64-linux/_ops.py +9 -0
  29. build/torch214-cxx11-xpu20261-x86_64-linux/distributed/__init__.py +0 -0
  30. build/torch214-cxx11-xpu20261-x86_64-linux/distributed/distributed_utils.py +144 -0
  31. build/torch214-cxx11-xpu20261-x86_64-linux/distributed/tensor_parallel.py +297 -0
  32. build/torch214-cxx11-xpu20261-x86_64-linux/layers.py +265 -0
  33. build/torch214-cxx11-xpu20261-x86_64-linux/metadata.json +70 -0
  34. build/torch214-cxx11-xpu20261-x86_64-linux/metadata.json.sigstore +1 -0
  35. build/torch214-cxx11-xpu20261-x86_64-linux/models/__init__.py +5 -0
  36. build/torch214-cxx11-xpu20261-x86_64-linux/models/config_mamba.py +18 -0
  37. build/torch214-cxx11-xpu20261-x86_64-linux/models/mixer_seq_simple.py +309 -0
  38. build/torch214-cxx11-xpu20261-x86_64-linux/modules/__init__.py +7 -0
  39. build/torch214-cxx11-xpu20261-x86_64-linux/modules/block.py +107 -0
  40. build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba2.py +477 -0
  41. build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba2_simple.py +228 -0
  42. build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba_simple.py +319 -0
  43. build/torch214-cxx11-xpu20261-x86_64-linux/modules/mha.py +341 -0
  44. build/torch214-cxx11-xpu20261-x86_64-linux/modules/mlp.py +34 -0
  45. build/torch214-cxx11-xpu20261-x86_64-linux/modules/ssd_minimal.py +111 -0
  46. build/torch214-cxx11-xpu20261-x86_64-linux/ops/__init__.py +1 -0
  47. build/torch214-cxx11-xpu20261-x86_64-linux/ops/selective_scan_interface.py +708 -0
  48. build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/__init__.py +2 -0
  49. build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/k_activations.py +171 -0
  50. build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/layer_norm.py +1115 -0
build/torch213-cxx11-xpu20260-x86_64-linux/modules/mha.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import math
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from einops import rearrange
9
+
10
+ try:
11
+ from flash_attn import flash_attn_with_kvcache
12
+ except ImportError:
13
+ flash_attn_with_kvcache = None
14
+
15
+ try:
16
+ from flash_attn.layers.rotary import RotaryEmbedding
17
+ except ImportError:
18
+ RotaryEmbedding = None
19
+
20
+ from .._causal_conv1d import causal_conv1d_fn, causal_conv1d_update
21
+
22
+
23
+ def _update_kv_cache(kv, inference_params, layer_idx):
24
+ """kv: (batch_size, seqlen, 2, nheads, head_dim) or (batch_size, 1, 2, nheads, head_dim)"""
25
+ # Pre-allocate memory for key-values for inference.
26
+ num_heads, head_dim = kv.shape[-2:]
27
+ assert layer_idx in inference_params.key_value_memory_dict
28
+ kv_cache, _ = inference_params.key_value_memory_dict[layer_idx]
29
+ # Adjust key and value for inference
30
+ batch_start = inference_params.batch_size_offset
31
+ batch_end = batch_start + kv.shape[0]
32
+ sequence_start = inference_params.seqlen_offset
33
+ sequence_end = sequence_start + kv.shape[1]
34
+ assert batch_end <= kv_cache.shape[0]
35
+ assert sequence_end <= kv_cache.shape[1]
36
+ assert kv_cache is not None
37
+ kv_cache[batch_start:batch_end, sequence_start:sequence_end, ...] = kv
38
+ return kv_cache[batch_start:batch_end, :sequence_end, ...]
39
+
40
+
41
+ class MHA(nn.Module):
42
+ """Multi-head self-attention and cross-attention"""
43
+
44
+ def __init__(
45
+ self,
46
+ embed_dim,
47
+ num_heads,
48
+ num_heads_kv=None,
49
+ head_dim=None, # If None, use embed_dim // num_heads
50
+ mlp_dim=0,
51
+ qkv_proj_bias=True,
52
+ out_proj_bias=True,
53
+ softmax_scale=None,
54
+ causal=False,
55
+ layer_idx=None,
56
+ d_conv=0,
57
+ rotary_emb_dim=0,
58
+ rotary_emb_base=10000.0,
59
+ rotary_emb_interleaved=False,
60
+ device=None,
61
+ dtype=None,
62
+ ) -> None:
63
+ """
64
+ num_heads_kv: can be used to toggle MQA / GQA. If None, use num_heads.
65
+ return_residual: whether to return the input x along with the output. This is for
66
+ performance reason: for post-norm architecture, returning the input allows us
67
+ to fuse the backward of nn.Linear with the residual connection.
68
+ """
69
+ factory_kwargs = {"device": device, "dtype": dtype}
70
+ super().__init__()
71
+ self.embed_dim = embed_dim
72
+ self.layer_idx = layer_idx
73
+ self.d_conv = d_conv
74
+ self.rotary_emb_dim = rotary_emb_dim
75
+ self.softmax_scale = softmax_scale
76
+ self.causal = causal
77
+
78
+ self.num_heads = num_heads
79
+ self.num_heads_kv = num_heads_kv if num_heads_kv is not None else num_heads
80
+ assert self.num_heads % self.num_heads_kv == 0, (
81
+ "num_heads must be divisible by num_heads_kv"
82
+ )
83
+ if head_dim is None:
84
+ assert self.embed_dim % num_heads == 0, (
85
+ "embed_dim must be divisible by num_heads"
86
+ )
87
+ self.head_dim = (
88
+ head_dim if head_dim is not None else self.embed_dim // num_heads
89
+ )
90
+ self.mlp_dim = math.ceil(mlp_dim / 256) * 256
91
+ qkv_dim = self.head_dim * (self.num_heads + 2 * self.num_heads_kv)
92
+ out_dim = self.head_dim * self.num_heads
93
+
94
+ if self.rotary_emb_dim > 0:
95
+ assert RotaryEmbedding is not None, (
96
+ "rotary requires flash_attn to be installed"
97
+ )
98
+ self.rotary_emb = RotaryEmbedding(
99
+ self.rotary_emb_dim,
100
+ base=rotary_emb_base,
101
+ interleaved=rotary_emb_interleaved,
102
+ device=device,
103
+ )
104
+
105
+ self.in_proj = nn.Linear(
106
+ embed_dim, qkv_dim + self.mlp_dim, bias=qkv_proj_bias, **factory_kwargs
107
+ )
108
+ if self.d_conv > 0:
109
+ self.conv1d = nn.Conv1d(
110
+ qkv_dim,
111
+ qkv_dim,
112
+ kernel_size=self.d_conv,
113
+ padding=self.d_conv - 1,
114
+ groups=qkv_dim,
115
+ **factory_kwargs,
116
+ )
117
+ self.out_proj = nn.Linear(
118
+ out_dim + self.mlp_dim // 2, embed_dim, bias=out_proj_bias, **factory_kwargs
119
+ )
120
+
121
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None):
122
+ dtype = self.out_proj.weight.dtype if dtype is None else dtype
123
+ device = self.out_proj.weight.device
124
+ if self.d_conv > 0:
125
+ conv_state = torch.zeros(
126
+ batch_size,
127
+ self.conv1d.weight.shape[0],
128
+ self.d_conv,
129
+ device=device,
130
+ dtype=dtype,
131
+ )
132
+ else:
133
+ conv_state = None
134
+ kv_cache = torch.empty(
135
+ batch_size,
136
+ max_seqlen,
137
+ 2,
138
+ self.num_heads_kv,
139
+ self.head_dim,
140
+ dtype=dtype,
141
+ device=device,
142
+ )
143
+ return kv_cache, conv_state
144
+
145
+ def _update_kv_cache(self, kv, inference_params):
146
+ """kv: (batch_size, seqlen, 2, nheads, head_dim) or (batch_size, 1, 2, nheads, head_dim)"""
147
+ assert self.layer_idx is not None, (
148
+ "Generation requires layer_idx in the constructor"
149
+ )
150
+ return _update_kv_cache(kv, inference_params, self.layer_idx)
151
+
152
+ def _apply_rotary_update_kvcache_attention(self, q, kv, inference_params):
153
+ """
154
+ Fast path that combine 3 steps: apply rotary to Q and K, update kv cache, and apply attention.
155
+ q: (batch_size, seqlen_q, nheads, head_dim)
156
+ kv: (batch_size, seqlen_k, 2, nheads_kv, head_dim)
157
+ """
158
+ assert inference_params is not None and inference_params.seqlen_offset > 0
159
+ if self.rotary_emb_dim > 0:
160
+ self.rotary_emb._update_cos_sin_cache(
161
+ inference_params.max_seqlen, device=q.device, dtype=q.dtype
162
+ )
163
+ rotary_cos, rotary_sin = (
164
+ self.rotary_emb._cos_cached,
165
+ self.rotary_emb._sin_cached,
166
+ )
167
+ else:
168
+ rotary_cos, rotary_sin = None, None
169
+ batch = q.shape[0]
170
+ kv_cache, _ = inference_params.key_value_memory_dict[self.layer_idx]
171
+ kv_cache = kv_cache[:batch]
172
+ cache_seqlens = (
173
+ inference_params.lengths_per_sample[:batch]
174
+ if inference_params.lengths_per_sample is not None
175
+ else inference_params.seqlen_offset
176
+ )
177
+ assert flash_attn_with_kvcache is not None, "flash_attn must be installed"
178
+ context = flash_attn_with_kvcache(
179
+ q,
180
+ kv_cache[:, :, 0],
181
+ kv_cache[:, :, 1],
182
+ kv[:, :, 0],
183
+ kv[:, :, 1],
184
+ rotary_cos=rotary_cos,
185
+ rotary_sin=rotary_sin,
186
+ cache_seqlens=cache_seqlens,
187
+ softmax_scale=self.softmax_scale,
188
+ causal=self.causal,
189
+ rotary_interleaved=self.rotary_emb.interleaved
190
+ if self.rotary_emb_dim > 0
191
+ else False,
192
+ )
193
+ return context
194
+
195
+ def _update_kvcache_attention(self, q, kv, inference_params):
196
+ """Write kv to inference_params, then do attention"""
197
+ if inference_params.seqlen_offset == 0 or flash_attn_with_kvcache is None:
198
+ # TODO: this only uses seqlen_offset and not lengths_per_sample.
199
+ kv = self._update_kv_cache(kv, inference_params)
200
+ k, v = kv.unbind(dim=-3)
201
+ k = torch.repeat_interleave(
202
+ k, dim=2, repeats=self.num_heads // self.num_heads_kv
203
+ )
204
+ v = torch.repeat_interleave(
205
+ v, dim=2, repeats=self.num_heads // self.num_heads_kv
206
+ )
207
+ return F.scaled_dot_product_attention(
208
+ q.transpose(1, 2),
209
+ k.transpose(1, 2),
210
+ v.transpose(1, 2),
211
+ is_causal=self.causal,
212
+ scale=self.softmax_scale,
213
+ ).transpose(1, 2)
214
+ else:
215
+ batch = q.shape[0]
216
+ kv_cache, _ = inference_params.key_value_memory_dict[self.layer_idx]
217
+ kv_cache = kv_cache[:batch]
218
+ cache_seqlens = (
219
+ inference_params.lengths_per_sample[:batch]
220
+ if inference_params.lengths_per_sample is not None
221
+ else inference_params.seqlen_offset
222
+ )
223
+ return flash_attn_with_kvcache(
224
+ q,
225
+ kv_cache[:, :, 0],
226
+ kv_cache[:, :, 1],
227
+ kv[:, :, 0],
228
+ kv[:, :, 1],
229
+ cache_seqlens=cache_seqlens,
230
+ softmax_scale=self.softmax_scale,
231
+ causal=self.causal,
232
+ )
233
+
234
+ def forward(self, x, inference_params=None):
235
+ """
236
+ Arguments:
237
+ x: (batch, seqlen, hidden_dim) (where hidden_dim = num heads * head dim) if
238
+ cu_seqlens is None and max_seqlen is None, else (total, hidden_dim) where total
239
+ is the is the sum of the sequence lengths in the batch.
240
+ inference_params: for generation. Adapted from Megatron-LM (and Apex)
241
+ https://github.com/NVIDIA/apex/blob/3ff1a10f72ec07067c4e44759442329804ac5162/apex/transformer/testing/standalone_transformer_lm.py#L470
242
+ """
243
+ if (
244
+ inference_params is not None
245
+ and self.layer_idx not in inference_params.key_value_memory_dict
246
+ ):
247
+ inference_params.key_value_memory_dict[self.layer_idx] = (
248
+ self.allocate_inference_cache(
249
+ x.shape[0], inference_params.max_seqlen, dtype=x.dtype
250
+ )
251
+ )
252
+ seqlen_offset = (
253
+ 0
254
+ if inference_params is None
255
+ else (
256
+ inference_params.lengths_per_sample
257
+ if inference_params.lengths_per_sample is not None
258
+ else inference_params.seqlen_offset
259
+ )
260
+ )
261
+ rotary_max_seqlen = (
262
+ inference_params.max_seqlen if inference_params is not None else None
263
+ )
264
+ qkv = self.in_proj(x)
265
+ if self.mlp_dim > 0:
266
+ qkv, x_mlp = qkv.split([qkv.shape[-1] - self.mlp_dim, self.mlp_dim], dim=-1)
267
+ x_mlp_up, x_mlp_gate = x_mlp.chunk(2, dim=-1)
268
+ x_mlp = x_mlp_up * F.silu(x_mlp_gate)
269
+ if self.d_conv > 0:
270
+ # The inference code for conv1d is pretty messy, should clean it up
271
+ if inference_params is None or inference_params.seqlen_offset == 0:
272
+ qkv = causal_conv1d_fn(
273
+ qkv.transpose(1, 2),
274
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
275
+ self.conv1d.bias,
276
+ ).transpose(1, 2)
277
+ if inference_params is not None:
278
+ _, conv_state = inference_params.key_value_memory_dict[
279
+ self.layer_idx
280
+ ]
281
+ # If we just take qkv[:, :, -self.d_conv :], it will error if seqlen < self.d_conv
282
+ # Instead F.pad will pad with zeros if seqlen < self.d_conv, and truncate otherwise.
283
+ qkv_t = rearrange(qkv, "b l d -> b d l")
284
+ conv_state.copy_(
285
+ F.pad(qkv_t, (self.d_conv - qkv_t.shape[-1], 0))
286
+ ) # Update state (B D W)
287
+ else:
288
+ _, conv_state = inference_params.key_value_memory_dict[self.layer_idx]
289
+ assert qkv.shape[1] == 1, (
290
+ "Only support decoding with 1 token at a time for now"
291
+ )
292
+ qkv = qkv.squeeze(1)
293
+ # Conv step
294
+ qkv = causal_conv1d_update(
295
+ qkv,
296
+ conv_state,
297
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
298
+ self.conv1d.bias,
299
+ )
300
+ qkv = qkv.unsqueeze(1)
301
+ q, kv = qkv.split(
302
+ [self.num_heads * self.head_dim, self.num_heads_kv * 2 * self.head_dim],
303
+ dim=-1,
304
+ )
305
+ q = rearrange(q, "... (h d) -> ... h d", d=self.head_dim)
306
+ kv = rearrange(kv, "... (two hkv d) -> ... two hkv d", two=2, d=self.head_dim)
307
+ if (
308
+ inference_params is None
309
+ or inference_params.seqlen_offset == 0
310
+ or (self.rotary_emb_dim == 0 or self.rotary_emb_dim % 16 != 0)
311
+ ):
312
+ if self.rotary_emb_dim > 0:
313
+ q, kv = self.rotary_emb(
314
+ q, kv, seqlen_offset=seqlen_offset, max_seqlen=rotary_max_seqlen
315
+ )
316
+ if inference_params is None:
317
+ k, v = kv.unbind(dim=-3)
318
+ k = torch.repeat_interleave(
319
+ k, dim=2, repeats=self.num_heads // self.num_heads_kv
320
+ )
321
+ v = torch.repeat_interleave(
322
+ v, dim=2, repeats=self.num_heads // self.num_heads_kv
323
+ )
324
+ context = F.scaled_dot_product_attention(
325
+ q.transpose(1, 2),
326
+ k.transpose(1, 2),
327
+ v.transpose(1, 2),
328
+ is_causal=self.causal,
329
+ scale=self.softmax_scale,
330
+ ).transpose(1, 2)
331
+ else:
332
+ context = self._update_kvcache_attention(q, kv, inference_params)
333
+ else:
334
+ context = self._apply_rotary_update_kvcache_attention(
335
+ q, kv, inference_params
336
+ )
337
+ context = rearrange(context, "... h d -> ... (h d)")
338
+ if self.mlp_dim > 0:
339
+ context = torch.cat([context, x_mlp], dim=-1)
340
+ out = self.out_proj(context)
341
+ return out
build/torch213-cxx11-xpu20260-x86_64-linux/modules/mlp.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+
5
+
6
+ class GatedMLP(nn.Module):
7
+ def __init__(
8
+ self,
9
+ in_features,
10
+ hidden_features=None,
11
+ out_features=None,
12
+ activation=F.silu,
13
+ bias=False,
14
+ multiple_of=128,
15
+ device=None,
16
+ dtype=None,
17
+ ):
18
+ factory_kwargs = {"device": device, "dtype": dtype}
19
+ super().__init__()
20
+ out_features = out_features if out_features is not None else in_features
21
+ hidden_features = (
22
+ hidden_features if hidden_features is not None else int(8 * in_features / 3)
23
+ )
24
+ hidden_features = (hidden_features + multiple_of - 1) // multiple_of * multiple_of
25
+ self.fc1 = nn.Linear(in_features, 2 * hidden_features, bias=bias, **factory_kwargs)
26
+ self.activation = activation
27
+ self.fc2 = nn.Linear(hidden_features, out_features, bias=bias, **factory_kwargs)
28
+
29
+ def forward(self, x):
30
+ y = self.fc1(x)
31
+ y, gate = y.chunk(2, dim=-1)
32
+ y = y * self.activation(gate)
33
+ y = self.fc2(y)
34
+ return y
build/torch213-cxx11-xpu20260-x86_64-linux/modules/ssd_minimal.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Albert Gu and Tri Dao.
2
+ """Minimal implementation of SSD.
3
+
4
+ This is the same as Listing 1 from the paper.
5
+ """
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from einops import rearrange, repeat
10
+
11
+ from ..ops.triton.ssd_combined import mamba_chunk_scan_combined
12
+
13
+
14
+ def segsum_unstable(x):
15
+ """Naive segment sum calculation."""
16
+ T = x.size(-1)
17
+ x_cumsum = torch.cumsum(x, dim=-1)
18
+ x_segsum = x_cumsum[..., :, None] - x_cumsum[..., None, :]
19
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=0)
20
+ x_segsum = x_segsum.masked_fill(~mask, -torch.inf)
21
+ return x_segsum
22
+
23
+
24
+ def segsum(x):
25
+ """More stable segment sum calculation."""
26
+ T = x.size(-1)
27
+ x = repeat(x, "... d -> ... d e", e=T)
28
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=-1)
29
+ x = x.masked_fill(~mask, 0)
30
+ x_segsum = torch.cumsum(x, dim=-2)
31
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=0)
32
+ x_segsum = x_segsum.masked_fill(~mask, -torch.inf)
33
+ return x_segsum
34
+
35
+
36
+ def ssd_minimal_discrete(X, A, B, C, block_len, initial_states=None):
37
+ """
38
+ Arguments:
39
+ X: (batch, length, n_heads, d_head)
40
+ A: (batch, length, n_heads)
41
+ B: (batch, length, n_heads, d_state)
42
+ C: (batch, length, n_heads, d_state)
43
+ Return:
44
+ Y: (batch, length, n_heads, d_head)
45
+ """
46
+ assert X.dtype == A.dtype == B.dtype == C.dtype
47
+ assert X.shape[1] % block_len == 0
48
+
49
+ # Rearrange into blocks/chunks
50
+ X, A, B, C = [
51
+ rearrange(x, "b (c l) ... -> b c l ...", l=block_len) for x in (X, A, B, C)
52
+ ]
53
+
54
+ A = rearrange(A, "b c l h -> b h c l")
55
+ A_cumsum = torch.cumsum(A, dim=-1)
56
+
57
+ # 1. Compute the output for each intra-chunk (diagonal blocks)
58
+ L = torch.exp(segsum(A))
59
+ Y_diag = torch.einsum("bclhn,bcshn,bhcls,bcshp->bclhp", C, B, L, X)
60
+
61
+ # 2. Compute the state for each intra-chunk
62
+ # (right term of low-rank factorization of off-diagonal blocks; B terms)
63
+ decay_states = torch.exp((A_cumsum[:, :, :, -1:] - A_cumsum))
64
+ states = torch.einsum("bclhn,bhcl,bclhp->bchpn", B, decay_states, X)
65
+
66
+ # 3. Compute the inter-chunk SSM recurrence; produces correct SSM states at chunk boundaries
67
+ # (middle term of factorization of off-diag blocks; A terms)
68
+ if initial_states is None:
69
+ initial_states = torch.zeros_like(states[:, :1])
70
+ states = torch.cat([initial_states, states], dim=1)
71
+ decay_chunk = torch.exp(segsum(F.pad(A_cumsum[:, :, :, -1], (1, 0))))
72
+ new_states = torch.einsum("bhzc,bchpn->bzhpn", decay_chunk, states)
73
+ states, final_state = new_states[:, :-1], new_states[:, -1]
74
+
75
+ # 4. Compute state -> output conversion per chunk
76
+ # (left term of low-rank factorization of off-diagonal blocks; C terms)
77
+ state_decay_out = torch.exp(A_cumsum)
78
+ Y_off = torch.einsum("bclhn,bchpn,bhcl->bclhp", C, states, state_decay_out)
79
+
80
+ # Add output of intra-chunk and inter-chunk terms (diagonal and off-diagonal blocks)
81
+ Y = rearrange(Y_diag + Y_off, "b c l h p -> b (c l) h p")
82
+ return Y, final_state
83
+
84
+
85
+ # Simple test
86
+ def test_correctness():
87
+ torch.manual_seed(42)
88
+
89
+ ## Dimensions
90
+ # Denoted (B, T, Q, D, P) in the paper
91
+ batch, seqlen, chunk_size, dim, headdim = 1, 2048, 64, 2048, 64
92
+ nheads = dim // headdim # (H) in the paper
93
+ ngroups = 1 # (G) in the paper
94
+ dstate = 64 # (N) in the paper
95
+ dtype = torch.float32
96
+ device = "cuda"
97
+
98
+ x = torch.randn(batch, seqlen, nheads, headdim, dtype=dtype, device=device)
99
+ dt = F.softplus(
100
+ torch.randn(batch, seqlen, nheads, dtype=torch.float32, device=device) - 4
101
+ ).requires_grad_()
102
+ A = (
103
+ -torch.exp(torch.rand(nheads, dtype=torch.float32, device=device))
104
+ ).requires_grad_()
105
+ B = torch.randn(batch, seqlen, ngroups, dstate, dtype=dtype, device=device)
106
+ C = torch.randn(batch, seqlen, ngroups, dstate, dtype=dtype, device=device)
107
+ D = torch.randn(nheads, dtype=dtype, device=device)
108
+
109
+ # Comparing fused version and minimal version
110
+ y = mamba_chunk_scan_combined(x, dt, A, B, C, chunk_size, D=None)
111
+ y_min, _ = ssd_minimal_discrete(x * dt.unsqueeze(-1), A * dt, B, C, chunk_size)
build/torch213-cxx11-xpu20260-x86_64-linux/ops/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .triton import selective_state_update, mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
build/torch213-cxx11-xpu20260-x86_64-linux/ops/selective_scan_interface.py ADDED
@@ -0,0 +1,708 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Tri Dao, Albert Gu.
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+ from einops import rearrange, repeat
6
+
7
+ from .._causal_conv1d import causal_conv1d_cuda, causal_conv1d_fn
8
+ from .._ops import add_op_namespace_prefix, ops
9
+ from ..utils.torch import custom_bwd, custom_fwd
10
+ from .triton.layer_norm import _layer_norm_fwd
11
+
12
+
13
+ # The CUDA scan processes the sequence in chunks of this size and saves one state per chunk, see
14
+ # `n_chunks` in `selective-scan/selective_scan.cpp`.
15
+ _SELECTIVE_SCAN_CHUNK_SIZE = 2048
16
+
17
+
18
+ def _selective_scan_fwd_fake(u, delta, A, B, C, D, z, delta_bias, delta_softplus):
19
+ batch, dim, seqlen = u.shape
20
+ n_chunks = (seqlen + _SELECTIVE_SCAN_CHUNK_SIZE - 1) // _SELECTIVE_SCAN_CHUNK_SIZE
21
+ x = u.new_empty((batch, dim, n_chunks, A.shape[1] * 2), dtype=A.dtype)
22
+ return [torch.empty_like(delta), x] + ([torch.empty_like(z)] if z is not None else [])
23
+
24
+
25
+ # XPU builds provide causal convolution, but do not define the native scan ops.
26
+ if hasattr(ops, "selective_scan_fwd"):
27
+ torch.library.register_fake(add_op_namespace_prefix("selective_scan_fwd"))(_selective_scan_fwd_fake)
28
+
29
+
30
+ # `selective_scan_bwd` returns undefined tensors for absent optionals as well as its `dz_`
31
+ # argument, so it cannot be given a fake implementation directly. This wrapper gives it a
32
+ # fixed signature that torch.compile can trace. Absent outputs are returned as empty tensors.
33
+ @torch.library.custom_op(add_op_namespace_prefix("_selective_scan_bwd"), mutates_args=("dz",), device_types="cuda")
34
+ def _selective_scan_bwd(
35
+ u: torch.Tensor,
36
+ delta: torch.Tensor,
37
+ A: torch.Tensor,
38
+ B: torch.Tensor,
39
+ C: torch.Tensor,
40
+ D: torch.Tensor | None,
41
+ z: torch.Tensor | None,
42
+ delta_bias: torch.Tensor | None,
43
+ dout: torch.Tensor,
44
+ x: torch.Tensor | None,
45
+ out: torch.Tensor | None,
46
+ dz: torch.Tensor | None,
47
+ delta_softplus: bool,
48
+ recompute_out_z: bool,
49
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
50
+ du, ddelta, dA, dB, dC, dD, ddelta_bias, *rest = ops.selective_scan_bwd(
51
+ u, delta, A, B, C, D, z, delta_bias, dout, x, out, dz, delta_softplus, recompute_out_z
52
+ )
53
+ empty = lambda: du.new_empty(0) # one per output, outputs may not alias each other
54
+ # A passed-in `dz` is written in place, so only return the one the kernel allocated.
55
+ dz_out = rest[0] if z is not None and dz is None else empty()
56
+ out_z = rest[-1] if z is not None and recompute_out_z else empty()
57
+ dD = dD if D is not None else empty()
58
+ ddelta_bias = ddelta_bias if delta_bias is not None else empty()
59
+ return du, ddelta, dA, dB, dC, dD, ddelta_bias, dz_out, out_z
60
+
61
+
62
+ @torch.library.register_fake(add_op_namespace_prefix("_selective_scan_bwd"))
63
+ def _selective_scan_bwd_fake(u, delta, A, B, C, D, z, delta_bias, dout, x, out, dz, delta_softplus, recompute_out_z):
64
+ like = lambda t, keep=True: torch.empty_like(t) if keep and t is not None else u.new_empty(0)
65
+ return (
66
+ *(like(t) for t in (u, delta, A, B, C, D, delta_bias)),
67
+ like(z, dz is None),
68
+ like(out, z is not None and recompute_out_z),
69
+ )
70
+
71
+
72
+ class SelectiveScanFn(torch.autograd.Function):
73
+ @staticmethod
74
+ def forward(
75
+ ctx,
76
+ u,
77
+ delta,
78
+ A,
79
+ B,
80
+ C,
81
+ D=None,
82
+ z=None,
83
+ delta_bias=None,
84
+ delta_softplus=False,
85
+ return_last_state=False,
86
+ ):
87
+ if u.stride(-1) != 1:
88
+ u = u.contiguous()
89
+ if delta.stride(-1) != 1:
90
+ delta = delta.contiguous()
91
+ if D is not None:
92
+ D = D.contiguous()
93
+ if B.stride(-1) != 1:
94
+ B = B.contiguous()
95
+ if C.stride(-1) != 1:
96
+ C = C.contiguous()
97
+ if z is not None and z.stride(-1) != 1:
98
+ z = z.contiguous()
99
+ if B.dim() == 3:
100
+ B = rearrange(B, "b dstate l -> b 1 dstate l")
101
+ ctx.squeeze_B = True
102
+ if C.dim() == 3:
103
+ C = rearrange(C, "b dstate l -> b 1 dstate l")
104
+ ctx.squeeze_C = True
105
+ out, x, *rest = ops.selective_scan_fwd(
106
+ u, delta, A, B, C, D, z, delta_bias, delta_softplus
107
+ )
108
+ ctx.delta_softplus = delta_softplus
109
+ ctx.has_z = z is not None
110
+ last_state = x[:, :, -1, 1::2] # (batch, dim, dstate)
111
+ if not ctx.has_z:
112
+ ctx.save_for_backward(u, delta, A, B, C, D, delta_bias, x)
113
+ return out if not return_last_state else (out, last_state)
114
+ else:
115
+ ctx.save_for_backward(u, delta, A, B, C, D, z, delta_bias, x, out)
116
+ out_z = rest[0]
117
+ return out_z if not return_last_state else (out_z, last_state)
118
+
119
+ @staticmethod
120
+ def backward(ctx, dout, *args):
121
+ if not ctx.has_z:
122
+ u, delta, A, B, C, D, delta_bias, x = ctx.saved_tensors
123
+ z = None
124
+ out = None
125
+ else:
126
+ u, delta, A, B, C, D, z, delta_bias, x, out = ctx.saved_tensors
127
+ if dout.stride(-1) != 1:
128
+ dout = dout.contiguous()
129
+ # The kernel supports passing in a pre-allocated dz (e.g., in case we want to fuse the
130
+ # backward of selective_scan_cuda with the backward of chunk).
131
+ # Here we just pass in None and dz will be allocated in the C++ code.
132
+ du, ddelta, dA, dB, dC, dD, ddelta_bias, *rest = _selective_scan_bwd(
133
+ u,
134
+ delta,
135
+ A,
136
+ B,
137
+ C,
138
+ D,
139
+ z,
140
+ delta_bias,
141
+ dout,
142
+ x,
143
+ out,
144
+ None,
145
+ ctx.delta_softplus,
146
+ False, # option to recompute out_z, not used here
147
+ )
148
+ dz = rest[0] if ctx.has_z else None
149
+ dB = dB.squeeze(1) if getattr(ctx, "squeeze_B", False) else dB
150
+ dC = dC.squeeze(1) if getattr(ctx, "squeeze_C", False) else dC
151
+ return (
152
+ du,
153
+ ddelta,
154
+ dA,
155
+ dB,
156
+ dC,
157
+ dD if D is not None else None,
158
+ dz,
159
+ ddelta_bias if delta_bias is not None else None,
160
+ None,
161
+ None,
162
+ )
163
+
164
+
165
+ def rms_norm_forward(
166
+ x,
167
+ weight,
168
+ bias,
169
+ eps=1e-6,
170
+ is_rms_norm=True,
171
+ ):
172
+ # x (b l) d
173
+ if x.stride(-1) != 1:
174
+ x = x.contiguous()
175
+ weight = weight.contiguous()
176
+ if bias is not None:
177
+ bias = bias.contiguous()
178
+ y = _layer_norm_fwd(
179
+ x, weight, bias, eps, None, residual_dtype=None, is_rms_norm=is_rms_norm
180
+ )[0]
181
+ # y (b l) d
182
+ return y
183
+
184
+
185
+ def selective_scan_fn(
186
+ u,
187
+ delta,
188
+ A,
189
+ B,
190
+ C,
191
+ D=None,
192
+ z=None,
193
+ delta_bias=None,
194
+ delta_softplus=False,
195
+ return_last_state=False,
196
+ ):
197
+ """if return_last_state is True, returns (out, last_state)
198
+ last_state has shape (batch, dim, dstate). Note that the gradient of the last state is
199
+ not considered in the backward pass.
200
+ """
201
+ return SelectiveScanFn.apply(
202
+ u, delta, A, B, C, D, z, delta_bias, delta_softplus, return_last_state
203
+ )
204
+
205
+
206
+ def selective_scan_ref(
207
+ u,
208
+ delta,
209
+ A,
210
+ B,
211
+ C,
212
+ D=None,
213
+ z=None,
214
+ delta_bias=None,
215
+ delta_softplus=False,
216
+ return_last_state=False,
217
+ ):
218
+ """
219
+ u: r(B D L)
220
+ delta: r(B D L)
221
+ A: c(D N) or r(D N)
222
+ B: c(D N) or r(B N L) or r(B N 2L) or r(B G N L) or (B G N L)
223
+ C: c(D N) or r(B N L) or r(B N 2L) or r(B G N L) or (B G N L)
224
+ D: r(D)
225
+ z: r(B D L)
226
+ delta_bias: r(D), fp32
227
+
228
+ out: r(B D L)
229
+ last_state (optional): r(B D dstate) or c(B D dstate)
230
+ """
231
+ dtype_in = u.dtype
232
+ u = u.float()
233
+ delta = delta.float()
234
+ if delta_bias is not None:
235
+ delta = delta + delta_bias[..., None].float()
236
+ if delta_softplus:
237
+ delta = F.softplus(delta)
238
+ batch, dim, dstate = u.shape[0], A.shape[0], A.shape[1]
239
+ is_variable_B = B.dim() >= 3
240
+ is_variable_C = C.dim() >= 3
241
+ if A.is_complex():
242
+ if is_variable_B:
243
+ B = torch.view_as_complex(
244
+ rearrange(B.float(), "... (L two) -> ... L two", two=2)
245
+ )
246
+ if is_variable_C:
247
+ C = torch.view_as_complex(
248
+ rearrange(C.float(), "... (L two) -> ... L two", two=2)
249
+ )
250
+ else:
251
+ B = B.float()
252
+ C = C.float()
253
+ x = A.new_zeros((batch, dim, dstate))
254
+ ys = []
255
+ deltaA = torch.exp(torch.einsum("bdl,dn->bdln", delta, A))
256
+ if not is_variable_B:
257
+ deltaB_u = torch.einsum("bdl,dn,bdl->bdln", delta, B, u)
258
+ else:
259
+ if B.dim() == 3:
260
+ deltaB_u = torch.einsum("bdl,bnl,bdl->bdln", delta, B, u)
261
+ else:
262
+ B = repeat(B, "B G N L -> B (G H) N L", H=dim // B.shape[1])
263
+ deltaB_u = torch.einsum("bdl,bdnl,bdl->bdln", delta, B, u)
264
+ if is_variable_C and C.dim() == 4:
265
+ C = repeat(C, "B G N L -> B (G H) N L", H=dim // C.shape[1])
266
+ last_state = None
267
+ for i in range(u.shape[2]):
268
+ x = deltaA[:, :, i] * x + deltaB_u[:, :, i]
269
+ if not is_variable_C:
270
+ y = torch.einsum("bdn,dn->bd", x, C)
271
+ else:
272
+ if C.dim() == 3:
273
+ y = torch.einsum("bdn,bn->bd", x, C[:, :, i])
274
+ else:
275
+ y = torch.einsum("bdn,bdn->bd", x, C[:, :, :, i])
276
+ if i == u.shape[2] - 1:
277
+ last_state = x
278
+ if y.is_complex():
279
+ y = y.real * 2
280
+ ys.append(y)
281
+ y = torch.stack(ys, dim=2) # (batch dim L)
282
+ out = y if D is None else y + u * rearrange(D, "d -> d 1")
283
+ if z is not None:
284
+ out = out * F.silu(z)
285
+ out = out.to(dtype=dtype_in)
286
+ return out if not return_last_state else (out, last_state)
287
+
288
+
289
+ class MambaInnerFn(torch.autograd.Function):
290
+ @staticmethod
291
+ @custom_fwd
292
+ def forward(
293
+ ctx,
294
+ xz,
295
+ conv1d_weight,
296
+ conv1d_bias,
297
+ x_proj_weight,
298
+ delta_proj_weight,
299
+ out_proj_weight,
300
+ out_proj_bias,
301
+ A,
302
+ B=None,
303
+ C=None,
304
+ D=None,
305
+ delta_bias=None,
306
+ B_proj_bias=None,
307
+ C_proj_bias=None,
308
+ delta_softplus=True,
309
+ checkpoint_lvl=1,
310
+ b_rms_weight=None,
311
+ c_rms_weight=None,
312
+ dt_rms_weight=None,
313
+ b_c_dt_rms_eps=1e-6,
314
+ ):
315
+ """
316
+ xz: (batch, dim, seqlen)
317
+ """
318
+ assert checkpoint_lvl in [0, 1]
319
+ L = xz.shape[-1]
320
+ delta_rank = delta_proj_weight.shape[1]
321
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
322
+ device_type = x_proj_weight.device.type
323
+ if torch.is_autocast_enabled(device_type):
324
+ dtype = torch.get_autocast_dtype(device_type)
325
+ x_proj_weight = x_proj_weight.to(dtype=dtype)
326
+ delta_proj_weight = delta_proj_weight.to(dtype=dtype)
327
+ out_proj_weight = out_proj_weight.to(dtype=dtype)
328
+ out_proj_bias = (
329
+ out_proj_bias.to(dtype=dtype)
330
+ if out_proj_bias is not None
331
+ else None
332
+ )
333
+ if xz.stride(-1) != 1:
334
+ xz = xz.contiguous()
335
+ conv1d_weight = rearrange(conv1d_weight, "d 1 w -> d w")
336
+ x, z = xz.chunk(2, dim=1)
337
+ conv1d_bias = conv1d_bias.contiguous() if conv1d_bias is not None else None
338
+ conv1d_out = causal_conv1d_cuda.causal_conv1d_fwd(
339
+ x, conv1d_weight, conv1d_bias, None, None, None, True
340
+ )
341
+ # We're being very careful here about the layout, to avoid extra transposes.
342
+ # We want delta to have d as the slowest moving dimension
343
+ # and L as the fastest moving dimension, since those are what the ssm_scan kernel expects.
344
+ x_dbl = F.linear(
345
+ rearrange(conv1d_out, "b d l -> (b l) d"), x_proj_weight
346
+ ) # (bl d)
347
+ delta = rearrange(
348
+ delta_proj_weight @ x_dbl[:, :delta_rank].t(), "d (b l) -> b d l", l=L
349
+ )
350
+ ctx.is_variable_B = B is None
351
+ ctx.is_variable_C = C is None
352
+ ctx.B_proj_bias_is_None = B_proj_bias is None
353
+ ctx.C_proj_bias_is_None = C_proj_bias is None
354
+ if B is None: # variable B
355
+ B = x_dbl[:, delta_rank : delta_rank + d_state] # (bl dstate)
356
+ if B_proj_bias is not None:
357
+ B = B + B_proj_bias.to(dtype=B.dtype)
358
+ if not A.is_complex():
359
+ # B = rearrange(B, "(b l) dstate -> b dstate l", l=L).contiguous()
360
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
361
+ else:
362
+ B = rearrange(
363
+ B, "(b l) (dstate two) -> b 1 dstate (l two)", l=L, two=2
364
+ ).contiguous()
365
+ else:
366
+ if B.stride(-1) != 1:
367
+ B = B.contiguous()
368
+ if C is None: # variable C
369
+ C = x_dbl[:, -d_state:] # (bl dstate)
370
+ if C_proj_bias is not None:
371
+ C = C + C_proj_bias.to(dtype=C.dtype)
372
+ if not A.is_complex():
373
+ # C = rearrange(C, "(b l) dstate -> b dstate l", l=L).contiguous()
374
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
375
+ else:
376
+ C = rearrange(
377
+ C, "(b l) (dstate two) -> b 1 dstate (l two)", l=L, two=2
378
+ ).contiguous()
379
+ else:
380
+ if C.stride(-1) != 1:
381
+ C = C.contiguous()
382
+ if D is not None:
383
+ D = D.contiguous()
384
+
385
+ if b_rms_weight is not None:
386
+ B = rearrange(B, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
387
+ B = rms_norm_forward(B, b_rms_weight, bias=None, eps=b_c_dt_rms_eps)
388
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
389
+ if c_rms_weight is not None:
390
+ C = rearrange(C, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
391
+ C = rms_norm_forward(C, c_rms_weight, bias=None, eps=b_c_dt_rms_eps)
392
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
393
+ if dt_rms_weight is not None:
394
+ delta = rearrange(delta, "b d l -> (b l) d", l=L).contiguous()
395
+ delta = rms_norm_forward(
396
+ delta, dt_rms_weight, bias=None, eps=b_c_dt_rms_eps
397
+ )
398
+ delta = rearrange(delta, "(b l) d -> b d l", l=L).contiguous()
399
+
400
+ out, scan_intermediates, out_z = ops.selective_scan_fwd(
401
+ conv1d_out, delta, A, B, C, D, z, delta_bias, delta_softplus
402
+ )
403
+ ctx.delta_softplus = delta_softplus
404
+ ctx.out_proj_bias_is_None = out_proj_bias is None
405
+ ctx.checkpoint_lvl = checkpoint_lvl
406
+ ctx.b_rms_weight = b_rms_weight
407
+ ctx.c_rms_weight = c_rms_weight
408
+ ctx.dt_rms_weight = dt_rms_weight
409
+ ctx.b_c_dt_rms_eps = b_c_dt_rms_eps
410
+ if (
411
+ checkpoint_lvl >= 1
412
+ ): # Will recompute conv1d_out and delta in the backward pass
413
+ conv1d_out, delta = None, None
414
+ ctx.save_for_backward(
415
+ xz,
416
+ conv1d_weight,
417
+ conv1d_bias,
418
+ x_dbl,
419
+ x_proj_weight,
420
+ delta_proj_weight,
421
+ out_proj_weight,
422
+ conv1d_out,
423
+ delta,
424
+ A,
425
+ B,
426
+ C,
427
+ D,
428
+ delta_bias,
429
+ scan_intermediates,
430
+ b_rms_weight,
431
+ c_rms_weight,
432
+ dt_rms_weight,
433
+ out,
434
+ )
435
+ return F.linear(
436
+ rearrange(out_z, "b d l -> b l d"), out_proj_weight, out_proj_bias
437
+ )
438
+
439
+ @staticmethod
440
+ @custom_bwd
441
+ def backward(ctx, dout):
442
+ # dout: (batch, seqlen, dim)
443
+ (
444
+ xz,
445
+ conv1d_weight,
446
+ conv1d_bias,
447
+ x_dbl,
448
+ x_proj_weight,
449
+ delta_proj_weight,
450
+ out_proj_weight,
451
+ conv1d_out,
452
+ delta,
453
+ A,
454
+ B,
455
+ C,
456
+ D,
457
+ delta_bias,
458
+ scan_intermediates,
459
+ b_rms_weight,
460
+ c_rms_weight,
461
+ dt_rms_weight,
462
+ out,
463
+ ) = ctx.saved_tensors
464
+ L = xz.shape[-1]
465
+ delta_rank = delta_proj_weight.shape[1]
466
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
467
+ x, z = xz.chunk(2, dim=1)
468
+ if dout.stride(-1) != 1:
469
+ dout = dout.contiguous()
470
+ if ctx.checkpoint_lvl == 1:
471
+ conv1d_out = causal_conv1d_cuda.causal_conv1d_fwd(
472
+ x, conv1d_weight, conv1d_bias, None, None, None, True
473
+ )
474
+ delta = rearrange(
475
+ delta_proj_weight @ x_dbl[:, :delta_rank].t(), "d (b l) -> b d l", l=L
476
+ )
477
+ if dt_rms_weight is not None:
478
+ delta = rearrange(delta, "b d l -> (b l) d", l=L).contiguous()
479
+ delta = rms_norm_forward(
480
+ delta, ctx.dt_rms_weight, None, ctx.b_c_dt_rms_eps
481
+ )
482
+ delta = rearrange(delta, "(b l) d -> b d l", l=L).contiguous()
483
+ if b_rms_weight is not None:
484
+ # Recompute & RMSNorm B
485
+ B = rearrange(B, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
486
+ B = rms_norm_forward(B, ctx.b_rms_weight, None, ctx.b_c_dt_rms_eps)
487
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
488
+ if c_rms_weight is not None:
489
+ # Recompute & RMSNorm C
490
+ C = rearrange(C, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
491
+ C = rms_norm_forward(C, ctx.c_rms_weight, None, ctx.b_c_dt_rms_eps)
492
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
493
+
494
+ # The kernel supports passing in a pre-allocated dz (e.g., in case we want to fuse the
495
+ # backward of selective_scan_cuda with the backward of chunk).
496
+ dxz = torch.empty_like(xz) # (batch, dim, seqlen)
497
+ dx, dz = dxz.chunk(2, dim=1)
498
+ dout = rearrange(dout, "b l e -> e (b l)")
499
+ # dout is (e, (b l)): sum over tokens only, see state-spaces/mamba#37
500
+ dout_proj_bias = dout.sum(dim=1) if not ctx.out_proj_bias_is_None else None
501
+ # Transformers can pass an FP32 output bias with BF16 projection weights.
502
+ dout = dout.to(dtype=out_proj_weight.dtype)
503
+ dout_y = rearrange(out_proj_weight.t() @ dout, "d (b l) -> b d l", l=L)
504
+ dconv1d_out, ddelta, dA, dB, dC, dD, ddelta_bias, _, out_z = (
505
+ _selective_scan_bwd(
506
+ conv1d_out,
507
+ delta,
508
+ A,
509
+ B,
510
+ C,
511
+ D,
512
+ z,
513
+ delta_bias,
514
+ dout_y,
515
+ scan_intermediates,
516
+ out,
517
+ dz,
518
+ ctx.delta_softplus,
519
+ True, # option to recompute out_z
520
+ )
521
+ )
522
+ dout_proj_weight = torch.einsum(
523
+ "eB,dB->ed", dout, rearrange(out_z, "b d l -> d (b l)")
524
+ )
525
+ dD = dD if D is not None else None
526
+ dx_dbl = torch.empty_like(x_dbl)
527
+ dB_proj_bias = None
528
+ if ctx.is_variable_B:
529
+ if not A.is_complex():
530
+ dB = rearrange(dB, "b 1 dstate l -> (b l) dstate").contiguous()
531
+ else:
532
+ dB = rearrange(
533
+ dB, "b 1 dstate (l two) -> (b l) (dstate two)", two=2
534
+ ).contiguous()
535
+ dB_proj_bias = dB.sum(0) if not ctx.B_proj_bias_is_None else None
536
+ dx_dbl[:, delta_rank : delta_rank + d_state] = dB # (bl d)
537
+ dB = None
538
+ dC_proj_bias = None
539
+ if ctx.is_variable_C:
540
+ if not A.is_complex():
541
+ dC = rearrange(dC, "b 1 dstate l -> (b l) dstate").contiguous()
542
+ else:
543
+ dC = rearrange(
544
+ dC, "b 1 dstate (l two) -> (b l) (dstate two)", two=2
545
+ ).contiguous()
546
+ dC_proj_bias = dC.sum(0) if not ctx.C_proj_bias_is_None else None
547
+ dx_dbl[:, -d_state:] = dC # (bl d)
548
+ dC = None
549
+ ddelta = rearrange(ddelta, "b d l -> d (b l)")
550
+ ddelta_proj_weight = torch.einsum("dB,Br->dr", ddelta, x_dbl[:, :delta_rank])
551
+ dx_dbl[:, :delta_rank] = torch.einsum("dB,dr->Br", ddelta, delta_proj_weight)
552
+ dconv1d_out = rearrange(dconv1d_out, "b d l -> d (b l)")
553
+ dx_proj_weight = torch.einsum(
554
+ "Br,Bd->rd", dx_dbl, rearrange(conv1d_out, "b d l -> (b l) d")
555
+ )
556
+ dconv1d_out = torch.addmm(
557
+ dconv1d_out, x_proj_weight.t(), dx_dbl.t(), out=dconv1d_out
558
+ )
559
+ dconv1d_out = rearrange(
560
+ dconv1d_out, "d (b l) -> b d l", b=x.shape[0], l=x.shape[-1]
561
+ )
562
+ # The kernel supports passing in a pre-allocated dx (e.g., in case we want to fuse the
563
+ # backward of conv1d with the backward of chunk).
564
+ dx, dconv1d_weight, dconv1d_bias, *_ = causal_conv1d_cuda.causal_conv1d_bwd(
565
+ x,
566
+ conv1d_weight,
567
+ conv1d_bias,
568
+ dconv1d_out,
569
+ None,
570
+ None,
571
+ None,
572
+ dx,
573
+ False,
574
+ True,
575
+ )
576
+ dconv1d_bias = dconv1d_bias if conv1d_bias is not None else None
577
+ dconv1d_weight = rearrange(dconv1d_weight, "d w -> d 1 w")
578
+ return (
579
+ dxz,
580
+ dconv1d_weight,
581
+ dconv1d_bias,
582
+ dx_proj_weight,
583
+ ddelta_proj_weight,
584
+ dout_proj_weight,
585
+ dout_proj_bias,
586
+ dA,
587
+ dB,
588
+ dC,
589
+ dD,
590
+ ddelta_bias if delta_bias is not None else None,
591
+ # 6-None are delta_softplus, checkpoint_lvl, b_rms_weight, c_rms_weight, dt_rms_weight, b_c_dt_rms_eps
592
+ dB_proj_bias,
593
+ dC_proj_bias,
594
+ None,
595
+ None,
596
+ None,
597
+ None,
598
+ None,
599
+ None,
600
+ )
601
+
602
+
603
+ # Dynamo cannot trace MambaInnerFn.forward when its inputs are module parameters: it saves
604
+ # no-op views of them (e.g. `D.contiguous()`, the rearranged conv weight) for backward, which
605
+ # Dynamo rejects as intermediates aliasing an input. Keep it opaque to Dynamo instead.
606
+ torch.compiler.allow_in_graph(MambaInnerFn)
607
+
608
+
609
+ def mamba_inner_fn(
610
+ xz,
611
+ conv1d_weight,
612
+ conv1d_bias,
613
+ x_proj_weight,
614
+ delta_proj_weight,
615
+ out_proj_weight,
616
+ out_proj_bias,
617
+ A,
618
+ B=None,
619
+ C=None,
620
+ D=None,
621
+ delta_bias=None,
622
+ B_proj_bias=None,
623
+ C_proj_bias=None,
624
+ delta_softplus=True,
625
+ checkpoint_lvl=1,
626
+ b_rms_weight=None,
627
+ c_rms_weight=None,
628
+ dt_rms_weight=None,
629
+ b_c_dt_rms_eps=1e-6,
630
+ ):
631
+ return MambaInnerFn.apply(
632
+ xz,
633
+ conv1d_weight,
634
+ conv1d_bias,
635
+ x_proj_weight,
636
+ delta_proj_weight,
637
+ out_proj_weight,
638
+ out_proj_bias,
639
+ A,
640
+ B,
641
+ C,
642
+ D,
643
+ delta_bias,
644
+ B_proj_bias,
645
+ C_proj_bias,
646
+ delta_softplus,
647
+ checkpoint_lvl,
648
+ b_rms_weight,
649
+ c_rms_weight,
650
+ dt_rms_weight,
651
+ b_c_dt_rms_eps,
652
+ )
653
+
654
+
655
+ def mamba_inner_ref(
656
+ xz,
657
+ conv1d_weight,
658
+ conv1d_bias,
659
+ x_proj_weight,
660
+ delta_proj_weight,
661
+ out_proj_weight,
662
+ out_proj_bias,
663
+ A,
664
+ B=None,
665
+ C=None,
666
+ D=None,
667
+ delta_bias=None,
668
+ B_proj_bias=None,
669
+ C_proj_bias=None,
670
+ delta_softplus=True,
671
+ ):
672
+ L = xz.shape[-1]
673
+ delta_rank = delta_proj_weight.shape[1]
674
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
675
+ x, z = xz.chunk(2, dim=1)
676
+ x = causal_conv1d_fn(
677
+ x, rearrange(conv1d_weight, "d 1 w -> d w"), conv1d_bias, activation="silu"
678
+ )
679
+ # We're being very careful here about the layout, to avoid extra transposes.
680
+ # We want delta to have d as the slowest moving dimension
681
+ # and L as the fastest moving dimension, since those are what the ssm_scan kernel expects.
682
+ x_dbl = F.linear(rearrange(x, "b d l -> (b l) d"), x_proj_weight) # (bl d)
683
+ delta = delta_proj_weight @ x_dbl[:, :delta_rank].t()
684
+ delta = rearrange(delta, "d (b l) -> b d l", l=L)
685
+ if B is None: # variable B
686
+ B = x_dbl[:, delta_rank : delta_rank + d_state] # (bl d)
687
+ if B_proj_bias is not None:
688
+ B = B + B_proj_bias.to(dtype=B.dtype)
689
+ if not A.is_complex():
690
+ B = rearrange(B, "(b l) dstate -> b dstate l", l=L).contiguous()
691
+ else:
692
+ B = rearrange(
693
+ B, "(b l) (dstate two) -> b dstate (l two)", l=L, two=2
694
+ ).contiguous()
695
+ if C is None: # variable B
696
+ C = x_dbl[:, -d_state:] # (bl d)
697
+ if C_proj_bias is not None:
698
+ C = C + C_proj_bias.to(dtype=C.dtype)
699
+ if not A.is_complex():
700
+ C = rearrange(C, "(b l) dstate -> b dstate l", l=L).contiguous()
701
+ else:
702
+ C = rearrange(
703
+ C, "(b l) (dstate two) -> b dstate (l two)", l=L, two=2
704
+ ).contiguous()
705
+ y = selective_scan_fn(
706
+ x, delta, A, B, C, D, z=z, delta_bias=delta_bias, delta_softplus=True
707
+ )
708
+ return F.linear(rearrange(y, "b d l -> b l d"), out_proj_weight, out_proj_bias)
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .selective_state_update import selective_state_update
2
+ from .ssd_combined import mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/k_activations.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import torch
4
+
5
+ import triton
6
+ import triton.language as tl
7
+
8
+ from ...utils.device import device_guard
9
+
10
+
11
+ @triton.autotune(
12
+ configs=[
13
+ triton.Config({'BLOCK_N': 32}),
14
+ triton.Config({'BLOCK_N': 64}),
15
+ triton.Config({'BLOCK_N': 128}),
16
+ triton.Config({'BLOCK_N': 256}),
17
+ triton.Config({'BLOCK_N': 512}),
18
+ triton.Config({'BLOCK_N': 1024}),
19
+ ],
20
+ key=['ncols'],
21
+ )
22
+ @triton.jit
23
+ def _swiglu_fwd_kernel(
24
+ X,
25
+ Y,
26
+ OUT,
27
+ stride_x_row, # how much to increase the pointer when moving by 1 row
28
+ stride_y_row,
29
+ stride_out_row,
30
+ ncols,
31
+ BLOCK_N: tl.constexpr,
32
+ ):
33
+ # Map the program id to the row of X and Y it should compute.
34
+ row = tl.program_id(0)
35
+ start_col = tl.program_id(1) * BLOCK_N
36
+ X += row * stride_x_row
37
+ Y += row * stride_y_row
38
+ OUT += row * stride_out_row
39
+ cols = start_col + tl.arange(0, BLOCK_N)
40
+ x = tl.load(X + cols, mask=cols < ncols, other=0.).to(tl.float32)
41
+ y = tl.load(Y + cols, mask=cols < ncols, other=0.).to(tl.float32)
42
+ out = x * tl.sigmoid(x) * y
43
+ tl.store(OUT + cols, out, mask=cols < ncols)
44
+
45
+
46
+ def _swiglu_fwd(xy, out=None):
47
+ if xy.stride(-1) != 1:
48
+ xy = xy.contiguous()
49
+ batch_shape = xy.shape[:-1]
50
+ xy = xy.reshape(-1, xy.shape[-1])
51
+ x, y = xy.chunk(2, dim=-1)
52
+ if out is None:
53
+ out = torch.empty_like(x)
54
+ else:
55
+ out = out.reshape(-1, out.shape[-1])
56
+ assert out.shape == x.shape
57
+ assert out.stride(-1) == 1
58
+ M, N = x.shape
59
+ grid = lambda META: (M, triton.cdiv(N, META['BLOCK_N']))
60
+ with device_guard(x):
61
+ _swiglu_fwd_kernel[grid](x, y, out, x.stride(0), y.stride(0), out.stride(0), N)
62
+ return out.reshape(*batch_shape, out.shape[-1])
63
+
64
+
65
+ @triton.autotune(
66
+ configs=[
67
+ triton.Config({'BLOCK_N': 32}),
68
+ triton.Config({'BLOCK_N': 64}),
69
+ triton.Config({'BLOCK_N': 128}),
70
+ triton.Config({'BLOCK_N': 256}),
71
+ triton.Config({'BLOCK_N': 512}),
72
+ triton.Config({'BLOCK_N': 1024}),
73
+ ],
74
+ key=['ncols'],
75
+ )
76
+ @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["OUT"] is not None})
77
+ @triton.jit
78
+ def _swiglu_bwd_kernel(
79
+ X,
80
+ Y,
81
+ DOUT,
82
+ OUT,
83
+ DX,
84
+ DY,
85
+ stride_x_row, # how much to increase the pointer when moving by 1 row
86
+ stride_y_row,
87
+ stride_dout_row,
88
+ stride_out_row,
89
+ stride_dx_row,
90
+ stride_dy_row,
91
+ ncols,
92
+ BLOCK_N: tl.constexpr,
93
+ RECOMPUTE_OUTPUT: tl.constexpr,
94
+ ):
95
+ # Map the program id to the row of X and Y it should compute.
96
+ row = tl.program_id(0)
97
+ start_col = tl.program_id(1) * BLOCK_N
98
+ X += row * stride_x_row
99
+ Y += row * stride_y_row
100
+ DOUT += row * stride_dout_row
101
+ if RECOMPUTE_OUTPUT:
102
+ OUT += row * stride_out_row
103
+ DX += row * stride_dx_row
104
+ DY += row * stride_dy_row
105
+ cols = start_col + tl.arange(0, BLOCK_N)
106
+ x = tl.load(X + cols, mask=cols < ncols, other=0.).to(tl.float32)
107
+ y = tl.load(Y + cols, mask=cols < ncols, other=0.).to(tl.float32)
108
+ dout = tl.load(DOUT + cols, mask=cols < ncols, other=0.).to(tl.float32)
109
+ x_sigmoid = tl.sigmoid(x)
110
+ dx = x_sigmoid * (1 + x * (1 - x_sigmoid)) * y * dout
111
+ dy = x * x_sigmoid * dout
112
+ tl.store(DX + cols, dx, mask=cols < ncols)
113
+ tl.store(DY + cols, dy, mask=cols < ncols)
114
+ if RECOMPUTE_OUTPUT:
115
+ out = x * x_sigmoid * y
116
+ tl.store(OUT + cols, out, mask=cols < ncols)
117
+
118
+
119
+ def _swiglu_bwd(xy, dout, dxy=None, recompute_output=False, out=None):
120
+ if xy.stride(-1) != 1:
121
+ xy = xy.contiguous()
122
+ if dout.stride(-1) != 1:
123
+ dout = dout.contiguous()
124
+ batch_shape = xy.shape[:-1]
125
+ xy = xy.reshape(-1, xy.shape[-1])
126
+ x, y = xy.chunk(2, dim=-1)
127
+ dout = dout.reshape(-1, dout.shape[-1])
128
+ assert dout.shape == x.shape
129
+ if dxy is None:
130
+ dxy = torch.empty_like(xy)
131
+ else:
132
+ dxy = dxy.reshape(-1, dxy.shape[-1])
133
+ assert dxy.shape == xy.shape
134
+ dx, dy = dxy.chunk(2, dim=-1)
135
+ assert dx.stride(-1) == 1
136
+ assert dy.stride(-1) == 1
137
+ if recompute_output:
138
+ if out is None:
139
+ out = torch.empty_like(x)
140
+ else:
141
+ out = out.reshape(-1, out.shape[-1])
142
+ assert out.shape == x.shape
143
+ assert out.stride(-1) == 1
144
+ M, N = x.shape
145
+ grid = lambda META: (M, triton.cdiv(N, META['BLOCK_N']))
146
+ with device_guard(x):
147
+ _swiglu_bwd_kernel[grid](x, y, dout, out if recompute_output else None, dx, dy,
148
+ x.stride(0), y.stride(0), dout.stride(0),
149
+ out.stride(0) if recompute_output else 0,
150
+ dx.stride(0), dy.stride(0),
151
+ N)
152
+ if not recompute_output:
153
+ return dxy.reshape(*batch_shape, dxy.shape[-1])
154
+ else:
155
+ return dxy.reshape(*batch_shape, dxy.shape[-1]), out.reshape(*batch_shape, out.shape[-1])
156
+
157
+
158
+ class SwiGLU(torch.autograd.Function):
159
+
160
+ @staticmethod
161
+ def forward(ctx, xy):
162
+ ctx.save_for_backward(xy)
163
+ return _swiglu_fwd(xy)
164
+
165
+ @staticmethod
166
+ def backward(ctx, dout):
167
+ xy, = ctx.saved_tensors
168
+ return _swiglu_bwd(xy, dout)
169
+
170
+
171
+ swiglu = SwiGLU.apply
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/layer_norm.py ADDED
@@ -0,0 +1,1115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+ # Implement dropout + residual + layer_norm / rms_norm.
3
+
4
+ # Based on the Triton LayerNorm tutorial: https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
5
+ # For the backward pass, we keep weight_grad and bias_grad in registers and accumulate.
6
+ # This is faster for dimensions up to 8k, but after that it's much slower due to register spilling.
7
+ # The models we train have hidden dim up to 8k anyway (e.g. Llama 70B), so this is fine.
8
+
9
+ import math
10
+ import warnings
11
+
12
+ import torch
13
+ import torch.nn.functional as F
14
+ from ...utils.torch import custom_bwd, custom_fwd
15
+ from ...utils.device import device_guard, get_sm_count
16
+
17
+ import triton
18
+ import triton.language as tl
19
+
20
+
21
+ def layer_norm_ref(
22
+ x,
23
+ weight,
24
+ bias,
25
+ residual=None,
26
+ x1=None,
27
+ weight1=None,
28
+ bias1=None,
29
+ eps=1e-6,
30
+ dropout_p=0.0,
31
+ rowscale=None,
32
+ prenorm=False,
33
+ dropout_mask=None,
34
+ dropout_mask1=None,
35
+ upcast=False,
36
+ ):
37
+ dtype = x.dtype
38
+ if upcast:
39
+ x = x.float()
40
+ weight = weight.float()
41
+ bias = bias.float() if bias is not None else None
42
+ residual = residual.float() if residual is not None else residual
43
+ x1 = x1.float() if x1 is not None else None
44
+ weight1 = weight1.float() if weight1 is not None else None
45
+ bias1 = bias1.float() if bias1 is not None else None
46
+ if x1 is not None:
47
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
48
+ if rowscale is not None:
49
+ x = x * rowscale[..., None]
50
+ if dropout_p > 0.0:
51
+ if dropout_mask is not None:
52
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
53
+ else:
54
+ x = F.dropout(x, p=dropout_p)
55
+ if x1 is not None:
56
+ if dropout_mask1 is not None:
57
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
58
+ else:
59
+ x1 = F.dropout(x1, p=dropout_p)
60
+ if x1 is not None:
61
+ x = x + x1
62
+ if residual is not None:
63
+ x = (x + residual).to(x.dtype)
64
+ out = F.layer_norm(x.to(weight.dtype), x.shape[-1:], weight=weight, bias=bias, eps=eps).to(
65
+ dtype
66
+ )
67
+ if weight1 is None:
68
+ return out if not prenorm else (out, x)
69
+ else:
70
+ out1 = F.layer_norm(
71
+ x.to(weight1.dtype), x.shape[-1:], weight=weight1, bias=bias1, eps=eps
72
+ ).to(dtype)
73
+ return (out, out1) if not prenorm else (out, out1, x)
74
+
75
+
76
+ def rms_norm_ref(
77
+ x,
78
+ weight,
79
+ bias,
80
+ residual=None,
81
+ x1=None,
82
+ weight1=None,
83
+ bias1=None,
84
+ eps=1e-6,
85
+ dropout_p=0.0,
86
+ rowscale=None,
87
+ prenorm=False,
88
+ dropout_mask=None,
89
+ dropout_mask1=None,
90
+ upcast=False,
91
+ ):
92
+ dtype = x.dtype
93
+ if upcast:
94
+ x = x.float()
95
+ weight = weight.float()
96
+ bias = bias.float() if bias is not None else None
97
+ residual = residual.float() if residual is not None else residual
98
+ x1 = x1.float() if x1 is not None else None
99
+ weight1 = weight1.float() if weight1 is not None else None
100
+ bias1 = bias1.float() if bias1 is not None else None
101
+ if x1 is not None:
102
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
103
+ if rowscale is not None:
104
+ x = x * rowscale[..., None]
105
+ if dropout_p > 0.0:
106
+ if dropout_mask is not None:
107
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
108
+ else:
109
+ x = F.dropout(x, p=dropout_p)
110
+ if x1 is not None:
111
+ if dropout_mask1 is not None:
112
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
113
+ else:
114
+ x1 = F.dropout(x1, p=dropout_p)
115
+ if x1 is not None:
116
+ x = x + x1
117
+ if residual is not None:
118
+ x = (x + residual).to(x.dtype)
119
+ rstd = 1 / torch.sqrt((x.square()).mean(dim=-1, keepdim=True) + eps)
120
+ out = ((x * rstd * weight) + bias if bias is not None else (x * rstd * weight)).to(dtype)
121
+ if weight1 is None:
122
+ return out if not prenorm else (out, x)
123
+ else:
124
+ out1 = ((x * rstd * weight1) + bias1 if bias1 is not None else (x * rstd * weight1)).to(
125
+ dtype
126
+ )
127
+ return (out, out1) if not prenorm else (out, out1, x)
128
+
129
+ def config_prune(configs):
130
+
131
+ if torch.version.hip:
132
+ try:
133
+ # set warp size based on gcn architecure
134
+ gcn_arch_name = torch.cuda.get_device_properties(0).gcnArchName
135
+ if "gfx10" in gcn_arch_name or "gfx11" in gcn_arch_name:
136
+ # radeon
137
+ warp_size = 32
138
+ else:
139
+ # instinct
140
+ warp_size = 64
141
+ except AttributeError as e:
142
+ # fall back to crude method to set warp size
143
+ device_name = torch.cuda.get_device_properties(0).name
144
+ if 'instinct' in device_name.lower():
145
+ warp_size = 64
146
+ else:
147
+ warp_size = 32
148
+ warnings.warn(f"{e}, warp size set to {warp_size} based on device name: {device_name}", UserWarning)
149
+
150
+ else:
151
+ # cuda
152
+ warp_size = 32
153
+
154
+ max_block_sz = 1024
155
+ max_num_warps = max_block_sz // warp_size
156
+ pruned_configs = [config for config in configs if config.num_warps <= max_num_warps]
157
+ return pruned_configs
158
+
159
+ configs_autotune = [
160
+ triton.Config({}, num_warps=1),
161
+ triton.Config({}, num_warps=2),
162
+ triton.Config({}, num_warps=4),
163
+ triton.Config({}, num_warps=8),
164
+ triton.Config({}, num_warps=16),
165
+ triton.Config({}, num_warps=32),
166
+ ]
167
+
168
+ pruned_configs_autotune = config_prune(configs_autotune)
169
+
170
+ @triton.autotune(
171
+ configs = pruned_configs_autotune,
172
+ key=["N", "HAS_RESIDUAL", "STORE_RESIDUAL_OUT", "IS_RMS_NORM", "HAS_BIAS"],
173
+ )
174
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
175
+ # @triton.heuristics({"HAS_RESIDUAL": lambda args: args["RESIDUAL"] is not None})
176
+ @triton.heuristics({"HAS_X1": lambda args: args["X1"] is not None})
177
+ @triton.heuristics({"HAS_W1": lambda args: args["W1"] is not None})
178
+ @triton.heuristics({"HAS_B1": lambda args: args["B1"] is not None})
179
+ @triton.jit
180
+ def _layer_norm_fwd_1pass_kernel(
181
+ X, # pointer to the input
182
+ Y, # pointer to the output
183
+ W, # pointer to the weights
184
+ B, # pointer to the biases
185
+ RESIDUAL, # pointer to the residual
186
+ X1,
187
+ W1,
188
+ B1,
189
+ Y1,
190
+ RESIDUAL_OUT, # pointer to the residual
191
+ ROWSCALE,
192
+ SEEDS, # Dropout seeds for each row
193
+ DROPOUT_MASK,
194
+ Mean, # pointer to the mean
195
+ Rstd, # pointer to the 1/std
196
+ stride_x_row, # how much to increase the pointer when moving by 1 row
197
+ stride_y_row,
198
+ stride_res_row,
199
+ stride_res_out_row,
200
+ stride_x1_row,
201
+ stride_y1_row,
202
+ M, # number of rows in X
203
+ N, # number of columns in X
204
+ eps, # epsilon to avoid division by zero
205
+ dropout_p, # Dropout probability
206
+ IS_RMS_NORM: tl.constexpr,
207
+ BLOCK_N: tl.constexpr,
208
+ HAS_RESIDUAL: tl.constexpr,
209
+ STORE_RESIDUAL_OUT: tl.constexpr,
210
+ HAS_BIAS: tl.constexpr,
211
+ HAS_DROPOUT: tl.constexpr,
212
+ STORE_DROPOUT_MASK: tl.constexpr,
213
+ HAS_ROWSCALE: tl.constexpr,
214
+ HAS_X1: tl.constexpr,
215
+ HAS_W1: tl.constexpr,
216
+ HAS_B1: tl.constexpr,
217
+ ):
218
+ # Map the program id to the row of X and Y it should compute.
219
+ row = tl.program_id(0)
220
+ X += row * stride_x_row
221
+ Y += row * stride_y_row
222
+ if HAS_RESIDUAL:
223
+ RESIDUAL += row * stride_res_row
224
+ if STORE_RESIDUAL_OUT:
225
+ RESIDUAL_OUT += row * stride_res_out_row
226
+ if HAS_X1:
227
+ X1 += row * stride_x1_row
228
+ if HAS_W1:
229
+ Y1 += row * stride_y1_row
230
+ # Compute mean and variance
231
+ cols = tl.arange(0, BLOCK_N)
232
+ x = tl.load(X + cols, mask=cols < N, other=0.0).to(tl.float32)
233
+ if HAS_ROWSCALE:
234
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
235
+ x *= rowscale
236
+ if HAS_DROPOUT:
237
+ # Compute dropout mask
238
+ # 7 rounds is good enough, and reduces register pressure
239
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
240
+ x = tl.where(keep_mask, x / (1.0 - dropout_p), 0.0)
241
+ if STORE_DROPOUT_MASK:
242
+ tl.store(DROPOUT_MASK + row * N + cols, keep_mask, mask=cols < N)
243
+ if HAS_X1:
244
+ x1 = tl.load(X1 + cols, mask=cols < N, other=0.0).to(tl.float32)
245
+ if HAS_ROWSCALE:
246
+ rowscale = tl.load(ROWSCALE + M + row).to(tl.float32)
247
+ x1 *= rowscale
248
+ if HAS_DROPOUT:
249
+ # Compute dropout mask
250
+ # 7 rounds is good enough, and reduces register pressure
251
+ keep_mask = (
252
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
253
+ )
254
+ x1 = tl.where(keep_mask, x1 / (1.0 - dropout_p), 0.0)
255
+ if STORE_DROPOUT_MASK:
256
+ tl.store(DROPOUT_MASK + (M + row) * N + cols, keep_mask, mask=cols < N)
257
+ x += x1
258
+ if HAS_RESIDUAL:
259
+ residual = tl.load(RESIDUAL + cols, mask=cols < N, other=0.0).to(tl.float32)
260
+ x += residual
261
+ if STORE_RESIDUAL_OUT:
262
+ tl.store(RESIDUAL_OUT + cols, x, mask=cols < N)
263
+ if not IS_RMS_NORM:
264
+ mean = tl.sum(x, axis=0) / N
265
+ tl.store(Mean + row, mean)
266
+ xbar = tl.where(cols < N, x - mean, 0.0)
267
+ var = tl.sum(xbar * xbar, axis=0) / N
268
+ else:
269
+ xbar = tl.where(cols < N, x, 0.0)
270
+ var = tl.sum(xbar * xbar, axis=0) / N
271
+ rstd = 1 / tl.sqrt(var + eps)
272
+ tl.store(Rstd + row, rstd)
273
+ # Normalize and apply linear transformation
274
+ mask = cols < N
275
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
276
+ if HAS_BIAS:
277
+ b = tl.load(B + cols, mask=mask).to(tl.float32)
278
+ x_hat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
279
+ y = x_hat * w + b if HAS_BIAS else x_hat * w
280
+ # Write output
281
+ tl.store(Y + cols, y, mask=mask)
282
+ if HAS_W1:
283
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
284
+ if HAS_B1:
285
+ b1 = tl.load(B1 + cols, mask=mask).to(tl.float32)
286
+ y1 = x_hat * w1 + b1 if HAS_B1 else x_hat * w1
287
+ tl.store(Y1 + cols, y1, mask=mask)
288
+
289
+
290
+ def _layer_norm_fwd(
291
+ x,
292
+ weight,
293
+ bias,
294
+ eps,
295
+ residual=None,
296
+ x1=None,
297
+ weight1=None,
298
+ bias1=None,
299
+ dropout_p=0.0,
300
+ rowscale=None,
301
+ out_dtype=None,
302
+ residual_dtype=None,
303
+ is_rms_norm=False,
304
+ return_dropout_mask=False,
305
+ ):
306
+ if residual is not None:
307
+ residual_dtype = residual.dtype
308
+ M, N = x.shape
309
+ assert x.stride(-1) == 1
310
+ if residual is not None:
311
+ assert residual.stride(-1) == 1
312
+ assert residual.shape == (M, N)
313
+ assert weight.shape == (N,)
314
+ assert weight.stride(-1) == 1
315
+ if bias is not None:
316
+ assert bias.stride(-1) == 1
317
+ assert bias.shape == (N,)
318
+ if x1 is not None:
319
+ assert x1.shape == x.shape
320
+ assert rowscale is None
321
+ assert x1.stride(-1) == 1
322
+ if weight1 is not None:
323
+ assert weight1.shape == (N,)
324
+ assert weight1.stride(-1) == 1
325
+ if bias1 is not None:
326
+ assert bias1.shape == (N,)
327
+ assert bias1.stride(-1) == 1
328
+ if rowscale is not None:
329
+ assert rowscale.is_contiguous()
330
+ assert rowscale.shape == (M,)
331
+ # allocate output
332
+ y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
333
+ assert y.stride(-1) == 1
334
+ if weight1 is not None:
335
+ y1 = torch.empty_like(y)
336
+ assert y1.stride(-1) == 1
337
+ else:
338
+ y1 = None
339
+ if (
340
+ residual is not None
341
+ or (residual_dtype is not None and residual_dtype != x.dtype)
342
+ or dropout_p > 0.0
343
+ or rowscale is not None
344
+ or x1 is not None
345
+ ):
346
+ residual_out = torch.empty(
347
+ M, N, device=x.device, dtype=residual_dtype if residual_dtype is not None else x.dtype
348
+ )
349
+ assert residual_out.stride(-1) == 1
350
+ else:
351
+ residual_out = None
352
+ mean = torch.empty((M,), dtype=torch.float32, device=x.device) if not is_rms_norm else None
353
+ rstd = torch.empty((M,), dtype=torch.float32, device=x.device)
354
+ if dropout_p > 0.0:
355
+ seeds = torch.randint(
356
+ 2**32, (M if x1 is None else 2 * M,), device=x.device, dtype=torch.int64
357
+ )
358
+ else:
359
+ seeds = None
360
+ if return_dropout_mask and dropout_p > 0.0:
361
+ dropout_mask = torch.empty(M if x1 is None else 2 * M, N, device=x.device, dtype=torch.bool)
362
+ else:
363
+ dropout_mask = None
364
+ # Less than 64KB per feature: enqueue fused kernel
365
+ MAX_FUSED_SIZE = 65536 // x.element_size()
366
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
367
+ if N > BLOCK_N:
368
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
369
+ with device_guard(x):
370
+ _layer_norm_fwd_1pass_kernel[(M,)](
371
+ x,
372
+ y,
373
+ weight,
374
+ bias,
375
+ residual,
376
+ x1,
377
+ weight1,
378
+ bias1,
379
+ y1,
380
+ residual_out,
381
+ rowscale,
382
+ seeds,
383
+ dropout_mask,
384
+ mean,
385
+ rstd,
386
+ x.stride(0),
387
+ y.stride(0),
388
+ residual.stride(0) if residual is not None else 0,
389
+ residual_out.stride(0) if residual_out is not None else 0,
390
+ x1.stride(0) if x1 is not None else 0,
391
+ y1.stride(0) if y1 is not None else 0,
392
+ M,
393
+ N,
394
+ eps,
395
+ dropout_p,
396
+ is_rms_norm,
397
+ BLOCK_N,
398
+ residual is not None,
399
+ residual_out is not None,
400
+ bias is not None,
401
+ dropout_p > 0.0,
402
+ dropout_mask is not None,
403
+ rowscale is not None,
404
+ )
405
+ # residual_out is None if residual is None and residual_dtype == input_dtype and dropout_p == 0.0
406
+ if dropout_mask is not None and x1 is not None:
407
+ dropout_mask, dropout_mask1 = dropout_mask.tensor_split(2, dim=0)
408
+ else:
409
+ dropout_mask1 = None
410
+ return (
411
+ y,
412
+ y1,
413
+ mean,
414
+ rstd,
415
+ residual_out if residual_out is not None else x,
416
+ seeds,
417
+ dropout_mask,
418
+ dropout_mask1,
419
+ )
420
+
421
+
422
+ @triton.autotune(
423
+ configs=pruned_configs_autotune,
424
+ key=["N", "HAS_DRESIDUAL", "STORE_DRESIDUAL", "IS_RMS_NORM", "HAS_BIAS", "HAS_DROPOUT"],
425
+ )
426
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
427
+ # @triton.heuristics({"HAS_DRESIDUAL": lambda args: args["DRESIDUAL"] is not None})
428
+ # @triton.heuristics({"STORE_DRESIDUAL": lambda args: args["DRESIDUAL_IN"] is not None})
429
+ @triton.heuristics({"HAS_ROWSCALE": lambda args: args["ROWSCALE"] is not None})
430
+ @triton.heuristics({"HAS_DY1": lambda args: args["DY1"] is not None})
431
+ @triton.heuristics({"HAS_DX1": lambda args: args["DX1"] is not None})
432
+ @triton.heuristics({"HAS_B1": lambda args: args["DB1"] is not None})
433
+ @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["Y"] is not None})
434
+ @triton.jit
435
+ def _layer_norm_bwd_kernel(
436
+ X, # pointer to the input
437
+ W, # pointer to the weights
438
+ B, # pointer to the biases
439
+ Y, # pointer to the output to be recomputed
440
+ DY, # pointer to the output gradient
441
+ DX, # pointer to the input gradient
442
+ DW, # pointer to the partial sum of weights gradient
443
+ DB, # pointer to the partial sum of biases gradient
444
+ DRESIDUAL,
445
+ W1,
446
+ DY1,
447
+ DX1,
448
+ DW1,
449
+ DB1,
450
+ DRESIDUAL_IN,
451
+ ROWSCALE,
452
+ SEEDS,
453
+ Mean, # pointer to the mean
454
+ Rstd, # pointer to the 1/std
455
+ stride_x_row, # how much to increase the pointer when moving by 1 row
456
+ stride_y_row,
457
+ stride_dy_row,
458
+ stride_dx_row,
459
+ stride_dres_row,
460
+ stride_dy1_row,
461
+ stride_dx1_row,
462
+ stride_dres_in_row,
463
+ M, # number of rows in X
464
+ N, # number of columns in X
465
+ eps, # epsilon to avoid division by zero
466
+ dropout_p,
467
+ rows_per_program,
468
+ IS_RMS_NORM: tl.constexpr,
469
+ BLOCK_N: tl.constexpr,
470
+ HAS_DRESIDUAL: tl.constexpr,
471
+ STORE_DRESIDUAL: tl.constexpr,
472
+ HAS_BIAS: tl.constexpr,
473
+ HAS_DROPOUT: tl.constexpr,
474
+ HAS_ROWSCALE: tl.constexpr,
475
+ HAS_DY1: tl.constexpr,
476
+ HAS_DX1: tl.constexpr,
477
+ HAS_B1: tl.constexpr,
478
+ RECOMPUTE_OUTPUT: tl.constexpr,
479
+ ):
480
+ # Map the program id to the elements of X, DX, and DY it should compute.
481
+ row_block_id = tl.program_id(0)
482
+ row_start = row_block_id * rows_per_program
483
+ # Do not early exit if row_start >= M, because we need to write DW and DB
484
+ cols = tl.arange(0, BLOCK_N)
485
+ mask = cols < N
486
+ X += row_start * stride_x_row
487
+ if HAS_DRESIDUAL:
488
+ DRESIDUAL += row_start * stride_dres_row
489
+ if STORE_DRESIDUAL:
490
+ DRESIDUAL_IN += row_start * stride_dres_in_row
491
+ DY += row_start * stride_dy_row
492
+ DX += row_start * stride_dx_row
493
+ if HAS_DY1:
494
+ DY1 += row_start * stride_dy1_row
495
+ if HAS_DX1:
496
+ DX1 += row_start * stride_dx1_row
497
+ if RECOMPUTE_OUTPUT:
498
+ Y += row_start * stride_y_row
499
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
500
+ if RECOMPUTE_OUTPUT and HAS_BIAS:
501
+ b = tl.load(B + cols, mask=mask, other=0.0).to(tl.float32)
502
+ if HAS_DY1:
503
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
504
+ dw = tl.zeros((BLOCK_N,), dtype=tl.float32)
505
+ if HAS_BIAS:
506
+ db = tl.zeros((BLOCK_N,), dtype=tl.float32)
507
+ if HAS_DY1:
508
+ dw1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
509
+ if HAS_B1:
510
+ db1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
511
+ row_end = min((row_block_id + 1) * rows_per_program, M)
512
+ for row in range(row_start, row_end):
513
+ # Load data to SRAM
514
+ x = tl.load(X + cols, mask=mask, other=0).to(tl.float32)
515
+ dy = tl.load(DY + cols, mask=mask, other=0).to(tl.float32)
516
+ if HAS_DY1:
517
+ dy1 = tl.load(DY1 + cols, mask=mask, other=0).to(tl.float32)
518
+ if not IS_RMS_NORM:
519
+ mean = tl.load(Mean + row)
520
+ rstd = tl.load(Rstd + row)
521
+ # Compute dx
522
+ xhat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
523
+ xhat = tl.where(mask, xhat, 0.0)
524
+ if RECOMPUTE_OUTPUT:
525
+ y = xhat * w + b if HAS_BIAS else xhat * w
526
+ tl.store(Y + cols, y, mask=mask)
527
+ wdy = w * dy
528
+ dw += dy * xhat
529
+ if HAS_BIAS:
530
+ db += dy
531
+ if HAS_DY1:
532
+ wdy += w1 * dy1
533
+ dw1 += dy1 * xhat
534
+ if HAS_B1:
535
+ db1 += dy1
536
+ if not IS_RMS_NORM:
537
+ c1 = tl.sum(xhat * wdy, axis=0) / N
538
+ c2 = tl.sum(wdy, axis=0) / N
539
+ dx = (wdy - (xhat * c1 + c2)) * rstd
540
+ else:
541
+ c1 = tl.sum(xhat * wdy, axis=0) / N
542
+ dx = (wdy - xhat * c1) * rstd
543
+ if HAS_DRESIDUAL:
544
+ dres = tl.load(DRESIDUAL + cols, mask=mask, other=0).to(tl.float32)
545
+ dx += dres
546
+ # Write dx
547
+ if STORE_DRESIDUAL:
548
+ tl.store(DRESIDUAL_IN + cols, dx, mask=mask)
549
+ if HAS_DX1:
550
+ if HAS_DROPOUT:
551
+ keep_mask = (
552
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
553
+ )
554
+ dx1 = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
555
+ else:
556
+ dx1 = dx
557
+ tl.store(DX1 + cols, dx1, mask=mask)
558
+ if HAS_DROPOUT:
559
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
560
+ dx = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
561
+ if HAS_ROWSCALE:
562
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
563
+ dx *= rowscale
564
+ tl.store(DX + cols, dx, mask=mask)
565
+
566
+ X += stride_x_row
567
+ if HAS_DRESIDUAL:
568
+ DRESIDUAL += stride_dres_row
569
+ if STORE_DRESIDUAL:
570
+ DRESIDUAL_IN += stride_dres_in_row
571
+ if RECOMPUTE_OUTPUT:
572
+ Y += stride_y_row
573
+ DY += stride_dy_row
574
+ DX += stride_dx_row
575
+ if HAS_DY1:
576
+ DY1 += stride_dy1_row
577
+ if HAS_DX1:
578
+ DX1 += stride_dx1_row
579
+ tl.store(DW + row_block_id * N + cols, dw, mask=mask)
580
+ if HAS_BIAS:
581
+ tl.store(DB + row_block_id * N + cols, db, mask=mask)
582
+ if HAS_DY1:
583
+ tl.store(DW1 + row_block_id * N + cols, dw1, mask=mask)
584
+ if HAS_B1:
585
+ tl.store(DB1 + row_block_id * N + cols, db1, mask=mask)
586
+
587
+
588
+ def _layer_norm_bwd(
589
+ dy,
590
+ x,
591
+ weight,
592
+ bias,
593
+ eps,
594
+ mean,
595
+ rstd,
596
+ dresidual=None,
597
+ dy1=None,
598
+ weight1=None,
599
+ bias1=None,
600
+ seeds=None,
601
+ dropout_p=0.0,
602
+ rowscale=None,
603
+ has_residual=False,
604
+ has_x1=False,
605
+ is_rms_norm=False,
606
+ x_dtype=None,
607
+ recompute_output=False,
608
+ ):
609
+ M, N = x.shape
610
+ assert x.stride(-1) == 1
611
+ assert dy.stride(-1) == 1
612
+ assert dy.shape == (M, N)
613
+ if dresidual is not None:
614
+ assert dresidual.stride(-1) == 1
615
+ assert dresidual.shape == (M, N)
616
+ assert weight.shape == (N,)
617
+ assert weight.stride(-1) == 1
618
+ if bias is not None:
619
+ assert bias.stride(-1) == 1
620
+ assert bias.shape == (N,)
621
+ if dy1 is not None:
622
+ assert weight1 is not None
623
+ assert dy1.shape == dy.shape
624
+ assert dy1.stride(-1) == 1
625
+ if weight1 is not None:
626
+ assert weight1.shape == (N,)
627
+ assert weight1.stride(-1) == 1
628
+ if bias1 is not None:
629
+ assert bias1.shape == (N,)
630
+ assert bias1.stride(-1) == 1
631
+ if seeds is not None:
632
+ assert seeds.is_contiguous()
633
+ assert seeds.shape == (M if not has_x1 else M * 2,)
634
+ if rowscale is not None:
635
+ assert rowscale.is_contiguous()
636
+ assert rowscale.shape == (M,)
637
+ # allocate output
638
+ dx = (
639
+ torch.empty_like(x)
640
+ if x_dtype is None
641
+ else torch.empty(M, N, dtype=x_dtype, device=x.device)
642
+ )
643
+ dresidual_in = (
644
+ torch.empty_like(x)
645
+ if has_residual
646
+ and (dx.dtype != x.dtype or dropout_p > 0.0 or rowscale is not None or has_x1)
647
+ else None
648
+ )
649
+ dx1 = torch.empty_like(dx) if (has_x1 and dropout_p > 0.0) else None
650
+ y = torch.empty(M, N, dtype=dy.dtype, device=dy.device) if recompute_output else None
651
+ if recompute_output:
652
+ assert weight1 is None, "recompute_output is not supported with parallel LayerNorm"
653
+
654
+ # Less than 64KB per feature: enqueue fused kernel
655
+ MAX_FUSED_SIZE = 65536 // x.element_size()
656
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
657
+ if N > BLOCK_N:
658
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
659
+ sm_count = get_sm_count(x.device)
660
+ _dw = torch.empty((sm_count, N), dtype=torch.float32, device=weight.device)
661
+ _db = (
662
+ torch.empty((sm_count, N), dtype=torch.float32, device=bias.device)
663
+ if bias is not None
664
+ else None
665
+ )
666
+ _dw1 = torch.empty_like(_dw) if weight1 is not None else None
667
+ _db1 = torch.empty_like(_db) if bias1 is not None else None
668
+ rows_per_program = math.ceil(M / sm_count)
669
+ grid = (sm_count,)
670
+ with device_guard(x):
671
+ _layer_norm_bwd_kernel[grid](
672
+ x,
673
+ weight,
674
+ bias,
675
+ y,
676
+ dy,
677
+ dx,
678
+ _dw,
679
+ _db,
680
+ dresidual,
681
+ weight1,
682
+ dy1,
683
+ dx1,
684
+ _dw1,
685
+ _db1,
686
+ dresidual_in,
687
+ rowscale,
688
+ seeds,
689
+ mean,
690
+ rstd,
691
+ x.stride(0),
692
+ 0 if not recompute_output else y.stride(0),
693
+ dy.stride(0),
694
+ dx.stride(0),
695
+ dresidual.stride(0) if dresidual is not None else 0,
696
+ dy1.stride(0) if dy1 is not None else 0,
697
+ dx1.stride(0) if dx1 is not None else 0,
698
+ dresidual_in.stride(0) if dresidual_in is not None else 0,
699
+ M,
700
+ N,
701
+ eps,
702
+ dropout_p,
703
+ rows_per_program,
704
+ is_rms_norm,
705
+ BLOCK_N,
706
+ dresidual is not None,
707
+ dresidual_in is not None,
708
+ bias is not None,
709
+ dropout_p > 0.0,
710
+ )
711
+ dw = _dw.sum(0).to(weight.dtype)
712
+ db = _db.sum(0).to(bias.dtype) if bias is not None else None
713
+ dw1 = _dw1.sum(0).to(weight1.dtype) if weight1 is not None else None
714
+ db1 = _db1.sum(0).to(bias1.dtype) if bias1 is not None else None
715
+ # Don't need to compute dresidual_in separately in this case
716
+ if has_residual and dx.dtype == x.dtype and dropout_p == 0.0 and rowscale is None:
717
+ dresidual_in = dx
718
+ if has_x1 and dropout_p == 0.0:
719
+ dx1 = dx
720
+ return (
721
+ (dx, dw, db, dresidual_in, dx1, dw1, db1)
722
+ if not recompute_output
723
+ else (dx, dw, db, dresidual_in, dx1, dw1, db1, y)
724
+ )
725
+
726
+
727
+ class LayerNormFn(torch.autograd.Function):
728
+ @staticmethod
729
+ def forward(
730
+ ctx,
731
+ x,
732
+ weight,
733
+ bias,
734
+ residual=None,
735
+ x1=None,
736
+ weight1=None,
737
+ bias1=None,
738
+ eps=1e-6,
739
+ dropout_p=0.0,
740
+ rowscale=None,
741
+ prenorm=False,
742
+ residual_in_fp32=False,
743
+ is_rms_norm=False,
744
+ return_dropout_mask=False,
745
+ ):
746
+ x_shape_og = x.shape
747
+ # reshape input data into 2D tensor
748
+ x = x.reshape(-1, x.shape[-1])
749
+ if x.stride(-1) != 1:
750
+ x = x.contiguous()
751
+ if residual is not None:
752
+ assert residual.shape == x_shape_og
753
+ residual = residual.reshape(-1, residual.shape[-1])
754
+ if residual.stride(-1) != 1:
755
+ residual = residual.contiguous()
756
+ if x1 is not None:
757
+ assert x1.shape == x_shape_og
758
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
759
+ x1 = x1.reshape(-1, x1.shape[-1])
760
+ if x1.stride(-1) != 1:
761
+ x1 = x1.contiguous()
762
+ weight = weight.contiguous()
763
+ if bias is not None:
764
+ bias = bias.contiguous()
765
+ if weight1 is not None:
766
+ weight1 = weight1.contiguous()
767
+ if bias1 is not None:
768
+ bias1 = bias1.contiguous()
769
+ if rowscale is not None:
770
+ rowscale = rowscale.reshape(-1).contiguous()
771
+ residual_dtype = (
772
+ residual.dtype
773
+ if residual is not None
774
+ else (torch.float32 if residual_in_fp32 else None)
775
+ )
776
+ y, y1, mean, rstd, residual_out, seeds, dropout_mask, dropout_mask1 = _layer_norm_fwd(
777
+ x,
778
+ weight,
779
+ bias,
780
+ eps,
781
+ residual,
782
+ x1,
783
+ weight1,
784
+ bias1,
785
+ dropout_p=dropout_p,
786
+ rowscale=rowscale,
787
+ residual_dtype=residual_dtype,
788
+ is_rms_norm=is_rms_norm,
789
+ return_dropout_mask=return_dropout_mask,
790
+ )
791
+ ctx.save_for_backward(
792
+ residual_out, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd
793
+ )
794
+ ctx.x_shape_og = x_shape_og
795
+ ctx.eps = eps
796
+ ctx.dropout_p = dropout_p
797
+ ctx.is_rms_norm = is_rms_norm
798
+ ctx.has_residual = residual is not None
799
+ ctx.has_x1 = x1 is not None
800
+ ctx.prenorm = prenorm
801
+ ctx.x_dtype = x.dtype
802
+ y = y.reshape(x_shape_og)
803
+ y1 = y1.reshape(x_shape_og) if y1 is not None else None
804
+ residual_out = residual_out.reshape(x_shape_og) if residual_out is not None else None
805
+ dropout_mask = dropout_mask.reshape(x_shape_og) if dropout_mask is not None else None
806
+ dropout_mask1 = dropout_mask1.reshape(x_shape_og) if dropout_mask1 is not None else None
807
+ if not return_dropout_mask:
808
+ if weight1 is None:
809
+ return y if not prenorm else (y, residual_out)
810
+ else:
811
+ return (y, y1) if not prenorm else (y, y1, residual_out)
812
+ else:
813
+ if weight1 is None:
814
+ return (
815
+ (y, dropout_mask, dropout_mask1)
816
+ if not prenorm
817
+ else (y, residual_out, dropout_mask, dropout_mask1)
818
+ )
819
+ else:
820
+ return (
821
+ (y, y1, dropout_mask, dropout_mask1)
822
+ if not prenorm
823
+ else (y, y1, residual_out, dropout_mask, dropout_mask1)
824
+ )
825
+
826
+ @staticmethod
827
+ def backward(ctx, dy, *args):
828
+ x, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd = ctx.saved_tensors
829
+ dy = dy.reshape(-1, dy.shape[-1])
830
+ if dy.stride(-1) != 1:
831
+ dy = dy.contiguous()
832
+ assert dy.shape == x.shape
833
+ if weight1 is not None:
834
+ dy1, args = args[0], args[1:]
835
+ dy1 = dy1.reshape(-1, dy1.shape[-1])
836
+ if dy1.stride(-1) != 1:
837
+ dy1 = dy1.contiguous()
838
+ assert dy1.shape == x.shape
839
+ else:
840
+ dy1 = None
841
+ if ctx.prenorm:
842
+ dresidual = args[0]
843
+ dresidual = dresidual.reshape(-1, dresidual.shape[-1])
844
+ if dresidual.stride(-1) != 1:
845
+ dresidual = dresidual.contiguous()
846
+ assert dresidual.shape == x.shape
847
+ else:
848
+ dresidual = None
849
+ dx, dw, db, dresidual_in, dx1, dw1, db1 = _layer_norm_bwd(
850
+ dy,
851
+ x,
852
+ weight,
853
+ bias,
854
+ ctx.eps,
855
+ mean,
856
+ rstd,
857
+ dresidual,
858
+ dy1,
859
+ weight1,
860
+ bias1,
861
+ seeds,
862
+ ctx.dropout_p,
863
+ rowscale,
864
+ ctx.has_residual,
865
+ ctx.has_x1,
866
+ ctx.is_rms_norm,
867
+ x_dtype=ctx.x_dtype,
868
+ )
869
+ return (
870
+ dx.reshape(ctx.x_shape_og),
871
+ dw,
872
+ db,
873
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
874
+ dx1.reshape(ctx.x_shape_og) if dx1 is not None else None,
875
+ dw1,
876
+ db1,
877
+ None,
878
+ None,
879
+ None,
880
+ None,
881
+ None,
882
+ None,
883
+ None,
884
+ )
885
+
886
+
887
+ def layer_norm_fn(
888
+ x,
889
+ weight,
890
+ bias,
891
+ residual=None,
892
+ x1=None,
893
+ weight1=None,
894
+ bias1=None,
895
+ eps=1e-6,
896
+ dropout_p=0.0,
897
+ rowscale=None,
898
+ prenorm=False,
899
+ residual_in_fp32=False,
900
+ is_rms_norm=False,
901
+ return_dropout_mask=False,
902
+ ):
903
+ return LayerNormFn.apply(
904
+ x,
905
+ weight,
906
+ bias,
907
+ residual,
908
+ x1,
909
+ weight1,
910
+ bias1,
911
+ eps,
912
+ dropout_p,
913
+ rowscale,
914
+ prenorm,
915
+ residual_in_fp32,
916
+ is_rms_norm,
917
+ return_dropout_mask,
918
+ )
919
+
920
+
921
+ def rms_norm_fn(
922
+ x,
923
+ weight,
924
+ bias,
925
+ residual=None,
926
+ x1=None,
927
+ weight1=None,
928
+ bias1=None,
929
+ eps=1e-6,
930
+ dropout_p=0.0,
931
+ rowscale=None,
932
+ prenorm=False,
933
+ residual_in_fp32=False,
934
+ return_dropout_mask=False,
935
+ ):
936
+ return LayerNormFn.apply(
937
+ x,
938
+ weight,
939
+ bias,
940
+ residual,
941
+ x1,
942
+ weight1,
943
+ bias1,
944
+ eps,
945
+ dropout_p,
946
+ rowscale,
947
+ prenorm,
948
+ residual_in_fp32,
949
+ True,
950
+ return_dropout_mask,
951
+ )
952
+
953
+
954
+ class RMSNorm(torch.nn.Module):
955
+
956
+ def __init__(self, hidden_size, eps=1e-5, dropout_p=0.0, device=None, dtype=None):
957
+ factory_kwargs = {"device": device, "dtype": dtype}
958
+ super().__init__()
959
+ self.eps = eps
960
+ if dropout_p > 0.0:
961
+ self.drop = torch.nn.Dropout(dropout_p)
962
+ else:
963
+ self.drop = None
964
+ self.weight = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
965
+ self.register_parameter("bias", None)
966
+ self.reset_parameters()
967
+
968
+ def reset_parameters(self):
969
+ torch.nn.init.ones_(self.weight)
970
+
971
+ def forward(self, x, residual=None, prenorm=False, residual_in_fp32=False):
972
+ return rms_norm_fn(
973
+ x,
974
+ self.weight,
975
+ self.bias,
976
+ residual=residual,
977
+ eps=self.eps,
978
+ dropout_p=self.drop.p if self.drop is not None and self.training else 0.0,
979
+ prenorm=prenorm,
980
+ residual_in_fp32=residual_in_fp32,
981
+ )
982
+
983
+
984
+ class LayerNormLinearFn(torch.autograd.Function):
985
+ @staticmethod
986
+ @custom_fwd
987
+ def forward(
988
+ ctx,
989
+ x,
990
+ norm_weight,
991
+ norm_bias,
992
+ linear_weight,
993
+ linear_bias,
994
+ residual=None,
995
+ eps=1e-6,
996
+ prenorm=False,
997
+ residual_in_fp32=False,
998
+ is_rms_norm=False,
999
+ ):
1000
+ x_shape_og = x.shape
1001
+ # reshape input data into 2D tensor
1002
+ x = x.reshape(-1, x.shape[-1])
1003
+ if x.stride(-1) != 1:
1004
+ x = x.contiguous()
1005
+ if residual is not None:
1006
+ assert residual.shape == x_shape_og
1007
+ residual = residual.reshape(-1, residual.shape[-1])
1008
+ if residual.stride(-1) != 1:
1009
+ residual = residual.contiguous()
1010
+ norm_weight = norm_weight.contiguous()
1011
+ if norm_bias is not None:
1012
+ norm_bias = norm_bias.contiguous()
1013
+ residual_dtype = (
1014
+ residual.dtype
1015
+ if residual is not None
1016
+ else (torch.float32 if residual_in_fp32 else None)
1017
+ )
1018
+ device_type = x.device.type
1019
+ y, _, mean, rstd, residual_out, *rest = _layer_norm_fwd(
1020
+ x,
1021
+ norm_weight,
1022
+ norm_bias,
1023
+ eps,
1024
+ residual,
1025
+ out_dtype=None if not torch.is_autocast_enabled(device_type) else torch.get_autocast_dtype(device_type),
1026
+ residual_dtype=residual_dtype,
1027
+ is_rms_norm=is_rms_norm,
1028
+ )
1029
+ y = y.reshape(x_shape_og)
1030
+ dtype = torch.get_autocast_dtype(device_type) if torch.is_autocast_enabled(device_type) else y.dtype
1031
+ linear_weight = linear_weight.to(dtype)
1032
+ linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
1033
+ out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
1034
+ # We don't store y, will be recomputed in the backward pass to save memory
1035
+ ctx.save_for_backward(residual_out, norm_weight, norm_bias, linear_weight, mean, rstd)
1036
+ ctx.x_shape_og = x_shape_og
1037
+ ctx.eps = eps
1038
+ ctx.is_rms_norm = is_rms_norm
1039
+ ctx.has_residual = residual is not None
1040
+ ctx.prenorm = prenorm
1041
+ ctx.x_dtype = x.dtype
1042
+ ctx.linear_bias_is_none = linear_bias is None
1043
+ return out if not prenorm else (out, residual_out.reshape(x_shape_og))
1044
+
1045
+ @staticmethod
1046
+ @custom_bwd
1047
+ def backward(ctx, dout, *args):
1048
+ x, norm_weight, norm_bias, linear_weight, mean, rstd = ctx.saved_tensors
1049
+ dout = dout.reshape(-1, dout.shape[-1])
1050
+ dy = F.linear(dout, linear_weight.t())
1051
+ dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
1052
+ if dy.stride(-1) != 1:
1053
+ dy = dy.contiguous()
1054
+ assert dy.shape == x.shape
1055
+ if ctx.prenorm:
1056
+ dresidual = args[0]
1057
+ dresidual = dresidual.reshape(-1, dresidual.shape[-1])
1058
+ if dresidual.stride(-1) != 1:
1059
+ dresidual = dresidual.contiguous()
1060
+ assert dresidual.shape == x.shape
1061
+ else:
1062
+ dresidual = None
1063
+ dx, dnorm_weight, dnorm_bias, dresidual_in, _, _, _, y = _layer_norm_bwd(
1064
+ dy,
1065
+ x,
1066
+ norm_weight,
1067
+ norm_bias,
1068
+ ctx.eps,
1069
+ mean,
1070
+ rstd,
1071
+ dresidual=dresidual,
1072
+ has_residual=ctx.has_residual,
1073
+ is_rms_norm=ctx.is_rms_norm,
1074
+ x_dtype=ctx.x_dtype,
1075
+ recompute_output=True,
1076
+ )
1077
+ dlinear_weight = torch.einsum("bo,bi->oi", dout, y)
1078
+ return (
1079
+ dx.reshape(ctx.x_shape_og),
1080
+ dnorm_weight,
1081
+ dnorm_bias,
1082
+ dlinear_weight,
1083
+ dlinear_bias,
1084
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
1085
+ None,
1086
+ None,
1087
+ None,
1088
+ None,
1089
+ )
1090
+
1091
+
1092
+ def layer_norm_linear_fn(
1093
+ x,
1094
+ norm_weight,
1095
+ norm_bias,
1096
+ linear_weight,
1097
+ linear_bias,
1098
+ residual=None,
1099
+ eps=1e-6,
1100
+ prenorm=False,
1101
+ residual_in_fp32=False,
1102
+ is_rms_norm=False,
1103
+ ):
1104
+ return LayerNormLinearFn.apply(
1105
+ x,
1106
+ norm_weight,
1107
+ norm_bias,
1108
+ linear_weight,
1109
+ linear_bias,
1110
+ residual,
1111
+ eps,
1112
+ prenorm,
1113
+ residual_in_fp32,
1114
+ is_rms_norm,
1115
+ )
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/layernorm_gated.py ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+ # Based on the Triton LayerNorm tutorial: https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
3
+ # For the backward pass, we keep weight_grad and bias_grad in registers and accumulate.
4
+ # This backward pass is faster for dimensions up to 8k, but after that it's much slower due to register spilling.
5
+ # The models we train have hidden dim up to 8k anyway (e.g. Llama 70B), so this is fine.
6
+
7
+ import math
8
+
9
+ import torch
10
+ import torch.nn.functional as F
11
+
12
+ import triton
13
+ import triton.language as tl
14
+
15
+ from einops import rearrange
16
+
17
+ from ...utils.device import device_guard, get_sm_count
18
+
19
+
20
+ def rms_norm_ref(x, weight, bias, z=None, eps=1e-6, group_size=None, norm_before_gate=True, upcast=True):
21
+ dtype = x.dtype
22
+ N = x.shape[-1]
23
+ weight = weight.float()
24
+ bias = bias.float() if bias is not None else None
25
+ if upcast:
26
+ x = x.float()
27
+ z = z.float() if z is not None else z
28
+ if z is not None and not norm_before_gate:
29
+ x = x * F.silu(z)
30
+ if group_size is None:
31
+ rstd = 1 / torch.sqrt((x.square()).mean(dim=-1, keepdim=True) + eps)
32
+ out = (x * rstd * weight) + bias if bias is not None else (x * rstd * weight)
33
+ else:
34
+ x_group = rearrange(x, "... (g d) -> ... g d", d=group_size)
35
+ rstd = 1 / torch.sqrt((x_group.square()).mean(dim=-1, keepdim=True) + eps)
36
+ out = rearrange(x_group * rstd, "... g d -> ... (g d)") * weight
37
+ if bias is not None:
38
+ out = out + bias
39
+ if z is not None and norm_before_gate:
40
+ out *= F.silu(z)
41
+ return out.to(dtype)
42
+
43
+
44
+ @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
45
+ @triton.heuristics({"HAS_Z": lambda args: args["Z"] is not None})
46
+ @triton.jit
47
+ def _layer_norm_fwd_1pass_kernel(
48
+ X, # pointer to the input
49
+ Y, # pointer to the output
50
+ W, # pointer to the weights
51
+ B, # pointer to the biases
52
+ Z, # pointer to the other branch
53
+ Mean, # pointer to the mean
54
+ Rstd, # pointer to the 1/std
55
+ stride_x_row, # how much to increase the pointer when moving by 1 row
56
+ stride_y_row,
57
+ stride_z_row,
58
+ M, # number of rows in X
59
+ N, # number of columns in X
60
+ eps, # epsilon to avoid division by zero
61
+ BLOCK_N: tl.constexpr,
62
+ HAS_BIAS: tl.constexpr,
63
+ HAS_Z: tl.constexpr,
64
+ NORM_BEFORE_GATE: tl.constexpr,
65
+ IS_RMS_NORM: tl.constexpr,
66
+ ):
67
+ # Map the program id to the row of X and Y it should compute.
68
+ row = tl.program_id(0)
69
+ group = tl.program_id(1)
70
+ X += row * stride_x_row + group * N
71
+ Y += row * stride_y_row + group * N
72
+ if HAS_Z:
73
+ Z += row * stride_z_row + group * N
74
+ if not IS_RMS_NORM:
75
+ Mean += group * M
76
+ Rstd += group * M
77
+ W += group * N
78
+ if HAS_BIAS:
79
+ B += group * N
80
+ # Compute mean and variance
81
+ cols = tl.arange(0, BLOCK_N)
82
+ x = tl.load(X + cols, mask=cols < N, other=0.).to(tl.float32)
83
+ if HAS_Z and not NORM_BEFORE_GATE:
84
+ z = tl.load(Z + cols, mask=cols < N).to(tl.float32)
85
+ x *= z * tl.sigmoid(z)
86
+ if not IS_RMS_NORM:
87
+ mean = tl.sum(x, axis=0) / N
88
+ tl.store(Mean + row, mean)
89
+ xbar = tl.where(cols < N, x - mean, 0.)
90
+ var = tl.sum(xbar * xbar, axis=0) / N
91
+ else:
92
+ xbar = tl.where(cols < N, x, 0.)
93
+ var = tl.sum(xbar * xbar, axis=0) / N
94
+ rstd = 1 / tl.sqrt(var + eps)
95
+ tl.store(Rstd + row, rstd)
96
+ # Normalize and apply linear transformation
97
+ mask = cols < N
98
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
99
+ if HAS_BIAS:
100
+ b = tl.load(B + cols, mask=mask).to(tl.float32)
101
+ x_hat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
102
+ y = x_hat * w + b if HAS_BIAS else x_hat * w
103
+ if HAS_Z and NORM_BEFORE_GATE:
104
+ z = tl.load(Z + cols, mask=mask).to(tl.float32)
105
+ y *= z * tl.sigmoid(z)
106
+ # Write output
107
+ tl.store(Y + cols, y, mask=mask)
108
+
109
+
110
+ def _layer_norm_fwd(x, weight, bias, eps, z=None, out=None, group_size=None, norm_before_gate=True, is_rms_norm=False):
111
+ M, N = x.shape
112
+ if group_size is None:
113
+ group_size = N
114
+ assert N % group_size == 0
115
+ ngroups = N // group_size
116
+ assert x.stride(-1) == 1
117
+ if z is not None:
118
+ assert z.stride(-1) == 1
119
+ assert z.shape == (M, N)
120
+ assert weight.shape == (N,)
121
+ assert weight.stride(-1) == 1
122
+ if bias is not None:
123
+ assert bias.stride(-1) == 1
124
+ assert bias.shape == (N,)
125
+ # allocate output
126
+ if out is not None:
127
+ assert out.shape == x.shape
128
+ else:
129
+ out = torch.empty_like(x)
130
+ assert out.stride(-1) == 1
131
+ mean = torch.empty((ngroups * M, ), dtype=torch.float32, device=x.device) if not is_rms_norm else None
132
+ rstd = torch.empty((ngroups * M, ), dtype=torch.float32, device=x.device)
133
+ # Less than 64KB per feature: enqueue fused kernel
134
+ MAX_FUSED_SIZE = 65536 // x.element_size()
135
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(group_size))
136
+ if group_size > BLOCK_N:
137
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
138
+ # heuristics for number of warps
139
+ num_warps = min(max(BLOCK_N // 256, 1), 8)
140
+ grid = (M, ngroups)
141
+ with device_guard(x):
142
+ _layer_norm_fwd_1pass_kernel[grid](x, out, weight, bias, z, mean, rstd,
143
+ x.stride(0), out.stride(0), z.stride(0) if z is not None else 0,
144
+ M, group_size, eps,
145
+ BLOCK_N=BLOCK_N,
146
+ NORM_BEFORE_GATE=norm_before_gate,
147
+ IS_RMS_NORM=is_rms_norm,
148
+ num_warps=num_warps)
149
+ return out, mean, rstd
150
+
151
+
152
+
153
+ @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
154
+ @triton.heuristics({"HAS_Z": lambda args: args["Z"] is not None})
155
+ @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["Y"] is not None})
156
+ @triton.jit
157
+ def _layer_norm_bwd_kernel(
158
+ X, # pointer to the input
159
+ W, # pointer to the weights
160
+ B, # pointer to the biases
161
+ Z, # pointer to the other branch
162
+ Y, # pointer to the output to be recomputed
163
+ DY, # pointer to the output gradient
164
+ DX, # pointer to the input gradient
165
+ DW, # pointer to the partial sum of weights gradient
166
+ DB, # pointer to the partial sum of biases gradient
167
+ DZ, # pointer to the other branch
168
+ Mean, # pointer to the mean
169
+ Rstd, # pointer to the 1/std
170
+ stride_x_row, # how much to increase the pointer when moving by 1 row
171
+ stride_z_row,
172
+ stride_y_row,
173
+ stride_dy_row,
174
+ stride_dx_row,
175
+ stride_dz_row,
176
+ stride_dw_row,
177
+ stride_db_row,
178
+ M, # number of rows in X
179
+ N, # number of columns in X
180
+ eps, # epsilon to avoid division by zero
181
+ rows_per_program,
182
+ NORM_BEFORE_GATE: tl.constexpr,
183
+ IS_RMS_NORM: tl.constexpr,
184
+ HAS_BIAS: tl.constexpr,
185
+ HAS_Z: tl.constexpr,
186
+ RECOMPUTE_OUTPUT: tl.constexpr,
187
+ BLOCK_N: tl.constexpr,
188
+ ):
189
+ # Map the program id to the elements of X, DX, and DY it should compute.
190
+ row_block_id = tl.program_id(0)
191
+ group = tl.program_id(1)
192
+ row_start = row_block_id * rows_per_program
193
+ cols = tl.arange(0, BLOCK_N)
194
+ mask = cols < N
195
+ X += row_start * stride_x_row + group * N
196
+ if HAS_Z:
197
+ Z += row_start * stride_z_row + group * N
198
+ DZ += row_start * stride_dz_row + group * N
199
+ DY += row_start * stride_dy_row + group * N
200
+ DX += row_start * stride_dx_row + group * N
201
+ if RECOMPUTE_OUTPUT:
202
+ Y += row_start * stride_y_row + group * N
203
+ if not IS_RMS_NORM:
204
+ Mean += group * M
205
+ Rstd += group * M
206
+ W += group * N
207
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
208
+ if (RECOMPUTE_OUTPUT or HAS_Z) and HAS_BIAS:
209
+ B += group * N
210
+ b = tl.load(B + cols, mask=mask, other=0.).to(tl.float32)
211
+ dw = tl.zeros((BLOCK_N,), dtype=tl.float32)
212
+ if HAS_BIAS:
213
+ db = tl.zeros((BLOCK_N,), dtype=tl.float32)
214
+ row_end = min((row_block_id + 1) * rows_per_program, M)
215
+ for row in range(row_start, row_end):
216
+ # Load data to SRAM
217
+ x = tl.load(X + cols, mask=mask, other=0).to(tl.float32)
218
+ dy = tl.load(DY + cols, mask=mask, other=0).to(tl.float32)
219
+ if not IS_RMS_NORM:
220
+ mean = tl.load(Mean + row)
221
+ if HAS_Z and not NORM_BEFORE_GATE:
222
+ z = tl.load(Z + cols, mask=mask, other=0.).to(tl.float32)
223
+ x_og = x
224
+ x = x_og * z * tl.sigmoid(z)
225
+ rstd = tl.load(Rstd + row)
226
+ # Compute dx
227
+ xhat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
228
+ xhat = tl.where(mask, xhat, 0.)
229
+ if HAS_Z and NORM_BEFORE_GATE:
230
+ z = tl.load(Z + cols, mask=mask, other=0.).to(tl.float32)
231
+ z_sigmoid = tl.sigmoid(z)
232
+ y = xhat * w + b if HAS_BIAS else xhat * w
233
+ if RECOMPUTE_OUTPUT:
234
+ tl.store(Y + cols, y * z * z_sigmoid, mask=mask)
235
+ dz = dy * y * z_sigmoid * (1 + z * (1 - z_sigmoid))
236
+ tl.store(DZ + cols, dz, mask=mask)
237
+ dy *= z * z_sigmoid
238
+ else:
239
+ if RECOMPUTE_OUTPUT:
240
+ y = xhat * w + b if HAS_BIAS else xhat * w
241
+ tl.store(Y + cols, y, mask=mask)
242
+ wdy = w * dy
243
+ c1 = tl.sum(xhat * wdy, axis=0) / N
244
+ if not IS_RMS_NORM:
245
+ c2 = tl.sum(wdy, axis=0) / N
246
+ dx = (wdy - (xhat * c1 + c2)) * rstd
247
+ else:
248
+ dx = (wdy - xhat * c1) * rstd
249
+ dw += dy * xhat
250
+ if HAS_BIAS:
251
+ db += dy
252
+ if HAS_Z and not NORM_BEFORE_GATE:
253
+ z_sigmoid = tl.sigmoid(z)
254
+ dz = dx * x_og * z_sigmoid * (1 + z * (1 - z_sigmoid))
255
+ tl.store(DZ + cols, dz, mask=mask)
256
+ dx *= z * z_sigmoid
257
+ # Write dx
258
+ tl.store(DX + cols, dx, mask=mask)
259
+
260
+ X += stride_x_row
261
+ if HAS_Z:
262
+ Z += stride_z_row
263
+ DZ += stride_dz_row
264
+ if RECOMPUTE_OUTPUT:
265
+ Y += stride_y_row
266
+ DY += stride_dy_row
267
+ DX += stride_dx_row
268
+ tl.store(DW + row_block_id * stride_dw_row + group * N + cols, dw, mask=mask)
269
+ if HAS_BIAS:
270
+ tl.store(DB + row_block_id * stride_db_row + group * N + cols, db, mask=mask)
271
+
272
+
273
+ def _layer_norm_bwd(dy, x, weight, bias, eps, mean, rstd, z=None, group_size=None,
274
+ norm_before_gate=True, is_rms_norm=False, recompute_output=False, dz=None, out=None):
275
+ M, N = x.shape
276
+ if group_size is None:
277
+ group_size = N
278
+ assert N % group_size == 0
279
+ ngroups = N // group_size
280
+ assert x.stride(-1) == 1
281
+ assert dy.stride(-1) == 1
282
+ assert dy.shape == (M, N)
283
+ if z is not None:
284
+ assert z.stride(-1) == 1
285
+ assert z.shape == (M, N)
286
+ assert weight.shape == (N,)
287
+ assert weight.stride(-1) == 1
288
+ if bias is not None:
289
+ assert bias.stride(-1) == 1
290
+ assert bias.shape == (N,)
291
+ # allocate output
292
+ dx = torch.empty_like(x)
293
+ if dz is not None:
294
+ assert z is not None
295
+ assert dz.shape == z.shape
296
+ assert dz.stride(-1) == 1
297
+ else:
298
+ dz = torch.empty_like(z) if z is not None else None
299
+ if recompute_output:
300
+ if out is None:
301
+ out = torch.empty_like(x)
302
+ assert out.shape == x.shape
303
+
304
+ # Less than 64KB per feature: enqueue fused kernel
305
+ MAX_FUSED_SIZE = 65536 // x.element_size()
306
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(group_size))
307
+ if group_size > BLOCK_N:
308
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
309
+ # heuristics for number of warps
310
+ num_warps = min(max(BLOCK_N // 256, 1), 8)
311
+ sm_count = get_sm_count(x.device)
312
+ # If group size is small (e.g., 64), we're only using 1 warp. So having just 108 programs
313
+ # would limit the occupancy.
314
+ nrow_groups = math.ceil(sm_count * math.ceil(4 / num_warps) / ngroups)
315
+ _dw = torch.empty((nrow_groups, N), dtype=torch.float32, device=weight.device)
316
+ _db = torch.empty((nrow_groups, N), dtype=torch.float32, device=bias.device) if bias is not None else None
317
+ rows_per_program = math.ceil(M / nrow_groups)
318
+ grid = (nrow_groups, ngroups)
319
+ with device_guard(x):
320
+ _layer_norm_bwd_kernel[grid](x, weight, bias, z, out if recompute_output else None,
321
+ dy, dx, _dw, _db, dz, mean, rstd,
322
+ x.stride(0),
323
+ z.stride(0) if z is not None else 0,
324
+ 0 if not recompute_output else out.stride(0),
325
+ dy.stride(0), dx.stride(0),
326
+ dz.stride(0) if dz is not None else 0,
327
+ _dw.stride(0),
328
+ _db.stride(0) if _db is not None else 0,
329
+ M, group_size, eps,
330
+ rows_per_program,
331
+ BLOCK_N=BLOCK_N,
332
+ NORM_BEFORE_GATE=norm_before_gate,
333
+ IS_RMS_NORM=is_rms_norm,
334
+ num_warps=num_warps)
335
+ dw = _dw.sum(0).to(weight.dtype)
336
+ db = _db.sum(0).to(bias.dtype) if bias is not None else None
337
+ return (dx, dw, db, dz) if not recompute_output else (dx, dw, db, dz, out)
338
+
339
+
340
+ class LayerNormFn(torch.autograd.Function):
341
+
342
+ @staticmethod
343
+ def forward(ctx, x, weight, bias, z=None, eps=1e-6, group_size=None, norm_before_gate=True,
344
+ is_rms_norm=False):
345
+ """If z is not None, we do norm(x) * silu(z) if norm_before_gate, else norm(x * silu(z))
346
+ """
347
+
348
+ x_shape_og = x.shape
349
+ # reshape input data into 2D tensor
350
+ x = x.reshape(-1, x.shape[-1])
351
+ if x.stride(-1) != 1:
352
+ x = x.contiguous()
353
+ if z is not None:
354
+ assert z.shape == x_shape_og
355
+ z = z.reshape(-1, z.shape[-1])
356
+ if z.stride(-1) != 1:
357
+ z = z.contiguous()
358
+ weight = weight.contiguous()
359
+ if bias is not None:
360
+ bias = bias.contiguous()
361
+ y, mean, rstd = _layer_norm_fwd(x, weight, bias, eps, z=z, group_size=group_size, norm_before_gate=norm_before_gate, is_rms_norm=is_rms_norm)
362
+ ctx.save_for_backward(x, weight, bias, mean, rstd, z)
363
+ ctx.x_shape_og = x_shape_og
364
+ ctx.eps = eps
365
+ ctx.group_size = group_size
366
+ ctx.norm_before_gate = norm_before_gate
367
+ ctx.is_rms_norm = is_rms_norm
368
+ return y.reshape(x_shape_og)
369
+
370
+ @staticmethod
371
+ def backward(ctx, dy):
372
+ x, weight, bias, mean, rstd, z = ctx.saved_tensors
373
+ dy = dy.reshape(-1, dy.shape[-1])
374
+ if dy.stride(-1) != 1:
375
+ dy = dy.contiguous()
376
+ assert dy.shape == x.shape
377
+ dx, dw, db, dz = _layer_norm_bwd(dy, x, weight, bias, ctx.eps, mean, rstd, z, ctx.group_size,
378
+ ctx.norm_before_gate, ctx.is_rms_norm)
379
+ return dx.reshape(ctx.x_shape_og), dw, db, dz.reshape(ctx.x_shape_og) if dz is not None else None, None, None, None, None
380
+
381
+
382
+ def layernorm_fn(x, weight, bias, z=None, eps=1e-6, group_size=None, norm_before_gate=True, is_rms_norm=False):
383
+ return LayerNormFn.apply(x, weight, bias, z, eps, group_size, norm_before_gate, is_rms_norm)
384
+
385
+
386
+ def rmsnorm_fn(x, weight, bias, z=None, eps=1e-6, group_size=None, norm_before_gate=True):
387
+ return LayerNormFn.apply(x, weight, bias, z, eps, group_size, norm_before_gate, True)
388
+
389
+
390
+ class LayerNorm(torch.nn.Module):
391
+
392
+ def __init__(self, hidden_size, eps=1e-5, group_size=None, norm_before_gate=True, device=None, dtype=None):
393
+ """If group_size is not None, we do GroupNorm with each group having group_size elements.
394
+ group_size=None is equivalent to group_size=hidden_size (i.e. there's only 1 group).
395
+ """
396
+
397
+ factory_kwargs = {"device": device, "dtype": dtype}
398
+ super().__init__()
399
+ self.eps = eps
400
+ self.weight = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
401
+ self.bias = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
402
+ self.group_size = group_size
403
+ self.norm_before_gate = norm_before_gate
404
+ self.reset_parameters()
405
+
406
+ def reset_parameters(self):
407
+ torch.nn.init.ones_(self.weight)
408
+ torch.nn.init.zeros_(self.bias)
409
+
410
+ def forward(self, x, z=None):
411
+ """If z is not None, we do norm(x) * silu(z) if norm_before_gate, else norm(x * silu(z))
412
+ """
413
+ return layernorm_fn(x, self.weight, self.bias, z=z, group_size=self.group_size, eps=self.eps,
414
+ norm_before_gate=self.norm_before_gate)
415
+
416
+
417
+ class RMSNorm(torch.nn.Module):
418
+
419
+ def __init__(self, hidden_size, eps=1e-5, group_size=None, norm_before_gate=True, device=None, dtype=None):
420
+ """If group_size is not None, we do GroupNorm with each group having group_size elements.
421
+ group_size=None is equivalent to group_size=hidden_size (i.e. there's only 1 group).
422
+ """
423
+ factory_kwargs = {"device": device, "dtype": dtype}
424
+ super().__init__()
425
+ self.eps = eps
426
+ self.weight = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
427
+ self.register_parameter("bias", None)
428
+ self.group_size = group_size
429
+ self.norm_before_gate = norm_before_gate
430
+ self.reset_parameters()
431
+
432
+ def reset_parameters(self):
433
+ torch.nn.init.ones_(self.weight)
434
+
435
+ def forward(self, x, z=None):
436
+ """If z is not None, we do norm(x) * silu(z) if norm_before_gate, else norm(x * silu(z))
437
+ """
438
+ return rmsnorm_fn(x, self.weight, self.bias, z=z, eps=self.eps, group_size=self.group_size,
439
+ norm_before_gate=self.norm_before_gate)
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/selective_state_update.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ """We want triton==2.1.0 or triton==2.2.0 or triton==2.3.0 for this
4
+ """
5
+
6
+ import math
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ import triton
11
+ import triton.language as tl
12
+
13
+ from einops import rearrange, repeat
14
+
15
+ from ...utils.device import device_guard
16
+
17
+ from .softplus import softplus
18
+
19
+
20
+ @triton.heuristics({"HAS_DT_BIAS": lambda args: args["dt_bias_ptr"] is not None})
21
+ @triton.heuristics({"HAS_D": lambda args: args["D_ptr"] is not None})
22
+ @triton.heuristics({"HAS_Z": lambda args: args["z_ptr"] is not None})
23
+ @triton.heuristics({"HAS_STATE_BATCH_INDICES": lambda args: args["state_batch_indices_ptr"] is not None})
24
+ @triton.heuristics({"BLOCK_SIZE_DSTATE": lambda args: triton.next_power_of_2(args["dstate"])})
25
+ @triton.jit
26
+ def _selective_scan_update_kernel(
27
+ # Pointers to matrices
28
+ state_ptr, x_ptr, dt_ptr, dt_bias_ptr, A_ptr, B_ptr, C_ptr, D_ptr, z_ptr, out_ptr, state_batch_indices_ptr,
29
+ # Matrix dimensions
30
+ batch, nheads, dim, dstate, nheads_ngroups_ratio,
31
+ # Strides
32
+ stride_state_batch, stride_state_head, stride_state_dim, stride_state_dstate,
33
+ stride_x_batch, stride_x_head, stride_x_dim,
34
+ stride_dt_batch, stride_dt_head, stride_dt_dim,
35
+ stride_dt_bias_head, stride_dt_bias_dim,
36
+ stride_A_head, stride_A_dim, stride_A_dstate,
37
+ stride_B_batch, stride_B_group, stride_B_dstate,
38
+ stride_C_batch, stride_C_group, stride_C_dstate,
39
+ stride_D_head, stride_D_dim,
40
+ stride_z_batch, stride_z_head, stride_z_dim,
41
+ stride_out_batch, stride_out_head, stride_out_dim,
42
+ # Meta-parameters
43
+ DT_SOFTPLUS: tl.constexpr,
44
+ TIE_HDIM: tl.constexpr,
45
+ BLOCK_SIZE_M: tl.constexpr,
46
+ HAS_DT_BIAS: tl.constexpr,
47
+ HAS_D: tl.constexpr,
48
+ HAS_Z: tl.constexpr,
49
+ HAS_STATE_BATCH_INDICES: tl.constexpr,
50
+ BLOCK_SIZE_DSTATE: tl.constexpr,
51
+ ):
52
+ pid_m = tl.program_id(axis=0)
53
+ pid_b = tl.program_id(axis=1)
54
+ pid_h = tl.program_id(axis=2)
55
+
56
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
57
+ out_ptr += pid_b * stride_out_batch + pid_h * stride_out_head
58
+ out_ptrs = out_ptr + offs_m * stride_out_dim
59
+
60
+ if HAS_STATE_BATCH_INDICES:
61
+ state_batch_indices_ptr += pid_b
62
+ state_batch_idx = tl.load(state_batch_indices_ptr)
63
+ # Skip padding tokens
64
+ if state_batch_idx < 0:
65
+ tl.store(out_ptrs, 0.0, mask=offs_m < dim)
66
+ return
67
+ state_ptr += state_batch_idx * stride_state_batch + pid_h * stride_state_head
68
+ else:
69
+ state_ptr += pid_b * stride_state_batch + pid_h * stride_state_head
70
+
71
+ x_ptr += pid_b * stride_x_batch + pid_h * stride_x_head
72
+ dt_ptr += pid_b * stride_dt_batch + pid_h * stride_dt_head
73
+ if HAS_DT_BIAS:
74
+ dt_bias_ptr += pid_h * stride_dt_bias_head
75
+ A_ptr += pid_h * stride_A_head
76
+ B_ptr += pid_b * stride_B_batch + (pid_h // nheads_ngroups_ratio) * stride_B_group
77
+ C_ptr += pid_b * stride_C_batch + (pid_h // nheads_ngroups_ratio) * stride_C_group
78
+ if HAS_Z:
79
+ z_ptr += pid_b * stride_z_batch + pid_h * stride_z_head
80
+
81
+ offs_n = tl.arange(0, BLOCK_SIZE_DSTATE)
82
+ state_ptrs = state_ptr + (offs_m[:, None] * stride_state_dim + offs_n[None, :] * stride_state_dstate)
83
+ x_ptrs = x_ptr + offs_m * stride_x_dim
84
+ dt_ptrs = dt_ptr + offs_m * stride_dt_dim
85
+ if HAS_DT_BIAS:
86
+ dt_bias_ptrs = dt_bias_ptr + offs_m * stride_dt_bias_dim
87
+ if HAS_D:
88
+ D_ptr += pid_h * stride_D_head
89
+ A_ptrs = A_ptr + (offs_m[:, None] * stride_A_dim + offs_n[None, :] * stride_A_dstate)
90
+ B_ptrs = B_ptr + offs_n * stride_B_dstate
91
+ C_ptrs = C_ptr + offs_n * stride_C_dstate
92
+ if HAS_D:
93
+ D_ptrs = D_ptr + offs_m * stride_D_dim
94
+ if HAS_Z:
95
+ z_ptrs = z_ptr + offs_m * stride_z_dim
96
+
97
+ state = tl.load(state_ptrs, mask=(offs_m[:, None] < dim) & (offs_n[None, :] < dstate), other=0.0)
98
+ x = tl.load(x_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
99
+ if not TIE_HDIM:
100
+ dt = tl.load(dt_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
101
+ if HAS_DT_BIAS:
102
+ dt += tl.load(dt_bias_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
103
+ if DT_SOFTPLUS:
104
+ dt = tl.where(dt <= 20.0, softplus(dt), dt)
105
+ A = tl.load(A_ptrs, mask=(offs_m[:, None] < dim) & (offs_n[None, :] < dstate), other=0.0).to(tl.float32)
106
+ dA = tl.exp(A * dt[:, None])
107
+ else:
108
+ dt = tl.load(dt_ptr).to(tl.float32)
109
+ if HAS_DT_BIAS:
110
+ dt += tl.load(dt_bias_ptr).to(tl.float32)
111
+ if DT_SOFTPLUS:
112
+ dt = tl.where(dt <= 20.0, softplus(dt), dt)
113
+ A = tl.load(A_ptr).to(tl.float32)
114
+ dA = tl.exp(A * dt) # scalar, not a matrix
115
+
116
+ B = tl.load(B_ptrs, mask=offs_n < dstate, other=0.0).to(tl.float32)
117
+ C = tl.load(C_ptrs, mask=offs_n < dstate, other=0.0).to(tl.float32)
118
+ if HAS_D:
119
+ D = tl.load(D_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
120
+ if HAS_Z:
121
+ z = tl.load(z_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
122
+
123
+ if not TIE_HDIM:
124
+ dB = B[None, :] * dt[:, None]
125
+ else:
126
+ dB = B * dt # vector of size (dstate,)
127
+ state = state * dA + dB * x[:, None]
128
+ tl.store(state_ptrs, state, mask=(offs_m[:, None] < dim) & (offs_n[None, :] < dstate))
129
+ out = tl.sum(state * C[None, :], axis=1)
130
+ if HAS_D:
131
+ out += x * D
132
+ if HAS_Z:
133
+ out *= z * tl.sigmoid(z)
134
+ tl.store(out_ptrs, out, mask=offs_m < dim)
135
+
136
+
137
+ def selective_state_update(state, x, dt, A, B, C, D=None, z=None, dt_bias=None, dt_softplus=False,
138
+ state_batch_indices=None):
139
+ """
140
+ Argument:
141
+ state: (batch, dim, dstate) or (batch, nheads, dim, dstate)
142
+ x: (batch, dim) or (batch, nheads, dim)
143
+ dt: (batch, dim) or (batch, nheads, dim)
144
+ A: (dim, dstate) or (nheads, dim, dstate)
145
+ B: (batch, dstate) or (batch, ngroups, dstate)
146
+ C: (batch, dstate) or (batch, ngroups, dstate)
147
+ D: (dim,) or (nheads, dim)
148
+ z: (batch, dim) or (batch, nheads, dim)
149
+ dt_bias: (dim,) or (nheads, dim)
150
+ Return:
151
+ out: (batch, dim) or (batch, nheads, dim)
152
+ """
153
+ has_heads = state.dim() > 3
154
+ if state.dim() == 3:
155
+ state = state.unsqueeze(1)
156
+ if x.dim() == 2:
157
+ x = x.unsqueeze(1)
158
+ if dt.dim() == 2:
159
+ dt = dt.unsqueeze(1)
160
+ if A.dim() == 2:
161
+ A = A.unsqueeze(0)
162
+ if B.dim() == 2:
163
+ B = B.unsqueeze(1)
164
+ if C.dim() == 2:
165
+ C = C.unsqueeze(1)
166
+ if D is not None and D.dim() == 1:
167
+ D = D.unsqueeze(0)
168
+ if z is not None and z.dim() == 2:
169
+ z = z.unsqueeze(1)
170
+ if dt_bias is not None and dt_bias.dim() == 1:
171
+ dt_bias = dt_bias.unsqueeze(0)
172
+ _, nheads, dim, dstate = state.shape
173
+ batch = x.shape[0]
174
+ if x.shape != (batch, nheads, dim):
175
+ print(f"{state.shape} {x.shape} {batch} {nheads} {dim}")
176
+ assert x.shape == (batch, nheads, dim)
177
+ assert dt.shape == x.shape
178
+ assert A.shape == (nheads, dim, dstate)
179
+ ngroups = B.shape[1]
180
+ assert nheads % ngroups == 0, "nheads must be divisible by ngroups"
181
+ assert B.shape == (batch, ngroups, dstate)
182
+ assert C.shape == B.shape
183
+ if D is not None:
184
+ assert D.shape == (nheads, dim)
185
+ if z is not None:
186
+ assert z.shape == x.shape
187
+ if dt_bias is not None:
188
+ assert dt_bias.shape == (nheads, dim)
189
+ if state_batch_indices is not None:
190
+ assert state_batch_indices.shape == (batch,)
191
+ out = torch.empty_like(x)
192
+ grid = lambda META: (triton.cdiv(dim, META['BLOCK_SIZE_M']), batch, nheads)
193
+ z_strides = ((z.stride(0), z.stride(1), z.stride(2)) if z is not None else (0, 0, 0))
194
+ # We don't want autotune since it will overwrite the state
195
+ # We instead tune by hand.
196
+ BLOCK_SIZE_M, num_warps = ((32, 4) if dstate <= 16
197
+ else ((16, 4) if dstate <= 32 else
198
+ ((8, 4) if dstate <= 64 else
199
+ ((4, 4) if dstate <= 128 else
200
+ ((4, 8))))))
201
+ tie_hdim = (A.stride(-1) == 0 and A.stride(-2) == 0 and dt.stride(-1) == 0
202
+ and (dt_bias is None or dt_bias.stride(-1) == 0))
203
+ dt_bias_strides = ((dt_bias.stride(0), dt_bias.stride(1)) if dt_bias is not None else (0, 0))
204
+ D_strides = ((D.stride(0), D.stride(1)) if D is not None else (0, 0))
205
+ with device_guard(x):
206
+ _selective_scan_update_kernel[grid](
207
+ state, x, dt, dt_bias, A, B, C, D, z, out, state_batch_indices,
208
+ batch, nheads, dim, dstate, nheads // ngroups,
209
+ state.stride(0), state.stride(1), state.stride(2), state.stride(3),
210
+ x.stride(0), x.stride(1), x.stride(2),
211
+ dt.stride(0), dt.stride(1), dt.stride(2),
212
+ *dt_bias_strides,
213
+ A.stride(0), A.stride(1), A.stride(2),
214
+ B.stride(0), B.stride(1), B.stride(2),
215
+ C.stride(0), C.stride(1), C.stride(2),
216
+ *D_strides,
217
+ z_strides[0], z_strides[1], z_strides[2],
218
+ out.stride(0), out.stride(1), out.stride(2),
219
+ dt_softplus,
220
+ tie_hdim,
221
+ BLOCK_SIZE_M,
222
+ num_warps=num_warps,
223
+ )
224
+ if not has_heads:
225
+ out = out.squeeze(1)
226
+ return out
227
+
228
+
229
+ def selective_state_update_ref(state, x, dt, A, B, C, D=None, z=None, dt_bias=None, dt_softplus=False):
230
+ """
231
+ Argument:
232
+ state: (batch, dim, dstate) or (batch, nheads, dim, dstate)
233
+ x: (batch, dim) or (batch, nheads, dim)
234
+ dt: (batch, dim) or (batch, nheads, dim)
235
+ A: (dim, dstate) or (nheads, dim, dstate)
236
+ B: (batch, dstate) or (batch, ngroups, dstate)
237
+ C: (batch, dstate) or (batch, ngroups, dstate)
238
+ D: (dim,) or (nheads, dim)
239
+ z: (batch, dim) or (batch, nheads, dim)
240
+ dt_bias: (dim,) or (nheads, dim)
241
+ Return:
242
+ out: (batch, dim) or (batch, nheads, dim)
243
+ """
244
+ has_heads = state.dim() > 3
245
+ if state.dim() == 3:
246
+ state = state.unsqueeze(1)
247
+ if x.dim() == 2:
248
+ x = x.unsqueeze(1)
249
+ if dt.dim() == 2:
250
+ dt = dt.unsqueeze(1)
251
+ if A.dim() == 2:
252
+ A = A.unsqueeze(0)
253
+ if B.dim() == 2:
254
+ B = B.unsqueeze(1)
255
+ if C.dim() == 2:
256
+ C = C.unsqueeze(1)
257
+ if D is not None and D.dim() == 1:
258
+ D = D.unsqueeze(0)
259
+ if z is not None and z.dim() == 2:
260
+ z = z.unsqueeze(1)
261
+ if dt_bias is not None and dt_bias.dim() == 1:
262
+ dt_bias = dt_bias.unsqueeze(0)
263
+ batch, nheads, dim, dstate = state.shape
264
+ assert x.shape == (batch, nheads, dim)
265
+ assert dt.shape == x.shape
266
+ assert A.shape == (nheads, dim, dstate)
267
+ ngroups = B.shape[1]
268
+ assert nheads % ngroups == 0, "nheads must be divisible by ngroups"
269
+ assert B.shape == (batch, ngroups, dstate)
270
+ assert C.shape == B.shape
271
+ if D is not None:
272
+ assert D.shape == (nheads, dim)
273
+ if z is not None:
274
+ assert z.shape == x.shape
275
+ if dt_bias is not None:
276
+ assert dt_bias.shape == (nheads, dim)
277
+ dt = dt + dt_bias
278
+ dt = F.softplus(dt) if dt_softplus else dt
279
+ dA = torch.exp(rearrange(dt, "b h d -> b h d 1") * A) # (batch, nheads, dim, dstate)
280
+ B = repeat(B, "b g n -> b (g h) n", h=nheads // ngroups) # (batch, nheads, dstate)
281
+ C = repeat(C, "b g n -> b (g h) n", h=nheads // ngroups) # (batch, nheads, dstate)
282
+ dB = rearrange(dt, "b h d -> b h d 1") * rearrange(B, "b h n -> b h 1 n") # (batch, nheads, dim, dstate)
283
+ state.copy_(state * dA + dB * rearrange(x, "b h d -> b h d 1")) # (batch, dim, dstate
284
+ out = torch.einsum("bhdn,bhn->bhd", state.to(C.dtype), C)
285
+ if D is not None:
286
+ out += (x * D).to(out.dtype)
287
+ out = (out if z is None else out * F.silu(z)).to(x.dtype)
288
+ if not has_heads:
289
+ out = out.squeeze(1)
290
+ return out
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/softplus.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import triton
2
+ import triton.language as tl
3
+ from packaging import version
4
+
5
+ TRITON3 = version.parse(triton.__version__) >= version.parse("3.0.0")
6
+
7
+
8
+ if TRITON3:
9
+ @triton.jit
10
+ def softplus(dt):
11
+ return tl.math.log(tl.math.exp(dt) + 1)
12
+ else:
13
+ @triton.jit
14
+ def softplus(dt):
15
+ return tl.math.log1p(tl.exp(dt))
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_bmm.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ """We want triton==2.1.0 or 2.2.0 for this
4
+ """
5
+
6
+ import math
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ import triton
11
+ import triton.language as tl
12
+
13
+ from einops import rearrange, repeat
14
+
15
+ from ...utils.device import device_guard
16
+
17
+
18
+ def init_to_zero(names):
19
+ return lambda nargs: [nargs[name].zero_() for name in names if nargs[name] is not None]
20
+
21
+
22
+ @triton.autotune(
23
+ configs=[
24
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 64}, num_stages=3, num_warps=8),
25
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
26
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
27
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
28
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
29
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
30
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
31
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
32
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=2),
33
+ ],
34
+ key=['chunk_size', 'K', 'IS_CAUSAL'],
35
+ )
36
+ @triton.jit
37
+ def _bmm_chunk_fwd_kernel(
38
+ # Pointers to matrices
39
+ a_ptr, b_ptr, out_ptr, seq_idx_ptr,
40
+ # Matrix dimensions
41
+ seqlen, chunk_size, K, ngroups,
42
+ stride_a_batch, stride_a_seqlen, stride_a_head, stride_ak,
43
+ stride_b_batch, stride_b_seqlen, stride_b_head, stride_bk,
44
+ stride_out_batch, stride_out_chunk, stride_out_head, stride_outm, stride_outn,
45
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
46
+ # Meta-parameters
47
+ IS_CAUSAL: tl.constexpr,
48
+ dot_dtype: tl.constexpr,
49
+ HAS_SEQ_IDX: tl.constexpr,
50
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
51
+ ):
52
+ pid_b = tl.program_id(axis=1)
53
+ pid_ch = tl.program_id(axis=2)
54
+ pid_c = pid_ch // ngroups
55
+ pid_h = pid_ch - pid_c * ngroups
56
+ num_pid_n = tl.cdiv(chunk_size, BLOCK_SIZE_N)
57
+ pid_m = tl.program_id(axis=0) // num_pid_n
58
+ pid_n = tl.program_id(axis=0) % num_pid_n
59
+ if IS_CAUSAL:
60
+ if pid_n * BLOCK_SIZE_N >= (pid_m + 1) * BLOCK_SIZE_M:
61
+ return
62
+ a_ptr += pid_b * stride_a_batch + pid_c * chunk_size * stride_a_seqlen + pid_h * stride_a_head
63
+ b_ptr += pid_b * stride_b_batch + pid_c * chunk_size * stride_b_seqlen + pid_h * stride_b_head
64
+ if HAS_SEQ_IDX:
65
+ seq_idx_ptr += pid_b * stride_seq_idx_batch + pid_c * chunk_size * stride_seq_idx_seqlen
66
+
67
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
68
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
69
+ offs_k = tl.arange(0, BLOCK_SIZE_K)
70
+ a_ptrs = a_ptr + (offs_m[:, None] * stride_a_seqlen + offs_k[None, :] * stride_ak)
71
+ b_ptrs = b_ptr + (offs_k[:, None] * stride_bk + offs_n[None, :] * stride_b_seqlen)
72
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
73
+
74
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
75
+ for k in range(0, tl.cdiv(K, BLOCK_SIZE_K)):
76
+ a = tl.load(a_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < K - k * BLOCK_SIZE_K), other=0.0).to(dot_dtype)
77
+ b = tl.load(b_ptrs, mask=(offs_k[:, None] < K - k * BLOCK_SIZE_K) & (offs_n[None, :] < chunk_size_limit), other=0.0).to(dot_dtype)
78
+ acc += tl.dot(a, b)
79
+ a_ptrs += BLOCK_SIZE_K * stride_ak
80
+ b_ptrs += BLOCK_SIZE_K * stride_bk
81
+
82
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
83
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
84
+ if HAS_SEQ_IDX:
85
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
86
+ seq_idx_m = tl.load(seq_idx_ptr + offs_m * stride_seq_idx_seqlen, mask=offs_m < chunk_size_limit, other=-1)
87
+ seq_idx_n = tl.load(seq_idx_ptr + offs_n * stride_seq_idx_seqlen, mask=offs_n < chunk_size_limit, other=-2)
88
+ acc = tl.where(seq_idx_m[:, None] == seq_idx_n[None, :], acc, 0.0)
89
+ out = acc.to(out_ptr.dtype.element_ty)
90
+
91
+ out_ptr += pid_b * stride_out_batch + pid_c * stride_out_chunk + pid_h * stride_out_head
92
+ out_ptrs = out_ptr + (stride_outm * offs_m[:, None] + offs_n[None, :] * stride_outn)
93
+ tl.store(out_ptrs, out, mask=(offs_m[:, None] < chunk_size) & (offs_n[None, :] < chunk_size))
94
+
95
+
96
+ @triton.autotune(
97
+ configs=[
98
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_CS': 64}, num_stages=3, num_warps=8),
99
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=4),
100
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=4),
101
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=4),
102
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=4),
103
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=4),
104
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_CS': 32}, num_stages=5, num_warps=2),
105
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_CS': 32}, num_stages=5, num_warps=2),
106
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_CS': 32}, num_stages=4, num_warps=2),
107
+ ],
108
+ key=['chunk_size', 'K'],
109
+ )
110
+ @triton.jit
111
+ def _bmm_chunk_bwd_kernel(
112
+ # Pointers to matrices
113
+ a_ptr, dout_ptr, db_ptr, res_ptr,
114
+ # Matrix dimensions
115
+ seqlen, chunk_size, K, ngroups,
116
+ stride_a_batch, stride_a_seqlen, stride_a_head, stride_ak,
117
+ stride_dout_batch, stride_dout_chunk, stride_dout_head, stride_dout_csize_m, stride_dout_csize_n,
118
+ stride_db_batch, stride_db_seqlen, stride_db_head, stride_db_k,
119
+ stride_res_batch, stride_res_seqlen, stride_res_head, stride_res_k,
120
+ # Meta-parameters
121
+ dot_dtype: tl.constexpr,
122
+ HAS_RESIDUAL: tl.constexpr,
123
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_CS: tl.constexpr,
124
+ ):
125
+ pid_b = tl.program_id(axis=1)
126
+ pid_ch = tl.program_id(axis=2)
127
+ pid_c = pid_ch // ngroups
128
+ pid_h = pid_ch - pid_c * ngroups
129
+ num_pid_n = tl.cdiv(K, BLOCK_SIZE_N)
130
+ pid_m = tl.program_id(axis=0) // num_pid_n
131
+ pid_n = tl.program_id(axis=0) % num_pid_n
132
+
133
+ a_ptr += pid_b * stride_a_batch + pid_c * chunk_size * stride_a_seqlen + pid_h * stride_a_head
134
+ dout_ptr += pid_b * stride_dout_batch + pid_c * stride_dout_chunk + pid_h * stride_dout_head
135
+
136
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
137
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
138
+ offs_cs = tl.arange(0, BLOCK_SIZE_CS)
139
+ dout_ptrs = dout_ptr + (offs_m[:, None] * stride_dout_csize_n + offs_cs[None, :] * stride_dout_csize_m)
140
+ a_ptrs = a_ptr + (offs_cs[:, None] * stride_a_seqlen + offs_n[None, :] * stride_ak)
141
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
142
+
143
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
144
+ for cs in range(0, tl.cdiv(chunk_size_limit, BLOCK_SIZE_CS)):
145
+ dout = tl.load(dout_ptrs, mask=(offs_m[:, None] < chunk_size) & (offs_cs[None, :] < chunk_size_limit - cs * BLOCK_SIZE_CS), other=0.0).to(dot_dtype)
146
+ a = tl.load(a_ptrs, mask=(offs_cs[:, None] < chunk_size_limit - cs * BLOCK_SIZE_CS) & (offs_n[None, :] < K), other=0.0).to(dot_dtype)
147
+ acc += tl.dot(dout, a)
148
+ dout_ptrs += BLOCK_SIZE_CS * stride_dout_csize_m
149
+ a_ptrs += BLOCK_SIZE_CS * stride_a_seqlen
150
+
151
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
152
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
153
+ if HAS_RESIDUAL:
154
+ res_ptr += pid_b * stride_res_batch + pid_c * chunk_size * stride_res_seqlen + pid_h * stride_res_head
155
+ res_ptrs = res_ptr + (offs_m[:, None] * stride_res_seqlen + offs_n[None, :] * stride_res_k)
156
+ res = tl.load(res_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < K)).to(tl.float32)
157
+ acc += res
158
+ db = acc.to(db_ptr.dtype.element_ty)
159
+
160
+ db_ptr += pid_b * stride_db_batch + pid_c * chunk_size * stride_db_seqlen + pid_h * stride_db_head
161
+ db_ptrs = db_ptr + (offs_m[:, None] * stride_db_seqlen + offs_n[None, :] * stride_db_k)
162
+ tl.store(db_ptrs, db, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < K))
163
+
164
+
165
+ def _bmm_chunk_fwd(a, b, chunk_size, seq_idx=None, causal=False, output_dtype=None):
166
+ """
167
+ Argument:
168
+ a: (batch, seqlen, k) or (batch, seqlen, ngroups, k)
169
+ b: (batch, seqlen, k) or (batch, seqlen, ngroups, k)
170
+ seq_idx: (batch, seqlen) or None. out[i, j] for seq_idx[i] != seq_idx[j] will be zeroed out.
171
+ causal: if True, then out[i, j] for i > j will be arbitrary, only out[i, j] for i <= j are
172
+ guaranteed to be correct.
173
+ Return:
174
+ out: (batch, nchunks, chunk_size, chunk_size) or (batch, nchunks, ngroups, chunk_size, chunk_size)
175
+ """
176
+ # Check constraints.
177
+ has_groups = a.dim() == 4
178
+ if not has_groups:
179
+ batch, seqlen, k = a.shape
180
+ else:
181
+ batch, seqlen, ngroups, k = a.shape
182
+ assert b.shape == a.shape
183
+ if seq_idx is not None:
184
+ assert seq_idx.shape == (batch, seqlen)
185
+ if a.stride(-1) != 1 and a.stride(1) != 1:
186
+ a = a.contiguous()
187
+ if b.stride(-1) != 1 and b.stride(1) != 1:
188
+ b = b.contiguous()
189
+ nchunks = math.ceil(seqlen / chunk_size)
190
+ # Allocates output.
191
+ out_dtype = a.dtype if output_dtype is None else output_dtype
192
+ out = torch.empty((batch, nchunks, chunk_size, chunk_size) if not has_groups else (batch, nchunks, ngroups, chunk_size, chunk_size),
193
+ device=a.device, dtype=out_dtype)
194
+ dot_dtype = (tl.bfloat16 if a.dtype == torch.bfloat16 or b.dtype == torch.bfloat16 else
195
+ (tl.float16 if a.dtype == torch.float16 or b.dtype == torch.float16 else tl.float32))
196
+ grid = lambda META: (triton.cdiv(chunk_size, META['BLOCK_SIZE_M']) * triton.cdiv(chunk_size, META['BLOCK_SIZE_N']),
197
+ batch, nchunks if not has_groups else nchunks * ngroups)
198
+ with device_guard(a):
199
+ _bmm_chunk_fwd_kernel[grid](
200
+ a, b, out, seq_idx,
201
+ seqlen, chunk_size, k, ngroups if has_groups else 1,
202
+ a.stride(0), a.stride(1), 0 if not has_groups else a.stride(2), a.stride(-1),
203
+ b.stride(0), b.stride(1), 0 if not has_groups else b.stride(2), b.stride(-1),
204
+ out.stride(0), out.stride(1), 0 if not has_groups else out.stride(2), out.stride(-2), out.stride(-1),
205
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
206
+ causal,
207
+ dot_dtype,
208
+ HAS_SEQ_IDX=seq_idx is not None,
209
+ )
210
+ return out
211
+
212
+
213
+ def _bmm_chunk_bwd(a, dout, residual=None, out=None):
214
+ """
215
+ Argument:
216
+ a: (batch, seqlen, k) or (batch, seqlen, ngroups, k)
217
+ dout: (batch, nchunks, chunk_size, chunk_size) or (batch, nchunks, ngroups, chunk_size, chunk_size)
218
+ residual: (batch, seqlen, k) or (batch, seqlen, ngroups, k)
219
+ Return:
220
+ out: (batch, seqlen, k) or (batch, seqlen, ngroups, k)
221
+
222
+ If there was seq_idx in the fwd pass, then dout[i, j] for seq_idx[i] != seq_idx[j] should already be
223
+ zeroed out before calling this function.
224
+ """
225
+ # Check constraints.
226
+ has_groups = a.dim() == 4
227
+ if not has_groups:
228
+ batch, seqlen, k = a.shape
229
+ else:
230
+ batch, seqlen, ngroups, k = a.shape
231
+ nchunks, chunk_size = dout.shape[1], dout.shape[-1]
232
+ if a.stride(-1) != 1 and a.stride(-2) != 1:
233
+ a = a.contiguous()
234
+ if dout.stride(-1) != 1 and dout.stride(-2) != 1:
235
+ dout = dout.contiguous()
236
+ if residual is not None:
237
+ assert residual.shape == (batch, seqlen, k) if not has_groups else (batch, seqlen, ngroups, k)
238
+ if residual.stride(-1) != 1 and residual.stride(1) != 1:
239
+ residual = residual.contiguous()
240
+ # Allocates output.
241
+ if out is not None:
242
+ assert out.shape == a.shape
243
+ assert out.stride(-1) == 1 or out.stride(1) == 1
244
+ else:
245
+ out = torch.empty_like(a)
246
+ dot_dtype = (tl.bfloat16 if a.dtype == torch.bfloat16 or dout.dtype == torch.bfloat16 else
247
+ (tl.float16 if a.dtype == torch.float16 or dout.dtype == torch.float16 else tl.float32))
248
+ grid = lambda META: (triton.cdiv(chunk_size, META['BLOCK_SIZE_M']) * triton.cdiv(k, META['BLOCK_SIZE_N']), batch,
249
+ nchunks if not has_groups else nchunks * ngroups)
250
+ residual_strides = ((residual.stride(0), residual.stride(1), 0 if not has_groups else residual.stride(2),
251
+ residual.stride(-1))
252
+ if residual is not None else (0, 0, 0, 0))
253
+ with device_guard(a):
254
+ _bmm_chunk_bwd_kernel[grid](
255
+ a, dout, out, residual,
256
+ seqlen, chunk_size, k, ngroups if has_groups else 1,
257
+ a.stride(0), a.stride(1), 0 if not has_groups else a.stride(2), a.stride(-1),
258
+ dout.stride(0), dout.stride(1), 0 if not has_groups else dout.stride(2), dout.stride(-2), dout.stride(-1),
259
+ out.stride(0), out.stride(1), 0 if not has_groups else out.stride(2), out.stride(-1),
260
+ residual_strides[0], residual_strides[1], residual_strides[2], residual_strides[3],
261
+ dot_dtype,
262
+ HAS_RESIDUAL=residual is not None,
263
+ )
264
+ return out
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_chunk_scan.py ADDED
The diff for this file is too large to render. See raw diff
 
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_chunk_state.py ADDED
@@ -0,0 +1,1003 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ """We want triton==2.1.0 or 2.2.0 for this
4
+ """
5
+
6
+ import math
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ import triton
11
+ import triton.language as tl
12
+
13
+ from einops import rearrange, repeat
14
+
15
+ from ...utils.device import device_guard, get_sm_count
16
+
17
+ from .softplus import softplus
18
+
19
+
20
+ def init_to_zero(names):
21
+ return lambda nargs: [nargs[name].zero_() for name in names if nargs[name] is not None]
22
+
23
+ @triton.autotune(
24
+ configs=[
25
+ triton.Config({'BLOCK_SIZE_H': 1}),
26
+ triton.Config({'BLOCK_SIZE_H': 2}),
27
+ triton.Config({'BLOCK_SIZE_H': 4}),
28
+ triton.Config({'BLOCK_SIZE_H': 8}),
29
+ triton.Config({'BLOCK_SIZE_H': 16}),
30
+ triton.Config({'BLOCK_SIZE_H': 32}),
31
+ triton.Config({'BLOCK_SIZE_H': 64}),
32
+ ],
33
+ key=['chunk_size', 'nheads'],
34
+ )
35
+ @triton.jit
36
+ def _chunk_cumsum_fwd_kernel(
37
+ # Pointers to matrices
38
+ dt_ptr, A_ptr, dt_bias_ptr, dt_out_ptr, dA_cumsum_ptr,
39
+ # Matrix dimension
40
+ batch, seqlen, nheads, chunk_size,
41
+ dt_min, dt_max,
42
+ # Strides
43
+ stride_dt_batch, stride_dt_seqlen, stride_dt_head,
44
+ stride_A_head,
45
+ stride_dt_bias_head,
46
+ stride_dt_out_batch, stride_dt_out_chunk, stride_dt_out_head, stride_dt_out_csize,
47
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
48
+ # Meta-parameters
49
+ DT_SOFTPLUS: tl.constexpr,
50
+ HAS_DT_BIAS: tl.constexpr,
51
+ BLOCK_SIZE_H: tl.constexpr, BLOCK_SIZE_CHUNK: tl.constexpr,
52
+ ):
53
+ pid_b = tl.program_id(axis=0)
54
+ pid_c = tl.program_id(axis=1)
55
+ pid_h = tl.program_id(axis=2)
56
+ dt_ptr += pid_b * stride_dt_batch + pid_c * chunk_size * stride_dt_seqlen
57
+ dt_out_ptr += pid_b * stride_dt_out_batch + pid_c * stride_dt_out_chunk
58
+ dA_cumsum_ptr += pid_b * stride_dA_cs_batch + pid_c * stride_dA_cs_chunk
59
+
60
+ offs_h = pid_h * BLOCK_SIZE_H + tl.arange(0, BLOCK_SIZE_H)
61
+ offs_c = tl.arange(0, BLOCK_SIZE_CHUNK)
62
+ dt_ptrs = dt_ptr + (offs_h[:, None] * stride_dt_head + offs_c[None, :] * stride_dt_seqlen)
63
+ A_ptrs = A_ptr + offs_h * stride_A_head
64
+ dt_out_ptrs = dt_out_ptr + (offs_h[:, None] * stride_dt_out_head + offs_c[None, :] * stride_dt_out_csize)
65
+ dA_cs_ptrs = dA_cumsum_ptr + (offs_h[:, None] * stride_dA_cs_head + offs_c[None, :] * stride_dA_cs_csize)
66
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
67
+
68
+ dt = tl.load(dt_ptrs, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), other=0.0).to(tl.float32)
69
+ if HAS_DT_BIAS:
70
+ dt_bias = tl.load(dt_bias_ptr + offs_h * stride_dt_bias_head, mask=offs_h < nheads, other=0.0).to(tl.float32)
71
+ dt += dt_bias[:, None]
72
+ if DT_SOFTPLUS:
73
+ dt = tl.where(dt <= 20.0, softplus(dt), dt)
74
+ # As of Triton 2.2.0, tl.clamp is not available yet
75
+ # dt = tl.clamp(dt, dt_min, dt_max)
76
+ dt = tl.minimum(tl.maximum(dt, dt_min), dt_max)
77
+ dt = tl.where((offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), dt, 0.0)
78
+ tl.store(dt_out_ptrs, dt, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size))
79
+ A = tl.load(A_ptrs, mask=offs_h < nheads, other=0.0).to(tl.float32)
80
+ dA = dt * A[:, None]
81
+ dA_cs = tl.cumsum(dA, axis=1)
82
+ tl.store(dA_cs_ptrs, dA_cs, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size))
83
+
84
+
85
+ @triton.autotune(
86
+ configs=[
87
+ triton.Config({'BLOCK_SIZE_H': 1}),
88
+ triton.Config({'BLOCK_SIZE_H': 2}),
89
+ triton.Config({'BLOCK_SIZE_H': 4}),
90
+ triton.Config({'BLOCK_SIZE_H': 8}),
91
+ triton.Config({'BLOCK_SIZE_H': 16}),
92
+ triton.Config({'BLOCK_SIZE_H': 32}),
93
+ triton.Config({'BLOCK_SIZE_H': 64}),
94
+ ],
95
+ key=['chunk_size', 'nheads'],
96
+ reset_to_zero=["dA_ptr", "ddt_bias_ptr"],
97
+ )
98
+ @triton.jit
99
+ def _chunk_cumsum_bwd_kernel(
100
+ # Pointers to matrices
101
+ ddA_ptr, ddt_out_ptr, dt_ptr, A_ptr, dt_bias_ptr,
102
+ ddt_ptr, dA_ptr, ddt_bias_ptr,
103
+ # Matrix dimensions
104
+ batch, seqlen, nheads, chunk_size,
105
+ dt_min, dt_max,
106
+ # Strides
107
+ stride_ddA_batch, stride_ddA_chunk, stride_ddA_head, stride_ddA_csize,
108
+ stride_ddt_out_batch, stride_ddt_out_chunk, stride_ddt_out_head, stride_ddt_out_csize,
109
+ stride_dt_batch, stride_dt_seqlen, stride_dt_head,
110
+ stride_A_head,
111
+ stride_dt_bias_head,
112
+ stride_ddt_batch, stride_ddt_seqlen, stride_ddt_head,
113
+ stride_dA_head,
114
+ stride_ddt_bias_head,
115
+ # Meta-parameters
116
+ DT_SOFTPLUS: tl.constexpr,
117
+ HAS_DT_BIAS: tl.constexpr,
118
+ BLOCK_SIZE_H: tl.constexpr, BLOCK_SIZE_CHUNK: tl.constexpr,
119
+ ):
120
+ pid_b = tl.program_id(axis=0)
121
+ pid_c = tl.program_id(axis=1)
122
+ pid_h = tl.program_id(axis=2)
123
+ ddt_out_ptr += pid_b * stride_ddt_out_batch + pid_c * stride_ddt_out_chunk
124
+ ddA_ptr += pid_b * stride_ddA_batch + pid_c * stride_ddA_chunk
125
+ dt_ptr += pid_b * stride_dt_batch + pid_c * chunk_size * stride_dt_seqlen
126
+ ddt_ptr += pid_b * stride_ddt_batch + pid_c * chunk_size * stride_ddt_seqlen
127
+
128
+ offs_h = pid_h * BLOCK_SIZE_H + tl.arange(0, BLOCK_SIZE_H)
129
+ offs_c = tl.arange(0, BLOCK_SIZE_CHUNK)
130
+ ddt_out_ptrs = ddt_out_ptr + (offs_h[:, None] * stride_ddt_out_head + offs_c[None, :] * stride_ddt_out_csize)
131
+ ddA_ptrs = ddA_ptr + (offs_h[:, None] * stride_ddA_head + offs_c[None, :] * stride_ddA_csize)
132
+ dt_ptrs = dt_ptr + (offs_h[:, None] * stride_dt_head + offs_c[None, :] * stride_dt_seqlen)
133
+ ddt_ptrs = ddt_ptr + (offs_h[:, None] * stride_ddt_head + offs_c[None, :] * stride_ddt_seqlen)
134
+ A_ptrs = A_ptr + offs_h * stride_A_head
135
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
136
+
137
+ ddA = tl.load(ddA_ptrs, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), other=0.0).to(tl.float32)
138
+ ddt_out = tl.load(ddt_out_ptrs, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), other=0.0).to(tl.float32)
139
+ A = tl.load(A_ptrs, mask=offs_h < nheads, other=0.0).to(tl.float32)
140
+ ddt = ddA * A[:, None] + ddt_out
141
+ dt = tl.load(dt_ptrs, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), other=0.0).to(tl.float32)
142
+ if HAS_DT_BIAS:
143
+ dt_bias = tl.load(dt_bias_ptr + offs_h * stride_dt_bias_head, mask=offs_h < nheads, other=0.0).to(tl.float32)
144
+ dt += dt_bias[:, None]
145
+ if DT_SOFTPLUS:
146
+ dt_presoftplus = dt
147
+ dt = tl.where(dt <= 20.0, softplus(dt), dt)
148
+ clamp_mask = (dt < dt_min) | (dt > dt_max)
149
+ # As of Triton 2.2.0, tl.clamp is not available yet
150
+ # dt = tl.clamp(dt, dt_min, dt_max)
151
+ dt = tl.minimum(tl.maximum(dt, dt_min), dt_max)
152
+ dt = tl.where((offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), dt, 0.0)
153
+ ddt = tl.where((offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit), ddt, 0.0)
154
+ ddt = tl.where(clamp_mask, 0.0, ddt)
155
+ if DT_SOFTPLUS:
156
+ ddt = tl.where(dt_presoftplus <= 20.0, ddt * tl.sigmoid(dt_presoftplus), ddt)
157
+ tl.store(ddt_ptrs, ddt, mask=(offs_h[:, None] < nheads) & (offs_c[None, :] < chunk_size_limit))
158
+ dA = tl.sum(ddA * dt, axis=1)
159
+ tl.atomic_add(dA_ptr + offs_h * stride_dA_head, dA, mask=offs_h < nheads)
160
+ if HAS_DT_BIAS:
161
+ ddt_bias = tl.sum(ddt, axis=1)
162
+ tl.atomic_add(ddt_bias_ptr + offs_h * stride_ddt_bias_head, ddt_bias, mask=offs_h < nheads)
163
+
164
+
165
+ @triton.autotune(
166
+ configs=[
167
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 64}, num_stages=3, num_warps=8),
168
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
169
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
170
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
171
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
172
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
173
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
174
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
175
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=2),
176
+ ],
177
+ key=['hdim', 'dstate', 'chunk_size'],
178
+ )
179
+ @triton.jit
180
+ def _chunk_state_fwd_kernel(
181
+ # Pointers to matrices
182
+ x_ptr, b_ptr, states_ptr, dt_ptr, dA_cumsum_ptr, seq_idx_ptr,
183
+ # Matrix dimensions
184
+ hdim, dstate, chunk_size,
185
+ batch, seqlen, nheads_ngroups_ratio,
186
+ # Strides
187
+ stride_x_batch, stride_x_seqlen, stride_x_head, stride_x_hdim,
188
+ stride_b_batch, stride_b_seqlen, stride_b_head, stride_b_dstate,
189
+ stride_states_batch, stride_states_chunk, stride_states_head, stride_states_hdim, stride_states_dstate,
190
+ stride_dt_batch, stride_dt_chunk, stride_dt_head, stride_dt_csize,
191
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
192
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
193
+ # Meta-parameters
194
+ HAS_SEQ_IDX: tl.constexpr,
195
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
196
+ ):
197
+ pid_bc = tl.program_id(axis=1)
198
+ pid_c = pid_bc // batch
199
+ pid_b = pid_bc - pid_c * batch
200
+ pid_h = tl.program_id(axis=2)
201
+ num_pid_n = tl.cdiv(dstate, BLOCK_SIZE_N)
202
+ pid_m = tl.program_id(axis=0) // num_pid_n
203
+ pid_n = tl.program_id(axis=0) % num_pid_n
204
+ b_ptr += pid_b * stride_b_batch + pid_c * chunk_size * stride_b_seqlen + (pid_h // nheads_ngroups_ratio) * stride_b_head
205
+ x_ptr += pid_b * stride_x_batch + pid_c * chunk_size * stride_x_seqlen + pid_h * stride_x_head
206
+ dt_ptr += pid_b * stride_dt_batch + pid_c * stride_dt_chunk + pid_h * stride_dt_head
207
+ dA_cumsum_ptr += pid_b * stride_dA_cs_batch + pid_c * stride_dA_cs_chunk + pid_h * stride_dA_cs_head
208
+ if HAS_SEQ_IDX:
209
+ seq_idx_ptr += pid_b * stride_seq_idx_batch + pid_c * chunk_size * stride_seq_idx_seqlen
210
+
211
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
212
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
213
+ offs_k = tl.arange(0, BLOCK_SIZE_K)
214
+ x_ptrs = x_ptr + (offs_m[:, None] * stride_x_hdim + offs_k[None, :] * stride_x_seqlen)
215
+ b_ptrs = b_ptr + (offs_n[None, :] * stride_b_dstate + offs_k[:, None] * stride_b_seqlen)
216
+ dt_ptrs = dt_ptr + offs_k * stride_dt_csize
217
+ dA_cs_last = tl.load(dA_cumsum_ptr + (chunk_size - 1) * stride_dA_cs_csize).to(tl.float32)
218
+ dA_cumsum_ptrs = dA_cumsum_ptr + offs_k * stride_dA_cs_csize
219
+ if HAS_SEQ_IDX:
220
+ seq_idx_ptrs = seq_idx_ptr + offs_k * stride_seq_idx_seqlen
221
+
222
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
223
+ if HAS_SEQ_IDX:
224
+ seq_idx_last = tl.load(seq_idx_ptr + (chunk_size_limit - 1) * stride_seq_idx_seqlen)
225
+
226
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
227
+ for k in range(0, chunk_size_limit, BLOCK_SIZE_K):
228
+ x = tl.load(x_ptrs, mask=(offs_m[:, None] < hdim) & (offs_k[None, :] < chunk_size_limit - k), other=0.0)
229
+ b = tl.load(b_ptrs, mask=(offs_k[:, None] < chunk_size_limit - k) & (offs_n[None, :] < dstate), other=0.0).to(tl.float32)
230
+ dA_cs_k = tl.load(dA_cumsum_ptrs, mask=offs_k < chunk_size_limit - k, other=0.0).to(tl.float32)
231
+ if HAS_SEQ_IDX:
232
+ seq_idx_k = tl.load(seq_idx_ptrs, mask=offs_k < chunk_size_limit - k, other=-1)
233
+ dt_k = tl.load(dt_ptrs, mask=offs_k < chunk_size_limit - k, other=0.0).to(tl.float32)
234
+ if not HAS_SEQ_IDX:
235
+ # scale = tl.exp((dA_cs_last - dA_cs_k)) * dt_k
236
+ scale = tl.exp(tl.minimum((dA_cs_last - dA_cs_k), 0.0)) * dt_k
237
+ else:
238
+ # scale = tl.where(seq_idx_k == seq_idx_last, tl.exp((dA_cs_last - dA_cs_k)) * dt_k, 0.0)
239
+ scale = tl.where((seq_idx_last >= 0) & (seq_idx_k == seq_idx_last), tl.exp(tl.minimum((dA_cs_last - dA_cs_k), 0.0)) * dt_k, 0.0)
240
+ b *= scale[:, None]
241
+ b = b.to(x_ptr.dtype.element_ty)
242
+ acc += tl.dot(x, b)
243
+ x_ptrs += BLOCK_SIZE_K * stride_x_seqlen
244
+ b_ptrs += BLOCK_SIZE_K * stride_b_seqlen
245
+ dt_ptrs += BLOCK_SIZE_K * stride_dt_csize
246
+ dA_cumsum_ptrs += BLOCK_SIZE_K * stride_dA_cs_csize
247
+ if HAS_SEQ_IDX:
248
+ seq_idx_ptrs += BLOCK_SIZE_K * stride_seq_idx_seqlen
249
+ states = acc.to(states_ptr.dtype.element_ty)
250
+
251
+ states_ptr += pid_b * stride_states_batch + pid_c * stride_states_chunk + pid_h * stride_states_head
252
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
253
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
254
+ states_ptrs = states_ptr + (offs_m[:, None] * stride_states_hdim + offs_n[None, :] * stride_states_dstate)
255
+ c_mask = (offs_m[:, None] < hdim) & (offs_n[None, :] < dstate)
256
+ tl.store(states_ptrs, states, mask=c_mask)
257
+
258
+
259
+ @triton.autotune(
260
+ configs=[
261
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 64}, num_stages=3, num_warps=8, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
262
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
263
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
264
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
265
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
266
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
267
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
268
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
269
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddt_ptr", "ddA_cumsum_ptr"])),
270
+ ],
271
+ key=['chunk_size', 'hdim', 'dstate'],
272
+ )
273
+ @triton.jit
274
+ def _chunk_state_bwd_dx_kernel(
275
+ # Pointers to matrices
276
+ x_ptr, b_ptr, dstates_ptr, dt_ptr, dA_cumsum_ptr,
277
+ dx_ptr, ddt_ptr, ddA_cumsum_ptr,
278
+ # Matrix dimensions
279
+ chunk_size, hdim, dstate,
280
+ batch, seqlen, nheads_ngroups_ratio,
281
+ # Strides
282
+ stride_x_batch, stride_x_seqlen, stride_x_head, stride_x_hdim,
283
+ stride_b_batch, stride_b_seqlen, stride_b_head, stride_b_dstate,
284
+ stride_dstates_batch, stride_dstates_chunk, stride_states_head, stride_states_hdim, stride_states_dstate,
285
+ stride_dt_batch, stride_dt_chunk, stride_dt_head, stride_dt_csize,
286
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
287
+ stride_dx_batch, stride_dx_seqlen, stride_dx_head, stride_dx_hdim,
288
+ stride_ddt_batch, stride_ddt_chunk, stride_ddt_head, stride_ddt_csize,
289
+ stride_ddA_cs_batch, stride_ddA_cs_chunk, stride_ddA_cs_head, stride_ddA_cs_csize,
290
+ # Meta-parameters
291
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
292
+ BLOCK_SIZE_DSTATE: tl.constexpr,
293
+ ):
294
+ pid_bc = tl.program_id(axis=1)
295
+ pid_c = pid_bc // batch
296
+ pid_b = pid_bc - pid_c * batch
297
+ pid_h = tl.program_id(axis=2)
298
+ num_pid_n = tl.cdiv(hdim, BLOCK_SIZE_N)
299
+ pid_m = tl.program_id(axis=0) // num_pid_n
300
+ pid_n = tl.program_id(axis=0) % num_pid_n
301
+ x_ptr += pid_b * stride_x_batch + pid_c * chunk_size * stride_x_seqlen + pid_h * stride_x_head
302
+ b_ptr += pid_b * stride_b_batch + pid_c * chunk_size * stride_b_seqlen + (pid_h // nheads_ngroups_ratio) * stride_b_head
303
+ dstates_ptr += pid_b * stride_dstates_batch + pid_c * stride_dstates_chunk + pid_h * stride_states_head
304
+ dt_ptr += pid_b * stride_dt_batch + pid_c * stride_dt_chunk + pid_h * stride_dt_head
305
+ ddt_ptr += pid_b * stride_ddt_batch + pid_c * stride_ddt_chunk + pid_h * stride_ddt_head
306
+ ddA_cumsum_ptr += pid_b * stride_ddA_cs_batch + pid_c * stride_ddA_cs_chunk + pid_h * stride_ddA_cs_head
307
+ dA_cumsum_ptr += pid_b * stride_dA_cs_batch + pid_c * stride_dA_cs_chunk + pid_h * stride_dA_cs_head
308
+
309
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
310
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
311
+
312
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
313
+ # Faster to just do 1 iteration with larger BLOCK_SIZE_K, up to block size 128
314
+ offs_k = tl.arange(0, BLOCK_SIZE_DSTATE if BLOCK_SIZE_DSTATE <= 128 else BLOCK_SIZE_K)
315
+ b_ptrs = b_ptr + (offs_m[:, None] * stride_b_seqlen + offs_k[None, :] * stride_b_dstate)
316
+ dstates_ptrs = dstates_ptr + (offs_n[None, :] * stride_states_hdim + offs_k[:, None] * stride_states_dstate)
317
+ if BLOCK_SIZE_DSTATE <= 128:
318
+ b = tl.load(b_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < dstate), other=0.0)
319
+ dstates = tl.load(dstates_ptrs, mask=(offs_k[:, None] < dstate) & (offs_n[None, :] < hdim), other=0.0)
320
+ dstates = dstates.to(b_ptr.dtype.element_ty)
321
+ acc = tl.dot(b, dstates)
322
+ else:
323
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
324
+ for k in range(0, dstate, BLOCK_SIZE_K):
325
+ b = tl.load(b_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < dstate - k), other=0.0)
326
+ dstates = tl.load(dstates_ptrs, mask=(offs_k[:, None] < dstate - k) & (offs_n[None, :] < hdim), other=0.0)
327
+ dstates = dstates.to(b_ptr.dtype.element_ty)
328
+ acc += tl.dot(b, dstates)
329
+ b_ptrs += BLOCK_SIZE_K * stride_b_dstate
330
+ dstates_ptrs += BLOCK_SIZE_K * stride_states_dstate
331
+
332
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
333
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
334
+
335
+ dA_cs_last = tl.load(dA_cumsum_ptr + (chunk_size - 1) * stride_dA_cs_csize).to(tl.float32)
336
+ dt_ptrs = dt_ptr + offs_m * stride_dt_csize
337
+ dA_cumsum_ptrs = dA_cumsum_ptr + offs_m * stride_dA_cs_csize
338
+ dA_cs_m = tl.load(dA_cumsum_ptrs, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
339
+ dt_m = tl.load(dt_ptrs, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
340
+ # acc *= tl.exp(dA_cs_last - dA_cs_m)[:, None]
341
+ acc *= tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0))[:, None]
342
+
343
+ x_ptrs = x_ptr + (offs_m[:, None] * stride_x_seqlen + offs_n[None, :] * stride_x_hdim)
344
+ x = tl.load(x_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim), other=0.0).to(tl.float32)
345
+ ddt = tl.sum(acc * x, axis=1)
346
+ ddt_ptrs = ddt_ptr + offs_m * stride_ddt_csize
347
+ tl.atomic_add(ddt_ptrs, ddt, mask=offs_m < chunk_size)
348
+ ddA_cs = -(ddt * dt_m)
349
+ ddA_cs_last = -tl.sum(ddA_cs)
350
+ ddA_cumsum_ptrs = ddA_cumsum_ptr + offs_m * stride_ddA_cs_csize
351
+ tl.atomic_add(ddA_cumsum_ptrs, ddA_cs, mask=offs_m < chunk_size)
352
+ tl.atomic_add(ddA_cumsum_ptr + (chunk_size - 1) * stride_ddA_cs_csize, ddA_cs_last)
353
+
354
+ dx = (acc * dt_m[:, None]).to(dx_ptr.dtype.element_ty)
355
+ dx_ptr += pid_b * stride_dx_batch + pid_c * chunk_size * stride_dx_seqlen + pid_h * stride_dx_head
356
+ dx_ptrs = dx_ptr + (offs_m[:, None] * stride_dx_seqlen + offs_n[None, :] * stride_dx_hdim)
357
+ tl.store(dx_ptrs, dx, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim))
358
+
359
+
360
+ @triton.autotune(
361
+ configs=[
362
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 128}, num_stages=3, num_warps=4),
363
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32}, num_stages=3, num_warps=4),
364
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128}, num_stages=3, num_warps=4),
365
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64}, num_stages=3, num_warps=4),
366
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64}, num_stages=3, num_warps=4),
367
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32}, num_stages=3, num_warps=4),
368
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64}, num_stages=3, num_warps=4),
369
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 32}, num_stages=3, num_warps=4),
370
+ ],
371
+ key=['chunk_size', 'dstate', 'hdim'],
372
+ reset_to_zero=["ddA_cumsum_ptr"],
373
+ )
374
+ @triton.jit
375
+ def _chunk_state_bwd_db_kernel(
376
+ # Pointers to matrices
377
+ x_ptr, dstates_ptr, b_ptr, dt_ptr, dA_cumsum_ptr, seq_idx_ptr,
378
+ db_ptr, ddA_cumsum_ptr,
379
+ # Matrix dimensions
380
+ chunk_size, dstate, hdim,
381
+ batch, seqlen, nheads, nheads_per_program, ngroups,
382
+ # Strides
383
+ stride_x_batch, stride_x_seqlen, stride_x_head, stride_x_hdim,
384
+ stride_dstates_batch, stride_dstates_chunk, stride_states_head, stride_states_hdim, stride_states_dstate,
385
+ stride_b_batch, stride_b_seqlen, stride_b_head, stride_b_dstate,
386
+ stride_dt_batch, stride_dt_chunk, stride_dt_head, stride_dt_csize,
387
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
388
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
389
+ stride_db_batch, stride_db_seqlen, stride_db_split, stride_db_group, stride_db_dstate,
390
+ stride_ddA_cs_batch, stride_ddA_cs_chunk, stride_ddA_cs_head, stride_ddA_cs_csize,
391
+ # Meta-parameters
392
+ HAS_DDA_CS: tl.constexpr,
393
+ HAS_SEQ_IDX: tl.constexpr,
394
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
395
+ ):
396
+ pid_bc = tl.program_id(axis=1)
397
+ pid_c = pid_bc // batch
398
+ pid_b = pid_bc - pid_c * batch
399
+ pid_sg = tl.program_id(axis=2)
400
+ pid_s = pid_sg // ngroups
401
+ pid_g = pid_sg - pid_s * ngroups
402
+ num_pid_n = tl.cdiv(dstate, BLOCK_SIZE_N)
403
+ pid_m = tl.program_id(axis=0) // num_pid_n
404
+ pid_n = tl.program_id(axis=0) % num_pid_n
405
+ x_ptr += pid_b * stride_x_batch + pid_c * chunk_size * stride_x_seqlen + (pid_g * (nheads // ngroups) + pid_s * nheads_per_program) * stride_x_head
406
+ db_ptr += pid_b * stride_db_batch + pid_c * chunk_size * stride_db_seqlen + pid_g * stride_db_group + pid_s * stride_db_split
407
+ dstates_ptr += pid_b * stride_dstates_batch + pid_c * stride_dstates_chunk + (pid_g * (nheads // ngroups) + pid_s * nheads_per_program) * stride_states_head
408
+ dt_ptr += pid_b * stride_dt_batch + pid_c * stride_dt_chunk + (pid_g * (nheads // ngroups) + pid_s * nheads_per_program) * stride_dt_head
409
+ dA_cumsum_ptr += pid_b * stride_dA_cs_batch + pid_c * stride_dA_cs_chunk + (pid_g * (nheads // ngroups) + pid_s * nheads_per_program) * stride_dA_cs_head
410
+ if HAS_DDA_CS:
411
+ b_ptr += pid_b * stride_b_batch + pid_c * chunk_size * stride_b_seqlen + pid_g * stride_b_head
412
+ ddA_cumsum_ptr += pid_b * stride_ddA_cs_batch + pid_c * stride_ddA_cs_chunk + (pid_g * (nheads // ngroups) + pid_s * nheads_per_program) * stride_ddA_cs_head
413
+ if HAS_SEQ_IDX:
414
+ seq_idx_ptr += pid_b * stride_seq_idx_batch + pid_c * chunk_size * stride_seq_idx_seqlen
415
+
416
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
417
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
418
+ offs_k = tl.arange(0, BLOCK_SIZE_K)
419
+ x_ptrs = x_ptr + (offs_m[:, None] * stride_x_seqlen + offs_k[None, :] * stride_x_hdim)
420
+ dstates_ptrs = dstates_ptr + (offs_n[None, :] * stride_states_dstate + offs_k[:, None] * stride_states_hdim)
421
+ dt_ptrs = dt_ptr + offs_m * stride_dt_csize
422
+ dA_cumsum_ptrs = dA_cumsum_ptr + offs_m * stride_dA_cs_csize
423
+ if HAS_DDA_CS:
424
+ b_ptrs = b_ptr + (offs_m[:, None] * stride_b_seqlen + offs_n[None, :] * stride_b_dstate)
425
+ ddA_cumsum_ptrs = ddA_cumsum_ptr + offs_m * stride_ddA_cs_csize
426
+
427
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
428
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
429
+ if HAS_DDA_CS:
430
+ b = tl.load(b_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < dstate), other=0.0).to(tl.float32)
431
+ if HAS_SEQ_IDX:
432
+ seq_idx_m = tl.load(seq_idx_ptr + offs_m * stride_seq_idx_seqlen, mask=offs_m < chunk_size_limit, other=-1)
433
+ seq_idx_last = tl.load(seq_idx_ptr + (chunk_size_limit - 1) * stride_seq_idx_seqlen)
434
+ nheads_iter = min(nheads_per_program, nheads // ngroups - pid_s * nheads_per_program)
435
+ for h in range(nheads_iter):
436
+ x = tl.load(x_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < hdim), other=0.0)
437
+ dstates = tl.load(dstates_ptrs, mask=(offs_k[:, None] < hdim) & (offs_n[None, :] < dstate), other=0.0)
438
+ dstates = dstates.to(x_ptrs.dtype.element_ty)
439
+ db = tl.dot(x, dstates)
440
+ dA_cs_last = tl.load(dA_cumsum_ptr + (chunk_size - 1) * stride_dA_cs_csize).to(tl.float32)
441
+ dA_cs_m = tl.load(dA_cumsum_ptrs, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
442
+ dt_m = tl.load(dt_ptrs, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
443
+ if not HAS_SEQ_IDX:
444
+ # scale = tl.exp(dA_cs_last - dA_cs_m)
445
+ scale = tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0))
446
+ else:
447
+ # scale = tl.where(seq_idx_m == seq_idx_last, tl.exp(dA_cs_last - dA_cs_m), 0.0)
448
+ scale = tl.where(seq_idx_m == seq_idx_last, tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0)), 0.0)
449
+ db *= (scale * dt_m)[:, None]
450
+ if HAS_DDA_CS:
451
+ # This is the gradient wrt (dA_cs_last - dA_cs_m), i.e. the exclusive reverse cumsum
452
+ ddA_cs = tl.sum(db * b, axis=1)
453
+ tl.atomic_add(ddA_cumsum_ptrs + stride_ddA_cs_csize, ddA_cs, mask=offs_m < chunk_size - 1)
454
+ acc += db
455
+ x_ptrs += stride_x_head
456
+ dstates_ptrs += stride_states_head
457
+ dt_ptrs += stride_dt_head
458
+ dA_cumsum_ptr += stride_dA_cs_head
459
+ dA_cumsum_ptrs += stride_dA_cs_head
460
+ if HAS_DDA_CS:
461
+ ddA_cumsum_ptrs += stride_ddA_cs_head
462
+
463
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
464
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
465
+ # if HAS_SEQ_IDX:
466
+ # seq_idx_last = tl.load(seq_idx_ptr + (chunk_size_limit - 1) * stride_seq_idx_seqlen)
467
+ # seq_idx_m = tl.load(seq_idx_ptr + offs_m * stride_seq_idx_seqlen, mask=offs_m < chunk_size_limit, other=-1)
468
+ # acc = tl.where(seq_idx_m[:, None] == seq_idx_last, acc, 0.0)
469
+ db_ptrs = db_ptr + (offs_m[:, None] * stride_db_seqlen + offs_n[None, :] * stride_db_dstate)
470
+ tl.store(db_ptrs, acc, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < dstate))
471
+
472
+
473
+ @triton.autotune(
474
+ configs=[
475
+ # triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 64}, num_stages=3, num_warps=8, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
476
+ # triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
477
+ # triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
478
+ # triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
479
+ # triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
480
+ # triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
481
+ # triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
482
+ # triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
483
+ # triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
484
+ triton.Config({'BLOCK_SIZE_N': 16, 'BLOCK_SIZE_K': 32}, num_stages=3, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
485
+ triton.Config({'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=3, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
486
+ triton.Config({'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=3, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
487
+ triton.Config({'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=3, num_warps=4, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
488
+ triton.Config({'BLOCK_SIZE_N': 16, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=8, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
489
+ triton.Config({'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=8, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
490
+ triton.Config({'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=8, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
491
+ triton.Config({'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=8, pre_hook=init_to_zero(["ddA_cumsum_ptr"])),
492
+ ],
493
+ key=['chunk_size', 'hdim', 'dstate'],
494
+ )
495
+ @triton.jit
496
+ def _chunk_state_bwd_ddAcs_stable_kernel(
497
+ # Pointers to matrices
498
+ x_ptr, b_ptr, dstates_ptr, dt_ptr, dA_cumsum_ptr, seq_idx_ptr,
499
+ ddA_cumsum_ptr,
500
+ # Matrix dimensions
501
+ chunk_size, hdim, dstate,
502
+ batch, seqlen, nheads_ngroups_ratio,
503
+ # Strides
504
+ stride_x_batch, stride_x_seqlen, stride_x_head, stride_x_hdim,
505
+ stride_b_batch, stride_b_seqlen, stride_b_head, stride_b_dstate,
506
+ stride_dstates_batch, stride_dstates_chunk, stride_states_head, stride_states_hdim, stride_states_dstate,
507
+ stride_dt_batch, stride_dt_chunk, stride_dt_head, stride_dt_csize,
508
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
509
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
510
+ stride_ddA_cs_batch, stride_ddA_cs_chunk, stride_ddA_cs_head, stride_ddA_cs_csize,
511
+ # Meta-parameters
512
+ HAS_SEQ_IDX: tl.constexpr,
513
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
514
+ BLOCK_SIZE_DSTATE: tl.constexpr,
515
+ ):
516
+ pid_bc = tl.program_id(axis=1)
517
+ pid_c = pid_bc // batch
518
+ pid_b = pid_bc - pid_c * batch
519
+ pid_h = tl.program_id(axis=2)
520
+ num_pid_n = tl.cdiv(hdim, BLOCK_SIZE_N)
521
+ pid_m = tl.program_id(axis=0) // num_pid_n
522
+ pid_n = tl.program_id(axis=0) % num_pid_n
523
+ x_ptr += pid_b * stride_x_batch + pid_c * chunk_size * stride_x_seqlen + pid_h * stride_x_head
524
+ b_ptr += pid_b * stride_b_batch + pid_c * chunk_size * stride_b_seqlen + (pid_h // nheads_ngroups_ratio) * stride_b_head
525
+ dstates_ptr += pid_b * stride_dstates_batch + pid_c * stride_dstates_chunk + pid_h * stride_states_head
526
+ dt_ptr += pid_b * stride_dt_batch + pid_c * stride_dt_chunk + pid_h * stride_dt_head
527
+ ddA_cumsum_ptr += pid_b * stride_ddA_cs_batch + pid_c * stride_ddA_cs_chunk + pid_h * stride_ddA_cs_head
528
+ dA_cumsum_ptr += pid_b * stride_dA_cs_batch + pid_c * stride_dA_cs_chunk + pid_h * stride_dA_cs_head
529
+ if HAS_SEQ_IDX:
530
+ seq_idx_ptr += pid_b * stride_seq_idx_batch + pid_c * chunk_size * stride_seq_idx_seqlen
531
+
532
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
533
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
534
+
535
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
536
+ # Faster to just do 1 iteration with larger BLOCK_SIZE_K, up to block size 128
537
+ offs_k = tl.arange(0, BLOCK_SIZE_DSTATE if BLOCK_SIZE_DSTATE <= 128 else BLOCK_SIZE_K)
538
+ b_ptrs = b_ptr + (offs_m[:, None] * stride_b_seqlen + offs_k[None, :] * stride_b_dstate)
539
+ dstates_ptrs = dstates_ptr + (offs_n[None, :] * stride_states_hdim + offs_k[:, None] * stride_states_dstate)
540
+ if BLOCK_SIZE_DSTATE <= 128:
541
+ b = tl.load(b_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < dstate), other=0.0)
542
+ dstates = tl.load(dstates_ptrs, mask=(offs_k[:, None] < dstate) & (offs_n[None, :] < hdim), other=0.0)
543
+ dstates = dstates.to(b_ptr.dtype.element_ty)
544
+ acc = tl.dot(b, dstates)
545
+ else:
546
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
547
+ for k in range(0, dstate, BLOCK_SIZE_K):
548
+ b = tl.load(b_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_k[None, :] < dstate - k), other=0.0)
549
+ dstates = tl.load(dstates_ptrs, mask=(offs_k[:, None] < dstate - k) & (offs_n[None, :] < hdim), other=0.0)
550
+ dstates = dstates.to(b_ptr.dtype.element_ty)
551
+ acc += tl.dot(b, dstates)
552
+ b_ptrs += BLOCK_SIZE_K * stride_b_dstate
553
+ dstates_ptrs += BLOCK_SIZE_K * stride_states_dstate
554
+
555
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
556
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
557
+
558
+ dA_cs_m = tl.load(dA_cumsum_ptr + offs_m * stride_dA_cs_csize, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
559
+ dA_cs_last = tl.load(dA_cumsum_ptr + (chunk_size - 1) * stride_dA_cs_csize).to(tl.float32)
560
+ if not HAS_SEQ_IDX:
561
+ # scale = tl.exp(dA_cs_last - dA_cs_m)
562
+ scale = tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0))
563
+ else:
564
+ seq_idx_m = tl.load(seq_idx_ptr + offs_m * stride_seq_idx_seqlen, mask=offs_m < chunk_size_limit, other=-1)
565
+ seq_idx_last = tl.load(seq_idx_ptr + (chunk_size_limit - 1) * stride_seq_idx_seqlen)
566
+ # scale = tl.where(seq_idx_m == seq_idx_last, tl.exp(dA_cs_last - dA_cs_m), 0.0)
567
+ scale = tl.where(seq_idx_m == seq_idx_last, tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0)), 0.0)
568
+ acc *= scale[:, None]
569
+
570
+ x_ptrs = x_ptr + (offs_m[:, None] * stride_x_seqlen + offs_n[None, :] * stride_x_hdim)
571
+ x = tl.load(x_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim), other=0.0).to(tl.float32)
572
+ dt_ptrs = dt_ptr + offs_m * stride_dt_csize
573
+ dt_m = tl.load(dt_ptrs, mask=offs_m < chunk_size, other=0.0).to(tl.float32)
574
+ ddt = tl.sum(acc * x, axis=1)
575
+ # ddA_cs = -(ddt * dt_m)
576
+ # Triton 2.2.0 errors if we have the cumsum here, so we just write it out
577
+ # then call torch.cumsum outside this kernel.
578
+ # ddA_cs = tl.cumsum(ddt * dt_m)
579
+ ddA_cs = ddt * dt_m
580
+ ddA_cumsum_ptrs = ddA_cumsum_ptr + offs_m * stride_ddA_cs_csize
581
+ # tl.atomic_add(ddA_cumsum_ptrs, ddA_cs, mask=offs_m < chunk_size)
582
+ tl.atomic_add(ddA_cumsum_ptrs + stride_ddA_cs_csize, ddA_cs, mask=offs_m < chunk_size - 1)
583
+
584
+
585
+ @triton.autotune(
586
+ configs=[
587
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 64}, num_stages=3, num_warps=8),
588
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
589
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
590
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
591
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
592
+ triton.Config({'BLOCK_SIZE_M': 128, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=4),
593
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 32, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
594
+ triton.Config({'BLOCK_SIZE_M': 32, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=5, num_warps=2),
595
+ triton.Config({'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 64, 'BLOCK_SIZE_K': 32}, num_stages=4, num_warps=2),
596
+ ],
597
+ key=['hdim', 'dstate', 'chunk_size'],
598
+ )
599
+ @triton.jit
600
+ def _chunk_state_varlen_kernel(
601
+ # Pointers to matrices
602
+ x_ptr, b_ptr, dt_ptr, dA_cumsum_ptr, chunk_states_ptr, cu_seqlens_ptr, states_ptr,
603
+ # Matrix dimensions
604
+ hdim, dstate, chunk_size,
605
+ seqlen, nheads_ngroups_ratio,
606
+ # Strides
607
+ stride_x_seqlen, stride_x_head, stride_x_hdim,
608
+ stride_b_seqlen, stride_b_head, stride_b_dstate,
609
+ stride_dt_chunk, stride_dt_head, stride_dt_csize,
610
+ stride_dA_cs_chunk, stride_dA_cs_head, stride_dA_cs_csize,
611
+ stride_chunk_states_chunk, stride_chunk_states_head, stride_chunk_states_hdim, stride_chunk_states_dstate,
612
+ stride_states_batch, stride_states_head, stride_states_hdim, stride_states_dstate,
613
+ # Meta-parameters
614
+ BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_N: tl.constexpr, BLOCK_SIZE_K: tl.constexpr,
615
+ ):
616
+ pid_b = tl.program_id(axis=1)
617
+ pid_h = tl.program_id(axis=2)
618
+ num_pid_n = tl.cdiv(dstate, BLOCK_SIZE_N)
619
+ pid_m = tl.program_id(axis=0) // num_pid_n
620
+ pid_n = tl.program_id(axis=0) % num_pid_n
621
+ end_idx = tl.load(cu_seqlens_ptr + pid_b + 1)
622
+ pid_c = (end_idx - 1) // chunk_size
623
+ b_ptr += pid_c * chunk_size * stride_b_seqlen + (pid_h // nheads_ngroups_ratio) * stride_b_head
624
+ x_ptr += pid_c * chunk_size * stride_x_seqlen + pid_h * stride_x_head
625
+ dt_ptr += pid_c * stride_dt_chunk + pid_h * stride_dt_head
626
+ dA_cumsum_ptr += pid_c * stride_dA_cs_chunk + pid_h * stride_dA_cs_head
627
+ chunk_states_ptr += pid_c * stride_chunk_states_chunk + pid_h * stride_chunk_states_head
628
+
629
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
630
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
631
+ offs_k = tl.arange(0, BLOCK_SIZE_K)
632
+ x_ptrs = x_ptr + (offs_m[:, None] * stride_x_hdim + offs_k[None, :] * stride_x_seqlen)
633
+ b_ptrs = b_ptr + (offs_n[None, :] * stride_b_dstate + offs_k[:, None] * stride_b_seqlen)
634
+ dt_ptrs = dt_ptr + offs_k * stride_dt_csize
635
+ dA_cs_last = tl.load(dA_cumsum_ptr + (end_idx - pid_c * chunk_size - 1) * stride_dA_cs_csize).to(tl.float32)
636
+ dA_cumsum_ptrs = dA_cumsum_ptr + offs_k * stride_dA_cs_csize
637
+
638
+ chunk_size_limit = end_idx - pid_c * chunk_size
639
+ start_idx = tl.load(cu_seqlens_ptr + pid_b)
640
+ start_idx_cur = tl.maximum(start_idx - pid_c * chunk_size, 0)
641
+
642
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
643
+ for k in range(0, chunk_size_limit, BLOCK_SIZE_K):
644
+ x = tl.load(x_ptrs, mask=(offs_m[:, None] < hdim) & (offs_k[None, :] < chunk_size_limit - k) & (offs_k[None, :] >= start_idx_cur - k), other=0.0)
645
+ b = tl.load(b_ptrs, mask=(offs_k[:, None] < chunk_size_limit - k) & (offs_n[None, :] < dstate) & (offs_k[:, None] >= start_idx_cur - k), other=0.0).to(tl.float32)
646
+ dA_cs_k = tl.load(dA_cumsum_ptrs, mask=offs_k < chunk_size_limit - k, other=0.0).to(tl.float32)
647
+ dt_k = tl.load(dt_ptrs, mask=offs_k < chunk_size_limit - k, other=0.0).to(tl.float32)
648
+ # scale = tl.where((offs_k >= start_idx_cur - k) & (offs_k < chunk_size_limit - k),
649
+ # tl.exp((dA_cs_last - dA_cs_k)) * dt_k, 0.0)
650
+ scale = tl.where((offs_k >= start_idx_cur - k) & (offs_k < chunk_size_limit - k),
651
+ tl.exp(tl.minimum((dA_cs_last - dA_cs_k), 0.0)) * dt_k, 0.0)
652
+ b *= scale[:, None]
653
+ b = b.to(x_ptr.dtype.element_ty)
654
+ acc += tl.dot(x, b)
655
+ x_ptrs += BLOCK_SIZE_K * stride_x_seqlen
656
+ b_ptrs += BLOCK_SIZE_K * stride_b_seqlen
657
+ dt_ptrs += BLOCK_SIZE_K * stride_dt_csize
658
+ dA_cumsum_ptrs += BLOCK_SIZE_K * stride_dA_cs_csize
659
+
660
+ # If the sequence starts after the last chunk idx, we don't need to add the contribution from the last chunk
661
+ if start_idx < pid_c * chunk_size:
662
+ chunk_states_ptrs = chunk_states_ptr + (offs_m[:, None] * stride_chunk_states_hdim + offs_n[None, :] * stride_chunk_states_dstate)
663
+ chunk_states = tl.load(chunk_states_ptrs, mask=(offs_m[:, None] < hdim) & (offs_n[None, :] < dstate), other=0.0).to(tl.float32)
664
+ # scale = tl.where(start_idx < pid_c * chunk_size, tl.exp(dA_cs_last), 0.0)
665
+ scale = tl.exp(dA_cs_last)
666
+ acc += chunk_states * scale
667
+
668
+ states = acc.to(states_ptr.dtype.element_ty)
669
+
670
+ states_ptr += pid_b * stride_states_batch + pid_h * stride_states_head
671
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
672
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
673
+ states_ptrs = states_ptr + (offs_m[:, None] * stride_states_hdim + offs_n[None, :] * stride_states_dstate)
674
+ c_mask = (offs_m[:, None] < hdim) & (offs_n[None, :] < dstate)
675
+ tl.store(states_ptrs, states, mask=c_mask)
676
+
677
+
678
+ def _chunk_cumsum_fwd(dt, A, chunk_size, dt_bias=None, dt_softplus=False, dt_limit=(0.0, float("inf"))):
679
+ batch, seqlen, nheads = dt.shape
680
+ assert A.shape == (nheads,)
681
+ if dt_bias is not None:
682
+ assert dt_bias.shape == (nheads,)
683
+ nchunks = math.ceil(seqlen / chunk_size)
684
+ dt_out = torch.empty(batch, nheads, nchunks, chunk_size, device=dt.device, dtype=torch.float32)
685
+ dA_cumsum = torch.empty(batch, nheads, nchunks, chunk_size, device=dt.device, dtype=torch.float32)
686
+ grid_chunk_cs = lambda META: (batch, nchunks, triton.cdiv(nheads, META['BLOCK_SIZE_H']))
687
+ with device_guard(dt):
688
+ _chunk_cumsum_fwd_kernel[grid_chunk_cs](
689
+ dt, A, dt_bias, dt_out, dA_cumsum,
690
+ batch, seqlen, nheads, chunk_size,
691
+ dt_limit[0], dt_limit[1],
692
+ dt.stride(0), dt.stride(1), dt.stride(2),
693
+ A.stride(0),
694
+ dt_bias.stride(0) if dt_bias is not None else 0,
695
+ dt_out.stride(0), dt_out.stride(2), dt_out.stride(1), dt_out.stride(3),
696
+ dA_cumsum.stride(0), dA_cumsum.stride(2), dA_cumsum.stride(1), dA_cumsum.stride(3),
697
+ dt_softplus,
698
+ HAS_DT_BIAS=dt_bias is not None,
699
+ BLOCK_SIZE_CHUNK=triton.next_power_of_2(chunk_size),
700
+ )
701
+ return dA_cumsum, dt_out
702
+
703
+
704
+ def _chunk_cumsum_bwd(ddA, ddt_out, dt, A, dt_bias=None, dt_softplus=False, dt_limit=(0.0, float("inf")), ddt=None):
705
+ batch, seqlen, nheads = dt.shape
706
+ _, _, nchunks, chunk_size = ddA.shape
707
+ assert ddA.shape == (batch, nheads, nchunks, chunk_size)
708
+ assert ddt_out.shape == (batch, nheads, nchunks, chunk_size)
709
+ assert A.shape == (nheads,)
710
+ if dt_bias is not None:
711
+ assert dt_bias.shape == (nheads,)
712
+ ddt_bias = torch.zeros_like(dt_bias, dtype=torch.float32)
713
+ else:
714
+ ddt_bias = None
715
+ if ddt is not None:
716
+ assert ddt.shape == dt.shape
717
+ else:
718
+ ddt = torch.empty_like(dt)
719
+ dA = torch.zeros_like(A, dtype=torch.float32)
720
+ grid_chunk_cs = lambda META: (batch, nchunks, triton.cdiv(nheads, META['BLOCK_SIZE_H']))
721
+ with device_guard(dt):
722
+ _chunk_cumsum_bwd_kernel[grid_chunk_cs](
723
+ # `reset_to_zero` needs a tensor even when the kernel ignores it (no dt_bias).
724
+ ddA, ddt_out, dt, A, dt_bias, ddt, dA, ddt_bias if ddt_bias is not None else dA.new_zeros(1),
725
+ batch, seqlen, nheads, chunk_size,
726
+ dt_limit[0], dt_limit[1],
727
+ ddA.stride(0), ddA.stride(2), ddA.stride(1), ddA.stride(3),
728
+ ddt_out.stride(0), ddt_out.stride(2), ddt_out.stride(1), ddt_out.stride(3),
729
+ dt.stride(0), dt.stride(1), dt.stride(2),
730
+ A.stride(0),
731
+ dt_bias.stride(0) if dt_bias is not None else 0,
732
+ ddt.stride(0), ddt.stride(1), ddt.stride(2),
733
+ dA.stride(0),
734
+ ddt_bias.stride(0) if ddt_bias is not None else 0,
735
+ dt_softplus,
736
+ HAS_DT_BIAS=dt_bias is not None,
737
+ BLOCK_SIZE_CHUNK=triton.next_power_of_2(chunk_size),
738
+ )
739
+ return ddt, dA, ddt_bias
740
+
741
+
742
+ def _chunk_state_fwd(B, x, dt, dA_cumsum, seq_idx=None, states=None, states_in_fp32=True):
743
+ batch, seqlen, nheads, headdim = x.shape
744
+ _, _, nchunks, chunk_size = dt.shape
745
+ _, _, ngroups, dstate = B.shape
746
+ assert nheads % ngroups == 0
747
+ assert B.shape == (batch, seqlen, ngroups, dstate)
748
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
749
+ assert dA_cumsum.shape == dt.shape
750
+ if seq_idx is not None:
751
+ assert seq_idx.shape == (batch, seqlen)
752
+ if states is not None:
753
+ assert states.shape == (batch, nchunks, nheads, headdim, dstate)
754
+ else:
755
+ states_dtype = torch.float32 if states_in_fp32 else B.dtype
756
+ states = torch.empty((batch, nchunks, nheads, headdim, dstate), device=x.device, dtype=states_dtype)
757
+ grid = lambda META: (triton.cdiv(headdim, META['BLOCK_SIZE_M']) * triton.cdiv(dstate, META['BLOCK_SIZE_N']),
758
+ batch * nchunks, nheads)
759
+ with device_guard(x):
760
+ _chunk_state_fwd_kernel[grid](
761
+ x, B, states, dt, dA_cumsum, seq_idx,
762
+ headdim, dstate, chunk_size,
763
+ batch, seqlen, nheads // ngroups,
764
+ x.stride(0), x.stride(1), x.stride(2), x.stride(3),
765
+ B.stride(0), B.stride(1), B.stride(2), B.stride(-1),
766
+ states.stride(0), states.stride(1), states.stride(2), states.stride(3), states.stride(4),
767
+ dt.stride(0), dt.stride(2), dt.stride(1), dt.stride(3),
768
+ dA_cumsum.stride(0), dA_cumsum.stride(2), dA_cumsum.stride(1), dA_cumsum.stride(3),
769
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
770
+ HAS_SEQ_IDX=seq_idx is not None,
771
+ )
772
+ return states
773
+
774
+
775
+ def _chunk_state_bwd_dx(B, x, dt, dA_cumsum, dstates, dx=None):
776
+ batch, seqlen, nheads, headdim = x.shape
777
+ _, _, nchunks, chunk_size = dt.shape
778
+ _, _, ngroups, dstate = B.shape
779
+ assert nheads % ngroups == 0
780
+ assert B.shape == (batch, seqlen, ngroups, dstate)
781
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
782
+ assert dA_cumsum.shape == dt.shape
783
+ assert dstates.shape == (batch, nchunks, nheads, headdim, dstate)
784
+ if dx is not None:
785
+ assert dx.shape == x.shape
786
+ else:
787
+ dx = torch.empty_like(x)
788
+ ddt = torch.empty(batch, nheads, nchunks, chunk_size, device=dt.device, dtype=torch.float32)
789
+ ddA_cumsum = torch.empty(batch, nheads, nchunks, chunk_size, device=dA_cumsum.device, dtype=torch.float32)
790
+ grid_dx = lambda META: (triton.cdiv(chunk_size, META['BLOCK_SIZE_M']) * triton.cdiv(headdim, META['BLOCK_SIZE_N']),
791
+ batch * nchunks, nheads)
792
+ with device_guard(x):
793
+ _chunk_state_bwd_dx_kernel[grid_dx](
794
+ x, B, dstates, dt, dA_cumsum, dx, ddt, ddA_cumsum,
795
+ chunk_size, headdim, dstate,
796
+ batch, seqlen, nheads // ngroups,
797
+ x.stride(0), x.stride(1), x.stride(2), x.stride(3),
798
+ B.stride(0), B.stride(1), B.stride(2), B.stride(-1),
799
+ dstates.stride(0), dstates.stride(1), dstates.stride(2), dstates.stride(3), dstates.stride(4),
800
+ dt.stride(0), dt.stride(2), dt.stride(1), dt.stride(3),
801
+ dA_cumsum.stride(0), dA_cumsum.stride(2), dA_cumsum.stride(1), dA_cumsum.stride(3),
802
+ dx.stride(0), dx.stride(1), dx.stride(2), dx.stride(3),
803
+ ddt.stride(0), ddt.stride(2), ddt.stride(1), ddt.stride(3),
804
+ ddA_cumsum.stride(0), ddA_cumsum.stride(2), ddA_cumsum.stride(1), ddA_cumsum.stride(3),
805
+ BLOCK_SIZE_DSTATE=max(triton.next_power_of_2(dstate), 16),
806
+ )
807
+ return dx, ddt.to(dt.dtype), ddA_cumsum.to(dA_cumsum.dtype)
808
+
809
+
810
+ def _chunk_state_bwd_db(x, dt, dA_cumsum, dstates, seq_idx=None, B=None, ngroups=1):
811
+ batch, seqlen, nheads, headdim = x.shape
812
+ _, _, nchunks, chunk_size = dt.shape
813
+ dstate = dstates.shape[-1]
814
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
815
+ assert dA_cumsum.shape == dt.shape
816
+ assert dstates.shape == (batch, nchunks, nheads, headdim, dstate)
817
+ if seq_idx is not None:
818
+ assert seq_idx.shape == (batch, seqlen)
819
+ if B is not None:
820
+ assert B.shape == (batch, seqlen, ngroups, dstate)
821
+ B_strides = (B.stride(0), B.stride(1), B.stride(2), B.stride(3))
822
+ # Zero-initialized: `reset_to_zero` only zeroes it while autotuning
823
+ ddA_cumsum = torch.zeros(batch, nheads, nchunks, chunk_size, device=x.device, dtype=torch.float32)
824
+ ddA_cumsum_strides = (ddA_cumsum.stride(0), ddA_cumsum.stride(2), ddA_cumsum.stride(1), ddA_cumsum.stride(3))
825
+ else:
826
+ B_strides = (0, 0, 0, 0)
827
+ ddA_cumsum = None
828
+ ddA_cumsum_strides = (0, 0, 0, 0)
829
+ nheads_ngroups_ratio = nheads // ngroups
830
+ sm_count = get_sm_count(x.device)
831
+ nheads_per_program = max(min(math.ceil(batch * nchunks * nheads / sm_count), nheads_ngroups_ratio), 1)
832
+ nsplits = triton.cdiv(nheads_ngroups_ratio, nheads_per_program)
833
+ dB = torch.empty(batch, seqlen, nsplits, ngroups, dstate, device=x.device, dtype=torch.float32)
834
+ grid_db = lambda META: (triton.cdiv(chunk_size, META['BLOCK_SIZE_M']) * triton.cdiv(dstate, META['BLOCK_SIZE_N']),
835
+ batch * nchunks, nsplits * ngroups)
836
+ with device_guard(x):
837
+ _chunk_state_bwd_db_kernel[grid_db](
838
+ # `reset_to_zero` needs a tensor even when the kernel ignores it (no B).
839
+ x, dstates, B, dt, dA_cumsum, seq_idx, dB, ddA_cumsum if ddA_cumsum is not None else dB.new_zeros(1),
840
+ chunk_size, dstate, headdim,
841
+ batch, seqlen, nheads, nheads_per_program, ngroups,
842
+ x.stride(0), x.stride(1), x.stride(2), x.stride(3),
843
+ dstates.stride(0), dstates.stride(1), dstates.stride(2), dstates.stride(3), dstates.stride(4),
844
+ *B_strides,
845
+ dt.stride(0), dt.stride(2), dt.stride(1), dt.stride(3),
846
+ dA_cumsum.stride(0), dA_cumsum.stride(2), dA_cumsum.stride(1), dA_cumsum.stride(3),
847
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
848
+ dB.stride(0), dB.stride(1), dB.stride(2), dB.stride(3), dB.stride(4),
849
+ *ddA_cumsum_strides,
850
+ HAS_DDA_CS=ddA_cumsum is not None,
851
+ HAS_SEQ_IDX=seq_idx is not None,
852
+ BLOCK_SIZE_K=max(triton.next_power_of_2(headdim), 16),
853
+ )
854
+ dB = dB.sum(2)
855
+ if ddA_cumsum is not None:
856
+ # The first element of ddA_cumsum is always zero, since that dA_cumsum does not contribute
857
+ # to the state of the chunk.
858
+ # torch.cumsum(ddA_cumsum[..., 1:], dim=-1, out=ddA_cumsum[..., 1:])
859
+ # But it's easier to just do the cumsum for all elements, the result will be the same.
860
+ torch.cumsum(ddA_cumsum, dim=-1, out=ddA_cumsum)
861
+ return dB if B is None else (dB, ddA_cumsum)
862
+
863
+
864
+ def _chunk_state_bwd_ddAcs_stable(B, x, dt, dA_cumsum, dstates, seq_idx=None):
865
+ batch, seqlen, nheads, headdim = x.shape
866
+ _, _, nchunks, chunk_size = dt.shape
867
+ _, _, ngroups, dstate = B.shape
868
+ assert nheads % ngroups == 0
869
+ assert B.shape == (batch, seqlen, ngroups, dstate)
870
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
871
+ assert dA_cumsum.shape == dt.shape
872
+ assert dstates.shape == (batch, nchunks, nheads, headdim, dstate)
873
+ if seq_idx is not None:
874
+ assert seq_idx.shape == (batch, seqlen)
875
+ # Use torch.empty since the Triton kernel will call init_to_zero
876
+ ddA_cumsum = torch.empty(batch, nheads, nchunks, chunk_size, device=x.device, dtype=torch.float32)
877
+ grid_ddtcs = lambda META: (triton.cdiv(chunk_size, META['BLOCK_SIZE_M']) * triton.cdiv(headdim, META['BLOCK_SIZE_N']),
878
+ batch * nchunks, nheads)
879
+ with device_guard(x):
880
+ _chunk_state_bwd_ddAcs_stable_kernel[grid_ddtcs](
881
+ x, B, dstates, dt, dA_cumsum, seq_idx, ddA_cumsum,
882
+ chunk_size, headdim, dstate,
883
+ batch, seqlen, nheads // ngroups,
884
+ x.stride(0), x.stride(1), x.stride(2), x.stride(3),
885
+ B.stride(0), B.stride(1), B.stride(2), B.stride(-1),
886
+ dstates.stride(0), dstates.stride(1), dstates.stride(2), dstates.stride(3), dstates.stride(4),
887
+ dt.stride(0), dt.stride(2), dt.stride(1), dt.stride(3),
888
+ dA_cumsum.stride(0), dA_cumsum.stride(2), dA_cumsum.stride(1), dA_cumsum.stride(3),
889
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
890
+ ddA_cumsum.stride(0), ddA_cumsum.stride(2), ddA_cumsum.stride(1), ddA_cumsum.stride(3),
891
+ HAS_SEQ_IDX=seq_idx is not None,
892
+ BLOCK_SIZE_M=max(triton.next_power_of_2(chunk_size), 16),
893
+ BLOCK_SIZE_DSTATE=max(triton.next_power_of_2(dstate), 16),
894
+ )
895
+ torch.cumsum(ddA_cumsum[..., 1:], dim=-1, out=ddA_cumsum[..., 1:])
896
+ return ddA_cumsum
897
+
898
+
899
+ def chunk_state_varlen(B, x, dt, dA_cumsum, cu_seqlens, chunk_states):
900
+ total_seqlen, nheads, headdim = x.shape
901
+ _, nchunks, chunk_size = dt.shape
902
+ _, ngroups, dstate = B.shape
903
+ batch = cu_seqlens.shape[0] - 1
904
+ cu_seqlens = cu_seqlens.contiguous()
905
+ assert nheads % ngroups == 0
906
+ assert B.shape == (total_seqlen, ngroups, dstate)
907
+ assert dt.shape == (nheads, nchunks, chunk_size)
908
+ assert dA_cumsum.shape == dt.shape
909
+ assert chunk_states.shape == (nchunks, nheads, headdim, dstate)
910
+ states = torch.empty(batch, nheads, headdim, dstate, dtype=chunk_states.dtype, device=chunk_states.device)
911
+ grid = lambda META: (triton.cdiv(headdim, META['BLOCK_SIZE_M']) * triton.cdiv(dstate, META['BLOCK_SIZE_N']),
912
+ batch, nheads)
913
+ with device_guard(x):
914
+ _chunk_state_varlen_kernel[grid](
915
+ x, B, dt, dA_cumsum, chunk_states, cu_seqlens, states,
916
+ headdim, dstate, chunk_size,
917
+ total_seqlen, nheads // ngroups,
918
+ x.stride(0), x.stride(1), x.stride(2),
919
+ B.stride(0), B.stride(1), B.stride(2),
920
+ dt.stride(1), dt.stride(0), dt.stride(2),
921
+ dA_cumsum.stride(1), dA_cumsum.stride(0), dA_cumsum.stride(2),
922
+ chunk_states.stride(0), chunk_states.stride(1), chunk_states.stride(2), chunk_states.stride(3),
923
+ states.stride(0), states.stride(1), states.stride(2), states.stride(3),
924
+ )
925
+ return states
926
+
927
+
928
+ class ChunkStateFn(torch.autograd.Function):
929
+
930
+ @staticmethod
931
+ def forward(ctx, B, x, dt, dA_cumsum, states_in_fp32=True):
932
+ batch, seqlen, nheads, headdim = x.shape
933
+ _, _, nchunks, chunk_size = dt.shape
934
+ assert seqlen <= nchunks * chunk_size
935
+ _, _, ngroups, dstate = B.shape
936
+ assert B.shape == (batch, seqlen, ngroups, dstate)
937
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
938
+ assert dA_cumsum.shape == (batch, nheads, nchunks, chunk_size)
939
+ if B.stride(-1) != 1:
940
+ B = B.contiguous()
941
+ if x.stride(-1) != 1 and x.stride(1) != 1: # Either M or K dimension should be contiguous
942
+ x = x.contiguous()
943
+ states = _chunk_state_fwd(B, x, dt, dA_cumsum, states_in_fp32=states_in_fp32)
944
+ ctx.save_for_backward(B, x, dt, dA_cumsum)
945
+ return states
946
+
947
+ @staticmethod
948
+ def backward(ctx, dstates):
949
+ B, x, dt, dA_cumsum = ctx.saved_tensors
950
+ batch, seqlen, nheads, headdim = x.shape
951
+ _, _, nchunks, chunk_size = dt.shape
952
+ _, _, ngroups, dstate = B.shape
953
+ assert dstates.shape == (batch, nchunks, nheads, headdim, dstate)
954
+ if dstates.stride(-1) != 1:
955
+ dstates = dstates.contiguous()
956
+ dx, ddt, ddA_cumsum = _chunk_state_bwd_dx(B, x, dt, dA_cumsum, dstates)
957
+ dB = _chunk_state_bwd_db(x, dt, dA_cumsum, dstates, ngroups=ngroups)
958
+ dB = dB.to(B.dtype)
959
+ return dB, dx, ddt, ddA_cumsum, None
960
+
961
+
962
+ def chunk_state(B, x, dt, dA_cumsum, states_in_fp32=True):
963
+ """
964
+ Argument:
965
+ B: (batch, seqlen, ngroups, headdim)
966
+ x: (batch, seqlen, nheads, headdim)
967
+ dt: (batch, nheads, nchunks, chunk_size)
968
+ dA_cumsum: (batch, nheads, nchunks, chunk_size)
969
+ Return:
970
+ states: (batch, nchunks, nheads, headdim, dstate)
971
+ """
972
+ return ChunkStateFn.apply(B, x, dt, dA_cumsum, states_in_fp32)
973
+
974
+
975
+ def chunk_state_ref(B, x, dt, dA_cumsum):
976
+ """
977
+ Argument:
978
+ B: (batch, seqlen, ngroups, headdim)
979
+ x: (batch, seqlen, nheads, headdim)
980
+ dt: (batch, nheads, nchunks, chunk_size)
981
+ dA_cumsum: (batch, nheads, nchunks, chunk_size)
982
+ Return:
983
+ states: (batch, nchunks, nheads, headdim, dstate)
984
+ """
985
+ # Check constraints.
986
+ batch, seqlen, nheads, headdim = x.shape
987
+ dstate = B.shape[-1]
988
+ _, _, nchunks, chunk_size = dt.shape
989
+ assert seqlen <= nchunks * chunk_size
990
+ assert x.shape == (batch, seqlen, nheads, headdim)
991
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
992
+ ngroups = B.shape[2]
993
+ assert nheads % ngroups == 0
994
+ assert B.shape == (batch, seqlen, ngroups, dstate)
995
+ B = repeat(B, "b l g d -> b l (g h) d", h=nheads // ngroups)
996
+ assert dA_cumsum.shape == (batch, nheads, nchunks, chunk_size)
997
+ if seqlen < nchunks * chunk_size:
998
+ x = F.pad(x, (0, 0, 0, 0, 0, nchunks * chunk_size - seqlen))
999
+ B = F.pad(B, (0, 0, 0, 0, 0, nchunks * chunk_size - seqlen))
1000
+ x = rearrange(x, "b (c l) h p -> b c l h p", l=chunk_size)
1001
+ B = rearrange(B, "b (c l) ... -> b c l ...", l=chunk_size)
1002
+ decay_states = torch.exp((dA_cumsum[:, :, :, -1:] - dA_cumsum))
1003
+ return torch.einsum("bclhn,bhcl,bhcl,bclhp->bchpn", B.to(x.dtype), decay_states.to(x.dtype), dt.to(x.dtype), x)
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_combined.py ADDED
@@ -0,0 +1,1908 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ """We want triton==2.1.0 or 2.2.0 for this"""
4
+
5
+ import math
6
+ from typing import Optional
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ import triton
11
+ import triton.language as tl
12
+ from einops import rearrange, repeat
13
+ from packaging import version
14
+ from torch import Tensor
15
+
16
+ try:
17
+ from ..._causal_conv1d import causal_conv1d_cuda, causal_conv1d_fn
18
+ except ImportError:
19
+ # Compiled extension, only needed by mamba_split_conv1d_scan_combined. Without
20
+ # it the pure-Triton SSD path stays importable instead of failing at module scope.
21
+ causal_conv1d_cuda = causal_conv1d_fn = None
22
+ from ...utils.torch import custom_bwd, custom_fwd
23
+ from ...utils.device import device_guard
24
+ from .k_activations import _swiglu_bwd, _swiglu_fwd
25
+ from .layernorm_gated import _layer_norm_bwd, _layer_norm_fwd, rmsnorm_fn
26
+ from .ssd_bmm import _bmm_chunk_bwd, _bmm_chunk_fwd
27
+ from .ssd_chunk_scan import (
28
+ _chunk_scan_bwd_dC,
29
+ _chunk_scan_bwd_dcb,
30
+ _chunk_scan_bwd_ddAcs_prev,
31
+ _chunk_scan_bwd_ddAcs_stable,
32
+ _chunk_scan_bwd_dstates,
33
+ _chunk_scan_bwd_dz,
34
+ _chunk_scan_fwd,
35
+ chunk_scan,
36
+ chunk_scan_ref,
37
+ )
38
+ from .ssd_chunk_state import (
39
+ _chunk_cumsum_bwd,
40
+ _chunk_cumsum_fwd,
41
+ _chunk_state_bwd_db,
42
+ _chunk_state_bwd_ddAcs_stable,
43
+ _chunk_state_fwd,
44
+ chunk_state,
45
+ chunk_state_ref,
46
+ chunk_state_varlen,
47
+ )
48
+ from .ssd_state_passing import (
49
+ _state_passing_bwd,
50
+ _state_passing_fwd,
51
+ state_passing,
52
+ state_passing_ref,
53
+ )
54
+
55
+ TRITON_22 = version.parse(triton.__version__) >= version.parse("2.2.0")
56
+
57
+
58
+ def init_to_zero(names):
59
+ return lambda nargs: [
60
+ nargs[name].zero_() for name in names if nargs[name] is not None
61
+ ]
62
+
63
+
64
+ def rearrange_and_update_stride(tensor, pattern=None, dim=2):
65
+ # ensure tensor.stride(dim) is a multiple of eight after rearranging according to pattern,
66
+ # if not call contiguous(), rearrange only if pattern is not None
67
+ tensor_rearranged = rearrange(tensor, pattern) if pattern is not None else tensor
68
+ return (
69
+ tensor_rearranged.contiguous()
70
+ if tensor_rearranged.stride(dim) % 8 != 0
71
+ else tensor_rearranged
72
+ )
73
+
74
+
75
+ @triton.autotune(
76
+ configs=[
77
+ triton.Config(
78
+ {"BLOCK_SIZE_M": 128, "BLOCK_SIZE_N": 256, "BLOCK_SIZE_K": 64},
79
+ num_stages=3,
80
+ num_warps=8,
81
+ ),
82
+ triton.Config(
83
+ {"BLOCK_SIZE_M": 64, "BLOCK_SIZE_N": 256, "BLOCK_SIZE_K": 32},
84
+ num_stages=4,
85
+ num_warps=4,
86
+ ),
87
+ triton.Config(
88
+ {"BLOCK_SIZE_M": 128, "BLOCK_SIZE_N": 128, "BLOCK_SIZE_K": 32},
89
+ num_stages=4,
90
+ num_warps=4,
91
+ ),
92
+ triton.Config(
93
+ {"BLOCK_SIZE_M": 128, "BLOCK_SIZE_N": 64, "BLOCK_SIZE_K": 32},
94
+ num_stages=4,
95
+ num_warps=4,
96
+ ),
97
+ triton.Config(
98
+ {"BLOCK_SIZE_M": 64, "BLOCK_SIZE_N": 128, "BLOCK_SIZE_K": 32},
99
+ num_stages=4,
100
+ num_warps=4,
101
+ ),
102
+ triton.Config(
103
+ {"BLOCK_SIZE_M": 128, "BLOCK_SIZE_N": 32, "BLOCK_SIZE_K": 32},
104
+ num_stages=4,
105
+ num_warps=4,
106
+ ),
107
+ triton.Config(
108
+ {"BLOCK_SIZE_M": 64, "BLOCK_SIZE_N": 32, "BLOCK_SIZE_K": 32},
109
+ num_stages=5,
110
+ num_warps=4,
111
+ ),
112
+ triton.Config(
113
+ {"BLOCK_SIZE_M": 32, "BLOCK_SIZE_N": 64, "BLOCK_SIZE_K": 32},
114
+ num_stages=5,
115
+ num_warps=4,
116
+ ),
117
+ triton.Config(
118
+ {"BLOCK_SIZE_M": 64, "BLOCK_SIZE_N": 64, "BLOCK_SIZE_K": 32},
119
+ num_stages=4,
120
+ num_warps=4,
121
+ ),
122
+ ],
123
+ key=["chunk_size", "hdim", "dstate"],
124
+ reset_to_zero=["ddt_ptr", "dD_ptr"],
125
+ )
126
+ @triton.jit
127
+ def _chunk_scan_chunk_state_bwd_dx_kernel(
128
+ # Pointers to matrices
129
+ x_ptr,
130
+ cb_ptr,
131
+ dout_ptr,
132
+ dt_ptr,
133
+ dA_cumsum_ptr,
134
+ seq_idx_ptr,
135
+ D_ptr,
136
+ b_ptr,
137
+ dstates_ptr,
138
+ dx_ptr,
139
+ ddt_ptr,
140
+ dD_ptr,
141
+ # Matrix dimensions
142
+ chunk_size,
143
+ hdim,
144
+ dstate,
145
+ batch,
146
+ seqlen,
147
+ nheads_ngroups_ratio,
148
+ # Strides
149
+ stride_x_batch,
150
+ stride_x_seqlen,
151
+ stride_x_head,
152
+ stride_x_hdim,
153
+ stride_cb_batch,
154
+ stride_cb_chunk,
155
+ stride_cb_head,
156
+ stride_cb_csize_m,
157
+ stride_cb_csize_k,
158
+ stride_dout_batch,
159
+ stride_dout_seqlen,
160
+ stride_dout_head,
161
+ stride_dout_hdim,
162
+ stride_dt_batch,
163
+ stride_dt_chunk,
164
+ stride_dt_head,
165
+ stride_dt_csize,
166
+ stride_dA_cs_batch,
167
+ stride_dA_cs_chunk,
168
+ stride_dA_cs_head,
169
+ stride_dA_cs_csize,
170
+ stride_seq_idx_batch,
171
+ stride_seq_idx_seqlen,
172
+ stride_D_head,
173
+ stride_b_batch,
174
+ stride_b_seqlen,
175
+ stride_b_head,
176
+ stride_b_dstate,
177
+ stride_dstates_batch,
178
+ stride_dstates_chunk,
179
+ stride_dstates_head,
180
+ stride_dstates_hdim,
181
+ stride_dstates_dstate,
182
+ stride_dx_batch,
183
+ stride_dx_seqlen,
184
+ stride_dx_head,
185
+ stride_dx_hdim,
186
+ stride_ddt_batch,
187
+ stride_ddt_chunk,
188
+ stride_ddt_head,
189
+ stride_ddt_csize,
190
+ stride_dD_batch,
191
+ stride_dD_chunk,
192
+ stride_dD_head,
193
+ stride_dD_csize,
194
+ stride_dD_hdim,
195
+ # Meta-parameters
196
+ HAS_D: tl.constexpr,
197
+ D_HAS_HDIM: tl.constexpr,
198
+ HAS_SEQ_IDX: tl.constexpr,
199
+ BLOCK_SIZE_M: tl.constexpr,
200
+ BLOCK_SIZE_N: tl.constexpr,
201
+ BLOCK_SIZE_K: tl.constexpr,
202
+ BLOCK_SIZE_DSTATE: tl.constexpr,
203
+ IS_TRITON_22: tl.constexpr,
204
+ ):
205
+ pid_bc = tl.program_id(axis=1)
206
+ pid_c = pid_bc // batch
207
+ pid_b = pid_bc - pid_c * batch
208
+ pid_h = tl.program_id(axis=2)
209
+ num_pid_n = tl.cdiv(hdim, BLOCK_SIZE_N)
210
+ pid_m = tl.program_id(axis=0) // num_pid_n
211
+ pid_n = tl.program_id(axis=0) % num_pid_n
212
+ x_ptr += (
213
+ pid_b * stride_x_batch
214
+ + pid_c * chunk_size * stride_x_seqlen
215
+ + pid_h * stride_x_head
216
+ )
217
+ cb_ptr += (
218
+ pid_b * stride_cb_batch
219
+ + pid_c * stride_cb_chunk
220
+ + (pid_h // nheads_ngroups_ratio) * stride_cb_head
221
+ )
222
+ dout_ptr += (
223
+ pid_b * stride_dout_batch
224
+ + pid_c * chunk_size * stride_dout_seqlen
225
+ + pid_h * stride_dout_head
226
+ )
227
+ dt_ptr += pid_b * stride_dt_batch + pid_c * stride_dt_chunk + pid_h * stride_dt_head
228
+ ddt_ptr += (
229
+ pid_b * stride_ddt_batch + pid_c * stride_ddt_chunk + pid_h * stride_ddt_head
230
+ )
231
+ dA_cumsum_ptr += (
232
+ pid_b * stride_dA_cs_batch
233
+ + pid_c * stride_dA_cs_chunk
234
+ + pid_h * stride_dA_cs_head
235
+ )
236
+ b_ptr += (
237
+ pid_b * stride_b_batch
238
+ + pid_c * chunk_size * stride_b_seqlen
239
+ + (pid_h // nheads_ngroups_ratio) * stride_b_head
240
+ )
241
+ dstates_ptr += (
242
+ pid_b * stride_dstates_batch
243
+ + pid_c * stride_dstates_chunk
244
+ + pid_h * stride_dstates_head
245
+ )
246
+ if HAS_SEQ_IDX:
247
+ seq_idx_ptr += (
248
+ pid_b * stride_seq_idx_batch + pid_c * chunk_size * stride_seq_idx_seqlen
249
+ )
250
+
251
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
252
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
253
+
254
+ chunk_size_limit = min(chunk_size, seqlen - pid_c * chunk_size)
255
+
256
+ acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32)
257
+
258
+ dA_cs_m = tl.load(
259
+ dA_cumsum_ptr + offs_m * stride_dA_cs_csize,
260
+ mask=offs_m < chunk_size_limit,
261
+ other=0.0,
262
+ ).to(tl.float32)
263
+
264
+ dA_cs_last = tl.load(dA_cumsum_ptr + (chunk_size - 1) * stride_dA_cs_csize).to(
265
+ tl.float32
266
+ )
267
+ if not HAS_SEQ_IDX:
268
+ # scale = tl.exp(dA_cs_last - dA_cs_m)
269
+ scale = tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0))
270
+ else:
271
+ seq_idx_m = tl.load(
272
+ seq_idx_ptr + offs_m * stride_seq_idx_seqlen,
273
+ mask=offs_m < chunk_size_limit,
274
+ other=-1,
275
+ )
276
+ seq_idx_last = tl.load(
277
+ seq_idx_ptr + (chunk_size_limit - 1) * stride_seq_idx_seqlen
278
+ )
279
+ # scale = tl.where(seq_idx_m == seq_idx_last, tl.exp(dA_cs_last - dA_cs_m), 0.0)
280
+ scale = tl.where(
281
+ seq_idx_m == seq_idx_last,
282
+ tl.exp(tl.minimum((dA_cs_last - dA_cs_m), 0.0)),
283
+ 0.0,
284
+ )
285
+ # Might be faster to just do 1 iteration with larger BLOCK_SIZE_K, up to block size 128
286
+ # However, we're getting error with the Triton compiler 2.1.0 for that code path:
287
+ # Unexpected mma -> mma layout conversion
288
+ # Triton 2.2.0 fixes this
289
+ offs_dstate = tl.arange(
290
+ 0,
291
+ BLOCK_SIZE_DSTATE
292
+ if IS_TRITON_22 and BLOCK_SIZE_DSTATE <= 128
293
+ else BLOCK_SIZE_K,
294
+ )
295
+ b_ptrs = b_ptr + (
296
+ offs_m[:, None] * stride_b_seqlen + offs_dstate[None, :] * stride_b_dstate
297
+ )
298
+ dstates_ptrs = dstates_ptr + (
299
+ offs_n[None, :] * stride_dstates_hdim
300
+ + offs_dstate[:, None] * stride_dstates_dstate
301
+ )
302
+ if IS_TRITON_22 and BLOCK_SIZE_DSTATE <= 128:
303
+ b = tl.load(
304
+ b_ptrs,
305
+ mask=(offs_m[:, None] < chunk_size_limit) & (offs_dstate[None, :] < dstate),
306
+ other=0.0,
307
+ )
308
+ dstates = tl.load(
309
+ dstates_ptrs,
310
+ mask=(offs_dstate[:, None] < dstate) & (offs_n[None, :] < hdim),
311
+ other=0.0,
312
+ )
313
+ dstates = dstates.to(b_ptr.dtype.element_ty)
314
+ acc = tl.dot(b, dstates) * scale[:, None]
315
+ else:
316
+ for k in range(0, dstate, BLOCK_SIZE_K):
317
+ b = tl.load(
318
+ b_ptrs,
319
+ mask=(offs_m[:, None] < chunk_size_limit)
320
+ & (offs_dstate[None, :] < dstate - k),
321
+ other=0.0,
322
+ )
323
+ dstates = tl.load(
324
+ dstates_ptrs,
325
+ mask=(offs_dstate[:, None] < dstate - k) & (offs_n[None, :] < hdim),
326
+ other=0.0,
327
+ )
328
+ dstates = dstates.to(b_ptr.dtype.element_ty)
329
+ acc += tl.dot(b, dstates)
330
+ b_ptrs += BLOCK_SIZE_K * stride_b_dstate
331
+ dstates_ptrs += BLOCK_SIZE_K * stride_dstates_dstate
332
+ acc *= scale[:, None]
333
+
334
+ # x_ptrs = x_ptr + (offs_m[:, None] * stride_x_seqlen + offs_n[None, :] * stride_x_hdim)
335
+ # x = tl.load(x_ptrs, mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim), other=0.0).to(tl.float32)
336
+ # dt_ptrs = dt_ptr + offs_m * stride_dt_csize
337
+ # dt_m = tl.load(dt_ptrs, mask=offs_m < chunk_size_limit, other=0.0).to(tl.float32)
338
+ # ddt = tl.sum(acc * x, axis=1) * dt_m
339
+ # ddt_ptrs = ddt_ptr + offs_m * stride_ddt_csize
340
+ # tl.atomic_add(ddt_ptrs, ddt, mask=offs_m < chunk_size)
341
+
342
+ offs_k = tl.arange(0, BLOCK_SIZE_K)
343
+ cb_ptrs = cb_ptr + (
344
+ offs_m[:, None] * stride_cb_csize_m + offs_k[None, :] * stride_cb_csize_k
345
+ )
346
+ dout_ptrs = dout_ptr + (
347
+ offs_k[:, None] * stride_dout_seqlen + offs_n[None, :] * stride_dout_hdim
348
+ )
349
+ dA_cumsum_ptrs = dA_cumsum_ptr + offs_k * stride_dA_cs_csize
350
+ K_MAX = chunk_size_limit
351
+ K_MIN = pid_m * BLOCK_SIZE_M
352
+ cb_ptrs += K_MIN * stride_cb_csize_k
353
+ dout_ptrs += K_MIN * stride_dout_seqlen
354
+ dA_cumsum_ptrs += K_MIN * stride_dA_cs_csize
355
+ for k in range(K_MIN, K_MAX, BLOCK_SIZE_K):
356
+ k = tl.multiple_of(k, BLOCK_SIZE_K)
357
+ # For some reason setting mask to (offs_m[:, None] < chunk_size_limit) is much slower
358
+ cb = tl.load(
359
+ cb_ptrs,
360
+ mask=(offs_m[:, None] < chunk_size) & (offs_k[None, :] < K_MAX - k),
361
+ other=0.0,
362
+ )
363
+ dout = tl.load(
364
+ dout_ptrs,
365
+ mask=(offs_k[:, None] < K_MAX - k) & (offs_n[None, :] < hdim),
366
+ other=0.0,
367
+ )
368
+ dA_cs_k = tl.load(dA_cumsum_ptrs, mask=offs_k < K_MAX - k, other=0.0).to(
369
+ tl.float32
370
+ )
371
+ # cb *= tl.exp(dA_cs_k[None, :] - dA_cs_m[:, None])
372
+ cb *= tl.exp(tl.minimum((dA_cs_k[None, :] - dA_cs_m[:, None]), 0.0))
373
+ # If we don't have the (k + offs_k[None, :] < K_MAX) mask, for indices outside this range,
374
+ # we might have dA_cs_m = 0.0 and dA_cs_k very negative, and tl.exp will return inf.
375
+ # Multiplying with cb, which is 0.0 outside the range, will make the result NaN.
376
+ # This will cause NaN in acc, and hence NaN in dx and ddt.
377
+ mask = (k + offs_k[None, :] >= offs_m[:, None]) & (k + offs_k[None, :] < K_MAX)
378
+ cb = tl.where(mask, cb, 0.0)
379
+ cb = cb.to(dout_ptr.dtype.element_ty)
380
+ acc += tl.dot(cb, dout)
381
+ cb_ptrs += BLOCK_SIZE_K * stride_cb_csize_k
382
+ dout_ptrs += BLOCK_SIZE_K * stride_dout_seqlen
383
+ dA_cumsum_ptrs += BLOCK_SIZE_K * stride_dA_cs_csize
384
+
385
+ offs_m = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)
386
+ offs_n = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)
387
+ dt_ptrs = dt_ptr + offs_m * stride_dt_csize
388
+ dt_m = tl.load(dt_ptrs, mask=offs_m < chunk_size_limit, other=0.0).to(tl.float32)
389
+ dx = acc * dt_m[:, None]
390
+ dx_ptr += (
391
+ pid_b * stride_dx_batch
392
+ + pid_c * chunk_size * stride_dx_seqlen
393
+ + pid_h * stride_dx_head
394
+ )
395
+ dx_ptrs = dx_ptr + (
396
+ offs_m[:, None] * stride_dx_seqlen + offs_n[None, :] * stride_dx_hdim
397
+ )
398
+ if HAS_D:
399
+ dout_res_ptrs = dout_ptr + (
400
+ offs_m[:, None] * stride_dout_seqlen + offs_n[None, :] * stride_dout_hdim
401
+ )
402
+ dout_res = tl.load(
403
+ dout_res_ptrs,
404
+ mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim),
405
+ other=0.0,
406
+ ).to(tl.float32)
407
+ if D_HAS_HDIM:
408
+ D = tl.load(
409
+ D_ptr + pid_h * stride_D_head + offs_n, mask=offs_n < hdim, other=0.0
410
+ ).to(tl.float32)
411
+ else:
412
+ D = tl.load(D_ptr + pid_h * stride_D_head).to(tl.float32)
413
+ dx += dout_res * D
414
+ tl.store(
415
+ dx_ptrs,
416
+ dx,
417
+ mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim),
418
+ )
419
+
420
+ x_ptrs = x_ptr + (
421
+ offs_m[:, None] * stride_x_seqlen + offs_n[None, :] * stride_x_hdim
422
+ )
423
+ x = tl.load(
424
+ x_ptrs,
425
+ mask=(offs_m[:, None] < chunk_size_limit) & (offs_n[None, :] < hdim),
426
+ other=0.0,
427
+ ).to(tl.float32)
428
+ if HAS_D:
429
+ dD_ptr += (
430
+ pid_b * stride_dD_batch
431
+ + pid_c * stride_dD_chunk
432
+ + pid_h * stride_dD_head
433
+ + pid_m * stride_dD_csize
434
+ )
435
+ if D_HAS_HDIM:
436
+ dD_ptrs = dD_ptr + offs_n * stride_dD_hdim
437
+ dD = tl.sum(dout_res * x, axis=0)
438
+ tl.store(dD_ptrs, dD, mask=offs_n < hdim)
439
+ else:
440
+ dD = tl.sum(dout_res * x)
441
+ tl.store(dD_ptr, dD)
442
+ ddt = tl.sum(acc * x, axis=1)
443
+ ddt_ptrs = ddt_ptr + offs_m * stride_ddt_csize
444
+ tl.atomic_add(ddt_ptrs, ddt, mask=offs_m < chunk_size)
445
+
446
+
447
+ def _chunk_scan_chunk_state_bwd_dx(
448
+ x, dt, dA_cumsum, B, CB, dout, dstates, D=None, seq_idx=None, dx=None
449
+ ):
450
+ batch, seqlen, nheads, headdim = x.shape
451
+ _, _, nchunks, chunk_size = dt.shape
452
+ _, _, ngroups, dstate = B.shape
453
+ assert nheads % ngroups == 0
454
+ assert B.shape == (batch, seqlen, ngroups, dstate)
455
+ assert CB.shape == (batch, nchunks, ngroups, chunk_size, chunk_size)
456
+ assert dt.shape == (batch, nheads, nchunks, chunk_size)
457
+ assert dA_cumsum.shape == dt.shape
458
+ assert dout.shape == x.shape
459
+ assert dstates.shape == (batch, nchunks, nheads, headdim, dstate)
460
+ if seq_idx is not None:
461
+ assert seq_idx.shape == (batch, seqlen)
462
+ if D is not None:
463
+ assert D.shape == (nheads, headdim) or D.shape == (nheads,)
464
+ assert D.stride(-1) == 1
465
+ BLOCK_SIZE_min = 32
466
+ # Zero-initialized so the sum below can cover every block without reading `best_config`.
467
+ dD = torch.zeros(
468
+ triton.cdiv(chunk_size, BLOCK_SIZE_min),
469
+ batch,
470
+ nchunks,
471
+ nheads,
472
+ headdim if D.dim() == 2 else 1,
473
+ device=D.device,
474
+ dtype=torch.float32,
475
+ )
476
+ else:
477
+ dD = None
478
+ dD_strides = (
479
+ (dD.stride(0), dD.stride(1), dD.stride(2), dD.stride(3), dD.stride(4))
480
+ if D is not None
481
+ else (0, 0, 0, 0, 0)
482
+ )
483
+ if dx is None:
484
+ dx = torch.empty_like(x)
485
+ else:
486
+ assert dx.shape == x.shape
487
+ ddt = torch.zeros(
488
+ batch, nheads, nchunks, chunk_size, device=dout.device, dtype=torch.float32
489
+ )
490
+ grid_dx = lambda META: (
491
+ triton.cdiv(chunk_size, META["BLOCK_SIZE_M"])
492
+ * triton.cdiv(headdim, META["BLOCK_SIZE_N"]),
493
+ batch * nchunks,
494
+ nheads,
495
+ )
496
+ with device_guard(x):
497
+ _chunk_scan_chunk_state_bwd_dx_kernel[grid_dx](
498
+ x,
499
+ CB,
500
+ dout,
501
+ dt,
502
+ dA_cumsum,
503
+ seq_idx,
504
+ D,
505
+ B,
506
+ dstates,
507
+ dx,
508
+ ddt,
509
+ # `reset_to_zero` needs a tensor even when the kernel ignores it (no D).
510
+ dD if dD is not None else ddt.new_zeros(1),
511
+ chunk_size,
512
+ headdim,
513
+ dstate,
514
+ batch,
515
+ seqlen,
516
+ nheads // ngroups,
517
+ x.stride(0),
518
+ x.stride(1),
519
+ x.stride(2),
520
+ x.stride(3),
521
+ CB.stride(0),
522
+ CB.stride(1),
523
+ CB.stride(2),
524
+ CB.stride(-1),
525
+ CB.stride(-2),
526
+ dout.stride(0),
527
+ dout.stride(1),
528
+ dout.stride(2),
529
+ dout.stride(3),
530
+ dt.stride(0),
531
+ dt.stride(2),
532
+ dt.stride(1),
533
+ dt.stride(3),
534
+ dA_cumsum.stride(0),
535
+ dA_cumsum.stride(2),
536
+ dA_cumsum.stride(1),
537
+ dA_cumsum.stride(3),
538
+ *(
539
+ (seq_idx.stride(0), seq_idx.stride(1))
540
+ if seq_idx is not None
541
+ else (0, 0)
542
+ ),
543
+ D.stride(0) if D is not None else 0,
544
+ B.stride(0),
545
+ B.stride(1),
546
+ B.stride(2),
547
+ B.stride(3),
548
+ dstates.stride(0),
549
+ dstates.stride(1),
550
+ dstates.stride(2),
551
+ dstates.stride(3),
552
+ dstates.stride(4),
553
+ dx.stride(0),
554
+ dx.stride(1),
555
+ dx.stride(2),
556
+ dx.stride(3),
557
+ ddt.stride(0),
558
+ ddt.stride(2),
559
+ ddt.stride(1),
560
+ ddt.stride(3),
561
+ dD_strides[1],
562
+ dD_strides[2],
563
+ dD_strides[3],
564
+ dD_strides[0],
565
+ dD_strides[4],
566
+ D is not None,
567
+ D.dim() == 2 if D is not None else True,
568
+ HAS_SEQ_IDX=seq_idx is not None,
569
+ BLOCK_SIZE_DSTATE=max(triton.next_power_of_2(dstate), 16),
570
+ IS_TRITON_22=TRITON_22,
571
+ )
572
+ if D is not None:
573
+ dD = dD.sum(dim=(0, 1, 2)).to(dtype=D.dtype)
574
+ if D.dim() == 1:
575
+ dD = rearrange(dD, "h 1 -> h")
576
+ return dx, ddt.to(dtype=dt.dtype), dD
577
+
578
+
579
+ def _mamba_chunk_scan_combined_fwd(
580
+ x,
581
+ dt,
582
+ A,
583
+ B,
584
+ C,
585
+ chunk_size,
586
+ D=None,
587
+ z=None,
588
+ dt_bias=None,
589
+ initial_states=None,
590
+ seq_idx=None,
591
+ cu_seqlens=None,
592
+ dt_softplus=False,
593
+ dt_limit=(0.0, float("inf")),
594
+ ):
595
+ batch, seqlen, nheads, headdim = x.shape
596
+ _, _, ngroups, dstate = B.shape
597
+ assert nheads % ngroups == 0
598
+ assert B.shape == (batch, seqlen, ngroups, dstate)
599
+ assert x.shape == (batch, seqlen, nheads, headdim)
600
+ assert dt.shape == (batch, seqlen, nheads)
601
+ assert A.shape == (nheads,)
602
+ assert C.shape == B.shape
603
+ if z is not None:
604
+ assert z.shape == x.shape
605
+ if D is not None:
606
+ assert D.shape == (nheads, headdim) or D.shape == (nheads,)
607
+ if seq_idx is not None:
608
+ assert seq_idx.shape == (batch, seqlen)
609
+ if B.stride(-1) != 1:
610
+ B = B.contiguous()
611
+ if C.stride(-1) != 1:
612
+ C = C.contiguous()
613
+ if (
614
+ x.stride(-1) != 1 and x.stride(1) != 1
615
+ ): # Either M or K dimension should be contiguous
616
+ x = x.contiguous()
617
+ if (
618
+ z is not None and z.stride(-1) != 1 and z.stride(1) != 1
619
+ ): # Either M or K dimension should be contiguous
620
+ z = z.contiguous()
621
+ if D is not None and D.stride(-1) != 1:
622
+ D = D.contiguous()
623
+ if initial_states is not None:
624
+ assert initial_states.shape == (batch, nheads, headdim, dstate)
625
+ # # (batch, nchunks, chunk_size, chunk_size) or (batch, nchunks, nheads, chunk_size, chunk_size)
626
+ # dA_cumsum_tmp0, dt_tmp0 = _chunk_cumsum_fwd(dt[:, :147], A, chunk_size, dt_bias=dt_bias, dt_softplus=dt_softplus)
627
+ # dA_cumsum_tmp1, dt_tmp1 = _chunk_cumsum_fwd(dt[:, 147:], A, chunk_size, dt_bias=dt_bias, dt_softplus=dt_softplus)
628
+ # dA_cumsum_tmp2, dt_tmp2 = _chunk_cumsum_fwd(dt[:, 147:256], A, chunk_size, dt_bias=dt_bias, dt_softplus=dt_softplus)
629
+ dA_cumsum, dt = _chunk_cumsum_fwd(
630
+ dt, A, chunk_size, dt_bias=dt_bias, dt_softplus=dt_softplus, dt_limit=dt_limit
631
+ )
632
+ states = _chunk_state_fwd(B, x, dt, dA_cumsum, seq_idx=seq_idx, states_in_fp32=True)
633
+ # states_tmp0 = _chunk_state_fwd(B[:, :147], x[:, :147], dt_tmp0, dA_cumsum_tmp0, states_in_fp32=True)
634
+ # states_tmp1 = _chunk_state_fwd(B[:, 147:], x[:, 147:], dt_tmp1, dA_cumsum_tmp1, states_in_fp32=True)
635
+ # states_tmp2 = _chunk_state_fwd(B[:, 147:256], x[:, 147:256], dt_tmp2, dA_cumsum_tmp2, states_in_fp32=True)
636
+ states, final_states = _state_passing_fwd(
637
+ rearrange(states, "... p n -> ... (p n)"),
638
+ dA_cumsum[:, :, :, -1],
639
+ initial_states=rearrange(initial_states, "... p n -> ... (p n)")
640
+ if initial_states is not None
641
+ else None,
642
+ seq_idx=seq_idx,
643
+ chunk_size=chunk_size,
644
+ out_dtype=C.dtype,
645
+ )
646
+ states, final_states = [
647
+ rearrange(t, "... (p n) -> ... p n", n=dstate) for t in [states, final_states]
648
+ ]
649
+ # states_tmp0 = rearrange(_state_passing_fwd(rearrange(states_tmp0, "... p n -> ... (p n)"), dA_cumsum_tmp0[:, :, :, -1], chunk_size=chunk_size), "... (p n) -> ... p n", n=dstate)
650
+ # states_tmp1 = rearrange(_state_passing_fwd(rearrange(states_tmp1, "... p n -> ... (p n)"), dA_cumsum_tmp1[:, :, :, -1], chunk_size=chunk_size), "... (p n) -> ... p n", n=dstate)
651
+ CB = _bmm_chunk_fwd(C, B, chunk_size, seq_idx=seq_idx, output_dtype=torch.float32)
652
+ out, out_x = _chunk_scan_fwd(
653
+ CB, x, dt, dA_cumsum, C, states, D=D, z=z, seq_idx=seq_idx
654
+ )
655
+ if cu_seqlens is None:
656
+ return out, out_x, dt, dA_cumsum, states, final_states
657
+ else:
658
+ assert batch == 1, (
659
+ "passing cu_seqlens to get the varlen states is only supported if batch dimension is 1"
660
+ )
661
+ varlen_states = chunk_state_varlen(
662
+ B.squeeze(0),
663
+ x.squeeze(0),
664
+ dt.squeeze(0),
665
+ dA_cumsum.squeeze(0),
666
+ cu_seqlens,
667
+ states.squeeze(0),
668
+ )
669
+ return out, out_x, dt, dA_cumsum, states, final_states, varlen_states
670
+
671
+
672
+ def _mamba_chunk_scan_combined_bwd(
673
+ dout,
674
+ x,
675
+ dt,
676
+ A,
677
+ B,
678
+ C,
679
+ out,
680
+ chunk_size,
681
+ D=None,
682
+ z=None,
683
+ dt_bias=None,
684
+ initial_states=None,
685
+ dfinal_states=None,
686
+ seq_idx=None,
687
+ dt_softplus=False,
688
+ dt_limit=(0.0, float("inf")),
689
+ dx=None,
690
+ ddt=None,
691
+ dB=None,
692
+ dC=None,
693
+ dz=None,
694
+ recompute_output=False,
695
+ ):
696
+ if dout.stride(-1) != 1:
697
+ dout = dout.contiguous()
698
+ batch, seqlen, nheads, headdim = x.shape
699
+ nchunks = math.ceil(seqlen / chunk_size)
700
+ _, _, ngroups, dstate = B.shape
701
+ assert dout.shape == (batch, seqlen, nheads, headdim)
702
+ assert dt.shape == (batch, seqlen, nheads)
703
+ assert A.shape == (nheads,)
704
+ assert nheads % ngroups == 0
705
+ assert B.shape == (batch, seqlen, ngroups, dstate)
706
+ assert C.shape == B.shape
707
+ assert out.shape == x.shape
708
+ if initial_states is not None:
709
+ assert initial_states.shape == (batch, nheads, headdim, dstate)
710
+ if seq_idx is not None:
711
+ assert seq_idx.shape == (batch, seqlen)
712
+ if dx is not None:
713
+ assert dx.shape == x.shape
714
+ if dB is not None:
715
+ assert dB.shape == B.shape
716
+ dB_given = dB
717
+ else:
718
+ dB_given = torch.empty_like(B)
719
+ if dC is not None:
720
+ assert dC.shape == C.shape
721
+ dC_given = dC
722
+ else:
723
+ dC_given = torch.empty_like(C)
724
+ if dz is not None:
725
+ assert z is not None
726
+ assert dz.shape == z.shape
727
+ if ddt is not None:
728
+ assert ddt.shape == dt.shape
729
+ ddt_given = ddt
730
+ else:
731
+ ddt_given = torch.empty_like(dt)
732
+ # TD: For some reason Triton (2.1.0 and 2.2.0) errors with
733
+ # "[CUDA]: invalid device context" (e.g. during varlne test), and cloning makes it work. Idk why.
734
+ dt_in = dt.clone()
735
+ dA_cumsum, dt = _chunk_cumsum_fwd(
736
+ dt_in,
737
+ A,
738
+ chunk_size,
739
+ dt_bias=dt_bias,
740
+ dt_softplus=dt_softplus,
741
+ dt_limit=dt_limit,
742
+ )
743
+ CB = _bmm_chunk_fwd(C, B, chunk_size, seq_idx=seq_idx, output_dtype=torch.float32)
744
+ states = _chunk_state_fwd(B, x, dt, dA_cumsum, seq_idx=seq_idx, states_in_fp32=True)
745
+ states, _ = _state_passing_fwd(
746
+ rearrange(states, "... p n -> ... (p n)"),
747
+ dA_cumsum[:, :, :, -1],
748
+ initial_states=rearrange(initial_states, "... p n -> ... (p n)")
749
+ if initial_states is not None
750
+ else None,
751
+ seq_idx=seq_idx,
752
+ chunk_size=chunk_size,
753
+ )
754
+ states = rearrange(states, "... (p n) -> ... p n", n=dstate)
755
+ if z is not None:
756
+ dz, dout, dD, *rest = _chunk_scan_bwd_dz(
757
+ x,
758
+ z,
759
+ out,
760
+ dout,
761
+ chunk_size=chunk_size,
762
+ has_ddAcs=False,
763
+ D=D,
764
+ dz=dz,
765
+ recompute_output=recompute_output,
766
+ )
767
+ outz = rest[0] if recompute_output else out
768
+ else:
769
+ dz = None
770
+ outz = out
771
+ dstates = _chunk_scan_bwd_dstates(
772
+ C, dA_cumsum, dout, seq_idx=seq_idx, dtype=states.dtype
773
+ )
774
+ # dstates has length nchunks, containing the gradient to initial states at index 0 and
775
+ # gradient to the states of chunk (nchunks - 2) at index (nchunks - 1)
776
+ # Do computation in fp32 but convert dstates and states to fp16/bf16 since dstates and states
777
+ # will be used in matmul in the next kernels.
778
+ dstates, ddA_chunk_cumsum, dinitial_states, states = _state_passing_bwd(
779
+ rearrange(states, "... p n -> ... (p n)"),
780
+ dA_cumsum[:, :, :, -1],
781
+ rearrange(dstates, "... p n -> ... (p n)"),
782
+ dfinal_states=rearrange(dfinal_states, "... p n -> ... (p n)")
783
+ if dfinal_states is not None
784
+ else None,
785
+ seq_idx=seq_idx,
786
+ has_initial_states=initial_states is not None,
787
+ dstates_dtype=x.dtype,
788
+ states_dtype=x.dtype,
789
+ chunk_size=chunk_size,
790
+ )
791
+ # dstates has length nchunks, containing the gradient to states of chunk 0 at index 0 and
792
+ # gradient to the final states at index (nchunks - 1)
793
+ # states has length nchunks, containing the initial states at index 0 and the state for chunk (nchunks - 2) at index (nchunks - 1)
794
+ # The final states is not stored.
795
+ states = rearrange(states, "... (p n) -> ... p n", n=dstate)
796
+ dstates = rearrange(dstates, "... (p n) -> ... p n", n=dstate)
797
+ dinitial_states = (
798
+ rearrange(dinitial_states, "... (p n) -> ... p n", n=dstate)
799
+ if dinitial_states is not None
800
+ else None
801
+ )
802
+ dx, ddt, dD_from_x = _chunk_scan_chunk_state_bwd_dx(
803
+ x, dt, dA_cumsum, B, CB, dout, dstates, D=D, seq_idx=seq_idx, dx=dx
804
+ )
805
+ # dB = _chunk_state_bwd_db(x, dt, dA_cumsum, dstates, seq_idx=seq_idx, ngroups=ngroups)
806
+ dB, ddA_next = _chunk_state_bwd_db(
807
+ x, dt, dA_cumsum, dstates, seq_idx=seq_idx, B=B, ngroups=ngroups
808
+ )
809
+ # dC = _chunk_scan_bwd_dC(states[:, :-1].to(x.dtype), dA_cumsum, dout, seq_idx=seq_idx, ngroups=ngroups)
810
+ dC, ddA_cumsum_prev = _chunk_scan_bwd_dC(
811
+ states.to(x.dtype), dA_cumsum, dout, seq_idx=seq_idx, C=C, ngroups=ngroups
812
+ )
813
+ # Computing ddA with the dcb kernel is much slower, so we're not using it for now
814
+ dCB = _chunk_scan_bwd_dcb(x, dt, dA_cumsum, dout, seq_idx=seq_idx, ngroups=ngroups)
815
+ # dCB, ddA_tmp = _chunk_scan_bwd_dcb(x, dt, dA_cumsum, dout, seq_idx=seq_idx, CB=CB, ngroups=ngroups)
816
+ dCB = dCB.to(CB.dtype)
817
+ _bmm_chunk_bwd(C, dCB, residual=dB, out=dB_given)
818
+ _bmm_chunk_bwd(B, rearrange(dCB, "... l s -> ... s l"), residual=dC, out=dC_given)
819
+ # If we have z, then dout_x is recomputed in fp32 so dD = (dout_x * x).sum() is more accurate
820
+ # than dD_from_x = (dout_x * x).sum() where dout_x is in fp16/bf16
821
+ if z is None:
822
+ dD = dD_from_x
823
+ # Formula for ddA_cumsum, assuming out is the output of the forward pass before adding x * D.
824
+ # ddA_cumsum = torch.einsum("bclhp,bclhp->bhcl", out.float(), dout.float()) - ddt * dt
825
+ # However, this is numerically unstable: when we do the reverse cumsum on ddA_cumsum, there might
826
+ # be a lot of underflow.
827
+
828
+ # This is already done as part of bwd_dC kernel
829
+ # ddA_cumsum_prev = _chunk_scan_bwd_ddAcs_prev(states[:, :-1], C, dout, dA_cumsum, seq_idx=seq_idx)
830
+ ddA_cumsum_prev[..., -1] += ddA_chunk_cumsum
831
+ ddA_prev = ddA_cumsum_prev.flip([-1]).cumsum(dim=-1).flip([-1])
832
+ # This is already done as part of bwd_dB kernel
833
+ # ddA_next = _chunk_state_bwd_ddAcs_stable(B, x, dt, dA_cumsum, dstates, seq_idx=seq_idx)
834
+ # We don't need to pass in seq_idx because CB also zeros out entries where seq_idx[i] != seq_idx[j]
835
+ ddA = _chunk_scan_bwd_ddAcs_stable(x, dt, dA_cumsum, dout, CB)
836
+ ddA += ddA_next + ddA_prev
837
+
838
+ ddt_given, dA, ddt_bias = _chunk_cumsum_bwd(
839
+ ddA,
840
+ ddt,
841
+ dt_in,
842
+ A,
843
+ dt_bias=dt_bias,
844
+ dt_softplus=dt_softplus,
845
+ dt_limit=dt_limit,
846
+ ddt=ddt_given,
847
+ )
848
+
849
+ # These 2 lines are just to test ddt and dA being computed by old code
850
+ # _, dA = selective_scan_bwd(dout, x, dt, A, B, C, D=D.float(), z=z)
851
+ # ddt_given.copy_(ddt)
852
+
853
+ return_vals = (
854
+ dx,
855
+ ddt_given,
856
+ dA,
857
+ dB_given,
858
+ dC_given,
859
+ dD,
860
+ dz,
861
+ ddt_bias,
862
+ dinitial_states,
863
+ )
864
+ return return_vals if not recompute_output else (*return_vals, outz)
865
+
866
+
867
+ def selective_scan_bwd(dout, x, dt, A, B, C, D=None, z=None):
868
+ """
869
+ Argument:
870
+ dout: (batch, seqlen, nheads, headdim)
871
+ x: (batch, seqlen, nheads, headdim)
872
+ dt: (batch, nheads, nchunks, chunk_size) or (batch, nheads, headdim, nchunks, chunk_size)
873
+ A: (nheads) or (dim, dstate)
874
+ B: (batch, seqlen, ngroups, dstate)
875
+ C: (batch, seqlen, ngroups, dstate)
876
+ D: (nheads, headdim) or (nheads,)
877
+ z: (batch, seqlen, nheads, headdim)
878
+ Return:
879
+ out: (batch, seqlen, nheads, headdim)
880
+ """
881
+ import selective_scan
882
+
883
+ batch, seqlen, nheads, headdim = x.shape
884
+ chunk_size = dt.shape[-1]
885
+ _, _, ngroups, dstate = B.shape
886
+ assert nheads % ngroups == 0
887
+ x = rearrange(x, "b l h p -> b (h p) l")
888
+ squeeze_dt = dt.dim() == 4
889
+ if dt.dim() == 4:
890
+ dt = repeat(dt, "b h c l -> b h p c l", p=headdim)
891
+ dt = rearrange(dt, "b h p c l -> b (h p) (c l)", p=headdim)
892
+ squeeze_A = A.dim() == 1
893
+ if A.dim() == 1:
894
+ A = repeat(A, "h -> (h p) n", p=headdim, n=dstate).to(dtype=torch.float32)
895
+ else:
896
+ A = A.to(dtype=torch.float32)
897
+ B = rearrange(B, "b l g n -> b g n l")
898
+ C = rearrange(C, "b l g n -> b g n l")
899
+ if D is not None:
900
+ if D.dim() == 2:
901
+ D = rearrange(D, "h p -> (h p)")
902
+ else:
903
+ D = repeat(D, "h -> (h p)", p=headdim)
904
+ if z is not None:
905
+ z = rearrange(z, "b l h p -> b (h p) l")
906
+
907
+ if x.stride(-1) != 1:
908
+ x = x.contiguous()
909
+ if dt.stride(-1) != 1:
910
+ dt = dt.contiguous()
911
+ if D is not None:
912
+ D = D.contiguous()
913
+ if B.stride(-1) != 1:
914
+ B = B.contiguous()
915
+ if C.stride(-1) != 1:
916
+ C = C.contiguous()
917
+ if z is not None and z.stride(-1) != 1:
918
+ z = z.contiguous()
919
+ _, intermediate, *rest = selective_scan.fwd(
920
+ x, dt.to(dtype=x.dtype), A, B, C, D, z, None, False
921
+ )
922
+ if z is not None:
923
+ out = rest[0]
924
+ else:
925
+ out = None
926
+
927
+ dout = rearrange(dout, "b l h p -> b (h p) l")
928
+
929
+ if dout.stride(-1) != 1:
930
+ dout = dout.contiguous()
931
+ # The kernel supports passing in a pre-allocated dz (e.g., in case we want to fuse the
932
+ # backward of selective_scan with the backward of chunk).
933
+ # Here we just pass in None and dz will be allocated in the C++ code.
934
+ _, ddt, dA, *rest = selective_scan.bwd(
935
+ x,
936
+ dt.to(dtype=x.dtype),
937
+ A,
938
+ B,
939
+ C,
940
+ D,
941
+ z,
942
+ None,
943
+ dout,
944
+ intermediate,
945
+ out,
946
+ None,
947
+ False,
948
+ False, # option to recompute out_z, not used here
949
+ )
950
+ ddt = rearrange(ddt, "b (h p) (c l) -> b h p c l", p=headdim, l=chunk_size)
951
+ if squeeze_dt:
952
+ ddt = ddt.float().sum(dim=2)
953
+ if squeeze_A:
954
+ dA = rearrange(dA, "(h p) n -> h p n", p=headdim).sum(dim=(1, 2))
955
+ return ddt, dA
956
+
957
+
958
+ class MambaChunkScanCombinedFn(torch.autograd.Function):
959
+ @staticmethod
960
+ def forward(
961
+ ctx,
962
+ x,
963
+ dt,
964
+ A,
965
+ B,
966
+ C,
967
+ chunk_size,
968
+ D=None,
969
+ z=None,
970
+ dt_bias=None,
971
+ initial_states=None,
972
+ seq_idx=None,
973
+ cu_seqlens=None,
974
+ dt_softplus=False,
975
+ dt_limit=(0.0, float("inf")),
976
+ return_final_states=False,
977
+ return_varlen_states=False,
978
+ ):
979
+ ctx.dt_dtype = dt.dtype
980
+ if not return_varlen_states:
981
+ cu_seqlens = None
982
+ else:
983
+ assert cu_seqlens is not None, (
984
+ "cu_seqlens must be provided if return_varlen_states is True"
985
+ )
986
+ out, out_x, dt_out, dA_cumsum, states, final_states, *rest = (
987
+ _mamba_chunk_scan_combined_fwd(
988
+ x,
989
+ dt,
990
+ A,
991
+ B,
992
+ C,
993
+ chunk_size,
994
+ D=D,
995
+ z=z,
996
+ dt_bias=dt_bias,
997
+ initial_states=initial_states,
998
+ seq_idx=seq_idx,
999
+ cu_seqlens=cu_seqlens,
1000
+ dt_softplus=dt_softplus,
1001
+ dt_limit=dt_limit,
1002
+ )
1003
+ )
1004
+ ctx.save_for_backward(
1005
+ out if z is None else out_x,
1006
+ x,
1007
+ dt,
1008
+ dA_cumsum,
1009
+ A,
1010
+ B,
1011
+ C,
1012
+ D,
1013
+ z,
1014
+ dt_bias,
1015
+ initial_states,
1016
+ seq_idx,
1017
+ )
1018
+ ctx.dt_softplus = dt_softplus
1019
+ ctx.chunk_size = chunk_size
1020
+ ctx.dt_limit = dt_limit
1021
+ ctx.return_final_states = return_final_states
1022
+ ctx.return_varlen_states = return_varlen_states
1023
+ if not return_varlen_states:
1024
+ return out if not return_final_states else (out, final_states)
1025
+ else:
1026
+ varlen_states = rest[0]
1027
+ return (
1028
+ (out, varlen_states)
1029
+ if not return_final_states
1030
+ else (out, final_states, varlen_states)
1031
+ )
1032
+
1033
+ @staticmethod
1034
+ def backward(ctx, dout, *args):
1035
+ out, x, dt, dA_cumsum, A, B, C, D, z, dt_bias, initial_states, seq_idx = (
1036
+ ctx.saved_tensors
1037
+ )
1038
+ assert not ctx.return_varlen_states, (
1039
+ "return_varlen_states is not supported in backward"
1040
+ )
1041
+ dfinal_states = args[0] if ctx.return_final_states else None
1042
+ dx, ddt, dA, dB, dC, dD, dz, ddt_bias, dinitial_states = (
1043
+ _mamba_chunk_scan_combined_bwd(
1044
+ dout,
1045
+ x,
1046
+ dt,
1047
+ A,
1048
+ B,
1049
+ C,
1050
+ out,
1051
+ ctx.chunk_size,
1052
+ D=D,
1053
+ z=z,
1054
+ dt_bias=dt_bias,
1055
+ initial_states=initial_states,
1056
+ dfinal_states=dfinal_states,
1057
+ seq_idx=seq_idx,
1058
+ dt_softplus=ctx.dt_softplus,
1059
+ dt_limit=ctx.dt_limit,
1060
+ )
1061
+ )
1062
+ return (
1063
+ dx,
1064
+ ddt,
1065
+ dA,
1066
+ dB,
1067
+ dC,
1068
+ None,
1069
+ dD,
1070
+ dz,
1071
+ ddt_bias,
1072
+ dinitial_states,
1073
+ None,
1074
+ None,
1075
+ None,
1076
+ None,
1077
+ None,
1078
+ None,
1079
+ )
1080
+
1081
+
1082
+ def mamba_chunk_scan_combined(
1083
+ x,
1084
+ dt,
1085
+ A,
1086
+ B,
1087
+ C,
1088
+ chunk_size,
1089
+ D=None,
1090
+ z=None,
1091
+ dt_bias=None,
1092
+ initial_states=None,
1093
+ seq_idx=None,
1094
+ cu_seqlens=None,
1095
+ dt_softplus=False,
1096
+ dt_limit=(0.0, float("inf")),
1097
+ return_final_states=False,
1098
+ return_varlen_states=False,
1099
+ ):
1100
+ """
1101
+ Argument:
1102
+ x: (batch, seqlen, nheads, headdim)
1103
+ dt: (batch, seqlen, nheads)
1104
+ A: (nheads)
1105
+ B: (batch, seqlen, ngroups, dstate)
1106
+ C: (batch, seqlen, ngroups, dstate)
1107
+ chunk_size: int
1108
+ D: (nheads, headdim) or (nheads,)
1109
+ z: (batch, seqlen, nheads, headdim)
1110
+ dt_bias: (nheads,)
1111
+ initial_states: (batch, nheads, headdim, dstate)
1112
+ seq_idx: (batch, seqlen)
1113
+ cu_seqlens: (num_sequences + 1) or None, only used if return_varlen_states is True
1114
+ dt_softplus: Whether to apply softplus to dt
1115
+ Return:
1116
+ out: (batch, seqlen, nheads, headdim)
1117
+ """
1118
+ return MambaChunkScanCombinedFn.apply(
1119
+ x,
1120
+ dt,
1121
+ A,
1122
+ B,
1123
+ C,
1124
+ chunk_size,
1125
+ D,
1126
+ z,
1127
+ dt_bias,
1128
+ initial_states,
1129
+ seq_idx,
1130
+ cu_seqlens,
1131
+ dt_softplus,
1132
+ dt_limit,
1133
+ return_final_states,
1134
+ return_varlen_states,
1135
+ )
1136
+
1137
+
1138
+ def mamba_chunk_scan(
1139
+ x, dt, A, B, C, chunk_size, D=None, z=None, dt_bias=None, dt_softplus=False
1140
+ ):
1141
+ """
1142
+ Argument:
1143
+ x: (batch, seqlen, nheads, headdim)
1144
+ dt: (batch, seqlen, nheads)
1145
+ A: (nheads)
1146
+ B: (batch, seqlen, ngroups, dstate)
1147
+ C: (batch, seqlen, ngroups, dstate)
1148
+ D: (nheads, headdim) or (nheads,)
1149
+ z: (batch, seqlen, nheads, headdim)
1150
+ dt_bias: (nheads,)
1151
+ Return:
1152
+ out: (batch, seqlen, nheads, headdim)
1153
+ """
1154
+ batch, seqlen, nheads, headdim = x.shape
1155
+ dstate = B.shape[-1]
1156
+ if seqlen % chunk_size != 0:
1157
+ dt = F.pad(dt, (0, 0, 0, chunk_size - seqlen % chunk_size))
1158
+ dt = rearrange(dt, "b (c l) h -> b h c l", l=chunk_size)
1159
+ dt = dt.float() # We want high precision for this before cumsum
1160
+ if dt_bias is not None:
1161
+ dt = dt + rearrange(dt_bias, "h -> h 1 1")
1162
+ if dt_softplus:
1163
+ dt = F.softplus(dt)
1164
+ dA = dt * rearrange(A, "h -> h 1 1")
1165
+ dA = dt * rearrange(A, "h -> h 1 1")
1166
+ dA_cumsum = torch.cumsum(dA, dim=-1)
1167
+ # 1. Compute the state for each chunk
1168
+ states = chunk_state(B, x, dt, dA_cumsum, states_in_fp32=True)
1169
+ # 2. Pass the state to all the chunks by weighted cumsum.
1170
+ states = rearrange(
1171
+ state_passing(
1172
+ rearrange(states, "... p n -> ... (p n)"), dA_cumsum[:, :, :, -1]
1173
+ )[0],
1174
+ "... (p n) -> ... p n",
1175
+ n=dstate,
1176
+ )
1177
+ # 3. Compute the output for each chunk
1178
+ out = chunk_scan(B, C, x, dt, dA_cumsum, states, D=D, z=z)
1179
+ return out
1180
+
1181
+
1182
+ def ssd_chunk_scan_combined_ref(
1183
+ x, dt, A, B, C, chunk_size, D=None, z=None, dt_bias=None, dt_softplus=False
1184
+ ):
1185
+ """
1186
+ Argument:
1187
+ x: (batch, seqlen, nheads, headdim)
1188
+ dt: (batch, seqlen, nheads)
1189
+ A: (nheads)
1190
+ B: (batch, seqlen, ngroups, dstate)
1191
+ C: (batch, seqlen, ngroups, dstate)
1192
+ D: (nheads, headdim) or (nheads,)
1193
+ z: (batch, seqlen, nheads, headdim)
1194
+ dt_bias: (nheads,)
1195
+ Return:
1196
+ out: (batch, seqlen, nheads, headdim)
1197
+ """
1198
+ batch, seqlen, nheads, headdim = x.shape
1199
+ dstate = B.shape[-1]
1200
+ if seqlen % chunk_size != 0:
1201
+ dt = F.pad(dt, (0, 0, 0, chunk_size - seqlen % chunk_size))
1202
+ dt = rearrange(dt, "b (c l) h -> b h c l", l=chunk_size)
1203
+ dt = dt.float() # We want high precision for this before cumsum
1204
+ if dt_bias is not None:
1205
+ dt = dt + rearrange(dt_bias, "h -> h 1 1")
1206
+ if dt_softplus:
1207
+ dt = F.softplus(dt)
1208
+ dA = dt * rearrange(A, "h -> h 1 1")
1209
+ dA_cumsum = torch.cumsum(dA, dim=-1)
1210
+ # 1. Compute the state for each chunk
1211
+ states = chunk_state_ref(B, x, dt, dA_cumsum)
1212
+ states_dtype = states.dtype
1213
+ if states.dtype not in [torch.float32, torch.float64]:
1214
+ states = states.to(torch.float32)
1215
+ # 2. Pass the state to all the chunks by weighted cumsum.
1216
+ # state_passing_ref is much less numerically stable
1217
+ states = rearrange(
1218
+ state_passing_ref(
1219
+ rearrange(states, "... p n -> ... (p n)"), dA_cumsum[:, :, :, -1]
1220
+ )[0],
1221
+ "... (p n) -> ... p n",
1222
+ n=dstate,
1223
+ )
1224
+ states = states.to(states_dtype)
1225
+ # 3. Compute the output for each chunk
1226
+ out = chunk_scan_ref(B, C, x, dt, dA_cumsum, states, D=D, z=z)
1227
+ return out
1228
+
1229
+
1230
+ def ssd_selective_scan(
1231
+ x,
1232
+ dt,
1233
+ A,
1234
+ B,
1235
+ C,
1236
+ D=None,
1237
+ z=None,
1238
+ dt_bias=None,
1239
+ dt_softplus=False,
1240
+ dt_limit=(0.0, float("inf")),
1241
+ ):
1242
+ """
1243
+ Argument:
1244
+ x: (batch, seqlen, nheads, headdim)
1245
+ dt: (batch, seqlen, nheads) or (batch, seqlen, nheads, headdim)
1246
+ A: (nheads) or (dim, dstate)
1247
+ B: (batch, seqlen, ngroups, dstate)
1248
+ C: (batch, seqlen, ngroups, dstate)
1249
+ D: (nheads, headdim) or (nheads,)
1250
+ z: (batch, seqlen, nheads, headdim)
1251
+ dt_bias: (nheads,) or (nheads, headdim)
1252
+ Return:
1253
+ out: (batch, seqlen, nheads, headdim)
1254
+ """
1255
+ from ..selective_scan_interface import selective_scan_fn
1256
+
1257
+ batch, seqlen, nheads, headdim = x.shape
1258
+ _, _, ngroups, dstate = B.shape
1259
+ x = rearrange(x, "b l h p -> b (h p) l")
1260
+ if dt.dim() == 3:
1261
+ dt = repeat(dt, "b l h -> b l h p", p=headdim)
1262
+ dt = rearrange(dt, "b l h p -> b (h p) l")
1263
+ if A.dim() == 1:
1264
+ A = repeat(A, "h -> (h p) n", p=headdim, n=dstate).to(dtype=torch.float32)
1265
+ else:
1266
+ A = A.to(dtype=torch.float32)
1267
+ B = rearrange(B, "b l g n -> b g n l")
1268
+ C = rearrange(C, "b l g n -> b g n l")
1269
+ if D is not None:
1270
+ if D.dim() == 2:
1271
+ D = rearrange(D, "h p -> (h p)")
1272
+ else:
1273
+ D = repeat(D, "h -> (h p)", p=headdim)
1274
+ if z is not None:
1275
+ z = rearrange(z, "b l h p -> b (h p) l")
1276
+ if dt_bias is not None:
1277
+ if dt_bias.dim() == 1:
1278
+ dt_bias = repeat(dt_bias, "h -> h p", p=headdim)
1279
+ dt_bias = rearrange(dt_bias, "h p -> (h p)")
1280
+ if dt_limit != (0.0, float("inf")):
1281
+ if dt_bias is not None:
1282
+ dt = dt + rearrange(dt_bias, "d -> d 1")
1283
+ if dt_softplus:
1284
+ dt = F.softplus(dt)
1285
+ dt = dt.clamp(min=dt_limit[0], max=dt_limit[1]).to(x.dtype)
1286
+ dt_bias = None
1287
+ dt_softplus = None
1288
+ out = selective_scan_fn(
1289
+ x, dt, A, B, C, D=D, z=z, delta_bias=dt_bias, delta_softplus=dt_softplus
1290
+ )
1291
+ return rearrange(out, "b (h p) l -> b l h p", p=headdim)
1292
+
1293
+
1294
+ def mamba_conv1d_scan_ref(
1295
+ xBC,
1296
+ conv1d_weight,
1297
+ conv1d_bias,
1298
+ dt,
1299
+ A,
1300
+ chunk_size,
1301
+ D=None,
1302
+ z=None,
1303
+ dt_bias=None,
1304
+ dt_softplus=False,
1305
+ dt_limit=(0.0, float("inf")),
1306
+ activation="silu",
1307
+ headdim=None,
1308
+ ngroups=1,
1309
+ ):
1310
+ """
1311
+ Argument:
1312
+ xBC: (batch, seqlen, dim + 2 * ngroups * dstate) where dim == nheads * headdim
1313
+ conv1d_weight: (dim + 2 * ngroups * dstate, width)
1314
+ conv1d_bias: (dim + 2 * ngroups * dstate,)
1315
+ dt: (batch, seqlen, nheads) or (batch, seqlen, nheads, headdim)
1316
+ A: (nheads)
1317
+ D: (nheads, headdim) or (nheads,)
1318
+ z: (batch, seqlen, dim)
1319
+ dt_bias: (nheads) or (nheads, headdim)
1320
+ headdim: if D is 1D and z is None, headdim must be passed in
1321
+ Return:
1322
+ out: (batch, seqlen, dim)
1323
+ """
1324
+ batch, seqlen, nheads = dt.shape[:3]
1325
+ assert nheads % ngroups == 0
1326
+ if z is not None:
1327
+ dim = z.shape[-1]
1328
+ assert dim % nheads == 0
1329
+ headdim = dim // nheads
1330
+ else:
1331
+ if D.dim() == 1:
1332
+ assert headdim is not None
1333
+ else:
1334
+ headdim = D.shape[1]
1335
+ dim = nheads * headdim
1336
+ xBC = rearrange(
1337
+ causal_conv1d_fn(
1338
+ rearrange(xBC, "b s d -> b d s"),
1339
+ conv1d_weight,
1340
+ conv1d_bias,
1341
+ activation=activation,
1342
+ ),
1343
+ "b d s -> b s d",
1344
+ )
1345
+ dstate = (xBC.shape[-1] - dim) // ngroups // 2
1346
+ x, B, C = torch.split(xBC, [dim, ngroups * dstate, ngroups * dstate], dim=-1)
1347
+ x = rearrange(x, "b l (h p) -> b l h p", h=nheads)
1348
+ B = rearrange(B, "b l (g n) -> b l g n", g=ngroups)
1349
+ C = rearrange(C, "b l (g n) -> b l g n", g=ngroups)
1350
+ z = rearrange(z, "b l (h p) -> b l h p", h=nheads) if z is not None else None
1351
+ out = ssd_selective_scan(
1352
+ x,
1353
+ dt.to(x.dtype),
1354
+ A,
1355
+ B,
1356
+ C,
1357
+ D=D.float(),
1358
+ z=z,
1359
+ dt_bias=dt_bias,
1360
+ dt_softplus=dt_softplus,
1361
+ dt_limit=dt_limit,
1362
+ )
1363
+ return rearrange(out, "b s h p -> b s (h p)")
1364
+
1365
+
1366
+ class MambaSplitConv1dScanCombinedFn(torch.autograd.Function):
1367
+ @staticmethod
1368
+ @custom_fwd
1369
+ def forward(
1370
+ ctx,
1371
+ zxbcdt,
1372
+ conv1d_weight,
1373
+ conv1d_bias,
1374
+ dt_bias,
1375
+ A,
1376
+ D,
1377
+ chunk_size,
1378
+ initial_states=None,
1379
+ seq_idx=None,
1380
+ dt_limit=(0.0, float("inf")),
1381
+ return_final_states=False,
1382
+ activation="silu",
1383
+ rmsnorm_weight=None,
1384
+ rmsnorm_eps=1e-6,
1385
+ outproj_weight=None,
1386
+ outproj_bias=None,
1387
+ headdim=None,
1388
+ ngroups=1,
1389
+ norm_before_gate=True,
1390
+ ):
1391
+ assert activation in [None, "silu", "swish"]
1392
+ if D.dim() == 1:
1393
+ assert headdim is not None
1394
+ (nheads,) = D.shape
1395
+ else:
1396
+ nheads, headdim = D.shape
1397
+ batch, seqlen, _ = zxbcdt.shape
1398
+ dim = nheads * headdim
1399
+ assert nheads % ngroups == 0
1400
+ dstate = (conv1d_weight.shape[0] - dim) // ngroups // 2
1401
+ d_nonssm = (zxbcdt.shape[-1] - 2 * dim - 2 * ngroups * dstate - nheads) // 2
1402
+ assert d_nonssm >= 0
1403
+ assert zxbcdt.shape == (
1404
+ batch,
1405
+ seqlen,
1406
+ 2 * d_nonssm + 2 * dim + 2 * ngroups * dstate + nheads,
1407
+ )
1408
+ assert dt_bias.shape == (nheads,)
1409
+ assert A.shape == (nheads,)
1410
+ zx0, z, xBC, dt = torch.split(
1411
+ zxbcdt, [2 * d_nonssm, dim, dim + ngroups * dstate * 2, nheads], dim=-1
1412
+ )
1413
+ seq_idx = seq_idx.contiguous() if seq_idx is not None else None
1414
+ xBC_conv = rearrange(
1415
+ causal_conv1d_cuda.causal_conv1d_fwd(
1416
+ rearrange_and_update_stride(xBC, "b s d -> b d s"),
1417
+ conv1d_weight,
1418
+ conv1d_bias,
1419
+ seq_idx,
1420
+ None,
1421
+ None,
1422
+ activation in ["silu", "swish"],
1423
+ ),
1424
+ "b d s -> b s d",
1425
+ )
1426
+ x, B, C = torch.split(
1427
+ xBC_conv, [dim, ngroups * dstate, ngroups * dstate], dim=-1
1428
+ )
1429
+ x = rearrange(x, "b l (h p) -> b l h p", h=nheads)
1430
+ B = rearrange(B, "b l (g n) -> b l g n", g=ngroups)
1431
+ C = rearrange(C, "b l (g n) -> b l g n", g=ngroups)
1432
+ z = rearrange(z, "b l (h p) -> b l h p", h=nheads) if z is not None else None
1433
+ if rmsnorm_weight is None:
1434
+ out, out_x, dt_out, dA_cumsum, states, final_states = (
1435
+ _mamba_chunk_scan_combined_fwd(
1436
+ x,
1437
+ dt,
1438
+ A,
1439
+ B,
1440
+ C,
1441
+ chunk_size=chunk_size,
1442
+ D=D,
1443
+ z=z,
1444
+ dt_bias=dt_bias,
1445
+ initial_states=initial_states,
1446
+ seq_idx=seq_idx,
1447
+ dt_softplus=True,
1448
+ dt_limit=dt_limit,
1449
+ )
1450
+ )
1451
+ out = rearrange(out, "b s h p -> b s (h p)")
1452
+ rstd = None
1453
+ if d_nonssm > 0:
1454
+ out = torch.cat([_swiglu_fwd(zx0), out], dim=-1)
1455
+ else:
1456
+ out_x, _, dt_out, dA_cumsum, states, final_states = (
1457
+ _mamba_chunk_scan_combined_fwd(
1458
+ x,
1459
+ dt,
1460
+ A,
1461
+ B,
1462
+ C,
1463
+ chunk_size=chunk_size,
1464
+ D=D,
1465
+ z=None,
1466
+ dt_bias=dt_bias,
1467
+ initial_states=initial_states,
1468
+ seq_idx=seq_idx,
1469
+ dt_softplus=True,
1470
+ dt_limit=dt_limit,
1471
+ )
1472
+ )
1473
+ # reshape input data into 2D tensor
1474
+ x_rms = rearrange(out_x, "b s h p -> (b s) (h p)")
1475
+ z_rms = rearrange(z, "b s h p -> (b s) (h p)")
1476
+ rmsnorm_weight = rmsnorm_weight.contiguous()
1477
+ if d_nonssm == 0:
1478
+ out = None
1479
+ else:
1480
+ out01 = torch.empty(
1481
+ (batch, seqlen, d_nonssm + dim),
1482
+ dtype=x_rms.dtype,
1483
+ device=x_rms.device,
1484
+ )
1485
+ out = rearrange(out01[..., d_nonssm:], "b s d -> (b s) d")
1486
+ _swiglu_fwd(zx0, out=out01[..., :d_nonssm])
1487
+ out, _, rstd = _layer_norm_fwd(
1488
+ x_rms,
1489
+ rmsnorm_weight,
1490
+ None,
1491
+ rmsnorm_eps,
1492
+ z_rms,
1493
+ out=out,
1494
+ group_size=dim // ngroups,
1495
+ norm_before_gate=norm_before_gate,
1496
+ is_rms_norm=True,
1497
+ )
1498
+ if d_nonssm == 0:
1499
+ out = rearrange(out, "(b s) d -> b s d", b=batch)
1500
+ else:
1501
+ out = out01
1502
+ ctx.outproj_weight_dtype = (
1503
+ outproj_weight.dtype if outproj_weight is not None else None
1504
+ )
1505
+
1506
+ device_type = zxbcdt.device.type
1507
+ if outproj_weight is not None:
1508
+ if torch.is_autocast_enabled(device_type):
1509
+ dtype = torch.get_autocast_dtype(device_type)
1510
+ out, outproj_weight = out.to(dtype), outproj_weight.to(dtype)
1511
+ outproj_bias = (
1512
+ outproj_bias.to(dtype) if outproj_bias is not None else None
1513
+ )
1514
+ out = F.linear(out, outproj_weight, outproj_bias)
1515
+ else:
1516
+ assert outproj_bias is None
1517
+ ctx.save_for_backward(
1518
+ zxbcdt,
1519
+ conv1d_weight,
1520
+ conv1d_bias,
1521
+ out_x,
1522
+ A,
1523
+ D,
1524
+ dt_bias,
1525
+ initial_states,
1526
+ seq_idx,
1527
+ rmsnorm_weight,
1528
+ rstd,
1529
+ outproj_weight,
1530
+ outproj_bias,
1531
+ )
1532
+ ctx.dt_limit = dt_limit
1533
+ ctx.return_final_states = return_final_states
1534
+ ctx.activation = activation
1535
+ ctx.rmsnorm_eps = rmsnorm_eps
1536
+ ctx.norm_before_gate = norm_before_gate
1537
+ ctx.chunk_size = chunk_size
1538
+ ctx.headdim = headdim
1539
+ ctx.ngroups = ngroups
1540
+ return out if not return_final_states else (out, final_states)
1541
+
1542
+ @staticmethod
1543
+ @custom_bwd
1544
+ def backward(ctx, dout, *args):
1545
+ (
1546
+ zxbcdt,
1547
+ conv1d_weight,
1548
+ conv1d_bias,
1549
+ out,
1550
+ A,
1551
+ D,
1552
+ dt_bias,
1553
+ initial_states,
1554
+ seq_idx,
1555
+ rmsnorm_weight,
1556
+ rstd,
1557
+ outproj_weight,
1558
+ outproj_bias,
1559
+ ) = ctx.saved_tensors
1560
+ dfinal_states = args[0] if ctx.return_final_states else None
1561
+ headdim = ctx.headdim
1562
+ nheads = D.shape[0]
1563
+ dim = nheads * headdim
1564
+ assert nheads % ctx.ngroups == 0
1565
+ dstate = (conv1d_weight.shape[0] - dim) // ctx.ngroups // 2
1566
+ d_nonssm = (zxbcdt.shape[-1] - 2 * dim - 2 * ctx.ngroups * dstate - nheads) // 2
1567
+ assert d_nonssm >= 0
1568
+ recompute_output = outproj_weight is not None
1569
+ if recompute_output:
1570
+ out_recompute = torch.empty(
1571
+ *out.shape[:2], d_nonssm + dim, device=out.device, dtype=out.dtype
1572
+ )
1573
+ out0_recompute, out1_recompute = out_recompute.split(
1574
+ [d_nonssm, dim], dim=-1
1575
+ )
1576
+ zx0, z, xBC, dt = torch.split(
1577
+ zxbcdt, [2 * d_nonssm, dim, dim + 2 * ctx.ngroups * dstate, nheads], dim=-1
1578
+ )
1579
+ # Recompute x, B, C
1580
+ xBC_conv = rearrange(
1581
+ causal_conv1d_cuda.causal_conv1d_fwd(
1582
+ rearrange_and_update_stride(xBC, "b s d -> b d s"),
1583
+ conv1d_weight,
1584
+ conv1d_bias,
1585
+ seq_idx,
1586
+ None,
1587
+ None,
1588
+ ctx.activation in ["silu", "swish"],
1589
+ ),
1590
+ "b d s -> b s d",
1591
+ )
1592
+ x, B, C = torch.split(
1593
+ xBC_conv, [dim, ctx.ngroups * dstate, ctx.ngroups * dstate], dim=-1
1594
+ )
1595
+ x = rearrange(x, "b l (h p) -> b l h p", h=nheads)
1596
+ B = rearrange(B, "b l (g n) -> b l g n", g=ctx.ngroups)
1597
+ C = rearrange(C, "b l (g n) -> b l g n", g=ctx.ngroups)
1598
+ dzxbcdt = torch.empty_like(zxbcdt)
1599
+ dzx0, dz, dxBC_given, ddt_given = torch.split(
1600
+ dzxbcdt, [2 * d_nonssm, dim, dim + 2 * ctx.ngroups * dstate, nheads], dim=-1
1601
+ )
1602
+ dxBC = torch.empty_like(xBC)
1603
+ dx, dB, dC = torch.split(
1604
+ dxBC, [dim, ctx.ngroups * dstate, ctx.ngroups * dstate], dim=-1
1605
+ )
1606
+ # torch.compile reads out of bounds when Triton kernels write into different slices of one
1607
+ # buffer, so give each slice its own storage while compiling and copy back at the end.
1608
+ slices = dense = ()
1609
+ if torch.compiler.is_compiling():
1610
+ slices = (dzx0, dz, ddt_given, dx, dB, dC)
1611
+ dzx0, dz, ddt_given, dx, dB, dC = dense = [torch.empty_like(t) for t in slices]
1612
+ z = rearrange(z, "b l (h p) -> b l h p", h=nheads)
1613
+ dx = rearrange(dx, "b l (h p) -> b l h p", h=nheads)
1614
+ dB = rearrange(dB, "b l (g n) -> b l g n", g=ctx.ngroups)
1615
+ dC = rearrange(dC, "b l (g n) -> b l g n", g=ctx.ngroups)
1616
+ if outproj_weight is not None:
1617
+ dout_og = dout
1618
+ dout = F.linear(dout, outproj_weight.t())
1619
+ if d_nonssm > 0:
1620
+ dout0, dout = dout.split([d_nonssm, dim], dim=-1)
1621
+ _swiglu_bwd(zx0, dout0, dxy=dzx0, recompute_output=True, out=out0_recompute)
1622
+ dout = rearrange(dout, "b s (h p) -> b s h p", p=headdim)
1623
+ if rmsnorm_weight is None:
1624
+ dz = rearrange(dz, "b l (h p) -> b l h p", h=nheads)
1625
+ dx, ddt, dA, dB, dC, dD, dz, ddt_bias, dinitial_states, *rest = (
1626
+ _mamba_chunk_scan_combined_bwd(
1627
+ dout,
1628
+ x,
1629
+ dt,
1630
+ A,
1631
+ B,
1632
+ C,
1633
+ out,
1634
+ ctx.chunk_size,
1635
+ D=D,
1636
+ z=z,
1637
+ dt_bias=dt_bias,
1638
+ initial_states=initial_states,
1639
+ dfinal_states=dfinal_states,
1640
+ seq_idx=seq_idx,
1641
+ dt_softplus=True,
1642
+ dt_limit=ctx.dt_limit,
1643
+ dx=dx,
1644
+ ddt=ddt_given,
1645
+ dB=dB,
1646
+ dC=dC,
1647
+ dz=dz,
1648
+ recompute_output=recompute_output,
1649
+ )
1650
+ )
1651
+ out_for_linear = (
1652
+ rearrange(rest[0], "b s h p -> b s (h p)") if recompute_output else None
1653
+ )
1654
+ drmsnorm_weight = None
1655
+ else:
1656
+ batch = dout.shape[0]
1657
+ dy_rms = rearrange(dout, "b s h p -> (b s) (h p)")
1658
+ dz = rearrange(dz, "b l d -> (b l) d")
1659
+ x_rms = rearrange(out, "b s h p -> (b s) (h p)")
1660
+ z_rms = rearrange(z, "b s h p -> (b s) (h p)")
1661
+ out1_recompute = (
1662
+ rearrange(out1_recompute, "b s d -> (b s) d")
1663
+ if recompute_output
1664
+ else None
1665
+ )
1666
+ dout, drmsnorm_weight, _, dz, *rest = _layer_norm_bwd(
1667
+ dy_rms,
1668
+ x_rms,
1669
+ rmsnorm_weight,
1670
+ None,
1671
+ ctx.rmsnorm_eps,
1672
+ None,
1673
+ rstd,
1674
+ z_rms,
1675
+ group_size=dim // ctx.ngroups,
1676
+ norm_before_gate=ctx.norm_before_gate,
1677
+ is_rms_norm=True,
1678
+ recompute_output=recompute_output,
1679
+ dz=dz,
1680
+ out=out1_recompute if recompute_output else None,
1681
+ )
1682
+ out_for_linear = out_recompute if recompute_output else None
1683
+ dout = rearrange(dout, "(b s) (h p) -> b s h p", b=batch, p=headdim)
1684
+ dx, ddt, dA, dB, dC, dD, _, ddt_bias, dinitial_states = (
1685
+ _mamba_chunk_scan_combined_bwd(
1686
+ dout,
1687
+ x,
1688
+ dt,
1689
+ A,
1690
+ B,
1691
+ C,
1692
+ out,
1693
+ ctx.chunk_size,
1694
+ D=D,
1695
+ z=None,
1696
+ dt_bias=dt_bias,
1697
+ initial_states=initial_states,
1698
+ dfinal_states=dfinal_states,
1699
+ seq_idx=seq_idx,
1700
+ dt_softplus=True,
1701
+ dt_limit=ctx.dt_limit,
1702
+ dx=dx,
1703
+ ddt=ddt_given,
1704
+ dB=dB,
1705
+ dC=dC,
1706
+ )
1707
+ )
1708
+
1709
+ if outproj_weight is not None:
1710
+ doutproj_weight = torch.einsum("bso,bsd->od", dout_og, out_for_linear)
1711
+ doutproj_bias = (
1712
+ dout_og.sum(dim=(0, 1)) if outproj_bias is not None else None
1713
+ )
1714
+ else:
1715
+ doutproj_weight, doutproj_bias = None, None
1716
+ for sliced, t in zip(slices, dense):
1717
+ sliced.copy_(t)
1718
+ dxBC_given = rearrange(dxBC_given, "b s d -> b d s")
1719
+ dxBC_given_update, dweight, dbias, *_ = causal_conv1d_cuda.causal_conv1d_bwd(
1720
+ rearrange_and_update_stride(xBC, "b s d -> b d s"),
1721
+ conv1d_weight,
1722
+ conv1d_bias,
1723
+ rearrange(dxBC, "b s d -> b d s"),
1724
+ seq_idx,
1725
+ None,
1726
+ None,
1727
+ rearrange_and_update_stride(dxBC_given),
1728
+ False,
1729
+ ctx.activation in ["silu", "swish"],
1730
+ )
1731
+ if dxBC_given.stride() != dxBC_given_update.stride():
1732
+ dxBC_given.copy_(dxBC_given_update)
1733
+ else:
1734
+ dxBC_given = dxBC_given_update
1735
+ dxBC_given = rearrange(dxBC_given, "b d s -> b s d")
1736
+ return (
1737
+ dzxbcdt,
1738
+ dweight,
1739
+ dbias,
1740
+ ddt_bias,
1741
+ dA,
1742
+ dD,
1743
+ None,
1744
+ dinitial_states,
1745
+ None,
1746
+ None,
1747
+ None,
1748
+ None,
1749
+ drmsnorm_weight,
1750
+ None,
1751
+ doutproj_weight,
1752
+ doutproj_bias,
1753
+ None,
1754
+ None,
1755
+ None,
1756
+ )
1757
+
1758
+
1759
+ def mamba_split_conv1d_scan_combined(
1760
+ zxbcdt,
1761
+ conv1d_weight,
1762
+ conv1d_bias,
1763
+ dt_bias,
1764
+ A,
1765
+ D,
1766
+ chunk_size,
1767
+ initial_states=None,
1768
+ seq_idx=None,
1769
+ dt_limit=(0.0, float("inf")),
1770
+ return_final_states=False,
1771
+ activation="silu",
1772
+ rmsnorm_weight=None,
1773
+ rmsnorm_eps=1e-6,
1774
+ outproj_weight=None,
1775
+ outproj_bias=None,
1776
+ headdim=None,
1777
+ ngroups=1,
1778
+ norm_before_gate=True,
1779
+ ):
1780
+ """
1781
+ Argument:
1782
+ zxbcdt: (batch, seqlen, 2 * dim + 2 * ngroups * dstate + nheads) where dim == nheads * headdim
1783
+ conv1d_weight: (dim + 2 * ngroups * dstate, width)
1784
+ conv1d_bias: (dim + 2 * ngroups * dstate,)
1785
+ dt_bias: (nheads,)
1786
+ A: (nheads)
1787
+ D: (nheads, headdim) or (nheads,)
1788
+ initial_states: (batch, nheads, headdim, dstate)
1789
+ seq_idx: (batch, seqlen), int32
1790
+ rmsnorm_weight: (dim,)
1791
+ outproj_weight: (out_dim, dim)
1792
+ outproj_bias: (out_dim,)
1793
+ headdim: if D is 1D, headdim must be passed in
1794
+ norm_before_gate: if True, we do RMSNorm(x) * F.silu(z). If False, we do RMSNorm(x * F.silu(z))
1795
+ Return:
1796
+ out: (batch, seqlen, dim)
1797
+ """
1798
+ return MambaSplitConv1dScanCombinedFn.apply(
1799
+ zxbcdt,
1800
+ conv1d_weight,
1801
+ conv1d_bias,
1802
+ dt_bias,
1803
+ A,
1804
+ D,
1805
+ chunk_size,
1806
+ initial_states,
1807
+ seq_idx,
1808
+ dt_limit,
1809
+ return_final_states,
1810
+ activation,
1811
+ rmsnorm_weight,
1812
+ rmsnorm_eps,
1813
+ outproj_weight,
1814
+ outproj_bias,
1815
+ headdim,
1816
+ ngroups,
1817
+ norm_before_gate,
1818
+ )
1819
+
1820
+
1821
+ def mamba_split_conv1d_scan_ref(
1822
+ zxbcdt,
1823
+ conv1d_weight,
1824
+ conv1d_bias,
1825
+ dt_bias,
1826
+ A,
1827
+ D,
1828
+ chunk_size,
1829
+ dt_limit=(0.0, float("inf")),
1830
+ activation="silu",
1831
+ rmsnorm_weight=None,
1832
+ rmsnorm_eps=1e-6,
1833
+ outproj_weight=None,
1834
+ outproj_bias=None,
1835
+ headdim=None,
1836
+ ngroups=1,
1837
+ norm_before_gate=True,
1838
+ ):
1839
+ """
1840
+ Argument:
1841
+ zxbcdt: (batch, seqlen, 2 * dim + 2 * ngroups * dstate + nheads) where dim == nheads * headdim
1842
+ conv1d_weight: (dim + 2 * ngroups * dstate, width)
1843
+ conv1d_bias: (dim + 2 * ngroups * dstate,)
1844
+ dt_bias: (nheads,)
1845
+ A: (nheads)
1846
+ D: (nheads, headdim) or (nheads,)
1847
+ rmsnorm_weight: (dim,)
1848
+ outproj_weight: (out_dim, dim)
1849
+ outproj_bias: (out_dim,)
1850
+ headdim: if D is 1D, headdim must be passed in
1851
+ norm_before_gate: if True, we do RMSNorm(x) * F.silu(z). If False, we do RMSNorm(x * F.silu(z))
1852
+ Return:
1853
+ out: (batch, seqlen, dim)
1854
+ """
1855
+ if D.dim() == 1:
1856
+ assert headdim is not None
1857
+ (nheads,) = D.shape
1858
+ else:
1859
+ nheads, headdim = D.shape
1860
+ assert nheads % ngroups == 0
1861
+ batch, seqlen, _ = zxbcdt.shape
1862
+ dim = nheads * headdim
1863
+ dstate = (zxbcdt.shape[-1] - 2 * dim - nheads) // ngroups // 2
1864
+ assert zxbcdt.shape == (batch, seqlen, 2 * dim + 2 * ngroups * dstate + nheads)
1865
+ assert dt_bias.shape == (nheads,)
1866
+ assert A.shape == (nheads,)
1867
+ if rmsnorm_weight is not None:
1868
+ assert rmsnorm_weight.shape == (dim,)
1869
+ z, xBC, dt = torch.split(zxbcdt, [dim, dim + 2 * ngroups * dstate, nheads], dim=-1)
1870
+ xBC = rearrange(
1871
+ causal_conv1d_fn(
1872
+ rearrange(xBC, "b s d -> b d s"),
1873
+ conv1d_weight,
1874
+ conv1d_bias,
1875
+ activation=activation,
1876
+ ),
1877
+ "b d s -> b s d",
1878
+ )
1879
+ x, B, C = torch.split(xBC, [dim, ngroups * dstate, ngroups * dstate], dim=-1)
1880
+ x = rearrange(x, "b l (h p) -> b l h p", h=nheads)
1881
+ B = rearrange(B, "b l (g n) -> b l g n", g=ngroups)
1882
+ C = rearrange(C, "b l (g n) -> b l g n", g=ngroups)
1883
+ z = rearrange(z, "b l (h p) -> b l h p", h=nheads)
1884
+ out = ssd_selective_scan(
1885
+ x,
1886
+ dt.to(x.dtype),
1887
+ A,
1888
+ B,
1889
+ C,
1890
+ D=D.float(),
1891
+ z=z if rmsnorm_weight is None else None,
1892
+ dt_bias=dt_bias,
1893
+ dt_softplus=True,
1894
+ dt_limit=dt_limit,
1895
+ )
1896
+ out = rearrange(out, "b s h p -> b s (h p)")
1897
+ if rmsnorm_weight is not None:
1898
+ out = rmsnorm_fn(
1899
+ out,
1900
+ rmsnorm_weight,
1901
+ None,
1902
+ z=rearrange(z, "b l h p -> b l (h p)"),
1903
+ eps=rmsnorm_eps,
1904
+ norm_before_gate=norm_before_gate,
1905
+ )
1906
+ if outproj_weight is not None:
1907
+ out = F.linear(out, outproj_weight, outproj_bias)
1908
+ return out
build/torch213-cxx11-xpu20260-x86_64-linux/ops/triton/ssd_state_passing.py ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ """We want triton==2.1.0 or 2.2.0 for this
4
+ """
5
+
6
+ import math
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ import triton
11
+ import triton.language as tl
12
+
13
+ from einops import rearrange, repeat
14
+
15
+ from ...utils.device import device_guard
16
+
17
+
18
+ @triton.autotune(
19
+ configs=[
20
+ triton.Config({'BLOCK_SIZE': 64}),
21
+ triton.Config({'BLOCK_SIZE': 128}),
22
+ triton.Config({'BLOCK_SIZE': 256}),
23
+ triton.Config({'BLOCK_SIZE': 512}),
24
+ triton.Config({'BLOCK_SIZE': 1024}),
25
+ triton.Config({'BLOCK_SIZE': 2048}),
26
+ ],
27
+ key=['dim'],
28
+ )
29
+ @triton.jit
30
+ def _state_passing_fwd_kernel(
31
+ # Pointers to matrices
32
+ states_ptr, out_ptr, final_states_ptr, dA_cs_ptr, initstates_ptr, seq_idx_ptr,
33
+ # Matrix dimensions
34
+ dim, nchunks, seqlen, chunk_size,
35
+ # Strides
36
+ stride_states_batch, stride_states_chunk, stride_states_head, stride_states_dim,
37
+ stride_out_batch, stride_out_chunk, stride_out_head, stride_out_dim,
38
+ stride_final_states_batch, stride_final_states_head, stride_final_states_dim,
39
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head,
40
+ stride_initstates_batch, stride_initstates_head, stride_initstates_dim,
41
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
42
+ # Meta-parameters
43
+ HAS_INITSTATES: tl.constexpr,
44
+ HAS_SEQ_IDX: tl.constexpr,
45
+ BLOCK_SIZE: tl.constexpr,
46
+ ):
47
+ pid_b = tl.program_id(axis=1)
48
+ pid_h = tl.program_id(axis=2)
49
+ pid_m = tl.program_id(axis=0)
50
+ states_ptr += pid_b * stride_states_batch + pid_h * stride_states_head
51
+ dA_cs_ptr += pid_b * stride_dA_cs_batch + pid_h * stride_dA_cs_head
52
+ out_ptr += pid_b * stride_out_batch + pid_h * stride_out_head
53
+ final_states_ptr += pid_b * stride_final_states_batch + pid_h * stride_final_states_head
54
+ if HAS_INITSTATES:
55
+ initstates_ptr += pid_b * stride_initstates_batch + pid_h * stride_initstates_head
56
+ if HAS_SEQ_IDX:
57
+ seq_idx_ptr += pid_b * stride_seq_idx_batch
58
+
59
+ offs_m = pid_m * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
60
+ states_ptrs = states_ptr + offs_m * stride_states_dim
61
+ out_ptrs = out_ptr + offs_m * stride_out_dim
62
+ final_states_ptrs = final_states_ptr + offs_m * stride_final_states_dim
63
+
64
+ if not HAS_INITSTATES:
65
+ states = tl.zeros((BLOCK_SIZE, ), dtype=tl.float32)
66
+ else:
67
+ initstates_ptrs = initstates_ptr + offs_m * stride_initstates_dim
68
+ states = tl.load(initstates_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
69
+ tl.store(out_ptrs, states, mask=offs_m < dim)
70
+ out_ptrs += stride_out_chunk
71
+ seq_idx = 0
72
+ for c in range(nchunks):
73
+ new_states = tl.load(states_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
74
+ dA_cs = tl.load(dA_cs_ptr).to(tl.float32)
75
+ scale = tl.exp(dA_cs)
76
+ if HAS_SEQ_IDX:
77
+ seq_idx_new = tl.load(seq_idx_ptr + (min((c + 1) * chunk_size, seqlen) - 1) * stride_seq_idx_seqlen)
78
+ scale = tl.where(seq_idx_new == seq_idx, scale, 0.0)
79
+ seq_idx = seq_idx_new
80
+ states = scale * states + new_states
81
+ if c < nchunks - 1:
82
+ tl.store(out_ptrs, states, mask=offs_m < dim)
83
+ else:
84
+ tl.store(final_states_ptrs, states, mask=offs_m < dim)
85
+ states_ptrs += stride_states_chunk
86
+ dA_cs_ptr += stride_dA_cs_chunk
87
+ out_ptrs += stride_out_chunk
88
+
89
+
90
+ @triton.autotune(
91
+ configs=[
92
+ triton.Config({'BLOCK_SIZE': 64}),
93
+ triton.Config({'BLOCK_SIZE': 128}),
94
+ triton.Config({'BLOCK_SIZE': 256}),
95
+ triton.Config({'BLOCK_SIZE': 512}),
96
+ triton.Config({'BLOCK_SIZE': 1024}),
97
+ triton.Config({'BLOCK_SIZE': 2048}),
98
+ ],
99
+ key=['dim'],
100
+ reset_to_zero=["ddA_cs_ptr"],
101
+ )
102
+ @triton.jit
103
+ def _state_passing_bwd_kernel(
104
+ # Pointers to matrices
105
+ dout_ptr, out_ptr, dA_cs_ptr, dfinal_states_ptr, seq_idx_ptr,
106
+ dstates_ptr, ddA_cs_ptr, dinitstates_ptr, states_converted_ptr,
107
+ # Matrix dimensions
108
+ dim, nchunks, seqlen, chunk_size,
109
+ # Strides
110
+ stride_dout_batch, stride_dout_chunk, stride_dout_head, stride_dout_dim,
111
+ stride_out_batch, stride_out_chunk, stride_out_head, stride_out_dim,
112
+ stride_dA_cs_batch, stride_dA_cs_chunk, stride_dA_cs_head,
113
+ stride_dfinal_states_batch, stride_dfinal_states_head, stride_dfinal_states_dim,
114
+ stride_seq_idx_batch, stride_seq_idx_seqlen,
115
+ stride_dstates_batch, stride_dstates_chunk, stride_dstates_head, stride_dstates_dim,
116
+ stride_ddA_cs_batch, stride_ddA_cs_chunk, stride_ddA_cs_head,
117
+ stride_dinitstates_batch, stride_dinitstates_head, stride_dinitstates_dim,
118
+ # Meta-parameters
119
+ CONVERT_STATES: tl.constexpr,
120
+ HAS_DFINAL_STATES: tl.constexpr,
121
+ HAS_DINITSTATES: tl.constexpr,
122
+ HAS_SEQ_IDX: tl.constexpr,
123
+ BLOCK_SIZE: tl.constexpr,
124
+ ):
125
+ pid_b = tl.program_id(axis=1)
126
+ pid_h = tl.program_id(axis=2)
127
+ pid_m = tl.program_id(axis=0)
128
+ dstates_ptr += pid_b * stride_dstates_batch + pid_h * stride_dstates_head + (nchunks - 1) * stride_dstates_chunk
129
+ dA_cs_ptr += pid_b * stride_dA_cs_batch + pid_h * stride_dA_cs_head + (nchunks - 1) * stride_dA_cs_chunk
130
+ ddA_cs_ptr += pid_b * stride_ddA_cs_batch + pid_h * stride_ddA_cs_head + (nchunks - 1) * stride_ddA_cs_chunk + pid_m
131
+ out_ptr += pid_b * stride_out_batch + pid_h * stride_out_head + (nchunks - 1) * stride_out_chunk
132
+ dout_ptr += pid_b * stride_dout_batch + pid_h * stride_dout_head + (nchunks - 1) * stride_dout_chunk
133
+ if CONVERT_STATES:
134
+ states_converted_ptr += pid_b * stride_out_batch + pid_h * stride_out_head + (nchunks - 1) * stride_out_chunk
135
+ if HAS_DFINAL_STATES:
136
+ dfinal_states_ptr += pid_b * stride_dfinal_states_batch + pid_h * stride_dfinal_states_head
137
+ if HAS_DINITSTATES:
138
+ dinitstates_ptr += pid_b * stride_dinitstates_batch + pid_h * stride_dinitstates_head
139
+ if HAS_SEQ_IDX:
140
+ seq_idx_ptr += pid_b * stride_seq_idx_batch
141
+
142
+ offs_m = pid_m * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
143
+ dstates_ptrs = dstates_ptr + offs_m * stride_dstates_dim
144
+ out_ptrs = out_ptr + offs_m * stride_out_dim
145
+ dout_ptrs = dout_ptr + offs_m * stride_dout_dim
146
+ if CONVERT_STATES:
147
+ states_converted_ptrs = states_converted_ptr + offs_m * stride_out_dim
148
+
149
+ if HAS_DFINAL_STATES:
150
+ dstates = tl.load(dfinal_states_ptr + offs_m * stride_dfinal_states_dim, mask=offs_m < dim, other=0.0).to(tl.float32)
151
+ else:
152
+ dstates = tl.zeros((BLOCK_SIZE, ), dtype=tl.float32)
153
+ tl.store(dstates_ptrs, dstates, mask=offs_m < dim)
154
+ if HAS_SEQ_IDX:
155
+ seq_idx = tl.load(seq_idx_ptr + (seqlen - 1) * stride_seq_idx_seqlen)
156
+ dstates_ptrs -= stride_dstates_chunk
157
+ for c in range(nchunks - 1):
158
+ dA_cs = tl.load(dA_cs_ptr).to(tl.float32)
159
+ scale = tl.exp(dA_cs)
160
+ if HAS_SEQ_IDX:
161
+ seq_idx_new = tl.load(seq_idx_ptr + (((nchunks - c - 1) * chunk_size - 1) * stride_seq_idx_seqlen))
162
+ scale = tl.where(seq_idx_new == seq_idx, scale, 0.0)
163
+ seq_idx = seq_idx_new
164
+ out = tl.load(out_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
165
+ if CONVERT_STATES:
166
+ tl.store(states_converted_ptrs, out, mask=offs_m < dim)
167
+ ddA = tl.sum(out * dstates) * scale
168
+ tl.store(ddA_cs_ptr, ddA)
169
+ dout = tl.load(dout_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
170
+ dstates = scale * dstates + dout
171
+ tl.store(dstates_ptrs, dstates, mask=offs_m < dim)
172
+ dout_ptrs -= stride_dout_chunk
173
+ dstates_ptrs -= stride_dstates_chunk
174
+ dA_cs_ptr -= stride_dA_cs_chunk
175
+ ddA_cs_ptr -= stride_ddA_cs_chunk
176
+ out_ptrs -= stride_out_chunk
177
+ if CONVERT_STATES:
178
+ states_converted_ptrs -= stride_out_chunk
179
+ if CONVERT_STATES:
180
+ out = tl.load(out_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
181
+ tl.store(states_converted_ptrs, out, mask=offs_m < dim)
182
+ if not HAS_DINITSTATES:
183
+ tl.store(ddA_cs_ptr, 0.0)
184
+ else:
185
+ dA_cs = tl.load(dA_cs_ptr).to(tl.float32)
186
+ scale = tl.exp(dA_cs)
187
+ if HAS_SEQ_IDX:
188
+ scale = tl.where(seq_idx == 0, scale, 0.0)
189
+ out = tl.load(out_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
190
+ ddA = tl.sum(out * dstates) * scale
191
+ tl.store(ddA_cs_ptr, ddA)
192
+ dout = tl.load(dout_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
193
+ dstates = scale * dstates + dout
194
+ tl.store(dinitstates_ptr + offs_m * stride_dinitstates_dim, dstates, mask=offs_m < dim)
195
+
196
+
197
+ def _state_passing_fwd(states, dA_chunk_cumsum, initial_states=None, seq_idx=None, chunk_size=None,
198
+ out_dtype=None):
199
+ batch, nchunks, nheads, dim = states.shape
200
+ assert dA_chunk_cumsum.shape == (batch, nheads, nchunks)
201
+ if initial_states is not None:
202
+ assert initial_states.shape == (batch, nheads, dim)
203
+ if seq_idx is not None:
204
+ assert chunk_size is not None
205
+ seqlen = seq_idx.shape[-1]
206
+ assert seq_idx.shape == (batch, seqlen)
207
+ out_dtype = states.dtype if out_dtype is None else out_dtype
208
+ out = torch.empty((batch, nchunks, nheads, dim), device=states.device, dtype=out_dtype)
209
+ final_states = torch.empty((batch, nheads, dim), device=states.device, dtype=torch.float32)
210
+ grid = lambda META: (triton.cdiv(dim, META['BLOCK_SIZE']), batch, nheads)
211
+ with device_guard(states):
212
+ _state_passing_fwd_kernel[grid](
213
+ states, out, final_states, dA_chunk_cumsum, initial_states, seq_idx,
214
+ dim, nchunks, seqlen if seq_idx is not None else 0, chunk_size if seq_idx is not None else 0,
215
+ states.stride(0), states.stride(1), states.stride(2), states.stride(3),
216
+ out.stride(0), out.stride(1), out.stride(2), out.stride(3),
217
+ final_states.stride(0), final_states.stride(1), final_states.stride(2),
218
+ dA_chunk_cumsum.stride(0), dA_chunk_cumsum.stride(2), dA_chunk_cumsum.stride(1),
219
+ *((initial_states.stride(0), initial_states.stride(1), initial_states.stride(2))
220
+ if initial_states is not None else (0, 0, 0)),
221
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
222
+ HAS_INITSTATES=initial_states is not None,
223
+ HAS_SEQ_IDX=seq_idx is not None,
224
+ )
225
+ return out, final_states
226
+
227
+
228
+ def _state_passing_bwd(
229
+ states, dA_chunk_cumsum, dout, dfinal_states=None, seq_idx=None, has_initial_states=None,
230
+ dstates_dtype=None, states_dtype=None, chunk_size=None
231
+ ):
232
+ """
233
+ states contains the initial_states at index 0. The final states are not included in states.
234
+ """
235
+ batch, nchunks, nheads, dim = states.shape
236
+ assert dA_chunk_cumsum.shape == (batch, nheads, nchunks)
237
+ assert dout.shape == (batch, nchunks, nheads, dim)
238
+ if seq_idx is not None:
239
+ assert chunk_size is not None
240
+ seqlen = seq_idx.shape[-1]
241
+ assert seq_idx.shape == (batch, seqlen)
242
+ dstates = torch.empty_like(dout, dtype=dstates_dtype if dstates_dtype is not None else dout.dtype)
243
+ if states_dtype is not None and states_dtype != states.dtype:
244
+ states_converted = torch.empty_like(states, dtype=dstates_dtype if dstates_dtype is not None else dout.dtype)
245
+ assert states_converted.stride() == states.stride()
246
+ else:
247
+ states_converted = None
248
+ if has_initial_states:
249
+ dinitstates = torch.empty_like(dstates[:, 0])
250
+ else:
251
+ dinitstates = None
252
+ if dfinal_states is not None:
253
+ assert dfinal_states.shape == (batch, nheads, dim)
254
+ BLOCK_SIZE_min = 64
255
+ n_blocks = (dim + BLOCK_SIZE_min - 1) // BLOCK_SIZE_min
256
+ # Zero-initialized so the sum below can cover every block without reading `best_config`.
257
+ ddA_chunk_cumsum = torch.zeros(batch, nheads, nchunks, n_blocks,
258
+ dtype=torch.float32, device=dA_chunk_cumsum.device)
259
+ grid = lambda META: (triton.cdiv(dim, META['BLOCK_SIZE']), batch, nheads)
260
+ with device_guard(dout):
261
+ _state_passing_bwd_kernel[grid](
262
+ dout, states, dA_chunk_cumsum, dfinal_states, seq_idx,
263
+ dstates, ddA_chunk_cumsum, dinitstates, states_converted,
264
+ dim, nchunks, seqlen if seq_idx is not None else 0, chunk_size if seq_idx is not None else 0,
265
+ dout.stride(0), dout.stride(1), dout.stride(2), dout.stride(3),
266
+ states.stride(0), states.stride(1), states.stride(2), states.stride(3),
267
+ dA_chunk_cumsum.stride(0), dA_chunk_cumsum.stride(2), dA_chunk_cumsum.stride(1),
268
+ *((dfinal_states.stride(0), dfinal_states.stride(1), dfinal_states.stride(2))
269
+ if dfinal_states is not None else (0, 0, 0)),
270
+ *((seq_idx.stride(0), seq_idx.stride(1)) if seq_idx is not None else (0, 0)),
271
+ dstates.stride(0), dstates.stride(1), dstates.stride(2), dstates.stride(3),
272
+ ddA_chunk_cumsum.stride(0), ddA_chunk_cumsum.stride(2), ddA_chunk_cumsum.stride(1),
273
+ *((dinitstates.stride(0), dinitstates.stride(1), dinitstates.stride(2))
274
+ if dinitstates is not None else (0, 0, 0)),
275
+ CONVERT_STATES=states_converted is not None,
276
+ HAS_DFINAL_STATES=dfinal_states is not None,
277
+ HAS_DINITSTATES=dinitstates is not None,
278
+ HAS_SEQ_IDX=seq_idx is not None,
279
+ )
280
+ ddA_chunk_cumsum = ddA_chunk_cumsum.sum(dim=-1).to(dtype=dA_chunk_cumsum.dtype)
281
+ if states_dtype is not None and states_dtype == states.dtype:
282
+ states_converted = states
283
+ return (dstates, ddA_chunk_cumsum, dinitstates) if states_dtype is None else (dstates, ddA_chunk_cumsum, dinitstates, states_converted)
284
+
285
+
286
+ class StatePassingFn(torch.autograd.Function):
287
+
288
+ @staticmethod
289
+ def forward(ctx, states, dA_chunk_cumsum, initial_states=None):
290
+ batch, nchunks, nheads, dim = states.shape
291
+ assert dA_chunk_cumsum.shape == (batch, nheads, nchunks)
292
+ if states.stride(-1) != 1:
293
+ states = states.contiguous()
294
+ out, final_states = _state_passing_fwd(states, dA_chunk_cumsum, initial_states)
295
+ ctx.save_for_backward(out, dA_chunk_cumsum)
296
+ ctx.has_initial_states = initial_states is not None
297
+ return out, final_states
298
+
299
+ @staticmethod
300
+ def backward(ctx, dout, dfinal_states):
301
+ out, dA_chunk_cumsum = ctx.saved_tensors
302
+ batch, nchunks, nheads, dim = out.shape
303
+ assert dout.shape == (batch, nchunks, nheads, dim)
304
+ assert dA_chunk_cumsum.shape == (batch, nheads, nchunks)
305
+ assert dfinal_states.shape == (batch, nheads, dim)
306
+ if dout.stride(-1) != 1:
307
+ dout = dout.contiguous()
308
+ dstates, ddA_chunk_cumsum, dinitstates = _state_passing_bwd(
309
+ out, dA_chunk_cumsum, dout, dfinal_states=dfinal_states , has_initial_states=ctx.has_initial_states
310
+ )
311
+ return dstates, ddA_chunk_cumsum, dinitstates
312
+
313
+
314
+ def state_passing(states, dA_chunk_cumsum, initial_states=None):
315
+ """
316
+ Argument:
317
+ states: (batch, nchunks, nheads, dim)
318
+ dA_chunk_cumsum: (batch, nheads, nchunks)
319
+ initial_states: (batch, nheads, dim)
320
+ Return:
321
+ out: (batch, nchunks, nheads, dim)
322
+ final_states: (batch, nheads, dim)
323
+ """
324
+ return StatePassingFn.apply(states, dA_chunk_cumsum, initial_states)
325
+
326
+
327
+ def state_passing_ref(states, dA_chunk_cumsum, initial_states=None):
328
+ """
329
+ Argument:
330
+ states: (batch, nchunks, nheads, dim)
331
+ dA_chunk_cumsum: (batch, nheads, nchunks)
332
+ initial_states: (batch, nheads, dim)
333
+ Return:
334
+ out: (batch, nchunks, nheads, dim)
335
+ final_states: (batch, nheads, dim)
336
+ """
337
+ if initial_states is None:
338
+ initial_states = torch.zeros_like(states[:, 0])
339
+ states = torch.cat([rearrange(initial_states, "b h d -> b 1 h d"), states], dim=1)
340
+ dA_chunk_cumsum = F.pad(dA_chunk_cumsum, (1, 0))
341
+ dA_chunk_cumsum = torch.cumsum(dA_chunk_cumsum, dim=-1)
342
+ nchunks = dA_chunk_cumsum.shape[-1]
343
+ # (batch, nheads, nchunks, nchunks)
344
+ dt_chunk_segment_sum = dA_chunk_cumsum[:, :, :, None] - dA_chunk_cumsum[:, :, None, :]
345
+ # (batch, nheads, nchunks, nchunks)
346
+ decay_chunk = torch.exp(dt_chunk_segment_sum)
347
+ causal_mask = torch.tril(torch.ones(nchunks, nchunks, device=states.device, dtype=bool), diagonal=0)
348
+ decay_chunk = decay_chunk.masked_fill(~causal_mask, 0)
349
+ out = torch.einsum("bhzc,bchd->bzhd", decay_chunk.to(dtype=states.dtype), states)
350
+ return out[:, :-1], out[:, -1]
build/torch213-cxx11-xpu20260-x86_64-linux/utils/__init__.py ADDED
File without changes
build/torch213-cxx11-xpu20260-x86_64-linux/utils/device.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+
4
+ def device_guard(tensor):
5
+ """Replaces ``with torch.cuda.device(t.device.index):``.
6
+
7
+ ``torch.get_device_module`` resolves to ``torch.cuda`` for a CUDA tensor, so
8
+ behaviour there is unchanged.
9
+ """
10
+ return torch.get_device_module(tensor.device).device(tensor.device.index)
11
+
12
+
13
+ def get_sm_count(device):
14
+ """Number of independently schedulable compute units, used to size grids.
15
+
16
+ CUDA and ROCm call this ``multi_processor_count``, Intel ``max_compute_units``.
17
+ """
18
+ props = torch.get_device_module(device).get_device_properties(device)
19
+ count = getattr(props, "multi_processor_count", None)
20
+ if count is None:
21
+ count = getattr(props, "max_compute_units", None)
22
+ if count is None:
23
+ raise RuntimeError(f"cannot determine compute unit count for device {device}")
24
+ return count
build/torch213-cxx11-xpu20260-x86_64-linux/utils/generation.py ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Albert Gu, Tri Dao.
2
+ import gc
3
+ import time
4
+ from collections import namedtuple
5
+ from dataclasses import dataclass, field
6
+ from functools import partial
7
+ from typing import Callable, Optional, Sequence, Union
8
+
9
+ import torch
10
+ import torch.nn.functional as F
11
+ from einops import rearrange, repeat
12
+ from torch import Tensor
13
+ from torch.profiler import ProfilerActivity, profile, record_function
14
+ from transformers.generation import GenerateDecoderOnlyOutput, TextStreamer
15
+
16
+ @dataclass
17
+ class InferenceParams:
18
+ """Inference parameters that are passed to the main model in order
19
+ to efficienly calculate and store the context during inference."""
20
+
21
+ max_seqlen: int
22
+ max_batch_size: int
23
+ seqlen_offset: int = 0
24
+ batch_size_offset: int = 0
25
+ key_value_memory_dict: dict = field(default_factory=dict)
26
+ lengths_per_sample: Optional[Tensor] = None
27
+
28
+ def reset(self, max_seqlen, max_batch_size):
29
+ self.max_seqlen = max_seqlen
30
+ self.max_batch_size = max_batch_size
31
+ self.seqlen_offset = 0
32
+ if self.lengths_per_sample is not None:
33
+ self.lengths_per_sample.zero_()
34
+
35
+
36
+ def modify_logits_for_min_p_filtering(logits, min_p):
37
+ """Set the logits for none min_p values to -inf. Done in-place."""
38
+ if min_p <= 0.0 or min_p >= 1.0:
39
+ return
40
+ indices_to_remove = logits < min_p
41
+ logits.masked_fill_(indices_to_remove, float("-Inf"))
42
+ # https://github.com/NVIDIA/Megatron-LM/blob/0bb597b42c53355a567aba2a1357cc34b9d99ddd/megatron/text_generation/sampling.py
43
+ # https://github.com/huggingface/transformers/blob/a44985b41cfa2de48a5e1de7f1f93b7483da25d1/src/transformers/generation/logits_process.py#L231
44
+ def modify_logits_for_top_k_filtering(logits, top_k):
45
+ """Set the logits for none top-k values to -inf. Done in-place."""
46
+ indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
47
+ logits.masked_fill_(indices_to_remove, float("-Inf"))
48
+
49
+
50
+ # https://github.com/NVIDIA/Megatron-LM/blob/0bb597b42c53355a567aba2a1357cc34b9d99ddd/megatron/text_generation/sampling.py
51
+ # https://github.com/huggingface/transformers/blob/a44985b41cfa2de48a5e1de7f1f93b7483da25d1/src/transformers/generation/logits_process.py#L170
52
+ def modify_logits_for_top_p_filtering(logits, top_p):
53
+ """Set the logits for none top-p values to -inf. Done in-place."""
54
+ if top_p <= 0.0 or top_p >= 1.0:
55
+ return
56
+ # First sort and calculate cumulative sum of probabilities.
57
+ sorted_logits, sorted_indices = torch.sort(logits, descending=False)
58
+ cumulative_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1)
59
+ # Remove tokens with cumulative top_p above the threshold (token with 0 are kept)
60
+ sorted_indices_to_remove = cumulative_probs <= (1 - top_p)
61
+ # scatter sorted tensors to original indexing
62
+ indices_to_remove = sorted_indices_to_remove.scatter(
63
+ 1, sorted_indices, sorted_indices_to_remove
64
+ )
65
+ logits.masked_fill_(indices_to_remove, float("-inf"))
66
+
67
+
68
+ def modify_logit_for_repetition_penalty(logits, prev_output_tokens, repetition_penalty=1.0):
69
+ """Apply repetition penalty. See https://arxiv.org/abs/1909.05858
70
+ logits: (batch_size, vocab_size)
71
+ prev_output_tokens: (batch_size, seq_len)
72
+ """
73
+ if repetition_penalty == 1.0:
74
+ return logits
75
+ score = torch.gather(logits, 1, prev_output_tokens)
76
+ # if score < 0 then repetition penalty has to be multiplied to reduce the previous token probability
77
+ score = torch.where(score < 0, score * repetition_penalty, score / repetition_penalty)
78
+ logits.scatter_(1, prev_output_tokens, score)
79
+ return logits
80
+
81
+
82
+ def sample(logits, top_k=1, top_p=0.0, min_p=0.0, temperature=1.0):
83
+ """Sample from top-k logits.
84
+ Arguments:
85
+ logits: Tensor of shape (batch_size, vocab_size)
86
+ """
87
+ if top_k == 1: # Short-circuit for greedy decoding
88
+ return logits.argmax(dim=-1)
89
+ else:
90
+ if top_p > 0.0:
91
+ assert top_p <= 1.0, "top-p should be in (0, 1]."
92
+ if top_k > 0:
93
+ top_k = min(top_k, logits.size(-1)) # Safety check
94
+ logits_top, indices = torch.topk(logits, top_k, dim=-1)
95
+ if temperature != 1.0:
96
+ logits_top /= temperature
97
+ modify_logits_for_top_p_filtering(logits_top, top_p)
98
+ return indices[
99
+ torch.arange(indices.shape[0], device=indices.device),
100
+ torch.multinomial(torch.softmax(logits_top, dim=-1), num_samples=1).squeeze(dim=-1),
101
+ ]
102
+ else:
103
+ if min_p > 0.0:
104
+ logits_top = logits.clone()
105
+ max_prob = logits_top[..., 0].item()
106
+ min_prob = max_prob * min_p
107
+ modify_logits_for_min_p_filtering(logits_top, min_prob)
108
+ if temperature != 1.0:
109
+ logits_top /= temperature
110
+ return torch.multinomial(torch.softmax(logits_top, dim=-1), num_samples=1).squeeze(dim=-1)
111
+ # Clone so that when we modify for top_p we don't change the original logits
112
+ logits_top = logits / temperature if temperature != 1.0 else logits.clone()
113
+ modify_logits_for_top_p_filtering(logits_top, top_p)
114
+ return torch.multinomial(torch.softmax(logits_top, dim=-1), num_samples=1).squeeze(
115
+ dim=-1
116
+ )
117
+
118
+
119
+ @torch.inference_mode()
120
+ def decode(
121
+ input_ids,
122
+ model,
123
+ max_length,
124
+ top_k=1,
125
+ top_p=0.0,
126
+ min_p=0.0,
127
+ temperature=1.0,
128
+ repetition_penalty=1.0,
129
+ eos_token_id=None,
130
+ teacher_outputs=None,
131
+ vocab_size=None,
132
+ cg=False,
133
+ enable_timing=False,
134
+ output_scores=False,
135
+ streamer: Optional[TextStreamer] = None
136
+ ):
137
+ """Decoding, either greedy or with top-k or top-p sampling.
138
+ If top-k = 0, don't limit the number of candidates (pure sampling).
139
+ Top-k and top-p can be used together. If top_k > 0 and top_p > 0, then top-k is applied first,
140
+ then top-p.
141
+ We assume that all sequences in the same batch have the same length.
142
+
143
+ Arguments:
144
+ input_ids: (batch, seq_len)
145
+ max_length: int
146
+ teacher_outputs (optional): (batch, seq_len). If provided, instead of sampling from the
147
+ logits, the next token is taken from the teacher_outputs. Useful for testing.
148
+ Returns: GreedySearchDecoderOnlyOutput or SampleDecoderOnlyOutput, with the following fields:
149
+ sequences: (batch, max_length)
150
+ scores: tuples of (batch, vocab_size)
151
+ """
152
+ if streamer is not None:
153
+ streamer.put(input_ids.cpu())
154
+
155
+ batch_size, seqlen_og = input_ids.shape
156
+ teacher_output_len = teacher_outputs.shape[1] if teacher_outputs is not None else 0
157
+ if cg:
158
+ if not hasattr(model, "_decoding_cache"):
159
+ model._decoding_cache = None
160
+ model._decoding_cache = update_graph_cache(
161
+ model,
162
+ model._decoding_cache,
163
+ batch_size,
164
+ seqlen_og,
165
+ max_length,
166
+ )
167
+ inference_params = model._decoding_cache.inference_params
168
+ inference_params.reset(max_length, batch_size)
169
+ else:
170
+ inference_params = InferenceParams(max_seqlen=max_length, max_batch_size=batch_size)
171
+
172
+ def get_logits(input_ids, inference_params):
173
+ decoding = inference_params.seqlen_offset > 0
174
+ if decoding:
175
+ position_ids = torch.full(
176
+ (batch_size, 1),
177
+ inference_params.seqlen_offset,
178
+ dtype=torch.long,
179
+ device=input_ids.device,
180
+ )
181
+ else:
182
+ position_ids = None
183
+ if not cg or not decoding:
184
+ logits = model(
185
+ input_ids,
186
+ position_ids=position_ids,
187
+ inference_params=inference_params,
188
+ num_last_tokens=1,
189
+ ).logits.squeeze(dim=1)
190
+ else:
191
+ logits = model._decoding_cache.run(
192
+ input_ids, position_ids, inference_params.seqlen_offset
193
+ ).squeeze(dim=1)
194
+ return logits[..., :vocab_size] if vocab_size is not None else logits
195
+
196
+ def sample_tokens(logits, inference_params):
197
+ if teacher_outputs is None or teacher_output_len <= inference_params.seqlen_offset:
198
+ token = sample(logits, top_k=top_k, top_p=top_p, min_p=min_p, temperature=temperature)
199
+ else:
200
+ token = teacher_outputs[:, inference_params.seqlen_offset]
201
+ # return rearrange(token, "b -> b 1")
202
+ return token.unsqueeze(1)
203
+
204
+ def should_stop(current_token, inference_params):
205
+ if inference_params.seqlen_offset == 0:
206
+ return False
207
+ if eos_token_id is not None and (current_token == eos_token_id).all():
208
+ return True
209
+ if inference_params.seqlen_offset >= max_length - 1:
210
+ return True
211
+ return False
212
+
213
+ start = torch.cuda.Event(enable_timing=enable_timing)
214
+ end = torch.cuda.Event(enable_timing=enable_timing)
215
+
216
+ if enable_timing:
217
+ start.record()
218
+ scores, sequences = [], [input_ids]
219
+ sequences_cat = input_ids
220
+ while not should_stop(sequences[-1], inference_params):
221
+ logits = get_logits(sequences[-1], inference_params)
222
+ if output_scores:
223
+ scores.append(logits.clone())
224
+ inference_params.seqlen_offset += sequences[-1].shape[1]
225
+ if repetition_penalty == 1.0:
226
+ sampled_tokens = sample_tokens(logits, inference_params)
227
+ else:
228
+ logits = modify_logit_for_repetition_penalty(
229
+ logits, sequences_cat, repetition_penalty
230
+ )
231
+ sampled_tokens = sample_tokens(logits, inference_params)
232
+ sequences_cat = torch.cat([sequences_cat, sampled_tokens], dim=1)
233
+ sequences.append(sampled_tokens)
234
+ if streamer is not None:
235
+ streamer.put(sampled_tokens.cpu())
236
+ if streamer is not None:
237
+ streamer.end()
238
+ if enable_timing:
239
+ end.record()
240
+ torch.cuda.synchronize()
241
+ print(f"Prompt processing + decoding time: {(start.elapsed_time(end)):.0f}ms")
242
+ output_cls = GreedySearchDecoderOnlyOutput if top_k == 1 else SampleDecoderOnlyOutput
243
+ return output_cls(sequences=torch.cat(sequences, dim=1), scores=tuple(scores))
244
+
245
+
246
+ class GenerationMixin:
247
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
248
+ raise NotImplementedError
249
+
250
+ def generate(
251
+ self,
252
+ input_ids,
253
+ max_length,
254
+ top_k=1,
255
+ top_p=0.0,
256
+ min_p=0.0,
257
+ temperature=1.0,
258
+ return_dict_in_generate=False,
259
+ output_scores=False,
260
+ **kwargs,
261
+ ):
262
+ output = decode(
263
+ input_ids, self, max_length, top_k=top_k, top_p=top_p, min_p = min_p, temperature=temperature, output_scores=output_scores, **kwargs
264
+ )
265
+ if not output_scores:
266
+ output.scores = None
267
+ return output if return_dict_in_generate else output.sequences
268
+
269
+
270
+ @dataclass
271
+ class DecodingCGCache:
272
+ max_batch_size: int = 0
273
+ max_seqlen: int = 0
274
+ device = None
275
+ dtype = None
276
+ callables: dict = field(default_factory=dict)
277
+ mempool = None
278
+ inference_params: Optional[InferenceParams] = None
279
+ run: Optional[Callable] = None
280
+
281
+
282
+ @torch.inference_mode()
283
+ def update_graph_cache(
284
+ model,
285
+ cache,
286
+ batch_size,
287
+ seqlen_og,
288
+ max_seqlen,
289
+ decoding_seqlens=(1,),
290
+ dtype=None,
291
+ n_warmups=2,
292
+ ):
293
+ if cache is None:
294
+ cache = DecodingCGCache()
295
+ param_example = next(iter(model.parameters()))
296
+ device = param_example.device
297
+ if dtype is None:
298
+ dtype = param_example.dtype
299
+ if (
300
+ (device, dtype) != (cache.device, cache.dtype)
301
+ or batch_size > cache.max_batch_size
302
+ or max_seqlen > cache.max_seqlen
303
+ ): # Invalidate the cache
304
+ cache.callables = {}
305
+ cache.mempool = None
306
+ cache.inference_params = None
307
+ gc.collect()
308
+ cache.device, cache.dtype = device, dtype
309
+ cache.max_batch_size, cache.max_seqlen = batch_size, max_seqlen
310
+ assert hasattr(model, "allocate_inference_cache"), "CUDA graph decoding requires that the model has a method allocate_inference_cache"
311
+ inf_cache = model.allocate_inference_cache(batch_size, max_seqlen, dtype)
312
+ lengths_per_sample = torch.full((batch_size,), seqlen_og, dtype=torch.int32, device=device)
313
+ cache.inference_params = InferenceParams(
314
+ max_seqlen=max_seqlen,
315
+ max_batch_size=batch_size,
316
+ seqlen_offset=seqlen_og,
317
+ key_value_memory_dict=inf_cache,
318
+ lengths_per_sample=lengths_per_sample,
319
+ )
320
+ cache.mempool = torch.cuda.graphs.graph_pool_handle()
321
+ for decoding_seqlen in decoding_seqlens:
322
+ if (batch_size, decoding_seqlen) not in cache.callables:
323
+ cache.callables[batch_size, decoding_seqlen] = capture_graph(
324
+ model,
325
+ cache.inference_params,
326
+ batch_size,
327
+ max_seqlen,
328
+ decoding_seqlen=decoding_seqlen,
329
+ mempool=cache.mempool,
330
+ n_warmups=n_warmups,
331
+ )
332
+
333
+ def dispatch(input_ids, position_ids, seqlen):
334
+ batch_size, decoding_seqlen = input_ids.shape[:2]
335
+ return cache.callables[batch_size, decoding_seqlen](input_ids, position_ids, seqlen)
336
+
337
+ cache.run = dispatch
338
+ cache.inference_params.seqlen_offset = 0 # Reset so it's not confusing
339
+ return cache
340
+
341
+
342
+ def capture_graph(
343
+ model, inference_params, batch_size, max_seqlen, decoding_seqlen=1, mempool=None, n_warmups=2
344
+ ):
345
+ device = next(iter(model.parameters())).device
346
+ input_ids = torch.full((batch_size, decoding_seqlen), 0, dtype=torch.long, device=device)
347
+ position_ids = torch.full((batch_size, decoding_seqlen), 0, dtype=torch.long, device=device)
348
+ seqlen_offset_og = inference_params.seqlen_offset
349
+ inference_params.seqlen_offset = max_seqlen - decoding_seqlen
350
+ inference_params.lengths_per_sample[:] = inference_params.seqlen_offset
351
+
352
+ # Warmup before capture
353
+ s = torch.cuda.Stream()
354
+ s.wait_stream(torch.cuda.current_stream())
355
+ with torch.cuda.stream(s):
356
+ for _ in range(n_warmups):
357
+ logits = model(
358
+ input_ids,
359
+ position_ids=position_ids,
360
+ inference_params=inference_params,
361
+ num_last_tokens=decoding_seqlen,
362
+ ).logits
363
+ s.synchronize()
364
+ # This might be needed for correctness if we run with NCCL_GRAPH_MIXING_SUPPORT=0,
365
+ # which requires that graph launch and non-captured launch to not overlap (I think,
366
+ # that's how I interpret the documentation). I'm not sure if this is required.
367
+ if torch.distributed.is_initialized():
368
+ torch.distributed.barrier()
369
+ torch.cuda.current_stream().wait_stream(s)
370
+ # Captures the graph
371
+ # To allow capture, automatically sets a side stream as the current stream in the context
372
+ graph = torch.cuda.CUDAGraph()
373
+ with torch.cuda.graph(graph, pool=mempool):
374
+ logits = model(
375
+ input_ids,
376
+ position_ids=position_ids,
377
+ inference_params=inference_params,
378
+ num_last_tokens=decoding_seqlen,
379
+ ).logits
380
+
381
+ def run(new_input_ids, new_position_ids, seqlen):
382
+ inference_params.lengths_per_sample[:] = seqlen
383
+ input_ids.copy_(new_input_ids)
384
+ position_ids.copy_(new_position_ids)
385
+ graph.replay()
386
+ return logits.clone()
387
+
388
+ inference_params.seqlen_offset = seqlen_offset_og
389
+ return run
build/torch213-cxx11-xpu20260-x86_64-linux/utils/hf.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import torch
4
+
5
+ from transformers.utils import WEIGHTS_NAME, CONFIG_NAME
6
+ from transformers.utils.hub import cached_file
7
+
8
+
9
+ def load_config_hf(model_name):
10
+ resolved_archive_file = cached_file(model_name, CONFIG_NAME, _raise_exceptions_for_missing_entries=False)
11
+ return json.load(open(resolved_archive_file))
12
+
13
+
14
+ def load_state_dict_hf(model_name, device=None, dtype=None):
15
+ # If not fp32, then we don't want to load directly to the GPU
16
+ mapped_device = "cpu" if dtype not in [torch.float32, None] else device
17
+ resolved_archive_file = cached_file(model_name, WEIGHTS_NAME, _raise_exceptions_for_missing_entries=False)
18
+ return torch.load(resolved_archive_file, map_location=mapped_device)
19
+ # Convert dtype before moving to GPU to save memory
20
+ if dtype is not None:
21
+ state_dict = {k: v.to(dtype=dtype) for k, v in state_dict.items()}
22
+ state_dict = {k: v.to(device=device) for k, v in state_dict.items()}
23
+ return state_dict
build/torch213-cxx11-xpu20260-x86_64-linux/utils/torch.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from functools import partial
3
+ from typing import Callable
4
+
5
+ def custom_amp_decorator(dec: Callable, cuda_amp_deprecated: bool):
6
+ def decorator(*args, **kwargs):
7
+ if cuda_amp_deprecated:
8
+ kwargs["device_type"] = "cuda"
9
+ return dec(*args, **kwargs)
10
+ return decorator
11
+
12
+
13
+ if hasattr(torch.amp, "custom_fwd"): # type: ignore[attr-defined]
14
+ deprecated = True
15
+ from torch.amp import custom_fwd, custom_bwd # type: ignore[attr-defined]
16
+ else:
17
+ deprecated = False
18
+ from torch.cuda.amp import custom_fwd, custom_bwd
19
+
20
+ custom_fwd = custom_amp_decorator(custom_fwd, deprecated)
21
+ custom_bwd = custom_amp_decorator(custom_bwd, deprecated)
build/torch214-cxx11-xpu20261-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __version__ = "2.2.4"
2
+
3
+ from . import layers
4
+ from .models import MambaLMHeadModel
5
+ from .modules import Mamba, Mamba2
6
+ from .ops import mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined, selective_state_update
7
+ from .ops.selective_scan_interface import mamba_inner_fn, selective_scan_fn
8
+
9
+
10
+ falcon_mamba_inner_fn = mamba_inner_fn
11
+ __all__ = [
12
+ # wrappers
13
+ "layers",
14
+ # originals
15
+ "selective_scan_fn", "mamba_inner_fn", "falcon_mamba_inner_fn", "selective_state_update", "mamba_chunk_scan_combined", "mamba_split_conv1d_scan_combined",
16
+ "Mamba", "Mamba2", "MambaLMHeadModel",
17
+ ]
build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/__init__.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import types
2
+
3
+ from .causal_conv1d_interface import (
4
+ causal_conv1d_fn,
5
+ causal_conv1d_ref,
6
+ causal_conv1d_update,
7
+ )
8
+ from .causal_conv1d_varlen import causal_conv1d_varlen_states
9
+ from .cpp_functions import (
10
+ causal_conv1d_bwd_function,
11
+ causal_conv1d_fwd_function,
12
+ causal_conv1d_update_function,
13
+ )
14
+
15
+ # Module-like handle exposing the raw C++ ops, matching the legacy
16
+ # ``causal_conv1d_cuda`` import used by mamba-ssm internals.
17
+ causal_conv1d_cuda = types.SimpleNamespace(
18
+ causal_conv1d_fwd=causal_conv1d_fwd_function,
19
+ causal_conv1d_bwd=causal_conv1d_bwd_function,
20
+ causal_conv1d_update=causal_conv1d_update_function,
21
+ )
22
+
23
+ __all__ = [
24
+ "causal_conv1d_fn",
25
+ "causal_conv1d_update",
26
+ "causal_conv1d_ref",
27
+ "causal_conv1d_varlen_states",
28
+ "causal_conv1d_cuda",
29
+ ]
build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/causal_conv1d_interface.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+
6
+ from .cpp_functions import causal_conv1d_fwd_function, causal_conv1d_bwd_function, causal_conv1d_update_function
7
+
8
+
9
+ class CausalConv1dFn(torch.autograd.Function):
10
+ @staticmethod
11
+ def forward(
12
+ ctx,
13
+ x,
14
+ weight,
15
+ bias=None,
16
+ seq_idx=None,
17
+ initial_states=None,
18
+ return_final_states=False,
19
+ final_states_out=None,
20
+ activation=None,
21
+ ):
22
+ if activation not in [None, "silu", "swish"]:
23
+ raise NotImplementedError("activation must be None, silu, or swish")
24
+ if x.stride(2) != 1 and x.stride(1) != 1:
25
+ x = x.contiguous()
26
+ bias = bias.contiguous() if bias is not None else None
27
+ if seq_idx is not None:
28
+ assert (
29
+ initial_states is None
30
+ ), "initial_states must be None if seq_idx is not None"
31
+ assert (
32
+ not return_final_states
33
+ ), "If seq_idx is not None, we don't return final_states_out"
34
+ seq_idx = seq_idx.contiguous() if seq_idx is not None else None
35
+ if initial_states is not None and (
36
+ initial_states.stride(2) != 1 and initial_states.stride(1) != 1
37
+ ):
38
+ initial_states = initial_states.contiguous()
39
+ if return_final_states:
40
+ assert (
41
+ x.stride(1) == 1
42
+ ), "Only channel-last layout support returning final_states_out"
43
+ if final_states_out is not None:
44
+ assert (
45
+ final_states_out.stride(2) == 1 or final_states_out.stride(1) == 1
46
+ )
47
+ else:
48
+ batch, dim, seqlen = x.shape
49
+ width = weight.shape[1]
50
+ final_states_out = torch.empty(
51
+ batch, width - 1, dim, device=x.device, dtype=x.dtype
52
+ ).transpose(1, 2)
53
+ else:
54
+ final_states_out = None
55
+ ctx.activation = activation in ["silu", "swish"]
56
+ out = causal_conv1d_fwd_function(
57
+ x, weight, bias, seq_idx, initial_states, final_states_out, ctx.activation
58
+ )
59
+ ctx.save_for_backward(x, weight, bias, seq_idx, initial_states)
60
+ ctx.return_final_states = return_final_states
61
+ ctx.return_dinitial_states = (
62
+ initial_states is not None and initial_states.requires_grad
63
+ )
64
+ return out if not return_final_states else (out, final_states_out)
65
+
66
+ @staticmethod
67
+ def backward(ctx, dout, *args):
68
+ x, weight, bias, seq_idx, initial_states = ctx.saved_tensors
69
+ dfinal_states = args[0] if ctx.return_final_states else None
70
+ if dout.stride(2) != 1 and dout.stride(1) != 1:
71
+ dout = dout.contiguous()
72
+ # The kernel supports passing in a pre-allocated dx (e.g., in case we want to fuse the
73
+ # backward of conv1d with the backward of chunk).
74
+ # Here we just pass in None and dx will be allocated in the C++ code.
75
+ dx, dweight, dbias, dinitial_states = causal_conv1d_bwd_function(
76
+ x,
77
+ weight,
78
+ bias,
79
+ dout,
80
+ seq_idx,
81
+ initial_states,
82
+ dfinal_states,
83
+ None,
84
+ ctx.return_dinitial_states,
85
+ ctx.activation,
86
+ )
87
+ return (
88
+ dx,
89
+ dweight,
90
+ dbias if bias is not None else None,
91
+ None,
92
+ dinitial_states if initial_states is not None else None,
93
+ None,
94
+ None,
95
+ None,
96
+ )
97
+
98
+
99
+ def causal_conv1d_fn(
100
+ x,
101
+ weight,
102
+ bias=None,
103
+ seq_idx=None,
104
+ initial_states=None,
105
+ return_final_states=False,
106
+ final_states_out=None,
107
+ activation=None,
108
+ ):
109
+ """
110
+ x: (batch, dim, seqlen)
111
+ weight: (dim, width)
112
+ bias: (dim,)
113
+ seq_idx: (batch, seqlen)
114
+ initial_states: (batch, dim, width - 1)
115
+ final_states_out: (batch, dim, width - 1), to be written to
116
+ activation: either None or "silu" or "swish"
117
+
118
+ out: (batch, dim, seqlen)
119
+ """
120
+ return CausalConv1dFn.apply(
121
+ x,
122
+ weight,
123
+ bias,
124
+ seq_idx,
125
+ initial_states,
126
+ return_final_states,
127
+ final_states_out,
128
+ activation,
129
+ )
130
+
131
+
132
+ def causal_conv1d_ref(
133
+ x,
134
+ weight,
135
+ bias=None,
136
+ initial_states=None,
137
+ return_final_states=False,
138
+ final_states_out=None,
139
+ activation=None,
140
+ ):
141
+ """
142
+ x: (batch, dim, seqlen)
143
+ weight: (dim, width)
144
+ bias: (dim,)
145
+ initial_states: (batch, dim, width - 1)
146
+ final_states_out: (batch, dim, width - 1)
147
+
148
+ out: (batch, dim, seqlen)
149
+ """
150
+ if activation not in [None, "silu", "swish"]:
151
+ raise NotImplementedError("activation must be None, silu, or swish")
152
+ dtype_in = x.dtype
153
+ x = x.to(weight.dtype)
154
+ seqlen = x.shape[-1]
155
+ dim, width = weight.shape
156
+ if initial_states is None:
157
+ out = F.conv1d(x, weight.unsqueeze(1), bias, padding=width - 1, groups=dim)
158
+ else:
159
+ x = torch.cat([initial_states, x], dim=-1)
160
+ out = F.conv1d(x, weight.unsqueeze(1), bias, padding=0, groups=dim)
161
+ out = out[..., :seqlen]
162
+ if return_final_states:
163
+ final_states = F.pad(x, (width - 1 - x.shape[-1], 0)).to(
164
+ dtype_in
165
+ ) # (batch, dim, width - 1)
166
+ if final_states_out is not None:
167
+ final_states_out.copy_(final_states)
168
+ else:
169
+ final_states_out = final_states
170
+ out = (out if activation is None else F.silu(out)).to(dtype=dtype_in)
171
+ return out if not return_final_states else (out, final_states_out)
172
+
173
+
174
+ def causal_conv1d_update(x, conv_state, weight, bias=None, activation=None, cache_seqlens=None, conv_state_indices=None):
175
+ """
176
+ x: (batch, dim) or (batch, dim, seqlen)
177
+ conv_state: (batch, dim, state_len), where state_len >= width - 1
178
+ weight: (dim, width)
179
+ bias: (dim,)
180
+ cache_seqlens: (batch,), dtype int32.
181
+ If not None, the conv_state is treated as a circular buffer.
182
+ The conv_state will be updated by copying x to the conv_state starting at the index
183
+ @cache_seqlens % state_len.
184
+ conv_state_indices: (batch,), dtype int32
185
+ If None, the conv_state is a larger tensor along the batch dim,
186
+ and we are selecting the batch coords specified by conv_state_indices.
187
+ Useful for a continuous batching scenario.
188
+
189
+ out: (batch, dim) or (batch, dim, seqlen)
190
+ """
191
+ if activation not in [None, "silu", "swish"]:
192
+ raise NotImplementedError("activation must be None, silu, or swish")
193
+ activation = activation in ["silu", "swish"]
194
+ unsqueeze = x.dim() == 2
195
+ if unsqueeze:
196
+ x = x.unsqueeze(-1)
197
+ out = causal_conv1d_update_function(
198
+ x, conv_state, weight, bias, activation, cache_seqlens, conv_state_indices
199
+ )
200
+ if unsqueeze:
201
+ out = out.squeeze(-1)
202
+ return out
203
+
204
+
205
+ def causal_conv1d_update_ref(x, conv_state, weight, bias=None, activation=None, cache_seqlens=None):
206
+ """
207
+ x: (batch, dim) or (batch, dim, seqlen)
208
+ conv_state: (batch, dim, state_len), where state_len >= width - 1
209
+ weight: (dim, width)
210
+ bias: (dim,)
211
+ cache_seqlens: (batch,), dtype int32.
212
+ If not None, the conv_state is treated as a circular buffer.
213
+ The conv_state will be updated by copying x to the conv_state starting at the index
214
+ @cache_seqlens % state_len before performing the convolution.
215
+
216
+ out: (batch, dim) or (batch, dim, seqlen)
217
+ """
218
+ if activation not in [None, "silu", "swish"]:
219
+ raise NotImplementedError("activation must be None, silu, or swish")
220
+ dtype_in = x.dtype
221
+ unsqueeze = x.dim() == 2
222
+ if unsqueeze:
223
+ x = x.unsqueeze(-1)
224
+ batch, dim, seqlen = x.shape
225
+ width = weight.shape[1]
226
+ state_len = conv_state.shape[-1]
227
+ assert conv_state.shape == (batch, dim, state_len)
228
+ assert weight.shape == (dim, width)
229
+ if cache_seqlens is None:
230
+ x_new = torch.cat([conv_state, x], dim=-1).to(weight.dtype) # (batch, dim, state_len + seqlen)
231
+ conv_state.copy_(x_new[:, :, -state_len:])
232
+ else:
233
+ width_idx = torch.arange(-(width - 1), 0, dtype=torch.long, device=x.device).unsqueeze(0) + cache_seqlens.unsqueeze(1)
234
+ width_idx = torch.remainder(width_idx, state_len).unsqueeze(1).expand(-1, dim, -1)
235
+ x_new = torch.cat([conv_state.gather(2, width_idx), x], dim=-1).to(weight.dtype)
236
+ copy_idx = torch.arange(seqlen, dtype=torch.long, device=x.device).unsqueeze(0) + cache_seqlens.unsqueeze(1)
237
+ copy_idx = torch.remainder(copy_idx, state_len).unsqueeze(1).expand(-1, dim, -1)
238
+ conv_state.scatter_(2, copy_idx, x)
239
+ out = F.conv1d(x_new, weight.unsqueeze(1), bias, padding=0, groups=dim)[:, :, -seqlen:]
240
+ if unsqueeze:
241
+ out = out.squeeze(-1)
242
+ return (out if activation is None else F.silu(out)).to(dtype=dtype_in)
build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/causal_conv1d_varlen.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import Tensor
3
+
4
+ import triton
5
+ import triton.language as tl
6
+
7
+ from ..utils.device import device_guard
8
+
9
+
10
+ @triton.jit
11
+ def _causal_conv1d_varlen_states(
12
+ X,
13
+ CU_SEQLENS,
14
+ STATES,
15
+ state_len,
16
+ dim,
17
+ stride_x_seqlen, stride_x_dim,
18
+ stride_states_batch, stride_states_seqlen, stride_states_dim,
19
+ BLOCK_M: tl.constexpr,
20
+ BLOCK_N: tl.constexpr
21
+ ):
22
+ batch_idx = tl.program_id(2)
23
+ STATES += batch_idx * stride_states_batch
24
+ end_idx = tl.load(CU_SEQLENS + batch_idx + 1)
25
+ start_idx = tl.maximum(tl.load(CU_SEQLENS + batch_idx), end_idx - state_len)
26
+ rows = end_idx - (tl.program_id(1) + 1) * BLOCK_M + tl.arange(0, BLOCK_M)
27
+ cols = tl.program_id(0) * BLOCK_N + tl.arange(0, BLOCK_N)
28
+ x = tl.load(X + rows[:, None] * stride_x_seqlen + cols[None, :] * stride_x_dim,
29
+ mask=(rows[:, None] >= start_idx) & (cols[None, :] < dim),
30
+ other=0)
31
+ rows_states = state_len - (tl.program_id(1) + 1) * BLOCK_M + tl.arange(0, BLOCK_M)
32
+ tl.store(STATES + rows_states[:, None] * stride_states_seqlen + cols[None, :] * stride_states_dim,
33
+ x,
34
+ mask=(rows_states[:, None] >= 0) & (cols[None, :] < dim))
35
+
36
+
37
+ def causal_conv1d_varlen_states(x: Tensor, cu_seqlens: Tensor, state_len: int) -> Tensor:
38
+ """
39
+ Forward pass only, does not support backward pass.
40
+ Parameters:
41
+ x: (total_tokens, dim)
42
+ cu_seqlens: (batch + 1), must already be sorted. The cumulative sum of the sequence lengths, starting from 0.
43
+ state_len: int. For each cu_seqlens, how many elements from x should be copied to the state.
44
+ If some of those elements belong to a different sequence, the value of the states will be zero.
45
+ Return:
46
+ states: (batch, dim, state_len)
47
+ """
48
+ _, dim = x.shape
49
+ batch = cu_seqlens.shape[0] - 1
50
+ cu_seqlens = cu_seqlens.contiguous()
51
+ states = torch.empty(batch, state_len, dim, dtype=x.dtype, device=x.device).transpose(1, 2)
52
+ BLOCK_M = min(triton.next_power_of_2(state_len), 16)
53
+ BLOCK_N = min(triton.next_power_of_2(dim), 256)
54
+ grid = (triton.cdiv(dim, BLOCK_N), triton.cdiv(state_len, BLOCK_M), batch)
55
+ with device_guard(x):
56
+ _causal_conv1d_varlen_states[grid](
57
+ x,
58
+ cu_seqlens,
59
+ states,
60
+ state_len,
61
+ dim,
62
+ x.stride(0), x.stride(1),
63
+ states.stride(0), states.stride(2), states.stride(1),
64
+ BLOCK_M=BLOCK_M, BLOCK_N=BLOCK_N
65
+ )
66
+ return states
67
+
68
+
69
+ def causal_conv1d_varlen_states_ref(x: Tensor, cu_seqlens: Tensor, state_len: int) -> Tensor:
70
+ """
71
+ Forward pass only, does not support backward pass.
72
+ Parameters:
73
+ x: (total_tokens, dim)
74
+ cu_seqlens: (batch + 1), must already be sorted. The cumulative sum of the sequence lengths, starting from 0.
75
+ state_len: int. For each cu_seqlens, how many elements from x should be copied to the state.
76
+ If some of those elements belong to a different sequence, the value of the states will be zero.
77
+ Return:
78
+ states: (batch, dim, state_len)
79
+ """
80
+ _, dim = x.shape
81
+ batch = cu_seqlens.shape[0] - 1
82
+ cu_seqlens = cu_seqlens.contiguous()
83
+ states = torch.zeros(batch, state_len, dim, dtype=x.dtype, device=x.device).transpose(1, 2)
84
+ for i in range(batch):
85
+ end_idx = cu_seqlens[i + 1]
86
+ start_idx = torch.maximum(cu_seqlens[i], end_idx - state_len)
87
+ states[i, :, -(end_idx - start_idx):] = x[start_idx:end_idx].T
88
+ return states
build/torch214-cxx11-xpu20261-x86_64-linux/_causal_conv1d/cpp_functions.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+
3
+ import torch
4
+
5
+ from .._ops import ops
6
+
7
+
8
+ def causal_conv1d_fwd_function(
9
+ x: torch.Tensor,
10
+ weight: torch.Tensor,
11
+ bias: torch.Tensor | None,
12
+ seq_idx: torch.Tensor | None,
13
+ initial_states: torch.Tensor | None,
14
+ final_states_out: torch.Tensor | None,
15
+ silu_activation: bool,
16
+ ) -> torch.Tensor:
17
+ out = torch.empty_like(x)
18
+ # Positional: torch.compile rejects a non-contiguous (e.g. channel-last) `out=` keyword.
19
+ ops.causal_conv1d_fwd(
20
+ x, weight, bias, seq_idx, initial_states, out,
21
+ final_states_out=final_states_out,
22
+ silu_activation=silu_activation,
23
+ )
24
+ return out
25
+
26
+
27
+ def causal_conv1d_bwd_function(
28
+ x: torch.Tensor,
29
+ weight: torch.Tensor,
30
+ bias: torch.Tensor | None,
31
+ dout: torch.Tensor,
32
+ seq_idx: torch.Tensor | None,
33
+ initial_states: torch.Tensor | None,
34
+ dfinal_states: torch.Tensor | None,
35
+ dx: torch.Tensor | None,
36
+ return_dinitial_states: torch.Tensor,
37
+ silu_activation: bool,
38
+ ) -> tuple[torch.Tensor | None]:
39
+ batch_size, dim = x.size()[:2]
40
+ width = weight.size(-1)
41
+
42
+ if dx is None:
43
+ dx = torch.empty_like(x)
44
+ dweight = torch.zeros_like(weight, dtype=torch.float32)
45
+ dbias = None
46
+ if bias is not None:
47
+ dbias = torch.zeros_like(bias, dtype=torch.float32)
48
+ dinitial_states = None
49
+ if return_dinitial_states:
50
+ dinitial_states = torch.empty(
51
+ batch_size, width - 1, dim, device=x.device, dtype=x.dtype
52
+ ).transpose(1, 2)
53
+
54
+ ops.causal_conv1d_bwd(
55
+ x=x,
56
+ weight=weight,
57
+ bias=bias,
58
+ dout=dout,
59
+ seq_idx=seq_idx,
60
+ initial_states=initial_states,
61
+ dfinal_states=dfinal_states,
62
+ dx=dx,
63
+ dweight=dweight,
64
+ dbias=dbias,
65
+ dinitial_states=dinitial_states,
66
+ silu_activation=silu_activation,
67
+ )
68
+
69
+ dweight = dweight.type_as(weight)
70
+ if dbias is not None:
71
+ dbias = dbias.type_as(bias)
72
+ return dx, dweight, dbias, dinitial_states
73
+
74
+
75
+ def causal_conv1d_update_function(
76
+ x: torch.Tensor,
77
+ conv_state: torch.Tensor,
78
+ weight: torch.Tensor,
79
+ bias: torch.Tensor | None,
80
+ silu_activation: bool,
81
+ cache_seqlens: torch.Tensor | None,
82
+ conv_state_indices: torch.Tensor | None,
83
+ ) -> torch.Tensor:
84
+ out = torch.empty_like(x)
85
+ # Positional on purpose, see `causal_conv1d_fwd_function`.
86
+ ops.causal_conv1d_update(
87
+ x, conv_state, weight, bias, out,
88
+ silu_activation=silu_activation,
89
+ cache_seqlens=cache_seqlens,
90
+ conv_state_indices=conv_state_indices,
91
+ )
92
+ return out
build/torch214-cxx11-xpu20261-x86_64-linux/_mamba_ssm_xpu_81e0711.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a4b56a73456bac67fc3fd79b8af7be9ef6b0e706ec15d5ba67ca682b8c9f46f2
3
+ size 3131720
build/torch214-cxx11-xpu20261-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _mamba_ssm_xpu_81e0711
3
+ ops = torch.ops._mamba_ssm_xpu_81e0711
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_mamba_ssm_xpu_81e0711::{op_name}"
build/torch214-cxx11-xpu20261-x86_64-linux/distributed/__init__.py ADDED
File without changes
build/torch214-cxx11-xpu20261-x86_64-linux/distributed/distributed_utils.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ import torch
4
+ from torch import Tensor
5
+ from torch.distributed import ProcessGroup
6
+
7
+ # `all_gather_into_tensor` and `reduce_scatter_tensor` are new placeholders for
8
+ # `_all_gather_base` and `_reduce_scatter_base`. They require the most recent
9
+ # version of PyTorch. The following 4 lines are for backward compatibility with
10
+ # older PyTorch.
11
+ if "all_gather_into_tensor" not in dir(torch.distributed):
12
+ torch.distributed.all_gather_into_tensor = torch.distributed._all_gather_base
13
+ if "reduce_scatter_tensor" not in dir(torch.distributed):
14
+ torch.distributed.reduce_scatter_tensor = torch.distributed._reduce_scatter_base
15
+
16
+
17
+ # Raw operation, does not support autograd, but does support async
18
+ def all_gather_raw(input_: Tensor, process_group: ProcessGroup, async_op: bool = False):
19
+ world_size = torch.distributed.get_world_size(process_group)
20
+ output = torch.empty(
21
+ world_size * input_.shape[0], *input_.shape[1:], dtype=input_.dtype, device=input_.device
22
+ )
23
+ handle = torch.distributed.all_gather_into_tensor(
24
+ output, input_.contiguous(), group=process_group, async_op=async_op
25
+ )
26
+ return output, handle
27
+
28
+
29
+ # Raw operation, does not support autograd, but does support async
30
+ def reduce_scatter_raw(input_: Tensor, process_group: ProcessGroup, async_op: bool = False):
31
+ world_size = torch.distributed.get_world_size(process_group)
32
+ assert input_.shape[0] % world_size == 0
33
+ output = torch.empty(
34
+ input_.shape[0] // world_size, *input_.shape[1:], dtype=input_.dtype, device=input_.device
35
+ )
36
+ handle = torch.distributed.reduce_scatter_tensor(
37
+ output, input_.contiguous(), group=process_group, async_op=async_op
38
+ )
39
+ return output, handle
40
+
41
+
42
+ # Raw operation, does not support autograd, but does support async
43
+ def all_reduce_raw(input_: Tensor, process_group: ProcessGroup, async_op: bool = False):
44
+ input_ = input_.contiguous()
45
+ handle = torch.distributed.all_reduce(input_, group=process_group, async_op=async_op)
46
+ return input_, handle
47
+
48
+
49
+ class AllGatherFunc(torch.autograd.Function):
50
+ """Gather the input from sequence parallel region and concatenate."""
51
+
52
+ @staticmethod
53
+ def forward(ctx, input_: Tensor, process_group: ProcessGroup) -> Tensor:
54
+ ctx.process_group = process_group
55
+ output, _ = all_gather_raw(input_, process_group)
56
+ return output
57
+
58
+ @staticmethod
59
+ def backward(ctx, grad_output: Tensor):
60
+ grad_input, _ = reduce_scatter_raw(grad_output, ctx.process_group)
61
+ return grad_input, None
62
+
63
+
64
+ # Supports autograd, but does not support async
65
+ all_gather = AllGatherFunc.apply
66
+
67
+
68
+ class ReduceScatterFunc(torch.autograd.Function):
69
+ """Reduce scatter the input from the sequence parallel region and concatenate."""
70
+
71
+ @staticmethod
72
+ def forward(ctx, input_: Tensor, process_group: ProcessGroup) -> Tensor:
73
+ ctx.process_group = process_group
74
+ output, _ = reduce_scatter_raw(input_, process_group)
75
+ return output
76
+
77
+ @staticmethod
78
+ def backward(ctx, grad_output: Tensor):
79
+ grad_input, _ = all_gather_raw(grad_output, ctx.process_group)
80
+ return grad_input, None
81
+
82
+
83
+ # Supports autograd, but does not support async
84
+ reduce_scatter = ReduceScatterFunc.apply
85
+
86
+
87
+ class AllReduceFunc(torch.autograd.Function):
88
+ """Gather the input from sequence parallel region and concatenate."""
89
+
90
+ @staticmethod
91
+ def forward(ctx, input_: Tensor, process_group: ProcessGroup) -> Tensor:
92
+ ctx.process_group = process_group
93
+ output, _ = all_reduce_raw(input_, process_group)
94
+ return output
95
+
96
+ @staticmethod
97
+ def backward(ctx, grad_output: Tensor):
98
+ return grad_output, None
99
+
100
+
101
+ # Supports autograd, but does not support async
102
+ all_reduce = AllReduceFunc.apply
103
+
104
+
105
+ def sync_shared_params(model: torch.nn.Module, process_group: ProcessGroup):
106
+ # We want to iterate over parameters with _shared_params=True in the same order,
107
+ # as different ranks might have different number of parameters (e.g., only rank 0 has bias).
108
+ pamams_shared = {
109
+ name: p for name, p in model.named_parameters() if getattr(p, "_shared_params", False)
110
+ }
111
+ for _, p in sorted(pamams_shared.items()):
112
+ with torch.no_grad():
113
+ # Broadcast needs src to be global rank, not group rank
114
+ torch.distributed.broadcast(
115
+ p, src=torch.distributed.get_global_rank(process_group, 0), group=process_group
116
+ )
117
+
118
+
119
+ # Ref: https://github.com/NVIDIA/Megatron-LM/blob/52e636888cccc41e931251c417a7181fc36de926/megatron/optimizer/optimizer.py#L256
120
+ def allreduce_sequence_parallel_grad(model: torch.nn.Module, process_group: ProcessGroup):
121
+ # We want to iterate over parameters with _sequence_parallel=True in the same order,
122
+ # as different ranks might have different number of parameters (e.g., only rank 0 has bias).
123
+ params_seqparallel = {
124
+ name: p for name, p in model.named_parameters() if getattr(p, "_sequence_parallel", False)
125
+ }
126
+ grads = [p.grad for _, p in sorted(params_seqparallel.items())]
127
+ if grads:
128
+ with torch.no_grad():
129
+ coalesced = torch._utils._flatten_dense_tensors(grads)
130
+ torch.distributed.all_reduce(coalesced, group=process_group)
131
+ for buf, synced in zip(grads, torch._utils._unflatten_dense_tensors(coalesced, grads)):
132
+ buf.copy_(synced)
133
+
134
+
135
+ def get_dim_for_local_rank(dim: int, world_size: int, local_rank: int, multiple_of: int = 1) -> int:
136
+ """Get the dim for the local rank derived from splitting dim on world_size processes.
137
+
138
+ The split may not be even across the world_size processes.
139
+ """
140
+ multiple = dim // multiple_of
141
+ div = multiple // world_size
142
+ mod = multiple % world_size
143
+ local_multiple = div + int(local_rank < mod)
144
+ return local_multiple * multiple_of
build/torch214-cxx11-xpu20261-x86_64-linux/distributed/tensor_parallel.py ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+ # The TensorParallel linear modules are inspired by https://github.com/NVIDIA/apex/blob/master/apex/transformer/tensor_parallel/layers.py
3
+ from typing import Optional
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from torch import Tensor
9
+ from torch.distributed import ProcessGroup
10
+ from ..utils.torch import custom_bwd, custom_fwd
11
+
12
+ from einops import rearrange
13
+
14
+ from ..distributed.distributed_utils import (
15
+ all_gather_raw,
16
+ all_reduce,
17
+ all_reduce_raw,
18
+ reduce_scatter,
19
+ reduce_scatter_raw,
20
+ )
21
+
22
+
23
+ class ParallelLinearFunc(torch.autograd.Function):
24
+ @staticmethod
25
+ @custom_fwd
26
+ def forward(ctx, x, weight, bias, process_group=None, sequence_parallel=True):
27
+ """
28
+ If process_group is not None and sequence_parallel=True, we're doing Tensor Parallel
29
+ with sequence parallelism: we do an all_gather_raw of x before doing the matmul.
30
+ """
31
+ ctx.compute_weight_gradient = weight.requires_grad
32
+ ctx.process_group = process_group
33
+ ctx.sequence_parallel = sequence_parallel
34
+
35
+ device_type = x.device.type
36
+ if torch.is_autocast_enabled(device_type):
37
+ x = x.to(dtype=torch.get_autocast_dtype(device_type))
38
+ x = x.contiguous()
39
+ if process_group is not None and sequence_parallel:
40
+ # We want to kick off the all_gather early, before weight dtype conversion
41
+ total_x, handle_x = all_gather_raw(x, process_group, async_op=True)
42
+ else:
43
+ total_x = x
44
+
45
+ if torch.is_autocast_enabled(device_type):
46
+ weight = weight.to(dtype=torch.get_autocast_dtype(device_type))
47
+ bias = bias.to(dtype=torch.get_autocast_dtype(device_type)) if bias is not None else None
48
+ weight = weight.contiguous()
49
+ if process_group is not None and sequence_parallel:
50
+ handle_x.wait()
51
+ batch_shape, n = total_x.shape[:-1], total_x.shape[-1]
52
+ batch_dim = batch_shape.numel()
53
+ # https://github.com/pytorch/pytorch/blob/5b51849b48a7dbccd297286cc0110def4706f9e7/aten/src/ATen/native/cuda/Blas.cpp#L174
54
+ output = F.linear(total_x, weight, bias)
55
+ if ctx.compute_weight_gradient:
56
+ ctx.save_for_backward(x, weight)
57
+ else:
58
+ ctx.save_for_backward(weight)
59
+ return output
60
+
61
+ @staticmethod
62
+ @custom_bwd
63
+ def backward(ctx, grad_output):
64
+ grad_output = grad_output.contiguous()
65
+ process_group = ctx.process_group
66
+ sequence_parallel = ctx.sequence_parallel
67
+ if ctx.compute_weight_gradient:
68
+ x, weight = ctx.saved_tensors
69
+ if process_group is not None and sequence_parallel:
70
+ total_x, handle_x = all_gather_raw(x, process_group, async_op=True)
71
+ else:
72
+ total_x = x
73
+ else:
74
+ (weight,) = ctx.saved_tensors
75
+ total_x = None
76
+ batch_shape = grad_output.shape[:-1]
77
+ batch_dim = batch_shape.numel()
78
+ grad_output = grad_output.reshape(batch_dim, grad_output.shape[-1])
79
+ if ctx.needs_input_grad[0]:
80
+ grad_input = F.linear(grad_output, weight.t())
81
+ grad_input = grad_input.reshape(*batch_shape, grad_input.shape[-1])
82
+ if process_group is not None:
83
+ reduce_fn = reduce_scatter_raw if sequence_parallel else all_reduce_raw
84
+ grad_input, handle_grad_input = reduce_fn(grad_input, process_group, async_op=True)
85
+ else:
86
+ grad_input = None
87
+ if ctx.needs_input_grad[1]:
88
+ assert ctx.compute_weight_gradient
89
+ if process_group is not None and sequence_parallel:
90
+ handle_x.wait()
91
+ grad_weight = torch.einsum(
92
+ "bo,bi->oi", grad_output, total_x.reshape(batch_dim, total_x.shape[-1])
93
+ )
94
+ else:
95
+ grad_weight = None
96
+ grad_bias = grad_output.sum(dim=0) if ctx.needs_input_grad[2] else None
97
+ if process_group is not None and ctx.needs_input_grad[0]:
98
+ handle_grad_input.wait()
99
+ return grad_input, grad_weight, grad_bias, None, None
100
+
101
+
102
+ def parallel_linear_func(
103
+ x: Tensor,
104
+ weight: Tensor,
105
+ bias: Optional[Tensor] = None,
106
+ process_group: Optional[ProcessGroup] = None,
107
+ sequence_parallel: bool = True,
108
+ ):
109
+ return ParallelLinearFunc.apply(x, weight, bias, process_group, sequence_parallel)
110
+
111
+
112
+ class ColumnParallelLinear(nn.Linear):
113
+ def __init__(
114
+ self,
115
+ in_features: int,
116
+ out_features: int,
117
+ process_group: ProcessGroup,
118
+ bias: bool = True,
119
+ sequence_parallel=True,
120
+ multiple_of=1,
121
+ device=None,
122
+ dtype=None,
123
+ ) -> None:
124
+ world_size = torch.distributed.get_world_size(process_group)
125
+ if out_features % multiple_of:
126
+ raise ValueError(f"out_features ({out_features}) must be a multiple of {multiple_of}")
127
+ multiple = out_features // multiple_of
128
+ # We want to split @multiple across world_size, but it could be an uneven split
129
+ div = multiple // world_size
130
+ mod = multiple % world_size
131
+ # The first @mod ranks get @div + 1 copies, the rest get @div copies
132
+ local_multiple = div + int(torch.distributed.get_rank(process_group) < mod)
133
+ super().__init__(
134
+ in_features, local_multiple * multiple_of, bias=bias, device=device, dtype=dtype
135
+ )
136
+ self.process_group = process_group
137
+ self.sequence_parallel = sequence_parallel
138
+
139
+ def forward(self, x):
140
+ # If self.sequence_parallel is True, we're doing Tensor Parallel with sequence parallelism:
141
+ # we do an all_gather of x before doing the matmul.
142
+ # If not, then the input is already gathered.
143
+ return parallel_linear_func(
144
+ x,
145
+ self.weight,
146
+ self.bias,
147
+ process_group=self.process_group,
148
+ sequence_parallel=self.sequence_parallel,
149
+ )
150
+
151
+
152
+ class RowParallelLinear(nn.Linear):
153
+ def __init__(
154
+ self,
155
+ in_features: int,
156
+ out_features: int,
157
+ process_group: ProcessGroup,
158
+ bias: bool = True,
159
+ sequence_parallel=True,
160
+ multiple_of=1,
161
+ device=None,
162
+ dtype=None,
163
+ ) -> None:
164
+ world_size = torch.distributed.get_world_size(process_group)
165
+ rank = torch.distributed.get_rank(process_group)
166
+ if in_features % multiple_of:
167
+ raise ValueError(f"in_features ({in_features}) must be a multiple of {multiple_of}")
168
+ multiple = in_features // multiple_of
169
+ # We want to split @multiple across world_size, but it could be an uneven split
170
+ div = multiple // world_size
171
+ mod = multiple % world_size
172
+ # The first @mod ranks get @div + 1 copies, the rest get @div copies
173
+ local_multiple = div + int(torch.distributed.get_rank(process_group) < mod)
174
+ # Only rank 0 will have bias
175
+ super().__init__(
176
+ local_multiple * multiple_of,
177
+ out_features,
178
+ bias=bias and rank == 0,
179
+ device=device,
180
+ dtype=dtype,
181
+ )
182
+ self.process_group = process_group
183
+ self.sequence_parallel = sequence_parallel
184
+
185
+ def forward(self, x):
186
+ """
187
+ We're doing Tensor Parallel with sequence parallelism: we do the matmul and then
188
+ a reduce_scatter of the result.
189
+ """
190
+ out = parallel_linear_func(x, self.weight, self.bias)
191
+ reduce_fn = reduce_scatter if self.sequence_parallel else all_reduce
192
+ return reduce_fn(out, self.process_group)
193
+
194
+
195
+ class VocabParallelEmbedding(nn.Embedding):
196
+ def __init__(self, num_embeddings, *args, process_group=None, padding_idx=None, **kwargs):
197
+ self.process_group = process_group
198
+ if process_group is not None:
199
+ world_size = torch.distributed.get_world_size(process_group)
200
+ if num_embeddings % world_size != 0:
201
+ raise ValueError(
202
+ f"num_embeddings ({num_embeddings}) must be divisible by "
203
+ f"world_size ({world_size})"
204
+ )
205
+ if world_size > 1 and padding_idx is not None:
206
+ raise RuntimeError("ParallelEmbedding does not support padding_idx")
207
+ else:
208
+ world_size = 1
209
+ super().__init__(num_embeddings // world_size, *args, padding_idx=padding_idx, **kwargs)
210
+
211
+ def forward(self, input: Tensor) -> Tensor:
212
+ if self.process_group is None:
213
+ return super().forward(input)
214
+ else:
215
+ rank = torch.distributed.get_rank(self.process_group)
216
+ vocab_size = self.num_embeddings
217
+ vocab_start_index, vocab_end_index = rank * vocab_size, (rank + 1) * vocab_size
218
+ # Create a mask of valid vocab ids (1 means it needs to be masked).
219
+ input_ids_mask = (input < vocab_start_index) | (input >= vocab_end_index)
220
+ input = input - vocab_start_index
221
+ input[input_ids_mask] = 0
222
+ embeddings = super().forward(input)
223
+ embeddings[input_ids_mask] = 0.0
224
+ return embeddings
225
+
226
+
227
+ class ColumnParallelEmbedding(nn.Embedding):
228
+ def __init__(self, num_embeddings, embedding_dim, *args, process_group=None, **kwargs):
229
+ self.process_group = process_group
230
+ if process_group is not None:
231
+ world_size = torch.distributed.get_world_size(process_group)
232
+ if embedding_dim % world_size != 0:
233
+ raise ValueError(
234
+ f"embedding_dim ({embedding_dim}) must be divisible by "
235
+ f"world_size ({world_size})"
236
+ )
237
+ else:
238
+ world_size = 1
239
+ super().__init__(num_embeddings, embedding_dim // world_size, *args, **kwargs)
240
+
241
+
242
+ class ParallelEmbeddings(nn.Module):
243
+ def __init__(
244
+ self,
245
+ embed_dim,
246
+ vocab_size,
247
+ max_position_embeddings,
248
+ process_group,
249
+ padding_idx=None,
250
+ sequence_parallel=True,
251
+ device=None,
252
+ dtype=None,
253
+ ):
254
+ """
255
+ If max_position_embeddings <= 0, there's no position embeddings
256
+ """
257
+ factory_kwargs = {"device": device, "dtype": dtype}
258
+ super().__init__()
259
+ self.process_group = process_group
260
+ self.sequence_parallel = sequence_parallel
261
+ self.word_embeddings = VocabParallelEmbedding(
262
+ vocab_size,
263
+ embed_dim,
264
+ padding_idx=padding_idx,
265
+ process_group=process_group,
266
+ **factory_kwargs,
267
+ )
268
+ self.max_position_embeddings = max_position_embeddings
269
+ if self.max_position_embeddings > 0:
270
+ self.position_embeddings = ColumnParallelEmbedding(
271
+ max_position_embeddings, embed_dim, process_group=process_group, **factory_kwargs
272
+ )
273
+
274
+ def forward(self, input_ids, position_ids=None, combine_batch_seqlen_dim=False):
275
+ """
276
+ input_ids: (batch, seqlen)
277
+ position_ids: (batch, seqlen)
278
+ """
279
+ batch_size, seqlen = input_ids.shape
280
+ world_size = torch.distributed.get_world_size(self.process_group)
281
+ embeddings = self.word_embeddings(input_ids)
282
+ if self.max_position_embeddings > 0:
283
+ if position_ids is None:
284
+ position_ids = torch.arange(seqlen, dtype=torch.long, device=input_ids.device)
285
+ position_embeddings = self.position_embeddings(position_ids)
286
+ if world_size <= 1:
287
+ embeddings = embeddings + position_embeddings
288
+ else:
289
+ partition_dim = self.position_embeddings.embedding_dim
290
+ rank = torch.distributed.get_rank(self.process_group)
291
+ embeddings[
292
+ ..., rank * partition_dim : (rank + 1) * partition_dim
293
+ ] += position_embeddings
294
+ if combine_batch_seqlen_dim:
295
+ embeddings = rearrange(embeddings, "b s d -> (b s) d")
296
+ reduce_fn = reduce_scatter if self.sequence_parallel else all_reduce
297
+ return embeddings if world_size <= 1 else reduce_fn(embeddings, self.process_group)
build/torch214-cxx11-xpu20261-x86_64-linux/layers.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ from ._causal_conv1d import causal_conv1d_fn as cuda_causal_conv1d_fn
5
+ from ._causal_conv1d import causal_conv1d_update as cuda_causal_conv1d_update
6
+ from .ops import mamba_chunk_scan_combined as cuda_mamba_chunk_scan_combined
7
+ from .ops import mamba_split_conv1d_scan_combined as cuda_mamba_split_conv1d_scan_combined
8
+ from .ops import selective_state_update as cuda_selective_state_update
9
+ from .ops.selective_scan_interface import mamba_inner_fn as cuda_mamba_inner_fn
10
+ from .ops.selective_scan_interface import selective_scan_fn as cuda_selective_scan_fn
11
+
12
+
13
+ class mamba_inner_fn(nn.Module):
14
+ can_torch_compile = True
15
+
16
+ def forward(
17
+ self,
18
+ xz: torch.Tensor,
19
+ conv1d_weight: torch.Tensor,
20
+ conv1d_bias: torch.Tensor | None,
21
+ x_proj_weight: torch.Tensor,
22
+ delta_proj_weight: torch.Tensor,
23
+ out_proj_weight: torch.Tensor,
24
+ out_proj_bias: torch.Tensor | None,
25
+ A: torch.Tensor,
26
+ B: torch.Tensor | None = None,
27
+ C: torch.Tensor | None = None,
28
+ D: torch.Tensor | None = None,
29
+ delta_bias: torch.Tensor | None = None,
30
+ delta_softplus: bool = True,
31
+ b_rms_weight: torch.Tensor | None = None,
32
+ c_rms_weight: torch.Tensor | None = None,
33
+ dt_rms_weight: torch.Tensor | None = None,
34
+ b_c_dt_rms_eps: float = 1e-6,
35
+ **kwargs,
36
+ ):
37
+ return cuda_mamba_inner_fn(
38
+ xz,
39
+ conv1d_weight,
40
+ conv1d_bias,
41
+ x_proj_weight,
42
+ delta_proj_weight,
43
+ out_proj_weight,
44
+ out_proj_bias,
45
+ A,
46
+ B,
47
+ C,
48
+ D,
49
+ delta_bias=delta_bias,
50
+ delta_softplus=delta_softplus,
51
+ b_rms_weight=b_rms_weight,
52
+ c_rms_weight=c_rms_weight,
53
+ dt_rms_weight=dt_rms_weight,
54
+ b_c_dt_rms_eps=b_c_dt_rms_eps,
55
+ )
56
+
57
+
58
+ class mamba_split_conv1d_scan_combined(nn.Module):
59
+ can_torch_compile = True
60
+
61
+ def forward(
62
+ self,
63
+ zxbcdt: torch.Tensor,
64
+ conv1d_weight: torch.Tensor,
65
+ conv1d_bias: torch.Tensor | None,
66
+ dt_bias: torch.Tensor,
67
+ A: torch.Tensor,
68
+ D: torch.Tensor,
69
+ chunk_size: int,
70
+ initial_states: torch.Tensor | None = None,
71
+ dt_limit: tuple[float, float] = (0.0, float("inf")),
72
+ return_final_states: bool = False,
73
+ activation: str = "silu",
74
+ rmsnorm_weight: torch.Tensor | None = None,
75
+ rmsnorm_eps: float = 1e-6,
76
+ outproj_weight: torch.Tensor | None = None,
77
+ outproj_bias: torch.Tensor | None = None,
78
+ headdim: int | None = None,
79
+ ngroups: int = 1,
80
+ norm_before_gate: bool = True,
81
+ **kwargs,
82
+ ):
83
+ # For varlen
84
+ seq_idx = kwargs.pop("seq_idx", None)
85
+
86
+ return cuda_mamba_split_conv1d_scan_combined(
87
+ zxbcdt,
88
+ conv1d_weight,
89
+ conv1d_bias,
90
+ dt_bias,
91
+ A,
92
+ D=D,
93
+ chunk_size=chunk_size,
94
+ seq_idx=seq_idx,
95
+ activation=activation,
96
+ rmsnorm_weight=rmsnorm_weight,
97
+ rmsnorm_eps=rmsnorm_eps,
98
+ outproj_weight=outproj_weight,
99
+ outproj_bias=outproj_bias,
100
+ headdim=headdim,
101
+ ngroups=ngroups,
102
+ norm_before_gate=norm_before_gate,
103
+ return_final_states=return_final_states,
104
+ dt_limit=dt_limit,
105
+ initial_states=initial_states,
106
+ )
107
+
108
+
109
+ class mamba_chunk_scan_combined(nn.Module):
110
+ can_torch_compile = True
111
+
112
+ def forward(
113
+ self,
114
+ hidden_states: torch.Tensor,
115
+ dt: torch.Tensor,
116
+ A: torch.Tensor,
117
+ B: torch.Tensor,
118
+ C: torch.Tensor,
119
+ chunk_size: int,
120
+ D: torch.Tensor | None = None,
121
+ dt_bias: torch.Tensor | None = None,
122
+ initial_states: torch.Tensor | None = None,
123
+ dt_softplus: bool = False,
124
+ dt_limit: tuple[float, float] = (0.0, float("inf")),
125
+ return_final_states: bool = False,
126
+ **kwargs,
127
+ ):
128
+ # For varlen
129
+ seq_idx = kwargs.pop("seq_idx", None)
130
+
131
+ return cuda_mamba_chunk_scan_combined(
132
+ hidden_states,
133
+ dt,
134
+ A,
135
+ B,
136
+ C,
137
+ D=D,
138
+ z=None,
139
+ dt_bias=dt_bias,
140
+ dt_softplus=dt_softplus,
141
+ chunk_size=chunk_size,
142
+ seq_idx=seq_idx,
143
+ return_final_states=return_final_states,
144
+ dt_limit=dt_limit,
145
+ initial_states=initial_states,
146
+ )
147
+
148
+
149
+ class selective_state_update(nn.Module):
150
+ can_torch_compile = True
151
+
152
+ def forward(
153
+ self,
154
+ state: torch.Tensor,
155
+ hidden_states: torch.Tensor,
156
+ dt: torch.Tensor,
157
+ A: torch.Tensor,
158
+ B: torch.Tensor,
159
+ C: torch.Tensor,
160
+ D: torch.Tensor | None = None,
161
+ dt_bias: torch.Tensor | None = None,
162
+ dt_softplus: bool = False,
163
+ z: torch.Tensor | None = None,
164
+ **kwargs,
165
+ ):
166
+ return cuda_selective_state_update(
167
+ state,
168
+ hidden_states,
169
+ dt,
170
+ A,
171
+ B,
172
+ C,
173
+ D,
174
+ z=z,
175
+ dt_bias=dt_bias,
176
+ dt_softplus=dt_softplus,
177
+ )
178
+
179
+
180
+ class selective_scan_fn(nn.Module):
181
+ can_torch_compile = True
182
+
183
+ def forward(
184
+ self,
185
+ hidden_states: torch.Tensor,
186
+ dt: torch.Tensor,
187
+ A: torch.Tensor,
188
+ B: torch.Tensor,
189
+ C: torch.Tensor,
190
+ D: torch.Tensor | None = None,
191
+ z: torch.Tensor | None = None,
192
+ delta_bias: torch.Tensor | None = None,
193
+ delta_softplus: bool = False,
194
+ return_last_state: bool = False,
195
+ # Unused here but fallbacks for torch only paths
196
+ use_mambapy: bool = False,
197
+ use_associative_scan: bool = False,
198
+ **kwargs,
199
+ ):
200
+ return cuda_selective_scan_fn(
201
+ hidden_states,
202
+ dt,
203
+ A,
204
+ B,
205
+ C,
206
+ D=D,
207
+ z=z,
208
+ delta_bias=delta_bias,
209
+ delta_softplus=delta_softplus,
210
+ return_last_state=return_last_state,
211
+ )
212
+
213
+
214
+ class causal_conv1d_fn(nn.Module):
215
+ can_torch_compile = True
216
+
217
+ def forward(
218
+ self,
219
+ hidden_states,
220
+ weight,
221
+ bias=None,
222
+ activation=None,
223
+ **kwargs,
224
+ ):
225
+ # For varlen
226
+ seq_idx = kwargs.pop("seq_idx", None)
227
+
228
+ return cuda_causal_conv1d_fn(
229
+ x=hidden_states,
230
+ weight=weight,
231
+ bias=bias,
232
+ activation=activation,
233
+ seq_idx=seq_idx,
234
+ )
235
+
236
+
237
+ class causal_conv1d_update(nn.Module):
238
+ can_torch_compile = True
239
+
240
+ def forward(
241
+ self,
242
+ hidden_states,
243
+ conv_state,
244
+ weight,
245
+ bias=None,
246
+ activation=None,
247
+ ):
248
+ return cuda_causal_conv1d_update(
249
+ x=hidden_states,
250
+ conv_state=conv_state,
251
+ weight=weight,
252
+ bias=bias,
253
+ activation=activation,
254
+ )
255
+
256
+
257
+ __all__ = [
258
+ "causal_conv1d_fn",
259
+ "causal_conv1d_update",
260
+ "mamba_inner_fn",
261
+ "mamba_split_conv1d_scan_combined",
262
+ "mamba_chunk_scan_combined",
263
+ "selective_state_update",
264
+ "selective_scan_fn",
265
+ ]
build/torch214-cxx11-xpu20261-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "mamba-ssm",
3
+ "id": "_mamba_ssm_xpu_81e0711",
4
+ "version": 4,
5
+ "kernels-minver": "0.14.0",
6
+ "license": "Apache-2.0",
7
+ "python-depends": [
8
+ "einops"
9
+ ],
10
+ "kernel-depends": [],
11
+ "backend": {
12
+ "type": "xpu"
13
+ },
14
+ "digest": {
15
+ "algorithm": "sha256",
16
+ "files": {
17
+ "__init__.py": "nD4wkB6waTwtHyX+hTWxnxpG20lx20+4WIXQRaYVlAA=",
18
+ "_causal_conv1d/__init__.py": "0k4qW/hINms4Twy1DUIjiRmfeS48AzgU3TfOh2+5/NQ=",
19
+ "_causal_conv1d/causal_conv1d_interface.py": "Mm0fBbamT4dihp+Z53RzIFM/dn5Y8nLu1vJ4W4W53jQ=",
20
+ "_causal_conv1d/causal_conv1d_varlen.py": "vbnARQEt2mHp9UcduYiikYFg73Nyay7Vl9QYWxpH1sA=",
21
+ "_causal_conv1d/cpp_functions.py": "AlI7Xe0VkWZUybPTfsK+OdvylUXpBCmHlg2NzNimgWg=",
22
+ "_mamba_ssm_xpu_81e0711.abi3.so": "pLVqc0VrrGf8P9ebive+nvaw5wbsFdW6Z8poK4yfRvI=",
23
+ "_ops.py": "DGO+byAJFA0ZDGXOABVLxXyWTiie7fOd99CxhKw7vwE=",
24
+ "distributed/__init__.py": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
25
+ "distributed/distributed_utils.py": "qhcybRXtslssuV9LYaQy37haPaPtklM4YUMDx9UvnnQ=",
26
+ "distributed/tensor_parallel.py": "WIlmot0UQJHFnzYNIMKdRCVLFWYSufbarBHy0baW4a8=",
27
+ "layers.py": "B0VMeMqemybAKyB6/ZjpC9+aKLuTEhtg3T+VSJIcRzA=",
28
+ "models/__init__.py": "mGa9i0oDQaBiEv4FbpIfrvEyWhK75wFNP5g0ob0pw1U=",
29
+ "models/config_mamba.py": "KnLBaG93W1ZUfjnKRAa6EBSNEv16eRxXziuoUSYBD80=",
30
+ "models/mixer_seq_simple.py": "SegRdVaBQKml6uoMoKE5UFWRHta0IiJ2fp4Tw1JqHIo=",
31
+ "modules/__init__.py": "Q6q0wng3smVLvW2pxCAQPReaKkydvGCNHFjs4Lu3LB4=",
32
+ "modules/block.py": "fH/KDDXmUo6oKx6K+NVmCcsuW4nEm9ahBLtvDo3S1gY=",
33
+ "modules/mamba2.py": "YYUi1BahS45JY4ruzugkwi7v19ijGfRj1i3WpWtBZjU=",
34
+ "modules/mamba2_simple.py": "0teqUzcEaiq6/X3hf/wuuBHKfIElFms2qXNYGOOjD50=",
35
+ "modules/mamba_simple.py": "9EpZyWJg+66iZ3dDwulGOMCYBE6XFke2JRfUSkmgDxk=",
36
+ "modules/mha.py": "j6hLbPVbubSsYgwm2T9C2Qn6F3WqDGWUsypzspDvFrE=",
37
+ "modules/mlp.py": "06o2CuZ2CNJYKXXyXsmtxXYT5ELy7e/NiOkTY+beUCE=",
38
+ "modules/ssd_minimal.py": "2qLlzjJemIQmrSn4opZQxEES01l2X5Hm5DAGfwAmyDg=",
39
+ "ops/__init__.py": "t5DB51GI8HuvZP+P8rSHCamL7Yf+AYsGf28FZ8MKKrA=",
40
+ "ops/selective_scan_interface.py": "suZDiEWhVpk+BU2bg12Qy31G+13n3Q8YdqOnsb5p9PQ=",
41
+ "ops/triton/__init__.py": "EqZ8Nb7HWyhDVHYI34P87X1nTe5cmGtFGcpuwRwFEdY=",
42
+ "ops/triton/k_activations.py": "BXosJnTCJCXRWrhRFWTgoGGeXR/Rjfl3yTaF1fa/TWg=",
43
+ "ops/triton/layer_norm.py": "4mGWLbf6kyVDlZId1bSlZXzsX0zQm6EGqs4kMWtGnL0=",
44
+ "ops/triton/layernorm_gated.py": "cABJDSiJ1qkmLlwgxDOIRLR357urLCq4wcRRK+JmBYw=",
45
+ "ops/triton/selective_state_update.py": "cdPIinjlL8nPtB1sZrmh5OYoWONWrp3NQYDWayrWuEo=",
46
+ "ops/triton/softplus.py": "rdz5bzBt0sm/HJ75/tpCOBpuVa2QbdkuIgWY/P7HtQg=",
47
+ "ops/triton/ssd_bmm.py": "Y+floVIs3LfX9g79aexMn5+tW/iAHrycPA5gCDT3ZcI=",
48
+ "ops/triton/ssd_chunk_scan.py": "9Ob6vF8hYnOS8Jvc/yiZ5i2KejMqWS9ADYhdzUrmm24=",
49
+ "ops/triton/ssd_chunk_state.py": "26rm1fFmAD81YmZR7tJpADb1N40GwmBAJc7WKx7meaA=",
50
+ "ops/triton/ssd_combined.py": "uZae0V5rIZGWI8pDzmJPLf/j8aBlD83BbUfEZmK6bZM=",
51
+ "ops/triton/ssd_state_passing.py": "338jz7eRtYwI7YuiubNnEufXev28Al8+Hv7P7KhX0nE=",
52
+ "utils/__init__.py": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
53
+ "utils/device.py": "38RSd09YjhOijr0WRWb4DKl1uCEZIw4n1C1dxHVgsKs=",
54
+ "utils/generation.py": "21adNBvbzCLLvwW6lPmzhRofmxE68NR75fOWDl22ZkQ=",
55
+ "utils/hf.py": "qm86NJgmYSvzsxDSCevlBUa/GyvpvO49WVnKv6fSNfY=",
56
+ "utils/torch.py": "HDEyoadH6RSHToS18wDqgNApf6um65JWy1rEs9ZBPAY="
57
+ }
58
+ },
59
+ "provenance": {
60
+ "kernel-builder": {
61
+ "version": "0.17.0-dev0",
62
+ "commit": "a7f0afdb29a6a3372b1d47180cc0c182454c5e3b",
63
+ "dirty": false
64
+ },
65
+ "kernel": {
66
+ "commit": "81e071162629e5130d35a689a1ba7fdbc1feae15",
67
+ "dirty": false
68
+ }
69
+ }
70
+ }
build/torch214-cxx11-xpu20261-x86_64-linux/metadata.json.sigstore ADDED
@@ -0,0 +1 @@
 
 
1
+ {"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial":{"certificate":{"rawBytes":"MIIHLDCCBrOgAwIBAgIUVAzR2DNVbTvS9CX9CdtjhN7rcfcwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDE0MTg0NDMzWhcNMjYxMDE0MTg1NDMzWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYO4083wHyeVj/V3+dvFOVoCJlHptGmyPMO5eYM5pcwGrjj+awaypvusFkrVIYE89FIEcq4i2E6blztwUhghcb6OCBdIwggXOMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBrBgNVHREBAf8EYTBfhl1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBCg4MWUwNzExNjI2MjllNTEzMGQzNWE2ODlhMWJhN2ZkYmMxZmVhZTE1MBMGCisGAQQBg78wAQQEBUJ1aWxkMCsGCisGAQQBg78wAQUEHWh1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wbQYKKwYBBAGDvzABCQRfDF1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDCg4MWUwNzExNjI2MjllNTEzMGQzNWE2ODlhMWJhN2ZkYmMxZmVhZTE1MBsGCisGAQQBg78wAQsEDQwLc2VsZi1ob3N0ZWQwQAYKKwYBBAGDvzABDAQyDDBodHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkwOAYKKwYBBAGDvzABDQQqDCg4MWUwNzExNjI2MjllNTEzMGQzNWE2ODlhMWJhN2ZkYmMxZmVhZTE1MB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBoGCisGAQQBg78wAQ8EDAwKMTA3MTQ3NTUyOTAuBgorBgEEAYO/MAEQBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZTAYBgorBgEEAYO/MAERBAoMCDI1NzIwNzQzMG0GCisGAQQBg78wARIEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoODFlMDcxMTYyNjI5ZTUxMzBkMzVhNjg5YTFiYTdmZGJjMWZlYWUxNTAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rpc3BhdGNoMGQGCisGAQQBg78wARUEVgxUaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5L2FjdGlvbnMvcnVucy8zODYxNjkxOTkwNi9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMEYGCisGAQQBg78wARgEOAw2cmVwbzpodWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTpyZWY6cmVmcy9oZWFkcy9tYWluMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhO7sArwAABAMASDBGAiEAl0WFkq1yi7VEMYiTue7yMJX5TPgKk+6iunw5OPaY61ACIQCPEicDKFjZEgrCB3dEiC/qhzh5OHG1QVfncazMgZzDWzAKBggqhkjOPQQDAwNnADBkAjBzdAwoG23tJLH6ym4AmuejDQdhi/Kmof2kCKcm2WRrMXNZVzObn8CDP3bT0O7ER0ECMD3eaS//q9l3qm/cNRkLTN9YqBFxMSdlaolzBQamn4qPN/L97G4fUj7pvJwBynz86w=="}, "tlogEntries":[{"logIndex":"3253405420", "logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion":{"kind":"hashedrekord", "version":"0.0.1"}, "integratedTime":"1792003474", "inclusionPromise":{"signedEntryTimestamp":"MEQCICg0TEJQTM01D/5Qmk/yoZbnVEtf0nsQ+fcCKZMZDqj+AiBEPpHThUyXOc+mEHVdLoJ2WxxJuxVFWWCOP+Bwp5TfhQ=="}, "inclusionProof":{"logIndex":"3131501158", "rootHash":"N47nVQX30OmezY7aBUxImgQugBZDA6f26Ch3ASppvFo=", "treeSize":"3131501244", "hashes":["ZTlh5NOq71Z+Qjn3NbjSLRXjZ9ANYrDXmwhNPgyGCHI=", "L027mV3KniGz9FeNplb6vOpcp6kd2N9l8knjbj3Dhew=", "lIR/uAL0YdGZ9K1FXXYsyvQMrAaUEixyfRCltXjFaV4=", "cySGxB/mNaczt7JsUiWpJzEygZ9jEjQ8hsl8mQp4RnU=", "KOWfGiu/ZQHH9qIiB6L+zUmwyIFBm5XMa3KZ3o5oNvo=", "KEIx62KQrfbYLFjlV56L1BF0/4Zyi0jdJoFQriFlbdg=", "+XWmUoH7UcFU2cYZv6OLtjQjXDmgsB/o2nLa9A+/h9E=", "/CtHaXs0LXLBiDnvQKwmAXhT2ijfKen6riHZPo9NVT8=", "GO+goI6X7UtRTplOKRR3wvaWxDM6+OZ8ad5E7OtfuXM=", "geEhkQJhV7Mvrc/1XlEYAd/E2xEvGuEIWzF3K/WQqRs=", "azgA5l+dCus8JKHpt7SuU0eOmYP/t2q6Qr2hjpwkzck=", "P9YYoeZbSmecrFVIWfhdNqLoCqtSHCjCxLmRqgRj9HI=", "269risaJv49PdqnoapCLzEBqc7UGtT2sPMyMqf0AmdI=", "N2bqEKMHv+9iL6VHGFvsNEHd3Glamt/BPGd0Cu5Q3sk=", "TM/DI5q5VNdi7ZmPI8audBpIvokfwTzQwewC1MNx4UY=", "fBjWdrcjeVDmAVWQq4BmcXhqCqJvE/nse0IawshnKCM=", "PDmnPqqpjOVTeesoPXQDAeFP3UxQJYNIKu1opzLOH/U=", "wk2tYV/zs2FUIlhL9YQeUw8UqKbqhapvz1h7jtdeQWw=", "gg9GNApNke3+zNhl4tsWtmIycCFrOMCB3lys6XuSQNQ=", "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY="], "checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n3131501244\nN47nVQX30OmezY7aBUxImgQugBZDA6f26Ch3ASppvFo=\n\n— rekor.sigstore.dev wNI9ajBEAiBdDZcSLL5Z73Lwq0zFJ3cyAajbhWGMnYS/gkfmh1hQcQIgc1iAkUxyM7s0h9CG891bQwNcujdlrIr0Pz8cr4esmXY=\n"}}, "canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI1MDYwNzFmOTBiM2UyZmNlYjNjOTk3N2Q1ODc0NmY3YWQzNDM4ZDUxM2JhYjA0MmQyMmQ0YWM0OGJjMjY0M2ZjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUR3M2NZK1FXVEc4SHgrY0M4NTlUZTh5citoRnZ5b0tubW0xUUVBVFVqbFhBSWdGOWFGUlUxYTV0TzJLY3dYd29SbGVZWlJYSnhHZ2VWQ291aXUzYkZybWdNPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaE1SRU5EUW5KUFowRjNTVUpCWjBsVlZrRjZVakpFVGxaaVZIWlRPVU5ZT1VOa2RHcG9UamR5WTJaamQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFUlRCTlZHY3dUa1JOZWxkb1kwNU5hbGw0VFVSRk1FMVVaekZPUkUxNlYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZaVHpRd09ETjNTSGxsVm1vdlZqTXJaSFpHVDFadlEwcHNTSEIwUjIxNVVFMVBOV1VLV1UwMWNHTjNSM0pxYWl0aGQyRjVjSFoxYzBacmNsWkpXVVU0T1VaSlJXTnhOR2t5UlRaaWJIcDBkMVZvWjJoallqWlBRMEprU1hkbloxaFBUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFuSkNaMDVXU0ZKRlFrRm1PRVZaVkVKbWFHd3hiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWMllUSldlV0p0Vm5OamVURnFZakl4ZEdSWE5YQmtTR3QyVEcxa2NHUkhhREZaYVRrellqTktjZ3BhYlhoMlpETk5kbGx1Vm5CaVIxRjFaVmRHZEdKRlFubGFWMXA2VERKb2JGbFhVbnBNTWpGb1lWYzBkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5Q21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjR0l5TlhwTWJXUndaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJaa0puYjNJS1FtZEZSVUZaVHk5TlFVVkRRa0pHTTJJelNuSmFiWGgyWkRFNWEyRllUbmRaV0ZKcVlVUkJNa0puYjNKQ1owVkZRVmxQTDAxQlJVUkNRMmMwVFZkVmR3cE9la1Y0VG1wSk1rMXFiR3hPVkVWNlRVZFJlazVYUlRKUFJHeG9UVmRLYUU0eVdtdFpiVTE0V20xV2FGcFVSVEZOUWsxSFEybHpSMEZSVVVKbk56aDNDa0ZSVVVWQ1ZVb3hZVmQ0YTAxRGMwZERhWE5IUVZGUlFtYzNPSGRCVVZWRlNGZG9NVm95WkhCaWJXUnRXVmRPYkV3eWRHeGpiVFZzWWtoTmRGa3lPWFFLWWxoV2RXRllValZOUWpCSFEybHpSMEZSVVVKbk56aDNRVkZaUlVRelNteGFiazEyWVVkV2FGcElUWFppVjBad1ltcEJOMEpuYjNKQ1owVkZRVmxQTHdwTlFVVkpRa013VFVzeWFEQmtTRUo2VDJrNGRtUkhPWEphVnpSMVdWZE9NR0ZYT1hWamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcUNtSXlNSGRpVVZsTFMzZFpRa0pCUjBSMmVrRkNRMUZTWmtSR01XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaFNGWnVXakpzZFZveVdtZ0tXVEpWZG1FeVZubGliVlp6WTNreGFtSXlNWFJrVnpWd1pFaHJka3h0WkhCa1IyZ3hXV2s1TTJJelNuSmFiWGgyWkROTmRsbHVWbkJpUjFGMVpWZEdkQXBpUlVKNVdsZGFla3d5YUd4WlYxSjZUREl4YUdGWE5IZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1EyZFJjVVJEWnpSTlYxVjNUbnBGZUU1cVNUSk5hbXhzQ2s1VVJYcE5SMUY2VGxkRk1rOUViR2hOVjBwb1RqSmFhMWx0VFhoYWJWWm9XbFJGTVUxQ2MwZERhWE5IUVZGUlFtYzNPSGRCVVhORlJGRjNUR015Vm5NS1dta3hiMkl6VGpCYVYxRjNVVUZaUzB0M1dVSkNRVWRFZG5wQlFrUkJVWGxFUkVKdlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWVVoV2JncGFNbXgxV2pKYWFGa3lWWFpoTWxaNVltMVdjMk41TVdwaU1qRjBaRmMxY0dSSWEzZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JGRlJjVVJEWnpSTlYxVjNDazU2UlhoT2Fra3lUV3BzYkU1VVJYcE5SMUY2VGxkRk1rOUViR2hOVjBwb1RqSmFhMWx0VFhoYWJWWm9XbFJGTVUxQ09FZERhWE5IUVZGUlFtYzNPSGNLUVZFMFJVVlJkMUJqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxQ2IwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlJFRjNTMDFVUVROTlZGRXpUbFJWZVFwUFZFRjFRbWR2Y2tKblJVVkJXVTh2VFVGRlVVSkRRVTFJYldnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemx2WkZka2JtRlhOVzVhYlVacUNscFVRVmxDWjI5eVFtZEZSVUZaVHk5TlFVVlNRa0Z2VFVORVNURk9la2wzVG5wUmVrMUhNRWREYVhOSFFWRlJRbWMzT0hkQlVrbEZXSGQ0WkdGSVVqQUtZMGhOTmt4NU9XNWhXRkp2WkZkSmRWa3lPWFJNTW1neFdqSmtjR0p0WkcxWlYwNXNUREowYkdOdE5XeGlTRTEwV1RJNWRHSllWblZoV0ZJMVRIazFiZ3BoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3eVNqRmhWM2hyVEc1c2FHSlhlRUZqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxRVowZERhWE5IQ2tGUlVVSm5OemgzUVZKTlJVdG5kMjlQUkVac1RVUmplRTFVV1hsT2FrazFXbFJWZUUxNlFtdE5lbFpvVG1wbk5WbFVSbWxaVkdSdFdrZEthazFYV213S1dWZFZlRTVVUVdoQ1oyOXlRbWRGUlVGWlR5OU5RVVZWUWtKTlRVVllaSFpqYlhSdFlrYzVNMWd5VW5Cak0wSm9aRWRPYjAxSFVVZERhWE5IUVZGUlFncG5OemgzUVZKVlJWWm5lRlZoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlQwUlplRTVxYTNoUFZHdDNUbWs1YUdSSVVteGlXRUl3WTNrNGVFMUNXVWNLUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxRldVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlQwRjNNbU50Vm5kaWVuQnZaRmRrYmdwaFZ6VnVXbTFHYWxwVE9YSmFXRXAxV2xkNGVreFhUblppVnpFeFltMXNNR1ZVY0hsYVYxazJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOU1VkTUNrSm5iM0pDWjBWRlFXUmFOVUZuVVVOQ1NEQkZaWGRDTlVGSVkwRXpWREIzWVhOaVNFVlVTbXBIVWpSamJWZGpNMEZ4U2t0WWNtcGxVRXN6TDJnMGNIa0taME00Y0Rkdk5FRkJRVWRvVHpkelFYSjNRVUZDUVUxQlUwUkNSMEZwUlVGc01GZEdhM0V4ZVdrM1ZrVk5XV2xVZFdVM2VVMUtXRFZVVUdkTGF5czJhUXAxYm5jMVQxQmhXVFl4UVVOSlVVTlFSV2xqUkV0R2FscEZaM0pEUWpOa1JXbERMM0ZvZW1nMVQwaEhNVkZXWm01allYcE5aMXA2UkZkNlFVdENaMmR4Q21ocmFrOVFVVkZFUVhkT2JrRkVRbXRCYWtKNlpFRjNiMGN5TTNSS1RFZzJlVzAwUVcxMVpXcEVVV1JvYVM5TGJXOW1NbXREUzJOdE1sZFNjazFZVGxvS1ZucFBZbTQ0UTBSUU0ySlVNRTgzUlZJd1JVTk5SRE5sWVZNdkwzRTViRE54YlM5alRsSnJURlJPT1ZseFFrWjRUVk5rYkdGdmJIcENVV0Z0YmpSeFVBcE9MMHc1TjBjMFpsVnFOM0IyU25kQ2VXNTZPRFozUFQwS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19"}], "timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQg05fQPWW4iOTd/nOBzk89BOZjZkoJJHo6LkUX0qZm7J8CFDQf1+Xh/RKvvPx5xQOG6++ApU9pGA8yMDI2MTAxNDE4NDQzM1owAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYxMDE0MTg0NDMzWjAvBgkqhkiG9w0BCQQxIgQgMIiawk3xnB1iwfjNEisqljrhnrq5xVoLcUbxBASMHcowgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIwcr28+ho6lqoBIf74PI2wVyELYIrjBgEy8IOBAPzfq/Keob6sDp7vdrK6vNM6KWWlAjEAnmucp5PO6wN56CiJwdgRtigDLmkIMdAG8uA+XW1xvHF8PveYZbBvbbo3vrnPpR1q"}]}}, "messageSignature":{"messageDigest":{"algorithm":"SHA2_256", "digest":"UGBx+Qs+L86zyZd9WHRvetNDjVE7qwQtItSsSLwmQ/w="}, "signature":"MEUCIQDw3cY+QWTG8Hx+cC859Te8yr+hFvyoKnmm1QEATUjlXAIgF9aFRU1a5tO2KcwXwoRleYZRXJxGgeVCouiu3bFrmgM="}}
build/torch214-cxx11-xpu20261-x86_64-linux/models/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from .mixer_seq_simple import MambaLMHeadModel
2
+
3
+ __all__ = [
4
+ "MambaLMHeadModel",
5
+ ]
build/torch214-cxx11-xpu20261-x86_64-linux/models/config_mamba.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass, field
2
+
3
+
4
+ @dataclass
5
+ class MambaConfig:
6
+
7
+ d_model: int = 2560
8
+ d_intermediate: int = 0
9
+ n_layer: int = 64
10
+ vocab_size: int = 50277
11
+ ssm_cfg: dict = field(default_factory=dict)
12
+ attn_layer_idx: list = field(default_factory=list)
13
+ attn_cfg: dict = field(default_factory=dict)
14
+ rms_norm: bool = True
15
+ residual_in_fp32: bool = True
16
+ fused_add_norm: bool = True
17
+ pad_vocab_size_multiple: int = 8
18
+ tie_embeddings: bool = True
build/torch214-cxx11-xpu20261-x86_64-linux/models/mixer_seq_simple.py ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Albert Gu, Tri Dao.
2
+
3
+ import math
4
+ from functools import partial
5
+ import json
6
+ import os
7
+ import copy
8
+
9
+ from collections import namedtuple
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+
14
+ from .config_mamba import MambaConfig
15
+ from ..modules.mamba_simple import Mamba
16
+ from ..modules.mamba2 import Mamba2
17
+ from ..modules.mha import MHA
18
+ from ..modules.mlp import GatedMLP
19
+ from ..modules.block import Block
20
+ from ..utils.generation import GenerationMixin
21
+ from ..utils.hf import load_config_hf, load_state_dict_hf
22
+
23
+ try:
24
+ from ..ops.triton.layer_norm import RMSNorm, layer_norm_fn, rms_norm_fn
25
+ except ImportError:
26
+ RMSNorm, layer_norm_fn, rms_norm_fn = None, None, None
27
+
28
+
29
+ def create_block(
30
+ d_model,
31
+ d_intermediate,
32
+ ssm_cfg=None,
33
+ attn_layer_idx=None,
34
+ attn_cfg=None,
35
+ norm_epsilon=1e-5,
36
+ rms_norm=False,
37
+ residual_in_fp32=False,
38
+ fused_add_norm=False,
39
+ layer_idx=None,
40
+ device=None,
41
+ dtype=None,
42
+ ):
43
+ if ssm_cfg is None:
44
+ ssm_cfg = {}
45
+ if attn_layer_idx is None:
46
+ attn_layer_idx = []
47
+ if attn_cfg is None:
48
+ attn_cfg = {}
49
+ factory_kwargs = {"device": device, "dtype": dtype}
50
+ if layer_idx not in attn_layer_idx:
51
+ # Create a copy of the config to modify
52
+ ssm_cfg = copy.deepcopy(ssm_cfg) if ssm_cfg is not None else {}
53
+ ssm_layer = ssm_cfg.pop("layer", "Mamba1")
54
+ if ssm_layer not in ["Mamba1", "Mamba2"]:
55
+ raise ValueError(f"Invalid ssm_layer: {ssm_layer}, only support Mamba1 and Mamba2")
56
+ mixer_cls = partial(
57
+ Mamba2 if ssm_layer == "Mamba2" else Mamba,
58
+ layer_idx=layer_idx,
59
+ **ssm_cfg,
60
+ **factory_kwargs
61
+ )
62
+ else:
63
+ mixer_cls = partial(MHA, layer_idx=layer_idx, **attn_cfg, **factory_kwargs)
64
+ norm_cls = partial(
65
+ nn.LayerNorm if not rms_norm else RMSNorm, eps=norm_epsilon, **factory_kwargs
66
+ )
67
+ if d_intermediate == 0:
68
+ mlp_cls = nn.Identity
69
+ else:
70
+ mlp_cls = partial(
71
+ GatedMLP, hidden_features=d_intermediate, out_features=d_model, **factory_kwargs
72
+ )
73
+ block = Block(
74
+ d_model,
75
+ mixer_cls,
76
+ mlp_cls,
77
+ norm_cls=norm_cls,
78
+ fused_add_norm=fused_add_norm,
79
+ residual_in_fp32=residual_in_fp32,
80
+ )
81
+ block.layer_idx = layer_idx
82
+ return block
83
+
84
+
85
+ # https://github.com/huggingface/transformers/blob/c28d04e9e252a1a099944e325685f14d242ecdcd/src/transformers/models/gpt2/modeling_gpt2.py#L454
86
+ def _init_weights(
87
+ module,
88
+ n_layer,
89
+ initializer_range=0.02, # Now only used for embedding layer.
90
+ rescale_prenorm_residual=True,
91
+ n_residuals_per_layer=1, # Change to 2 if we have MLP
92
+ ):
93
+ if isinstance(module, nn.Linear):
94
+ if module.bias is not None:
95
+ if not getattr(module.bias, "_no_reinit", False):
96
+ nn.init.zeros_(module.bias)
97
+ elif isinstance(module, nn.Embedding):
98
+ nn.init.normal_(module.weight, std=initializer_range)
99
+
100
+ if rescale_prenorm_residual:
101
+ # Reinitialize selected weights subject to the OpenAI GPT-2 Paper Scheme:
102
+ # > A modified initialization which accounts for the accumulation on the residual path with model depth. Scale
103
+ # > the weights of residual layers at initialization by a factor of 1/√N where N is the # of residual layers.
104
+ # > -- GPT-2 :: https://openai.com/blog/better-language-models/
105
+ #
106
+ # Reference (Megatron-LM): https://github.com/NVIDIA/Megatron-LM/blob/main/megatron/model/gpt_model.py
107
+ for name, p in module.named_parameters():
108
+ if name in ["out_proj.weight", "fc2.weight"]:
109
+ # Special Scaled Initialization --> There are 2 Layer Norms per Transformer Block
110
+ # Following Pytorch init, except scale by 1/sqrt(2 * n_layer)
111
+ # We need to reinit p since this code could be called multiple times
112
+ # Having just p *= scale would repeatedly scale it down
113
+ nn.init.kaiming_uniform_(p, a=math.sqrt(5))
114
+ with torch.no_grad():
115
+ p /= math.sqrt(n_residuals_per_layer * n_layer)
116
+
117
+
118
+ class MixerModel(nn.Module):
119
+ def __init__(
120
+ self,
121
+ d_model: int,
122
+ n_layer: int,
123
+ d_intermediate: int,
124
+ vocab_size: int,
125
+ ssm_cfg=None,
126
+ attn_layer_idx=None,
127
+ attn_cfg=None,
128
+ norm_epsilon: float = 1e-5,
129
+ rms_norm: bool = False,
130
+ initializer_cfg=None,
131
+ fused_add_norm=False,
132
+ residual_in_fp32=False,
133
+ device=None,
134
+ dtype=None,
135
+ ) -> None:
136
+ factory_kwargs = {"device": device, "dtype": dtype}
137
+ super().__init__()
138
+ self.residual_in_fp32 = residual_in_fp32
139
+
140
+ self.embedding = nn.Embedding(vocab_size, d_model, **factory_kwargs)
141
+
142
+ # We change the order of residual and layer norm:
143
+ # Instead of LN -> Attn / MLP -> Add, we do:
144
+ # Add -> LN -> Attn / MLP / Mixer, returning both the residual branch (output of Add) and
145
+ # the main branch (output of MLP / Mixer). The model definition is unchanged.
146
+ # This is for performance reason: we can fuse add + layer_norm.
147
+ self.fused_add_norm = fused_add_norm
148
+ if self.fused_add_norm:
149
+ if layer_norm_fn is None or rms_norm_fn is None:
150
+ raise ImportError("Failed to import Triton LayerNorm / RMSNorm kernels")
151
+
152
+ self.layers = nn.ModuleList(
153
+ [
154
+ create_block(
155
+ d_model,
156
+ d_intermediate=d_intermediate,
157
+ ssm_cfg=ssm_cfg,
158
+ attn_layer_idx=attn_layer_idx,
159
+ attn_cfg=attn_cfg,
160
+ norm_epsilon=norm_epsilon,
161
+ rms_norm=rms_norm,
162
+ residual_in_fp32=residual_in_fp32,
163
+ fused_add_norm=fused_add_norm,
164
+ layer_idx=i,
165
+ **factory_kwargs,
166
+ )
167
+ for i in range(n_layer)
168
+ ]
169
+ )
170
+
171
+ self.norm_f = (nn.LayerNorm if not rms_norm else RMSNorm)(
172
+ d_model, eps=norm_epsilon, **factory_kwargs
173
+ )
174
+
175
+ self.apply(
176
+ partial(
177
+ _init_weights,
178
+ n_layer=n_layer,
179
+ **(initializer_cfg if initializer_cfg is not None else {}),
180
+ n_residuals_per_layer=1 if d_intermediate == 0 else 2, # 2 if we have MLP
181
+ )
182
+ )
183
+
184
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
185
+ return {
186
+ i: layer.allocate_inference_cache(batch_size, max_seqlen, dtype=dtype, **kwargs)
187
+ for i, layer in enumerate(self.layers)
188
+ }
189
+
190
+ def forward(self, input_ids, inference_params=None, **mixer_kwargs):
191
+ hidden_states = self.embedding(input_ids)
192
+ residual = None
193
+ for layer in self.layers:
194
+ hidden_states, residual = layer(
195
+ hidden_states, residual, inference_params=inference_params, **mixer_kwargs
196
+ )
197
+ if not self.fused_add_norm:
198
+ residual = (hidden_states + residual) if residual is not None else hidden_states
199
+ hidden_states = self.norm_f(residual.to(dtype=self.norm_f.weight.dtype))
200
+ else:
201
+ # Set prenorm=False here since we don't need the residual
202
+ hidden_states = layer_norm_fn(
203
+ hidden_states,
204
+ self.norm_f.weight,
205
+ self.norm_f.bias,
206
+ eps=self.norm_f.eps,
207
+ residual=residual,
208
+ prenorm=False,
209
+ residual_in_fp32=self.residual_in_fp32,
210
+ is_rms_norm=isinstance(self.norm_f, RMSNorm)
211
+ )
212
+ return hidden_states
213
+
214
+
215
+ class MambaLMHeadModel(nn.Module, GenerationMixin):
216
+
217
+ def __init__(
218
+ self,
219
+ config: MambaConfig,
220
+ initializer_cfg=None,
221
+ device=None,
222
+ dtype=None,
223
+ ) -> None:
224
+ self.config = config
225
+ d_model = config.d_model
226
+ n_layer = config.n_layer
227
+ d_intermediate = config.d_intermediate
228
+ vocab_size = config.vocab_size
229
+ ssm_cfg = config.ssm_cfg
230
+ attn_layer_idx = config.attn_layer_idx
231
+ attn_cfg = config.attn_cfg
232
+ rms_norm = config.rms_norm
233
+ residual_in_fp32 = config.residual_in_fp32
234
+ fused_add_norm = config.fused_add_norm
235
+ pad_vocab_size_multiple = config.pad_vocab_size_multiple
236
+ factory_kwargs = {"device": device, "dtype": dtype}
237
+
238
+ super().__init__()
239
+ if vocab_size % pad_vocab_size_multiple != 0:
240
+ vocab_size += pad_vocab_size_multiple - (vocab_size % pad_vocab_size_multiple)
241
+ self.backbone = MixerModel(
242
+ d_model=d_model,
243
+ n_layer=n_layer,
244
+ d_intermediate=d_intermediate,
245
+ vocab_size=vocab_size,
246
+ ssm_cfg=ssm_cfg,
247
+ attn_layer_idx=attn_layer_idx,
248
+ attn_cfg=attn_cfg,
249
+ rms_norm=rms_norm,
250
+ initializer_cfg=initializer_cfg,
251
+ fused_add_norm=fused_add_norm,
252
+ residual_in_fp32=residual_in_fp32,
253
+ **factory_kwargs,
254
+ )
255
+ self.lm_head = nn.Linear(d_model, vocab_size, bias=False, **factory_kwargs)
256
+
257
+ # Initialize weights and apply final processing
258
+ self.apply(
259
+ partial(
260
+ _init_weights,
261
+ n_layer=n_layer,
262
+ **(initializer_cfg if initializer_cfg is not None else {}),
263
+ )
264
+ )
265
+ self.tie_weights()
266
+
267
+ def tie_weights(self):
268
+ if self.config.tie_embeddings:
269
+ self.lm_head.weight = self.backbone.embedding.weight
270
+
271
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
272
+ return self.backbone.allocate_inference_cache(batch_size, max_seqlen, dtype=dtype, **kwargs)
273
+
274
+ def forward(self, input_ids, position_ids=None, inference_params=None, num_last_tokens=0, **mixer_kwargs):
275
+ """
276
+ "position_ids" is just to be compatible with Transformer generation. We don't use it.
277
+ num_last_tokens: if > 0, only return the logits for the last n tokens
278
+ """
279
+ hidden_states = self.backbone(input_ids, inference_params=inference_params, **mixer_kwargs)
280
+ if num_last_tokens > 0:
281
+ hidden_states = hidden_states[:, -num_last_tokens:]
282
+ lm_logits = self.lm_head(hidden_states)
283
+ CausalLMOutput = namedtuple("CausalLMOutput", ["logits"])
284
+ return CausalLMOutput(logits=lm_logits)
285
+
286
+ @classmethod
287
+ def from_pretrained(cls, pretrained_model_name, device=None, dtype=None, **kwargs):
288
+ config_data = load_config_hf(pretrained_model_name)
289
+ config = MambaConfig(**config_data)
290
+ model = cls(config, device=device, dtype=dtype, **kwargs)
291
+ model.load_state_dict(load_state_dict_hf(pretrained_model_name, device=device, dtype=dtype))
292
+ return model
293
+
294
+ def save_pretrained(self, save_directory):
295
+ """
296
+ Minimal implementation of save_pretrained for MambaLMHeadModel.
297
+ Save the model and its configuration file to a directory.
298
+ """
299
+ # Ensure save_directory exists
300
+ os.makedirs(save_directory, exist_ok=True)
301
+
302
+ # Save the model's state_dict
303
+ model_path = os.path.join(save_directory, 'pytorch_model.bin')
304
+ torch.save(self.state_dict(), model_path)
305
+
306
+ # Save the configuration of the model
307
+ config_path = os.path.join(save_directory, 'config.json')
308
+ with open(config_path, 'w') as f:
309
+ json.dump(self.config.__dict__, f, indent=4)
build/torch214-cxx11-xpu20261-x86_64-linux/modules/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from .mamba_simple import Mamba
2
+ from .mamba2 import Mamba2
3
+
4
+ __all__ = [
5
+ "Mamba",
6
+ "Mamba2",
7
+ ]
build/torch214-cxx11-xpu20261-x86_64-linux/modules/block.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+ from typing import Optional
3
+
4
+ import torch
5
+ from torch import nn, Tensor
6
+
7
+ from ..ops.triton.layer_norm import RMSNorm, layer_norm_fn
8
+
9
+
10
+ class Block(nn.Module):
11
+ def __init__(
12
+ self,
13
+ dim,
14
+ mixer_cls,
15
+ mlp_cls,
16
+ norm_cls=nn.LayerNorm,
17
+ fused_add_norm=False,
18
+ residual_in_fp32=False,
19
+ ):
20
+ """
21
+ Simple block wrapping a mixer class with LayerNorm/RMSNorm and residual connection"
22
+
23
+ This Block has a slightly different structure compared to a regular
24
+ prenorm Transformer block.
25
+ The standard block is: LN -> MHA/MLP -> Add.
26
+ [Ref: https://arxiv.org/abs/2002.04745]
27
+ Here we have: Add -> LN -> Mixer, returning both
28
+ the hidden_states (output of the mixer) and the residual.
29
+ This is purely for performance reasons, as we can fuse add and LayerNorm.
30
+ The residual needs to be provided (except for the very first block).
31
+ """
32
+ super().__init__()
33
+ self.residual_in_fp32 = residual_in_fp32
34
+ self.fused_add_norm = fused_add_norm
35
+ self.norm = norm_cls(dim)
36
+ self.mixer = mixer_cls(dim)
37
+ if mlp_cls is not nn.Identity:
38
+ self.norm2 = norm_cls(dim)
39
+ self.mlp = mlp_cls(dim)
40
+ else:
41
+ self.mlp = None
42
+ if self.fused_add_norm:
43
+ assert RMSNorm is not None, "RMSNorm import fails"
44
+ assert isinstance(
45
+ self.norm, (nn.LayerNorm, RMSNorm)
46
+ ), "Only LayerNorm and RMSNorm are supported for fused_add_norm"
47
+
48
+ def forward(
49
+ self,
50
+ hidden_states: Tensor,
51
+ residual: Optional[Tensor] = None,
52
+ inference_params=None,
53
+ **mixer_kwargs
54
+ ):
55
+ r"""Pass the input through the encoder layer.
56
+
57
+ Args:
58
+ hidden_states: the sequence to the encoder layer (required).
59
+ residual: hidden_states = Mixer(LN(residual))
60
+ """
61
+ if not self.fused_add_norm:
62
+ residual = (
63
+ (hidden_states + residual) if residual is not None else hidden_states
64
+ )
65
+ hidden_states = self.norm(residual.to(dtype=self.norm.weight.dtype))
66
+ if self.residual_in_fp32:
67
+ residual = residual.to(torch.float32)
68
+ else:
69
+ hidden_states, residual = layer_norm_fn(
70
+ hidden_states,
71
+ self.norm.weight,
72
+ self.norm.bias,
73
+ residual=residual,
74
+ prenorm=True,
75
+ residual_in_fp32=self.residual_in_fp32,
76
+ eps=self.norm.eps,
77
+ is_rms_norm=isinstance(self.norm, RMSNorm),
78
+ )
79
+ hidden_states = self.mixer(
80
+ hidden_states, inference_params=inference_params, **mixer_kwargs
81
+ )
82
+
83
+ if self.mlp is not None:
84
+ if not self.fused_add_norm:
85
+ residual = hidden_states + residual
86
+ hidden_states = self.norm2(residual.to(dtype=self.norm2.weight.dtype))
87
+ if self.residual_in_fp32:
88
+ residual = residual.to(torch.float32)
89
+ else:
90
+ hidden_states, residual = layer_norm_fn(
91
+ hidden_states,
92
+ self.norm2.weight,
93
+ self.norm2.bias,
94
+ residual=residual,
95
+ prenorm=True,
96
+ residual_in_fp32=self.residual_in_fp32,
97
+ eps=self.norm2.eps,
98
+ is_rms_norm=isinstance(self.norm2, RMSNorm),
99
+ )
100
+ hidden_states = self.mlp(hidden_states)
101
+
102
+ return hidden_states, residual
103
+
104
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
105
+ return self.mixer.allocate_inference_cache(
106
+ batch_size, max_seqlen, dtype=dtype, **kwargs
107
+ )
build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba2.py ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import math
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from einops import rearrange, repeat
9
+
10
+ from .._causal_conv1d import causal_conv1d_fn, causal_conv1d_update
11
+ from .._causal_conv1d.causal_conv1d_varlen import causal_conv1d_varlen_states
12
+
13
+ try:
14
+ from ..ops.triton.selective_state_update import selective_state_update
15
+ except ImportError:
16
+ selective_state_update = None
17
+
18
+ from huggingface_hub import PyTorchModelHubMixin
19
+
20
+ from ..distributed.distributed_utils import all_reduce, reduce_scatter
21
+ from ..distributed.tensor_parallel import ColumnParallelLinear, RowParallelLinear
22
+ from ..ops.triton.layernorm_gated import RMSNorm as RMSNormGated
23
+ from ..ops.triton.ssd_combined import (
24
+ mamba_chunk_scan_combined,
25
+ mamba_split_conv1d_scan_combined,
26
+ )
27
+
28
+
29
+ class Mamba2(nn.Module, PyTorchModelHubMixin):
30
+ def __init__(
31
+ self,
32
+ d_model,
33
+ d_state=128,
34
+ d_conv=4,
35
+ conv_init=None,
36
+ expand=2,
37
+ headdim=64,
38
+ d_ssm=None, # If not None, we only apply SSM on this many dimensions, the rest uses gated MLP
39
+ ngroups=1,
40
+ A_init_range=(1, 16),
41
+ D_has_hdim=False,
42
+ rmsnorm=True,
43
+ norm_before_gate=False,
44
+ dt_min=0.001,
45
+ dt_max=0.1,
46
+ dt_init_floor=1e-4,
47
+ dt_limit=(0.0, float("inf")),
48
+ bias=False,
49
+ conv_bias=True,
50
+ # Fused kernel and sharding options
51
+ chunk_size=256,
52
+ use_mem_eff_path=True,
53
+ layer_idx=None, # Absorb kwarg for general module
54
+ process_group=None,
55
+ sequence_parallel=True,
56
+ device=None,
57
+ dtype=None,
58
+ ):
59
+ factory_kwargs = {"device": device, "dtype": dtype}
60
+ super().__init__()
61
+ self.d_model = d_model
62
+ self.d_state = d_state
63
+ self.d_conv = d_conv
64
+ self.conv_init = conv_init
65
+ self.expand = expand
66
+ self.process_group = process_group
67
+ self.sequence_parallel = sequence_parallel
68
+ self.world_size = 1 if process_group is None else process_group.size()
69
+ self.local_rank = 0 if process_group is None else process_group.rank()
70
+ self.d_inner = (self.expand * self.d_model) // self.world_size
71
+ assert self.d_inner * self.world_size == self.expand * self.d_model
72
+ self.headdim = headdim
73
+ self.d_ssm = self.d_inner if d_ssm is None else d_ssm // self.world_size
74
+ assert ngroups % self.world_size == 0
75
+ self.ngroups = ngroups // self.world_size
76
+ assert self.d_ssm % self.headdim == 0
77
+ self.nheads = self.d_ssm // self.headdim
78
+ self.D_has_hdim = D_has_hdim
79
+ self.rmsnorm = rmsnorm
80
+ self.norm_before_gate = norm_before_gate
81
+ self.dt_limit = dt_limit
82
+ self.activation = "silu"
83
+ self.chunk_size = chunk_size
84
+ self.use_mem_eff_path = use_mem_eff_path
85
+ self.layer_idx = layer_idx
86
+
87
+ # Order: [z, x, B, C, dt]
88
+ d_in_proj = 2 * self.d_inner + 2 * self.ngroups * self.d_state + self.nheads
89
+ if self.process_group is None:
90
+ self.in_proj = nn.Linear(
91
+ self.d_model, d_in_proj, bias=bias, **factory_kwargs
92
+ )
93
+ else:
94
+ self.in_proj = ColumnParallelLinear(
95
+ self.d_model,
96
+ d_in_proj * self.world_size,
97
+ bias=bias,
98
+ process_group=self.process_group,
99
+ sequence_parallel=self.sequence_parallel,
100
+ **factory_kwargs,
101
+ )
102
+
103
+ conv_dim = self.d_ssm + 2 * self.ngroups * self.d_state
104
+ self.conv1d = nn.Conv1d(
105
+ in_channels=conv_dim,
106
+ out_channels=conv_dim,
107
+ bias=conv_bias,
108
+ kernel_size=d_conv,
109
+ groups=conv_dim,
110
+ padding=d_conv - 1,
111
+ **factory_kwargs,
112
+ )
113
+ if self.conv_init is not None:
114
+ nn.init.uniform_(self.conv1d.weight, -self.conv_init, self.conv_init)
115
+
116
+ self.act = nn.SiLU()
117
+
118
+ # Initialize log dt bias
119
+ dt = torch.exp(
120
+ torch.rand(self.nheads, **factory_kwargs)
121
+ * (math.log(dt_max) - math.log(dt_min))
122
+ + math.log(dt_min)
123
+ )
124
+ dt = torch.clamp(dt, min=dt_init_floor)
125
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
126
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
127
+ self.dt_bias = nn.Parameter(inv_dt)
128
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
129
+ # name.endswith("bias") in param_grouping.py
130
+ self.dt_bias._no_weight_decay = True
131
+
132
+ assert A_init_range[0] > 0 and A_init_range[1] >= A_init_range[0]
133
+ A = torch.empty(self.nheads, dtype=torch.float32, device=device).uniform_(
134
+ *A_init_range
135
+ )
136
+ A_log = torch.log(A).to(dtype=dtype)
137
+ self.A_log = nn.Parameter(A_log)
138
+ self.A_log._no_weight_decay = True
139
+
140
+ # D "skip" parameter
141
+ self.D = nn.Parameter(
142
+ torch.ones(self.d_ssm if self.D_has_hdim else self.nheads, device=device)
143
+ )
144
+ self.D._no_weight_decay = True
145
+
146
+ if self.rmsnorm:
147
+ assert RMSNormGated is not None
148
+ self.norm = RMSNormGated(
149
+ self.d_ssm,
150
+ eps=1e-5,
151
+ norm_before_gate=self.norm_before_gate,
152
+ group_size=self.d_ssm // ngroups,
153
+ **factory_kwargs,
154
+ )
155
+
156
+ if self.process_group is None:
157
+ self.out_proj = nn.Linear(
158
+ self.d_inner, self.d_model, bias=bias, **factory_kwargs
159
+ )
160
+ else:
161
+ self.out_proj = RowParallelLinear(
162
+ self.d_inner * self.world_size,
163
+ self.d_model,
164
+ bias=bias,
165
+ process_group=self.process_group,
166
+ sequence_parallel=self.sequence_parallel,
167
+ **factory_kwargs,
168
+ )
169
+
170
+ def forward(
171
+ self, u, seqlen=None, seq_idx=None, cu_seqlens=None, inference_params=None
172
+ ):
173
+ """
174
+ u: (batch, seqlen, hidden_dim) if seqlen=None.
175
+ If seqlen is not None, u is (batch * seqlen, hidden_dim). This is so that when we
176
+ split u during sequence parallel, we split the batch * seqlen dimension
177
+ (in case batch is small).
178
+ Returns: same shape as u
179
+ """
180
+ seqlen_og = seqlen
181
+ if seqlen is None:
182
+ batch, seqlen, dim = u.shape
183
+ else:
184
+ batch_seqlen, dim = u.shape
185
+ batch = batch_seqlen // seqlen
186
+
187
+ conv_state, ssm_state = None, None
188
+ if inference_params is not None:
189
+ inference_batch = (
190
+ cu_seqlens.shape[0] - 1 if cu_seqlens is not None else batch
191
+ )
192
+ conv_state, ssm_state = self._get_states_from_cache(
193
+ inference_params, inference_batch
194
+ )
195
+ if inference_params.seqlen_offset > 0:
196
+ # The states are updated inplace
197
+ out, _, _ = self.step(u, conv_state, ssm_state)
198
+ return out
199
+
200
+ zxbcdt = self.in_proj(u) # (B, L, d_in_proj) or (B * L, d_in_proj)
201
+ if seqlen_og is not None:
202
+ zxbcdt = rearrange(zxbcdt, "(b l) d -> b l d", l=seqlen)
203
+ # If the model is loaded in fp16, without the .float() here, A might be -inf
204
+ A = -torch.exp(self.A_log.float()) # (nheads) or (d_inner, d_state)
205
+ dt_limit_kwargs = (
206
+ {} if self.dt_limit == (0.0, float("inf")) else dict(dt_limit=self.dt_limit)
207
+ )
208
+ if self.use_mem_eff_path and inference_params is None:
209
+ out = mamba_split_conv1d_scan_combined(
210
+ zxbcdt,
211
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
212
+ self.conv1d.bias,
213
+ self.dt_bias,
214
+ A,
215
+ D=(
216
+ rearrange(self.D, "(h p) -> h p", p=self.headdim)
217
+ if self.D_has_hdim
218
+ else self.D
219
+ ),
220
+ chunk_size=self.chunk_size,
221
+ seq_idx=seq_idx,
222
+ activation=self.activation,
223
+ rmsnorm_weight=self.norm.weight if self.rmsnorm else None,
224
+ rmsnorm_eps=self.norm.eps if self.rmsnorm else 1e-6,
225
+ outproj_weight=self.out_proj.weight,
226
+ outproj_bias=self.out_proj.bias,
227
+ headdim=None if self.D_has_hdim else self.headdim,
228
+ ngroups=self.ngroups,
229
+ norm_before_gate=self.norm_before_gate,
230
+ **dt_limit_kwargs,
231
+ )
232
+ if seqlen_og is not None:
233
+ out = rearrange(out, "b l d -> (b l) d")
234
+ if self.process_group is not None:
235
+ reduce_fn = reduce_scatter if self.sequence_parallel else all_reduce
236
+ out = reduce_fn(out, self.process_group)
237
+ else:
238
+ d_mlp = (
239
+ zxbcdt.shape[-1]
240
+ - 2 * self.d_ssm
241
+ - 2 * self.ngroups * self.d_state
242
+ - self.nheads
243
+ ) // 2
244
+ z0, x0, z, xBC, dt = torch.split(
245
+ zxbcdt,
246
+ [
247
+ d_mlp,
248
+ d_mlp,
249
+ self.d_ssm,
250
+ self.d_ssm + 2 * self.ngroups * self.d_state,
251
+ self.nheads,
252
+ ],
253
+ dim=-1,
254
+ )
255
+ if conv_state is not None:
256
+ if cu_seqlens is None:
257
+ # If we just take xBC[:, :, -self.d_conv :], it will error if seqlen < self.d_conv
258
+ # Instead F.pad will pad with zeros if seqlen < self.d_conv, and truncate otherwise.
259
+ xBC_t = rearrange(xBC, "b l d -> b d l")
260
+ conv_state.copy_(
261
+ F.pad(xBC_t, (self.d_conv - xBC_t.shape[-1], 0))
262
+ ) # Update state (B D W)
263
+ else:
264
+ assert batch == 1, (
265
+ "varlen inference only supports batch dimension 1"
266
+ )
267
+ conv_varlen_states = causal_conv1d_varlen_states(
268
+ xBC.squeeze(0), cu_seqlens, state_len=conv_state.shape[-1]
269
+ )
270
+ conv_state.copy_(conv_varlen_states)
271
+ if self.activation not in ["silu", "swish"]:
272
+ assert seq_idx is None, (
273
+ "varlen conv1d requires the causal_conv1d package"
274
+ )
275
+ xBC = self.act(
276
+ self.conv1d(xBC.transpose(1, 2)).transpose(1, 2)[
277
+ :, : -(self.d_conv - 1)
278
+ ]
279
+ ) # (B, L, self.d_ssm + 2 * ngroups * d_state)
280
+ else:
281
+ xBC = causal_conv1d_fn(
282
+ xBC.transpose(1, 2),
283
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
284
+ bias=self.conv1d.bias,
285
+ activation=self.activation,
286
+ seq_idx=seq_idx,
287
+ ).transpose(1, 2)
288
+ x, B, C = torch.split(
289
+ xBC,
290
+ [self.d_ssm, self.ngroups * self.d_state, self.ngroups * self.d_state],
291
+ dim=-1,
292
+ )
293
+ y = mamba_chunk_scan_combined(
294
+ rearrange(x, "b l (h p) -> b l h p", p=self.headdim),
295
+ dt,
296
+ A,
297
+ rearrange(B, "b l (g n) -> b l g n", g=self.ngroups),
298
+ rearrange(C, "b l (g n) -> b l g n", g=self.ngroups),
299
+ chunk_size=self.chunk_size,
300
+ D=(
301
+ rearrange(self.D, "(h p) -> h p", p=self.headdim)
302
+ if self.D_has_hdim
303
+ else self.D
304
+ ),
305
+ z=(
306
+ rearrange(z, "b l (h p) -> b l h p", p=self.headdim)
307
+ if not self.rmsnorm
308
+ else None
309
+ ),
310
+ dt_bias=self.dt_bias,
311
+ dt_softplus=True,
312
+ seq_idx=seq_idx,
313
+ cu_seqlens=cu_seqlens,
314
+ **dt_limit_kwargs,
315
+ return_final_states=ssm_state is not None,
316
+ return_varlen_states=cu_seqlens is not None
317
+ and inference_params is not None,
318
+ )
319
+ if ssm_state is not None:
320
+ y, last_state, *rest = y
321
+ if cu_seqlens is None:
322
+ ssm_state.copy_(last_state)
323
+ else:
324
+ varlen_states = rest[0]
325
+ ssm_state.copy_(varlen_states)
326
+ y = rearrange(y, "b l h p -> b l (h p)")
327
+ if self.rmsnorm:
328
+ y = self.norm(y, z)
329
+ if d_mlp > 0:
330
+ y = torch.cat([F.silu(z0) * x0, y], dim=-1)
331
+ if seqlen_og is not None:
332
+ y = rearrange(y, "b l d -> (b l) d")
333
+ out = self.out_proj(y)
334
+ return out
335
+
336
+ def step(self, hidden_states, conv_state, ssm_state):
337
+ dtype = hidden_states.dtype
338
+ assert hidden_states.shape[1] == 1, (
339
+ "Only support decoding with 1 token at a time for now"
340
+ )
341
+ zxbcdt = self.in_proj(hidden_states.squeeze(1)) # (B 2D)
342
+ d_mlp = (
343
+ zxbcdt.shape[-1]
344
+ - 2 * self.d_ssm
345
+ - 2 * self.ngroups * self.d_state
346
+ - self.nheads
347
+ ) // 2
348
+ z0, x0, z, xBC, dt = torch.split(
349
+ zxbcdt,
350
+ [
351
+ d_mlp,
352
+ d_mlp,
353
+ self.d_ssm,
354
+ self.d_ssm + 2 * self.ngroups * self.d_state,
355
+ self.nheads,
356
+ ],
357
+ dim=-1,
358
+ )
359
+
360
+ # Conv step
361
+ xBC = causal_conv1d_update(
362
+ xBC,
363
+ conv_state,
364
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
365
+ self.conv1d.bias,
366
+ self.activation,
367
+ )
368
+
369
+ x, B, C = torch.split(
370
+ xBC,
371
+ [self.d_ssm, self.ngroups * self.d_state, self.ngroups * self.d_state],
372
+ dim=-1,
373
+ )
374
+ A = -torch.exp(self.A_log.float()) # (nheads,)
375
+
376
+ # SSM step
377
+ if selective_state_update is None:
378
+ assert self.ngroups == 1, (
379
+ "Only support ngroups=1 for this inference code path"
380
+ )
381
+ dt = F.softplus(dt + self.dt_bias.to(dtype=dt.dtype)) # (batch, nheads)
382
+ dA = torch.exp(dt * A) # (batch, nheads)
383
+ x = rearrange(x, "b (h p) -> b h p", p=self.headdim)
384
+ dBx = torch.einsum("bh,bn,bhp->bhpn", dt, B, x)
385
+ ssm_state.copy_(ssm_state * rearrange(dA, "b h -> b h 1 1") + dBx)
386
+ y = torch.einsum("bhpn,bn->bhp", ssm_state.to(dtype), C)
387
+ y = y + rearrange(self.D.to(dtype), "h -> h 1") * x
388
+ y = rearrange(y, "b h p -> b (h p)")
389
+ if not self.rmsnorm:
390
+ y = y * self.act(z) # (B D)
391
+ else:
392
+ A = repeat(A, "h -> h p n", p=self.headdim, n=self.d_state).to(
393
+ dtype=torch.float32
394
+ )
395
+ dt = repeat(dt, "b h -> b h p", p=self.headdim)
396
+ dt_bias = repeat(self.dt_bias, "h -> h p", p=self.headdim)
397
+ D = repeat(self.D, "h -> h p", p=self.headdim)
398
+ B = rearrange(B, "b (g n) -> b g n", g=self.ngroups)
399
+ C = rearrange(C, "b (g n) -> b g n", g=self.ngroups)
400
+ x_reshaped = rearrange(x, "b (h p) -> b h p", p=self.headdim)
401
+ if not self.rmsnorm:
402
+ z = rearrange(z, "b (h p) -> b h p", p=self.headdim)
403
+ y = selective_state_update(
404
+ ssm_state,
405
+ x_reshaped,
406
+ dt,
407
+ A,
408
+ B,
409
+ C,
410
+ D,
411
+ z=z if not self.rmsnorm else None,
412
+ dt_bias=dt_bias,
413
+ dt_softplus=True,
414
+ )
415
+ y = rearrange(y, "b h p -> b (h p)")
416
+ if self.rmsnorm:
417
+ y = self.norm(y, z)
418
+ if d_mlp > 0:
419
+ y = torch.cat([F.silu(z0) * x0, y], dim=-1)
420
+ out = self.out_proj(y)
421
+ return out.unsqueeze(1), conv_state, ssm_state
422
+
423
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
424
+ device = self.out_proj.weight.device
425
+ conv_dtype = self.conv1d.weight.dtype if dtype is None else dtype
426
+ conv_state = torch.zeros(
427
+ batch_size,
428
+ self.d_conv,
429
+ self.conv1d.weight.shape[0],
430
+ device=device,
431
+ dtype=conv_dtype,
432
+ ).transpose(1, 2)
433
+ ssm_dtype = self.in_proj.weight.dtype if dtype is None else dtype
434
+ ssm_state = torch.zeros(
435
+ batch_size,
436
+ self.nheads,
437
+ self.headdim,
438
+ self.d_state,
439
+ device=device,
440
+ dtype=ssm_dtype,
441
+ )
442
+ return conv_state, ssm_state
443
+
444
+ def _get_states_from_cache(
445
+ self, inference_params, batch_size, initialize_states=False
446
+ ):
447
+ assert self.layer_idx is not None
448
+ if self.layer_idx not in inference_params.key_value_memory_dict:
449
+ batch_shape = (batch_size,)
450
+ conv_state = torch.zeros(
451
+ batch_size,
452
+ self.d_conv,
453
+ self.conv1d.weight.shape[0],
454
+ device=self.conv1d.weight.device,
455
+ dtype=self.conv1d.weight.dtype,
456
+ ).transpose(1, 2)
457
+ ssm_state = torch.zeros(
458
+ batch_size,
459
+ self.nheads,
460
+ self.headdim,
461
+ self.d_state,
462
+ device=self.in_proj.weight.device,
463
+ dtype=self.in_proj.weight.dtype,
464
+ )
465
+ inference_params.key_value_memory_dict[self.layer_idx] = (
466
+ conv_state,
467
+ ssm_state,
468
+ )
469
+ else:
470
+ conv_state, ssm_state = inference_params.key_value_memory_dict[
471
+ self.layer_idx
472
+ ]
473
+ # TODO: What if batch size changes between generation, and we reuse the same states?
474
+ if initialize_states:
475
+ conv_state.zero_()
476
+ ssm_state.zero_()
477
+ return conv_state, ssm_state
build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba2_simple.py ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import math
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from einops import rearrange, repeat
9
+
10
+ from .._causal_conv1d import causal_conv1d_fn
11
+
12
+ try:
13
+ from ..ops.triton.layernorm_gated import LayerNorm
14
+ from ..ops.triton.layernorm_gated import RMSNorm as RMSNormGated
15
+ except ImportError:
16
+ RMSNormGated, LayerNorm = None, None
17
+
18
+ from ..ops.triton.ssd_combined import (
19
+ mamba_chunk_scan_combined,
20
+ mamba_split_conv1d_scan_combined,
21
+ )
22
+
23
+
24
+ class Mamba2Simple(nn.Module):
25
+ def __init__(
26
+ self,
27
+ d_model,
28
+ d_state=64,
29
+ d_conv=4,
30
+ conv_init=None,
31
+ expand=2,
32
+ headdim=128,
33
+ ngroups=1,
34
+ A_init_range=(1, 16),
35
+ dt_min=0.001,
36
+ dt_max=0.1,
37
+ dt_init_floor=1e-4,
38
+ dt_limit=(0.0, float("inf")),
39
+ learnable_init_states=False,
40
+ activation="swish",
41
+ bias=False,
42
+ conv_bias=True,
43
+ # Fused kernel and sharding options
44
+ chunk_size=256,
45
+ use_mem_eff_path=True,
46
+ layer_idx=None, # Absorb kwarg for general module
47
+ device=None,
48
+ dtype=None,
49
+ ):
50
+ factory_kwargs = {"device": device, "dtype": dtype}
51
+ super().__init__()
52
+ self.d_model = d_model
53
+ self.d_state = d_state
54
+ self.d_conv = d_conv
55
+ self.conv_init = conv_init
56
+ self.expand = expand
57
+ self.d_inner = self.expand * self.d_model
58
+ self.headdim = headdim
59
+ self.ngroups = ngroups
60
+ assert self.d_inner % self.headdim == 0
61
+ self.nheads = self.d_inner // self.headdim
62
+ self.dt_limit = dt_limit
63
+ self.learnable_init_states = learnable_init_states
64
+ self.activation = activation
65
+ self.chunk_size = chunk_size
66
+ self.use_mem_eff_path = use_mem_eff_path
67
+ self.layer_idx = layer_idx
68
+
69
+ # Order: [z, x, B, C, dt]
70
+ d_in_proj = 2 * self.d_inner + 2 * self.ngroups * self.d_state + self.nheads
71
+ self.in_proj = nn.Linear(self.d_model, d_in_proj, bias=bias, **factory_kwargs)
72
+
73
+ conv_dim = self.d_inner + 2 * self.ngroups * self.d_state
74
+ self.conv1d = nn.Conv1d(
75
+ in_channels=conv_dim,
76
+ out_channels=conv_dim,
77
+ bias=conv_bias,
78
+ kernel_size=d_conv,
79
+ groups=conv_dim,
80
+ padding=d_conv - 1,
81
+ **factory_kwargs,
82
+ )
83
+ if self.conv_init is not None:
84
+ nn.init.uniform_(self.conv1d.weight, -self.conv_init, self.conv_init)
85
+ # self.conv1d.weight._no_weight_decay = True
86
+
87
+ if self.learnable_init_states:
88
+ self.init_states = nn.Parameter(
89
+ torch.zeros(self.nheads, self.headdim, self.d_state, **factory_kwargs)
90
+ )
91
+ self.init_states._no_weight_decay = True
92
+
93
+ self.act = nn.SiLU()
94
+
95
+ # Initialize log dt bias
96
+ dt = torch.exp(
97
+ torch.rand(self.nheads, **factory_kwargs)
98
+ * (math.log(dt_max) - math.log(dt_min))
99
+ + math.log(dt_min)
100
+ )
101
+ dt = torch.clamp(dt, min=dt_init_floor)
102
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
103
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
104
+ self.dt_bias = nn.Parameter(inv_dt)
105
+ # Just to be explicit. Without this we already don't put wd on dt_bias because of the check
106
+ # name.endswith("bias") in param_grouping.py
107
+ self.dt_bias._no_weight_decay = True
108
+
109
+ # A parameter
110
+ assert A_init_range[0] > 0 and A_init_range[1] >= A_init_range[0]
111
+ A = torch.empty(self.nheads, dtype=torch.float32, device=device).uniform_(
112
+ *A_init_range
113
+ )
114
+ A_log = torch.log(A).to(dtype=dtype)
115
+ self.A_log = nn.Parameter(A_log)
116
+ # self.register_buffer("A_log", torch.zeros(self.nheads, dtype=torch.float32, device=device), persistent=True)
117
+ self.A_log._no_weight_decay = True
118
+
119
+ # D "skip" parameter
120
+ self.D = nn.Parameter(torch.ones(self.nheads, device=device))
121
+ self.D._no_weight_decay = True
122
+
123
+ # Extra normalization layer right before output projection
124
+ assert RMSNormGated is not None
125
+ self.norm = RMSNormGated(
126
+ self.d_inner, eps=1e-5, norm_before_gate=False, **factory_kwargs
127
+ )
128
+
129
+ self.out_proj = nn.Linear(
130
+ self.d_inner, self.d_model, bias=bias, **factory_kwargs
131
+ )
132
+
133
+ def forward(self, u, seq_idx=None):
134
+ """
135
+ u: (B, L, D)
136
+ Returns: same shape as u
137
+ """
138
+ batch, seqlen, dim = u.shape
139
+
140
+ zxbcdt = self.in_proj(u) # (B, L, d_in_proj)
141
+ A = -torch.exp(self.A_log) # (nheads) or (d_inner, d_state)
142
+ initial_states = (
143
+ repeat(self.init_states, "... -> b ...", b=batch)
144
+ if self.learnable_init_states
145
+ else None
146
+ )
147
+ dt_limit_kwargs = (
148
+ {} if self.dt_limit == (0.0, float("inf")) else dict(dt_limit=self.dt_limit)
149
+ )
150
+
151
+ if self.use_mem_eff_path:
152
+ # Fully fused path
153
+ out = mamba_split_conv1d_scan_combined(
154
+ zxbcdt,
155
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
156
+ self.conv1d.bias,
157
+ self.dt_bias,
158
+ A,
159
+ D=self.D,
160
+ chunk_size=self.chunk_size,
161
+ seq_idx=seq_idx,
162
+ activation=self.activation,
163
+ rmsnorm_weight=self.norm.weight,
164
+ rmsnorm_eps=self.norm.eps,
165
+ outproj_weight=self.out_proj.weight,
166
+ outproj_bias=self.out_proj.bias,
167
+ headdim=self.headdim,
168
+ ngroups=self.ngroups,
169
+ norm_before_gate=False,
170
+ initial_states=initial_states,
171
+ **dt_limit_kwargs,
172
+ )
173
+ else:
174
+ z, xBC, dt = torch.split(
175
+ zxbcdt,
176
+ [
177
+ self.d_inner,
178
+ self.d_inner + 2 * self.ngroups * self.d_state,
179
+ self.nheads,
180
+ ],
181
+ dim=-1,
182
+ )
183
+ dt = F.softplus(dt + self.dt_bias) # (B, L, nheads)
184
+
185
+ # 1D Convolution
186
+ if self.activation not in ["silu", "swish"]:
187
+ xBC = self.act(
188
+ self.conv1d(xBC.transpose(1, 2)).transpose(1, 2)
189
+ ) # (B, L, self.d_inner + 2 * ngroups * d_state)
190
+ xBC = xBC[:, :seqlen, :]
191
+ else:
192
+ xBC = causal_conv1d_fn(
193
+ x=xBC.transpose(1, 2),
194
+ weight=rearrange(self.conv1d.weight, "d 1 w -> d w"),
195
+ bias=self.conv1d.bias,
196
+ activation=self.activation,
197
+ ).transpose(1, 2)
198
+
199
+ # Split into 3 main branches: X, B, C
200
+ # These correspond to V, K, Q respectively in the SSM/attention duality
201
+ x, B, C = torch.split(
202
+ xBC,
203
+ [
204
+ self.d_inner,
205
+ self.ngroups * self.d_state,
206
+ self.ngroups * self.d_state,
207
+ ],
208
+ dim=-1,
209
+ )
210
+ y = mamba_chunk_scan_combined(
211
+ rearrange(x, "b l (h p) -> b l h p", p=self.headdim),
212
+ dt,
213
+ A,
214
+ rearrange(B, "b l (g n) -> b l g n", g=self.ngroups),
215
+ rearrange(C, "b l (g n) -> b l g n", g=self.ngroups),
216
+ chunk_size=self.chunk_size,
217
+ D=self.D,
218
+ z=None,
219
+ seq_idx=seq_idx,
220
+ initial_states=initial_states,
221
+ **dt_limit_kwargs,
222
+ )
223
+ y = rearrange(y, "b l h p -> b l (h p)")
224
+
225
+ # Multiply "gate" branch and apply extra normalization layer
226
+ y = self.norm(y, z)
227
+ out = self.out_proj(y)
228
+ return out
build/torch214-cxx11-xpu20261-x86_64-linux/modules/mamba_simple.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Tri Dao, Albert Gu.
2
+
3
+ import math
4
+ from typing import Optional
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+ from einops import rearrange, repeat
10
+ from torch import Tensor
11
+
12
+ from .._causal_conv1d import causal_conv1d_fn, causal_conv1d_update
13
+ from ..ops.selective_scan_interface import mamba_inner_fn, selective_scan_fn
14
+
15
+ try:
16
+ from ..ops.triton.selective_state_update import selective_state_update
17
+ except ImportError:
18
+ selective_state_update = None
19
+
20
+ try:
21
+ from ..ops.triton.layer_norm import RMSNorm, layer_norm_fn, rms_norm_fn
22
+ except ImportError:
23
+ RMSNorm, layer_norm_fn, rms_norm_fn = None, None, None
24
+
25
+
26
+ class Mamba(nn.Module):
27
+ def __init__(
28
+ self,
29
+ d_model,
30
+ d_state=16,
31
+ d_conv=4,
32
+ expand=2,
33
+ dt_rank="auto",
34
+ dt_min=0.001,
35
+ dt_max=0.1,
36
+ dt_init="random",
37
+ dt_scale=1.0,
38
+ dt_init_floor=1e-4,
39
+ conv_bias=True,
40
+ bias=False,
41
+ use_fast_path=True, # Fused kernel options
42
+ layer_idx=None,
43
+ device=None,
44
+ dtype=None,
45
+ ):
46
+ factory_kwargs = {"device": device, "dtype": dtype}
47
+ super().__init__()
48
+ self.d_model = d_model
49
+ self.d_state = d_state
50
+ self.d_conv = d_conv
51
+ self.expand = expand
52
+ self.d_inner = int(self.expand * self.d_model)
53
+ self.dt_rank = math.ceil(self.d_model / 16) if dt_rank == "auto" else dt_rank
54
+ self.use_fast_path = use_fast_path
55
+ self.layer_idx = layer_idx
56
+
57
+ self.in_proj = nn.Linear(
58
+ self.d_model, self.d_inner * 2, bias=bias, **factory_kwargs
59
+ )
60
+
61
+ self.conv1d = nn.Conv1d(
62
+ in_channels=self.d_inner,
63
+ out_channels=self.d_inner,
64
+ bias=conv_bias,
65
+ kernel_size=d_conv,
66
+ groups=self.d_inner,
67
+ padding=d_conv - 1,
68
+ **factory_kwargs,
69
+ )
70
+
71
+ self.activation = "silu"
72
+ self.act = nn.SiLU()
73
+
74
+ self.x_proj = nn.Linear(
75
+ self.d_inner, self.dt_rank + self.d_state * 2, bias=False, **factory_kwargs
76
+ )
77
+ self.dt_proj = nn.Linear(
78
+ self.dt_rank, self.d_inner, bias=True, **factory_kwargs
79
+ )
80
+
81
+ # Initialize special dt projection to preserve variance at initialization
82
+ dt_init_std = self.dt_rank**-0.5 * dt_scale
83
+ if dt_init == "constant":
84
+ nn.init.constant_(self.dt_proj.weight, dt_init_std)
85
+ elif dt_init == "random":
86
+ nn.init.uniform_(self.dt_proj.weight, -dt_init_std, dt_init_std)
87
+ else:
88
+ raise NotImplementedError
89
+
90
+ # Initialize dt bias so that F.softplus(dt_bias) is between dt_min and dt_max
91
+ dt = torch.exp(
92
+ torch.rand(self.d_inner, **factory_kwargs)
93
+ * (math.log(dt_max) - math.log(dt_min))
94
+ + math.log(dt_min)
95
+ ).clamp(min=dt_init_floor)
96
+ # Inverse of softplus: https://github.com/pytorch/pytorch/issues/72759
97
+ inv_dt = dt + torch.log(-torch.expm1(-dt))
98
+ with torch.no_grad():
99
+ self.dt_proj.bias.copy_(inv_dt)
100
+ # Our initialization would set all Linear.bias to zero, need to mark this one as _no_reinit
101
+ self.dt_proj.bias._no_reinit = True
102
+
103
+ # S4D real initialization
104
+ A = repeat(
105
+ torch.arange(1, self.d_state + 1, dtype=torch.float32, device=device),
106
+ "n -> d n",
107
+ d=self.d_inner,
108
+ ).contiguous()
109
+ A_log = torch.log(A) # Keep A_log in fp32
110
+ self.A_log = nn.Parameter(A_log)
111
+ self.A_log._no_weight_decay = True
112
+
113
+ # D "skip" parameter
114
+ self.D = nn.Parameter(torch.ones(self.d_inner, device=device)) # Keep in fp32
115
+ self.D._no_weight_decay = True
116
+
117
+ self.out_proj = nn.Linear(
118
+ self.d_inner, self.d_model, bias=bias, **factory_kwargs
119
+ )
120
+
121
+ def forward(self, hidden_states, inference_params=None):
122
+ """
123
+ hidden_states: (B, L, D)
124
+ Returns: same shape as hidden_states
125
+ """
126
+ batch, seqlen, dim = hidden_states.shape
127
+
128
+ conv_state, ssm_state = None, None
129
+ if inference_params is not None:
130
+ conv_state, ssm_state = self._get_states_from_cache(inference_params, batch)
131
+ if inference_params.seqlen_offset > 0:
132
+ # The states are updated inplace
133
+ out, _, _ = self.step(hidden_states, conv_state, ssm_state)
134
+ return out
135
+
136
+ # We do matmul and transpose BLH -> HBL at the same time
137
+ xz = rearrange(
138
+ self.in_proj.weight @ rearrange(hidden_states, "b l d -> d (b l)"),
139
+ "d (b l) -> b d l",
140
+ l=seqlen,
141
+ )
142
+ if self.in_proj.bias is not None:
143
+ xz = xz + rearrange(self.in_proj.bias.to(dtype=xz.dtype), "d -> d 1")
144
+
145
+ A = -torch.exp(self.A_log.float()) # (d_inner, d_state)
146
+ # In the backward pass we write dx and dz next to each other to avoid torch.cat
147
+ if (
148
+ self.use_fast_path and inference_params is None
149
+ ): # Doesn't support outputting the states
150
+ out = mamba_inner_fn(
151
+ xz,
152
+ self.conv1d.weight,
153
+ self.conv1d.bias,
154
+ self.x_proj.weight,
155
+ self.dt_proj.weight,
156
+ self.out_proj.weight,
157
+ self.out_proj.bias,
158
+ A,
159
+ None, # input-dependent B
160
+ None, # input-dependent C
161
+ self.D.float(),
162
+ delta_bias=self.dt_proj.bias.float(),
163
+ delta_softplus=True,
164
+ )
165
+ else:
166
+ x, z = xz.chunk(2, dim=1)
167
+ # Compute short convolution
168
+ if conv_state is not None:
169
+ # If we just take x[:, :, -self.d_conv :], it will error if seqlen < self.d_conv
170
+ # Instead F.pad will pad with zeros if seqlen < self.d_conv, and truncate otherwise.
171
+ conv_state.copy_(
172
+ F.pad(x, (self.d_conv - x.shape[-1], 0))
173
+ ) # Update state (B D W)
174
+ if self.activation not in ["silu", "swish"]:
175
+ x = self.act(self.conv1d(x)[..., :seqlen])
176
+ else:
177
+ x = causal_conv1d_fn(
178
+ x=x,
179
+ weight=rearrange(self.conv1d.weight, "d 1 w -> d w"),
180
+ bias=self.conv1d.bias,
181
+ activation=self.activation,
182
+ )
183
+
184
+ # We're careful here about the layout, to avoid extra transposes.
185
+ # We want dt to have d as the slowest moving dimension
186
+ # and L as the fastest moving dimension, since those are what the ssm_scan kernel expects.
187
+ x_dbl = self.x_proj(rearrange(x, "b d l -> (b l) d")) # (bl d)
188
+ dt, B, C = torch.split(
189
+ x_dbl, [self.dt_rank, self.d_state, self.d_state], dim=-1
190
+ )
191
+ dt = self.dt_proj.weight @ dt.t()
192
+ dt = rearrange(dt, "d (b l) -> b d l", l=seqlen)
193
+ B = rearrange(B, "(b l) dstate -> b dstate l", l=seqlen).contiguous()
194
+ C = rearrange(C, "(b l) dstate -> b dstate l", l=seqlen).contiguous()
195
+ assert self.activation in ["silu", "swish"]
196
+ y = selective_scan_fn(
197
+ x,
198
+ dt,
199
+ A,
200
+ B,
201
+ C,
202
+ self.D.float(),
203
+ z=z,
204
+ delta_bias=self.dt_proj.bias.float(),
205
+ delta_softplus=True,
206
+ return_last_state=ssm_state is not None,
207
+ )
208
+ if ssm_state is not None:
209
+ y, last_state = y
210
+ ssm_state.copy_(last_state)
211
+ y = rearrange(y, "b d l -> b l d")
212
+ out = self.out_proj(y)
213
+ return out
214
+
215
+ def step(self, hidden_states, conv_state, ssm_state):
216
+ dtype = hidden_states.dtype
217
+ assert hidden_states.shape[1] == 1, (
218
+ "Only support decoding with 1 token at a time for now"
219
+ )
220
+ xz = self.in_proj(hidden_states.squeeze(1)) # (B 2D)
221
+ x, z = xz.chunk(2, dim=-1) # (B D)
222
+
223
+ # Conv step
224
+ x = causal_conv1d_update(
225
+ x,
226
+ conv_state,
227
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
228
+ self.conv1d.bias,
229
+ self.activation,
230
+ )
231
+
232
+ x_db = self.x_proj(x) # (B dt_rank+2*d_state)
233
+ dt, B, C = torch.split(x_db, [self.dt_rank, self.d_state, self.d_state], dim=-1)
234
+ # Don't add dt_bias here
235
+ dt = F.linear(dt, self.dt_proj.weight) # (B d_inner)
236
+ A = -torch.exp(self.A_log.float()) # (d_inner, d_state)
237
+
238
+ # SSM step
239
+ if selective_state_update is None:
240
+ # Discretize A and B
241
+ dt = F.softplus(dt + self.dt_proj.bias.to(dtype=dt.dtype))
242
+ dA = torch.exp(torch.einsum("bd,dn->bdn", dt, A))
243
+ dB = torch.einsum("bd,bn->bdn", dt, B)
244
+ ssm_state.copy_(ssm_state * dA + rearrange(x, "b d -> b d 1") * dB)
245
+ y = torch.einsum("bdn,bn->bd", ssm_state.to(dtype), C)
246
+ y = y + self.D.to(dtype) * x
247
+ y = y * self.act(z) # (B D)
248
+ else:
249
+ y = selective_state_update(
250
+ ssm_state,
251
+ x,
252
+ dt,
253
+ A,
254
+ B,
255
+ C,
256
+ self.D,
257
+ z=z,
258
+ dt_bias=self.dt_proj.bias,
259
+ dt_softplus=True,
260
+ )
261
+
262
+ out = self.out_proj(y)
263
+ return out.unsqueeze(1), conv_state, ssm_state
264
+
265
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs):
266
+ device = self.out_proj.weight.device
267
+ conv_dtype = self.conv1d.weight.dtype if dtype is None else dtype
268
+ conv_state = torch.zeros(
269
+ batch_size,
270
+ self.d_model * self.expand,
271
+ self.d_conv,
272
+ device=device,
273
+ dtype=conv_dtype,
274
+ )
275
+ ssm_dtype = self.dt_proj.weight.dtype if dtype is None else dtype
276
+ # ssm_dtype = torch.float32
277
+ ssm_state = torch.zeros(
278
+ batch_size,
279
+ self.d_model * self.expand,
280
+ self.d_state,
281
+ device=device,
282
+ dtype=ssm_dtype,
283
+ )
284
+ return conv_state, ssm_state
285
+
286
+ def _get_states_from_cache(
287
+ self, inference_params, batch_size, initialize_states=False
288
+ ):
289
+ assert self.layer_idx is not None
290
+ if self.layer_idx not in inference_params.key_value_memory_dict:
291
+ batch_shape = (batch_size,)
292
+ conv_state = torch.zeros(
293
+ batch_size,
294
+ self.d_model * self.expand,
295
+ self.d_conv,
296
+ device=self.conv1d.weight.device,
297
+ dtype=self.conv1d.weight.dtype,
298
+ )
299
+ ssm_state = torch.zeros(
300
+ batch_size,
301
+ self.d_model * self.expand,
302
+ self.d_state,
303
+ device=self.dt_proj.weight.device,
304
+ dtype=self.dt_proj.weight.dtype,
305
+ # dtype=torch.float32,
306
+ )
307
+ inference_params.key_value_memory_dict[self.layer_idx] = (
308
+ conv_state,
309
+ ssm_state,
310
+ )
311
+ else:
312
+ conv_state, ssm_state = inference_params.key_value_memory_dict[
313
+ self.layer_idx
314
+ ]
315
+ # TODO: What if batch size changes between generation, and we reuse the same states?
316
+ if initialize_states:
317
+ conv_state.zero_()
318
+ ssm_state.zero_()
319
+ return conv_state, ssm_state
build/torch214-cxx11-xpu20261-x86_64-linux/modules/mha.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import math
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from einops import rearrange
9
+
10
+ try:
11
+ from flash_attn import flash_attn_with_kvcache
12
+ except ImportError:
13
+ flash_attn_with_kvcache = None
14
+
15
+ try:
16
+ from flash_attn.layers.rotary import RotaryEmbedding
17
+ except ImportError:
18
+ RotaryEmbedding = None
19
+
20
+ from .._causal_conv1d import causal_conv1d_fn, causal_conv1d_update
21
+
22
+
23
+ def _update_kv_cache(kv, inference_params, layer_idx):
24
+ """kv: (batch_size, seqlen, 2, nheads, head_dim) or (batch_size, 1, 2, nheads, head_dim)"""
25
+ # Pre-allocate memory for key-values for inference.
26
+ num_heads, head_dim = kv.shape[-2:]
27
+ assert layer_idx in inference_params.key_value_memory_dict
28
+ kv_cache, _ = inference_params.key_value_memory_dict[layer_idx]
29
+ # Adjust key and value for inference
30
+ batch_start = inference_params.batch_size_offset
31
+ batch_end = batch_start + kv.shape[0]
32
+ sequence_start = inference_params.seqlen_offset
33
+ sequence_end = sequence_start + kv.shape[1]
34
+ assert batch_end <= kv_cache.shape[0]
35
+ assert sequence_end <= kv_cache.shape[1]
36
+ assert kv_cache is not None
37
+ kv_cache[batch_start:batch_end, sequence_start:sequence_end, ...] = kv
38
+ return kv_cache[batch_start:batch_end, :sequence_end, ...]
39
+
40
+
41
+ class MHA(nn.Module):
42
+ """Multi-head self-attention and cross-attention"""
43
+
44
+ def __init__(
45
+ self,
46
+ embed_dim,
47
+ num_heads,
48
+ num_heads_kv=None,
49
+ head_dim=None, # If None, use embed_dim // num_heads
50
+ mlp_dim=0,
51
+ qkv_proj_bias=True,
52
+ out_proj_bias=True,
53
+ softmax_scale=None,
54
+ causal=False,
55
+ layer_idx=None,
56
+ d_conv=0,
57
+ rotary_emb_dim=0,
58
+ rotary_emb_base=10000.0,
59
+ rotary_emb_interleaved=False,
60
+ device=None,
61
+ dtype=None,
62
+ ) -> None:
63
+ """
64
+ num_heads_kv: can be used to toggle MQA / GQA. If None, use num_heads.
65
+ return_residual: whether to return the input x along with the output. This is for
66
+ performance reason: for post-norm architecture, returning the input allows us
67
+ to fuse the backward of nn.Linear with the residual connection.
68
+ """
69
+ factory_kwargs = {"device": device, "dtype": dtype}
70
+ super().__init__()
71
+ self.embed_dim = embed_dim
72
+ self.layer_idx = layer_idx
73
+ self.d_conv = d_conv
74
+ self.rotary_emb_dim = rotary_emb_dim
75
+ self.softmax_scale = softmax_scale
76
+ self.causal = causal
77
+
78
+ self.num_heads = num_heads
79
+ self.num_heads_kv = num_heads_kv if num_heads_kv is not None else num_heads
80
+ assert self.num_heads % self.num_heads_kv == 0, (
81
+ "num_heads must be divisible by num_heads_kv"
82
+ )
83
+ if head_dim is None:
84
+ assert self.embed_dim % num_heads == 0, (
85
+ "embed_dim must be divisible by num_heads"
86
+ )
87
+ self.head_dim = (
88
+ head_dim if head_dim is not None else self.embed_dim // num_heads
89
+ )
90
+ self.mlp_dim = math.ceil(mlp_dim / 256) * 256
91
+ qkv_dim = self.head_dim * (self.num_heads + 2 * self.num_heads_kv)
92
+ out_dim = self.head_dim * self.num_heads
93
+
94
+ if self.rotary_emb_dim > 0:
95
+ assert RotaryEmbedding is not None, (
96
+ "rotary requires flash_attn to be installed"
97
+ )
98
+ self.rotary_emb = RotaryEmbedding(
99
+ self.rotary_emb_dim,
100
+ base=rotary_emb_base,
101
+ interleaved=rotary_emb_interleaved,
102
+ device=device,
103
+ )
104
+
105
+ self.in_proj = nn.Linear(
106
+ embed_dim, qkv_dim + self.mlp_dim, bias=qkv_proj_bias, **factory_kwargs
107
+ )
108
+ if self.d_conv > 0:
109
+ self.conv1d = nn.Conv1d(
110
+ qkv_dim,
111
+ qkv_dim,
112
+ kernel_size=self.d_conv,
113
+ padding=self.d_conv - 1,
114
+ groups=qkv_dim,
115
+ **factory_kwargs,
116
+ )
117
+ self.out_proj = nn.Linear(
118
+ out_dim + self.mlp_dim // 2, embed_dim, bias=out_proj_bias, **factory_kwargs
119
+ )
120
+
121
+ def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None):
122
+ dtype = self.out_proj.weight.dtype if dtype is None else dtype
123
+ device = self.out_proj.weight.device
124
+ if self.d_conv > 0:
125
+ conv_state = torch.zeros(
126
+ batch_size,
127
+ self.conv1d.weight.shape[0],
128
+ self.d_conv,
129
+ device=device,
130
+ dtype=dtype,
131
+ )
132
+ else:
133
+ conv_state = None
134
+ kv_cache = torch.empty(
135
+ batch_size,
136
+ max_seqlen,
137
+ 2,
138
+ self.num_heads_kv,
139
+ self.head_dim,
140
+ dtype=dtype,
141
+ device=device,
142
+ )
143
+ return kv_cache, conv_state
144
+
145
+ def _update_kv_cache(self, kv, inference_params):
146
+ """kv: (batch_size, seqlen, 2, nheads, head_dim) or (batch_size, 1, 2, nheads, head_dim)"""
147
+ assert self.layer_idx is not None, (
148
+ "Generation requires layer_idx in the constructor"
149
+ )
150
+ return _update_kv_cache(kv, inference_params, self.layer_idx)
151
+
152
+ def _apply_rotary_update_kvcache_attention(self, q, kv, inference_params):
153
+ """
154
+ Fast path that combine 3 steps: apply rotary to Q and K, update kv cache, and apply attention.
155
+ q: (batch_size, seqlen_q, nheads, head_dim)
156
+ kv: (batch_size, seqlen_k, 2, nheads_kv, head_dim)
157
+ """
158
+ assert inference_params is not None and inference_params.seqlen_offset > 0
159
+ if self.rotary_emb_dim > 0:
160
+ self.rotary_emb._update_cos_sin_cache(
161
+ inference_params.max_seqlen, device=q.device, dtype=q.dtype
162
+ )
163
+ rotary_cos, rotary_sin = (
164
+ self.rotary_emb._cos_cached,
165
+ self.rotary_emb._sin_cached,
166
+ )
167
+ else:
168
+ rotary_cos, rotary_sin = None, None
169
+ batch = q.shape[0]
170
+ kv_cache, _ = inference_params.key_value_memory_dict[self.layer_idx]
171
+ kv_cache = kv_cache[:batch]
172
+ cache_seqlens = (
173
+ inference_params.lengths_per_sample[:batch]
174
+ if inference_params.lengths_per_sample is not None
175
+ else inference_params.seqlen_offset
176
+ )
177
+ assert flash_attn_with_kvcache is not None, "flash_attn must be installed"
178
+ context = flash_attn_with_kvcache(
179
+ q,
180
+ kv_cache[:, :, 0],
181
+ kv_cache[:, :, 1],
182
+ kv[:, :, 0],
183
+ kv[:, :, 1],
184
+ rotary_cos=rotary_cos,
185
+ rotary_sin=rotary_sin,
186
+ cache_seqlens=cache_seqlens,
187
+ softmax_scale=self.softmax_scale,
188
+ causal=self.causal,
189
+ rotary_interleaved=self.rotary_emb.interleaved
190
+ if self.rotary_emb_dim > 0
191
+ else False,
192
+ )
193
+ return context
194
+
195
+ def _update_kvcache_attention(self, q, kv, inference_params):
196
+ """Write kv to inference_params, then do attention"""
197
+ if inference_params.seqlen_offset == 0 or flash_attn_with_kvcache is None:
198
+ # TODO: this only uses seqlen_offset and not lengths_per_sample.
199
+ kv = self._update_kv_cache(kv, inference_params)
200
+ k, v = kv.unbind(dim=-3)
201
+ k = torch.repeat_interleave(
202
+ k, dim=2, repeats=self.num_heads // self.num_heads_kv
203
+ )
204
+ v = torch.repeat_interleave(
205
+ v, dim=2, repeats=self.num_heads // self.num_heads_kv
206
+ )
207
+ return F.scaled_dot_product_attention(
208
+ q.transpose(1, 2),
209
+ k.transpose(1, 2),
210
+ v.transpose(1, 2),
211
+ is_causal=self.causal,
212
+ scale=self.softmax_scale,
213
+ ).transpose(1, 2)
214
+ else:
215
+ batch = q.shape[0]
216
+ kv_cache, _ = inference_params.key_value_memory_dict[self.layer_idx]
217
+ kv_cache = kv_cache[:batch]
218
+ cache_seqlens = (
219
+ inference_params.lengths_per_sample[:batch]
220
+ if inference_params.lengths_per_sample is not None
221
+ else inference_params.seqlen_offset
222
+ )
223
+ return flash_attn_with_kvcache(
224
+ q,
225
+ kv_cache[:, :, 0],
226
+ kv_cache[:, :, 1],
227
+ kv[:, :, 0],
228
+ kv[:, :, 1],
229
+ cache_seqlens=cache_seqlens,
230
+ softmax_scale=self.softmax_scale,
231
+ causal=self.causal,
232
+ )
233
+
234
+ def forward(self, x, inference_params=None):
235
+ """
236
+ Arguments:
237
+ x: (batch, seqlen, hidden_dim) (where hidden_dim = num heads * head dim) if
238
+ cu_seqlens is None and max_seqlen is None, else (total, hidden_dim) where total
239
+ is the is the sum of the sequence lengths in the batch.
240
+ inference_params: for generation. Adapted from Megatron-LM (and Apex)
241
+ https://github.com/NVIDIA/apex/blob/3ff1a10f72ec07067c4e44759442329804ac5162/apex/transformer/testing/standalone_transformer_lm.py#L470
242
+ """
243
+ if (
244
+ inference_params is not None
245
+ and self.layer_idx not in inference_params.key_value_memory_dict
246
+ ):
247
+ inference_params.key_value_memory_dict[self.layer_idx] = (
248
+ self.allocate_inference_cache(
249
+ x.shape[0], inference_params.max_seqlen, dtype=x.dtype
250
+ )
251
+ )
252
+ seqlen_offset = (
253
+ 0
254
+ if inference_params is None
255
+ else (
256
+ inference_params.lengths_per_sample
257
+ if inference_params.lengths_per_sample is not None
258
+ else inference_params.seqlen_offset
259
+ )
260
+ )
261
+ rotary_max_seqlen = (
262
+ inference_params.max_seqlen if inference_params is not None else None
263
+ )
264
+ qkv = self.in_proj(x)
265
+ if self.mlp_dim > 0:
266
+ qkv, x_mlp = qkv.split([qkv.shape[-1] - self.mlp_dim, self.mlp_dim], dim=-1)
267
+ x_mlp_up, x_mlp_gate = x_mlp.chunk(2, dim=-1)
268
+ x_mlp = x_mlp_up * F.silu(x_mlp_gate)
269
+ if self.d_conv > 0:
270
+ # The inference code for conv1d is pretty messy, should clean it up
271
+ if inference_params is None or inference_params.seqlen_offset == 0:
272
+ qkv = causal_conv1d_fn(
273
+ qkv.transpose(1, 2),
274
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
275
+ self.conv1d.bias,
276
+ ).transpose(1, 2)
277
+ if inference_params is not None:
278
+ _, conv_state = inference_params.key_value_memory_dict[
279
+ self.layer_idx
280
+ ]
281
+ # If we just take qkv[:, :, -self.d_conv :], it will error if seqlen < self.d_conv
282
+ # Instead F.pad will pad with zeros if seqlen < self.d_conv, and truncate otherwise.
283
+ qkv_t = rearrange(qkv, "b l d -> b d l")
284
+ conv_state.copy_(
285
+ F.pad(qkv_t, (self.d_conv - qkv_t.shape[-1], 0))
286
+ ) # Update state (B D W)
287
+ else:
288
+ _, conv_state = inference_params.key_value_memory_dict[self.layer_idx]
289
+ assert qkv.shape[1] == 1, (
290
+ "Only support decoding with 1 token at a time for now"
291
+ )
292
+ qkv = qkv.squeeze(1)
293
+ # Conv step
294
+ qkv = causal_conv1d_update(
295
+ qkv,
296
+ conv_state,
297
+ rearrange(self.conv1d.weight, "d 1 w -> d w"),
298
+ self.conv1d.bias,
299
+ )
300
+ qkv = qkv.unsqueeze(1)
301
+ q, kv = qkv.split(
302
+ [self.num_heads * self.head_dim, self.num_heads_kv * 2 * self.head_dim],
303
+ dim=-1,
304
+ )
305
+ q = rearrange(q, "... (h d) -> ... h d", d=self.head_dim)
306
+ kv = rearrange(kv, "... (two hkv d) -> ... two hkv d", two=2, d=self.head_dim)
307
+ if (
308
+ inference_params is None
309
+ or inference_params.seqlen_offset == 0
310
+ or (self.rotary_emb_dim == 0 or self.rotary_emb_dim % 16 != 0)
311
+ ):
312
+ if self.rotary_emb_dim > 0:
313
+ q, kv = self.rotary_emb(
314
+ q, kv, seqlen_offset=seqlen_offset, max_seqlen=rotary_max_seqlen
315
+ )
316
+ if inference_params is None:
317
+ k, v = kv.unbind(dim=-3)
318
+ k = torch.repeat_interleave(
319
+ k, dim=2, repeats=self.num_heads // self.num_heads_kv
320
+ )
321
+ v = torch.repeat_interleave(
322
+ v, dim=2, repeats=self.num_heads // self.num_heads_kv
323
+ )
324
+ context = F.scaled_dot_product_attention(
325
+ q.transpose(1, 2),
326
+ k.transpose(1, 2),
327
+ v.transpose(1, 2),
328
+ is_causal=self.causal,
329
+ scale=self.softmax_scale,
330
+ ).transpose(1, 2)
331
+ else:
332
+ context = self._update_kvcache_attention(q, kv, inference_params)
333
+ else:
334
+ context = self._apply_rotary_update_kvcache_attention(
335
+ q, kv, inference_params
336
+ )
337
+ context = rearrange(context, "... h d -> ... (h d)")
338
+ if self.mlp_dim > 0:
339
+ context = torch.cat([context, x_mlp], dim=-1)
340
+ out = self.out_proj(context)
341
+ return out
build/torch214-cxx11-xpu20261-x86_64-linux/modules/mlp.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+ from torch import nn
3
+ from torch.nn import functional as F
4
+
5
+
6
+ class GatedMLP(nn.Module):
7
+ def __init__(
8
+ self,
9
+ in_features,
10
+ hidden_features=None,
11
+ out_features=None,
12
+ activation=F.silu,
13
+ bias=False,
14
+ multiple_of=128,
15
+ device=None,
16
+ dtype=None,
17
+ ):
18
+ factory_kwargs = {"device": device, "dtype": dtype}
19
+ super().__init__()
20
+ out_features = out_features if out_features is not None else in_features
21
+ hidden_features = (
22
+ hidden_features if hidden_features is not None else int(8 * in_features / 3)
23
+ )
24
+ hidden_features = (hidden_features + multiple_of - 1) // multiple_of * multiple_of
25
+ self.fc1 = nn.Linear(in_features, 2 * hidden_features, bias=bias, **factory_kwargs)
26
+ self.activation = activation
27
+ self.fc2 = nn.Linear(hidden_features, out_features, bias=bias, **factory_kwargs)
28
+
29
+ def forward(self, x):
30
+ y = self.fc1(x)
31
+ y, gate = y.chunk(2, dim=-1)
32
+ y = y * self.activation(gate)
33
+ y = self.fc2(y)
34
+ return y
build/torch214-cxx11-xpu20261-x86_64-linux/modules/ssd_minimal.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Albert Gu and Tri Dao.
2
+ """Minimal implementation of SSD.
3
+
4
+ This is the same as Listing 1 from the paper.
5
+ """
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from einops import rearrange, repeat
10
+
11
+ from ..ops.triton.ssd_combined import mamba_chunk_scan_combined
12
+
13
+
14
+ def segsum_unstable(x):
15
+ """Naive segment sum calculation."""
16
+ T = x.size(-1)
17
+ x_cumsum = torch.cumsum(x, dim=-1)
18
+ x_segsum = x_cumsum[..., :, None] - x_cumsum[..., None, :]
19
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=0)
20
+ x_segsum = x_segsum.masked_fill(~mask, -torch.inf)
21
+ return x_segsum
22
+
23
+
24
+ def segsum(x):
25
+ """More stable segment sum calculation."""
26
+ T = x.size(-1)
27
+ x = repeat(x, "... d -> ... d e", e=T)
28
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=-1)
29
+ x = x.masked_fill(~mask, 0)
30
+ x_segsum = torch.cumsum(x, dim=-2)
31
+ mask = torch.tril(torch.ones(T, T, device=x.device, dtype=bool), diagonal=0)
32
+ x_segsum = x_segsum.masked_fill(~mask, -torch.inf)
33
+ return x_segsum
34
+
35
+
36
+ def ssd_minimal_discrete(X, A, B, C, block_len, initial_states=None):
37
+ """
38
+ Arguments:
39
+ X: (batch, length, n_heads, d_head)
40
+ A: (batch, length, n_heads)
41
+ B: (batch, length, n_heads, d_state)
42
+ C: (batch, length, n_heads, d_state)
43
+ Return:
44
+ Y: (batch, length, n_heads, d_head)
45
+ """
46
+ assert X.dtype == A.dtype == B.dtype == C.dtype
47
+ assert X.shape[1] % block_len == 0
48
+
49
+ # Rearrange into blocks/chunks
50
+ X, A, B, C = [
51
+ rearrange(x, "b (c l) ... -> b c l ...", l=block_len) for x in (X, A, B, C)
52
+ ]
53
+
54
+ A = rearrange(A, "b c l h -> b h c l")
55
+ A_cumsum = torch.cumsum(A, dim=-1)
56
+
57
+ # 1. Compute the output for each intra-chunk (diagonal blocks)
58
+ L = torch.exp(segsum(A))
59
+ Y_diag = torch.einsum("bclhn,bcshn,bhcls,bcshp->bclhp", C, B, L, X)
60
+
61
+ # 2. Compute the state for each intra-chunk
62
+ # (right term of low-rank factorization of off-diagonal blocks; B terms)
63
+ decay_states = torch.exp((A_cumsum[:, :, :, -1:] - A_cumsum))
64
+ states = torch.einsum("bclhn,bhcl,bclhp->bchpn", B, decay_states, X)
65
+
66
+ # 3. Compute the inter-chunk SSM recurrence; produces correct SSM states at chunk boundaries
67
+ # (middle term of factorization of off-diag blocks; A terms)
68
+ if initial_states is None:
69
+ initial_states = torch.zeros_like(states[:, :1])
70
+ states = torch.cat([initial_states, states], dim=1)
71
+ decay_chunk = torch.exp(segsum(F.pad(A_cumsum[:, :, :, -1], (1, 0))))
72
+ new_states = torch.einsum("bhzc,bchpn->bzhpn", decay_chunk, states)
73
+ states, final_state = new_states[:, :-1], new_states[:, -1]
74
+
75
+ # 4. Compute state -> output conversion per chunk
76
+ # (left term of low-rank factorization of off-diagonal blocks; C terms)
77
+ state_decay_out = torch.exp(A_cumsum)
78
+ Y_off = torch.einsum("bclhn,bchpn,bhcl->bclhp", C, states, state_decay_out)
79
+
80
+ # Add output of intra-chunk and inter-chunk terms (diagonal and off-diagonal blocks)
81
+ Y = rearrange(Y_diag + Y_off, "b c l h p -> b (c l) h p")
82
+ return Y, final_state
83
+
84
+
85
+ # Simple test
86
+ def test_correctness():
87
+ torch.manual_seed(42)
88
+
89
+ ## Dimensions
90
+ # Denoted (B, T, Q, D, P) in the paper
91
+ batch, seqlen, chunk_size, dim, headdim = 1, 2048, 64, 2048, 64
92
+ nheads = dim // headdim # (H) in the paper
93
+ ngroups = 1 # (G) in the paper
94
+ dstate = 64 # (N) in the paper
95
+ dtype = torch.float32
96
+ device = "cuda"
97
+
98
+ x = torch.randn(batch, seqlen, nheads, headdim, dtype=dtype, device=device)
99
+ dt = F.softplus(
100
+ torch.randn(batch, seqlen, nheads, dtype=torch.float32, device=device) - 4
101
+ ).requires_grad_()
102
+ A = (
103
+ -torch.exp(torch.rand(nheads, dtype=torch.float32, device=device))
104
+ ).requires_grad_()
105
+ B = torch.randn(batch, seqlen, ngroups, dstate, dtype=dtype, device=device)
106
+ C = torch.randn(batch, seqlen, ngroups, dstate, dtype=dtype, device=device)
107
+ D = torch.randn(nheads, dtype=dtype, device=device)
108
+
109
+ # Comparing fused version and minimal version
110
+ y = mamba_chunk_scan_combined(x, dt, A, B, C, chunk_size, D=None)
111
+ y_min, _ = ssd_minimal_discrete(x * dt.unsqueeze(-1), A * dt, B, C, chunk_size)
build/torch214-cxx11-xpu20261-x86_64-linux/ops/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .triton import selective_state_update, mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
build/torch214-cxx11-xpu20261-x86_64-linux/ops/selective_scan_interface.py ADDED
@@ -0,0 +1,708 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Tri Dao, Albert Gu.
2
+
3
+ import torch
4
+ import torch.nn.functional as F
5
+ from einops import rearrange, repeat
6
+
7
+ from .._causal_conv1d import causal_conv1d_cuda, causal_conv1d_fn
8
+ from .._ops import add_op_namespace_prefix, ops
9
+ from ..utils.torch import custom_bwd, custom_fwd
10
+ from .triton.layer_norm import _layer_norm_fwd
11
+
12
+
13
+ # The CUDA scan processes the sequence in chunks of this size and saves one state per chunk, see
14
+ # `n_chunks` in `selective-scan/selective_scan.cpp`.
15
+ _SELECTIVE_SCAN_CHUNK_SIZE = 2048
16
+
17
+
18
+ def _selective_scan_fwd_fake(u, delta, A, B, C, D, z, delta_bias, delta_softplus):
19
+ batch, dim, seqlen = u.shape
20
+ n_chunks = (seqlen + _SELECTIVE_SCAN_CHUNK_SIZE - 1) // _SELECTIVE_SCAN_CHUNK_SIZE
21
+ x = u.new_empty((batch, dim, n_chunks, A.shape[1] * 2), dtype=A.dtype)
22
+ return [torch.empty_like(delta), x] + ([torch.empty_like(z)] if z is not None else [])
23
+
24
+
25
+ # XPU builds provide causal convolution, but do not define the native scan ops.
26
+ if hasattr(ops, "selective_scan_fwd"):
27
+ torch.library.register_fake(add_op_namespace_prefix("selective_scan_fwd"))(_selective_scan_fwd_fake)
28
+
29
+
30
+ # `selective_scan_bwd` returns undefined tensors for absent optionals as well as its `dz_`
31
+ # argument, so it cannot be given a fake implementation directly. This wrapper gives it a
32
+ # fixed signature that torch.compile can trace. Absent outputs are returned as empty tensors.
33
+ @torch.library.custom_op(add_op_namespace_prefix("_selective_scan_bwd"), mutates_args=("dz",), device_types="cuda")
34
+ def _selective_scan_bwd(
35
+ u: torch.Tensor,
36
+ delta: torch.Tensor,
37
+ A: torch.Tensor,
38
+ B: torch.Tensor,
39
+ C: torch.Tensor,
40
+ D: torch.Tensor | None,
41
+ z: torch.Tensor | None,
42
+ delta_bias: torch.Tensor | None,
43
+ dout: torch.Tensor,
44
+ x: torch.Tensor | None,
45
+ out: torch.Tensor | None,
46
+ dz: torch.Tensor | None,
47
+ delta_softplus: bool,
48
+ recompute_out_z: bool,
49
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
50
+ du, ddelta, dA, dB, dC, dD, ddelta_bias, *rest = ops.selective_scan_bwd(
51
+ u, delta, A, B, C, D, z, delta_bias, dout, x, out, dz, delta_softplus, recompute_out_z
52
+ )
53
+ empty = lambda: du.new_empty(0) # one per output, outputs may not alias each other
54
+ # A passed-in `dz` is written in place, so only return the one the kernel allocated.
55
+ dz_out = rest[0] if z is not None and dz is None else empty()
56
+ out_z = rest[-1] if z is not None and recompute_out_z else empty()
57
+ dD = dD if D is not None else empty()
58
+ ddelta_bias = ddelta_bias if delta_bias is not None else empty()
59
+ return du, ddelta, dA, dB, dC, dD, ddelta_bias, dz_out, out_z
60
+
61
+
62
+ @torch.library.register_fake(add_op_namespace_prefix("_selective_scan_bwd"))
63
+ def _selective_scan_bwd_fake(u, delta, A, B, C, D, z, delta_bias, dout, x, out, dz, delta_softplus, recompute_out_z):
64
+ like = lambda t, keep=True: torch.empty_like(t) if keep and t is not None else u.new_empty(0)
65
+ return (
66
+ *(like(t) for t in (u, delta, A, B, C, D, delta_bias)),
67
+ like(z, dz is None),
68
+ like(out, z is not None and recompute_out_z),
69
+ )
70
+
71
+
72
+ class SelectiveScanFn(torch.autograd.Function):
73
+ @staticmethod
74
+ def forward(
75
+ ctx,
76
+ u,
77
+ delta,
78
+ A,
79
+ B,
80
+ C,
81
+ D=None,
82
+ z=None,
83
+ delta_bias=None,
84
+ delta_softplus=False,
85
+ return_last_state=False,
86
+ ):
87
+ if u.stride(-1) != 1:
88
+ u = u.contiguous()
89
+ if delta.stride(-1) != 1:
90
+ delta = delta.contiguous()
91
+ if D is not None:
92
+ D = D.contiguous()
93
+ if B.stride(-1) != 1:
94
+ B = B.contiguous()
95
+ if C.stride(-1) != 1:
96
+ C = C.contiguous()
97
+ if z is not None and z.stride(-1) != 1:
98
+ z = z.contiguous()
99
+ if B.dim() == 3:
100
+ B = rearrange(B, "b dstate l -> b 1 dstate l")
101
+ ctx.squeeze_B = True
102
+ if C.dim() == 3:
103
+ C = rearrange(C, "b dstate l -> b 1 dstate l")
104
+ ctx.squeeze_C = True
105
+ out, x, *rest = ops.selective_scan_fwd(
106
+ u, delta, A, B, C, D, z, delta_bias, delta_softplus
107
+ )
108
+ ctx.delta_softplus = delta_softplus
109
+ ctx.has_z = z is not None
110
+ last_state = x[:, :, -1, 1::2] # (batch, dim, dstate)
111
+ if not ctx.has_z:
112
+ ctx.save_for_backward(u, delta, A, B, C, D, delta_bias, x)
113
+ return out if not return_last_state else (out, last_state)
114
+ else:
115
+ ctx.save_for_backward(u, delta, A, B, C, D, z, delta_bias, x, out)
116
+ out_z = rest[0]
117
+ return out_z if not return_last_state else (out_z, last_state)
118
+
119
+ @staticmethod
120
+ def backward(ctx, dout, *args):
121
+ if not ctx.has_z:
122
+ u, delta, A, B, C, D, delta_bias, x = ctx.saved_tensors
123
+ z = None
124
+ out = None
125
+ else:
126
+ u, delta, A, B, C, D, z, delta_bias, x, out = ctx.saved_tensors
127
+ if dout.stride(-1) != 1:
128
+ dout = dout.contiguous()
129
+ # The kernel supports passing in a pre-allocated dz (e.g., in case we want to fuse the
130
+ # backward of selective_scan_cuda with the backward of chunk).
131
+ # Here we just pass in None and dz will be allocated in the C++ code.
132
+ du, ddelta, dA, dB, dC, dD, ddelta_bias, *rest = _selective_scan_bwd(
133
+ u,
134
+ delta,
135
+ A,
136
+ B,
137
+ C,
138
+ D,
139
+ z,
140
+ delta_bias,
141
+ dout,
142
+ x,
143
+ out,
144
+ None,
145
+ ctx.delta_softplus,
146
+ False, # option to recompute out_z, not used here
147
+ )
148
+ dz = rest[0] if ctx.has_z else None
149
+ dB = dB.squeeze(1) if getattr(ctx, "squeeze_B", False) else dB
150
+ dC = dC.squeeze(1) if getattr(ctx, "squeeze_C", False) else dC
151
+ return (
152
+ du,
153
+ ddelta,
154
+ dA,
155
+ dB,
156
+ dC,
157
+ dD if D is not None else None,
158
+ dz,
159
+ ddelta_bias if delta_bias is not None else None,
160
+ None,
161
+ None,
162
+ )
163
+
164
+
165
+ def rms_norm_forward(
166
+ x,
167
+ weight,
168
+ bias,
169
+ eps=1e-6,
170
+ is_rms_norm=True,
171
+ ):
172
+ # x (b l) d
173
+ if x.stride(-1) != 1:
174
+ x = x.contiguous()
175
+ weight = weight.contiguous()
176
+ if bias is not None:
177
+ bias = bias.contiguous()
178
+ y = _layer_norm_fwd(
179
+ x, weight, bias, eps, None, residual_dtype=None, is_rms_norm=is_rms_norm
180
+ )[0]
181
+ # y (b l) d
182
+ return y
183
+
184
+
185
+ def selective_scan_fn(
186
+ u,
187
+ delta,
188
+ A,
189
+ B,
190
+ C,
191
+ D=None,
192
+ z=None,
193
+ delta_bias=None,
194
+ delta_softplus=False,
195
+ return_last_state=False,
196
+ ):
197
+ """if return_last_state is True, returns (out, last_state)
198
+ last_state has shape (batch, dim, dstate). Note that the gradient of the last state is
199
+ not considered in the backward pass.
200
+ """
201
+ return SelectiveScanFn.apply(
202
+ u, delta, A, B, C, D, z, delta_bias, delta_softplus, return_last_state
203
+ )
204
+
205
+
206
+ def selective_scan_ref(
207
+ u,
208
+ delta,
209
+ A,
210
+ B,
211
+ C,
212
+ D=None,
213
+ z=None,
214
+ delta_bias=None,
215
+ delta_softplus=False,
216
+ return_last_state=False,
217
+ ):
218
+ """
219
+ u: r(B D L)
220
+ delta: r(B D L)
221
+ A: c(D N) or r(D N)
222
+ B: c(D N) or r(B N L) or r(B N 2L) or r(B G N L) or (B G N L)
223
+ C: c(D N) or r(B N L) or r(B N 2L) or r(B G N L) or (B G N L)
224
+ D: r(D)
225
+ z: r(B D L)
226
+ delta_bias: r(D), fp32
227
+
228
+ out: r(B D L)
229
+ last_state (optional): r(B D dstate) or c(B D dstate)
230
+ """
231
+ dtype_in = u.dtype
232
+ u = u.float()
233
+ delta = delta.float()
234
+ if delta_bias is not None:
235
+ delta = delta + delta_bias[..., None].float()
236
+ if delta_softplus:
237
+ delta = F.softplus(delta)
238
+ batch, dim, dstate = u.shape[0], A.shape[0], A.shape[1]
239
+ is_variable_B = B.dim() >= 3
240
+ is_variable_C = C.dim() >= 3
241
+ if A.is_complex():
242
+ if is_variable_B:
243
+ B = torch.view_as_complex(
244
+ rearrange(B.float(), "... (L two) -> ... L two", two=2)
245
+ )
246
+ if is_variable_C:
247
+ C = torch.view_as_complex(
248
+ rearrange(C.float(), "... (L two) -> ... L two", two=2)
249
+ )
250
+ else:
251
+ B = B.float()
252
+ C = C.float()
253
+ x = A.new_zeros((batch, dim, dstate))
254
+ ys = []
255
+ deltaA = torch.exp(torch.einsum("bdl,dn->bdln", delta, A))
256
+ if not is_variable_B:
257
+ deltaB_u = torch.einsum("bdl,dn,bdl->bdln", delta, B, u)
258
+ else:
259
+ if B.dim() == 3:
260
+ deltaB_u = torch.einsum("bdl,bnl,bdl->bdln", delta, B, u)
261
+ else:
262
+ B = repeat(B, "B G N L -> B (G H) N L", H=dim // B.shape[1])
263
+ deltaB_u = torch.einsum("bdl,bdnl,bdl->bdln", delta, B, u)
264
+ if is_variable_C and C.dim() == 4:
265
+ C = repeat(C, "B G N L -> B (G H) N L", H=dim // C.shape[1])
266
+ last_state = None
267
+ for i in range(u.shape[2]):
268
+ x = deltaA[:, :, i] * x + deltaB_u[:, :, i]
269
+ if not is_variable_C:
270
+ y = torch.einsum("bdn,dn->bd", x, C)
271
+ else:
272
+ if C.dim() == 3:
273
+ y = torch.einsum("bdn,bn->bd", x, C[:, :, i])
274
+ else:
275
+ y = torch.einsum("bdn,bdn->bd", x, C[:, :, :, i])
276
+ if i == u.shape[2] - 1:
277
+ last_state = x
278
+ if y.is_complex():
279
+ y = y.real * 2
280
+ ys.append(y)
281
+ y = torch.stack(ys, dim=2) # (batch dim L)
282
+ out = y if D is None else y + u * rearrange(D, "d -> d 1")
283
+ if z is not None:
284
+ out = out * F.silu(z)
285
+ out = out.to(dtype=dtype_in)
286
+ return out if not return_last_state else (out, last_state)
287
+
288
+
289
+ class MambaInnerFn(torch.autograd.Function):
290
+ @staticmethod
291
+ @custom_fwd
292
+ def forward(
293
+ ctx,
294
+ xz,
295
+ conv1d_weight,
296
+ conv1d_bias,
297
+ x_proj_weight,
298
+ delta_proj_weight,
299
+ out_proj_weight,
300
+ out_proj_bias,
301
+ A,
302
+ B=None,
303
+ C=None,
304
+ D=None,
305
+ delta_bias=None,
306
+ B_proj_bias=None,
307
+ C_proj_bias=None,
308
+ delta_softplus=True,
309
+ checkpoint_lvl=1,
310
+ b_rms_weight=None,
311
+ c_rms_weight=None,
312
+ dt_rms_weight=None,
313
+ b_c_dt_rms_eps=1e-6,
314
+ ):
315
+ """
316
+ xz: (batch, dim, seqlen)
317
+ """
318
+ assert checkpoint_lvl in [0, 1]
319
+ L = xz.shape[-1]
320
+ delta_rank = delta_proj_weight.shape[1]
321
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
322
+ device_type = x_proj_weight.device.type
323
+ if torch.is_autocast_enabled(device_type):
324
+ dtype = torch.get_autocast_dtype(device_type)
325
+ x_proj_weight = x_proj_weight.to(dtype=dtype)
326
+ delta_proj_weight = delta_proj_weight.to(dtype=dtype)
327
+ out_proj_weight = out_proj_weight.to(dtype=dtype)
328
+ out_proj_bias = (
329
+ out_proj_bias.to(dtype=dtype)
330
+ if out_proj_bias is not None
331
+ else None
332
+ )
333
+ if xz.stride(-1) != 1:
334
+ xz = xz.contiguous()
335
+ conv1d_weight = rearrange(conv1d_weight, "d 1 w -> d w")
336
+ x, z = xz.chunk(2, dim=1)
337
+ conv1d_bias = conv1d_bias.contiguous() if conv1d_bias is not None else None
338
+ conv1d_out = causal_conv1d_cuda.causal_conv1d_fwd(
339
+ x, conv1d_weight, conv1d_bias, None, None, None, True
340
+ )
341
+ # We're being very careful here about the layout, to avoid extra transposes.
342
+ # We want delta to have d as the slowest moving dimension
343
+ # and L as the fastest moving dimension, since those are what the ssm_scan kernel expects.
344
+ x_dbl = F.linear(
345
+ rearrange(conv1d_out, "b d l -> (b l) d"), x_proj_weight
346
+ ) # (bl d)
347
+ delta = rearrange(
348
+ delta_proj_weight @ x_dbl[:, :delta_rank].t(), "d (b l) -> b d l", l=L
349
+ )
350
+ ctx.is_variable_B = B is None
351
+ ctx.is_variable_C = C is None
352
+ ctx.B_proj_bias_is_None = B_proj_bias is None
353
+ ctx.C_proj_bias_is_None = C_proj_bias is None
354
+ if B is None: # variable B
355
+ B = x_dbl[:, delta_rank : delta_rank + d_state] # (bl dstate)
356
+ if B_proj_bias is not None:
357
+ B = B + B_proj_bias.to(dtype=B.dtype)
358
+ if not A.is_complex():
359
+ # B = rearrange(B, "(b l) dstate -> b dstate l", l=L).contiguous()
360
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
361
+ else:
362
+ B = rearrange(
363
+ B, "(b l) (dstate two) -> b 1 dstate (l two)", l=L, two=2
364
+ ).contiguous()
365
+ else:
366
+ if B.stride(-1) != 1:
367
+ B = B.contiguous()
368
+ if C is None: # variable C
369
+ C = x_dbl[:, -d_state:] # (bl dstate)
370
+ if C_proj_bias is not None:
371
+ C = C + C_proj_bias.to(dtype=C.dtype)
372
+ if not A.is_complex():
373
+ # C = rearrange(C, "(b l) dstate -> b dstate l", l=L).contiguous()
374
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
375
+ else:
376
+ C = rearrange(
377
+ C, "(b l) (dstate two) -> b 1 dstate (l two)", l=L, two=2
378
+ ).contiguous()
379
+ else:
380
+ if C.stride(-1) != 1:
381
+ C = C.contiguous()
382
+ if D is not None:
383
+ D = D.contiguous()
384
+
385
+ if b_rms_weight is not None:
386
+ B = rearrange(B, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
387
+ B = rms_norm_forward(B, b_rms_weight, bias=None, eps=b_c_dt_rms_eps)
388
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
389
+ if c_rms_weight is not None:
390
+ C = rearrange(C, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
391
+ C = rms_norm_forward(C, c_rms_weight, bias=None, eps=b_c_dt_rms_eps)
392
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
393
+ if dt_rms_weight is not None:
394
+ delta = rearrange(delta, "b d l -> (b l) d", l=L).contiguous()
395
+ delta = rms_norm_forward(
396
+ delta, dt_rms_weight, bias=None, eps=b_c_dt_rms_eps
397
+ )
398
+ delta = rearrange(delta, "(b l) d -> b d l", l=L).contiguous()
399
+
400
+ out, scan_intermediates, out_z = ops.selective_scan_fwd(
401
+ conv1d_out, delta, A, B, C, D, z, delta_bias, delta_softplus
402
+ )
403
+ ctx.delta_softplus = delta_softplus
404
+ ctx.out_proj_bias_is_None = out_proj_bias is None
405
+ ctx.checkpoint_lvl = checkpoint_lvl
406
+ ctx.b_rms_weight = b_rms_weight
407
+ ctx.c_rms_weight = c_rms_weight
408
+ ctx.dt_rms_weight = dt_rms_weight
409
+ ctx.b_c_dt_rms_eps = b_c_dt_rms_eps
410
+ if (
411
+ checkpoint_lvl >= 1
412
+ ): # Will recompute conv1d_out and delta in the backward pass
413
+ conv1d_out, delta = None, None
414
+ ctx.save_for_backward(
415
+ xz,
416
+ conv1d_weight,
417
+ conv1d_bias,
418
+ x_dbl,
419
+ x_proj_weight,
420
+ delta_proj_weight,
421
+ out_proj_weight,
422
+ conv1d_out,
423
+ delta,
424
+ A,
425
+ B,
426
+ C,
427
+ D,
428
+ delta_bias,
429
+ scan_intermediates,
430
+ b_rms_weight,
431
+ c_rms_weight,
432
+ dt_rms_weight,
433
+ out,
434
+ )
435
+ return F.linear(
436
+ rearrange(out_z, "b d l -> b l d"), out_proj_weight, out_proj_bias
437
+ )
438
+
439
+ @staticmethod
440
+ @custom_bwd
441
+ def backward(ctx, dout):
442
+ # dout: (batch, seqlen, dim)
443
+ (
444
+ xz,
445
+ conv1d_weight,
446
+ conv1d_bias,
447
+ x_dbl,
448
+ x_proj_weight,
449
+ delta_proj_weight,
450
+ out_proj_weight,
451
+ conv1d_out,
452
+ delta,
453
+ A,
454
+ B,
455
+ C,
456
+ D,
457
+ delta_bias,
458
+ scan_intermediates,
459
+ b_rms_weight,
460
+ c_rms_weight,
461
+ dt_rms_weight,
462
+ out,
463
+ ) = ctx.saved_tensors
464
+ L = xz.shape[-1]
465
+ delta_rank = delta_proj_weight.shape[1]
466
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
467
+ x, z = xz.chunk(2, dim=1)
468
+ if dout.stride(-1) != 1:
469
+ dout = dout.contiguous()
470
+ if ctx.checkpoint_lvl == 1:
471
+ conv1d_out = causal_conv1d_cuda.causal_conv1d_fwd(
472
+ x, conv1d_weight, conv1d_bias, None, None, None, True
473
+ )
474
+ delta = rearrange(
475
+ delta_proj_weight @ x_dbl[:, :delta_rank].t(), "d (b l) -> b d l", l=L
476
+ )
477
+ if dt_rms_weight is not None:
478
+ delta = rearrange(delta, "b d l -> (b l) d", l=L).contiguous()
479
+ delta = rms_norm_forward(
480
+ delta, ctx.dt_rms_weight, None, ctx.b_c_dt_rms_eps
481
+ )
482
+ delta = rearrange(delta, "(b l) d -> b d l", l=L).contiguous()
483
+ if b_rms_weight is not None:
484
+ # Recompute & RMSNorm B
485
+ B = rearrange(B, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
486
+ B = rms_norm_forward(B, ctx.b_rms_weight, None, ctx.b_c_dt_rms_eps)
487
+ B = rearrange(B, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
488
+ if c_rms_weight is not None:
489
+ # Recompute & RMSNorm C
490
+ C = rearrange(C, "b 1 dstate l -> (b l) dstate", l=L).contiguous()
491
+ C = rms_norm_forward(C, ctx.c_rms_weight, None, ctx.b_c_dt_rms_eps)
492
+ C = rearrange(C, "(b l) dstate -> b 1 dstate l", l=L).contiguous()
493
+
494
+ # The kernel supports passing in a pre-allocated dz (e.g., in case we want to fuse the
495
+ # backward of selective_scan_cuda with the backward of chunk).
496
+ dxz = torch.empty_like(xz) # (batch, dim, seqlen)
497
+ dx, dz = dxz.chunk(2, dim=1)
498
+ dout = rearrange(dout, "b l e -> e (b l)")
499
+ # dout is (e, (b l)): sum over tokens only, see state-spaces/mamba#37
500
+ dout_proj_bias = dout.sum(dim=1) if not ctx.out_proj_bias_is_None else None
501
+ # Transformers can pass an FP32 output bias with BF16 projection weights.
502
+ dout = dout.to(dtype=out_proj_weight.dtype)
503
+ dout_y = rearrange(out_proj_weight.t() @ dout, "d (b l) -> b d l", l=L)
504
+ dconv1d_out, ddelta, dA, dB, dC, dD, ddelta_bias, _, out_z = (
505
+ _selective_scan_bwd(
506
+ conv1d_out,
507
+ delta,
508
+ A,
509
+ B,
510
+ C,
511
+ D,
512
+ z,
513
+ delta_bias,
514
+ dout_y,
515
+ scan_intermediates,
516
+ out,
517
+ dz,
518
+ ctx.delta_softplus,
519
+ True, # option to recompute out_z
520
+ )
521
+ )
522
+ dout_proj_weight = torch.einsum(
523
+ "eB,dB->ed", dout, rearrange(out_z, "b d l -> d (b l)")
524
+ )
525
+ dD = dD if D is not None else None
526
+ dx_dbl = torch.empty_like(x_dbl)
527
+ dB_proj_bias = None
528
+ if ctx.is_variable_B:
529
+ if not A.is_complex():
530
+ dB = rearrange(dB, "b 1 dstate l -> (b l) dstate").contiguous()
531
+ else:
532
+ dB = rearrange(
533
+ dB, "b 1 dstate (l two) -> (b l) (dstate two)", two=2
534
+ ).contiguous()
535
+ dB_proj_bias = dB.sum(0) if not ctx.B_proj_bias_is_None else None
536
+ dx_dbl[:, delta_rank : delta_rank + d_state] = dB # (bl d)
537
+ dB = None
538
+ dC_proj_bias = None
539
+ if ctx.is_variable_C:
540
+ if not A.is_complex():
541
+ dC = rearrange(dC, "b 1 dstate l -> (b l) dstate").contiguous()
542
+ else:
543
+ dC = rearrange(
544
+ dC, "b 1 dstate (l two) -> (b l) (dstate two)", two=2
545
+ ).contiguous()
546
+ dC_proj_bias = dC.sum(0) if not ctx.C_proj_bias_is_None else None
547
+ dx_dbl[:, -d_state:] = dC # (bl d)
548
+ dC = None
549
+ ddelta = rearrange(ddelta, "b d l -> d (b l)")
550
+ ddelta_proj_weight = torch.einsum("dB,Br->dr", ddelta, x_dbl[:, :delta_rank])
551
+ dx_dbl[:, :delta_rank] = torch.einsum("dB,dr->Br", ddelta, delta_proj_weight)
552
+ dconv1d_out = rearrange(dconv1d_out, "b d l -> d (b l)")
553
+ dx_proj_weight = torch.einsum(
554
+ "Br,Bd->rd", dx_dbl, rearrange(conv1d_out, "b d l -> (b l) d")
555
+ )
556
+ dconv1d_out = torch.addmm(
557
+ dconv1d_out, x_proj_weight.t(), dx_dbl.t(), out=dconv1d_out
558
+ )
559
+ dconv1d_out = rearrange(
560
+ dconv1d_out, "d (b l) -> b d l", b=x.shape[0], l=x.shape[-1]
561
+ )
562
+ # The kernel supports passing in a pre-allocated dx (e.g., in case we want to fuse the
563
+ # backward of conv1d with the backward of chunk).
564
+ dx, dconv1d_weight, dconv1d_bias, *_ = causal_conv1d_cuda.causal_conv1d_bwd(
565
+ x,
566
+ conv1d_weight,
567
+ conv1d_bias,
568
+ dconv1d_out,
569
+ None,
570
+ None,
571
+ None,
572
+ dx,
573
+ False,
574
+ True,
575
+ )
576
+ dconv1d_bias = dconv1d_bias if conv1d_bias is not None else None
577
+ dconv1d_weight = rearrange(dconv1d_weight, "d w -> d 1 w")
578
+ return (
579
+ dxz,
580
+ dconv1d_weight,
581
+ dconv1d_bias,
582
+ dx_proj_weight,
583
+ ddelta_proj_weight,
584
+ dout_proj_weight,
585
+ dout_proj_bias,
586
+ dA,
587
+ dB,
588
+ dC,
589
+ dD,
590
+ ddelta_bias if delta_bias is not None else None,
591
+ # 6-None are delta_softplus, checkpoint_lvl, b_rms_weight, c_rms_weight, dt_rms_weight, b_c_dt_rms_eps
592
+ dB_proj_bias,
593
+ dC_proj_bias,
594
+ None,
595
+ None,
596
+ None,
597
+ None,
598
+ None,
599
+ None,
600
+ )
601
+
602
+
603
+ # Dynamo cannot trace MambaInnerFn.forward when its inputs are module parameters: it saves
604
+ # no-op views of them (e.g. `D.contiguous()`, the rearranged conv weight) for backward, which
605
+ # Dynamo rejects as intermediates aliasing an input. Keep it opaque to Dynamo instead.
606
+ torch.compiler.allow_in_graph(MambaInnerFn)
607
+
608
+
609
+ def mamba_inner_fn(
610
+ xz,
611
+ conv1d_weight,
612
+ conv1d_bias,
613
+ x_proj_weight,
614
+ delta_proj_weight,
615
+ out_proj_weight,
616
+ out_proj_bias,
617
+ A,
618
+ B=None,
619
+ C=None,
620
+ D=None,
621
+ delta_bias=None,
622
+ B_proj_bias=None,
623
+ C_proj_bias=None,
624
+ delta_softplus=True,
625
+ checkpoint_lvl=1,
626
+ b_rms_weight=None,
627
+ c_rms_weight=None,
628
+ dt_rms_weight=None,
629
+ b_c_dt_rms_eps=1e-6,
630
+ ):
631
+ return MambaInnerFn.apply(
632
+ xz,
633
+ conv1d_weight,
634
+ conv1d_bias,
635
+ x_proj_weight,
636
+ delta_proj_weight,
637
+ out_proj_weight,
638
+ out_proj_bias,
639
+ A,
640
+ B,
641
+ C,
642
+ D,
643
+ delta_bias,
644
+ B_proj_bias,
645
+ C_proj_bias,
646
+ delta_softplus,
647
+ checkpoint_lvl,
648
+ b_rms_weight,
649
+ c_rms_weight,
650
+ dt_rms_weight,
651
+ b_c_dt_rms_eps,
652
+ )
653
+
654
+
655
+ def mamba_inner_ref(
656
+ xz,
657
+ conv1d_weight,
658
+ conv1d_bias,
659
+ x_proj_weight,
660
+ delta_proj_weight,
661
+ out_proj_weight,
662
+ out_proj_bias,
663
+ A,
664
+ B=None,
665
+ C=None,
666
+ D=None,
667
+ delta_bias=None,
668
+ B_proj_bias=None,
669
+ C_proj_bias=None,
670
+ delta_softplus=True,
671
+ ):
672
+ L = xz.shape[-1]
673
+ delta_rank = delta_proj_weight.shape[1]
674
+ d_state = A.shape[-1] * (1 if not A.is_complex() else 2)
675
+ x, z = xz.chunk(2, dim=1)
676
+ x = causal_conv1d_fn(
677
+ x, rearrange(conv1d_weight, "d 1 w -> d w"), conv1d_bias, activation="silu"
678
+ )
679
+ # We're being very careful here about the layout, to avoid extra transposes.
680
+ # We want delta to have d as the slowest moving dimension
681
+ # and L as the fastest moving dimension, since those are what the ssm_scan kernel expects.
682
+ x_dbl = F.linear(rearrange(x, "b d l -> (b l) d"), x_proj_weight) # (bl d)
683
+ delta = delta_proj_weight @ x_dbl[:, :delta_rank].t()
684
+ delta = rearrange(delta, "d (b l) -> b d l", l=L)
685
+ if B is None: # variable B
686
+ B = x_dbl[:, delta_rank : delta_rank + d_state] # (bl d)
687
+ if B_proj_bias is not None:
688
+ B = B + B_proj_bias.to(dtype=B.dtype)
689
+ if not A.is_complex():
690
+ B = rearrange(B, "(b l) dstate -> b dstate l", l=L).contiguous()
691
+ else:
692
+ B = rearrange(
693
+ B, "(b l) (dstate two) -> b dstate (l two)", l=L, two=2
694
+ ).contiguous()
695
+ if C is None: # variable B
696
+ C = x_dbl[:, -d_state:] # (bl d)
697
+ if C_proj_bias is not None:
698
+ C = C + C_proj_bias.to(dtype=C.dtype)
699
+ if not A.is_complex():
700
+ C = rearrange(C, "(b l) dstate -> b dstate l", l=L).contiguous()
701
+ else:
702
+ C = rearrange(
703
+ C, "(b l) (dstate two) -> b dstate (l two)", l=L, two=2
704
+ ).contiguous()
705
+ y = selective_scan_fn(
706
+ x, delta, A, B, C, D, z=z, delta_bias=delta_bias, delta_softplus=True
707
+ )
708
+ return F.linear(rearrange(y, "b d l -> b l d"), out_proj_weight, out_proj_bias)
build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .selective_state_update import selective_state_update
2
+ from .ssd_combined import mamba_chunk_scan_combined, mamba_split_conv1d_scan_combined
build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/k_activations.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao, Albert Gu.
2
+
3
+ import torch
4
+
5
+ import triton
6
+ import triton.language as tl
7
+
8
+ from ...utils.device import device_guard
9
+
10
+
11
+ @triton.autotune(
12
+ configs=[
13
+ triton.Config({'BLOCK_N': 32}),
14
+ triton.Config({'BLOCK_N': 64}),
15
+ triton.Config({'BLOCK_N': 128}),
16
+ triton.Config({'BLOCK_N': 256}),
17
+ triton.Config({'BLOCK_N': 512}),
18
+ triton.Config({'BLOCK_N': 1024}),
19
+ ],
20
+ key=['ncols'],
21
+ )
22
+ @triton.jit
23
+ def _swiglu_fwd_kernel(
24
+ X,
25
+ Y,
26
+ OUT,
27
+ stride_x_row, # how much to increase the pointer when moving by 1 row
28
+ stride_y_row,
29
+ stride_out_row,
30
+ ncols,
31
+ BLOCK_N: tl.constexpr,
32
+ ):
33
+ # Map the program id to the row of X and Y it should compute.
34
+ row = tl.program_id(0)
35
+ start_col = tl.program_id(1) * BLOCK_N
36
+ X += row * stride_x_row
37
+ Y += row * stride_y_row
38
+ OUT += row * stride_out_row
39
+ cols = start_col + tl.arange(0, BLOCK_N)
40
+ x = tl.load(X + cols, mask=cols < ncols, other=0.).to(tl.float32)
41
+ y = tl.load(Y + cols, mask=cols < ncols, other=0.).to(tl.float32)
42
+ out = x * tl.sigmoid(x) * y
43
+ tl.store(OUT + cols, out, mask=cols < ncols)
44
+
45
+
46
+ def _swiglu_fwd(xy, out=None):
47
+ if xy.stride(-1) != 1:
48
+ xy = xy.contiguous()
49
+ batch_shape = xy.shape[:-1]
50
+ xy = xy.reshape(-1, xy.shape[-1])
51
+ x, y = xy.chunk(2, dim=-1)
52
+ if out is None:
53
+ out = torch.empty_like(x)
54
+ else:
55
+ out = out.reshape(-1, out.shape[-1])
56
+ assert out.shape == x.shape
57
+ assert out.stride(-1) == 1
58
+ M, N = x.shape
59
+ grid = lambda META: (M, triton.cdiv(N, META['BLOCK_N']))
60
+ with device_guard(x):
61
+ _swiglu_fwd_kernel[grid](x, y, out, x.stride(0), y.stride(0), out.stride(0), N)
62
+ return out.reshape(*batch_shape, out.shape[-1])
63
+
64
+
65
+ @triton.autotune(
66
+ configs=[
67
+ triton.Config({'BLOCK_N': 32}),
68
+ triton.Config({'BLOCK_N': 64}),
69
+ triton.Config({'BLOCK_N': 128}),
70
+ triton.Config({'BLOCK_N': 256}),
71
+ triton.Config({'BLOCK_N': 512}),
72
+ triton.Config({'BLOCK_N': 1024}),
73
+ ],
74
+ key=['ncols'],
75
+ )
76
+ @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["OUT"] is not None})
77
+ @triton.jit
78
+ def _swiglu_bwd_kernel(
79
+ X,
80
+ Y,
81
+ DOUT,
82
+ OUT,
83
+ DX,
84
+ DY,
85
+ stride_x_row, # how much to increase the pointer when moving by 1 row
86
+ stride_y_row,
87
+ stride_dout_row,
88
+ stride_out_row,
89
+ stride_dx_row,
90
+ stride_dy_row,
91
+ ncols,
92
+ BLOCK_N: tl.constexpr,
93
+ RECOMPUTE_OUTPUT: tl.constexpr,
94
+ ):
95
+ # Map the program id to the row of X and Y it should compute.
96
+ row = tl.program_id(0)
97
+ start_col = tl.program_id(1) * BLOCK_N
98
+ X += row * stride_x_row
99
+ Y += row * stride_y_row
100
+ DOUT += row * stride_dout_row
101
+ if RECOMPUTE_OUTPUT:
102
+ OUT += row * stride_out_row
103
+ DX += row * stride_dx_row
104
+ DY += row * stride_dy_row
105
+ cols = start_col + tl.arange(0, BLOCK_N)
106
+ x = tl.load(X + cols, mask=cols < ncols, other=0.).to(tl.float32)
107
+ y = tl.load(Y + cols, mask=cols < ncols, other=0.).to(tl.float32)
108
+ dout = tl.load(DOUT + cols, mask=cols < ncols, other=0.).to(tl.float32)
109
+ x_sigmoid = tl.sigmoid(x)
110
+ dx = x_sigmoid * (1 + x * (1 - x_sigmoid)) * y * dout
111
+ dy = x * x_sigmoid * dout
112
+ tl.store(DX + cols, dx, mask=cols < ncols)
113
+ tl.store(DY + cols, dy, mask=cols < ncols)
114
+ if RECOMPUTE_OUTPUT:
115
+ out = x * x_sigmoid * y
116
+ tl.store(OUT + cols, out, mask=cols < ncols)
117
+
118
+
119
+ def _swiglu_bwd(xy, dout, dxy=None, recompute_output=False, out=None):
120
+ if xy.stride(-1) != 1:
121
+ xy = xy.contiguous()
122
+ if dout.stride(-1) != 1:
123
+ dout = dout.contiguous()
124
+ batch_shape = xy.shape[:-1]
125
+ xy = xy.reshape(-1, xy.shape[-1])
126
+ x, y = xy.chunk(2, dim=-1)
127
+ dout = dout.reshape(-1, dout.shape[-1])
128
+ assert dout.shape == x.shape
129
+ if dxy is None:
130
+ dxy = torch.empty_like(xy)
131
+ else:
132
+ dxy = dxy.reshape(-1, dxy.shape[-1])
133
+ assert dxy.shape == xy.shape
134
+ dx, dy = dxy.chunk(2, dim=-1)
135
+ assert dx.stride(-1) == 1
136
+ assert dy.stride(-1) == 1
137
+ if recompute_output:
138
+ if out is None:
139
+ out = torch.empty_like(x)
140
+ else:
141
+ out = out.reshape(-1, out.shape[-1])
142
+ assert out.shape == x.shape
143
+ assert out.stride(-1) == 1
144
+ M, N = x.shape
145
+ grid = lambda META: (M, triton.cdiv(N, META['BLOCK_N']))
146
+ with device_guard(x):
147
+ _swiglu_bwd_kernel[grid](x, y, dout, out if recompute_output else None, dx, dy,
148
+ x.stride(0), y.stride(0), dout.stride(0),
149
+ out.stride(0) if recompute_output else 0,
150
+ dx.stride(0), dy.stride(0),
151
+ N)
152
+ if not recompute_output:
153
+ return dxy.reshape(*batch_shape, dxy.shape[-1])
154
+ else:
155
+ return dxy.reshape(*batch_shape, dxy.shape[-1]), out.reshape(*batch_shape, out.shape[-1])
156
+
157
+
158
+ class SwiGLU(torch.autograd.Function):
159
+
160
+ @staticmethod
161
+ def forward(ctx, xy):
162
+ ctx.save_for_backward(xy)
163
+ return _swiglu_fwd(xy)
164
+
165
+ @staticmethod
166
+ def backward(ctx, dout):
167
+ xy, = ctx.saved_tensors
168
+ return _swiglu_bwd(xy, dout)
169
+
170
+
171
+ swiglu = SwiGLU.apply
build/torch214-cxx11-xpu20261-x86_64-linux/ops/triton/layer_norm.py ADDED
@@ -0,0 +1,1115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+ # Implement dropout + residual + layer_norm / rms_norm.
3
+
4
+ # Based on the Triton LayerNorm tutorial: https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
5
+ # For the backward pass, we keep weight_grad and bias_grad in registers and accumulate.
6
+ # This is faster for dimensions up to 8k, but after that it's much slower due to register spilling.
7
+ # The models we train have hidden dim up to 8k anyway (e.g. Llama 70B), so this is fine.
8
+
9
+ import math
10
+ import warnings
11
+
12
+ import torch
13
+ import torch.nn.functional as F
14
+ from ...utils.torch import custom_bwd, custom_fwd
15
+ from ...utils.device import device_guard, get_sm_count
16
+
17
+ import triton
18
+ import triton.language as tl
19
+
20
+
21
+ def layer_norm_ref(
22
+ x,
23
+ weight,
24
+ bias,
25
+ residual=None,
26
+ x1=None,
27
+ weight1=None,
28
+ bias1=None,
29
+ eps=1e-6,
30
+ dropout_p=0.0,
31
+ rowscale=None,
32
+ prenorm=False,
33
+ dropout_mask=None,
34
+ dropout_mask1=None,
35
+ upcast=False,
36
+ ):
37
+ dtype = x.dtype
38
+ if upcast:
39
+ x = x.float()
40
+ weight = weight.float()
41
+ bias = bias.float() if bias is not None else None
42
+ residual = residual.float() if residual is not None else residual
43
+ x1 = x1.float() if x1 is not None else None
44
+ weight1 = weight1.float() if weight1 is not None else None
45
+ bias1 = bias1.float() if bias1 is not None else None
46
+ if x1 is not None:
47
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
48
+ if rowscale is not None:
49
+ x = x * rowscale[..., None]
50
+ if dropout_p > 0.0:
51
+ if dropout_mask is not None:
52
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
53
+ else:
54
+ x = F.dropout(x, p=dropout_p)
55
+ if x1 is not None:
56
+ if dropout_mask1 is not None:
57
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
58
+ else:
59
+ x1 = F.dropout(x1, p=dropout_p)
60
+ if x1 is not None:
61
+ x = x + x1
62
+ if residual is not None:
63
+ x = (x + residual).to(x.dtype)
64
+ out = F.layer_norm(x.to(weight.dtype), x.shape[-1:], weight=weight, bias=bias, eps=eps).to(
65
+ dtype
66
+ )
67
+ if weight1 is None:
68
+ return out if not prenorm else (out, x)
69
+ else:
70
+ out1 = F.layer_norm(
71
+ x.to(weight1.dtype), x.shape[-1:], weight=weight1, bias=bias1, eps=eps
72
+ ).to(dtype)
73
+ return (out, out1) if not prenorm else (out, out1, x)
74
+
75
+
76
+ def rms_norm_ref(
77
+ x,
78
+ weight,
79
+ bias,
80
+ residual=None,
81
+ x1=None,
82
+ weight1=None,
83
+ bias1=None,
84
+ eps=1e-6,
85
+ dropout_p=0.0,
86
+ rowscale=None,
87
+ prenorm=False,
88
+ dropout_mask=None,
89
+ dropout_mask1=None,
90
+ upcast=False,
91
+ ):
92
+ dtype = x.dtype
93
+ if upcast:
94
+ x = x.float()
95
+ weight = weight.float()
96
+ bias = bias.float() if bias is not None else None
97
+ residual = residual.float() if residual is not None else residual
98
+ x1 = x1.float() if x1 is not None else None
99
+ weight1 = weight1.float() if weight1 is not None else None
100
+ bias1 = bias1.float() if bias1 is not None else None
101
+ if x1 is not None:
102
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
103
+ if rowscale is not None:
104
+ x = x * rowscale[..., None]
105
+ if dropout_p > 0.0:
106
+ if dropout_mask is not None:
107
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
108
+ else:
109
+ x = F.dropout(x, p=dropout_p)
110
+ if x1 is not None:
111
+ if dropout_mask1 is not None:
112
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
113
+ else:
114
+ x1 = F.dropout(x1, p=dropout_p)
115
+ if x1 is not None:
116
+ x = x + x1
117
+ if residual is not None:
118
+ x = (x + residual).to(x.dtype)
119
+ rstd = 1 / torch.sqrt((x.square()).mean(dim=-1, keepdim=True) + eps)
120
+ out = ((x * rstd * weight) + bias if bias is not None else (x * rstd * weight)).to(dtype)
121
+ if weight1 is None:
122
+ return out if not prenorm else (out, x)
123
+ else:
124
+ out1 = ((x * rstd * weight1) + bias1 if bias1 is not None else (x * rstd * weight1)).to(
125
+ dtype
126
+ )
127
+ return (out, out1) if not prenorm else (out, out1, x)
128
+
129
+ def config_prune(configs):
130
+
131
+ if torch.version.hip:
132
+ try:
133
+ # set warp size based on gcn architecure
134
+ gcn_arch_name = torch.cuda.get_device_properties(0).gcnArchName
135
+ if "gfx10" in gcn_arch_name or "gfx11" in gcn_arch_name:
136
+ # radeon
137
+ warp_size = 32
138
+ else:
139
+ # instinct
140
+ warp_size = 64
141
+ except AttributeError as e:
142
+ # fall back to crude method to set warp size
143
+ device_name = torch.cuda.get_device_properties(0).name
144
+ if 'instinct' in device_name.lower():
145
+ warp_size = 64
146
+ else:
147
+ warp_size = 32
148
+ warnings.warn(f"{e}, warp size set to {warp_size} based on device name: {device_name}", UserWarning)
149
+
150
+ else:
151
+ # cuda
152
+ warp_size = 32
153
+
154
+ max_block_sz = 1024
155
+ max_num_warps = max_block_sz // warp_size
156
+ pruned_configs = [config for config in configs if config.num_warps <= max_num_warps]
157
+ return pruned_configs
158
+
159
+ configs_autotune = [
160
+ triton.Config({}, num_warps=1),
161
+ triton.Config({}, num_warps=2),
162
+ triton.Config({}, num_warps=4),
163
+ triton.Config({}, num_warps=8),
164
+ triton.Config({}, num_warps=16),
165
+ triton.Config({}, num_warps=32),
166
+ ]
167
+
168
+ pruned_configs_autotune = config_prune(configs_autotune)
169
+
170
+ @triton.autotune(
171
+ configs = pruned_configs_autotune,
172
+ key=["N", "HAS_RESIDUAL", "STORE_RESIDUAL_OUT", "IS_RMS_NORM", "HAS_BIAS"],
173
+ )
174
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
175
+ # @triton.heuristics({"HAS_RESIDUAL": lambda args: args["RESIDUAL"] is not None})
176
+ @triton.heuristics({"HAS_X1": lambda args: args["X1"] is not None})
177
+ @triton.heuristics({"HAS_W1": lambda args: args["W1"] is not None})
178
+ @triton.heuristics({"HAS_B1": lambda args: args["B1"] is not None})
179
+ @triton.jit
180
+ def _layer_norm_fwd_1pass_kernel(
181
+ X, # pointer to the input
182
+ Y, # pointer to the output
183
+ W, # pointer to the weights
184
+ B, # pointer to the biases
185
+ RESIDUAL, # pointer to the residual
186
+ X1,
187
+ W1,
188
+ B1,
189
+ Y1,
190
+ RESIDUAL_OUT, # pointer to the residual
191
+ ROWSCALE,
192
+ SEEDS, # Dropout seeds for each row
193
+ DROPOUT_MASK,
194
+ Mean, # pointer to the mean
195
+ Rstd, # pointer to the 1/std
196
+ stride_x_row, # how much to increase the pointer when moving by 1 row
197
+ stride_y_row,
198
+ stride_res_row,
199
+ stride_res_out_row,
200
+ stride_x1_row,
201
+ stride_y1_row,
202
+ M, # number of rows in X
203
+ N, # number of columns in X
204
+ eps, # epsilon to avoid division by zero
205
+ dropout_p, # Dropout probability
206
+ IS_RMS_NORM: tl.constexpr,
207
+ BLOCK_N: tl.constexpr,
208
+ HAS_RESIDUAL: tl.constexpr,
209
+ STORE_RESIDUAL_OUT: tl.constexpr,
210
+ HAS_BIAS: tl.constexpr,
211
+ HAS_DROPOUT: tl.constexpr,
212
+ STORE_DROPOUT_MASK: tl.constexpr,
213
+ HAS_ROWSCALE: tl.constexpr,
214
+ HAS_X1: tl.constexpr,
215
+ HAS_W1: tl.constexpr,
216
+ HAS_B1: tl.constexpr,
217
+ ):
218
+ # Map the program id to the row of X and Y it should compute.
219
+ row = tl.program_id(0)
220
+ X += row * stride_x_row
221
+ Y += row * stride_y_row
222
+ if HAS_RESIDUAL:
223
+ RESIDUAL += row * stride_res_row
224
+ if STORE_RESIDUAL_OUT:
225
+ RESIDUAL_OUT += row * stride_res_out_row
226
+ if HAS_X1:
227
+ X1 += row * stride_x1_row
228
+ if HAS_W1:
229
+ Y1 += row * stride_y1_row
230
+ # Compute mean and variance
231
+ cols = tl.arange(0, BLOCK_N)
232
+ x = tl.load(X + cols, mask=cols < N, other=0.0).to(tl.float32)
233
+ if HAS_ROWSCALE:
234
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
235
+ x *= rowscale
236
+ if HAS_DROPOUT:
237
+ # Compute dropout mask
238
+ # 7 rounds is good enough, and reduces register pressure
239
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
240
+ x = tl.where(keep_mask, x / (1.0 - dropout_p), 0.0)
241
+ if STORE_DROPOUT_MASK:
242
+ tl.store(DROPOUT_MASK + row * N + cols, keep_mask, mask=cols < N)
243
+ if HAS_X1:
244
+ x1 = tl.load(X1 + cols, mask=cols < N, other=0.0).to(tl.float32)
245
+ if HAS_ROWSCALE:
246
+ rowscale = tl.load(ROWSCALE + M + row).to(tl.float32)
247
+ x1 *= rowscale
248
+ if HAS_DROPOUT:
249
+ # Compute dropout mask
250
+ # 7 rounds is good enough, and reduces register pressure
251
+ keep_mask = (
252
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
253
+ )
254
+ x1 = tl.where(keep_mask, x1 / (1.0 - dropout_p), 0.0)
255
+ if STORE_DROPOUT_MASK:
256
+ tl.store(DROPOUT_MASK + (M + row) * N + cols, keep_mask, mask=cols < N)
257
+ x += x1
258
+ if HAS_RESIDUAL:
259
+ residual = tl.load(RESIDUAL + cols, mask=cols < N, other=0.0).to(tl.float32)
260
+ x += residual
261
+ if STORE_RESIDUAL_OUT:
262
+ tl.store(RESIDUAL_OUT + cols, x, mask=cols < N)
263
+ if not IS_RMS_NORM:
264
+ mean = tl.sum(x, axis=0) / N
265
+ tl.store(Mean + row, mean)
266
+ xbar = tl.where(cols < N, x - mean, 0.0)
267
+ var = tl.sum(xbar * xbar, axis=0) / N
268
+ else:
269
+ xbar = tl.where(cols < N, x, 0.0)
270
+ var = tl.sum(xbar * xbar, axis=0) / N
271
+ rstd = 1 / tl.sqrt(var + eps)
272
+ tl.store(Rstd + row, rstd)
273
+ # Normalize and apply linear transformation
274
+ mask = cols < N
275
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
276
+ if HAS_BIAS:
277
+ b = tl.load(B + cols, mask=mask).to(tl.float32)
278
+ x_hat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
279
+ y = x_hat * w + b if HAS_BIAS else x_hat * w
280
+ # Write output
281
+ tl.store(Y + cols, y, mask=mask)
282
+ if HAS_W1:
283
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
284
+ if HAS_B1:
285
+ b1 = tl.load(B1 + cols, mask=mask).to(tl.float32)
286
+ y1 = x_hat * w1 + b1 if HAS_B1 else x_hat * w1
287
+ tl.store(Y1 + cols, y1, mask=mask)
288
+
289
+
290
+ def _layer_norm_fwd(
291
+ x,
292
+ weight,
293
+ bias,
294
+ eps,
295
+ residual=None,
296
+ x1=None,
297
+ weight1=None,
298
+ bias1=None,
299
+ dropout_p=0.0,
300
+ rowscale=None,
301
+ out_dtype=None,
302
+ residual_dtype=None,
303
+ is_rms_norm=False,
304
+ return_dropout_mask=False,
305
+ ):
306
+ if residual is not None:
307
+ residual_dtype = residual.dtype
308
+ M, N = x.shape
309
+ assert x.stride(-1) == 1
310
+ if residual is not None:
311
+ assert residual.stride(-1) == 1
312
+ assert residual.shape == (M, N)
313
+ assert weight.shape == (N,)
314
+ assert weight.stride(-1) == 1
315
+ if bias is not None:
316
+ assert bias.stride(-1) == 1
317
+ assert bias.shape == (N,)
318
+ if x1 is not None:
319
+ assert x1.shape == x.shape
320
+ assert rowscale is None
321
+ assert x1.stride(-1) == 1
322
+ if weight1 is not None:
323
+ assert weight1.shape == (N,)
324
+ assert weight1.stride(-1) == 1
325
+ if bias1 is not None:
326
+ assert bias1.shape == (N,)
327
+ assert bias1.stride(-1) == 1
328
+ if rowscale is not None:
329
+ assert rowscale.is_contiguous()
330
+ assert rowscale.shape == (M,)
331
+ # allocate output
332
+ y = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
333
+ assert y.stride(-1) == 1
334
+ if weight1 is not None:
335
+ y1 = torch.empty_like(y)
336
+ assert y1.stride(-1) == 1
337
+ else:
338
+ y1 = None
339
+ if (
340
+ residual is not None
341
+ or (residual_dtype is not None and residual_dtype != x.dtype)
342
+ or dropout_p > 0.0
343
+ or rowscale is not None
344
+ or x1 is not None
345
+ ):
346
+ residual_out = torch.empty(
347
+ M, N, device=x.device, dtype=residual_dtype if residual_dtype is not None else x.dtype
348
+ )
349
+ assert residual_out.stride(-1) == 1
350
+ else:
351
+ residual_out = None
352
+ mean = torch.empty((M,), dtype=torch.float32, device=x.device) if not is_rms_norm else None
353
+ rstd = torch.empty((M,), dtype=torch.float32, device=x.device)
354
+ if dropout_p > 0.0:
355
+ seeds = torch.randint(
356
+ 2**32, (M if x1 is None else 2 * M,), device=x.device, dtype=torch.int64
357
+ )
358
+ else:
359
+ seeds = None
360
+ if return_dropout_mask and dropout_p > 0.0:
361
+ dropout_mask = torch.empty(M if x1 is None else 2 * M, N, device=x.device, dtype=torch.bool)
362
+ else:
363
+ dropout_mask = None
364
+ # Less than 64KB per feature: enqueue fused kernel
365
+ MAX_FUSED_SIZE = 65536 // x.element_size()
366
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
367
+ if N > BLOCK_N:
368
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
369
+ with device_guard(x):
370
+ _layer_norm_fwd_1pass_kernel[(M,)](
371
+ x,
372
+ y,
373
+ weight,
374
+ bias,
375
+ residual,
376
+ x1,
377
+ weight1,
378
+ bias1,
379
+ y1,
380
+ residual_out,
381
+ rowscale,
382
+ seeds,
383
+ dropout_mask,
384
+ mean,
385
+ rstd,
386
+ x.stride(0),
387
+ y.stride(0),
388
+ residual.stride(0) if residual is not None else 0,
389
+ residual_out.stride(0) if residual_out is not None else 0,
390
+ x1.stride(0) if x1 is not None else 0,
391
+ y1.stride(0) if y1 is not None else 0,
392
+ M,
393
+ N,
394
+ eps,
395
+ dropout_p,
396
+ is_rms_norm,
397
+ BLOCK_N,
398
+ residual is not None,
399
+ residual_out is not None,
400
+ bias is not None,
401
+ dropout_p > 0.0,
402
+ dropout_mask is not None,
403
+ rowscale is not None,
404
+ )
405
+ # residual_out is None if residual is None and residual_dtype == input_dtype and dropout_p == 0.0
406
+ if dropout_mask is not None and x1 is not None:
407
+ dropout_mask, dropout_mask1 = dropout_mask.tensor_split(2, dim=0)
408
+ else:
409
+ dropout_mask1 = None
410
+ return (
411
+ y,
412
+ y1,
413
+ mean,
414
+ rstd,
415
+ residual_out if residual_out is not None else x,
416
+ seeds,
417
+ dropout_mask,
418
+ dropout_mask1,
419
+ )
420
+
421
+
422
+ @triton.autotune(
423
+ configs=pruned_configs_autotune,
424
+ key=["N", "HAS_DRESIDUAL", "STORE_DRESIDUAL", "IS_RMS_NORM", "HAS_BIAS", "HAS_DROPOUT"],
425
+ )
426
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
427
+ # @triton.heuristics({"HAS_DRESIDUAL": lambda args: args["DRESIDUAL"] is not None})
428
+ # @triton.heuristics({"STORE_DRESIDUAL": lambda args: args["DRESIDUAL_IN"] is not None})
429
+ @triton.heuristics({"HAS_ROWSCALE": lambda args: args["ROWSCALE"] is not None})
430
+ @triton.heuristics({"HAS_DY1": lambda args: args["DY1"] is not None})
431
+ @triton.heuristics({"HAS_DX1": lambda args: args["DX1"] is not None})
432
+ @triton.heuristics({"HAS_B1": lambda args: args["DB1"] is not None})
433
+ @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["Y"] is not None})
434
+ @triton.jit
435
+ def _layer_norm_bwd_kernel(
436
+ X, # pointer to the input
437
+ W, # pointer to the weights
438
+ B, # pointer to the biases
439
+ Y, # pointer to the output to be recomputed
440
+ DY, # pointer to the output gradient
441
+ DX, # pointer to the input gradient
442
+ DW, # pointer to the partial sum of weights gradient
443
+ DB, # pointer to the partial sum of biases gradient
444
+ DRESIDUAL,
445
+ W1,
446
+ DY1,
447
+ DX1,
448
+ DW1,
449
+ DB1,
450
+ DRESIDUAL_IN,
451
+ ROWSCALE,
452
+ SEEDS,
453
+ Mean, # pointer to the mean
454
+ Rstd, # pointer to the 1/std
455
+ stride_x_row, # how much to increase the pointer when moving by 1 row
456
+ stride_y_row,
457
+ stride_dy_row,
458
+ stride_dx_row,
459
+ stride_dres_row,
460
+ stride_dy1_row,
461
+ stride_dx1_row,
462
+ stride_dres_in_row,
463
+ M, # number of rows in X
464
+ N, # number of columns in X
465
+ eps, # epsilon to avoid division by zero
466
+ dropout_p,
467
+ rows_per_program,
468
+ IS_RMS_NORM: tl.constexpr,
469
+ BLOCK_N: tl.constexpr,
470
+ HAS_DRESIDUAL: tl.constexpr,
471
+ STORE_DRESIDUAL: tl.constexpr,
472
+ HAS_BIAS: tl.constexpr,
473
+ HAS_DROPOUT: tl.constexpr,
474
+ HAS_ROWSCALE: tl.constexpr,
475
+ HAS_DY1: tl.constexpr,
476
+ HAS_DX1: tl.constexpr,
477
+ HAS_B1: tl.constexpr,
478
+ RECOMPUTE_OUTPUT: tl.constexpr,
479
+ ):
480
+ # Map the program id to the elements of X, DX, and DY it should compute.
481
+ row_block_id = tl.program_id(0)
482
+ row_start = row_block_id * rows_per_program
483
+ # Do not early exit if row_start >= M, because we need to write DW and DB
484
+ cols = tl.arange(0, BLOCK_N)
485
+ mask = cols < N
486
+ X += row_start * stride_x_row
487
+ if HAS_DRESIDUAL:
488
+ DRESIDUAL += row_start * stride_dres_row
489
+ if STORE_DRESIDUAL:
490
+ DRESIDUAL_IN += row_start * stride_dres_in_row
491
+ DY += row_start * stride_dy_row
492
+ DX += row_start * stride_dx_row
493
+ if HAS_DY1:
494
+ DY1 += row_start * stride_dy1_row
495
+ if HAS_DX1:
496
+ DX1 += row_start * stride_dx1_row
497
+ if RECOMPUTE_OUTPUT:
498
+ Y += row_start * stride_y_row
499
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
500
+ if RECOMPUTE_OUTPUT and HAS_BIAS:
501
+ b = tl.load(B + cols, mask=mask, other=0.0).to(tl.float32)
502
+ if HAS_DY1:
503
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
504
+ dw = tl.zeros((BLOCK_N,), dtype=tl.float32)
505
+ if HAS_BIAS:
506
+ db = tl.zeros((BLOCK_N,), dtype=tl.float32)
507
+ if HAS_DY1:
508
+ dw1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
509
+ if HAS_B1:
510
+ db1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
511
+ row_end = min((row_block_id + 1) * rows_per_program, M)
512
+ for row in range(row_start, row_end):
513
+ # Load data to SRAM
514
+ x = tl.load(X + cols, mask=mask, other=0).to(tl.float32)
515
+ dy = tl.load(DY + cols, mask=mask, other=0).to(tl.float32)
516
+ if HAS_DY1:
517
+ dy1 = tl.load(DY1 + cols, mask=mask, other=0).to(tl.float32)
518
+ if not IS_RMS_NORM:
519
+ mean = tl.load(Mean + row)
520
+ rstd = tl.load(Rstd + row)
521
+ # Compute dx
522
+ xhat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
523
+ xhat = tl.where(mask, xhat, 0.0)
524
+ if RECOMPUTE_OUTPUT:
525
+ y = xhat * w + b if HAS_BIAS else xhat * w
526
+ tl.store(Y + cols, y, mask=mask)
527
+ wdy = w * dy
528
+ dw += dy * xhat
529
+ if HAS_BIAS:
530
+ db += dy
531
+ if HAS_DY1:
532
+ wdy += w1 * dy1
533
+ dw1 += dy1 * xhat
534
+ if HAS_B1:
535
+ db1 += dy1
536
+ if not IS_RMS_NORM:
537
+ c1 = tl.sum(xhat * wdy, axis=0) / N
538
+ c2 = tl.sum(wdy, axis=0) / N
539
+ dx = (wdy - (xhat * c1 + c2)) * rstd
540
+ else:
541
+ c1 = tl.sum(xhat * wdy, axis=0) / N
542
+ dx = (wdy - xhat * c1) * rstd
543
+ if HAS_DRESIDUAL:
544
+ dres = tl.load(DRESIDUAL + cols, mask=mask, other=0).to(tl.float32)
545
+ dx += dres
546
+ # Write dx
547
+ if STORE_DRESIDUAL:
548
+ tl.store(DRESIDUAL_IN + cols, dx, mask=mask)
549
+ if HAS_DX1:
550
+ if HAS_DROPOUT:
551
+ keep_mask = (
552
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
553
+ )
554
+ dx1 = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
555
+ else:
556
+ dx1 = dx
557
+ tl.store(DX1 + cols, dx1, mask=mask)
558
+ if HAS_DROPOUT:
559
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
560
+ dx = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
561
+ if HAS_ROWSCALE:
562
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
563
+ dx *= rowscale
564
+ tl.store(DX + cols, dx, mask=mask)
565
+
566
+ X += stride_x_row
567
+ if HAS_DRESIDUAL:
568
+ DRESIDUAL += stride_dres_row
569
+ if STORE_DRESIDUAL:
570
+ DRESIDUAL_IN += stride_dres_in_row
571
+ if RECOMPUTE_OUTPUT:
572
+ Y += stride_y_row
573
+ DY += stride_dy_row
574
+ DX += stride_dx_row
575
+ if HAS_DY1:
576
+ DY1 += stride_dy1_row
577
+ if HAS_DX1:
578
+ DX1 += stride_dx1_row
579
+ tl.store(DW + row_block_id * N + cols, dw, mask=mask)
580
+ if HAS_BIAS:
581
+ tl.store(DB + row_block_id * N + cols, db, mask=mask)
582
+ if HAS_DY1:
583
+ tl.store(DW1 + row_block_id * N + cols, dw1, mask=mask)
584
+ if HAS_B1:
585
+ tl.store(DB1 + row_block_id * N + cols, db1, mask=mask)
586
+
587
+
588
+ def _layer_norm_bwd(
589
+ dy,
590
+ x,
591
+ weight,
592
+ bias,
593
+ eps,
594
+ mean,
595
+ rstd,
596
+ dresidual=None,
597
+ dy1=None,
598
+ weight1=None,
599
+ bias1=None,
600
+ seeds=None,
601
+ dropout_p=0.0,
602
+ rowscale=None,
603
+ has_residual=False,
604
+ has_x1=False,
605
+ is_rms_norm=False,
606
+ x_dtype=None,
607
+ recompute_output=False,
608
+ ):
609
+ M, N = x.shape
610
+ assert x.stride(-1) == 1
611
+ assert dy.stride(-1) == 1
612
+ assert dy.shape == (M, N)
613
+ if dresidual is not None:
614
+ assert dresidual.stride(-1) == 1
615
+ assert dresidual.shape == (M, N)
616
+ assert weight.shape == (N,)
617
+ assert weight.stride(-1) == 1
618
+ if bias is not None:
619
+ assert bias.stride(-1) == 1
620
+ assert bias.shape == (N,)
621
+ if dy1 is not None:
622
+ assert weight1 is not None
623
+ assert dy1.shape == dy.shape
624
+ assert dy1.stride(-1) == 1
625
+ if weight1 is not None:
626
+ assert weight1.shape == (N,)
627
+ assert weight1.stride(-1) == 1
628
+ if bias1 is not None:
629
+ assert bias1.shape == (N,)
630
+ assert bias1.stride(-1) == 1
631
+ if seeds is not None:
632
+ assert seeds.is_contiguous()
633
+ assert seeds.shape == (M if not has_x1 else M * 2,)
634
+ if rowscale is not None:
635
+ assert rowscale.is_contiguous()
636
+ assert rowscale.shape == (M,)
637
+ # allocate output
638
+ dx = (
639
+ torch.empty_like(x)
640
+ if x_dtype is None
641
+ else torch.empty(M, N, dtype=x_dtype, device=x.device)
642
+ )
643
+ dresidual_in = (
644
+ torch.empty_like(x)
645
+ if has_residual
646
+ and (dx.dtype != x.dtype or dropout_p > 0.0 or rowscale is not None or has_x1)
647
+ else None
648
+ )
649
+ dx1 = torch.empty_like(dx) if (has_x1 and dropout_p > 0.0) else None
650
+ y = torch.empty(M, N, dtype=dy.dtype, device=dy.device) if recompute_output else None
651
+ if recompute_output:
652
+ assert weight1 is None, "recompute_output is not supported with parallel LayerNorm"
653
+
654
+ # Less than 64KB per feature: enqueue fused kernel
655
+ MAX_FUSED_SIZE = 65536 // x.element_size()
656
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
657
+ if N > BLOCK_N:
658
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
659
+ sm_count = get_sm_count(x.device)
660
+ _dw = torch.empty((sm_count, N), dtype=torch.float32, device=weight.device)
661
+ _db = (
662
+ torch.empty((sm_count, N), dtype=torch.float32, device=bias.device)
663
+ if bias is not None
664
+ else None
665
+ )
666
+ _dw1 = torch.empty_like(_dw) if weight1 is not None else None
667
+ _db1 = torch.empty_like(_db) if bias1 is not None else None
668
+ rows_per_program = math.ceil(M / sm_count)
669
+ grid = (sm_count,)
670
+ with device_guard(x):
671
+ _layer_norm_bwd_kernel[grid](
672
+ x,
673
+ weight,
674
+ bias,
675
+ y,
676
+ dy,
677
+ dx,
678
+ _dw,
679
+ _db,
680
+ dresidual,
681
+ weight1,
682
+ dy1,
683
+ dx1,
684
+ _dw1,
685
+ _db1,
686
+ dresidual_in,
687
+ rowscale,
688
+ seeds,
689
+ mean,
690
+ rstd,
691
+ x.stride(0),
692
+ 0 if not recompute_output else y.stride(0),
693
+ dy.stride(0),
694
+ dx.stride(0),
695
+ dresidual.stride(0) if dresidual is not None else 0,
696
+ dy1.stride(0) if dy1 is not None else 0,
697
+ dx1.stride(0) if dx1 is not None else 0,
698
+ dresidual_in.stride(0) if dresidual_in is not None else 0,
699
+ M,
700
+ N,
701
+ eps,
702
+ dropout_p,
703
+ rows_per_program,
704
+ is_rms_norm,
705
+ BLOCK_N,
706
+ dresidual is not None,
707
+ dresidual_in is not None,
708
+ bias is not None,
709
+ dropout_p > 0.0,
710
+ )
711
+ dw = _dw.sum(0).to(weight.dtype)
712
+ db = _db.sum(0).to(bias.dtype) if bias is not None else None
713
+ dw1 = _dw1.sum(0).to(weight1.dtype) if weight1 is not None else None
714
+ db1 = _db1.sum(0).to(bias1.dtype) if bias1 is not None else None
715
+ # Don't need to compute dresidual_in separately in this case
716
+ if has_residual and dx.dtype == x.dtype and dropout_p == 0.0 and rowscale is None:
717
+ dresidual_in = dx
718
+ if has_x1 and dropout_p == 0.0:
719
+ dx1 = dx
720
+ return (
721
+ (dx, dw, db, dresidual_in, dx1, dw1, db1)
722
+ if not recompute_output
723
+ else (dx, dw, db, dresidual_in, dx1, dw1, db1, y)
724
+ )
725
+
726
+
727
+ class LayerNormFn(torch.autograd.Function):
728
+ @staticmethod
729
+ def forward(
730
+ ctx,
731
+ x,
732
+ weight,
733
+ bias,
734
+ residual=None,
735
+ x1=None,
736
+ weight1=None,
737
+ bias1=None,
738
+ eps=1e-6,
739
+ dropout_p=0.0,
740
+ rowscale=None,
741
+ prenorm=False,
742
+ residual_in_fp32=False,
743
+ is_rms_norm=False,
744
+ return_dropout_mask=False,
745
+ ):
746
+ x_shape_og = x.shape
747
+ # reshape input data into 2D tensor
748
+ x = x.reshape(-1, x.shape[-1])
749
+ if x.stride(-1) != 1:
750
+ x = x.contiguous()
751
+ if residual is not None:
752
+ assert residual.shape == x_shape_og
753
+ residual = residual.reshape(-1, residual.shape[-1])
754
+ if residual.stride(-1) != 1:
755
+ residual = residual.contiguous()
756
+ if x1 is not None:
757
+ assert x1.shape == x_shape_og
758
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
759
+ x1 = x1.reshape(-1, x1.shape[-1])
760
+ if x1.stride(-1) != 1:
761
+ x1 = x1.contiguous()
762
+ weight = weight.contiguous()
763
+ if bias is not None:
764
+ bias = bias.contiguous()
765
+ if weight1 is not None:
766
+ weight1 = weight1.contiguous()
767
+ if bias1 is not None:
768
+ bias1 = bias1.contiguous()
769
+ if rowscale is not None:
770
+ rowscale = rowscale.reshape(-1).contiguous()
771
+ residual_dtype = (
772
+ residual.dtype
773
+ if residual is not None
774
+ else (torch.float32 if residual_in_fp32 else None)
775
+ )
776
+ y, y1, mean, rstd, residual_out, seeds, dropout_mask, dropout_mask1 = _layer_norm_fwd(
777
+ x,
778
+ weight,
779
+ bias,
780
+ eps,
781
+ residual,
782
+ x1,
783
+ weight1,
784
+ bias1,
785
+ dropout_p=dropout_p,
786
+ rowscale=rowscale,
787
+ residual_dtype=residual_dtype,
788
+ is_rms_norm=is_rms_norm,
789
+ return_dropout_mask=return_dropout_mask,
790
+ )
791
+ ctx.save_for_backward(
792
+ residual_out, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd
793
+ )
794
+ ctx.x_shape_og = x_shape_og
795
+ ctx.eps = eps
796
+ ctx.dropout_p = dropout_p
797
+ ctx.is_rms_norm = is_rms_norm
798
+ ctx.has_residual = residual is not None
799
+ ctx.has_x1 = x1 is not None
800
+ ctx.prenorm = prenorm
801
+ ctx.x_dtype = x.dtype
802
+ y = y.reshape(x_shape_og)
803
+ y1 = y1.reshape(x_shape_og) if y1 is not None else None
804
+ residual_out = residual_out.reshape(x_shape_og) if residual_out is not None else None
805
+ dropout_mask = dropout_mask.reshape(x_shape_og) if dropout_mask is not None else None
806
+ dropout_mask1 = dropout_mask1.reshape(x_shape_og) if dropout_mask1 is not None else None
807
+ if not return_dropout_mask:
808
+ if weight1 is None:
809
+ return y if not prenorm else (y, residual_out)
810
+ else:
811
+ return (y, y1) if not prenorm else (y, y1, residual_out)
812
+ else:
813
+ if weight1 is None:
814
+ return (
815
+ (y, dropout_mask, dropout_mask1)
816
+ if not prenorm
817
+ else (y, residual_out, dropout_mask, dropout_mask1)
818
+ )
819
+ else:
820
+ return (
821
+ (y, y1, dropout_mask, dropout_mask1)
822
+ if not prenorm
823
+ else (y, y1, residual_out, dropout_mask, dropout_mask1)
824
+ )
825
+
826
+ @staticmethod
827
+ def backward(ctx, dy, *args):
828
+ x, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd = ctx.saved_tensors
829
+ dy = dy.reshape(-1, dy.shape[-1])
830
+ if dy.stride(-1) != 1:
831
+ dy = dy.contiguous()
832
+ assert dy.shape == x.shape
833
+ if weight1 is not None:
834
+ dy1, args = args[0], args[1:]
835
+ dy1 = dy1.reshape(-1, dy1.shape[-1])
836
+ if dy1.stride(-1) != 1:
837
+ dy1 = dy1.contiguous()
838
+ assert dy1.shape == x.shape
839
+ else:
840
+ dy1 = None
841
+ if ctx.prenorm:
842
+ dresidual = args[0]
843
+ dresidual = dresidual.reshape(-1, dresidual.shape[-1])
844
+ if dresidual.stride(-1) != 1:
845
+ dresidual = dresidual.contiguous()
846
+ assert dresidual.shape == x.shape
847
+ else:
848
+ dresidual = None
849
+ dx, dw, db, dresidual_in, dx1, dw1, db1 = _layer_norm_bwd(
850
+ dy,
851
+ x,
852
+ weight,
853
+ bias,
854
+ ctx.eps,
855
+ mean,
856
+ rstd,
857
+ dresidual,
858
+ dy1,
859
+ weight1,
860
+ bias1,
861
+ seeds,
862
+ ctx.dropout_p,
863
+ rowscale,
864
+ ctx.has_residual,
865
+ ctx.has_x1,
866
+ ctx.is_rms_norm,
867
+ x_dtype=ctx.x_dtype,
868
+ )
869
+ return (
870
+ dx.reshape(ctx.x_shape_og),
871
+ dw,
872
+ db,
873
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
874
+ dx1.reshape(ctx.x_shape_og) if dx1 is not None else None,
875
+ dw1,
876
+ db1,
877
+ None,
878
+ None,
879
+ None,
880
+ None,
881
+ None,
882
+ None,
883
+ None,
884
+ )
885
+
886
+
887
+ def layer_norm_fn(
888
+ x,
889
+ weight,
890
+ bias,
891
+ residual=None,
892
+ x1=None,
893
+ weight1=None,
894
+ bias1=None,
895
+ eps=1e-6,
896
+ dropout_p=0.0,
897
+ rowscale=None,
898
+ prenorm=False,
899
+ residual_in_fp32=False,
900
+ is_rms_norm=False,
901
+ return_dropout_mask=False,
902
+ ):
903
+ return LayerNormFn.apply(
904
+ x,
905
+ weight,
906
+ bias,
907
+ residual,
908
+ x1,
909
+ weight1,
910
+ bias1,
911
+ eps,
912
+ dropout_p,
913
+ rowscale,
914
+ prenorm,
915
+ residual_in_fp32,
916
+ is_rms_norm,
917
+ return_dropout_mask,
918
+ )
919
+
920
+
921
+ def rms_norm_fn(
922
+ x,
923
+ weight,
924
+ bias,
925
+ residual=None,
926
+ x1=None,
927
+ weight1=None,
928
+ bias1=None,
929
+ eps=1e-6,
930
+ dropout_p=0.0,
931
+ rowscale=None,
932
+ prenorm=False,
933
+ residual_in_fp32=False,
934
+ return_dropout_mask=False,
935
+ ):
936
+ return LayerNormFn.apply(
937
+ x,
938
+ weight,
939
+ bias,
940
+ residual,
941
+ x1,
942
+ weight1,
943
+ bias1,
944
+ eps,
945
+ dropout_p,
946
+ rowscale,
947
+ prenorm,
948
+ residual_in_fp32,
949
+ True,
950
+ return_dropout_mask,
951
+ )
952
+
953
+
954
+ class RMSNorm(torch.nn.Module):
955
+
956
+ def __init__(self, hidden_size, eps=1e-5, dropout_p=0.0, device=None, dtype=None):
957
+ factory_kwargs = {"device": device, "dtype": dtype}
958
+ super().__init__()
959
+ self.eps = eps
960
+ if dropout_p > 0.0:
961
+ self.drop = torch.nn.Dropout(dropout_p)
962
+ else:
963
+ self.drop = None
964
+ self.weight = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
965
+ self.register_parameter("bias", None)
966
+ self.reset_parameters()
967
+
968
+ def reset_parameters(self):
969
+ torch.nn.init.ones_(self.weight)
970
+
971
+ def forward(self, x, residual=None, prenorm=False, residual_in_fp32=False):
972
+ return rms_norm_fn(
973
+ x,
974
+ self.weight,
975
+ self.bias,
976
+ residual=residual,
977
+ eps=self.eps,
978
+ dropout_p=self.drop.p if self.drop is not None and self.training else 0.0,
979
+ prenorm=prenorm,
980
+ residual_in_fp32=residual_in_fp32,
981
+ )
982
+
983
+
984
+ class LayerNormLinearFn(torch.autograd.Function):
985
+ @staticmethod
986
+ @custom_fwd
987
+ def forward(
988
+ ctx,
989
+ x,
990
+ norm_weight,
991
+ norm_bias,
992
+ linear_weight,
993
+ linear_bias,
994
+ residual=None,
995
+ eps=1e-6,
996
+ prenorm=False,
997
+ residual_in_fp32=False,
998
+ is_rms_norm=False,
999
+ ):
1000
+ x_shape_og = x.shape
1001
+ # reshape input data into 2D tensor
1002
+ x = x.reshape(-1, x.shape[-1])
1003
+ if x.stride(-1) != 1:
1004
+ x = x.contiguous()
1005
+ if residual is not None:
1006
+ assert residual.shape == x_shape_og
1007
+ residual = residual.reshape(-1, residual.shape[-1])
1008
+ if residual.stride(-1) != 1:
1009
+ residual = residual.contiguous()
1010
+ norm_weight = norm_weight.contiguous()
1011
+ if norm_bias is not None:
1012
+ norm_bias = norm_bias.contiguous()
1013
+ residual_dtype = (
1014
+ residual.dtype
1015
+ if residual is not None
1016
+ else (torch.float32 if residual_in_fp32 else None)
1017
+ )
1018
+ device_type = x.device.type
1019
+ y, _, mean, rstd, residual_out, *rest = _layer_norm_fwd(
1020
+ x,
1021
+ norm_weight,
1022
+ norm_bias,
1023
+ eps,
1024
+ residual,
1025
+ out_dtype=None if not torch.is_autocast_enabled(device_type) else torch.get_autocast_dtype(device_type),
1026
+ residual_dtype=residual_dtype,
1027
+ is_rms_norm=is_rms_norm,
1028
+ )
1029
+ y = y.reshape(x_shape_og)
1030
+ dtype = torch.get_autocast_dtype(device_type) if torch.is_autocast_enabled(device_type) else y.dtype
1031
+ linear_weight = linear_weight.to(dtype)
1032
+ linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
1033
+ out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
1034
+ # We don't store y, will be recomputed in the backward pass to save memory
1035
+ ctx.save_for_backward(residual_out, norm_weight, norm_bias, linear_weight, mean, rstd)
1036
+ ctx.x_shape_og = x_shape_og
1037
+ ctx.eps = eps
1038
+ ctx.is_rms_norm = is_rms_norm
1039
+ ctx.has_residual = residual is not None
1040
+ ctx.prenorm = prenorm
1041
+ ctx.x_dtype = x.dtype
1042
+ ctx.linear_bias_is_none = linear_bias is None
1043
+ return out if not prenorm else (out, residual_out.reshape(x_shape_og))
1044
+
1045
+ @staticmethod
1046
+ @custom_bwd
1047
+ def backward(ctx, dout, *args):
1048
+ x, norm_weight, norm_bias, linear_weight, mean, rstd = ctx.saved_tensors
1049
+ dout = dout.reshape(-1, dout.shape[-1])
1050
+ dy = F.linear(dout, linear_weight.t())
1051
+ dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
1052
+ if dy.stride(-1) != 1:
1053
+ dy = dy.contiguous()
1054
+ assert dy.shape == x.shape
1055
+ if ctx.prenorm:
1056
+ dresidual = args[0]
1057
+ dresidual = dresidual.reshape(-1, dresidual.shape[-1])
1058
+ if dresidual.stride(-1) != 1:
1059
+ dresidual = dresidual.contiguous()
1060
+ assert dresidual.shape == x.shape
1061
+ else:
1062
+ dresidual = None
1063
+ dx, dnorm_weight, dnorm_bias, dresidual_in, _, _, _, y = _layer_norm_bwd(
1064
+ dy,
1065
+ x,
1066
+ norm_weight,
1067
+ norm_bias,
1068
+ ctx.eps,
1069
+ mean,
1070
+ rstd,
1071
+ dresidual=dresidual,
1072
+ has_residual=ctx.has_residual,
1073
+ is_rms_norm=ctx.is_rms_norm,
1074
+ x_dtype=ctx.x_dtype,
1075
+ recompute_output=True,
1076
+ )
1077
+ dlinear_weight = torch.einsum("bo,bi->oi", dout, y)
1078
+ return (
1079
+ dx.reshape(ctx.x_shape_og),
1080
+ dnorm_weight,
1081
+ dnorm_bias,
1082
+ dlinear_weight,
1083
+ dlinear_bias,
1084
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
1085
+ None,
1086
+ None,
1087
+ None,
1088
+ None,
1089
+ )
1090
+
1091
+
1092
+ def layer_norm_linear_fn(
1093
+ x,
1094
+ norm_weight,
1095
+ norm_bias,
1096
+ linear_weight,
1097
+ linear_bias,
1098
+ residual=None,
1099
+ eps=1e-6,
1100
+ prenorm=False,
1101
+ residual_in_fp32=False,
1102
+ is_rms_norm=False,
1103
+ ):
1104
+ return LayerNormLinearFn.apply(
1105
+ x,
1106
+ norm_weight,
1107
+ norm_bias,
1108
+ linear_weight,
1109
+ linear_bias,
1110
+ residual,
1111
+ eps,
1112
+ prenorm,
1113
+ residual_in_fp32,
1114
+ is_rms_norm,
1115
+ )