Skip to content

[PyTorch] Enable FP8 block scaling for fusible ops#3242

Open
denera wants to merge 1 commit into
NVIDIA:mainfrom
denera:pytorch/fp8bs-in-fusible-ops
Open

[PyTorch] Enable FP8 block scaling for fusible ops#3242
denera wants to merge 1 commit into
NVIDIA:mainfrom
denera:pytorch/fp8bs-in-fusible-ops

Conversation

@denera

@denera denera commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Description

Enables FP8 block scaling (FP8BS) for TE/PyTorch fusible-ops with coverage for both non-grouped and grouped linears, following the MXFP8 paths.

IMPORTANT: FP8BS support for comm+GEMM overlap is deferred to a future PR.

Changes

  • Drop the NotImplementedError for FP8BS, use the generic recipe-state path like MXFP8.
  • Add Float8BlockwiseQTensorStorage.view() so quantized norm outputs reshape without dequantizing (mirrors MXFP8TensorStorage.view()).
  • Route grouped FP8BS through the Hopper graph-safe path (cuBLAS 13.4+). Fuse dbias in the rowwise pass when dgrad is required.
  • Exercise FP8BS across the fusible-ops test suite with 128-divisible sizes.

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

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

@denera
denera requested a review from vthumbe1503 July 23, 2026 10:16
@denera denera self-assigned this Jul 23, 2026
@denera denera added the FP8 label Jul 23, 2026
Enables FP8 block scaling (FP8BS) in composable fusible-ops for both
non-grouped and grouped linears.

- Drop the blanket FP8BS NotImplementedError in ops/op.py; FP8BS now uses the
  generic recipe-state path like MXFP8.
- Add `Float8BlockwiseQTensorStorage.view()` so quantized norm outputs reshape
  without dequantizing (mirrors `MXFP8TensorStorage.view()`).
- Route grouped FP8BS through the Hopper graph-safe path (cuBLAS 13.4+). Fuse
  dbias in the rowwise pass when dgrad is required.
- Exercise FP8BS across the fusible-ops test suite with 128-divisible sizes.

Signed-off-by: Alp Dener <adener@nvidia.com>
@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR enables FP8 block scaling (FP8BS) for TE/PyTorch fusible ops by removing the NotImplementedError and routing it through the same generic recipe-state path used by MXFP8.

  • op.py: Drops the unconditional raise NotImplementedError for FP8BS so the recipe-state path can proceed normally.
  • float8_blockwise_tensor_storage.py: Adds view() to reshape leading (token) dimensions of a quantized norm output without dequantizing — mirrors MXFP8TensorStorage.view(), correctly preserving scale-inv tensors (which depend only on the fixed inner block dims) and properly handling both rowwise and transposed columnwise data for both 1D and 2D block-scaling modes.
  • grouped_linear.py: Routes grouped FP8BS through the Hopper graph-safe path when cuBLAS ≥ 13.4; fuses dbias computation into the rowwise (dgrad) quantize pass only when dgrad is actually required, falling back to a standalone compute_grouped_dbias call for wgrad-only backward passes.
  • Tests: Extends test_fusible_ops.py with 128-divisible weight shapes and token dims, and bumps sequence_length from 48 to 64 in TestSequentialModules so that batch × seq = 256 satisfies the 128-divisibility requirement.

Confidence Score: 5/5

Safe to merge. All new code paths are well-guarded by hardware capability and cuBLAS version checks, and the view() implementation correctly preserves scale-inv invariants for both 1D and 2D block-scaling modes.

The removal of the NotImplementedError is mechanical and routes FP8BS through the well-tested recipe-state path already used by MXFP8. The new view() precisely mirrors the MXFP8 reference implementation, accounting for the transposed columnwise storage layout. The grouped-linear changes correctly restrict the new graph-safe path to Hopper + cuBLAS 13.4+ and gate dbias fusion on whether a dgrad pass is actually needed. No incorrect computations, stale state, or dropped side-effects were found across the five changed files.

No files require special attention.

Important Files Changed

Filename Overview
transformer_engine/pytorch/tensor/storage/float8_blockwise_tensor_storage.py Adds view() mirroring MXFP8TensorStorage; correctly preserves scale-inv (depends only on fixed inner dims), handles rowwise and transposed columnwise storage for both 1D and 2D block-scaling modes, and matches edge-case handling of the MXFP8 reference implementation.
transformer_engine/pytorch/ops/basic/grouped_linear.py Adds Float8BlockQuantizer branch to _use_grouped_compute (Hopper + cuBLAS >= 13.4 only) and correctly gates dbias fusion on ctx.input_requires_grad since bgrad_group_quantize is tied to the rowwise dgrad pass; falls back to compute_grouped_dbias for wgrad-only paths.
transformer_engine/pytorch/ops/op.py Removes the unconditional NotImplementedError for float8_block_scaling recipes, allowing the existing generic recipe-state construction path to proceed — a clean one-liner removal with no side effects.
tests/pytorch/test_fusible_ops.py Adds fp8_block_scaling to the quantization list with correct 128-divisibility skip guards; adds (128, 128) weight shape and (128, -1) in_shape for block-scaling coverage; bumps TestSequentialModules sequence_length from 48 to 64 so batch x seq=256 meets the 128-divisibility requirement.
tests/pytorch/utils.py Adds 'fp8_block_scaling' to the set of quantization names that use the same numerical tolerance as other FP8 recipes — a correct single-line addition.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[FP8BS recipe active in fusible op] --> B{need_to_reset_recipe_state?}
    B -- yes --> C[RecipeState.create for FP8BS]
    C --> D[make_quantizers → Float8BlockQuantizer list]
    B -- no --> E[reuse existing quantizers]
    D & E --> F[Forward pass]
    F --> G{GroupedLinear?}
    G -- yes --> H{_use_grouped_compute?}
    H -- yes --> I{CC >= 10.0 Blackwell?}
    I -- yes --> J[Return False → split-quantize fallback]
    I -- no Hopper --> K{cuBLAS >= 13.4?}
    K -- yes --> L[graph-safe grouped GEMM path]
    K -- no --> J
    G -- no --> M[single linear path unchanged]
    L --> N[Backward pass]
    N --> O{input_requires_grad?}
    O -- yes --> P[bgrad_group_quantize - fuse dbias in rowwise dgrad pass]
    O -- no --> Q[group_quantize columnwise only]
    Q --> R[compute_grouped_dbias separately]
    P & R --> S[Return grads]
Loading

Reviews (2): Last reviewed commit: "[PyTorch] Enable FP8 block scaling acros..." | Re-trigger Greptile

Comment on lines +343 to +348
if -1 in shape:
d_inferred = -math.prod(cur_shape) // math.prod(shape)
for i, d in enumerate(shape):
if d == -1:
shape[i] = d_inferred
break

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 -1 inference silently truncates for non-divisible shapes

d_inferred = -math.prod(cur_shape) // math.prod(shape) uses integer floor division. If the total element count isn't evenly divisible by the product of the explicit dims (e.g. cur_shape=(3, 128), shape=[2, -1, 128]), the inferred dim is silently truncated (d_inferred = 1 instead of fractional 1.5). The subsequent self._rowwise_data.view(*shape) will then raise a PyTorch error because 2 * 1 * 128 ≠ 3 * 128, but the inferred shape[i] value (1) is already wrong. This mirrors the MXFP8 implementation exactly — it is a pre-existing pattern — but worth documenting that -1 semantics only produce a meaningful result when the remaining dimensions divide evenly (same contract as torch.Tensor.view).

Comment thread transformer_engine/pytorch/ops/basic/grouped_linear.py
@denera
denera force-pushed the pytorch/fp8bs-in-fusible-ops branch from f517d02 to 639233e Compare July 23, 2026 10:23
@denera

denera commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator Author

/te-ci pytorch

@timmoon10 timmoon10 left a comment

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.

LGTM

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants