Skip to content

Fix checkpoint rank selection for Ulysses sequence parallelism - #8226

Open
sfc-gh-thonguyen wants to merge 2 commits into
deepspeedai:masterfrom
Snowflake-Labs:fix/ulysses-checkpoint-mp-rank
Open

Fix checkpoint rank selection for Ulysses sequence parallelism#8226
sfc-gh-thonguyen wants to merge 2 commits into
deepspeedai:masterfrom
Snowflake-Labs:fix/ulysses-checkpoint-mp-rank

Conversation

@sfc-gh-thonguyen

Copy link
Copy Markdown

Summary

  • use checkpoint model-parallel rank 0 for Ulysses sequence parallelism
  • centralize checkpoint rank selection across model, expert, optimizer, and ZeRO checkpoint paths
  • preserve the real model-parallel rank for tensor-parallel MPUs

Problem

Ulysses sequence parallelism does not shard model weights, so DeepSpeed records mp_world_size == 1. However, the Ulysses MPU aliases get_model_parallel_rank() to the sequence-parallel rank. Checkpoint loading combined those values when selecting a model-state file, causing SP ranks greater than zero to index past a single non-SP checkpoint shard.

The same rank interpretation was also used for checkpoint filenames, so this change keeps save and load behavior consistent for replicated SP weights and optimizer shards.

Tests

  • pytest tests/unit/sequence_parallelism/test_ulysses.py -k 'CheckpointRank or load_non_sequence_parallel_checkpoint' -q (3 passed)
  • pytest tests/unit/checkpoint/test_latest_checkpoint.py -q (2 passed)
  • pre-commit run --files deepspeed/runtime/engine.py tests/unit/sequence_parallelism/test_ulysses.py

The distributed regression saves without SP, loads module-only with SP=2, then saves and fully resumes the SP checkpoint.

@stas00 stas00 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you for the fix, Thong.

I have a small simplification suggestion, but otherwise looks great.

Comment thread deepspeed/runtime/engine.py Outdated
@sfc-gh-thonguyen
sfc-gh-thonguyen force-pushed the fix/ulysses-checkpoint-mp-rank branch from da455ab to 86ab256 Compare August 6, 2026 20:51
Comment thread deepspeed/runtime/engine.py Outdated
@sfc-gh-thonguyen
sfc-gh-thonguyen force-pushed the fix/ulysses-checkpoint-mp-rank branch from 86ab256 to c8aa365 Compare August 6, 2026 20:56
Signed-off-by: Thong Nguyen <thong.nguyen@snowflake.com>
@sfc-gh-thonguyen
sfc-gh-thonguyen force-pushed the fix/ulysses-checkpoint-mp-rank branch from c8aa365 to 6df83ff Compare August 6, 2026 20:59
Comment on lines +5056 to +5060
moe_save_path = self._get_expert_ckpt_name(save_dir,
moe_layer_id,
global_expert_id,
tag,
checkpoint_mp_rank=self.checkpoint_mp_rank)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is there any time where checkpoint_mp_rank arg isn't self.checkpoint_mp_rank?

if so it doesn't need to be passed as an arg and can be pulled from self, no?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

In DeepSpeedEngine save paths it is always self.checkpoint_mp_rank. However, _get_expert_ckpt_name is static and is also called by static load_moe_state_dict, including from InferenceEngine, where no DeepSpeedEngine instance exists. The optional argument preserves those legacy/static callers while letting DeepSpeedEngine override the MPU rank for Ulysses. So it cannot generally pull the value from self.

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