fix: fa3 broken on Blackwell+

#1
by raphael-gl HF Staff - opened
Files changed (1) hide show
  1. qwenimage/qwen_fa3_processor.py +34 -19
qwenimage/qwen_fa3_processor.py CHANGED
@@ -6,22 +6,40 @@ import torch
6
  from typing import Optional, Tuple
7
  from diffusers.models.transformers.transformer_qwenimage import apply_rotary_emb_qwen
8
 
 
 
 
 
 
9
  try:
10
  from kernels import get_kernel
11
- _k = get_kernel("kernels-community/vllm-flash-attn3")
12
- _flash_attn_func = _k.flash_attn_func
 
 
 
 
 
 
 
 
13
  except Exception as e:
14
  _flash_attn_func = None
15
  _kernels_err = e
16
 
17
 
18
- def _ensure_fa3_available():
19
- if _flash_attn_func is None:
20
- raise ImportError(
21
- "FlashAttention-3 via Hugging Face `kernels` is required. "
22
- "Tried `get_kernel('kernels-community/vllm-flash-attn3')` and failed with:\n"
23
- f"{_kernels_err}"
24
- )
 
 
 
 
 
25
 
26
  @torch.library.custom_op("flash::flash_attn_func", mutates_args=())
27
  def flash_attn_func(
@@ -32,11 +50,7 @@ def flash_attn_func(
32
 
33
  @flash_attn_func.register_fake
34
  def _(q, k, v, **kwargs):
35
- # two outputs:
36
- # 1. output: (batch, seq_len, num_heads, head_dim)
37
- # 2. softmax_lse: (batch, num_heads, seq_len) with dtype=torch.float32
38
- meta_q = torch.empty_like(q).contiguous()
39
- return meta_q #, q.new_empty((q.size(0), q.size(2), q.size(1)), dtype=torch.float32)
40
 
41
 
42
  class QwenDoubleStreamAttnProcessorFA3:
@@ -54,7 +68,8 @@ class QwenDoubleStreamAttnProcessorFA3:
54
  _attention_backend = "fa3" # for parity with your other processors, not used internally
55
 
56
  def __init__(self):
57
- _ensure_fa3_available()
 
58
 
59
  @torch.no_grad()
60
  def __call__(
@@ -72,8 +87,6 @@ class QwenDoubleStreamAttnProcessorFA3:
72
  # FA3 kernel path here does not consume arbitrary masks; fail fast to avoid silent correctness issues.
73
  raise NotImplementedError("attention_mask is not supported in this FA3 implementation.")
74
 
75
- _ensure_fa3_available()
76
-
77
  B, S_img, _ = hidden_states.shape
78
  S_txt = encoder_hidden_states.shape[1]
79
 
@@ -122,8 +135,10 @@ class QwenDoubleStreamAttnProcessorFA3:
122
  k = torch.cat([txt_k, img_k], dim=1)
123
  v = torch.cat([txt_v, img_v], dim=1)
124
 
125
- # FlashAttention-3 path expects (B, S, H, D_h) and returns (out, softmax_lse)
126
- out = flash_attn_func(q, k, v, causal=False) # out: (B, S_total, H, D_h)
 
 
127
 
128
  # ---- Back to (B, S, D_model) ----
129
  out = out.flatten(2, 3).to(q.dtype)
 
6
  from typing import Optional, Tuple
7
  from diffusers.models.transformers.transformer_qwenimage import apply_rotary_emb_qwen
8
 
9
+ import torch.nn.functional as F
10
+
11
+ _flash_attn_func = None
12
+ _kernels_err = None
13
+
14
  try:
15
  from kernels import get_kernel
16
+ # Blackwell (sm_120+) is not yet supported by the vllm-flash-attn3 kernel binary
17
+ _cap = torch.cuda.get_device_capability() if torch.cuda.is_available() else (0, 0)
18
+ if _cap >= (12, 0):
19
+ _kernels_err = RuntimeError(
20
+ f"GPU compute capability sm_{_cap[0]}{_cap[1]} (Blackwell+) is not supported "
21
+ "by the kernels-community/vllm-flash-attn3 binary; using SDPA fallback."
22
+ )
23
+ else:
24
+ _k = get_kernel("kernels-community/vllm-flash-attn3")
25
+ _flash_attn_func = _k.flash_attn_func
26
  except Exception as e:
27
  _flash_attn_func = None
28
  _kernels_err = e
29
 
30
 
31
+ def _fa3_available() -> bool:
32
+ return _flash_attn_func is not None
33
+
34
+
35
+ def _sdpa_fallback(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
36
+ # q/k/v: (B, S, H, D_h) → SDPA expects (B, H, S, D_h)
37
+ q = q.transpose(1, 2)
38
+ k = k.transpose(1, 2)
39
+ v = v.transpose(1, 2)
40
+ out = F.scaled_dot_product_attention(q, k, v, is_causal=False)
41
+ return out.transpose(1, 2) # back to (B, S, H, D_h)
42
+
43
 
44
  @torch.library.custom_op("flash::flash_attn_func", mutates_args=())
45
  def flash_attn_func(
 
50
 
51
  @flash_attn_func.register_fake
52
  def _(q, k, v, **kwargs):
53
+ return torch.empty_like(q).contiguous()
 
 
 
 
54
 
55
 
56
  class QwenDoubleStreamAttnProcessorFA3:
 
68
  _attention_backend = "fa3" # for parity with your other processors, not used internally
69
 
70
  def __init__(self):
71
+ if not _fa3_available():
72
+ print(f"[QwenDoubleStreamAttnProcessorFA3] FA3 unavailable, using SDPA fallback. Reason: {_kernels_err}")
73
 
74
  @torch.no_grad()
75
  def __call__(
 
87
  # FA3 kernel path here does not consume arbitrary masks; fail fast to avoid silent correctness issues.
88
  raise NotImplementedError("attention_mask is not supported in this FA3 implementation.")
89
 
 
 
90
  B, S_img, _ = hidden_states.shape
91
  S_txt = encoder_hidden_states.shape[1]
92
 
 
135
  k = torch.cat([txt_k, img_k], dim=1)
136
  v = torch.cat([txt_v, img_v], dim=1)
137
 
138
+ if _fa3_available():
139
+ out = flash_attn_func(q, k, v, causal=False) # out: (B, S_total, H, D_h)
140
+ else:
141
+ out = _sdpa_fallback(q, k, v) # out: (B, S_total, H, D_h)
142
 
143
  # ---- Back to (B, S, D_model) ----
144
  out = out.flatten(2, 3).to(q.dtype)