fix(trainer): avoid KeyError when a checkpoint is saved at an unvalidated step - #3455
Conversation
…ated step When save_checkpoint_interval is not a multiple of validate_interval, a checkpoint can be saved at a step that was never validated. The best-ckpt comparison then indexes val_acc/val_loss_step_or_epoch[ckpt_name], raising KeyError right after the checkpoint was already written and aborting the run. Guard both the DeepSpeed and the torch.save checkpoint paths with .get() so an unvalidated checkpoint is skipped for the "best" bookkeeping (and logged) instead of crashing; fall back to 0.0 when recording saved_ckpts. Co-Authored-By: Claude <noreply@anthropic.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
LauraGPT
left a comment
There was a problem hiding this comment.
The KeyError is avoided, but this fallback makes an unvalidated checkpoint participate in best-model ranking with a fabricated score of 0.0. That can delete a real validated checkpoint.
I reproduced this on commit f3c5bd73e63073063e4ca2ccf8665b4be22da32e with loss-based ranking and keep_nbest_models=1:
- save validated
model.pt.ep1.1with loss1.0; - save
model.pt.ep1.2at a step that has no validation metric; - the new checkpoint is inserted into
saved_ckptswith0.0; - the pruning code removes
model.pt.ep1.1, leaving only the unvalidated checkpoint.
Please keep checkpoints without the configured validation metric out of saved_ckpts (or retain them through a separate, explicitly non-ranked policy) instead of assigning a synthetic score. Please also add focused regression coverage for both loss and acc ranking, including the DeepSpeed and non-DeepSpeed save paths, so an unvalidated checkpoint cannot evict a validated best checkpoint.
…nking Address review feedback on PR modelscope#3455. A checkpoint saved at a step that was never validated (save_checkpoint_interval not a multiple of validate_interval) used to be inserted into `saved_ckpts` with a fabricated score of 0.0. Under loss-based ranking that synthetic "perfect" loss could evict a real validated best checkpoint via keep_nbest_models pruning. Now such checkpoints are kept on disk but excluded from `saved_ckpts` entirely, so they never compete in best-model ranking or pruning, and `best_step_or_epoch` only ever references validated checkpoints. Adds regression coverage for both loss and acc ranking on the DeepSpeed and torch.save paths, asserting an unvalidated checkpoint cannot evict a validated best checkpoint.
…cc case The fake DeepSpeed engine now writes a placeholder file per tag (mirroring DeepSpeed's per-tag checkpoint dirs), so keep_nbest_models pruning's smart_remove() is observable. This closes a gap where the [DeepSpeed, acc] combination passed on the buggy code: under acc ranking the fabricated 0.0 is the minimum, so pruning deletes the unvalidated checkpoint itself rather than the validated best, and without an on-disk artifact that deletion was invisible. With the fix, all 8 cases pass; on the previous code all 4 unvalidated-step cases now fail (loss: fabricated 0.0 evicts the validated best; acc: the unvalidated checkpoint file is pruned).
…eed Trainer
`funasr-train` (funasr/train_utils/trainer.py) shares the identical
checkpoint-ranking code as trainer_ds.py and had the same bug: direct
indexing of `val_{acc,loss}_step_or_epoch[ckpt_name]` raised KeyError when
a checkpoint was saved at a step that was never validated, and the
keep_nbest_models bookkeeping inserted a fabricated score for such
checkpoints.
Apply the same fix: checkpoints saved at an unvalidated step are kept on
disk but excluded from saved_ckpts (no synthetic score), best_step_or_epoch
only ever references validated checkpoints, and the metric dicts are read
via .get().
Tests now parametrize over all three checkpointing paths (trainer_ds
torch.save, trainer_ds DeepSpeed, and trainer torch.save) x loss/acc.
On upstream main all 6 unvalidated-step cases fail with
`KeyError: 'model.pt.ep1.2'`; with the fix all 12 cases pass.
|
@LauraGPT thanks for the review — both points are addressed. 1. Unvalidated checkpoints no longer enter ranking. I removed the Your repro is now the exact regression test: with 2. Regression coverage added in
While covering the non-DeepSpeed Honesty of the tests: on upstream |
LauraGPT
left a comment
There was a problem hiding this comment.
Re-reviewed the updated head 99af35d. The requested ranking issue is fixed across all three save paths: checkpoints without the configured validation metric remain on disk but no longer enter saved_ckpts, best-model selection, or keep_nbest_models pruning.\n\nVerification on the exact head:\n- New focused matrix: 12 passed (loss/acc x Trainer, TrainerDS torch.save, TrainerDS DeepSpeed fake).\n- The same test file against the pre-fix f3c5bd7 produced 6 failures and 6 control passes, confirming the regression coverage is meaningful.\n- Broader collectable suite: 432 passed, 1 skipped, 1 unrelated environment failure in test_auto_model because this host lacks modelscope/rapidfuzz and other optional runtime dependencies.\n- compileall passed for both trainer modules; git diff --check passed.\n\nThanks for covering the non-DeepSpeed path and strengthening the DeepSpeed+acc assertion.
Bug
When
save_checkpoint_intervalis not a multiple ofvalidate_interval, a checkpoint can be saved at a step that was never validated. The best-ckpt comparison then indexesval_acc_step_or_epoch[ckpt_name], raisingKeyErrorright after the checkpoint was written and aborting the whole run.Reproduce
save_checkpoint_interval=5000,validate_interval=2000→ crash at step 5000:KeyError: 'model.pt.ep0.5000'.Fix
Guard both the DeepSpeed and the
torch.savecheckpoint paths with.get(). An unvalidated checkpoint is skipped for the "best" bookkeeping (and logged) instead of crashing;saved_ckptsfalls back to0.0.Verified
Two-stage training run (TTS 6.3k → real 517, 50 epochs) completed without the crash across ~50 checkpoint saves.