Repository navigation
Conversation
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.
PR type
PR information
Summary
AccelerateStrategy.save_optimizer_checkpoint/load_optimizer_checkpointcan crash withKeyError: 0insidetorch.distributed.checkpoint.state_dictwhen an optimizer checkpoint is saved after ano_gradevaluation of an FSDP2 model whose parameters are not all individually wrapped byfully_shard(VL models with a visual tower, tied-weight tail groups, etc.). This PR reshards any FSDP2 param group left unsharded before the state-dict conversion.Root cause
Three behaviors combine:
reshard_after_forward=None, which PyTorch's heuristic resolves toFalse(accelerate/utils/fsdp_utils.py:883-888); tied-weight tail groups are also created withreshard_after_forward=False(accelerate/utils/fsdp_utils.py:879).nn.Parameteron unshard (to_unsharded) and back to shardedDTensoron reshard (to_sharded). Withreshard_after_forward=False,reshard()early-returns in theFORWARDstate, so unsharding is only undone by the post-backward reshard. Ano_gradevaluation never runs backward, so params stay materialized as fullnn.Parameter, while the optimizer still holds the shardedDTensorit was switched to byfsdp2_switch_optimizer_parameters.get/set_optimizer_state_dictmaps optimizer params back to model params by object identity. The stale full-nn.Parameterobjects are not inmodel.named_parameters(), so_get_optim_state_dictraises:Training itself is unaffected (gradients flow through the unsharded params and are reduce-scattered into the sharded
DTensors the optimizer holds); only the identity-based checkpoint conversion breaks.Repro conditions: accelerate FSDP2 + a
no_gradeval pass + params outside individually-wrapped groups. OnQwen3.6-27B(qwen3_5, VL) with 8-rank HSDP LoRA training this crashes at the first eval-then-save on every rank, with 220/1212 optimizer params missing frommodel.named_parameters().Fix
Add
AccelerateStrategy._reshard_unsharded_fsdp_params(model)— walk the model tree and call the publicFSDPModule.reshard()API ("freeing the unsharded parameters if they are allocated"; a safe no-op for already-sharded groups) — and invoke it in the FSDP2 branches of both:save_optimizer_checkpoint, beforeget_optimizer_state_dictload_optimizer_checkpoint, beforeset_optimizer_state_dict(the load path has the symmetric identity-mapping problem when resuming right after an eval)Cookbook-level workarounds are unnecessary after this.
Impact
Experiment results
Environment: 8 × Ascend910 (64GB), CANN 9.0.0, torch 2.10.0 / torch_npu 2.10.0, accelerate 1.15.0, transformers 5.5.4.
Task:
cookbook/transformers/fsdp2.shLoRA SFT (FSDP2, fsdp_size=2 × dp_size=4, Muon optimizer, GSM8K_zh dataset).Before (this PR) — training healthy, crash at first eval-then-save on every rank
After (this PR) — full run passes end to end, 0 exceptions
Quick regression (8 steps, eval every 2): 4 evals + 4 checkpoint saves all pass; no behavioral change to the training loop.