Skip to content

Add deepspeed.comm.pg_utils.is_parallel for optional parallel groups - #8815

Open
jinyouzhi wants to merge 10 commits into
deepspeedai:masterfrom
jinyouzhi:comm-all-reduce-if-parallel
Open

jinyouzhi wants to merge 10 commits into
deepspeedai:masterfrom
jinyouzhi:comm-all-reduce-if-parallel

Conversation

@jinyouzhi

@jinyouzhi jinyouzhi commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Part of #8814, following @delock's suggestion in #8791 and the review discussion on where the helper should live.

Change

  • Add deepspeed/comm/pg_utils.py with is_parallel(group): group is not None and spans more than one rank.
    • comm.py keeps the plain collectives, where group=None means the world group. In pg_utils, group=None means the parallel dimension is absent.
    • pg_utils is not star-exported from deepspeed.comm; callers write from deepspeed.comm import pg_utils, so the two meanings of None stay apart.
    • It is a predicate rather than a per-collective wrapper (an earlier revision had all_reduce_if_parallel), so one helper guards every primitive: sync or async all-reduce, all-gather, inference all-reduce, ...:
      if pg_utils.is_parallel(group):
          dist.all_reduce(tensor, group=group)
  • Replace the hand-written group is not None and dist.get_world_size(group) > 1 guards, and variants that only check None:
Area Sites
sequence vocab_parallel_ops.py (5; local _tp_active/_all_reduce removed), cross_entropy.py (4, _global_sp_sum, empty-shard check)
MoE sharded_moe.py capacity MAX reductions (3)
inference v1 ds_mlp.py, triton/mlp.py, ds_attention.py, triton/attention.py, moe_inference.py (async all-reduce, expert-MP all-gather and split)
ZeRO stage_1_and_2.py / stage3.py _model_parallel_all_reduce, stage3.py AutoEP norm reductions (3)
AutoTP module_inject/layers.py: RowParallel forward, ScatterToTensorParallelRegion / ColumnParallel backward, LmHeadLinearAllreduce forward; TensorParallel_Layer caches is_tp_parallel = is_parallel(mp_group) once at construction, used by the 6 mp_group is None or tp_world_size == 1 guards in LinearAllreduce / LinearLayer / SubParam* / fused-QKV layers (no per-call cost)
other runtime/utils.py MoE EP norm reductions (2)

Behavior is unchanged. Sites that only checked None now also skip single-rank groups, where every guarded collective is a no-op.

Not migrated:

  • Guards on a separately supplied size (len(partition_sizes), a tp_world_size argument) in gather helpers: the size is not derived from a group.
  • Sites where None means the world group: kv_cache warm-up, moe_inference._alltoall.
  • AutoEP folding correction: its guard covers more than a collective.
  • Engine/ZeRO DP buckets.

Tests

  • tests/unit/comm/test_dist.py: pg_utils contract on 4 ranks.
    • 2-rank and world groups are parallel; None and single-rank groups are not.
    • group=None works without a process group.
    • is_parallel is not exported as deepspeed.comm.is_parallel.
  • tests/unit/module_inject/test_tp_autograd_reduce.py, with 2-rank, single-rank and None groups:
    • RowParallel forward.
    • ColumnParallel / ScatterToTensorParallelRegion backward.
    • LmHeadLinearAllreduce output matches the unsharded linear.
  • tests/unit/runtime/test_runtime_utils.py::TestGlobalNormMoEGroup: expert-group 2-norm and inf-norm with the same three group kinds.
  • Mutation check: making is_parallel(None) return True (a world reduction) fails the None cases of the new tests.
  • Regression, 108 passed and 4 skipped: the new tests plus
    • test_runtime_utils.py
    • test_moe.py::TestMoESingleton
    • test_vocab_parallel_ops.py
    • test_vocab_parallel_cross_entropy.py
    • test_liger_vocab_parallel_cross_entropy.py
    • test_invalid_grad_norm.py

Run on 8× Intel Arc Pro B70 (XPU, XCCL), torch 2.14.0.dev20260804+xpu.

Contribution checklist

Related work. This is part of RFC #8814. A search for is_parallel, all_reduce_if_parallel and "optional parallel group" found no other PR that adds an optional-group predicate.

Commands and results. Hardware and software: 8× Intel Arc Pro B70 (XPU, XCCL), Level Zero driver 1.15.39122 (compute runtime 26.27.39122.11), torch 2.14.0.dev20260804+xpu.

pytest -p no:randomly tests/unit/comm/test_dist.py tests/unit/module_inject/test_tp_autograd_reduce.py \
  tests/unit/runtime/test_runtime_utils.py tests/unit/v1/moe/test_moe.py::TestMoESingleton \
  tests/unit/v1/sequence_parallelism/test_vocab_parallel_ops.py \
  tests/unit/v1/sequence_parallelism/test_vocab_parallel_cross_entropy.py \
  tests/unit/v1/sequence_parallelism/test_liger_vocab_parallel_cross_entropy.py \
  tests/unit/v1/zero/test_invalid_grad_norm.py
  • The command above: 108 passed, 4 skipped.
  • tests/unit/v1/moe/test_autoep_unit.py: 192 passed. This covers the ZeRO-3 AutoEP norm paths. Its fake EP group now mocks dist.get_world_size, because is_parallel queries the group size.

Numerics, performance, memory. Nothing changes. Every site keeps the same collective; sites that only checked for None now also skip single-rank groups, where the collective is a no-op.

Compatibility matrix.

Validated Not validated on device
AutoTP RowParallel / ColumnParallel / ScatterToTensorParallelRegion / LmHeadLinearAllreduce with 2-rank, single-rank and None groups
ZeRO stage 1/2/3 _model_parallel_all_reduce; stage-3 AutoEP norm paths in unit tests Offload
MoE EP norm reductions; TestMoESingleton
Sequence Vocab-parallel ops and cross entropy with TP=2
Inference v1 ds_mlp, ds_attention, triton/*, moe_inference: mechanical guard replacement only
Accelerator XPU CUDA, HPU

AI assistance. This PR was developed with AI assistance (GitHub Copilot CLI). I reviewed every changed line and ran the tests above.

Many modules guard all_reduce with 'group is not None and world_size > 1' so
that code written for an optional TP/SP group runs without it. Provide this
as a comm helper where group=None explicitly means an absent parallel
dimension (not the world group), and use it in sequence/cross_entropy.py.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T10:39:44.726122Z ab0aead Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 2d64bd8725

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread deepspeed/comm/comm.py Outdated
``tensor`` unchanged. Only synchronous reductions are supported, since a skipped call has no work
handle to return.
"""
if group is None or get_world_size(group) == 1:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip process groups that exclude this rank

When a caller passes a process group that excludes the current rank, get_world_size(group) returns -1 per this module's contract, so this equality check falls through even though there is no local work. This regresses the replaced > 1 guards and is not harmless on the custom CCL backend: CCLBackend.get_all_ranks_from_group derives an empty rank list and calls _new_group, which indexes ranks[0]; reduce only when the reported size is greater than one so non-members skip the collective.

AGENTS.md reference: AGENTS.md:L40-L40

Useful? React with 👍 / 👎.

Comment thread deepspeed/comm/comm.py Outdated
return cdb.all_reduce(tensor, op, group, async_op)


def all_reduce_if_parallel(tensor, op=ReduceOp.SUM, group=None):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add API-reference docs for the public helper

all_reduce_if_parallel is exported through deepspeed.comm and gives group=None semantics that intentionally differ from all_reduce, but this commit adds no entry under docs/code-docs/source, and a repository-wide rg finds no documentation of the name outside source and tests. Without a public reference, downstream callers can easily apply torch.distributed's world-group convention to it; add the documentation required for this new public feature.

AGENTS.md reference: AGENTS.md:L71-L71

Useful? React with 👍 / 👎.

@jinyouzhi
jinyouzhi marked this pull request as draft October 16, 2026 08:37
…ll sites

Keep deepspeed/comm/comm.py for plain collectives, where group=None means the
world group, and put helpers for optional parallel groups, where group=None
means the dimension is absent, in deepspeed/comm/pg_utils.py. pg_utils is not
star-exported from deepspeed.comm, so the two meanings of None stay apart.

- pg_utils.is_parallel(group): group is not None and has more than one rank.
- pg_utils.all_reduce_if_parallel(tensor, op, group): synchronous all-reduce
  guarded by is_parallel.

Replace the hand-written "group is not None and world_size > 1" guards in
sequence (vocab_parallel_ops, cross_entropy), MoE (sharded_moe), inference v1
(ds_mlp, ds_attention, triton mlp/attention, moe_inference), ZeRO
(stage_1_and_2, stage3), module_inject/layers.py and runtime/utils.py.
Guards that compare a separately supplied world size are left unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@jinyouzhi jinyouzhi changed the title Add deepspeed.comm.all_reduce_if_parallel for optional parallel groups Add deepspeed.comm.pg_utils for optional parallel groups Oct 16, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@jinyouzhi jinyouzhi changed the title Add deepspeed.comm.pg_utils for optional parallel groups Add deepspeed.comm.pg_utils.is_parallel for optional parallel groups Oct 16, 2026
jinyouzhi and others added 2 commits October 16, 2026 10:14
Drop all_reduce_if_parallel: a single predicate works for every collective
(sync, async, all_gather, ...) without one wrapper per primitive. Also guard
the lm_head inference all-reduce and the MoE inference expert-MP gather.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
Replace the per-call 'mp_group is None or tp_world_size == 1' guards in the
AutoTP layers with a value computed once from pg_utils.is_parallel at
construction, so forward/backward pay no extra cost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@jinyouzhi
jinyouzhi marked this pull request as ready for review October 16, 2026 10:32
@jinyouzhi
jinyouzhi requested a review from hwchen2017 as a code owner October 16, 2026 10:32
jinyouzhi and others added 2 commits October 16, 2026 15:15
…parallel

Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@delock
delock enabled auto-merge October 17, 2026 14:29
The AutoEP expert group is now reduced only when it spans more than one rank,
so the test's stand-in group needs a world size like the neighbouring tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com>
@jinyouzhi

jinyouzhi commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

@delock I reproed the CI failure cases, I fixed test_autoep_unit. Need I skip the TestLionConfigs? or use #8833
Thanks for your review.

FAILED unit/ops/lion/test_lion.py::TestLionConfigs::test[Lion-False-FusedLion]
FAILED unit/v1/moe/test_autoep_unit.py::TestAutoEPConfig::test_zero3_cpu_offload_grad_norm_reduces_autoep_expert_parallel_group

auto-merge was automatically disabled October 17, 2026 15:19

Head branch was pushed to by a user without write access

This branch has not been deployed

No deployments
Sign up for free to 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.

2 participants