|
43 | 43 | from orbax.checkpoint._src.checkpoint_managers import preservation_policy as preservation_policy_lib |
44 | 44 | from orbax.checkpoint._src.checkpoint_managers import save_decision_policy as save_decision_policy_lib |
45 | 45 |
|
46 | | - |
47 | 46 | CheckpointManagerOptions = ocp.CheckpointManagerOptions |
48 | 47 | Composite = ocp.args.Composite |
49 | 48 | PyTreeCheckpointHandler = ocp.PyTreeCheckpointHandler |
@@ -394,6 +393,21 @@ def print_save_message(step, async_checkpointing): |
394 | 393 | max_logging.log(f"Saved a checkpoint at step {step}.") |
395 | 394 |
|
396 | 395 |
|
| 396 | +def latest_step(checkpoint_manager): |
| 397 | + """Latest saved step or None, across the v0 emergency manager and the v1 Checkpointer.""" |
| 398 | + return checkpoint_manager.latest_step() |
| 399 | + |
| 400 | + |
| 401 | +def wait_until_finished(checkpoint_manager): |
| 402 | + """Blocks until pending saves finish, across the v0 emergency manager and the v1 Checkpointer.""" |
| 403 | + return checkpoint_manager.wait_until_finished() |
| 404 | + |
| 405 | + |
| 406 | +def reached_preemption(checkpoint_manager, step: int) -> bool: |
| 407 | + """Whether a preemption sync point has been reached at `step`, across the v0 emergency manager and the v1 Checkpointer.""" |
| 408 | + return checkpoint_manager.reached_preemption(step) |
| 409 | + |
| 410 | + |
397 | 411 | def load_state_if_possible( |
398 | 412 | checkpoint_manager: CheckpointManager | None, |
399 | 413 | data_iterator: MultiHostDataLoadIterator | list[MultiHostDataLoadIterator] | None, |
@@ -446,7 +460,7 @@ def load_state_if_possible( |
446 | 460 | if checkpoint_manager is not None: |
447 | 461 | max_logging.log("checkpoint manager exists so trying to load this run's existing checkpoint") |
448 | 462 |
|
449 | | - step = checkpoint_manager.latest_step() if step < 0 else step # pyrefly: ignore[bad-assignment] |
| 463 | + step = latest_step(checkpoint_manager) if step < 0 else step # pyrefly: ignore[bad-assignment] |
450 | 464 | if step is not None: |
451 | 465 | max_logging.log(f"restoring from this run's directory step {step}") |
452 | 466 |
|
@@ -690,16 +704,18 @@ def _should_save_checkpoint_at_step(checkpoint_manager, step, config, force): |
690 | 704 | else: |
691 | 705 | base_checkpoint_due = step % config.checkpoint_period == 0 |
692 | 706 | local_checkpoint_due = _uses_local_checkpoint_period(config) and step % config.local_checkpoint_period == 0 |
693 | | - autocheckpoint_due = config.enable_autocheckpoint and checkpoint_manager.reached_preemption(step) |
| 707 | + autocheckpoint_due = config.enable_autocheckpoint and reached_preemption(checkpoint_manager, step) |
694 | 708 | return base_checkpoint_due or local_checkpoint_due or autocheckpoint_due |
695 | 709 |
|
696 | 710 |
|
697 | 711 | def _handle_post_checkpoint_preemption(checkpoint_manager, step, force_ckpt_save): |
698 | 712 | """Waits on final/preemption saves and raises if preempted.""" |
699 | | - reached_preemption = checkpoint_manager.reached_preemption(step) |
700 | | - if force_ckpt_save or reached_preemption: |
701 | | - checkpoint_manager.wait_until_finished() |
702 | | - if reached_preemption: |
| 713 | + # Named is_preempted (not reached_preemption) so it doesn't shadow the module-level |
| 714 | + # reached_preemption dispatcher we call below. |
| 715 | + is_preempted = reached_preemption(checkpoint_manager, step) |
| 716 | + if force_ckpt_save or is_preempted: |
| 717 | + wait_until_finished(checkpoint_manager) |
| 718 | + if is_preempted: |
703 | 719 | raise exceptions.StopTraining("Job is preempted.") |
704 | 720 |
|
705 | 721 |
|
@@ -733,7 +749,7 @@ def maybe_save_checkpoint(checkpoint_manager, state, config, data_iterator, step |
733 | 749 | _handle_post_checkpoint_preemption(checkpoint_manager, actual_step, force_ckpt_save) |
734 | 750 | return |
735 | 751 |
|
736 | | - if checkpoint_manager.latest_step() == actual_step: |
| 752 | + if latest_step(checkpoint_manager) == actual_step: |
737 | 753 | max_logging.log(f"Checkpoint for step {actual_step} already exists, skipping save.") |
738 | 754 | return |
739 | 755 |
|
@@ -782,7 +798,7 @@ def save_checkpoint(checkpoint_manager, step, state, config=None, data_iterator= |
782 | 798 | force |
783 | 799 | or (step % config.checkpoint_period == 0 and not config.enable_continuous_checkpointing) |
784 | 800 | or (_uses_local_checkpoint_period(config) and step % config.local_checkpoint_period == 0) |
785 | | - or (config.enable_autocheckpoint and checkpoint_manager.reached_preemption(step)) |
| 801 | + or (config.enable_autocheckpoint and reached_preemption(checkpoint_manager, step)) |
786 | 802 | ): |
787 | 803 | blocking_until_ready_start = time.time() |
788 | 804 | max_logging.log(f"Waiting for step {step} to finish before checkpoint...") |
|
0 commit comments