deepspeedai / deepspeedai/DeepSpeed

[REQUEST] An option for SUM gradient allreduce instead of MEAN

Open
#7,107 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
43.1k
Forks
5k
Avg merge
4d 15h
Merged PRs (30d)
112

Description

Is your feature request related to a problem? Please describe.
In some learning problems, the correct allreduce of gradients across data-parallel workers is SUM rather than MEAN. For example, when doing contrastive learning for embedding models, it is common to allgather embeddings across all workers during the forward pass, compute a global loss, and then back-propagate, making the correct gradient reduction a SUM aggregation. Both PyTorch DDP and DeepSpeed currently appear to hard-code a 1/world_size rescaling of gradients into the distributed backwards pass before executing a SUM allreduce, essentially hard-coding the backwards pass allreduce to be a MEAN operation.

To work around this hard-coded behavior, practitioners have to manually re-scale the loss value by world_size before back-propagating (e.g. as this PyTorch community post suggests). Other workarounds include disabling or manually adjusting gradient clipping in proportion to the number of workers while simultaneously using a scale-invariant optimizer like Adam.

Describe the solution you'd like
I would like DeepSpeed to support for an additional configuration which would simply disable the 1/world_size scaling, e.g. my config could look like {"zero_optimization": {"stage": 1}, "gradient_allreduce_op": "sum"}.

Describe alternatives you've considered
I have thought about trying to subclass DeepSpeedZeroOptimizer to modify its average_tensor method to not actually average anything but perform a SUM allreduce (I believe that would just involve gating line 1122 on a check that the config is the default value of "MEAN" instead of "SUM"). However, this would only apply to ZeRO stage1 and stage2, and I couldn't figure out a clean way to actually use my own subclass in my training loop.

Additional context
I chatted a bit with @stas00 about this possible feature, who mentioned this might be of interest to @tjruwase

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the average_tensor method around line 1122 of deepspeed/runtime/zero/stage_1_and_2.py, then trace how gradient allreduce configuration is parsed and used across the supported ZeRO stages. Check existing tests for gradient reduction behavior. Done means a configuration can select SUM without 1/world_size scaling while the default MEAN behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
distributed-systems, machine-learning
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.