Skip to content

fix: never fast-forward an infinite env's generator on resume - #3253

Draft
parkerpettit wants to merge 1 commit into
mainfrom
fix/infinite-env-resume-replay
Draft

fix: never fast-forward an infinite env's generator on resume#3253
parkerpettit wants to merge 1 commit into
mainfrom
fix/infinite-env-resume-replay

Conversation

@parkerpettit

Copy link
Copy Markdown

Problem

TrainSource.load_state_dict restores an infinite env's data position by calling next() on the generator cursor-many times. That replay is only correct for a pure deterministic generator — an assumption nowhere declared. An infinite taskset backed by live external state (a task server, a curriculum stream) does a real draw on every pull.

Hit on live runs: resuming a run whose infinite env had drawn thousands of episodes made the orchestrator grind at 60% CPU for what projected to hours, leaking hundreds of claimed-but-never-run generation assignments into the external task server, while the trainer sat blocked in the startup weight broadcast until its 3600s timeout killed the job. No log line is emitted during the replay, so the run looks silently wedged (field workaround: --orchestrator.ckpt.skip-progress, which also drops the RNG/cursor state).

Fix

Restore the infinite env's cursor as a counter only — never by consuming the generator. A fresh iterator is not the old one; for stateful streams the position is owned by the stream itself. Finite envs keep the exact epoch-shuffle position replay, which is pure.

Trade-off: a taskset whose generator IS a pure seeded function no longer replays to its old position and will restart its sequence after resume (possible repeats). If that matters, the cleaner contract is an explicit replayability attribute on the taskset — happy to do that instead if preferred.

Tests

tests/unit/orchestrator/test_train_source.py: resume of an infinite env consumes zero generator pulls and continues from the restored counter; finite-env resume still replays the exact epoch-shuffle position. Verified on ar-cluster (2 passed).

🤖 Prepared with Claude Code (draft per Parker)

TrainSource.load_state_dict restored an infinite env's data position by
calling next() on the generator cursor-many times. That is only correct
for a pure deterministic generator. An infinite taskset backed by live
external state (a task server, a curriculum stream) does a real draw on
every pull — with a cursor in the thousands, resume leaks thousands of
claimed-but-never-run assignments and grinds for hours while the trainer
sits in the startup weight broadcast until its timeout kills the job.

Restore the cursor as a counter only. Finite envs keep the exact
epoch-shuffle position replay.
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