@@ -4946,6 +4946,7 @@ def test_preprocess_fsdp_dtensor_state_dict(self):
49464946 mock_model_config = Mock ()
49474947 mock_model_config .gated_linear_unit = False
49484948 mock_model_config .num_moe_experts = None
4949+ mock_model_config .pipeline_model_parallel_size = 1
49494950 mock_get_config .return_value = mock_model_config
49504951
49514952 with (
@@ -4956,15 +4957,47 @@ def test_preprocess_fsdp_dtensor_state_dict(self):
49564957 patch ("megatron.bridge.training.checkpointing.handle_gdn_in_state_dict" , None ),
49574958 patch ("megatron.bridge.training.checkpointing.handle_mla_down_proj_in_state_dict" , None ),
49584959 patch ("megatron.bridge.training.checkpointing.handle_mtp_in_state_dict" , None ),
4960+ patch (
4961+ "megatron.bridge.training.checkpointing.handle_pipeline_parallel_in_state_dict" ,
4962+ side_effect = lambda model , state , optim : (state , optim ),
4963+ ) as mock_pipeline ,
49594964 ):
49604965 raw_state_dict = {"model" : {"test_param" : torch .tensor ([1.0 ])}}
49614966 result = preprocess_fsdp_dtensor_state_dict (mock_cfg , raw_state_dict , mock_model )
49624967
49634968 # Should call FP8 and uneven dtensor preprocessing
49644969 mock_fp8 .assert_called_once ()
49654970 mock_uneven .assert_called_once ()
4971+ mock_pipeline .assert_called_once_with (mock_model , raw_state_dict ["model" ], None )
49664972 assert "model" in result
49674973
4974+ @pytest .mark .parametrize ("pp" , [1 , 2 ])
4975+ def test_fsdp_pipeline_checkpoint_requires_core_handler (self , pp : int ) -> None :
4976+ """Old Core remains usable for PP=1 but must not silently corrupt PP>1."""
4977+ from types import SimpleNamespace
4978+
4979+ from megatron .bridge .training import checkpointing
4980+
4981+ model_config = SimpleNamespace (gated_linear_unit = False , num_moe_experts = None , pipeline_model_parallel_size = pp )
4982+ with (
4983+ patch ("megatron.core.utils.get_model_config" , return_value = model_config ),
4984+ patch .object (checkpointing , "handle_fp8_extra_state_case" ),
4985+ patch .object (checkpointing , "preprocess_state_dict_for_uneven_dtensor" ),
4986+ patch .multiple (
4987+ checkpointing ,
4988+ handle_gdn_in_state_dict = None ,
4989+ handle_mla_down_proj_in_state_dict = None ,
4990+ handle_mtp_in_state_dict = None ,
4991+ handle_pipeline_parallel_in_state_dict = None ,
4992+ ),
4993+ ):
4994+ state = {"model" : {"weight" : torch .ones (1 )}}
4995+ if pp > 1 :
4996+ with pytest .raises (RuntimeError , match = "collide stage-local layer names" ):
4997+ checkpointing .preprocess_fsdp_dtensor_state_dict (None , state , None )
4998+ else :
4999+ assert checkpointing .preprocess_fsdp_dtensor_state_dict (None , state , None ) == state
5000+
49685001 @patch ("megatron.bridge.training.checkpointing.HAVE_MEGATRON_FSDP" , True )
49695002 def test_save_fsdp_dtensor_checkpoint_preprocesses_and_saves (self , tmp_path ):
49705003 """Test public FSDP DTensor save helper preprocesses and calls PyTorch DCP."""
0 commit comments