bep40 commited on
Commit
e0a40f3
·
verified ·
1 Parent(s): 21d65ec

Fix: Add qwen_fa3_processor.py and update __init__.py

Browse files
qwenimage/__init__.py CHANGED
@@ -1,3 +1,2 @@
1
  from .pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
2
  from .transformer_qwenimage import QwenImageTransformer2DModel
3
- from .qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
 
1
  from .pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
2
  from .transformer_qwenimage import QwenImageTransformer2DModel
 
qwenimage/qwen_fa3_processor.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FA3 attention processor for Qwen-Image-Edit with SDPA fallback for Blackwell GPUs.
3
+ """
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from typing import Optional, Tuple
7
+ from diffusers.models.transformers.transformer_qwenimage import apply_rotary_emb_qwen
8
+
9
+ def _is_blackwell() -> bool:
10
+ if not torch.cuda.is_available():
11
+ return False
12
+ cap = torch.cuda.get_device_capability()
13
+ return cap[0] >= 10
14
+
15
+ _fa3_available = False
16
+ _fa3_unavailable_reason = ""
17
+ _flash_attn_func = None
18
+
19
+ if _is_blackwell():
20
+ _fa3_unavailable_reason = "FlashAttention-3 unsupported on Blackwell. Falling back to SDPA."
21
+ else:
22
+ try:
23
+ from kernels import get_kernel
24
+ _k = get_kernel("kernels-community/vllm-flash-attn3")
25
+ _flash_attn_func = _k.flash_attn_func
26
+ _fa3_available = True
27
+ except Exception as e:
28
+ _fa3_unavailable_reason = f"kernels unavailable: {e}. Falling back to SDPA."
29
+
30
+ if _fa3_available:
31
+ @torch.library.custom_op("flash::flash_attn_func", mutates_args=())
32
+ def flash_attn_func(q, k, v, causal=False):
33
+ output, _ = _flash_attn_func(q, k, v, causal=causal)
34
+ return output
35
+ @flash_attn_func.register_fake
36
+ def _fa_fake(q, k, v, causal=False):
37
+ return torch.empty_like(q).contiguous()
38
+ else:
39
+ def flash_attn_func(q, k, v, causal=False):
40
+ raise RuntimeError(_fa3_unavailable_reason)
41
+
42
+ def _sdpa_attention(q, k, v, causal=False):
43
+ return F.scaled_dot_product_attention(q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), is_causal=causal).transpose(1, 2)
44
+
45
+ class QwenDoubleStreamAttnProcessorFA3:
46
+ def __init__(self):
47
+ if _fa3_available:
48
+ self._attention_backend = "fa3"
49
+ else:
50
+ import warnings
51
+ warnings.warn(f"QwenDoubleStreamAttnProcessorFA3: {_fa3_unavailable_reason}")
52
+ self._attention_backend = "sdpa"
53
+
54
+ def _attend(self, q, k, v, causal=False):
55
+ if self._attention_backend == "fa3":
56
+ return flash_attn_func(q, k, v, causal=causal)
57
+ return _sdpa_attention(q, k, v, causal=causal)
58
+
59
+ @torch.no_grad()
60
+ def __call__(self, attn, hidden_states, encoder_hidden_states=None, encoder_hidden_states_mask=None, attention_mask=None, image_rotary_emb=None):
61
+ if encoder_hidden_states is None:
62
+ raise ValueError("QwenDoubleStreamAttnProcessorFA3 requires encoder_hidden_states.")
63
+ B, S_img, _ = hidden_states.shape
64
+ S_txt = encoder_hidden_states.shape[1]
65
+ img_q = attn.to_q(hidden_states).unflatten(-1, (attn.heads, -1))
66
+ img_k = attn.to_k(hidden_states).unflatten(-1, (attn.heads, -1))
67
+ img_v = attn.to_v(hidden_states).unflatten(-1, (attn.heads, -1))
68
+ txt_q = attn.add_q_proj(encoder_hidden_states).unflatten(-1, (attn.heads, -1))
69
+ txt_k = attn.add_k_proj(encoder_hidden_states).unflatten(-1, (attn.heads, -1))
70
+ txt_v = attn.add_v_proj(encoder_hidden_states).unflatten(-1, (attn.heads, -1))
71
+ if getattr(attn, "norm_q", None) is not None: img_q = attn.norm_q(img_q)
72
+ if getattr(attn, "norm_k", None) is not None: img_k = attn.norm_k(img_k)
73
+ if getattr(attn, "norm_added_q", None) is not None: txt_q = attn.norm_added_q(txt_q)
74
+ if getattr(attn, "norm_added_k", None) is not None: txt_k = attn.norm_added_k(txt_k)
75
+ if image_rotary_emb is not None:
76
+ img_freqs, txt_freqs = image_rotary_emb
77
+ img_q = apply_rotary_emb_qwen(img_q, img_freqs, use_real=False)
78
+ img_k = apply_rotary_emb_qwen(img_k, img_freqs, use_real=False)
79
+ txt_q = apply_rotary_emb_qwen(txt_q, txt_freqs, use_real=False)
80
+ txt_k = apply_rotary_emb_qwen(txt_k, txt_freqs, use_real=False)
81
+ q = torch.cat([txt_q, img_q], dim=1)
82
+ k = torch.cat([txt_k, img_k], dim=1)
83
+ v = torch.cat([txt_v, img_v], dim=1)
84
+ out = self._attend(q, k, v, causal=False).flatten(2, 3).to(q.dtype)
85
+ txt_attn_out = out[:, :S_txt, :]
86
+ img_attn_out = out[:, S_txt:, :]
87
+ img_attn_out = attn.to_out[0](img_attn_out)
88
+ if len(attn.to_out) > 1: img_attn_out = attn.to_out[1](img_attn_out)
89
+ txt_attn_out = attn.to_add_out(txt_attn_out)
90
+ return img_attn_out, txt_attn_out