Skip to content

perf(training): cut data-loader stalls and skip unused tactile decode - #15

Merged
Vertax42 merged 7 commits into
mainfrom
optimize-training-duration
Aug 26, 2026
Merged

Vertax42 merged 7 commits into
mainfrom
optimize-training-duration

Conversation

@Hubo1231

@Hubo1231 Hubo1231 commented Aug 26, 2026 •

Copy link
Copy Markdown
Collaborator

Improves training data-loading throughput and removes periodic pipeline stalls.

Changes

  • Skip decoding tactile video streams that are discarded by the configured repack transforms.
  • Deliver batches as workers finish with in_order=False, avoiding head-of-line blocking.
  • Add an InfiniteSampler to prevent iterator teardown and prefetch warm-up at epoch boundaries.
  • Preserve explicitly supplied samplers, including the PyTorch DDP path.
  • Add configuration switches (DataConfig.tactile, TrainConfig.strict_batch_order), H100 training examples, regression tests, and benchmark documentation.

Results

Controlled 400-step H100 training A/B:

  • Total time: 770.8 s → 715.7 s (1.08x speedup)
  • Data stalls over 0.5 s: 20 → 0
  • Maximum next_batch wait: 7.83 s → 0.43 s

Selective tactile decoding reduces single-sample __getitem__ latency from 262.4 ms to 153.3 ms (1.71x). It also reduced startup-to-first-batch time by 37.3 s, although it did not improve steady-state end-to-end throughput in the tested H100 configuration because decoding was not the remaining bottleneck.

A separate 64,951-step production run confirmed that stalls at worker-rotation and epoch boundaries were eliminated. The remaining long waits occurred after checkpoint saves. The production comparison documented in this PR is cross-task and is therefore not presented as a controlled experiment — only the 400-step A/B above is.

Full write-up: docs/data-pipeline-stalls.md.

Test coverage

Regression tests in src/openpi/training/data_loader_test.py cover:

  • selective tactile-stream decoding
  • validation of repack-required streams
  • decoding everything when no whitelist is set
  • infinite sampler coverage and determinism
  • out-of-order delivery defaults
  • strict ordering opt-in
  • preservation of explicit samplers

Review round

Addressed in bc394fc and eb6d358:

  • SelectiveVideoLeRobotDataset.decode_video_keys now defaults to None ("decode everything") rather than an empty whitelist, so a construction site that forgets to set it degrades to plain LeRobotDataset behaviour instead of silently training on missing images.
  • Raised the declared torch floor to >=2.6, the release that added DataLoader(in_order=...).
  • Fixed a ruff RUF043 failure in the new tests.
  • Dropped docs/data-pipeline-stalls.html, which duplicated the .md in the same directory.
  • Documented strict_batch_order in configs/_examples/_FULL_REFERENCE.yaml.
  • Translated the two new H100 config comments to English, matching the rest of configs/_examples/.

Hubo1231 and others added 6 commits August 26, 2026 13:39
- `SelectiveVideoLeRobotDataset.decode_video_keys` now defaults to `None`
  ("decode everything") instead of an empty whitelist. A construction site
  that forgets to set it degrades to plain `LeRobotDataset` behaviour rather
  than silently decoding nothing and training on missing images. Covered by
  a new test.
- Escape the regex metacharacters in the `pytest.raises(match=...)` pattern
  so `ruff check` passes again (RUF043).
- Drop `docs/data-pipeline-stalls.html`: it duplicates the `.md` in the same
  directory, nothing references it, and two copies of one document only drift.
- Document the new top-level `strict_batch_order` in `_FULL_REFERENCE.yaml`,
  alongside `num_workers`.
- Translate the comments in the two new H100 configs to English, matching
  every other file under `configs/_examples/`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The data loader now passes `in_order=` to `torch.utils.data.DataLoader`, which
landed in torch 2.6. The declared floor of 2.2.1 would resolve to versions that
raise `TypeError: unexpected keyword argument 'in_order'` at construction.

requirements.txt already pins torch==2.7.1, so no lock regeneration is needed;
this only corrects the declared lower bound.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Hubo1231
Hubo1231 requested a review from Vertax42 August 26, 2026 07:44
@Vertax42 Vertax42 changed the title Optimize training duration perf(training): cut data-loader stalls and skip unused tactile decode Aug 26, 2026
…llings

The `tactile` switch matches by substring, which is correct and stays
correct — but the comment, the doc table and the test fixture all spelled
the streams `_tactile_{0,1}`, which reads as the naming rather than as one
of two.

lerobot-xense suffixed the tactile cameras by USB enumeration order until
`1146d034` and by the jaw the pad sits on (serial parity) after it, and a
recorded stream is named after its lerobot camera key. So both spellings
are on disk, and `TACTILE_KEY_MARKER` catching either is load-bearing
rather than incidental.

Says so where it matters, and parametrises the decode-key tests over both
key sets instead of only the legacy one, so a future exact-match
"cleanup" fails a test rather than silently decoding four streams nobody
reads.

No behaviour change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Vertax42

Copy link
Copy Markdown
Collaborator

Pushed one commit onto this branch (b1f90d7) — docs/tests only, no behaviour change. Flagging it since it is your PR.

Context: #16 renames the tactile camera keys to follow lerobot-xense 1146d034, where the suffix became the jaw the pad sits on (serial parity) instead of USB enumeration order. This PR needs no functional change for that — TACTILE_KEY_MARKER = "tactile" matches by substring, so the new keys are caught exactly as the old ones were, and the two branches touch disjoint files.

What was misleading was that the comment, the doc table and the _XENSE_VIDEO_KEYS fixture all spelled the streams _tactile_{0,1}, which reads as the naming rather than as one of two. Both spellings are on disk — datasets recorded before that commit have one, later ones the other — so the substring match is load-bearing, not incidental. The commit says that where it matters and parametrises the decode-key tests over both key sets, so a future exact-match "cleanup" fails a test instead of silently skipping four streams nobody reads.

pytest src/openpi/training/ → 71 passed, ruff check clean.

One scheduling note, unrelated to the content: main has strict: true + dismiss_stale_reviews: true, so whichever of #15 / #16 merges second needs Update branch → CI re-run → re-approval. Approving after the update rather than before saves a round trip.

@Vertax42
Vertax42 merged commit ec72f34 into main Aug 26, 2026
1 check passed
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