Skip to content

[Common/PyTorch] Fused grouped MXFP8 requantization - #3359

Merged
ptrendx merged 8 commits into
NVIDIA:mainfrom
YangFei1990:fused_group_requantize
Aug 21, 2026
Merged

[Common/PyTorch] Fused grouped MXFP8 requantization#3359
ptrendx merged 8 commits into
NVIDIA:mainfrom
YangFei1990:fused_group_requantize

Conversation

@YangFei1990

Copy link
Copy Markdown
Collaborator

Description

Replace the group_dequantize -> group_quantize(columnwise) -> grouped_swizzle(rowwise scales) chain in group_requantize_inplace with a single kernel (NVTE_FUSED_GROUP_REQUANTIZE=0 restores the unfused path).

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

Replace the group_dequantize -> group_quantize(columnwise) ->
grouped_swizzle(rowwise scales) chain in group_requantize_inplace with a
single kernel (NVTE_FUSED_GROUP_REQUANTIZE=0 restores the unfused path).
Co-authored-by: Oleg Goncharov <ogoncharov@nvidia.com>
Signed-off-by: YangFei1990 <feiw@nvidia.com>
@greptile-apps

greptile-appsBot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR replaces grouped MXFP8 dequantize, columnwise requantize, and scale swizzle operations with a fused Blackwell CUDA kernel while retaining an environment-controlled fallback.

  • Adds a public common-core requantization API and PyTorch dispatch path.
  • Supports optional BF16 dequantized output, capacity tails, zero-sized groups, and E4M3/E5M2 rowwise inputs.
  • Adds parameterized C++ coverage comparing fused output with the existing unfused operations.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

FilenameOverview
transformer_engine/common/cast/fused_group_requantize.cuImplements the Blackwell fused grouped MXFP8 dequantization, requantization, scale emission, and optional BF16-output kernel.
transformer_engine/pytorch/csrc/extensions/cast.cppSelects the fused operation for supported PyTorch grouped tensors and preserves the existing unfused fallback.
transformer_engine/common/include/transformer_engine/cast.hDeclares and documents the new common C API.
tests/cpp/operator/test_fused_group_requantize_mxfp8.cuAdds reference comparisons across group layouts, input FP8 types, fast-math modes, optional dequantization, and capacity tails.

Sequence Diagram

sequenceDiagram
participant PT as PyTorch GroupedTensor
participant Bind as group_requantize_inplace
participant Core as nvte_group_requantize
participant GPU as Fused CUDA kernel
PT->>Bind: Rowwise MXFP8 data, scales, offsets
alt Fused path supported and enabled
Bind->>Core: Input/output descriptors and offsets
Core->>GPU: Launch grouped requantization
GPU-->>Core: Columnwise E4M3 data and swizzled scales
Core-->>Bind: Optional BF16 dequantized output
Bind-->>PT: Replace scale and columnwise buffers
else Fallback path
Bind->>Bind: Group dequantize
Bind->>Bind: Group columnwise quantize
Bind->>Bind: Grouped scale swizzle
end
Loading

Reviews (3): Last reviewed commit: "[pre-commit.ci] auto fixes from pre-comm..." | Re-trigger Greptile

@Oleg-GoncharovOleg-Goncharov left a comment

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.

Hi @YangFei1990, I’ve done some further optimization work on this implementation, and the version in this GitLab branch is ~10% faster than the current implementation in this PR:
https://gitlab-master.nvidia.com/ogoncharov/transformerengine/-/tree/pr_requantize_mxfp8

The main improvements came from using data swizzling in the TMA descriptor and the redux.sync instruction, which reduces the number of reads/writes to the shared buffer holding intermediate results.

Could you please update the PR to incorporate the corresponding changes before merging?

* \param[in] stream CUDA stream used for the operation.
*/
void nvte_fused_group_requantize_mxfp8(const NVTETensor input, NVTETensor output,
const NVTETensor tensor_offsets, NVTETensor dequantized,

@phu0ngngphu0ngngAug 20, 2026

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.

In which case do callers need the dequantized?

Could we rename this function to nvte_group_requantize since it already contains "fusion" and is also more general, so that we can extend it in the future? Ofc we should make sure to check and only support MXFP8 for now.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

dequantized is required to compute dbias when it is needed. I will update the func name.

* path.
* \param[in] stream CUDA stream used for the operation.
*/
void nvte_fused_group_requantize_mxfp8(const NVTETensor input, NVTETensor output,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we leave out the "mxfp8" from the name? We can note in the documentation that currently it only supports mxfp8, but we should still do a general API name.

// unfused chain's dedicated empty-input handling accepts and the kernel's pointer
// validation (correctly) rejects.
const bool use_fused_kernel =
transformer_engine::getenv<bool>("NVTE_FUSED_GROUP_REQUANTIZE", true) && need_columnwise &&

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.

Why env variable? If we are confident of its perf, then we should always enable it.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I would like to keep it just for debugging purpose. The default path is fused op. Please let me know if you really want to get rid of it.

const bool use_fused_kernel =
transformer_engine::getenv<bool>("NVTE_FUSED_GROUP_REQUANTIZE", true) && need_columnwise &&
has_usable_offsets && total_tokens > 0 && otype == DType::kBFloat16 &&
quantizer.attr("dtype").cast<DType>() == DType::kFloat8E4M3 &&

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.

Doing attr access for the same attribute again and again should be avoided, since it can be pretty heavy considering cpu overheads.

Could we initialize them once for the fused and unfused cases in the start of the function and reuse them?

"Requantizing a grouped input requires dims that are multiples of 128, but got (",
total_tokens, ", ", hidden_dim, ").");

// Fused path (default; NVTE_FUSED_GROUP_REQUANTIZE=0 recovers the unfused chain): one

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.

Do we already have pytorch side unit test to test the fused kernel?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yes all tests in test_mxfp8_group_quantize_graph_safe.py will run this path

@Oleg-GoncharovOleg-Goncharov left a comment

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.

The kernel LGTM for now. A follow-up PR with performance optimizations will come later

@Oleg-Goncharov
Oleg-Goncharov self-requested a review August 21, 2026 15:10
@YangFei1990

Copy link
Copy Markdown
CollaboratorAuthor

/te-ci L1 pytorch

@ptrendx
ptrendx dismissed Oleg-Goncharov’s stale reviewAugust 21, 2026 23:10

Based on the latest comment that the optimizations will be part of the subsequent PR.

@ptrendx
ptrendx merged commit 8d9325f into NVIDIA:mainAug 21, 2026
30 of 35 checks passed
@mmarcinkiewiczmmarcinkiewicz mentioned this pull request Aug 22, 2026
13 tasks
Sign up for freeto 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.

5 participants

@YangFei1990@ptrendx@phu0ngng@Oleg-Goncharov@vthumbe1503