Repository navigation
Conversation
A universal checkpoint converted from ZeRO-3 could not be loaded into ZeRO-1/2, and one converted from ZeRO-1/2 could not be loaded into ZeRO-3: - the engine looked only for the model-states file named by its own stage; - the ZeRO-3 converter dropped ds_version, which the ZeRO-1/2 loader asserts on; - the ZeRO-1/2 loader expected dict-wrapped states, but the ZeRO-3 converter writes bare flat tensors; - the step was read from where the target's own stage keeps it. Fall back to the other stage's file name on universal loads, copy ds_version in the converter, accept flat tensors when they fill the whole parameter, and read the step and param_groups from either layout. Signed-off-by: Jin, Youzhi <youzhi.jin@intel.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.
A universal checkpoint converted from a ZeRO-3 run cannot be loaded into ZeRO-1/2, and one converted from a ZeRO-1/2 run cannot be loaded into ZeRO-3. This PR makes both directions load, with the fp32 master weights, Adam states and step restored exactly.
Reproduction
Train under one stage,
save_checkpoint, runds_to_universal, thenload_checkpoint(..., load_optimizer_states=True)withcheckpoint.load_universal: trueunder the other stage. On master a75ab89 each gap below surfaces once the previous one is worked around:assert len(self.ckpt_list) > 0_get_all_ckpt_namesglobs only the current stage's model-states name:zero_pp_rank_0_mp_rank_*_model_states.ptfor ZeRO-3,mp_rank_*_model_states.ptfor ZeRO-1/2. A universal load reads only metadata from this file, so either name works.AssertionError: Empty ds_version_save_optimizer_state_stage3writes the inner optimizer dict, but ZeRO-3 keepsds_versionbeside it.DeepSpeedZeroOptimizer._load_global_stateasserts on it.IndexError: too many indices for tensor of dimension 1merge_zero3_slices) writes each state as a bare flat tensor;load_hp_checkpoint_stateindexesckpt_dict[PARAM]. The stage-3 loader already accepts both forms.step.pt; its step is inoptimizer_state_dict.state.KeyError: 'optimizer_state_dict'param_groupsfromoptimizer_state_dict, which a ZeRO-1/2 source does not have (it has top-levelparam_groupsand per-parameterstep.pt).Changes
engine._get_all_ckpt_names: on a universal load with no match, glob the other stage's name, built by_get_ckpt_name(new optionalpartition_weightsargument).ds_to_universal._save_optimizer_state_stage3: copyds_versionintozero/optimizer_state.pt.universal_checkpoint.py:load_hp_checkpoint_stateviews a bare flat tensor as the parameter's shape. A flat tensor carries no TP layout, so if it does not fill the whole parameter (ZeRO-3 source → ZeRO-1/2 with TP>1) it raises aValueErrorsaying so, instead of anIndexError.load_universal_optimizer_stepreads the step from either layout. It is used by the ZeRO-1/2 path (ZeROOptimizer.load_hp_checkpoint_state_from_checkpoint_dir, when nostep.ptexists) and by the ZeRO-3 path.stage3.load_hp_checkpoint_state_from_checkpoint_dir_stage3: takeparam_groupsfrom the top level when present (the ZeRO-3 converter has always written it there too).Same-stage loads take the same paths as before: every new branch is reached only when the old lookup finds nothing.
Sibling paths checked:
BF16_Optimizersharesload_hp_checkpoint_state_from_checkpoint_dirand its_load_global_stateis a no-op, so it gets fixes 3 and 4 and is unaffected by 2.stage_1_and_2andstage3are both patched.Not a duplicate
No existing issue or PR covers cross-stage universal loading. #9069 also touches bare flat tensors but fixes the ZeRO-3 + AutoTP load path, not ZeRO-1/2 targets. #7546, #8848 and #8898 are different bugs.
Tests
New
TestUniversalCheckpointAcrossZeROStagesintests/unit/checkpoint/test_universal_checkpoint.py(world size 2, fp32,torch.optim.Adam), parametrized over (1→3), (2→3), (3→1), (3→2). It trains 2 steps, saves, converts, loads into the other stage, then checks:exp_avgandexp_avg_sqof every parameter aretorch.equalto the source (the conversion only moves fp32 data, so the comparison is exact);Hardware: Intel Arc Pro B70 (XPU), Linux 6.19.10 in-tree
xedriver, compute runtime 26.27.39122.11, torch 2.14.0.dev20260804+xpu. Run from the repo root.assert len(self.ckpt_list) > 0)Regression on B70, master and this PR in the same environment:
TestUniversalCheckpointAcrossZeROStagescases.TestZeROUniversalCheckpointDPwith ZeRO-1 andload_optim=True: the bit-exact optimizer-state check fails intermittently on this XPU setup. Which cases fail changes from run to run; re-running 7 of them gave 5/7 failures with this PR and 4/7 and 5/7 on master.TestRealCheckpointUniversalConversionTPxPP:No backend type associated with device type xpu.End to end on B70 (2 ranks): Qwen3-0.6B, bf16,
torch.optim.AdamW. Train 2 steps under one stage, save,ds_to_universal, load under the other stage, and comparesafe_get_full_fp32_param/safe_get_full_optimizer_statebefore and after:Validated matrix cells
Limitations
ds_version, so loading it into ZeRO-1/2 still fails the version assert; re-runds_to_universalon the original checkpoint.AI assistance
This PR was prepared with AI assistance (GitHub Copilot CLI), covering the root-cause analysis, the code, the tests and this description. I reviewed the changes and ran the tests reported above on the hardware listed.