Skip to content

[python] Speed up LeRobot video window reads - #9852

Merged
JingsongLi merged 2 commits into
apache:masterfrom
XiaoHongbo-Hope:codex/lerobot-direct-windows
Sep 16, 2026
Merged

JingsongLi merged 2 commits into
apache:masterfrom
XiaoHongbo-Hope:codex/lerobot-direct-windows

Conversation

@XiaoHongbo-Hope

@XiaoHongbo-Hope XiaoHongbo-Hope commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Purpose

Speed up overlapping LeRobot video windows by decoding sorted unique frame requests once per payload, then gathering independent, contiguous outputs. Preserve fallback handling for cross-file windows and decoders without batch support.

Validation

89 tests and Flake8 passed; real-video uint8/float32 pixels and mutation isolation verified. Tests assert one decoder call per payload.

CPU overlap benchmark: 37.5 ms for the original unique-frame/stack path, 154.7 ms for the previous PR head, 23.4 ms after this fix (7-run medians). Random 4-camera throughput decreased from 177.9 to 165.1 samples/s versus the previous PR head (3-run medians, controls run earlier). Kept draft while evaluating this tradeoff.

@XiaoHongbo-Hope XiaoHongbo-Hope changed the title [python] Optimize LeRobot temporal window assembly [python] Speed up LeRobot temporal reads with direct window decoding Sep 15, 2026
@XiaoHongbo-Hope XiaoHongbo-Hope changed the title [python] Speed up LeRobot temporal reads with direct window decoding [python] Speed up LeRobot video window reads Sep 15, 2026
@XiaoHongbo-Hope
XiaoHongbo-Hope force-pushed the codex/lerobot-direct-windows branch from a1bb417 to 37ecc0e Compare September 15, 2026 15:11
@XiaoHongbo-Hope
XiaoHongbo-Hope force-pushed the codex/lerobot-direct-windows branch from 37ecc0e to 56e5716 Compare September 15, 2026 15:13
@XiaoHongbo-Hope
XiaoHongbo-Hope marked this pull request as ready for review September 15, 2026 15:14
Comment on lines +448 to +452
visual_windows = _stack_visual_windows(
plans, converted, [key for key in self._visual_keys
if key not in video_windows]
) if plans[0]["windows"] else {}
visual_windows.update(video_windows)

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.

[P2] Avoid materializing the entire batch of windows before image transforms

When image_transforms returns new storage, such as resizing frames to a smaller resolution, these eager paths allocate every full-resolution window before the first transform runs. visual_windows then keeps all those input tensors alive until get_items() returns, even after the transformed outputs have replaced them in each item. Previously, window assembly and transforms ran one sample at a time.

I reproduced this with 32 samples, two image cameras, 16-frame windows, and a resize transform: the baseline kept at most 2 original window tensors alive simultaneously, while this version kept all 64 alive through the last transform. This significantly increases peak memory in DataLoader workers when preprocessing reduces the frame size.

Could we retain the per-sample path when image_transforms is configured, or assemble windows in bounded groups? This should cover both _decode_video_windows and _stack_visual_windows. Clearing list entries after consumption alone would not eliminate the initial batch-wide allocation peak.

@XiaoHongbo-Hope XiaoHongbo-Hope Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[P2] Avoid materializing the entire batch of windows before image transforms

When image_transforms returns new storage, such as resizing frames to a smaller resolution, these eager paths allocate every full-resolution window before the first transform runs. visual_windows then keeps all those input tensors alive until get_items() returns, even after the transformed outputs have replaced them in each item. Previously, window assembly and transforms ran one sample at a time.

I reproduced this with 32 samples, two image cameras, 16-frame windows, and a resize transform: the baseline kept at most 2 original window tensors alive simultaneously, while this version kept all 64 alive through the last transform. This significantly increases peak memory in DataLoader workers when preprocessing reduces the frame size.

Could we retain the per-sample path when image_transforms is configured, or assemble windows in bounded groups? This should cover both _decode_video_windows and _stack_visual_windows. Clearing list entries after consumption alone would not eliminate the initial batch-wide allocation peak.

Fixed by falling back to per-sample window assembly and transforms when image_transforms is configured, for both image and video windows. I consider we can set up a basic benchmark first. Optimizing the image_transforms path can be handled in a follow-up PR.

@JingsongLi

Copy link
Copy Markdown
Contributor

+1

@JingsongLi
JingsongLi merged commit aafc720 into apache:master Sep 16, 2026
14 checks 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