Instruction file imported from juliusaka/bnode-core (
.github/instructions/trainer-restart.instructions.md). Copyright stays with the author.
bnode-core trainer restart states
Apply these instructions when editing trainer restart/resume state logic or its documentation.
State model contract
- Keep exactly two persisted restart-state classes:
TrainAllPhasesStateTrainOnePhaseState
- Current trainer runs use one restart checkpoint bundle and one completion marker:
training_restart_checkpoint.pt— active during training; removed on clean completiontraining_complete.marker— written byclear_restart_artifacts()at the end of successful training; checked attrain_all_phases()startup to guard against spurious Slurm requeues after completion
- Do not re-introduce wrapper-state layers such as
OuterTrainingState,TrainingPhaseState, orLiveTrainingState. - Do not add legacy compatibility readers, old multi-file restart schemas, or obsolete restart filenames unless the user explicitly asks for compatibility.
Ownership boundary
TrainAllPhasesStateowns only the outer resume anchor:job_idxnext_epoch_anchormlflow_run_idstate_version
TrainOnePhaseStateowns only the persisted inner runtime/control state:phase_epochnan_counter— accumulates across restarts; reflects lifetime NaN-loss events for this phase, not just the current execution segmentgrad_norm_last_reduced_counterstable_epochs— accumulates across restarts; reflects lifetime stable-gradient epochs- RNG state
deterministic_mode_active- effective
seq_len_increase_in_batches state_version- attached
EarlyStoppingmodule state when the trainer attaches it beforeload()
- Keep these as explicit locals in
trainer.py, not persisted restart fields:job_list- dataset / dataloader objects
- optimizer / scheduler / scaler runtime objects (restored from
bundle["optimizer"],bundle["scheduler"],bundle["scaler"]respectively) - retry batch-size locals
first_epoch_is_evaluationflag_out_of_seq_len_increaseflag_out_of_warmup— re-derived fromphase_state.phase_epoch * batches_per_epoch >= warmup_batcheson resume; no extra persisted field neededepoch_stop- checkpoint-path locals
_seq_len_now- copied
train_cfgstate
Construction and restore order
train_all_phases()loads the bundle early only to choose the resumed job and epoch anchor.RestartCheckpointStoreowns:- atomic writes for the restart bundle (
training_restart_checkpoint.pt) - restart cleanup (single bundle file) —
clear_restart_artifacts()removes the bundle and writestraining_complete.marker - the completion guard —
is_training_complete()returnsTruewhentraining_complete.markerexists
- atomic writes for the restart bundle (
train_one_phase()must construct:- optimizer
- schedulers
- scaler
- early-stopping before restoring state from the bundle.
- Keep
EarlyStoppingmodule-backed so it can be attached directly toTrainOnePhaseStatebefore save/load instead of being converted into a separate restart dict. - The model state dict and optimizer state dict are stored inside the bundle (
bundle["model"]andbundle["optimizer"]). They are not written as separate files. Load them explicitly intrain_one_phase()from the state dicts passed in viarestart_model_stateandrestart_optimizer_state. - Restore schedulers and scaler from the bundle (passed as
restart_scheduler_statesandrestart_scaler_statedicts totrain_one_phase()). - Keep state-class special serialization explicit via class-level serializer mapping for non-trivial fields and raise clear errors when a declared serializer method is missing.
Documentation contract
- Keep
docs/bnode_core/ode/restart_training.mdaligned with:- the actual single-file bundle resume workflow
- the explicit-local-variable flow in
trainer.py - the current persisted-field lists for
TrainAllPhasesStateandTrainOnePhaseState
- The "Accumulating counters across restarts" section in
restart_training.mdmust document thatnan_counterandstable_epochsaccumulate across restarts (they are lifetime counts for the phase, not per-segment). Keep this section when editing the doc. - When code comments or docstrings explain restart ownership, point readers to
docs/bnode_core/ode/restart_training.md.
Test expectations
tests/ode/test_restart_state.pyshould cover:- roundtrips for
TrainAllPhasesState - roundtrips for
TrainOnePhaseState - syncing effective
seq_len_increase_in_batchesat epoch-end checkpoint save boundary - restoring early-stopping and RNG state from
TrainOnePhaseState training_complete.markerandis_training_complete()behavior inRestartCheckpointStore- early-exit guard in
train_all_phases()whenis_training_complete()is True - explicit serializer-missing failure behavior for declared special fields
- saving/loading model and optimizer state dicts in the bundle
- roundtrips for
tests/ode/test_bnode.pyresume tests should assert the single-file bundle layout explicitly:- interrupted runs leave
training_restart_checkpoint.ptbehind (no separatemodel.ptoroptimizer.pt) - successful completed runs remove the restart checkpoint file and write
training_complete.marker - a second trainer run on the same output directory (simulating Slurm requeue after completion) exits immediately without retraining
- MLflow resume metadata comes from the outer state in the bundle
model_phase_{idx}.pt/optimizer_phase_{idx}.pt(EarlyStopping best) remain as separate files
- interrupted runs leave
- If persisted fields, restore ordering, or restart filenames change, update docs and all relevant restart tests in the same task.