Skip to content

Commit 6a40c9e

Browse files
committed
[sync][training] fix: honor checkpoint sharding validation policy
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com>
1 parent b1bb0a9 commit 6a40c9e

2 files changed

Lines changed: 96 additions & 2 deletions

File tree

‎src/megatron/bridge/training/checkpointing.py‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@
119119
_get_legacy_grad_dtypes = getattr(distrib_optimizer, "get_legacy_grad_dtypes", None)
120120
_CHECKPOINT_FORMAT_VERSION = 3.1 if _get_legacy_grad_dtypes is not None else 3.0
121121

122+
# The supported dev pin exposes a load-only policy and has no save-side opt-out.
123+
_FULLY_PARALLEL_SAVE_HAS_VALIDATION_POLICY = (
124+
"validate_access_integrity" in inspect.signature(FullyParallelSaveStrategyWrapper).parameters
125+
)
126+
122127

123128
_, HAVE_RESIL = safe_import("nvidia_resiliency_ext.checkpointing")
124129

@@ -1532,11 +1537,19 @@ def save_checkpoint(
15321537
logger.debug("Failed to plug in the read metadata from the load strategy...")
15331538

15341539
if ckpt_cfg.fully_parallel_save:
1540+
validation_kwargs = (
1541+
{"validate_access_integrity": ckpt_cfg.ckpt_load_validate_sharding_integrity}
1542+
if _FULLY_PARALLEL_SAVE_HAS_VALIDATION_POLICY
1543+
else {}
1544+
)
15351545
save_strategy = FullyParallelSaveStrategyWrapper(
15361546
save_strategy,
15371547
_checkpoint_dp_cp_group(pg_collection),
15381548
ckpt_cfg.ckpt_assume_constant_structure,
1549+
**validation_kwargs,
15391550
)
1551+
if _FULLY_PARALLEL_SAVE_HAS_VALIDATION_POLICY and not ckpt_cfg.ckpt_load_validate_sharding_integrity:
1552+
validate_sharding_integrity = False
15401553
# MegatronMIMO + torch_dist can hit known access-pattern validation failures
15411554
# for nested DDP language model tensors in PP>1 runs when
15421555
# fully_parallel_save is disabled. Keep validation enabled otherwise.
@@ -3839,7 +3852,7 @@ def _load_global_dist_base_checkpoint(
38393852
load_strategy = FullyParallelLoadStrategyWrapper(load_strategy, _checkpoint_dp_cp_group(pg_collection))
38403853
if checkpointing_context is not None:
38413854
checkpointing_context["load_strategy"] = load_strategy
3842-
validate_sharding_integrity = True
3855+
validate_sharding_integrity = ckpt_cfg.ckpt_load_validate_sharding_integrity
38433856
if is_megatron_mimo and ckpt_cfg.ckpt_format == "torch_dist" and not ckpt_cfg.fully_parallel_save:
38443857
validate_sharding_integrity = False
38453858
if cfg is not None:

‎tests/unit_tests/training/test_checkpointing.py‎

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
_has_global_non_persistent_checkpoint,
5757
_load_base_checkpoint,
5858
_load_checkpoint_from_path,
59+
_load_global_dist_base_checkpoint,
5960
_load_hf_pretrained_checkpoint,
6061
_load_model_state_dict,
6162
_load_non_persistent_base_checkpoint,
@@ -846,7 +847,22 @@ def test_metadata_failure_does_not_publish_incomplete_checkpoint(self, tmp_path,
846847
assert torch.load(latest_train_state, weights_only=True)["step"].item() == 500
847848
assert legacy_tracker.read_text() == "500"
848849

850+
@pytest.mark.parametrize("save_validation_supported", [True, False])
849851
@pytest.mark.parametrize("save_rng", [True, False])
852+
@pytest.mark.parametrize("validate_sharding", [True, False])
853+
@pytest.mark.parametrize(
854+
"fully_parallel,cached_strategy,constant_structure,is_mimo",
855+
[
856+
(False, False, False, False),
857+
(True, False, False, False),
858+
(False, True, True, False),
859+
(True, True, True, False),
860+
(True, True, False, False),
861+
(False, False, False, True),
862+
(True, False, False, True),
863+
],
864+
)
865+
@patch("megatron.bridge.training.checkpointing.FullyParallelSaveStrategyWrapper")
850866
@patch("megatron.bridge.training.checkpointing.wandb_utils")
851867
@patch("megatron.bridge.training.checkpointing.is_last_rank")
852868
@patch("builtins.open", new_callable=mock_open)
@@ -893,10 +909,29 @@ def test_save_checkpoint_global(
893909
mock_file_open,
894910
mock_is_last_rank,
895911
mock_wandb,
912+
mock_parallel_strategy,
896913
save_checkpoint_fixtures,
914+
monkeypatch,
915+
save_validation_supported,
897916
save_rng,
917+
validate_sharding,
918+
fully_parallel,
919+
cached_strategy,
920+
constant_structure,
921+
is_mimo,
898922
):
899923
"""Test saving a global checkpoint."""
924+
monkeypatch.setattr(
925+
"megatron.bridge.training.checkpointing._FULLY_PARALLEL_SAVE_HAS_VALIDATION_POLICY",
926+
save_validation_supported,
927+
raising=False,
928+
)
929+
if not save_validation_supported:
930+
# Match the supported dev pin's constructor: a new keyword must fail this test.
931+
def legacy_wrapper(strategy, parallelization_group, do_cache_distribution):
932+
return Mock()
933+
934+
mock_parallel_strategy.side_effect = legacy_wrapper
900935
# Setup mocks
901936
mock_dist_init.return_value = True
902937
mock_get_dist_rank.return_value = 0
@@ -929,6 +964,12 @@ def test_save_checkpoint_global(
929964
save_checkpoint_fixtures["mock_state"].wandb_logger = Mock()
930965
save_checkpoint_fixtures["mock_state"].cfg.checkpoint.most_recent_k = -1
931966
save_checkpoint_fixtures["mock_state"].cfg.checkpoint.save_rng = save_rng
967+
save_checkpoint_fixtures["mock_state"].cfg.checkpoint.ckpt_load_validate_sharding_integrity = validate_sharding
968+
save_checkpoint_fixtures["mock_state"].cfg.checkpoint.fully_parallel_save = fully_parallel
969+
save_checkpoint_fixtures["mock_state"].cfg.checkpoint.ckpt_assume_constant_structure = constant_structure
970+
if not is_mimo:
971+
del save_checkpoint_fixtures["mock_model"][0].mimo_config
972+
checkpoint_context = {"save_strategy": Mock()} if cached_strategy else {}
932973

933974
call_order = Mock()
934975
call_order.attach_mock(mock_dist_ckpt.save, "model")
@@ -941,7 +982,7 @@ def test_save_checkpoint_global(
941982
save_checkpoint_fixtures["mock_optimizer"],
942983
save_checkpoint_fixtures["mock_scheduler"],
943984
1000000,
944-
checkpointing_context={},
985+
checkpointing_context=checkpoint_context,
945986
non_persistent_ckpt=False,
946987
)
947988

@@ -951,6 +992,19 @@ def test_save_checkpoint_global(
951992
mock_ft.on_checkpointing_start.assert_called_once()
952993
mock_gen_state.assert_called_once()
953994
mock_dist_ckpt.save.assert_called_once()
995+
expected_validation = (validate_sharding or not save_validation_supported) and not (
996+
(cached_strategy and constant_structure) or (is_mimo and not fully_parallel)
997+
)
998+
assert mock_dist_ckpt.save.call_args.kwargs["validate_access_integrity"] is expected_validation
999+
if fully_parallel and not cached_strategy:
1000+
if save_validation_supported:
1001+
assert (
1002+
mock_parallel_strategy.call_args.kwargs.get("validate_access_integrity", True) is validate_sharding
1003+
)
1004+
else:
1005+
assert "validate_access_integrity" not in mock_parallel_strategy.call_args.kwargs
1006+
else:
1007+
mock_parallel_strategy.assert_not_called()
9541008
if save_rng:
9551009
mock_get_rng.assert_called_once()
9561010
else:
@@ -6836,3 +6890,30 @@ def test_checkpoint_minor_version_changes_are_compatible(monkeypatch, versions):
68366890
assert checkpointing.get_checkpoint_version() == versions[-1]
68376891
with pytest.raises(AssertionError, match="checkpoint versions do not match"):
68386892
checkpointing.set_checkpoint_version(2.0)
6893+
6894+
6895+
@pytest.mark.unit
6896+
@pytest.mark.parametrize("validate_sharding", [True, False])
6897+
@pytest.mark.parametrize("fully_parallel", [True, False])
6898+
@pytest.mark.parametrize("is_mimo", [True, False])
6899+
def test_global_checkpoint_load_honors_sharding_validation(
6900+
validate_sharding: bool, fully_parallel: bool, is_mimo: bool
6901+
) -> None:
6902+
"""Public checkpoint policy must reach the Core loader."""
6903+
cfg = CheckpointConfig(
6904+
ckpt_format="torch_dist",
6905+
ckpt_load_validate_sharding_integrity=validate_sharding,
6906+
fully_parallel_load=fully_parallel,
6907+
fully_parallel_save=fully_parallel,
6908+
)
6909+
pg_collection = Mock()
6910+
with (
6911+
patch("megatron.bridge.training.checkpointing.TorchDistLoadShardedStrategy"),
6912+
patch("megatron.bridge.training.checkpointing.FullyParallelLoadStrategyWrapper"),
6913+
patch("megatron.bridge.training.checkpointing.dist_checkpointing.load", return_value={}) as load,
6914+
):
6915+
_load_global_dist_base_checkpoint(
6916+
"checkpoints", cfg, False, {"model": {}}, 1, False, is_megatron_mimo=is_mimo, pg_collection=pg_collection
6917+
)
6918+
expected_validation = validate_sharding and not (is_mimo and not fully_parallel)
6919+
assert load.call_args.kwargs["validate_access_integrity"] is expected_validation

0 commit comments

Comments
 (0)