Skip to content

[Common][PyTorch] Add NVFP4 EP dispatch and combine backward - #3753

Open
sraman-rgb wants to merge 7 commits into
NVIDIA:mainfrom
sraman-rgb:sraman/nvfp4-ep-direct-receive
Open

sraman-rgb wants to merge 7 commits into
NVIDIA:mainfrom
sraman-rgb:sraman/nvfp4-ep-direct-receive

Conversation

@sraman-rgb

Copy link
Copy Markdown
Collaborator

Accept NVFP4BlockScaling as the EP dispatch_fwd_quant_recipe and combine_bwd_quant_recipe. Tokens travel as packed NVFP4 rows (E2M1 codes, E4M3 block scales and a power-of-two FP32 token scale) through the unscaled dispatch / combine-backward path.

Under NVFP4 autocast in graph mode, the receiver builds the expert GEMM's NVFP4 GroupedTensor straight from the rows in one pass: the rowwise operand reuses the sender's codes and the columnwise RHT operand is quantized with a bound-derived per-expert scale, so no BF16 round trip or amax pass is needed. The combine backward uses stochastic rounding per the recipe. Otherwise the rows are decoded to BF16.

Add nvte_ep_nvfp4_pack / _unpack / _direct_receive to the common EP API, the tex bindings, single-GPU tests and multi-GPU EP harness tests.

Description

Please include a brief summary of the changes, relevant motivation and context.

Fixes # (issue)

Type of change

  • Documentation change (change only to the documentation, either a fix or a new content)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Infra/Build change
  • Code refactoring

Changes

Please list the changes introduced in this PR:

  • Change A
  • Change B

Checklist:

  • I have read and followed the contributing guidelines
  • The functionality is complete
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

…ect receive

Accept NVFP4BlockScaling as the EP dispatch_fwd_quant_recipe and
combine_bwd_quant_recipe. Tokens travel as packed NVFP4 rows (E2M1 codes,
E4M3 block scales and a power-of-two FP32 token scale) through the unscaled
dispatch / combine-backward path.

Under NVFP4 autocast in graph mode, the receiver builds the expert GEMM's
NVFP4 GroupedTensor straight from the rows in one pass: the rowwise operand
reuses the sender's codes and the columnwise RHT operand is quantized with a
bound-derived per-expert scale, so no BF16 round trip or amax pass is needed.
The combine backward uses stochastic rounding per the recipe. Otherwise the
rows are decoded to BF16.

Add nvte_ep_nvfp4_pack / _unpack / _direct_receive to the common EP API, the
tex bindings, single-GPU tests and multi-GPU EP harness tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>
@greptile-apps

greptile-apps Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the latest change fixes the capture test's pass selection.

Summary

Adds NVFP4 token transport for EP dispatch and combine backward.

  • Expert-parallel dispatch can send tokens as packed NVFP4 rows.
  • Combine backward can return NVFP4 gradient rows for expert GEMMs.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[BF16 tokens or gradients] --> B[Pack NVFP4 rows]
  B --> C[EP transport]
  C --> D{Direct receive enabled?}
  D -->|Yes| E[NVFP4 GroupedTensor]
  D -->|No| F[Decode to BF16]
Loading

Reviews (5) · Last reviewed commit: "[PyTorch] EP test: keep the alignment-pa..." · Reviewed by Greptile

Comment thread transformer_engine/pytorch/ep.py Resolved
@phu0ngng
phu0ngng self-requested a review October 27, 2026 23:27
@ksivaman ksivaman self-assigned this Nov 2, 2026
Comment on lines +10 to +11
* The sender packs each token into one NVFP4 row (E2M1 codes, E4M3 block scales and a
* power-of-two FP32 token scale); the rows travel as an unscaled payload. The receiver either

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions here

  1. I think you will need to sync the power-of-two FP32 token scale before quantization within the DP group already. Why do you need to send it one more time here?
  2. When we don't need to send the extra FP32 tensor scale, we should be able to use the current existing infrastructure to dispatch token and block scale with this packing.

sraman-rgb and others added 2 commits November 10, 2026 08:38
…decode path

Guard the NVFP4 EP bindings (pack, unpack, direct receive) with the input
tensor's device so the launch stream, allocations and the stochastic
rounding generator follow the input rather than the current device.

Under zero-copy, land packed NVFP4 rows that are decoded to BF16 (dispatch
and combine backward outside NVFP4 autocast) in a persistent symm-mem
scratch on the EpBuffer, allocated on first use, instead of allocating from
the symm-mem pool on every call. This makes the decode path CUDA-graph
capturable with caller-provided persistent buffers.

Add a cross-device test for the bindings and run the NVFP4 dispatch and
combine-backward capture tests in the zero-copy EP pass.

Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ect-receive

Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>

# Conflicts:
#	transformer_engine/common/CMakeLists.txt
Comment thread transformer_engine/pytorch/ep.py Resolved
sraman-rgb and others added 3 commits November 13, 2026 12:30
…cast

Review feedback: under NVFP4 autocast the NVFP4 combine backward returns FC2's grad_output as a
swizzled NVFP4 GroupedTensor, which holds only GEMM operands. A consumer that needs the decoded
gradient, such as a grouped linear with a bias (bias gradient), could not get it. Add
ep_combine(..., nvfp4_grad_direct_receive=True); with False the backward decodes the received
rows to the BF16 expert_out grad, as outside NVFP4 autocast. Test: the opt-out returns a BF16
grad equal to a BF16 combine backward of the sender-decoded result-grad.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>
…equires

The upstream merge brought _DispatchState.layer_args and the (top_k, alignment, topk_idx_dtype)
arguments of the combine backward; the NVFP4 dispatch and combine-backward paths of this PR did
not pass them (merged without a textual conflict), so every NVFP4 EP path failed. Pass them as
the BF16/MXFP8 paths do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>
…=256 reference

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>
Comment thread tests/pytorch/distributed/run_ep.py Resolved
…pture test

Adding the opt-out test before test_combine_bwd_nvfp4_direct_capture moved that test's
@_mxfp8_align_test decorator onto the new test, so the capture test was skipped in the
alignment=256 passes. Both tests use alignment=256 and carry the decorator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Siddhartha Raman S <sraman@nvidia.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants