feat(rldb): h264 video-backed images + role-in-key annotations + span selection - #541
feat(rldb): h264 video-backed images + role-in-key annotations + span selection#541ElmoPA wants to merge 1 commit into
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
c9e0e8a to
d7ab8c0
Compare
Claude Code ReviewReview of PR #541SummarySubstantial feature PR adding h264-video-backed image storage (chunked mp4s), role-in-key annotation processing, and span-based selection to the rldb data path. The primary changes look well-thought-out (chunked layout with keyframe-aligned decoding, dispatch on Key concerns1. Unrelated changes bundled into one PRThe description advertises h264 + annotations + span selection, but the diff also includes:
Each of these is a training-affecting change on its own. Bundling them makes the PR very hard to bisect if training regressions appear, and violates the "don't break training" priority. Strongly recommend splitting into at least: (a) h264 + annotations + spans (the advertised change), (b) embodiment collapse + mandatory intrinsics, (c) Aria orientation fix, (d) HPT text prompts, (e) eval_latent. 2. Backward-compat break: embodiment collapse is a hard-crash migrationThe README explicitly acknowledges that already-uploaded episodes with
3. Aria EE/wrist orientation change silently invalidates cached episodesChanging 4.
|
… selection
Video image storage (video_codec.py, _common.decode_video_span, zarr_writer,
zarr_dataset_multi): store frames as one mp4 per group of frames_per_chunk
instead of per-frame JPEG. Measured on real fold episodes: 44.8 -> 20.2 KB/frame
and 8.33 -> 1.68 ms/frame decode, and h264 also beats JPEG at EQUAL bytes
(+2.4..2.9 dB PSNR at 4-8 KB), so it is strictly better coding rather than a
quality-for-size trade. crf15/gop30/yuv420p; decode speed is flat across CRF, so
compressing harder would buy only disk.
Layout: chunk-indexed, NOT one blob per episode -- a span read would otherwise
pull the whole episode (~68 MB) and we read ~13 spans/episode. Frame f lives in
chunk f//fpc at offset f%fpc; chunks start on a keyframe (keyint_min=g,
sc_threshold=0) so each decodes independently. Readers dispatch on
_features[key]["dtype"] ("jpeg" vs "h264"), so existing episodes are untouched
and both formats coexist. decode_video_span returns the same (T,3,H,W) float
array as decode_jpeg_window, so pack_collate/TargetBuilder need no change;
equivalence-gated against the JPEG path on the same episode (38.6-39.1 dB,
including a chunk-boundary span and the partial tail chunk) and stride parity
matches decode_jpeg_window_strided.
annotation_processing.py: port of the role-in-key-name scheme -- role lives in
the zarr key NAME (annotations_task/annotations_subtask), entries are plain
{text,start_idx,end_idx} spans. _load_annotations is now per-key (the previous
single-slot cache aliased across keys) and an absent key degrades to [] rather
than raising.
zarr_dataset_packed: annotation_key + span_indices, so a run can read a
structural segmentation key (fold_segments) and select individual spans. Note
fold_segments deliberately sits OUTSIDE the annotations* glob -- those spans
define training windows, not language, and must not reach the batch as a text
role.
fold_span_transforms: RH_WRIST_MODE=none -> 126-dim keypoints-only (the wrist
pose is redundant with the keypoints). ypr(138)/pos(132) unchanged; default
still pos.
61cc54d to
bb52176
Compare
74b3185 to
6a75409
Compare

Video image storage (video_codec.py, _common.decode_video_span, zarr_writer,
zarr_dataset_multi): store frames as one mp4 per group of frames_per_chunk
instead of per-frame JPEG. Measured on real fold episodes: 44.8 -> 20.2 KB/frame
and 8.33 -> 1.68 ms/frame decode, and h264 also beats JPEG at EQUAL bytes
(+2.4..2.9 dB PSNR at 4-8 KB), so it is strictly better coding rather than a
quality-for-size trade. crf15/gop30/yuv420p; decode speed is flat across CRF, so
compressing harder would buy only disk.
Layout: chunk-indexed, NOT one blob per episode -- a span read would otherwise
pull the whole episode (~68 MB) and we read ~13 spans/episode. Frame f lives in
chunk f//fpc at offset f%fpc; chunks start on a keyframe (keyint_min=g,
sc_threshold=0) so each decodes independently. Readers dispatch on
_features[key]["dtype"] ("jpeg" vs "h264"), so existing episodes are untouched
and both formats coexist. decode_video_span returns the same (T,3,H,W) float
array as decode_jpeg_window, so pack_collate/TargetBuilder need no change;
equivalence-gated against the JPEG path on the same episode (38.6-39.1 dB,
including a chunk-boundary span and the partial tail chunk) and stride parity
matches decode_jpeg_window_strided.
annotation_processing.py: port of the role-in-key-name scheme -- role lives in
the zarr key NAME (annotations_task/annotations_subtask), entries are plain
{text,start_idx,end_idx} spans. _load_annotations is now per-key (the previous
single-slot cache aliased across keys) and an absent key degrades to [] rather
than raising.
zarr_dataset_packed: annotation_key + span_indices, so a run can read a
structural segmentation key (fold_segments) and select individual spans. Note
fold_segments deliberately sits OUTSIDE the annotations* glob -- those spans
define training windows, not language, and must not reach the batch as a text
role.
fold_span_transforms: RH_WRIST_MODE=none -> 126-dim keypoints-only (the wrist
pose is redundant with the keypoints). ypr(138)/pos(132) unchanged; default
still pos.