Uh oh!
There was an error while loading. Please reload this page.
add SP support for _flash_3_varlen_hub backend - #13809
Conversation
| if attn_mask is not None: | ||
| attn_mask = _normalize_attn_mask(attn_mask, batch_size, seq_len_kv) | ||
| (_, seqlens_k), (cu_seqlens_q, cu_seqlens_k), (max_seqlen_q, max_seqlen_k) = ( | ||
| _prepare_for_flash_attn_or_sage_varlen( | ||
| batch_size, seq_len_q, seq_len_kv, attn_mask=attn_mask, device=query.device | ||
| ) | ||
| ) | ||
| key_valid, value_valid = [], [] | ||
| for b in range(batch_size): | ||
| valid_len = seqlens_k[b] | ||
| key_valid.append(key[b, :valid_len]) | ||
| value_valid.append(value[b, :valid_len]) |
There was a problem hiding this comment.
This seems like should come under if _parallel_config is None and attn_mask is not None:?
There was a problem hiding this comment.
There is a little refactor in this PR, and basically it is doing the same thing as
#13479 (comment)
| max_seqlen_k=max_seqlen_k, | ||
| softmax_scale=scale, | ||
| causal=is_causal, | ||
| return_attn_probs=return_lse, |
There was a problem hiding this comment.
This seems like an extra argument?
There was a problem hiding this comment.
yes, we following the other implementation's style.
And actually return_attn_probs by default is False (see `https://github.com/huggingface/kernels-community/blob/main/flash-attn3/torch-ext/flash_attn3/flash_attn_interface.py#L648)
So it will only return single tensor (see https://github.com/huggingface/kernels-community/blob/main/flash-attn3/torch-ext/flash_attn3/flash_attn_interface.py#L691),
the previous code should not be runnable.
| return_attn_probs=return_lse, | ||
| ) | ||
| if return_lse: | ||
| out, lse, *_ = out |
There was a problem hiding this comment.
Why do we need to initialize lse = None above?
There was a problem hiding this comment.
It is a guard similar to _native_cudnn_attention, _sage_attention, etc. To make the code in same style
sayakpaul
commented
May 29, 2026
@askserge could you do a review? |
There was a problem hiding this comment.
🤗 Serge says:
This PR adds sequence parallel (context parallel) support for the _flash_3_varlen_hub attention backend, following the same pattern established by the existing _flash_varlen_hub (flash-attn2) and _flash_3_hub implementations. The code is well-structured and closely mirrors the existing patterns.
Correctness
Potential bug:
indices_kused before assignment on the no-mask path. In_flash_attention_3_varlen_hub_forward_op, whenattn_mask is None, the variableindices_kis never assigned, but at line 1721ctx.indices_k = indices_k if attn_mask is not None else None— this is actually fine because the conditional guards it. However, if_save_ctxisFalse,indices_kis never referenced at all on the no-mask path, so there's no issue. This matches the flash-attn2 varlen pattern exactly.Positional argument fragility in
wrapped_forward_fncall. The non-varlen_flash_attention_3_hub_forward_opuses keyword arguments forcausal,window_size_left, etc., but the new varlen forward op passes everything positionally (lines 1677–1712). This makes the code harder to read and more fragile if the upstream_flash_attn_forwardsignature changes. Consider using keyword arguments for at least the trailing parameters, consistent with the non-varlen version.return_lsehandling change in the non-SP path. The original code always unpackedout, lse, *_from the function call. The new code passesreturn_attn_probs=return_lseand conditionally unpacks. This is a behavioral change for the non-SP path — ifreturn_lse=False, the function now returns a single tensor instead of a tuple. This should be verified to work correctly with theflash_attn_varlen_funcAPI. The flash-attn2 varlen hub usesreturn_attn_probs=return_lsesimilarly, so this is likely correct.
Tests
- The new backend is properly added to
ContextParallelAttentionBackendsTesterMixinand thering_degreeskip logic. - The
_FLASH_3_VARLEN_HUBis added to the hub kernels set intests/models/testing_utils/utils.py.
Minor Issues
- Bug in existing test code (pre-existing). Line 413 (deleted):
attention_backend in ("flash_varlen_hub")— usinginwith a parenthesized string (not a tuple) means this is justattention_backend in "flash_varlen_hub", which checks character membership, not string membership. The fix on line 417 adds a proper tuple("flash_varlen_hub", "_flash_3_varlen_hub"), which is correct. However, the original single-element check was buggy. Good that it's fixed now.
Overall the implementation follows established patterns well and looks correct.
17 LLM turns · 18 tool calls · 92.5s · 309778 in / 4124 out tokens
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| max_seqlen_k=max_seqlen_k, | ||
| softmax_scale=scale, | ||
| causal=is_causal, | ||
| return_attn_probs=return_lse, |
There was a problem hiding this comment.
Note: The original code always unpacked out, lse, *_ = func(...). Now with return_attn_probs=return_lse, when return_lse=False the return value may be different (single tensor vs tuple). Make sure flash_attn_varlen_func from flash-attn3 returns a single tensor (not a tuple) when return_attn_probs=False. The flash-attn2 varlen hub uses the same pattern, so this is likely fine, but worth verifying.
There was a problem hiding this comment.
zhtmike
commented
Jun 3, 2026
Hi @sayakpaul sorry for late update. The review should be addressed, can you take a look? |
sayakpaul
commented
Jun 4, 2026
Waiting for PR #13756. |
zhtmike
commented
Jun 12, 2026
Per the discussion in PR #13756, I have added a precision test in ContextParallelAttentionBackendsTesterMixin. I have tested with:
and the tests passed. Meanwhile, there is a breaking change in huggingface/kernels-community@1471f94 that causes FA2 to fail to run with recent pre‑built kernels (missing |
zhtmike
commented
Jun 29, 2026
@sayakpaul please take a look if you have time~ |
sayakpaul
commented
Jul 3, 2026
Could you please resolve the conflicts? |
There was a problem hiding this comment.
🤗 Serge says:
Clean, well-scoped port of the existing FLASH_VARLEN_HUB context-parallel implementation to the _FLASH_3_VARLEN_HUB backend. The new forward/backward ops mirror the established FA3 (_flash_attention_3_hub_*) and FA2-varlen (_flash_varlen_attention_hub_*) patterns closely, and the wiring all cross-checks:
- The FA3
_flash_attn_forward/_flash_attn_backwardpositional call signatures match those already used by_flash_attention_3_hub_forward_op/_backward_op, with the varlen-specificcu_seqlens/max_seqlenargs inserted in the right positions. ctx.indices_k = indices_k if attn_mask is not None else Noneis safe — the ternary short-circuits beforeindices_k(only defined in the masked branch) is evaluated.- The non-CP path change to gate lse via
return_attn_probs=return_lseand unpack conditionally is correct and avoids requesting lse unnecessarily. ring_degree > 1is explicitly rejected in both the dispatch function and the test skip list; ulysses is the supported path.functoolsis imported; the registrywrapped_*_attrentries point at the FA3flash_attn_interface._flash_attn_{forward,backward}which matches the long-signature calls.
Tests
- The
_context_parallel_workeralready accepts the newstate_dictpositional arg, so the added argument at the call site is consistent. Capturing weights from the (bf16-cast) reference model and reloading them into a fresh model in the worker before its own cast ensures both sides use identical weights — this upgrades the test from a shape-only check to a real numericalassert_close, which is a genuine improvement.
No correctness or security concerns found. The description's claims (SP forward/backward support, Flux/QwenImage tests) are consistent with the diff.
serge v0.1.0 · model: claude-opus-4-8 · 14 LLM turns · 14 tool calls · 89.5s · 439489 in / 5510 out tokens
# Conflicts: # src/diffusers/models/attention_dispatch.py
zhtmike
commented
Jul 3, 2026
Done! |
| wrapped_forward_attr="flash_attn_interface._flash_attn_forward", | ||
| wrapped_backward_attr="flash_attn_interface._flash_attn_backward", |
There was a problem hiding this comment.
there is a breaking change in huggingface/kernels-community@1471f94 in PR huggingface/kernels-community#877 that causes FA2 to fail to run with recent pre‑built kernels (missing _wrapped_flash_attn_forward), so I have to fix it here to pass the tests.
There was a problem hiding this comment.
Just run with the latest kernels version; it seems to be fixed. I’ve reverted the changes.
| wrapped_forward_attr="flash_attn_interface._wrapped_flash_attn_varlen_forward", | ||
| wrapped_backward_attr="flash_attn_interface._wrapped_flash_attn_varlen_backward", | ||
| wrapped_forward_attr="flash_attn_interface._flash_attn_varlen_forward", | ||
| wrapped_backward_attr="flash_attn_interface._flash_attn_varlen_backward", |
| AttentionBackendName._FLASH_3_VARLEN_HUB, | ||
| constraints=[_check_device, _check_qkv_dtype_bf16_or_fp16, _check_shape], | ||
| supports_context_parallel=False, | ||
| supports_context_parallel=True, |
| batch_size, seq_len_q, _, _ = query.shape | ||
| _, seq_len_kv, _, _ = key.shape | ||
| if attn_mask is not None: |
There was a problem hiding this comment.
Sorry I have lost the context here since it's been a while. Can you explain why do we need these changes? I don't think the if _parallel_config is None: branch is doing what we had previously.
There was a problem hiding this comment.
For if _parallel_config is None: branch, I major do a fix for non-contiguous mark handling for models like Qwen-Image, following the pattern of https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_dispatch.py#L2783.
Both implementations are equivalent for contiguous masks, but the previous implementation was buggy for non‑contiguous masks.
There was a problem hiding this comment.
Can that come in a separate PR before we merge this PR? I think the two are slightly unrelated?
zhtmike
commented
Jul 8, 2026
Updated the PR with latest main, tested with |
sayakpaul
commented
Jul 8, 2026
For this I think only varlen applies since Qwen has masks? |
zhtmike
commented
Jul 8, 2026
yeah right! |
HuggingFaceDocBuilderDev
commented
Jul 8, 2026
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
sayakpaul
left a comment
There was a problem hiding this comment.
Ran pytest tests/models/transformers/ -k "test_context_parallel_attn_backend_inference" on 2 H100s and all were green! Let's go.
What does this PR do?
A follow up work for #13479. I have added
_flash_3_varlen_hubsupport for SP forward & backward.Tested with QwenImage pipeline, the result image is expected.
Tested with QwenImage training with SP, there is no error.
The UTs for Flux and QwenImage are passed.
Fixes # (issue)
Before submitting
documentation guidelines, and
here are tips on formatting docstrings.
Who can review?
@sayakpaul
Anyone in the community is free to review the PR once the tests have passed. Feel free to tag
members/contributors who may be interested in your PR.