Description
save_checkpoint() in rllm/trainer/verl/utils.py only writes the
latest_checkpointed_iteration.txt tracker file when async_save is False. When
actor.checkpoint.async_save=true is set on the default FSDP strategy, the actor
checkpoint itself is written correctly, but the tracker file is never written. verl's
find_latest_ckpt_path() (the function resume_mode: auto calls to find where to
resume from) has no other way to locate a checkpoint, so it returns None and
training silently starts from scratch, discarding every checkpoint saved so far.
I checked megatron_checkpoint_manager.py in the pinned verl==0.8.0 wheel: it
writes this same tracker file itself once an async Megatron save completes, so
Megatron is self-healing here. fsdp_checkpoint_manager.py has no equivalent, and
rLLM's default strategy is fsdp (rllm/trainer/config/_generated_agent_ppo_trainer.yaml),
so this hits the common path, not an edge case.
Steps to Reproduce
I reproduced this directly against save_checkpoint() (not a full training run), which is
enough to show the tracker file is skipped:
- Call
save_checkpoint(config, global_steps=5, actor_rollout_wg=<a stub whose save_checkpoint() writes files under the given path>, train_dataloader=None)
twice, once with config.actor_rollout_ref.actor.checkpoint.async_save = False
and once with True, both pointed at a fresh trainer.default_local_dir.
- Check for
latest_checkpointed_iteration.txt under default_local_dir after each call.
With async_save=False, the tracker file is written. With async_save=True, it is
not, even though the actor checkpoint files are written in both cases.
Error Output / Traceback
No exception. resume_mode: auto just logs "Training from scratch" every time,
because find_latest_ckpt_path() returns None when the tracker file is missing.
rLLM Version
commit 9beb6e0f676a46d38858991fd79ac5f8e0b16d4c (current main)
Training Backend
verl
Additional Context
Fault: rllm/trainer/verl/utils.py, the if not async_save: gate around the
tracker-file write in save_checkpoint() (roughly lines 245-259), and the
matching read side in load_checkpoint().
This exact unconditional gate also exists in vanilla verl's ray_trainer.py, so it
may be worth fixing upstream in verl too rather than only in rLLM's wrapper, or it
may already be a known verl limitation. Happy to send a PR (write the tracker file
regardless of async_save, matching what the Megatron manager already does) if
that's useful, once there's agreement on whether the fix belongs here or upstream.
Description
save_checkpoint()inrllm/trainer/verl/utils.pyonly writes thelatest_checkpointed_iteration.txttracker file whenasync_saveisFalse. Whenactor.checkpoint.async_save=trueis set on the default FSDP strategy, the actorcheckpoint itself is written correctly, but the tracker file is never written. verl's
find_latest_ckpt_path()(the functionresume_mode: autocalls to find where toresume from) has no other way to locate a checkpoint, so it returns
Noneandtraining silently starts from scratch, discarding every checkpoint saved so far.
I checked
megatron_checkpoint_manager.pyin the pinnedverl==0.8.0wheel: itwrites this same tracker file itself once an async Megatron save completes, so
Megatron is self-healing here.
fsdp_checkpoint_manager.pyhas no equivalent, andrLLM's default strategy is
fsdp(rllm/trainer/config/_generated_agent_ppo_trainer.yaml),so this hits the common path, not an edge case.
Steps to Reproduce
I reproduced this directly against
save_checkpoint()(not a full training run), which isenough to show the tracker file is skipped:
save_checkpoint(config, global_steps=5, actor_rollout_wg=<a stub whose save_checkpoint() writes files under the given path>, train_dataloader=None)twice, once with
config.actor_rollout_ref.actor.checkpoint.async_save = Falseand once with
True, both pointed at a freshtrainer.default_local_dir.latest_checkpointed_iteration.txtunderdefault_local_dirafter each call.With
async_save=False, the tracker file is written. Withasync_save=True, it isnot, even though the actor checkpoint files are written in both cases.
Error Output / Traceback
No exception.
resume_mode: autojust logs "Training from scratch" every time,because
find_latest_ckpt_path()returnsNonewhen the tracker file is missing.rLLM Version
commit
9beb6e0f676a46d38858991fd79ac5f8e0b16d4c(currentmain)Training Backend
verl
Additional Context
Fault:
rllm/trainer/verl/utils.py, theif not async_save:gate around thetracker-file write in
save_checkpoint()(roughly lines 245-259), and thematching read side in
load_checkpoint().This exact unconditional gate also exists in vanilla verl's
ray_trainer.py, so itmay be worth fixing upstream in verl too rather than only in rLLM's wrapper, or it
may already be a known verl limitation. Happy to send a PR (write the tracker file
regardless of
async_save, matching what the Megatron manager already does) ifthat's useful, once there's agreement on whether the fix belongs here or upstream.