| 125 | |
| 126 | |
| 127 | def check_state_structure( |
| 128 | ckpt_structure: list[tuple[str, Any]], |
| 129 | target_structure: list[tuple[str, Any]], |
| 130 | *, |
| 131 | validation: CheckpointValidationType = CheckpointValidationType.EXACT, |
| 132 | ): |
| 133 | # Maybe filter structure before comparison. |
| 134 | def filter_for_validation(structure): |
| 135 | filtered_structure = [] |
| 136 | for key, value in structure: |
| 137 | if validation in [ |
| 138 | CheckpointValidationType.EXACT_UP_TO_DTYPE, |
| 139 | CheckpointValidationType.CONTAINS_STATE_UP_TO_DTYPE, |
| 140 | ] and isinstance(value, dict): |
| 141 | # Drop dtype if it's in the value. |
| 142 | value = {k: v for k, v in value.items() if k != "dtype"} |
| 143 | filtered_structure.append((key, value)) |
| 144 | return filtered_structure |
| 145 | |
| 146 | filtered_ckpt_structure = sorted( |
| 147 | [f"{key}={value}" for key, value in filter_for_validation(ckpt_structure)] |
| 148 | ) |
| 149 | filtered_target_structure = sorted( |
| 150 | [f"{key}={value}" for key, value in filter_for_validation(target_structure)] |
| 151 | ) |
| 152 | |
| 153 | msg = "" |
| 154 | if validation in [CheckpointValidationType.EXACT, CheckpointValidationType.EXACT_UP_TO_DTYPE]: |
| 155 | is_compatible = filtered_ckpt_structure == filtered_target_structure |
| 156 | elif validation in [ |
| 157 | CheckpointValidationType.CONTAINS_STATE, |
| 158 | CheckpointValidationType.CONTAINS_STATE_UP_TO_DTYPE, |
| 159 | ]: |
| 160 | # Allow checkpoint to contain additional information. |
| 161 | is_compatible = set(filtered_ckpt_structure) >= set(filtered_target_structure) |
| 162 | if not is_compatible: |
| 163 | msg = ( |
| 164 | "Missing:\n" |
| 165 | + "\n".join(sorted(set(filtered_target_structure) - set(filtered_ckpt_structure))) |
| 166 | + "\n" |
| 167 | ) |
| 168 | else: |
| 169 | raise ValueError(f"Unknown validation type: {validation}") |
| 170 | if not is_compatible: |
| 171 | msg += "Diff:\n" + "\n".join( |
| 172 | difflib.ndiff(sorted(filtered_ckpt_structure), sorted(filtered_target_structure)) |
| 173 | ) |
| 174 | raise ValueError( |
| 175 | f"Unable to restore checkpoint ({validation}). A mismatch between the saved " |
| 176 | "checkpoint tree dtypes or shapes and the current one has been detected:\n" |
| 177 | f"{msg}" |
| 178 | ) |
| 179 | |
| 180 | |
| 181 | def _upload_dir(src_dir_handle: tempfile.TemporaryDirectory, *, dst_dir: str): |