comdoleger commited on
Commit
e899567
·
verified ·
1 Parent(s): dfa5bbf

Upload extensions_built_in/diffusion_models/omnigen2/src/models/attention_processor.py with huggingface_hub

Browse files
extensions_built_in/diffusion_models/omnigen2/src/models/attention_processor.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ OmniGen2 Attention Processor Module
3
+
4
+ Copyright 2025 BAAI, The OmniGen2 Team and The HuggingFace Team. All rights reserved.
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ """
18
+
19
+ import warnings
20
+ import math
21
+ from typing import Optional, Tuple, Dict, Any
22
+
23
+ import torch
24
+ import torch.nn.functional as F
25
+ from einops import repeat
26
+
27
+ from ..utils.import_utils import is_flash_attn_available
28
+
29
+ if is_flash_attn_available():
30
+ from flash_attn import flash_attn_varlen_func
31
+ from flash_attn.bert_padding import index_first_axis, pad_input, unpad_input
32
+ else:
33
+ warnings.warn("Cannot import flash_attn, install flash_attn to use Flash2Varlen attention for better performance")
34
+
35
+
36
+ from diffusers.models.attention_processor import Attention
37
+ from .embeddings import apply_rotary_emb
38
+
39
+
40
+ class OmniGen2AttnProcessorFlash2Varlen:
41
+ """
42
+ Processor for implementing scaled dot-product attention with flash attention and variable length sequences.
43
+
44
+ This processor implements:
45
+ - Flash attention with variable length sequences
46
+ - Rotary position embeddings (RoPE)
47
+ - Query-Key normalization
48
+ - Proportional attention scaling
49
+
50
+ Args:
51
+ None
52
+ """
53
+
54
+ def __init__(self) -> None:
55
+ """Initialize the attention processor."""
56
+ if not is_flash_attn_available():
57
+ raise ImportError(
58
+ "OmniGen2AttnProcessorFlash2Varlen requires flash_attn. "
59
+ "Please install flash_attn."
60
+ )
61
+
62
+ def _upad_input(
63
+ self,
64
+ query_layer: torch.Tensor,
65
+ key_layer: torch.Tensor,
66
+ value_layer: torch.Tensor,
67
+ attention_mask: torch.Tensor,
68
+ query_length: int,
69
+ num_heads: int,
70
+ ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, Tuple[torch.Tensor, torch.Tensor], Tuple[int, int]]:
71
+ """
72
+ Unpad the input tensors for flash attention.
73
+
74
+ Args:
75
+ query_layer: Query tensor of shape (batch_size, seq_len, num_heads, head_dim)
76
+ key_layer: Key tensor of shape (batch_size, seq_len, num_kv_heads, head_dim)
77
+ value_layer: Value tensor of shape (batch_size, seq_len, num_kv_heads, head_dim)
78
+ attention_mask: Attention mask tensor of shape (batch_size, seq_len)
79
+ query_length: Length of the query sequence
80
+ num_heads: Number of attention heads
81
+
82
+ Returns:
83
+ Tuple containing:
84
+ - Unpadded query tensor
85
+ - Unpadded key tensor
86
+ - Unpadded value tensor
87
+ - Query indices
88
+ - Tuple of cumulative sequence lengths for query and key
89
+ - Tuple of maximum sequence lengths for query and key
90
+ """
91
+ def _get_unpad_data(attention_mask: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, int]:
92
+ """Helper function to get unpadding data from attention mask."""
93
+ seqlens_in_batch = attention_mask.sum(dim=-1, dtype=torch.int32)
94
+ indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten()
95
+ max_seqlen_in_batch = seqlens_in_batch.max().item()
96
+ cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.int32), (1, 0))
97
+ return indices, cu_seqlens, max_seqlen_in_batch
98
+
99
+ indices_k, cu_seqlens_k, max_seqlen_in_batch_k = _get_unpad_data(attention_mask)
100
+ batch_size, kv_seq_len, num_key_value_heads, head_dim = key_layer.shape
101
+
102
+ # Unpad key and value layers
103
+ key_layer = index_first_axis(
104
+ key_layer.reshape(batch_size * kv_seq_len, num_key_value_heads, head_dim),
105
+ indices_k,
106
+ )
107
+ value_layer = index_first_axis(
108
+ value_layer.reshape(batch_size * kv_seq_len, num_key_value_heads, head_dim),
109
+ indices_k,
110
+ )
111
+
112
+ # Handle different query length cases
113
+ if query_length == kv_seq_len:
114
+ query_layer = index_first_axis(
115
+ query_layer.reshape(batch_size * kv_seq_len, num_heads, head_dim),
116
+ indices_k,
117
+ )
118
+ cu_seqlens_q = cu_seqlens_k
119
+ max_seqlen_in_batch_q = max_seqlen_in_batch_k
120
+ indices_q = indices_k
121
+ elif query_length == 1:
122
+ max_seqlen_in_batch_q = 1
123
+ cu_seqlens_q = torch.arange(
124
+ batch_size + 1, dtype=torch.int32, device=query_layer.device
125
+ )
126
+ indices_q = cu_seqlens_q[:-1]
127
+ query_layer = query_layer.squeeze(1)
128
+ else:
129
+ attention_mask = attention_mask[:, -query_length:]
130
+ query_layer, indices_q, cu_seqlens_q, max_seqlen_in_batch_q = unpad_input(query_layer, attention_mask)
131
+
132
+ return (
133
+ query_layer,
134
+ key_layer,
135
+ value_layer,
136
+ indices_q,
137
+ (cu_seqlens_q, cu_seqlens_k),
138
+ (max_seqlen_in_batch_q, max_seqlen_in_batch_k),
139
+ )
140
+
141
+ def __call__(
142
+ self,
143
+ attn: Attention,
144
+ hidden_states: torch.Tensor,
145
+ encoder_hidden_states: torch.Tensor,
146
+ attention_mask: Optional[torch.Tensor] = None,
147
+ image_rotary_emb: Optional[torch.Tensor] = None,
148
+ base_sequence_length: Optional[int] = None,
149
+ ) -> torch.Tensor:
150
+ """
151
+ Process attention computation with flash attention.
152
+
153
+ Args:
154
+ attn: Attention module
155
+ hidden_states: Hidden states tensor of shape (batch_size, seq_len, hidden_dim)
156
+ encoder_hidden_states: Encoder hidden states tensor
157
+ attention_mask: Optional attention mask tensor
158
+ image_rotary_emb: Optional rotary embeddings for image tokens
159
+ base_sequence_length: Optional base sequence length for proportional attention
160
+
161
+ Returns:
162
+ torch.Tensor: Processed hidden states after attention computation
163
+ """
164
+ batch_size, sequence_length, _ = hidden_states.shape
165
+
166
+ # Get Query-Key-Value Pair
167
+ query = attn.to_q(hidden_states)
168
+ key = attn.to_k(encoder_hidden_states)
169
+ value = attn.to_v(encoder_hidden_states)
170
+
171
+ query_dim = query.shape[-1]
172
+ inner_dim = key.shape[-1]
173
+ head_dim = query_dim // attn.heads
174
+ dtype = query.dtype
175
+
176
+ # Get key-value heads
177
+ kv_heads = inner_dim // head_dim
178
+
179
+ # Reshape tensors for attention computation
180
+ query = query.view(batch_size, -1, attn.heads, head_dim)
181
+ key = key.view(batch_size, -1, kv_heads, head_dim)
182
+ value = value.view(batch_size, -1, kv_heads, head_dim)
183
+
184
+ # Apply Query-Key normalization
185
+ if attn.norm_q is not None:
186
+ query = attn.norm_q(query)
187
+ if attn.norm_k is not None:
188
+ key = attn.norm_k(key)
189
+
190
+ # Apply Rotary Position Embeddings
191
+ if image_rotary_emb is not None:
192
+ query = apply_rotary_emb(query, image_rotary_emb, use_real=False)
193
+ key = apply_rotary_emb(key, image_rotary_emb, use_real=False)
194
+
195
+ query, key = query.to(dtype), key.to(dtype)
196
+
197
+ # Calculate attention scale
198
+ if base_sequence_length is not None:
199
+ softmax_scale = math.sqrt(math.log(sequence_length, base_sequence_length)) * attn.scale
200
+ else:
201
+ softmax_scale = attn.scale
202
+
203
+ # Unpad input for flash attention
204
+ (
205
+ query_states,
206
+ key_states,
207
+ value_states,
208
+ indices_q,
209
+ cu_seq_lens,
210
+ max_seq_lens,
211
+ ) = self._upad_input(query, key, value, attention_mask, sequence_length, attn.heads)
212
+
213
+ cu_seqlens_q, cu_seqlens_k = cu_seq_lens
214
+ max_seqlen_in_batch_q, max_seqlen_in_batch_k = max_seq_lens
215
+
216
+ # Handle different number of heads
217
+ if kv_heads < attn.heads:
218
+ key_states = repeat(key_states, "l h c -> l (h k) c", k=attn.heads // kv_heads)
219
+ value_states = repeat(value_states, "l h c -> l (h k) c", k=attn.heads // kv_heads)
220
+
221
+ # Apply flash attention
222
+ attn_output_unpad = flash_attn_varlen_func(
223
+ query_states,
224
+ key_states,
225
+ value_states,
226
+ cu_seqlens_q=cu_seqlens_q,
227
+ cu_seqlens_k=cu_seqlens_k,
228
+ max_seqlen_q=max_seqlen_in_batch_q,
229
+ max_seqlen_k=max_seqlen_in_batch_k,
230
+ dropout_p=0.0,
231
+ causal=False,
232
+ softmax_scale=softmax_scale,
233
+ )
234
+
235
+ # Pad output and apply final transformations
236
+ hidden_states = pad_input(attn_output_unpad, indices_q, batch_size, sequence_length)
237
+ hidden_states = hidden_states.flatten(-2)
238
+ hidden_states = hidden_states.type_as(query)
239
+
240
+ # Apply output projection
241
+ hidden_states = attn.to_out[0](hidden_states)
242
+ hidden_states = attn.to_out[1](hidden_states)
243
+
244
+ return hidden_states
245
+
246
+
247
+ class OmniGen2AttnProcessor:
248
+ """
249
+ Processor for implementing scaled dot-product attention with flash attention and variable length sequences.
250
+
251
+ This processor is optimized for PyTorch 2.0 and implements:
252
+ - Flash attention with variable length sequences
253
+ - Rotary position embeddings (RoPE)
254
+ - Query-Key normalization
255
+ - Proportional attention scaling
256
+
257
+ Args:
258
+ None
259
+
260
+ Raises:
261
+ ImportError: If PyTorch version is less than 2.0
262
+ """
263
+
264
+ def __init__(self) -> None:
265
+ """Initialize the attention processor."""
266
+ if not hasattr(F, "scaled_dot_product_attention"):
267
+ raise ImportError(
268
+ "OmniGen2AttnProcessorFlash2Varlen requires PyTorch 2.0. "
269
+ "Please upgrade PyTorch to version 2.0 or later."
270
+ )
271
+
272
+ def __call__(
273
+ self,
274
+ attn: Attention,
275
+ hidden_states: torch.Tensor,
276
+ encoder_hidden_states: torch.Tensor,
277
+ attention_mask: Optional[torch.Tensor] = None,
278
+ image_rotary_emb: Optional[torch.Tensor] = None,
279
+ base_sequence_length: Optional[int] = None,
280
+ ) -> torch.Tensor:
281
+ """
282
+ Process attention computation with flash attention.
283
+
284
+ Args:
285
+ attn: Attention module
286
+ hidden_states: Hidden states tensor of shape (batch_size, seq_len, hidden_dim)
287
+ encoder_hidden_states: Encoder hidden states tensor
288
+ attention_mask: Optional attention mask tensor
289
+ image_rotary_emb: Optional rotary embeddings for image tokens
290
+ base_sequence_length: Optional base sequence length for proportional attention
291
+
292
+ Returns:
293
+ torch.Tensor: Processed hidden states after attention computation
294
+ """
295
+ batch_size, sequence_length, _ = hidden_states.shape
296
+
297
+ # Get Query-Key-Value Pair
298
+ query = attn.to_q(hidden_states)
299
+ key = attn.to_k(encoder_hidden_states)
300
+ value = attn.to_v(encoder_hidden_states)
301
+
302
+ query_dim = query.shape[-1]
303
+ inner_dim = key.shape[-1]
304
+ head_dim = query_dim // attn.heads
305
+ dtype = query.dtype
306
+
307
+ # Get key-value heads
308
+ kv_heads = inner_dim // head_dim
309
+
310
+ # Reshape tensors for attention computation
311
+ query = query.view(batch_size, -1, attn.heads, head_dim)
312
+ key = key.view(batch_size, -1, kv_heads, head_dim)
313
+ value = value.view(batch_size, -1, kv_heads, head_dim)
314
+
315
+ # Apply Query-Key normalization
316
+ if attn.norm_q is not None:
317
+ query = attn.norm_q(query)
318
+ if attn.norm_k is not None:
319
+ key = attn.norm_k(key)
320
+
321
+ # Apply Rotary Position Embeddings
322
+ if image_rotary_emb is not None:
323
+ query = apply_rotary_emb(query, image_rotary_emb, use_real=False)
324
+ key = apply_rotary_emb(key, image_rotary_emb, use_real=False)
325
+
326
+ query, key = query.to(dtype), key.to(dtype)
327
+
328
+ # Calculate attention scale
329
+ if base_sequence_length is not None:
330
+ softmax_scale = math.sqrt(math.log(sequence_length, base_sequence_length)) * attn.scale
331
+ else:
332
+ softmax_scale = attn.scale
333
+
334
+ # scaled_dot_product_attention expects attention_mask shape to be
335
+ # (batch, heads, source_length, target_length)
336
+ if attention_mask is not None:
337
+ attention_mask = attention_mask.bool().view(batch_size, 1, 1, -1)
338
+
339
+ query = query.transpose(1, 2)
340
+ key = key.transpose(1, 2)
341
+ value = value.transpose(1, 2)
342
+
343
+ # explicitly repeat key and value to match query length, otherwise using enable_gqa=True results in MATH backend of sdpa in our test of pytorch2.6
344
+ key = key.repeat_interleave(query.size(-3) // key.size(-3), -3)
345
+ value = value.repeat_interleave(query.size(-3) // value.size(-3), -3)
346
+
347
+ hidden_states = F.scaled_dot_product_attention(
348
+ query, key, value, attn_mask=attention_mask, scale=softmax_scale
349
+ )
350
+ hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
351
+ hidden_states = hidden_states.type_as(query)
352
+
353
+ # Apply output projection
354
+ hidden_states = attn.to_out[0](hidden_states)
355
+ hidden_states = attn.to_out[1](hidden_states)
356
+
357
+ return hidden_states