@@ -1394,9 +1394,10 @@ def save_checkpoint(
13941394 rank = torch .distributed .get_rank () if torch .distributed .is_initialized () else 0
13951395
13961396 # Collect cfg, model, RNG.
1397- sharded_sd_metadata = _build_sharded_state_dict_metadata (uses_distributed_optimizer (cfg .optimizer ), ckpt_cfg )
1397+ use_distributed_optimizer = _uses_distributed_optimizer (cfg .optimizer , optimizer )
1398+ sharded_sd_metadata = _build_sharded_state_dict_metadata (use_distributed_optimizer , ckpt_cfg )
13981399 sharded_sd_metadata ["dp_cp_group" ] = _checkpoint_dp_cp_group (pg_collection )
1399- if uses_distributed_optimizer ( cfg . optimizer ) :
1400+ if use_distributed_optimizer :
14001401 print_rank_0 (
14011402 f"Storing distributed optimizer sharded state of type { sharded_sd_metadata ['distrib_optim_sharding_type' ]} "
14021403 )
@@ -2913,6 +2914,7 @@ def _load_checkpoint_from_path(
29132914 model = unwrap_model (model )
29142915 pg_collection = pg_collection or get_pg_collection (model )
29152916 ckpt_format = cfg .checkpoint .ckpt_format
2917+ use_distributed_optimizer = _uses_distributed_optimizer (cfg .optimizer , optimizer )
29162918
29172919 # HuggingFace-format directories are only honored for pretrained model
29182920 # initialization. Resume training via ``checkpoint.load`` should use a
@@ -3048,9 +3050,7 @@ def _load_checkpoint_from_path(
30483050
30493051 if ckpt_type == CheckpointType .LOCAL :
30503052 # Local checkpoints don't store content metadata in common.pt.
3051- sharded_sd_metadata = _build_sharded_state_dict_metadata (
3052- uses_distributed_optimizer (cfg .optimizer ), cfg .checkpoint
3053- )
3053+ sharded_sd_metadata = _build_sharded_state_dict_metadata (use_distributed_optimizer , cfg .checkpoint )
30543054 else :
30553055 sharded_sd_metadata = dist_checkpointing .load_content_metadata (preloaded_state_dict = state_dict )
30563056 print_rank_0 (f"sharded_state_dict metadata loaded from the checkpoint: { sharded_sd_metadata } " )
@@ -3065,23 +3065,23 @@ def _load_checkpoint_from_path(
30653065 gen_sd_optim = optimizer
30663066 gen_sd_opt_param_scheduler = opt_param_scheduler
30673067
3068- if uses_distributed_optimizer ( cfg . optimizer ) :
3068+ if use_distributed_optimizer :
30693069 if sharded_sd_metadata is None :
30703070 sharded_sd_metadata = {
30713071 "distrib_optim_sharding_type" : (
30723072 "fully_sharded_model_space"
3073- if run_config ["checkpoint" ]["fully_parallel_save" ]
3073+ if not cfg .optimizer .use_distributed_optimizer
3074+ or run_config ["checkpoint" ]["fully_parallel_save" ]
30743075 else "dp_zero_gather_scatter"
30753076 ),
30763077 }
3077- if (
3078- not tp_pp_match
3079- and sharded_sd_metadata ["distrib_optim_sharding_type" ]
3080- not in DistributedOptimizer .checkpoint_fully_reshardable_formats
3081- ):
3078+ # Older mixed-optimizer checkpoints omitted this key and used
3079+ # DistributedOptimizer's model-space default.
3080+ sharding_type = sharded_sd_metadata .get ("distrib_optim_sharding_type" , "fully_sharded_model_space" )
3081+ if not tp_pp_match and sharding_type not in DistributedOptimizer .checkpoint_fully_reshardable_formats :
30823082 raise RuntimeError (
30833083 f"{ mismatch_msg } : not supported for DistributedOptimizer with sharding type"
3084- f" { sharded_sd_metadata [ 'distrib_optim_sharding_type' ] } ."
3084+ f" { sharding_type } ."
30853085 f" Please use `checkpoint_config.fully_parallel_save=True` for checkpoint saving."
30863086 )
30873087 else :
@@ -3199,7 +3199,7 @@ def _load_checkpoint_from_path(
31993199 print_rank_0 ("Optimizer state was not saved in the FSDP checkpoint; using a fresh optimizer" )
32003200
32013201 optim_sd_kwargs = dict (
3202- metadata = _build_sharded_state_dict_metadata (uses_distributed_optimizer ( cfg . optimizer ) , cfg .checkpoint ),
3202+ metadata = _build_sharded_state_dict_metadata (use_distributed_optimizer , cfg .checkpoint ),
32033203 is_loading = True ,
32043204 )
32053205 # DTensor optimizer state does not contain dtype-keyed FQNs.
@@ -4149,6 +4149,20 @@ def load_fsdp_dtensor_checkpoint(
41494149 return state_dict , checkpoint_name , release , CheckpointType .FSDP_DTENSOR
41504150
41514151
4152+ def _has_distributed_optimizer (optimizer : MegatronOptimizer | None ) -> bool :
4153+ """Find tensor-sharded DistributedOptimizer leaves inside optimizer wrappers."""
4154+ if isinstance (optimizer , DistributedOptimizer ):
4155+ return True
4156+ if not isinstance (optimizer , MegatronOptimizer ):
4157+ return False
4158+ return any (_has_distributed_optimizer (child ) for child in getattr (optimizer , "chained_optimizers" , ()))
4159+
4160+
4161+ def _uses_distributed_optimizer (config : Any , optimizer : MegatronOptimizer | None ) -> bool :
4162+ """Combine declared LayerWise mode with the constructed optimizer tree."""
4163+ return uses_distributed_optimizer (config ) or _has_distributed_optimizer (optimizer )
4164+
4165+
41524166def _build_sharded_state_dict_metadata (use_distributed_optimizer : bool , cfg : CheckpointConfig ) -> dict :
41534167 """Builds metadata used for sharded_state_dict versioning.
41544168
0 commit comments