Skip to content

Release train DataLoader workers before validation#890

Open
yutong-xiang-97 wants to merge 3 commits into
mainfrom
agent/release-train-workers-before-validation
Open

Release train DataLoader workers before validation#890
yutong-xiang-97 wants to merge 3 commits into
mainfrom
agent/release-train-workers-before-validation

Conversation

@yutong-xiang-97

@yutong-xiang-97 yutong-xiang-97 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What has changed and why?

During task training, two DataLoader worker pools could be alive at the same time throughout every validation phase.

InfiniteCycleIterator caches its underlying iterator and keeps it alive across training steps, so the train workers did not shut down before validation. When validation started, iter(val_dataloader) spawned a second pool while the train pool was still held. Because the validation loader uses the same num_workers as training, the number of live worker processes doubled during validation (for example, 2 GPUs x 8 workers = 16 -> 32).

This PR ensures only one task DataLoader worker pool is alive at a time:

  1. Release train workers before validation: when num_workers > 0, infinite_train_dataloader.reset() drops the cached train iterator before validation starts, allowing its workers to shut down before validation workers spawn.
  2. Release validation workers before training resumes: the validation iterator is scoped with try/finally and deleted in the finally, so validation workers are released even if validation exits early or raises.
  3. Disallow persistent task workers: persistent_workers passed through loader_args is now ignored for both task train and validation dataloaders. Persistent workers are owned by the DataLoader and survive iterator shutdown, so allowing this override would defeat the release-before-validation behavior.

How has it been tested?

Ran a 2-GPU / num_workers=4 job under SLURM on a small COCO instance-segmentation subset (ltdetrv2-seg-s, 30 steps, validating at steps 10/20/30 plus the final step). A psutil monitor sampled the number of live DataLoader worker processes, matched by their pt_data_worker process name and isolated to the job by run name, every 0.25 s.

Did you update CHANGELOG.md?

  • Yes
  • Not needed (internal change)

Did you update the documentation?

  • Yes
  • Not needed (internal change without effects for user)

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bad13082d3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lightly_train/_commands/train_task.py
Comment thread src/lightly_train/_commands/train_task.py Outdated
Comment thread src/lightly_train/_commands/train_task.py
@yutong-xiang-97
yutong-xiang-97 force-pushed the agent/release-train-workers-before-validation branch from bad1308 to 58ee117 Compare July 21, 2026 15:24

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58ee11752d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lightly_train/_commands/train_task.py Outdated
Comment thread src/lightly_train/_commands/train_task.py Outdated
@yutong-xiang-97
yutong-xiang-97 force-pushed the agent/release-train-workers-before-validation branch from 373a8a7 to 053c886 Compare July 22, 2026 08:32
Guarantee validation DataLoader worker release via try/finally

Wrap the validation loop in try/finally and release the val DataLoader
iterator (val_dataloader_iter = None) in the finally block, replacing the
bare `del` at the end of the loop.

Functionally equivalent to the previous `del` (both drop the sole reference
so CPython ref-counting runs _MultiProcessingDataLoaderIter._shutdown_workers
immediately), but the release is now structurally guaranteed: it still runs if
the validation loop exits early via an exception or a future break/return, and
it reads symmetrically with the train-side infinite_train_dataloader.reset().

Verified on a 2-GPU / num_workers=8 SLURM run over a small COCO instance-seg
dataset: concurrent DataLoader workers stay at 16 (2 ranks x 8) through every
validation phase and never double to 32 (the pre-fix behavior), matching the
original fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

fix codex reviews

Address review: robust val iterator release and zero-batch guard

- Release the validation iterator with `val_dataloader_iter = None` instead
  of `del` in the finally block: functionally identical, matches the PR
  description, and won't raise NameError if the iter() assignment is ever
  moved inside the try.
- Guard the train_dataloader_position modulo with max(train_num_batches, 1)
  to avoid ZeroDivisionError on a zero-length train dataloader.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Revert val iterator release to del to satisfy mypy

The `val_dataloader_iter = None` variant violates the variable's inferred
iterator type under mypy. Use `del val_dataloader_iter` in the finally block
instead (functionally identical). Keeps the max(train_num_batches, 1)
zero-batch guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Revert val iterator release to del to satisfy mypy

The `val_dataloader_iter = None` variant violates the variable's inferred
iterator type under mypy. Use `del val_dataloader_iter` in the finally block
instead (functionally identical). Keeps the max(train_num_batches, 1)
zero-batch guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yutong-xiang-97
yutong-xiang-97 force-pushed the agent/release-train-workers-before-validation branch from 053c886 to 5dc298a Compare July 22, 2026 09:08
@yutong-xiang-97

Copy link
Copy Markdown
Contributor Author

/review

@yutong-xiang-97
yutong-xiang-97 force-pushed the agent/release-train-workers-before-validation branch from 6332734 to 117a7af Compare July 22, 2026 09:38

@liopeer liopeer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh, I don't think we can merge it like this. I don't have an idea at the moment either on how to handle this, but if I have a calm minute in the next few days I will try to figure something out. The sampler for the train dataloader needs to somehow be resumable.

# the current epoch's remaining batches, but we make no
# per-epoch coverage guarantees anyway. The next next() call
# re-creates the iterator and respawns the workers.
infinite_train_dataloader.reset()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now there is basically no guarantee that if you set steps=len(dataset) // batch_size that every sample gets seen once. I am not sure if this is desirable tbh and would prefer a different solution, since most people would expect that to be the case. Also we still log the "epoch".

@yutong-xiang-97

yutong-xiang-97 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Note: we would go with improving the batch sampler later on and leave this PR as is atm. (Issue backlogged with a plan on Linear)

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.

2 participants