Skip to content

feat(zarr): persist camera intrinsics in zarr.json#386

Merged
ElmoPA merged 7 commits into
mainfrom
elmo/intrinsic-zarr
Jul 9, 2026
Merged

feat(zarr): persist camera intrinsics in zarr.json#386
ElmoPA merged 7 commits into
mainfrom
elmo/intrinsic-zarr

Conversation

@ElmoPA

@ElmoPA ElmoPA commented May 4, 2026

Copy link
Copy Markdown
Contributor

Add an intrinsics parameter to ZarrWriter (and create_and_write) that
serializes a single np.ndarray K matrix or a {camera_key: K} dict into
zarr metadata. Expose ZarrEpisode.intrinsics / ZarrDataset.intrinsics
that read it back as ndarray(s), or None when not written.

This unblocks per-episode intrinsics so viz no longer has to rely on
class-level Embodiment.INTRINSICS constants.

ElmoPA commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@ElmoPA ElmoPA marked this pull request as ready for review May 4, 2026 18:57
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch 2 times, most recently from 66a49fd to f058830 Compare May 5, 2026 16:33
@ElmoPA ElmoPA force-pushed the elmo/lightwheel-emb branch from 5265946 to fb7e066 Compare June 12, 2026 20:59
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch 3 times, most recently from c73430a to 75a9774 Compare June 16, 2026 20:24
@ElmoPA ElmoPA changed the base branch from elmo/lightwheel-emb to graphite-base/386 June 16, 2026 21:03
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch from 75a9774 to 5f26d41 Compare June 16, 2026 21:03
@ElmoPA ElmoPA force-pushed the graphite-base/386 branch from fb7e066 to 1c23942 Compare June 16, 2026 21:03
@ElmoPA ElmoPA changed the base branch from graphite-base/386 to main June 16, 2026 21:03
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch 11 times, most recently from d70ad6c to e84a5e9 Compare June 24, 2026 01:29
ElmoPA and others added 3 commits July 6, 2026 15:30
…odiments

Squashed combining the intrinsics/embodiment work:
- move intrinsics/extrinsics into embodiment classes (remove CameraTransforms)
- gaze viz mode + zarr_data_viz notebook update; add LightWheel embodiment
- persist camera intrinsics in zarr.json; make them MANDATORY (validated {camera_key: 3x4} dict)
- collapse aria/mecka/scale/lightwheel human data into human_* (ids 1-3); eva = 4-6
- strict extrinsics (None or non-empty dict); embodiment validated at write time
- aria right-hand ee-pose + wrist-pose orientation fix
- sweep all hydra configs + tests to the collapsed embodiment

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop RIGHT_HAND_ORIENTATION_FIX (ee, diag(-1,-1,1) X/Y) and
RIGHT_WRIST_ORIENTATION_FIX (wrist, diag(-1,1,-1) X/Z) so the right
hand uses T_ROT_CAM like the left. Verified in dataset viz: both hands
share one convention after revert. Intrinsics + human_bimanual kept.
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch from e84a5e9 to e6dcf42 Compare July 6, 2026 19:41
- pi.py / pl_data_utils.py: control_mode is declared per-embodiment in
  yaml only — remove the dead "aria" fallback and the silent gripper
  default; an embodiment with no matching key now raises ValueError.
- zarr_dataset_multi.py: precomputed norm_stats.json missing the
  requested embodiment id now raises ValueError instead of silently
  loading empty stats (enum ids were renumbered by the collapse).
- zarr_writer.py: actually enforce the documented intrinsics/extrinsics
  contract — each intrinsics value must be 3x4, each extrinsics value
  4x4; fix stale CONTRIBUTING_DATA.md section refs (§8->§9, §5.4->§6.4/§6.3).
- notebooks: replace imports of deleted egomimicUtils names
  (CameraTransforms/INTRINSICS) with the relocated constants in
  rldb/embodiment (ARIA_/SCALE_/MECKA_INTRINSICS, Eva.EXTRINSICS).
- aria_utils.py: delete the dead RIGHT_HAND/RIGHT_WRIST_ORIENTATION_FIX
  constants and their stale rationale (usages were reverted in e6dcf42).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmG3nhxt7LYiaaSJPsKEV
…lapse data (audit B5/B1)

B5: the changelog claimed the right-hand orientation fix is applied, but
commit e6dcf42 reverts it. Describe the actual convention (both aria hands
share one T_ROT_CAM convention; the per-hand fix was reverted as unnecessary).

B1: get_embodiment_id has no alias for legacy vendor strings, so a locally
cached pre-collapse episode (attrs embodiment='aria_bimanual' etc.) hard-crashes
with KeyError on load. Rather than add an alias, the changelog now tells users
to delete their local cache and re-download the reprocessed (human_*) episodes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmG3nhxt7LYiaaSJPsKEV
@ElmoPA ElmoPA force-pushed the elmo/intrinsic-zarr branch from 7066428 to d052953 Compare July 9, 2026 01:01
ElmoPA and others added 2 commits July 8, 2026 21:09
…gration)

Prepares for the deferred SQL migration: all data-config filter lambdas and
csv_uploader now select on the collapsed embodiment value 'human_bimanual'
instead of the legacy 'aria_bimanual'. 9 configs + csv_uploader, matching
cotrain_pi_latent which was already human_bimanual.

COORDINATION: these filters now match zero rows until the SQL embodiment/
robot_name column is renamed to human_bimanual — land this together with the
SQL migration (see human.yaml note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmG3nhxt7LYiaaSJPsKEV
#508 dropped the robot_name column from the DB (only embodiment remains) but
left many filters + code still referencing row['robot_name'] -> KeyError at
filter time. Point everything at embodiment:
- 6 filter lambdas (cotrain_pi_lang, cotrain_pi_no_lang, eva_pi_lang, human,
  scale_pi): row['robot_name'] -> row['embodiment'].
- scale_pi also: 'scale_bimanual' -> 'human_bimanual' (value collapsed; the
  existing lab=='scale' clause still isolates the source).
- aria_keypoints, aria_keypoints_wrist, industry_eva_pi(eva): converted plain
  {robot_name/embodiment, task} dict filters -> DatasetFilter+filter_lambdas on
  embodiment (plain-dict filters are also rejected by the zarr resolver).
- latent_dataset.build_dataset: constructed filter -> row['embodiment'].
- csv_uploader: dropped the orphaned robot_name write (embodiment already set;
  TableRow has no robot_name field so it would raise).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmG3nhxt7LYiaaSJPsKEV
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Claude Code Review

Summary

Massive PR that combines three orthogonal changes: (1) the advertised feature — persisting camera intrinsics in zarr.json, (2) collapsing all human embodiments (aria_*, mecka_*, scale_*) into a single human_* embodiment, and (3) hardening PI._get_control_mode to remove the aria fallback. The scope is far broader than the PR title/description advertise.

Key concerns

1. PR scope mismatch — this is not a single-feature PR

The title says "persist camera intrinsics in zarr.json" but the diff also:

  • Renames the entire aria_*/mecka_*/scale_* embodiment enum to human_* (breaking change, ids re-numbered).
  • Collapses the Aria/Mecka/Scale embodiment classes into a single Human class.
  • Reassigns integer embodiment ids (Eva was 6/7/8 → now 4/5/6; aria_bimanual was 5 → gone).
  • Removes HPT.camera_transforms assignment.
  • Removes the aria fallback in PI._get_control_mode.

Each of these deserves its own PR + review. Please split.

2. Embodiment integer id renumbering is a silent data-corruption risk

Old eva_bimanual = 8, new eva_bimanual = 6. Any checkpoint / cached norm-stats / logged artifact that stored the integer id is now silently mis-mapped to a different embodiment. If integer ids are used anywhere in checkpoints, replay buffers, or persisted training state, existing runs will train against the wrong per-embodiment head/stats without erroring. This needs either (a) preserving old integer assignments and only appending new ones, or (b) an explicit audit of every persisted use of the int id.

3. SQL migration is assumed but not included

human.yaml's own comment says: "this ASSUMES the SQL embodiment/robot_name column has been migrated from the old vendor values ('aria_bimanual'). Until that migration lands, this dataset matches zero rows." Shipping data configs that match zero rows will silently produce empty dataloaders (or crash at first-batch depending on MultiDataset behavior). The SQL migration script + a preflight check should land before or with this PR, not after.

Related: the README changelog tells users to re-download data, but there's no migration path for the DB itself, and robot_name conventions in CONTRIBUTING_DATA.md changed (aria_bimanualhuman_bimanual) — existing rows with robot_name="aria_bimanual" will be filtered out by any config that switches to row['embodiment'] == 'human_bimanual'.

4. Intrinsics contract is stricter than the codebase can honor today

ZarrWriter.create_and_write now raises if intrinsics isn't a non-empty dict, and CONTRIBUTING_DATA.md calls it MANDATORY. But:

  • The README changelog itself says "Mecka and Scale will be asked to add intrinsics to their exports." So today's Mecka/Scale conversion scripts presumably cannot call create_and_write without erroring. Have you verified mecka_to_zarr.py / scale_to_zarr.py pass intrinsics?
  • 3×4 K with a zero column is unusual — standard convention is 3×3. Enforcing 3×4 in the writer will bite anyone constructing K from calibration output. At minimum, accept 3×3 in the writer and pad internally, or make the shape check crystal clear in the ValueError.

5. Judgment calls buried in configs

industry_eva_pi.yaml and mecka_scale_cotrain_pi.yaml comments say: "mecka has a head pose and scale does not, so the merged human keymap uses has_head_pose=false (scale-compatible) for a consistent representation." This silently drops the head-pose signal from Mecka episodes in every training run using these configs. That's a real regression for anyone whose current runs relied on mecka head pose. Flag this loudly in the changelog, not in a yaml comment.

6. HPT.camera_transforms removal

self.camera_transforms = camera_transforms was deleted from HPT.__init__ with no replacement. If any downstream code (viz, eval) reads self.camera_transforms on an HPT instance, it now AttributeErrors. Was the attribute unused everywhere, or only in the paths you happened to hit? Grep confirmation needed.

7. PI._get_control_mode — behavior change

Removing the aria default is correct in spirit, but any existing pi model yaml that omitted an explicit control_mode entry for aria will now hard-crash at first forward pass. Make sure every checked-in pi yaml has explicit control_mode entries for every embodiment it can encounter (including human_* post-rename).

8. Tests are shallow for a change this size

The test_pi.py diff is purely a string-rename (aria_bimanualhuman_bimanual). There's no new test for:

  • ZarrWriter round-trip of intrinsics (create_and_write → read back via ZarrEpisode.intrinsics).
  • ZarrWriter rejection of malformed intrinsics (missing, 3×3 instead of 3×4, empty dict, non-dict).
  • ZarrEpisode.intrinsics returning None for legacy episodes.
  • get_embodiment_id behavior on legacy strings (should hard-crash per README — is there a test?).

Suggestions

  • Split the PR. Land intrinsics-writer feature first (with tests), then the embodiment collapse (with SQL migration + id-preservation), then the pi/hpt cleanups.
  • Preserve old integer ids — never renumber. Assign new ids sequentially past the existing max.
  • Add a preflight check in `M

Reviewed by Claude · Review workflow

@ElmoPA ElmoPA merged commit 2935f2c into main Jul 9, 2026
2 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.

1 participant