Skip to content

Fuse Linear WGRAD accumulation across PP microbatches - #4386

Draft
anijain2305 wants to merge 1 commit into
mainfrom
fused-inplace-wgrad-accumulate
Draft

Fuse Linear WGRAD accumulation across PP microbatches#4386
anijain2305 wants to merge 1 commit into
mainfrom
fused-inplace-wgrad-accumulate

Conversation

@anijain2305

Copy link
Copy Markdown
Contributor

Pipeline parallelism invokes backward separately for each microbatch. For BF16 Linear weights, each backward currently materializes a BF16 weight gradient. When FSDP uses an FP32 reduce dtype, it casts and accumulates these gradients into a separate FP32 buffer, requiring an additional accumulation kernel for each microbatch.

Introduce a BF16 Linear implementation whose custom autograd.Function computes the first weight gradient directly in the configured reduce dtype and folds subsequent accumulation into the GEMM using addmm. This avoids the separate gradient-add kernels while preserving FSDP's reduction precision.

When param_dtype is BF16 and reduce_dtype is FP32, the unsharded parameter remains BF16 while param.grad is FP32. This relies on Tensor.grad_dtype, which is set to the configured reduce dtype. When both dtypes are BF16, the weight gradient and its accumulation remain BF16.

For subsequent backward calls, the autograd.Function reads the existing param.grad, accumulates into it, temporarily clears param.grad, and returns the same buffer. This prevents AccumulateGrad from adding the buffer to itself while still allowing autograd and FSDP hooks to observe a normal weight-gradient return value.

FSDP remains responsible for the final reduce-scatter and sharded gradient.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 31, 2026
"it mutates parameter.grad during backward"
)
weight_NK = (
self.weight.to_local() if isinstance(self.weight, DTensor) else self.weight

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

dont support DTensor

Pipeline parallelism invokes backward separately for each microbatch. For BF16 Linear weights, each backward currently materializes a BF16 weight gradient. When FSDP uses an FP32 reduce dtype, it casts and accumulates these gradients into a separate FP32 buffer, requiring an additional accumulation kernel for each microbatch.

Introduce a BF16 Linear implementation whose custom autograd.Function computes the first weight gradient directly in the configured reduce dtype and folds subsequent accumulation into the GEMM using addmm. This avoids the separate gradient-add kernels while preserving FSDP's reduction precision.

When param_dtype is BF16 and reduce_dtype is FP32, the unsharded parameter remains BF16 while param.grad is FP32. This relies on **Tensor.grad_dtype**, which is set to the configured reduce dtype. When both dtypes are BF16, the weight gradient and its accumulation remain BF16.

For subsequent backward calls, the autograd.Function reads the existing param.grad, accumulates into it, temporarily clears param.grad, and returns the same buffer. This prevents AccumulateGrad from adding the buffer to itself while still allowing autograd and FSDP hooks to observe a normal weight-gradient return value.

FSDP remains responsible for the final reduce-scatter and sharded gradient.
@anijain2305
anijain2305 force-pushed the fused-inplace-wgrad-accumulate branch from 73af371 to 1c7d7eb Compare August 31, 2026 22:12
weight_NK = (
self.weight.to_local() if isinstance(self.weight, DTensor) else self.weight
)
weight_NK.grad_dtype = self.wgrad_accum_dtype

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the KEY change.



def _get_local_wgrad(grad: torch.Tensor) -> torch.Tensor:
return grad.to_local() if isinstance(grad, DTensor) else grad

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do we need this?

return grad_input, grad_weight_NK, None, None


class FusedWGradAccumLinear(Linear):

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.

Does / how does this compose with other override of Linear, including

I would recommend we first support mxfp8 linear and DistMoE with grad accum fusion "hardcoded" in those autograd functions, and not others.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sounds good.

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

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants