Skip to content

Fix shared loss gradient accumulation - #8245

Open
tohtana wants to merge 3 commits into
deepspeedai:masterfrom
tohtana:tohtana/fix-zero2-bf16-shared-grad-8224
Open

Fix shared loss gradient accumulation#8245
tohtana wants to merge 3 commits into
deepspeedai:masterfrom
tohtana:tohtana/fix-zero2-bf16-shared-grad-8224

Conversation

@tohtana

@tohtana tohtana commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Fixes #8224

With gradient accumulation enabled, a loss can combine a forward pass through the DeepSpeed engine with a forward pass through the model inside the engine. The engine-output hook divides only the gradient from the engine forward by the accumulation count. The gradient from the forward pass on the model inside the engine remains unscaled, producing an incorrect gradient for that parameter.

This PR applies gradient-accumulation scaling to the complete loss passed through managed engine.backward. During that call, mark the loss as already scaled so engine-output hooks do not apply the scaling again, and restore the marker on every exit. The behavior of direct tensor backward, pipeline output hooks, and scale_wrt_gas=False is unchanged.

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92302850b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

backward_kwargs["retain_graph"] = True

self._running_engine_backward = False
loss = loss / self.gradient_accumulation_steps() if scale_wrt_gas else loss

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Prevent double-scaling branches from other engines

When engine_a.backward(loss_a + loss_b) is used with multiple DeepSpeed engines and gradient accumulation greater than one, this divides the entire combined loss by engine A's accumulation count, but only engine A has _is_engine_backward_loss_scaled set. Engine B's output hook therefore still divides its incoming gradient in _backward_prologue_per_tensor, silently scaling engine B's gradient twice (by an extra 1 / GAS when the engines use the same count). Combined multi-engine autograd graphs are already supported by TestZeroUserBackwardMultipleEngines, so the suppression needs to cover every participating engine or preserve branch-specific scaling.

Useful? React with 👍 / 👎.

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Discard unfinished ZeRO hook, bucket, and unreduced gradient state at the next root forward when an aborted backward has not crossed a reduction boundary. Track actual bucket drains and fail closed before forward or step once an accumulation window may contain an irreversible contribution.

Preserve step guards across runtime optimizer replacement and restore ZeRO-1/2 micro-step state for safe CPU-offload retry. Reject incomplete backward state at the public engine step entry, including non-boundary accumulation steps. Add lifecycle coverage for clean-control parity, oversized ZeRO-2 gradients, BF16 immediate updates, ZeRO-1 accumulation, coalesced ZeRO-2/3 gradients, multi-bucket ZeRO-2/3 failures, ZeRO-3 leaf reductions, step-before-forward rejection, CPU offload, and GAS>1 non-boundary step rejection.

Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant