Skip to content

Commit fd0df72

Browse files
Merge pull request #4340 from AI-Hypercomputer:jackyf/cleanup-scan-layers-mismatch
PiperOrigin-RevId: 941921993
2 parents fcb7ebe + f5f3af7 commit fd0df72

6 files changed

Lines changed: 317 additions & 471 deletions

File tree

src/maxtext/checkpoint_conversion/inspect_checkpoint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def print_structure(data_dict, output_file=""):
7979
"""Utility to format and print sorted keys and shapes from a flattened dictionary."""
8080
if output_file:
8181
# Save command
82-
save_lines = [f"# {" ".join(sys.orig_argv)}", ""]
82+
save_lines = [f"# {' '.join(sys.orig_argv)}", ""]
8383

8484
for key in sorted(data_dict.keys(), key=natural_sort_key):
8585
line = f"key: {key} | {data_dict[key]}"

src/maxtext/common/checkpointing.py

Lines changed: 68 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from typing import Any, Optional
2020

2121
from absl import flags
22-
import contextlib
2322
import datetime
2423
from etils import epath
2524
from flax import nnx
@@ -661,14 +660,12 @@ def _restore_grain_iterator(
661660
if isinstance(data_iterator, RemoteIteratorWrapper):
662661
grain_restore_args = GrainCheckpointRestore(item=data_iterator)
663662
restored_state = checkpoint_manager.restore(step, args=Composite(items=checkpoint_args, iter=grain_restore_args))
664-
_assert_no_shaped_dtype_struct(restored_state)
665663
return (restored_state, None)
666664

667665
# ElasticIterator: one shared `process_0.json` regardless of shard count.
668666
if not isinstance(data_iterator, list) and isinstance(data_iterator.local_iterator, ElasticIterator):
669667
grain_restore_args = GrainCheckpointRestore(item=data_iterator.local_iterator)
670668
restored_state = checkpoint_manager.restore(step, args=Composite(items=checkpoint_args, iter=grain_restore_args))
671-
_assert_no_shaped_dtype_struct(restored_state)
672669
return (restored_state, None)
673670

674671
directory = checkpoint_manager.directory / str(step) / "iter"
@@ -717,67 +714,9 @@ def _restore_grain_iterator(
717714

718715
# Call restore once with the composed arguments
719716
restored_state = checkpoint_manager.restore(step, args=Composite(items=checkpoint_args, iter=grain_restore_args))
720-
_assert_no_shaped_dtype_struct(restored_state)
721717
return (restored_state, None)
722718

723719

724-
def is_structural_or_shape_mismatch(e: Exception) -> bool:
725-
"""Helper to check if an exception is likely a PyTree structure or shape mismatch."""
726-
if not isinstance(e, (ValueError, TypeError)):
727-
return False
728-
msg = str(e).lower()
729-
mismatch_keywords = [
730-
"mismatch",
731-
"structure",
732-
"shape",
733-
"tree",
734-
"leaf",
735-
"leaves",
736-
"paths matched",
737-
"shapedtypestruct",
738-
"invalid type",
739-
]
740-
return any(kw in msg for kw in mismatch_keywords)
741-
742-
743-
def _assert_no_shaped_dtype_struct(pytree):
744-
"""Asserts that there are no jax.ShapeDtypeStruct leaves in the restored pytree."""
745-
if isinstance(pytree, jax.ShapeDtypeStruct):
746-
raise ValueError(
747-
"Some parameters in the restored state remained as ShapeDtypeStruct"
748-
f" (indicating structure mismatch): {pytree}."
749-
)
750-
751-
if hasattr(pytree, "keys") and hasattr(pytree, "__getitem__"):
752-
for k in pytree.keys():
753-
_assert_no_shaped_dtype_struct(pytree[k])
754-
elif isinstance(pytree, (list, tuple)):
755-
for v in pytree:
756-
_assert_no_shaped_dtype_struct(v)
757-
else:
758-
leaves = jax.tree_util.tree_leaves(pytree)
759-
if len(leaves) == 1 and leaves[0] is pytree:
760-
return
761-
for leaf in leaves:
762-
_assert_no_shaped_dtype_struct(leaf)
763-
764-
765-
@contextlib.contextmanager
766-
def handle_checkpoint_mismatch(context_name: str, path: str):
767-
"""Context manager to intercept PyTree/shape mismatches and raise descriptive errors."""
768-
try:
769-
yield
770-
except Exception as e:
771-
if is_structural_or_shape_mismatch(e):
772-
raise ValueError(
773-
f"Failed to {context_name} from {path}. This is often caused by a"
774-
" mismatch in the 'scan_layers' configuration (stacked vs unstacked)"
775-
" between your current execution command and the saved checkpoint."
776-
f" Original error: {e}"
777-
) from e
778-
raise
779-
780-
781720
def load_state_if_possible(
782721
checkpoint_manager: CheckpointManager | None,
783722
data_iterator: MultiHostDataLoadIterator | list[MultiHostDataLoadIterator] | None,
@@ -860,30 +799,26 @@ def map_to_pspec(data):
860799
(EmergencyCheckpointManager, EmergencyReplicatorCheckpointManager),
861800
):
862801
checkpoint_path = str(checkpoint_manager.directory / str(step) / "items")
863-
with handle_checkpoint_mismatch("restore NNX checkpoint", checkpoint_path):
864-
restored_nnx = _load_linen_checkpoint_into_nnx(
865-
checkpoint_path,
866-
abstract_unboxed_pre_state,
867-
checkpoint_storage_concurrent_gb,
868-
use_ocdbt,
869-
use_zarr3,
870-
)
871-
_assert_no_shaped_dtype_struct(restored_nnx)
802+
restored_nnx = _load_linen_checkpoint_into_nnx(
803+
checkpoint_path,
804+
abstract_unboxed_pre_state,
805+
checkpoint_storage_concurrent_gb,
806+
use_ocdbt,
807+
use_zarr3,
808+
)
872809
return ({"items": restored_nnx}, None)
873810

874811
if isinstance(abstract_unboxed_pre_state, nnx.State) and isinstance(
875812
checkpoint_manager,
876813
(EmergencyCheckpointManager, EmergencyReplicatorCheckpointManager),
877814
):
878815
checkpoint_path = str(checkpoint_manager.directory / str(step))
879-
with handle_checkpoint_mismatch("restore emergency NNX checkpoint", checkpoint_path):
880-
restored = _restore_emergency_linen_checkpoint_into_nnx(
881-
checkpoint_manager,
882-
step,
883-
abstract_unboxed_pre_state,
884-
map_to_pspec,
885-
)
886-
_assert_no_shaped_dtype_struct(restored)
816+
restored = _restore_emergency_linen_checkpoint_into_nnx(
817+
checkpoint_manager,
818+
step,
819+
abstract_unboxed_pre_state,
820+
map_to_pspec,
821+
)
887822
return (
888823
restored,
889824
None,
@@ -902,49 +837,46 @@ def map_to_pspec(data):
902837
)
903838

904839
checkpoint_path = str(checkpoint_manager.directory / str(step))
905-
with handle_checkpoint_mismatch("restore checkpoint", checkpoint_path):
906-
match (checkpoint_manager, dataset_type, data_iterator):
907-
# Case 1: Matches if 'checkpoint_manager' is an instance of either EmergencyCheckpointManager
908-
# or EmergencyReplicatorCheckpointManager. The '_' indicates that 'dataset_type' and
909-
# 'data_iterator' can be any value and aren't used in this pattern.
910-
case (checkpoint_manager, _, _) if isinstance(
911-
checkpoint_manager,
912-
(
913-
EmergencyCheckpointManager,
914-
EmergencyReplicatorCheckpointManager,
915-
),
916-
):
917-
restored = checkpoint_manager.restore(step, args=Composite(state=checkpoint_args)).state
918-
_assert_no_shaped_dtype_struct(restored)
919-
return (
920-
restored,
921-
None,
922-
)
923-
# Case 2: Matches if dataset type is "grain" and the data iterator is not a
924-
# PlaceHolderDataIterator and a specific checkpoint file exists for the iterator
925-
case (
840+
match (checkpoint_manager, dataset_type, data_iterator):
841+
# Case 1: Matches if 'checkpoint_manager' is an instance of either EmergencyCheckpointManager
842+
# or EmergencyReplicatorCheckpointManager. The '_' indicates that 'dataset_type' and
843+
# 'data_iterator' can be any value and aren't used in this pattern.
844+
case (checkpoint_manager, _, _) if isinstance(
845+
checkpoint_manager,
846+
(
847+
EmergencyCheckpointManager,
848+
EmergencyReplicatorCheckpointManager,
849+
),
850+
):
851+
restored = checkpoint_manager.restore(step, args=Composite(state=checkpoint_args)).state
852+
return (
853+
restored,
854+
None,
855+
)
856+
# Case 2: Matches if dataset type is "grain" and the data iterator is not a
857+
# PlaceHolderDataIterator and a specific checkpoint file exists for the iterator
858+
case (
859+
checkpoint_manager,
860+
dataset_type,
861+
data_iterator,
862+
) if (
863+
dataset_type == "grain"
864+
and data_iterator
865+
and not isinstance(data_iterator, PlaceHolderDataIterator)
866+
and (checkpoint_manager.directory / str(step) / "iter").exists()
867+
):
868+
return _restore_grain_iterator(
926869
checkpoint_manager,
927-
dataset_type,
870+
step,
928871
data_iterator,
929-
) if (
930-
dataset_type == "grain"
931-
and data_iterator
932-
and not isinstance(data_iterator, PlaceHolderDataIterator)
933-
and (checkpoint_manager.directory / str(step) / "iter").exists()
934-
):
935-
return _restore_grain_iterator(
936-
checkpoint_manager,
937-
step,
938-
data_iterator,
939-
checkpoint_args,
940-
expansion_factor_real_data,
941-
)
942-
# Case 3: Default/Fallback case.
943-
# This case acts as a wildcard ('_') and matches if none of the preceding cases were met.
944-
case _:
945-
restored = checkpoint_manager.restore(step, args=Composite(items=checkpoint_args))
946-
_assert_no_shaped_dtype_struct(restored)
947-
return (restored, None)
872+
checkpoint_args,
873+
expansion_factor_real_data,
874+
)
875+
# Case 3: Default/Fallback case.
876+
# This case acts as a wildcard ('_') and matches if none of the preceding cases were met.
877+
case _:
878+
restored = checkpoint_manager.restore(step, args=Composite(items=checkpoint_args))
879+
return (restored, None)
948880

949881
if source_checkpoint_layout == "safetensors_dynamic":
950882
path = load_parameters_from_path or load_full_state_from_path
@@ -957,30 +889,26 @@ def map_to_pspec(data):
957889
else:
958890
params = abstract_unboxed_pre_state.params
959891

960-
with handle_checkpoint_mismatch("load parameters", load_parameters_from_path):
961-
restored_params = load_params_from_path(
962-
load_parameters_from_path,
963-
params,
964-
checkpoint_storage_concurrent_gb,
965-
use_ocdbt=use_ocdbt,
966-
use_zarr3=use_zarr3,
967-
)
968-
_assert_no_shaped_dtype_struct(restored_params)
892+
restored_params = load_params_from_path(
893+
load_parameters_from_path,
894+
params,
895+
checkpoint_storage_concurrent_gb,
896+
use_ocdbt=use_ocdbt,
897+
use_zarr3=use_zarr3,
898+
)
969899
return None, restored_params
970900
elif load_full_state_from_path != "":
971901
max_logging.log(f"Loading full state from path: {load_full_state_from_path}")
972-
with handle_checkpoint_mismatch("load full state", load_full_state_from_path):
973-
restored_state = _load_full_state_from_path(
974-
path=load_full_state_from_path,
975-
abstract_unboxed_pre_state=abstract_unboxed_pre_state,
976-
enable_orbax_v1=enable_orbax_v1,
977-
checkpoint_conversion_fn=checkpoint_conversion_fn,
978-
source_checkpoint_layout=source_checkpoint_layout,
979-
checkpoint_storage_concurrent_gb=checkpoint_storage_concurrent_gb,
980-
use_ocdbt=use_ocdbt,
981-
use_zarr3=use_zarr3,
982-
)
983-
_assert_no_shaped_dtype_struct(restored_state)
902+
restored_state = _load_full_state_from_path(
903+
path=load_full_state_from_path,
904+
abstract_unboxed_pre_state=abstract_unboxed_pre_state,
905+
enable_orbax_v1=enable_orbax_v1,
906+
checkpoint_conversion_fn=checkpoint_conversion_fn,
907+
source_checkpoint_layout=source_checkpoint_layout,
908+
checkpoint_storage_concurrent_gb=checkpoint_storage_concurrent_gb,
909+
use_ocdbt=use_ocdbt,
910+
use_zarr3=use_zarr3,
911+
)
984912
return {"items": restored_state}, None
985913
else:
986914
max_logging.log("No existing checkpoints found, not restoring checkpoint.")

0 commit comments

Comments
 (0)