Skip to content

Warn when zero.Init silently falls back to a single rank (#8084)#8089

Open
akshansh47 wants to merge 1 commit into
deepspeedai:masterfrom
akshansh47:fix/zero-init-unsharded-single-rank-warning
Open

Warn when zero.Init silently falls back to a single rank (#8084)#8089
akshansh47 wants to merge 1 commit into
deepspeedai:masterfrom
akshansh47:fix/zero-init-unsharded-single-rank-warning

Conversation

@akshansh47

Copy link
Copy Markdown

Problem

Fixes #8084.

deepspeed.zero.Init resolves its partition group from dist.get_world_group(). If the distributed process group has not been initialized before zero.Init runs (the classic case: AutoModel.from_pretrained(...) under an active HfDeepSpeedConfig executes before deepspeed.init_distributed()), the call at the top of Init.__init__:

if not dist.is_initialized():
    init_distributed()

ends up with a process group that only sees the local rank, so self.dp_world_size == 1. zero.Init then materializes every parameter whole on every rank instead of partitioning it. Under deepspeed --num_gpus N every rank loads the full (unsharded) model and OOMs. The failure is silent and indistinguishable from an honest "model too big" OOM, which makes it very hard to diagnose.

Fix

Detect the case and emit a loud, actionable warning: the launcher reports WORLD_SIZE > 1 but the resolved group collapsed to a single rank. The warning names the likely cause and the fix (call deepspeed.init_distributed() before building the model under zero.Init).

This is intentionally a warning, not an error or an auto-fix:

  • An explicitly supplied size-1 data_parallel_group is treated as intentional and never warns.
  • A genuine single-process run (WORLD_SIZE unset or 1) never warns.
  • It does not change any partitioning behavior, so it cannot break a working setup.

Detection is factored into a small pure helper _unsharded_single_rank_warning(...) so it is unit-testable without a GPU or a live process group.

Tests

tests/unit/runtime/zero/test_zero_init_unsharded_warning.py covers:

  • warns when launcher WORLD_SIZE>1 but group is single-rank,
  • no warning for a genuine single-process run (WORLD_SIZE unset / 1),
  • no warning when the group actually shards (dp_world_size>1),
  • no warning when an explicit data_parallel_group is supplied,
  • malformed WORLD_SIZE values do not raise.

Made with Cursor

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

…#8084)

When a multi-process launcher sets WORLD_SIZE>1 but the distributed
process group is not initialized before zero.Init runs (e.g.
from_pretrained before deepspeed.init_distributed()), the resolved group
collapses to a single rank. zero.Init then materializes every parameter
whole on every rank instead of partitioning, so each rank loads the full
model and OOMs with no diagnostic. Detect this case and emit an
actionable warning pointing at the missing init_distributed() call.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: FNU AKSHANSH <105249360+akshansh47@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@akshansh47 akshansh47 force-pushed the fix/zero-init-unsharded-single-rank-warning branch from 34c5b28 to 642a9d2 Compare June 25, 2026 18:41
@sfc-gh-truwase

Copy link
Copy Markdown
Collaborator

@akshansh47 thanks for the PR. Do you know why init_distributed() fails? I think the better solution is to make it work.
https://github.com/akshansh47/DeepSpeed/blob/642a9d2827218bd5465d553933f9d75afcc3ce31/deepspeed/runtime/zero/partition_parameters.py#L1046-L1048

@akshansh47

Copy link
Copy Markdown
Author

Good question — I dug into this, and in this scenario init_distributed() doesn't actually fail. zero.Init already auto-initializes when no process group exists:

# partition_parameters.py L1017-1019
if not dist.is_initialized():
    init_distributed()
    assert dist.is_initialized(), "Parameters cannot be scattered without initializing deepspeed.comm"

and when the launcher env (RANK/WORLD_SIZE/MASTER_ADDR/MASTER_PORT) is visible, that path initializes at the correct world size. So the silent world_size=1 outcome reported in #8084 arises when the gate is skipped: a process group already exists at zero.Init time but is single-rank — e.g. user code or another library (accelerate/transformers init paths, per-GPU Ray actors, notebook helpers) called init_process_group earlier with a size-1 world, before from_pretrained ran under the active HfDeepSpeedConfig.

In that case I don't think DeepSpeed can safely "make it work": the existing PG is user/library state, and respecting it is correct — tearing it down and re-initializing from env inside zero.Init would be surprising and unsafe (in-flight collectives, custom groups). What DeepSpeed can own is detecting the contradiction (launcher says WORLD_SIZE>1, resolved group is size 1, no explicit data_parallel_group passed) and saying loudly that nothing will be partitioned — which is what this PR does.

Happy to adjust if you'd prefer a different behavior:

  1. keep it a warning (current PR),
  2. escalate to a hard error (strictest, but could break exotic-but-intentional setups), or
  3. attempt re-init from env behind an opt-in flag (I'd advise against default-on for the reasons above).

I've also asked the reporter on #8084 to share their exact init order to confirm which actor created the single-rank group in their case.

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.

zero.Init silently does not shard (world_size=1) when the process group is uninitialized before from_pretrained -> per-rank full load -> OOM

2 participants