Skip to content

[python] Preserve source LeRobot Episode statistics - #11082

Open
XiaoHongbo-Hope wants to merge 3 commits into
apache:masterfrom
XiaoHongbo-Hope:codex/preserve-source-episode-stats
Open

XiaoHongbo-Hope wants to merge 3 commits into
apache:masterfrom
XiaoHongbo-Hope:codex/preserve-source-episode-stats

Conversation

@XiaoHongbo-Hope

@XiaoHongbo-Hope XiaoHongbo-Hope commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Importing multiple LeRobot sources rewrote Episode control statistics and dropped source quantiles even though stored frames kept source-local IDs. This preserves original Episode stats VARIANT and stores derived training-view controls in a marked internal Dataset column.

The training reader computes episode_index statistics in reader-visible coordinates. Existing user text columns named read_control_stats remain readable after append. If a legacy user column has the exact internal column name without its marker, append fails before writing instead of silently publishing incorrect training statistics.

Validation: 392 LeRobot import, reader, writer, and text-field tests passed; 1 skipped. Flake8 on changed Python files and git diff --check passed.

@XiaoHongbo-Hope
XiaoHongbo-Hope force-pushed the codex/preserve-source-episode-stats branch from 5b70d03 to b4618d7 Compare November 10, 2026 22:14
stats = {}
for name in _CONTROLS:
parts = [values[name] for values in plan["control_stats"].values()
if name in values]

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.

Could we make the episode_index entry use the combined reader’s coordinates before storing these statistics? _transform_frames intentionally keeps frame episode_index values source-local, while _SourceLocalReader.read_indices adds each source’s Episode offset. With the existing two-source fixture, the reader returns [0,0,1,1,1,2,2,3,3,3], but meta.stats["episode_index"]["mean"] is 0.6 instead of 1.6 (and its min/max/std are likewise source-local). Computing the Episode statistic column with plan["episode_offset"] while leaving the stored frame column unchanged fixes both local and Ray imports. Could we also update the regression assertion to compare against the reader-visible Episode IDs?

@JingsongLi JingsongLi 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.

Requirement fit: SUPPORTED. Implementation: FINDINGS. Preserving original Episode statistics and quantiles separately from training-view controls has direct data round-trip value.

Reviewed all four files and local/Ray publication, legacy fallback and schema evolution. 384 selected LeRobot import/reader/writer/text-column tests passed, with 2 platform/dependency skips; project flake8 and diff whitespace checks passed. A parent-version writer/current reader probe reproduces the backward-compatibility failure below (unrelated-field control passes). The existing episode-coordinate statistics comment also remains relevant; the underlying local-coordinate calculation predates this diff. Current GitHub metadata reports merge conflicts, so UUID/VARIANT master changes also need reconciliation and revalidation before landing.

for source in sources:
raw = source.get("read_control_stats")
if raw:
decoded_rows.append(json.loads(raw))

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] Distinguish internal statistics from existing user text columns

read_control_stats was a valid public extra_dataset_fields name before this change, but the reader now interprets any column with that name as internal statistics. Using the exact parent writer, I imported a source with extra_dataset_fields={'read_control_stats': 'notes.txt'} containing ordinary text; the parent can read the resulting group, while this head's PaimonLeRobotDataset raises JSONDecodeError here. The same import with field name notes remains readable. This breaks the stated existing-group compatibility even without appending or changing any files. Use distinguishable internal metadata/versioning (and preserve historical user columns), rather than selecting this representation solely by an unreserved column name.

@XiaoHongbo-Hope
XiaoHongbo-Hope force-pushed the codex/preserve-source-episode-stats branch from b4618d7 to 63642b1 Compare November 14, 2026 15:04

@Akash3121 Akash3121 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.

LGTM

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.

3 participants