Skip to content

fix: make checkpoint resume explicit and stop claiming optimizer state - #17

Merged
Ayyankhan101 merged 1 commit into
masterfrom
fix/checkpoint-resume
Aug 24, 2026
Merged

fix: make checkpoint resume explicit and stop claiming optimizer state#17
Ayyankhan101 merged 1 commit into
masterfrom
fix/checkpoint-resume

Conversation

@Ayyankhan101

Copy link
Copy Markdown
Owner

The last piece of the training path that was written, claimed, and never checked.

Resume was implicit, and could silently do nothing

train() loaded any checkpoint it found with no flag and no way to opt out, restoring the
step counter along with the weights. So re-running glm-train --steps 80 after an 80-step
run restored step = 80, fell straight through the loop, and printed what looked like a
successful run having trained nothing.

Resume is now opt-in via --resume:

$ glm-train --steps 40                     # second time, no --resume
Note: checkpoints exist in "glm_checkpoint" but --resume was not passed;
starting from step 0 and overwriting.
Starting training from step 0

$ glm-train --steps 40 --resume            # already at the limit
Resumed from step 40 (optimizer moments restart cold)
Error: nothing to do: resumed at step 40 but max_steps is 40.
Pass a larger --steps to continue training.        # exit 1

$ glm-train --steps 80 --resume            # continues
Resumed from step 40 (optimizer moments restart cold)
Starting training from step 40
Step 45: loss = 5.1103 (avg = 5.2861), lr = 7.04e-4

save_optimizer_state did not save optimizer state

It wrote {"step": N} — 16 bytes, no AdamW moments — while the README claimed "model +
optimizer state", and load_checkpoint read that file into an empty if let whose body
was a comment admitting nothing happened.

candle keeps first_moment / second_moment in a private VarAdamW with no accessor, so
honouring the claim means writing and maintaining our own optimizer. Not worth it for a CPU
playground with short runs, so the claim goes instead: the config field, the
optimizer_step_*.json file, the empty if let, and the README line are removed. What
resume does restore — weights, step counter, LR schedule position — is now documented,
along with the fact that Adam restarts cold and the loss briefly rises.

Also

save_checkpoint fell back to the literal name "unknown" when the parameter and name
lists disagreed in length. That collides in the safetensors map and silently drops every
parameter after the first. It now errors.

Verification

The check that matters is continuity across a resume. Last loss before: 5.0751 at step
40. First after: 5.1103 at step 45, with the learning rate picking up at the right point
on the cosine schedule. A cold start would have been back near 10.8, so the weights
genuinely restored.

New tests: a checkpoint round trip asserting every parameter matches after save and load,
and a check that the parameter and name lists agree in length and carry no duplicates —
the positional pairing is only safe while both hold.

104 tests pass
cargo clippy --all-targets --all-features -- -D warnings   exit 0
cargo fmt --all -- --check                                  clean

Resume was implicit. train() loaded any checkpoint it found in checkpoint_dir
with no flag and no way to opt out, restoring the step counter along with the
weights — so re-running `glm-train --steps 80` after an 80-step run restored
step = 80, fell straight through the loop, and printed what looked like a
successful run having trained nothing.

Resume is now opt-in via --resume. Without it, an existing checkpoint
directory is left alone and the run starts from step 0, with a note on stdout
so a stale directory is visible rather than surprising. With it and a restored
step already at max_steps, the run fails naming both numbers instead of
exiting quietly.

save_optimizer_state claimed to save optimizer state and wrote {"step": N} —
no AdamW moments. candle keeps first_moment and second_moment in a private
VarAdamW with no accessor, so honouring that claim means writing and
maintaining our own optimizer, which is not worth it for a CPU playground with
short runs. The config field, the optimizer_step_*.json file, the empty if-let
that read it back, and the README claim are gone. What resume does restore —
weights, step counter, LR schedule position — is now documented, along with
the fact that Adam restarts cold and the loss briefly rises.

save_checkpoint also fell back to the literal name "unknown" when the
parameter and name lists disagreed in length. That collides in the safetensors
map and silently drops every parameter after the first; it now errors.

Verified end to end. Last loss before resuming was 5.0751 at step 40; the
first after was 5.1103 at step 45, and the learning rate picked up at the
right point on the cosine schedule. A cold start would have been back near
10.8.

104 tests pass, including a checkpoint round trip that asserts every parameter
matches after a save and load, and a check that the parameter and name lists
agree in length and carry no duplicates.
@git-mind-pr-guardian

Copy link
Copy Markdown

GitMind PR Review

{'pr_url': '#17', 'repo': 'Ayyankhan101/Transformer-In-Rust', 'pr_num': '17', 'title': 'fix: make checkpoint resume explicit and stop claiming optimizer state', 'author': 'Ayyankhan101', 'additions': 206, 'deletions': 87, 'changed_files': 9, 'review': '## Summary\nAutomatic review could not be generated — please review the diff manually.\n\n## Issues\nNo significant issues found.\n\n## Verdict\n💬 NEEDS DISCUSSION\nThe automated review failed; human review required.'}


Auto-generated by GitMind — AI-powered code analysis.

@Ayyankhan101
Ayyankhan101 merged commit 6a62174 into master Aug 24, 2026
10 checks passed
@Ayyankhan101
Ayyankhan101 deleted the fix/checkpoint-resume branch August 24, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant