fix: proper checkpoint restore weights-only vs full training state#240
fix: proper checkpoint restore weights-only vs full training state#240Mani212005 wants to merge 1 commit into
Conversation
6771b0e to
da70355
Compare
|
@observingClouds @joeloskarsson Kindly review this code. If you think something should be implemented differently. Please let me know |
joeloskarsson
left a comment
There was a problem hiding this comment.
Thanks! I think this looks really great. Had a couple small thoughts that I commented on here
joeloskarsson
left a comment
There was a problem hiding this comment.
Sorry for taking so long to look at this again, it drowned below a lot of other things in my inbox :/
Anyway, I think this looks pretty good, just had one documentation suggestion. And unfortunately (since I took so long here) I think the branch needs to be updated with all the recent changes to main, before we can merge. In particular make sure that the changelog entry ends up in the right place with all the additions there.
|
No worries :) |
| # In tests parse_args may be patched with MagicMock. Normalize the flag | ||
| # to avoid truthy MagicMock attributes changing control flow. | ||
| load_training_state = bool(vars(args).get("load_training_state", False)) |
There was a problem hiding this comment.
I don't fully follow this, and this seems quite hard to read now. It would be better to not adapt the code to the testing framework. If testing does not work without this then we need to reconsider the testing approach, not change the actual codebase IMO.
There was a problem hiding this comment.
Will the refactoring in #208 make this easier? It should relieve some need for mocking argparse, and it will be merged before this PR.
|
Sorry for taking such a long time to revert. I’ve been busy. would update the required changes on weekend. |
|
#208 is merged now, which means 1) sadly some conflicts and this needing to be adapted, but also 2) maybe #240 (comment) will be easier to sort out? |
0ef9cf3 to
73333bd
Compare
…llam#240) Re-applies @Mani212005's PR mllam#240 onto current main. The original PR was pre-mllam#208 and pre-mllam#641; this version applies the same Lightning-native pattern to current main with a much smaller surface area because the machinery is already in place via `load_forecaster_module_from_checkpoint` (introduced as part of the mllam#208 refactor). Source change: - Remove the `if not self.restore_opt: ...` fresh-optimizer hack from `ForecasterModule.on_load_checkpoint`. The hack only reset the optimizer state and silently left epoch / scheduler / callbacks restored from the checkpoint, which is not what `--restore_opt=False` is supposed to mean. - In `train_model.py`, branch on `args.restore_opt` for the `--load` path: weights-only goes through `load_forecaster_module_from_checkpoint` + `trainer.fit(model)` (no `ckpt_path`), full-resume keeps `trainer.fit(..., ckpt_path=args.load)`. Skipped the 239-line tests/test_checkpoint_restore.py from the original PR: it targeted the pre-mllam#208 API and would require a full rewrite. The existing `tests/test_training.py` smoke tests pass on the new code path. Verified: 18 training-related tests pass locally (test_training.py, test_cli.py, test_train_model_warnings.py). Co-Authored-By: Mani <Mani212005@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…llam#240) Re-applies @Mani212005's PR mllam#240 onto current main, picking up the naming/rename agreed with @joeloskarsson in the review thread. Source changes: - Rename CLI flag `--restore_opt` -> `--load_training_state` per @joeloskarsson's review comment (the old name was misleading because the flag controls epoch / scheduler / callbacks too, not just the optimizer). The internal `ForecasterModule(restore_opt=...)` keyword stays for now to keep legacy ARModel checkpoints loading via the `args=` shim. - Remove the `if not self.restore_opt: ...` fresh-optimizer hack from `ForecasterModule.on_load_checkpoint`. The hack only reset the optimizer state and silently left epoch / scheduler / callbacks restored from the checkpoint. - In `train_model.py`, branch on `args.load_training_state` for the `--load` path: weights-only goes through `load_forecaster_module_from_checkpoint` + `trainer.fit(model)` with no `ckpt_path`, full-resume keeps `trainer.fit(..., ckpt_path=args.load)`. - Add CLI assertion that `--load_training_state` requires `--load`. Test changes: - Drop the 239-line tests/test_checkpoint_restore.py from the original PR (targeted pre-mllam#208 API; @joeloskarsson also flagged it as adapting code to fit tests rather than testing real behaviour). - Add `test_load_training_state_requires_load` covering the new CLI assertion (parser.error -> SystemExit before any datastore loading). - Update tests/test_train_model_warnings.py mocks to set `load_training_state=False` explicitly (MagicMock returns truthy by default, which would trip the new assertion). Co-Authored-By: Mani <Mani212005@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73333bd to
ccfbbd7
Compare
sadamov
left a comment
There was a problem hiding this comment.
I rebased on main which made this PR much lighter. @Mani212005 and @joeloskarsson please have a look if this is still in line with your original intent.
| - Fix `--load` to truly restore weights only by default: instead of overriding the optimizer state inside `on_load_checkpoint` (which left epoch / scheduler / callbacks inherited from the checkpoint), `train_model.py` now reconstructs the model via `ForecasterModule.load_from_checkpoint` and calls `trainer.fit(model)` with no `ckpt_path`, so all non-weight training state starts fresh. Also rename the CLI flag from `--restore_opt` to `--load_training_state` to reflect that it controls more than just the optimizer (epoch / scheduler / callbacks too), and assert it requires `--load` [\#240](https://github.com/mllam/neural-lam/pull/240) @Mani212005 | ||
|
|
There was a problem hiding this comment.
Please simplify this changelog entry. The point is to get an idea of the change at a glance, not for this to be a full description of the change done (that's what the PR description is for 😄).
joeloskarsson
left a comment
There was a problem hiding this comment.
Great! Yes, I am also happy with this now. Just added a small comment about simplifying the changelog, which can be done before merging this (does not affect code).
Describe your changes
Replaces the fragile
on_load_checkpointoptimizer hack inARModelwith proper PyTorchLightning patterns for checkpoint loading. This separates two distinct behaviours:
--loadwithout--restore_opt): callsModelClass.load_from_checkpoint(path, ...)to instantiate the model, then
trainer.fit(model, ckpt_path=None)— epoch/step/scheduler reset to 0.--load+--restore_opt): uses the normal constructor, thentrainer.fit(model, ckpt_path=path)— restores optimizer, epoch, LR scheduler, and callbacks.ar_model.pyself.restore_opt = args.restore_optattribute.on_load_checkpointblock that manually replaced optimizer/scheduler/epoch state — kept only the key-migration logic for older checkpoints.train_model.py--restore_opthelp text to say "full training state" (not just "optimizer state").--restore_optrequires--load(fails fast with a clear message).test_checkpoint_restore.py(new)test_restore_opt_without_load_raises— assertion fires without--load.test_weights_only_uses_load_from_checkpoint—load_from_checkpointcalled,ckpt_path=Nonein fit.test_restore_opt_passes_ckpt_path— normal constructor used,ckpt_pathpassed to fit.test_eval_always_passes_ckpt_path—ckpt_pathalways passed to test.test_no_load_creates_fresh_model— no--load, normal constructor,ckpt_path=None.Other test files
restore_opt = FalsefromModelArgsintest_training.py,test_clamping.py,test_plotting.py, andtest_datasets.py.Behaviour Table
trainer.fitckpt_pathModelClass(args, ...)None--load PATHload_from_checkpoint(PATH, ...)None--load PATH --restore_optModelClass(args, ...)PATH--eval test --load PATHload_from_checkpoint(PATH, ...)trainer.test)Issue Link
Closes #131
Type of change
Checklist before requesting a review
pullwith--rebaseoption if possible).Checklist for reviewers
Each PR comes with its own improvements and flaws. The reviewer should check the following:
Author checklist after completed review
reflecting type of change (add section where missing):
Checklist for assignee