Conversation
Third stage of the RNG refactoring plan (dev/checkpoint_plan.md):
policies can now be pickled safely and a run can be suspended and
resumed bit-exactly.
- CheckpointMixin (physbo/search/_checkpoint.py), inherited by all six
policies via discrete.Policy and range.Policy:
- __getstate__/__setstate__ exclude the MPI communicator (mpi4py
comms other than the predefined ones are not picklable) so a policy
can be embedded directly in a host application's own checkpoint,
e.g. ODAT-SE's per-rank state dict.
- set_comm(comm) re-attaches a communicator after unpickling, with
size/rank validation against the stored state.
- save_checkpoint/load_checkpoint: a single-file checkpoint
consolidated on rank 0 (collective operations; atomic write via
os.replace). Rank-local state (candidate partition and RNG) is
gathered per rank; the shared model state is stored once. The file
records format version, PHYSBO version, policy class, and mpisize,
all validated on load.
- RNG state: the Generator mode stores the policy-owned generators;
the legacy mode captures and restores the global numpy.random state
per rank (documented side effect).
- save()/load() docstrings now point to the checkpoint API for exact
resumption; they remain the portable, results-only persistence.
Verification: resumed runs equal uninterrupted runs bit-exactly in
both RNG modes, serial and MPI (np=2, np=4), including multi-probe
search; policies created with a Dup()ed communicator pickle and
checkpoint correctly; wrong mpisize/format/class are rejected on load.
No numerical change to existing behavior (fixed-seed references are
bit-identical to the previous commit). 272 tests pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a "Checkpoint and restart" page (en/ja) covering: - the difference between save()/load() (portable results) and save_checkpoint()/load_checkpoint() (bit-exact resumption), - the legacy vs Generator RNG modes and their interaction with checkpointing, - usage under MPI (collective operations, same mpisize required, BLM recommended for TS), - the embedding pattern for host applications (pickling the policy into the host's own checkpoint and re-attaching the communicator with set_comm()). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR makes the search policies safely picklable and adds a checkpoint
API so that an interrupted search can be resumed bit-exactly: the
continued run selects exactly the same candidates as if it had never
stopped.
Built on top of #NN (RNG refactoring); please merge that first — this
branch is based on it.
The primary motivation is applications that embed PHYSBO as a library
(e.g. ODAT-SE): they already have their own checkpoint cycle but had to
approximate PHYSBO's state via
save()/load(), giving up bit-wisereproducibility because the policy could not be pickled (the MPI
communicator blocked it) and internal state (RNG, pending predictor
updates, candidate partition) was not captured.
What's added
All functionality lives in a new
CheckpointMixin(
physbo/search/_checkpoint.py), inherited by all six policies viadiscrete.Policyandrange.Policy.Safe pickling (the embedding use case)
__getstate__/__setstate__exclude the MPI communicator(mpi4py communicators other than predefined ones are not picklable),
so a policy can be embedded directly in a host application's own
checkpoint dict:
set_comm(comm)re-attaches a communicator after unpickling, andvalidates that its size and rank match the stored state.
In the Generator RNG mode (
rng=argument from #NN) the RNG state ispart of the policy, so a plain pickle captures everything needed for
exact resumption. Hosts using the legacy mode keep saving
numpy.random.get_state()themselves, as ODAT-SE already does.Single-file checkpoint API (standalone use)
policy.save_checkpoint(filename)— collective under MPI: rank-localstate (each rank's remaining candidates and RNG state) is gathered and
rank 0 writes one file atomically (temp file +
os.replace);the shared model state (predictor/training/history, identical across
ranks) is stored once, not per rank.
Policy.load_checkpoint(filename, comm=None)— collective: rank 0reads and broadcasts; each rank takes back its local state and the
communicator is re-attached.
policy class, and mpisize. On load: wrong format/class/mpisize raise
a
RuntimeErrorwith a clear message; a PHYSBO version mismatchemits a
RuntimeWarning(bit-exact resumption is guaranteed onlywithin the same version).
numpy.randomstateof each rank is captured in the checkpoint and restored on load
(documented as a deliberate side effect — the stream lives there).
Relation to
save()/load()The existing
save()/load()are unchanged and keep their role:portable, results-only persistence (loadable with a different number of
MPI processes, robust across versions). Docstrings of both APIs now
cross-reference each other, and a new manual page (en/ja,
checkpoint.rst) explains the distinction, MPI usage, and theembedding pattern.
Tests
np=2 and np=4).
legacy and Generator modes, including multi-probe search.
Dup()ed communicator pickles and checkpoints correctly.version-mismatch warning verified.
outputs (10 scenarios, serial and np=2) are bit-identical to the
base branch.
Limitations / future work
With the single-sequence RNG design from #NN this is no longer
blocked by RNG state in principle (for the BLM path), but the
re-partitioning of the candidate set is left for a follow-up; the
format version field is there to allow it.
🤖 Generated with Claude Code