Repository navigation
Universal Checkpointing: read AutoEP ZeRO-3 optimizer files one at a time - #8844
Draft
pengdurice wants to merge 1 commit into
Draft
pengdurice wants to merge 1 commit into
pengdurice wants to merge 1 commit into
Conversation
…time Signed-off-by: pengdurice <pengduhit@gmail.com>
banxingmjj
pushed a commit
to openanolis/DeepSpeed
that referenced
this pull request
Oct 26, 2026
…pspeedai#8800) ## Summary deepspeedai#8623 plans shard-to-shard copies between two `ParamAffineMap`s. Today, though, the only AutoEP maps come from checkpoint metadata, so nothing at runtime can feed the planner. This PR closes that gap: it builds the source map from the placement the live `AutoEPMoELayer` actually holds, and builds the target map from a target placement descriptor. Both maps then go straight to `plan_transfer`. ``` AutoEP runtime placement -> source / target ParamAffineMap -> plan_transfer (deepspeedai#8623) -> copy descriptors ``` Maps of what each process actually stores under expert data parallelism (EDP) and ZeRO are left to a follow-up, which builds them by nesting these layout maps with ZeRO's storage maps. Related: deepspeedai#8252 (§8.4 AutoEP expert placement), deepspeedai#8230, deepspeedai#8544. ## Changes - `AutoEPMoELayer.expert_affine_maps()` returns the affine maps of the live `w1`/`w2`/`w3`. - Map ranks are EP-local ranks. The docstring explains how to translate them with `dist.get_global_rank(self.ep_group, rank)`. - Each shard is the unpartitioned packed `[local_experts, ...]` tensor. ZeRO-3/EDP fragments stay outside the map, and the shape comes from `ds_shape`. - No collectives. - `AutoEPMoELayer.plan_expert_transfer(target_placement, limits=None, *, replica_selector=None)` returns one `TransferPlan` per expert parameter. - It only plans: it moves no data, swaps no parameters and migrates no optimizer state. - `autoep_affine.plan_autoep_placement_transfer(source_placement, target_placement, logical_shape, ...)` is the layer-independent form. Both placements go through the existing `autoep_placement_to_affine_map`, so no second placement→map conversion is introduced. - Placements are compared by explicit rank IDs rather than list order (`autoep_placements_equal`), and each parameter's published `DS_AUTOEP_UC_META` placement and affine map must equal the live lowering. - The live placement must match how `repack_expert_weights` actually packed the weights; today that is contiguous and uniform. A descriptor that disagrees raises `NotImplementedError`, rather than producing a map that addresses shards the weights do not have. - A placement the descriptor can express is not necessarily one the runtime can execute. The target placement is only used for planning. ## Not in scope - Executing plans or transporting data (deepspeedai#8809), parameter swap, optimizer-state migration. - Storage maps of EDP replicas and ZeRO-3 fragments (follow-up PR), and replica selection policy (deepspeedai#8252). - Placement generation/versioning: the runtime does not change placement after construction yet. - Runtime support for non-uniform placements. ## Tests `tests/unit/v1/moe/test_autoep_unit.py`: - `test_live_expert_maps_address_the_packed_runtime_weights`: for each rank, the map's shard shape and contents match the real packed `w1/w2/w3`. The reference is the full tensor from `repack_expert_weights(ep_size=1)`, which does not depend on any affine map. - `test_plan_expert_transfer_moves_live_shards_into_target_packed_order`: from EP=2 into 3 ranks with reordered, uneven, empty and replicated placements; executing the plan reproduces the target shards, every element is written once, and planning never calls `rebuild`/`extract`. - `test_live_expert_maps_reject_a_placement_the_weights_do_not_have`, `test_live_expert_maps_identify_placement_ranks_by_id`, `test_live_expert_maps_reject_a_published_map_the_placement_does_not_produce`. `tests/unit/checkpoint/test_autoep_affine.py`: `test_placements_equal_identifies_ranks_by_id`. Results (Intel Arc Pro B70): - `test_autoep_unit.py`, `test_autoep_affine.py`, `test_autoep_affine_universal.py`, `test_affine_transfer_plan.py`, `test_affine_shard_map.py`, `test_autoep_zero3_metadata.py`: 432 passed, 6 skipped. - `test_autoep_checkpoint.py` (8× B70): 32 passed, 2 skipped. ## Contribution checklist **Related work.** - This PR builds on deepspeedai#8623 (`plan_transfer`). - Plan execution is deepspeedai#8809; replica policy is deepspeedai#8252. - deepspeedai#8844 and deepspeedai#8848 change Universal Checkpointing for AutoEP. They do not produce runtime maps. A search for AutoEP placement and transfer and for affine maps found no overlapping PR. **Commands and results.** Hardware and software: 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/v1/moe/test_autoep_unit.py tests/unit/checkpoint/test_autoep_affine.py \ tests/unit/checkpoint/test_autoep_affine_universal.py tests/unit/checkpoint/test_affine_transfer_plan.py \ tests/unit/checkpoint/test_affine_shard_map.py tests/unit/checkpoint/test_autoep_zero3_metadata.py pytest -p no:randomly tests/unit/v1/moe/test_autoep_checkpoint.py ``` Results are listed under Tests above. **Numerics, performance, memory.** Training is not affected. The new methods only run when called and use no collectives. **Compatibility matrix.** | | Validated | Not validated | |---|---|---| | ZeRO | Independent: maps describe the unpartitioned packed tensors | Storage under EDP/ZeRO (follow-up) | | Parallelism | EP=2; target placements on 3 ranks | | | Precision | Dtype-independent: maps describe shapes and offsets | | | 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. --------- Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Universal Checkpointing: read AutoEP ZeRO-3 optimizer files one at a time
Problem
ds_to_universalconverts a ZeRO-3 AutoEP checkpoint in two parts. The dense parameters go through the usualextract-and-merge path, which reads one optimizer file per worker and writes fragments to
tmp/. The routed expertsgo through
_consolidate_zero3_autoep_expert_states, which first loads every rank's optimizer file into one dict(
optim_states_by_rank) and then keeps a copy of every expert fragment in memory until all of them are merged.Together those files hold every optimizer state of the model: fp32 (or bf16) master weights plus both Adam moments.
For a large MoE model that is more than one host has:
The H200 nodes this was found on have 2 TiB of host memory, so the conversion cannot finish for either model.
Change
_consolidate_zero3_autoep_expert_statesreads one rank's optimizer file at a time. Each expert fragment it finds iswritten to
<output>/tmp/autoep_expert_fragments/(one file per parameter, optimizer state, EP rank and partitionrank) and the rank's file is released before the next one is read. The merge then loads, for one parameter and one
state at a time, only that parameter's fragments. Peak host memory becomes one optimizer file plus one full expert
tensor, instead of all optimizer files.
The checks are unchanged: missing ranks, duplicate or missing expert-data-parallel partitions, shape mismatches and
placement disagreements raise the same errors. The temporary fragments live under
<output>/tmp, which the converteralready uses for the dense fragments and removes at the end.
Tests
tests/unit/checkpoint/test_autoep_affine_universal.py(calls the function directly; CPU)tests/unit/v1/moe/test_autoep_checkpoint.py(AutoEP ZeRO-3 save, convert, load at other layouts; GPU)Hardware for the GPU tests: 1 node of 8 H200 (driver 580.126.09), torch 2.8.0+cu126, pytest 9.1.1.
pre-commit run --filespasses on the changed file.Not measured: the peak host memory of a full-size conversion before and after. The bound follows from the code:
before, every rank's optimizer file is loaded at once (for MiniMax-M3 with fp32 master weights and fp32 Adam states,
4.65 TiB in total, more than the 2 TiB of the H200 hosts this was found on); after, one rank's file plus one
parameter's fragments.
Duplicate check
Searched open and recent pull requests on 2026-10-15 ("universal checkpoint", "ds_to_universal", "AutoEP
checkpoint"): #8800 plans live expert transfers between placements and #8637 links ZeRO-1/2 fragments; neither
changes how
ds_to_universalreads the ZeRO-3 AutoEP optimizer files.Compatibility
AI assistance
This change, its tests and this description were prepared with AI assistance (Claude).