|
35 | 35 | _extract_megatron_lm_args_from_state_dict, |
36 | 36 | _get_checkpoint_format, |
37 | 37 | _get_non_persistent_iteration, |
| 38 | + _has_global_non_persistent_checkpoint, |
38 | 39 | _load_base_checkpoint, |
39 | 40 | _load_checkpoint_from_path, |
40 | 41 | _load_hf_pretrained_checkpoint, |
@@ -1931,6 +1932,116 @@ def mock_pg_collection(self): |
1931 | 1932 | mock_pg.tp.size.return_value = 1 |
1932 | 1933 | return mock_pg |
1933 | 1934 |
|
| 1935 | + def test_global_non_persistent_checkpoint_is_found_under_distinct_save_dir(self, tmp_path): |
| 1936 | + """An unchanged restart discovers the non-persistent checkpoint written under save.""" |
| 1937 | + load_dir = tmp_path / "input" |
| 1938 | + save_dir = tmp_path / "output" |
| 1939 | + non_persistent_dir = save_dir / "non_persistent" |
| 1940 | + non_persistent_dir.mkdir(parents=True) |
| 1941 | + (non_persistent_dir / "latest_train_state.pt").touch() |
| 1942 | + |
| 1943 | + ckpt_cfg = Mock(spec=CheckpointConfig) |
| 1944 | + ckpt_cfg.save = str(save_dir) |
| 1945 | + ckpt_cfg.non_persistent_ckpt_type = "global" |
| 1946 | + ckpt_cfg.non_persistent_global_ckpt_dir = None |
| 1947 | + |
| 1948 | + assert _has_global_non_persistent_checkpoint(str(load_dir), ckpt_cfg) |
| 1949 | + |
| 1950 | + @patch("megatron.bridge.training.checkpointing._load_global_dist_base_checkpoint") |
| 1951 | + @patch("megatron.bridge.training.checkpointing._get_checkpoint_format", return_value="torch_dist") |
| 1952 | + @patch("megatron.bridge.training.checkpointing._load_non_persistent_base_checkpoint") |
| 1953 | + @patch("megatron.bridge.training.checkpointing._resolve_checkpoint_iteration", return_value=(100, False)) |
| 1954 | + def test_newer_global_non_persistent_checkpoint_is_loaded_from_distinct_save_dir( |
| 1955 | + self, |
| 1956 | + _mock_resolve, |
| 1957 | + mock_load_non_persistent, |
| 1958 | + _mock_get_format, |
| 1959 | + mock_load_persistent, |
| 1960 | + tmp_path, |
| 1961 | + base_config, |
| 1962 | + mock_pg_collection, |
| 1963 | + ): |
| 1964 | + """A restart prefers the newer recovery point written under checkpoint.save.""" |
| 1965 | + load_dir = tmp_path / "input" |
| 1966 | + save_dir = tmp_path / "output" |
| 1967 | + non_persistent_dir = save_dir / "non_persistent" |
| 1968 | + non_persistent_dir.mkdir(parents=True) |
| 1969 | + torch.save( |
| 1970 | + TrainState(step=200).state_dict(), |
| 1971 | + get_checkpoint_train_state_filename(str(non_persistent_dir), prefix="latest"), |
| 1972 | + ) |
| 1973 | + |
| 1974 | + base_config.save = str(save_dir) |
| 1975 | + base_config.ckpt_format = "torch_dist" |
| 1976 | + base_config.non_persistent_ckpt_type = "global" |
| 1977 | + base_config.non_persistent_global_ckpt_dir = None |
| 1978 | + expected = ({"model": "newer"}, str(non_persistent_dir / "iter_0000200"), False, CheckpointType.GLOBAL) |
| 1979 | + mock_load_non_persistent.return_value = expected |
| 1980 | + |
| 1981 | + checkpointing_context = {} |
| 1982 | + result = _load_base_checkpoint( |
| 1983 | + str(load_dir), |
| 1984 | + base_config, |
| 1985 | + checkpointing_context=checkpointing_context, |
| 1986 | + pg_collection=mock_pg_collection, |
| 1987 | + ) |
| 1988 | + |
| 1989 | + assert result == expected |
| 1990 | + assert mock_load_non_persistent.call_args.args[0] == str(non_persistent_dir) |
| 1991 | + assert mock_load_non_persistent.call_args.args[4] == 200 |
| 1992 | + assert checkpointing_context["dataloader_state_dir"] == str(save_dir / DATALOADER_STATE_SUBDIR) |
| 1993 | + mock_load_persistent.assert_not_called() |
| 1994 | + |
| 1995 | + @patch("megatron.bridge.training.checkpointing._load_non_persistent_base_checkpoint") |
| 1996 | + @patch("megatron.bridge.training.checkpointing._resolve_checkpoint_iteration", return_value=(50, False)) |
| 1997 | + def test_newer_global_non_persistent_checkpoint_under_load_remains_available( |
| 1998 | + self, |
| 1999 | + _mock_resolve, |
| 2000 | + mock_load_non_persistent, |
| 2001 | + tmp_path, |
| 2002 | + base_config, |
| 2003 | + mock_pg_collection, |
| 2004 | + ): |
| 2005 | + """A distinct empty save root does not hide a newer recovery point under load.""" |
| 2006 | + load_dir = tmp_path / "input" |
| 2007 | + save_dir = tmp_path / "output" |
| 2008 | + load_non_persistent_dir = load_dir / "non_persistent" |
| 2009 | + save_non_persistent_dir = save_dir / "non_persistent" |
| 2010 | + load_non_persistent_dir.mkdir(parents=True) |
| 2011 | + save_non_persistent_dir.mkdir(parents=True) |
| 2012 | + torch.save( |
| 2013 | + TrainState(step=200).state_dict(), |
| 2014 | + get_checkpoint_train_state_filename(str(load_non_persistent_dir), prefix="latest"), |
| 2015 | + ) |
| 2016 | + torch.save( |
| 2017 | + TrainState(step=100).state_dict(), |
| 2018 | + get_checkpoint_train_state_filename(str(save_non_persistent_dir), prefix="latest"), |
| 2019 | + ) |
| 2020 | + |
| 2021 | + base_config.save = str(save_dir) |
| 2022 | + base_config.non_persistent_ckpt_type = "global" |
| 2023 | + base_config.non_persistent_global_ckpt_dir = None |
| 2024 | + expected = ( |
| 2025 | + {"model": "newer"}, |
| 2026 | + str(load_non_persistent_dir / "iter_0000200"), |
| 2027 | + False, |
| 2028 | + CheckpointType.GLOBAL, |
| 2029 | + ) |
| 2030 | + mock_load_non_persistent.return_value = expected |
| 2031 | + |
| 2032 | + checkpointing_context = {} |
| 2033 | + result = _load_base_checkpoint( |
| 2034 | + str(load_dir), |
| 2035 | + base_config, |
| 2036 | + checkpointing_context=checkpointing_context, |
| 2037 | + pg_collection=mock_pg_collection, |
| 2038 | + ) |
| 2039 | + |
| 2040 | + assert result == expected |
| 2041 | + assert mock_load_non_persistent.call_args.args[0] == str(load_non_persistent_dir) |
| 2042 | + assert mock_load_non_persistent.call_args.args[4] == 200 |
| 2043 | + assert checkpointing_context["dataloader_state_dir"] == str(load_dir / DATALOADER_STATE_SUBDIR) |
| 2044 | + |
1934 | 2045 | @patch("megatron.bridge.training.checkpointing._get_non_persistent_iteration") |
1935 | 2046 | @patch("megatron.bridge.training.checkpointing.file_exists") |
1936 | 2047 | def test_load_base_checkpoint_no_checkpoint( |
|
0 commit comments