[PyTorch] Add no-load-balance THD all-gather CP - #3221
Conversation
50b86ff to
9645f28
Compare
Allow causal THD attention to shard the complete packed token buffer with mirrored context-parallel chunks while retaining document boundaries through sequence metadata. This supports workloads whose individual documents are not divisible by twice the CP size. Keep the existing per-document partition as the default and reject backend or attention combinations that the prototype has not validated, so existing paths remain unchanged. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Reuse the existing THD CUDA partition and reorder kernels by representing the complete physical token buffer as one partitioning sequence. Preserve CPU and mixed-device dataloader behavior with a reference fallback. Rename the opt-in policy to packed_super_sequence to distinguish physical partitioning from THD packing, and add a narrowly gated matched-input benchmark path so the two policies can be compared without workload or timing asymmetry. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Allow relaxed THD all-gather to assign one contiguous chunk per CP rank while preserving the mirrored policy for compatibility and comparison. Rank-major ownership needs no KV reorder and reduces each rank to one attention step; keep it opt-in while the performance tradeoffs are evaluated. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Keep per-document partitioning as the default and packed-contiguous as the only packed opt-in so the experimental API has one global ownership contract. Delete the unused 2*CP global metadata and reorder paths, simplify packed metadata to one chunk and one attention step per rank, and retain a negative test for the retired selector. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Keep the experimental packed-contiguous selection internal to context parallelism so public TransformerLayer and attention APIs retain their existing signatures. Per-document partitioning remains the default unless NVTE_EXPERIMENTAL_CP_AG_THD_PACKED_CONTIGUOUS=1 is set. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Keep the initial upstream review focused on the production context-parallel implementation. The test development remains available in the preceding commits while the branch tip restores the existing test suite unchanged. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
9645f28 to
57f3cf8
Compare
Greptile SummaryThe PR adds an explicit context-parallel load-balancing strategy and implements contiguous physical-token partitioning for no-load-balance THD all-gather attention.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported backward-layout instability is addressed by consistently using the strategy captured during forward. Important Files Changed
Sequence DiagramsequenceDiagram
participant Input as Input partitioner
participant Layer as TransformerLayer / MHA
participant DPA as DotProductAttention
participant CP as THD all-gather CP
participant Bwd as Autograd backward
Input->>Input: Partition tokens using selected strategy
Layer->>DPA: Propagate strategy
DPA->>CP: Forward Q/K/V and strategy
CP->>CP: Gather K/V and build strategy-specific metadata
CP->>CP: Save strategy on autograd context
CP-->>Layer: Attention output
Bwd->>CP: Restore saved strategy
CP->>CP: Select matching step layout and K/V ordering
CP-->>Bwd: dQ/dK/dV
Reviews (7): Last reviewed commit: "Skip known sm90 deterministic THD OOM" | Re-trigger Greptile |
Name the single contiguous-chunk policy after its deliberate lack of causal load balancing so the performance tradeoff is explicit. Remove the CPU reference partitioner and require the existing CUDA path for per-document metadata. Capture the selected layout through backward and add focused helper plus CP2 forward/backward coverage so mutable environment state cannot make the two passes use different token orders. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Validate the experimental policy where context-parallel communication is selected so unsupported combinations fail before entering custom autograd. Passing the captured mode into the internal all-gather call also prevents a second environment lookup from selecting a different layout. Restore the default CPU dataloader slicing behavior, keep one stream dependency per format path, and exercise padded feature execution so the lean experimental path does not regress existing callers. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
|
|
||
| # Float8CurrentScaling: fused_attn_bwd takes O in FP8 by default, this flag allows it in F16 | ||
| _dpa_fp8_cs_o_in_f16 = os.getenv("NVTE_DPA_FP8CS_O_in_F16", "1") == "1" | ||
| _NO_LOAD_BALANCE_ENV = "NVTE_EXPERIMENTAL_CP_AG_THD_NO_LOAD_BALANCE" |
There was a problem hiding this comment.
Jax CP defines "DualChunkSwap", "Stripped", and "NoLoadBalance" as some Strategy (an enum). Maybe we can do the same on the PyTorch side? We can still label it experimental that way (in the docs), but without the environment variable.
There was a problem hiding this comment.
Done. The environment flag is replaced by the public CPLoadBalancingStrategy enum. NO_LOAD_BALANCE is documented as experimental, and DUAL_CHUNK_SWAP remains the default.
| fp8_meta, | ||
| quantizers, | ||
| fp8_output, | ||
| no_load_balance, |
There was a problem hiding this comment.
These "no_load_balance" flags in code and tests can all become an Enum, or a flag for load_balancing_strategy I think.
There was a problem hiding this comment.
Done. The booleans are replaced with CPLoadBalancingStrategy, propagated through the attention stack, and captured for backward.
| cp_stream.wait_stream(torch.cuda.current_stream()) | ||
|
|
||
| # Preserve overlap by letting cp_stream proceed before output initialization. | ||
| cp_stream.wait_stream(torch.cuda.current_stream()) |
There was a problem hiding this comment.
Why shifting wait_stream to only the else branch? Any particular reason for this?
There was a problem hiding this comment.
The THD wait follows K/V restoration and metadata preparation; the non-THD wait remains after K/V reordering. Comments now clarify both dependencies.
| contiguous physical-buffer chunk to each rank and uses one attention step per rank. | ||
| Logical sequences remain isolated by ``cu_seqlens``. This mode requires THD, | ||
| all-gather, full causal self-attention, and FusedAttention, or FlashAttention 3 | ||
| without padding. Input producers must use the same flag when partitioning inputs |
There was a problem hiding this comment.
I guess "without padding" here means pad_between_seqs=False?
There was a problem hiding this comment.
Yes—this specifically means pad_between_seqs=False. The documentation and validation now state that explicitly.
| assert "causal" in attn_mask_type and window_size == ( | ||
| -1, | ||
| 0, | ||
| ), "No-load-balance THD partitioning currently supports full causal attention only." |
There was a problem hiding this comment.
I think you mentioned somewhere else about "full causal attention". I understand you mean "no sliding window", but I feel generally when people say causal mask or causal attention, they do mean "full causal"? (nit)
There was a problem hiding this comment.
Updated to “causal attention without a sliding window,” specifically window_size=(-1, 0).
| def build_rank_indices(device): | ||
| # Preserve the CPU-capable per-document dataloader path. | ||
| rank_slices = [] | ||
| for slice_size, seq_start in zip(slice_sizes, cu_seqlens_padded[:-1]): |
There was a problem hiding this comment.
Is there any clever way to do this without this loop? Can you ask your agent? :)
There was a problem hiding this comment.
Done. CUDA partitioning now uses tex.thd_get_partitioned_indices; the Python loop remains only as the CPU fallback.
Refresh the PR on current upstream before addressing review feedback. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Make token partitioning explicit so input slicing and attention cannot diverge through mutable process state. Reuse native THD indices for CUDA while preserving CPU dataloader behavior, and cover the supported FusedAttention and unpadded FlashAttention 3 paths. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Use the shorter public name because the strategy governs both input partitioning and attention execution. Consolidate redundant low-level partition tests into the existing end-to-end slicing coverage. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
Document the experimental contract at the public selection points. Preserve the legacy child-setter invocation for the default strategy so the additive API does not disrupt existing extension modules. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
|
/te-ci pytorch L1 |
The focused no-load-balance test uses cp_2_0, which reaches the same known cuDNN deterministic THD backward workspace limit as the generic CP matrix. Apply the equivalent sm90 skip so the standalone coverage does not bypass that guard. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
|
/te-ci pytorch |
How to use
Select the token partition strategy explicitly and use the same value for both
context-parallel attention configuration and input partitioning:
CPAttentionLoadBalancingStrategy.DUAL_CHUNK_SWAPremains the default.What changed
CPAttentionLoadBalancingStrategyenum withDUAL_CHUNK_SWAPand experimentalNO_LOAD_BALANCEstrategies.MultiheadAttention, DotProductAttention, and the context-parallel attention
backends.
NO_LOAD_BALANCE, while preserving logical document boundaries through THDmetadata.
same token layout.
slicing while retaining the CPU dataloader fallback.
FlashAttention 3 coverage.
Why
The default per-document DualChunkSwap partition divides every sequence into
2 * cp_sizechunks and performs two attention steps per rank. Partitioningthe complete physical buffer into
cp_sizecontiguous chunks allows oneattention step per rank and supports packed documents whose individual lengths
are not divisible by
2 * cp_size.This strategy intentionally trades causal load balance for fewer attention
calls.
Scope and constraints
The experimental strategy currently requires THD self-attention,
cp_comm_type="all_gather", causal attention without a sliding window(
window_size=(-1, 0)), equal local Q/K/V physical lengths, and eitherFusedAttention or FlashAttention 3. FlashAttention 3 requires
pad_between_seqs=False. FP8 and CUDA graph capture are not supported.Input partitioning and attention configuration must use the same strategy.
Validation
DUAL_CHUNK_SWAPandNO_LOAD_BALANCE.DUAL_CHUNK_SWAPbehavior passed focused smoke checks.git diff --checkpassed.