diffsynth 2.1.12__py3-none-any.whl → 2.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffsynth/core/attention/__init__.py +2 -1
- diffsynth/core/attention/attention.py +36 -240
- diffsynth/core/attention/common.py +27 -0
- diffsynth/core/attention/flash_attention.py +118 -0
- diffsynth/core/attention/flex_attention.py +28 -0
- diffsynth/core/attention/registry.py +48 -0
- diffsynth/core/attention/sage_attention.py +20 -0
- diffsynth/core/attention/torch_attention.py +82 -0
- diffsynth/core/attention/xformers_attention.py +22 -0
- diffsynth/core/data/operators.py +11 -5
- diffsynth/core/data/unified_dataset.py +2 -1
- diffsynth/core/gradient/gradient_checkpoint.py +5 -6
- diffsynth/core/loader/config.py +2 -2
- diffsynth/core/loader/model.py +12 -4
- diffsynth/core/quant/backends/__init__.py +2 -0
- diffsynth/core/quant/backends/deep_gemm.py +618 -0
- diffsynth/models/minimax_h3_dit_vdn.py +1 -1
- diffsynth/version.py +1 -1
- {diffsynth-2.1.12.dist-info → diffsynth-2.2.0.dist-info}/METADATA +1 -1
- {diffsynth-2.1.12.dist-info → diffsynth-2.2.0.dist-info}/RECORD +23 -15
- {diffsynth-2.1.12.dist-info → diffsynth-2.2.0.dist-info}/WHEEL +0 -0
- {diffsynth-2.1.12.dist-info → diffsynth-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {diffsynth-2.1.12.dist-info → diffsynth-2.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1 +1,2 @@
|
|
|
1
|
-
from .attention import attention_forward,
|
|
1
|
+
from .attention import attention_forward, list_attention_implementations
|
|
2
|
+
from .flex_attention import FLEX_ATTN_AVAILABLE
|
|
@@ -1,255 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
else:
|
|
13
|
-
CUSTOMIZED_FA_KERNEL_AVAILABLE = False
|
|
14
|
-
|
|
15
|
-
try:
|
|
16
|
-
from flash_attn.cute import flash_attn_func as flash_attn_func_cute
|
|
17
|
-
FLASH_ATTN_4_AVAILABLE = True
|
|
18
|
-
except Exception:
|
|
19
|
-
FLASH_ATTN_4_AVAILABLE = False
|
|
20
|
-
|
|
21
|
-
try:
|
|
22
|
-
import flash_attn_interface
|
|
23
|
-
FLASH_ATTN_3_AVAILABLE = True
|
|
24
|
-
except Exception:
|
|
25
|
-
FLASH_ATTN_3_AVAILABLE = False
|
|
26
|
-
|
|
27
|
-
try:
|
|
28
|
-
import flash_attn
|
|
29
|
-
FLASH_ATTN_2_AVAILABLE = True
|
|
30
|
-
except Exception:
|
|
31
|
-
FLASH_ATTN_2_AVAILABLE = False
|
|
32
|
-
|
|
33
|
-
try:
|
|
34
|
-
from sageattention import sageattn
|
|
35
|
-
SAGE_ATTN_AVAILABLE = True
|
|
36
|
-
except Exception:
|
|
37
|
-
SAGE_ATTN_AVAILABLE = False
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
import xformers.ops as xops
|
|
41
|
-
XFORMERS_AVAILABLE = True
|
|
42
|
-
except Exception:
|
|
43
|
-
XFORMERS_AVAILABLE = False
|
|
44
|
-
|
|
45
|
-
try:
|
|
46
|
-
from torch.nn.attention.flex_attention import flex_attention as flex_attention_func
|
|
47
|
-
flex_attention_func = torch.compile(flex_attention_func)
|
|
48
|
-
FLEX_ATTN_AVAILABLE = True
|
|
49
|
-
except Exception:
|
|
50
|
-
FLEX_ATTN_AVAILABLE = False
|
|
51
|
-
|
|
52
|
-
try:
|
|
53
|
-
if "enable_gqa" in inspect.signature(torch.nn.functional.scaled_dot_product_attention).parameters:
|
|
54
|
-
TORCH_SUPPORT_GQA = True
|
|
55
|
-
else:
|
|
56
|
-
TORCH_SUPPORT_GQA = False
|
|
57
|
-
except Exception:
|
|
58
|
-
TORCH_SUPPORT_GQA = False
|
|
1
|
+
import os
|
|
2
|
+
from .registry import (
|
|
3
|
+
get_attention_implementation,
|
|
4
|
+
list_attention_implementations,
|
|
5
|
+
register_attention_implementation,
|
|
6
|
+
)
|
|
7
|
+
from .flash_attention import CUSTOMIZED_FA_KERNEL_AVAILABLE, FLASH_ATTN_4_AVAILABLE, FLASH_ATTN_3_AVAILABLE, FLASH_ATTN_2_AVAILABLE
|
|
8
|
+
from .sage_attention import SAGE_ATTN_AVAILABLE
|
|
9
|
+
from .xformers_attention import XFORMERS_AVAILABLE
|
|
10
|
+
from .torch_attention import torch_sdpa, torch_sdpa_sliding_window
|
|
11
|
+
from .flex_attention import flex_attention
|
|
59
12
|
|
|
60
13
|
|
|
61
14
|
def initialize_attention_priority():
|
|
62
15
|
if os.environ.get('DIFFSYNTH_ATTENTION_IMPLEMENTATION') is not None:
|
|
63
|
-
return os.environ.get('DIFFSYNTH_ATTENTION_IMPLEMENTATION').lower()
|
|
64
|
-
elif CUSTOMIZED_FA_KERNEL_AVAILABLE:
|
|
65
|
-
return "customized_fa_kernel"
|
|
66
|
-
elif FLASH_ATTN_4_AVAILABLE:
|
|
67
|
-
return "flash_attention_4"
|
|
68
|
-
elif FLASH_ATTN_3_AVAILABLE:
|
|
69
|
-
return "flash_attention_3"
|
|
70
|
-
elif FLASH_ATTN_2_AVAILABLE:
|
|
71
|
-
return "flash_attention_2"
|
|
72
|
-
elif SAGE_ATTN_AVAILABLE:
|
|
73
|
-
return "sage_attention"
|
|
74
|
-
elif XFORMERS_AVAILABLE:
|
|
75
|
-
return "xformers"
|
|
16
|
+
return os.environ.get('DIFFSYNTH_ATTENTION_IMPLEMENTATION').strip().lower()
|
|
76
17
|
else:
|
|
18
|
+
for name in ["customized_fa_kernel", "flash_attention_4", "flash_attention_3", "flash_attention_2", "sage_attention", "xformers"]:
|
|
19
|
+
if name in list_attention_implementations():
|
|
20
|
+
return name
|
|
77
21
|
return "torch"
|
|
78
22
|
|
|
79
23
|
|
|
80
24
|
ATTENTION_IMPLEMENTATION = initialize_attention_priority()
|
|
81
25
|
|
|
82
26
|
|
|
83
|
-
def
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
q = rearrange(q, f"{q_pattern} -> {required_in_pattern}", **dims)
|
|
87
|
-
if k_pattern != required_in_pattern:
|
|
88
|
-
k = rearrange(k, f"{k_pattern} -> {required_in_pattern}", **dims)
|
|
89
|
-
if v_pattern != required_in_pattern:
|
|
90
|
-
v = rearrange(v, f"{v_pattern} -> {required_in_pattern}", **dims)
|
|
91
|
-
return q, k, v
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def rearrange_out(out: torch.Tensor, out_pattern="b n s d", required_out_pattern="b n s d", dims=None):
|
|
95
|
-
dims = {} if dims is None else dims
|
|
96
|
-
if out_pattern != required_out_pattern:
|
|
97
|
-
out = rearrange(out, f"{required_out_pattern} -> {out_pattern}", **dims)
|
|
98
|
-
return out
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def torch_sdpa(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, is_causal=False):
|
|
102
|
-
required_in_pattern, required_out_pattern= "b n s d", "b n s d"
|
|
103
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
104
|
-
if q.shape[1] != k.shape[1] or q.shape[1] != v.shape[1]:
|
|
105
|
-
# Grouped Query Attention
|
|
106
|
-
if TORCH_SUPPORT_GQA:
|
|
107
|
-
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal, enable_gqa=True)
|
|
108
|
-
else:
|
|
109
|
-
# In low-version torch, `enable_gqa` is not supported.
|
|
110
|
-
k = repeat(k, "b n s d -> b (n m) s d", m=q.shape[1]//k.shape[1])
|
|
111
|
-
v = repeat(v, "b n s d -> b (n m) s d", m=q.shape[1]//v.shape[1])
|
|
112
|
-
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal)
|
|
113
|
-
else:
|
|
114
|
-
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal)
|
|
115
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
116
|
-
return out
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def torch_sdpa_sliding_window(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, sliding_window: int, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
120
|
-
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
121
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
122
|
-
|
|
123
|
-
B, N, S, D = q.shape
|
|
124
|
-
W = sliding_window
|
|
125
|
-
chunk_size = W
|
|
126
|
-
num_chunks = (S + chunk_size - 1) // chunk_size
|
|
127
|
-
|
|
128
|
-
output = torch.empty_like(q)
|
|
129
|
-
dtype = q.dtype
|
|
130
|
-
device = q.device
|
|
131
|
-
min_val = torch.finfo(dtype).min
|
|
132
|
-
|
|
133
|
-
for i in range(num_chunks):
|
|
134
|
-
q_start = i * chunk_size
|
|
135
|
-
q_end = min(q_start + chunk_size, S)
|
|
136
|
-
actual_chunk_size = q_end - q_start
|
|
27
|
+
def attention_forward(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, is_causal=False, compatibility_mode=False, window_size=None, use_flex=False, score_mod=None):
|
|
28
|
+
if use_flex or score_mod is not None:
|
|
29
|
+
return flex_attention(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, score_mod=score_mod)
|
|
137
30
|
|
|
138
|
-
|
|
139
|
-
|
|
31
|
+
if compatibility_mode:
|
|
32
|
+
return torch_sdpa(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
140
33
|
|
|
141
|
-
|
|
142
|
-
k_chunk = k[:, :, kv_start:kv_end, :]
|
|
143
|
-
v_chunk = v[:, :, kv_start:kv_end, :]
|
|
34
|
+
backend = get_attention_implementation(ATTENTION_IMPLEMENTATION)
|
|
144
35
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
36
|
+
if attn_mask is not None and not backend.supports_mask:
|
|
37
|
+
return torch_sdpa(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, is_causal=is_causal)
|
|
38
|
+
if window_size is not None and not backend.supports_window:
|
|
39
|
+
assert is_causal == False and attn_mask is None
|
|
40
|
+
return torch_sdpa_sliding_window(q, k, v, window_size, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
41
|
+
if is_causal and not backend.supports_causal:
|
|
42
|
+
return torch_sdpa(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, is_causal=is_causal)
|
|
149
43
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
output = rearrange_out(output, out_pattern, required_out_pattern, dims)
|
|
160
|
-
return output
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def flash_attention_4(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
164
|
-
required_in_pattern, required_out_pattern= "b s n d", "b s n d"
|
|
165
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
166
|
-
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
167
|
-
out = flash_attn_func_cute(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
168
|
-
if isinstance(out, tuple):
|
|
169
|
-
out = out[0]
|
|
170
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
171
|
-
return out
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def flash_attention_3(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
175
|
-
required_in_pattern, required_out_pattern= "b s n d", "b s n d"
|
|
176
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
177
|
-
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
178
|
-
out = flash_attn_interface.flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
179
|
-
if isinstance(out, tuple):
|
|
180
|
-
out = out[0]
|
|
181
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
182
|
-
return out
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def flash_attention_2(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
186
|
-
required_in_pattern, required_out_pattern= "b s n d", "b s n d"
|
|
187
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
188
|
-
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
189
|
-
out = flash_attn.flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
190
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
191
|
-
return out
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def flash_attention_customized_kernel(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
195
|
-
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
196
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
197
|
-
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
198
|
-
out = customized_flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
199
|
-
if isinstance(out, tuple):
|
|
200
|
-
out = out[0]
|
|
201
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
202
|
-
return out
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
def sage_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
206
|
-
required_in_pattern, required_out_pattern= "b n s d", "b n s d"
|
|
207
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
208
|
-
out = sageattn(q, k, v, sm_scale=scale)
|
|
209
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
210
|
-
return out
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def xformers_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
214
|
-
required_in_pattern, required_out_pattern= "b s n d", "b s n d"
|
|
215
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
216
|
-
out = xops.memory_efficient_attention(q, k, v, scale=scale)
|
|
217
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
218
|
-
return out
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def flex_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, score_mod=None):
|
|
222
|
-
assert FLEX_ATTN_AVAILABLE, "Flex Attention is not available. Please upgrade torch to 2.5.0 or later."
|
|
223
|
-
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
224
|
-
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
225
|
-
out = flex_attention_func(query=q, key=k, value=v, block_mask=attn_mask, scale=scale, score_mod=score_mod)
|
|
226
|
-
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
227
|
-
return out
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def attention_forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, is_causal=False, compatibility_mode=False, window_size=None, use_flex=False, score_mod=None):
|
|
231
|
-
if compatibility_mode or (attn_mask is not None) or ATTENTION_IMPLEMENTATION == "torch":
|
|
232
|
-
if use_flex or score_mod is not None:
|
|
233
|
-
return flex_attention(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, score_mod=score_mod)
|
|
234
|
-
elif window_size is None:
|
|
235
|
-
return torch_sdpa(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask=attn_mask, scale=scale, is_causal=is_causal)
|
|
236
|
-
else:
|
|
237
|
-
# Sliding Window Attention is not compatible with `is_causal` and `attn_mask`.
|
|
238
|
-
assert is_causal == False and attn_mask is None
|
|
239
|
-
return torch_sdpa_sliding_window(q, k, v, window_size, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
240
|
-
elif ATTENTION_IMPLEMENTATION == "customized_fa_kernel":
|
|
241
|
-
return flash_attention_customized_kernel(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
242
|
-
elif ATTENTION_IMPLEMENTATION == "flash_attention_4":
|
|
243
|
-
return flash_attention_4(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
244
|
-
elif ATTENTION_IMPLEMENTATION == "flash_attention_3":
|
|
245
|
-
return flash_attention_3(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
246
|
-
elif ATTENTION_IMPLEMENTATION == "flash_attention_2":
|
|
247
|
-
return flash_attention_2(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale, is_causal=is_causal, window_size=window_size)
|
|
248
|
-
elif ATTENTION_IMPLEMENTATION == "sage_attention":
|
|
249
|
-
if window_size is not None or is_causal: return attention_forward(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask, scale, is_causal, compatibility_mode=True, window_size=window_size)
|
|
250
|
-
return sage_attention(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
251
|
-
elif ATTENTION_IMPLEMENTATION == "xformers":
|
|
252
|
-
if window_size is not None or is_causal: return attention_forward(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, attn_mask, scale, is_causal, compatibility_mode=True, window_size=window_size)
|
|
253
|
-
return xformers_attention(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
254
|
-
else:
|
|
255
|
-
raise NotImplementedError("No available attention implementation.")
|
|
44
|
+
kwargs = {"scale": scale}
|
|
45
|
+
if backend.supports_causal:
|
|
46
|
+
kwargs["is_causal"] = is_causal
|
|
47
|
+
if backend.supports_mask:
|
|
48
|
+
kwargs["attn_mask"] = attn_mask
|
|
49
|
+
if backend.supports_window:
|
|
50
|
+
kwargs["window_size"] = window_size
|
|
51
|
+
return backend.func(q, k, v, q_pattern, k_pattern, v_pattern, out_pattern, dims, **kwargs)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from einops import rearrange
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
TORCH_SUPPORT_GQA = "enable_gqa" in inspect.signature(torch.nn.functional.scaled_dot_product_attention).parameters
|
|
8
|
+
except Exception:
|
|
9
|
+
TORCH_SUPPORT_GQA = False
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def rearrange_qkv(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", required_in_pattern="b n s d", dims=None):
|
|
13
|
+
dims = {} if dims is None else dims
|
|
14
|
+
if q_pattern != required_in_pattern:
|
|
15
|
+
q = rearrange(q, f"{q_pattern} -> {required_in_pattern}", **dims)
|
|
16
|
+
if k_pattern != required_in_pattern:
|
|
17
|
+
k = rearrange(k, f"{k_pattern} -> {required_in_pattern}", **dims)
|
|
18
|
+
if v_pattern != required_in_pattern:
|
|
19
|
+
v = rearrange(v, f"{v_pattern} -> {required_in_pattern}", **dims)
|
|
20
|
+
return q, k, v
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def rearrange_out(out: torch.Tensor, out_pattern="b n s d", required_out_pattern="b n s d", dims=None):
|
|
24
|
+
dims = {} if dims is None else dims
|
|
25
|
+
if out_pattern != required_out_pattern:
|
|
26
|
+
out = rearrange(out, f"{required_out_pattern} -> {out_pattern}", **dims)
|
|
27
|
+
return out
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from .common import rearrange_qkv, rearrange_out
|
|
4
|
+
from .registry import register_attention_implementation
|
|
5
|
+
|
|
6
|
+
if os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_REPO_ID") is not None:
|
|
7
|
+
try:
|
|
8
|
+
from kernels import get_kernel
|
|
9
|
+
kernel_module = get_kernel(os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_REPO_ID"), version=int(os.environ.get("DIFFSYNTH_FLASH_ATTN_KERNEL_VERSION")))
|
|
10
|
+
customized_flash_attn_func = kernel_module.flash_attn_func
|
|
11
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = True
|
|
12
|
+
except Exception:
|
|
13
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = False
|
|
14
|
+
else:
|
|
15
|
+
CUSTOMIZED_FA_KERNEL_AVAILABLE = False
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from flash_attn.cute import flash_attn_func as flash_attn_func_cute
|
|
19
|
+
FLASH_ATTN_4_AVAILABLE = True
|
|
20
|
+
except Exception:
|
|
21
|
+
FLASH_ATTN_4_AVAILABLE = False
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from flash_attn_3 import flash_attn_interface
|
|
25
|
+
FLASH_ATTN_3_AVAILABLE = True
|
|
26
|
+
except Exception:
|
|
27
|
+
FLASH_ATTN_3_AVAILABLE = False
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
import flash_attn
|
|
31
|
+
FLASH_ATTN_2_AVAILABLE = hasattr(flash_attn, "flash_attn_func")
|
|
32
|
+
except Exception:
|
|
33
|
+
FLASH_ATTN_2_AVAILABLE = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _require(flag, name):
|
|
37
|
+
if not flag:
|
|
38
|
+
raise RuntimeError(f"{name} is not available.")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def flash_attention_4(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
42
|
+
_require(FLASH_ATTN_4_AVAILABLE, "FlashAttention-4")
|
|
43
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
44
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
45
|
+
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
46
|
+
out = flash_attn_func_cute(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
47
|
+
if isinstance(out, tuple):
|
|
48
|
+
out = out[0]
|
|
49
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
50
|
+
return out
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def flash_attention_3(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
54
|
+
_require(FLASH_ATTN_3_AVAILABLE, "FlashAttention-3")
|
|
55
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
56
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
57
|
+
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
58
|
+
out = flash_attn_interface.flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
59
|
+
if isinstance(out, tuple):
|
|
60
|
+
out = out[0]
|
|
61
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
62
|
+
return out
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def flash_attention_2(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
66
|
+
_require(FLASH_ATTN_2_AVAILABLE, "FlashAttention-2")
|
|
67
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
68
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
69
|
+
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
70
|
+
out = flash_attn.flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
71
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
72
|
+
return out
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def flash_attention_customized_kernel(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None, is_causal=False, window_size=None):
|
|
76
|
+
_require(CUSTOMIZED_FA_KERNEL_AVAILABLE, "customized FlashAttention kernel")
|
|
77
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
78
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
79
|
+
window_size = (window_size, window_size) if window_size is not None else (-1, -1)
|
|
80
|
+
out = customized_flash_attn_func(q, k, v, softmax_scale=scale, causal=is_causal, window_size=window_size)
|
|
81
|
+
if isinstance(out, tuple):
|
|
82
|
+
out = out[0]
|
|
83
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
84
|
+
return out
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if CUSTOMIZED_FA_KERNEL_AVAILABLE:
|
|
88
|
+
register_attention_implementation(
|
|
89
|
+
"customized_fa_kernel",
|
|
90
|
+
flash_attention_customized_kernel,
|
|
91
|
+
supports_causal=True,
|
|
92
|
+
supports_window=True,
|
|
93
|
+
supports_gqa=True,
|
|
94
|
+
)
|
|
95
|
+
if FLASH_ATTN_4_AVAILABLE:
|
|
96
|
+
register_attention_implementation(
|
|
97
|
+
"flash_attention_4",
|
|
98
|
+
flash_attention_4,
|
|
99
|
+
supports_causal=True,
|
|
100
|
+
supports_window=True,
|
|
101
|
+
supports_gqa=True,
|
|
102
|
+
)
|
|
103
|
+
if FLASH_ATTN_3_AVAILABLE:
|
|
104
|
+
register_attention_implementation(
|
|
105
|
+
"flash_attention_3",
|
|
106
|
+
flash_attention_3,
|
|
107
|
+
supports_causal=True,
|
|
108
|
+
supports_window=True,
|
|
109
|
+
supports_gqa=True,
|
|
110
|
+
)
|
|
111
|
+
if FLASH_ATTN_2_AVAILABLE:
|
|
112
|
+
register_attention_implementation(
|
|
113
|
+
"flash_attention_2",
|
|
114
|
+
flash_attention_2,
|
|
115
|
+
supports_causal=True,
|
|
116
|
+
supports_window=True,
|
|
117
|
+
supports_gqa=True,
|
|
118
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
|
|
3
|
+
from .common import rearrange_qkv, rearrange_out
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from torch.nn.attention.flex_attention import flex_attention as _flex_attention_func
|
|
7
|
+
FLEX_ATTN_AVAILABLE = True
|
|
8
|
+
except Exception:
|
|
9
|
+
FLEX_ATTN_AVAILABLE = False
|
|
10
|
+
|
|
11
|
+
# Compile flex attention lazily
|
|
12
|
+
_compiled_flex_attention_func = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_flex_attention_func():
|
|
16
|
+
global _compiled_flex_attention_func
|
|
17
|
+
if _compiled_flex_attention_func is None:
|
|
18
|
+
_compiled_flex_attention_func = torch.compile(_flex_attention_func)
|
|
19
|
+
return _compiled_flex_attention_func
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def flex_attention(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, score_mod=None):
|
|
23
|
+
assert FLEX_ATTN_AVAILABLE, "Flex Attention is not available. Please upgrade torch to 2.5.0 or later."
|
|
24
|
+
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
25
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
26
|
+
out = get_flex_attention_func()(query=q, key=k, value=v, block_mask=attn_mask, scale=scale, score_mod=score_mod)
|
|
27
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
28
|
+
return out
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Callable, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass(frozen=True)
|
|
6
|
+
class AttentionBackend:
|
|
7
|
+
func: Callable
|
|
8
|
+
supports_causal: bool = False
|
|
9
|
+
supports_window: bool = False
|
|
10
|
+
supports_mask: bool = False
|
|
11
|
+
supports_gqa: bool = False
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_ATTENTION_BACKENDS = {}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def register_attention_implementation(
|
|
18
|
+
name: str,
|
|
19
|
+
func: Optional[Callable] = None,
|
|
20
|
+
supports_causal: bool = False,
|
|
21
|
+
supports_window: bool = False,
|
|
22
|
+
supports_mask: bool = False,
|
|
23
|
+
supports_gqa: bool = False,
|
|
24
|
+
):
|
|
25
|
+
key = name.strip().lower()
|
|
26
|
+
_ATTENTION_BACKENDS[key] = AttentionBackend(
|
|
27
|
+
func=func,
|
|
28
|
+
supports_causal=supports_causal,
|
|
29
|
+
supports_window=supports_window,
|
|
30
|
+
supports_mask=supports_mask,
|
|
31
|
+
supports_gqa=supports_gqa,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_attention_implementation(name: str) -> AttentionBackend:
|
|
36
|
+
key = name.strip().lower()
|
|
37
|
+
if key not in _ATTENTION_BACKENDS:
|
|
38
|
+
available = ", ".join(list_attention_implementations()) or "none"
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"Unknown attention implementation: {name!r}. "
|
|
41
|
+
f"Available implementations: {available}. "
|
|
42
|
+
f"Please check the environment variable `DIFFSYNTH_ATTENTION_IMPLEMENTATION`."
|
|
43
|
+
)
|
|
44
|
+
return _ATTENTION_BACKENDS[key]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def list_attention_implementations():
|
|
48
|
+
return sorted(_ATTENTION_BACKENDS)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from .common import rearrange_qkv, rearrange_out
|
|
2
|
+
from .registry import register_attention_implementation
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
from sageattention import sageattn
|
|
6
|
+
SAGE_ATTN_AVAILABLE = True
|
|
7
|
+
except Exception:
|
|
8
|
+
SAGE_ATTN_AVAILABLE = False
|
|
9
|
+
|
|
10
|
+
def sage_attention(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
11
|
+
if not SAGE_ATTN_AVAILABLE:
|
|
12
|
+
raise RuntimeError("SageAttention is not available.")
|
|
13
|
+
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
14
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
15
|
+
out = sageattn(q, k, v, sm_scale=scale)
|
|
16
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
17
|
+
return out
|
|
18
|
+
|
|
19
|
+
if SAGE_ATTN_AVAILABLE:
|
|
20
|
+
register_attention_implementation("sage_attention", sage_attention)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from einops import repeat
|
|
3
|
+
|
|
4
|
+
from .common import TORCH_SUPPORT_GQA, rearrange_qkv, rearrange_out
|
|
5
|
+
from .registry import register_attention_implementation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def torch_sdpa(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, attn_mask=None, scale=None, is_causal=False, window_size=None):
|
|
9
|
+
if window_size is not None:
|
|
10
|
+
if is_causal or attn_mask is not None:
|
|
11
|
+
raise ValueError("Sliding window attention does not support `is_causal=True` or `attn_mask`.")
|
|
12
|
+
return torch_sdpa_sliding_window(q, k, v, window_size, q_pattern, k_pattern, v_pattern, out_pattern, dims, scale=scale)
|
|
13
|
+
|
|
14
|
+
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
15
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
16
|
+
if q.shape[1] != k.shape[1] or q.shape[1] != v.shape[1]:
|
|
17
|
+
# Grouped Query Attention
|
|
18
|
+
if TORCH_SUPPORT_GQA:
|
|
19
|
+
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal, enable_gqa=True)
|
|
20
|
+
else:
|
|
21
|
+
# In low-version torch, `enable_gqa` is not supported.
|
|
22
|
+
k = repeat(k, "b n s d -> b (n m) s d", m=q.shape[1]//k.shape[1])
|
|
23
|
+
v = repeat(v, "b n s d -> b (n m) s d", m=q.shape[1]//v.shape[1])
|
|
24
|
+
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal)
|
|
25
|
+
else:
|
|
26
|
+
out = torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_mask, scale=scale, is_causal=is_causal)
|
|
27
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
28
|
+
return out
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def torch_sdpa_sliding_window(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, sliding_window: int, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
32
|
+
required_in_pattern, required_out_pattern = "b n s d", "b n s d"
|
|
33
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
34
|
+
|
|
35
|
+
B, N, S, D = q.shape
|
|
36
|
+
W = sliding_window
|
|
37
|
+
chunk_size = W
|
|
38
|
+
num_chunks = (S + chunk_size - 1) // chunk_size
|
|
39
|
+
|
|
40
|
+
output = torch.empty_like(q)
|
|
41
|
+
dtype = q.dtype
|
|
42
|
+
device = q.device
|
|
43
|
+
min_val = torch.finfo(dtype).min
|
|
44
|
+
|
|
45
|
+
for i in range(num_chunks):
|
|
46
|
+
q_start = i * chunk_size
|
|
47
|
+
q_end = min(q_start + chunk_size, S)
|
|
48
|
+
actual_chunk_size = q_end - q_start
|
|
49
|
+
|
|
50
|
+
kv_start = max(0, q_start - W)
|
|
51
|
+
kv_end = min(S, q_end + W)
|
|
52
|
+
|
|
53
|
+
q_chunk = q[:, :, q_start:q_end, :]
|
|
54
|
+
k_chunk = k[:, :, kv_start:kv_end, :]
|
|
55
|
+
v_chunk = v[:, :, kv_start:kv_end, :]
|
|
56
|
+
|
|
57
|
+
q_indices = torch.arange(q_start, q_end, device=device)
|
|
58
|
+
k_indices = torch.arange(kv_start, kv_end, device=device)
|
|
59
|
+
diff = q_indices.unsqueeze(1) - k_indices.unsqueeze(0)
|
|
60
|
+
valid = diff.abs() <= W
|
|
61
|
+
|
|
62
|
+
local_mask = torch.zeros(actual_chunk_size, kv_end - kv_start, dtype=dtype, device=device)
|
|
63
|
+
local_mask.masked_fill_(~valid, min_val)
|
|
64
|
+
local_mask = local_mask.unsqueeze(0).unsqueeze(0)
|
|
65
|
+
|
|
66
|
+
out_chunk = torch_sdpa(
|
|
67
|
+
q_chunk, k_chunk, v_chunk, attn_mask=local_mask, scale=scale
|
|
68
|
+
)
|
|
69
|
+
output[:, :, q_start:q_end, :] = out_chunk
|
|
70
|
+
|
|
71
|
+
output = rearrange_out(output, out_pattern, required_out_pattern, dims)
|
|
72
|
+
return output
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
register_attention_implementation(
|
|
76
|
+
"torch",
|
|
77
|
+
torch_sdpa,
|
|
78
|
+
supports_window=True,
|
|
79
|
+
supports_causal=True,
|
|
80
|
+
supports_mask=True,
|
|
81
|
+
supports_gqa=True,
|
|
82
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from .common import rearrange_qkv, rearrange_out
|
|
2
|
+
from .registry import register_attention_implementation
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import xformers.ops as xops
|
|
6
|
+
XFORMERS_AVAILABLE = True
|
|
7
|
+
except Exception:
|
|
8
|
+
XFORMERS_AVAILABLE = False
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def xformers_attention(q, k, v, q_pattern="b n s d", k_pattern="b n s d", v_pattern="b n s d", out_pattern="b n s d", dims=None, scale=None):
|
|
12
|
+
if not XFORMERS_AVAILABLE:
|
|
13
|
+
raise RuntimeError("xformers is not available.")
|
|
14
|
+
required_in_pattern, required_out_pattern = "b s n d", "b s n d"
|
|
15
|
+
q, k, v = rearrange_qkv(q, k, v, q_pattern, k_pattern, v_pattern, required_in_pattern, dims)
|
|
16
|
+
out = xops.memory_efficient_attention(q, k, v, scale=scale)
|
|
17
|
+
out = rearrange_out(out, out_pattern, required_out_pattern, dims)
|
|
18
|
+
return out
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if XFORMERS_AVAILABLE:
|
|
22
|
+
register_attention_implementation("xformers", xformers_attention)
|