--- license: apache-2.0 tags: - robotics - pi0.5 - openpi - lora - RA-BC --- # pi05-bread-r1-top200 — RA-BC policy for bread-to-toaster (bimanual UMI) pi0.5 base + LoRA finetune (10k steps, killed at loss plateau), trained with **RA-BC** (reward-model-weighted BC, SARM2 delta-progress weights, clipped at 0) on **200 curated bimanual UMI episodes** (top-200 of 256 by reward-model mean-dP + dP-variance). Training code: https://github.com/BrianZhengJourney/openpi/tree/bread-r1 (`pi05_bread_r1_lora` config; `BreadInputs`/`BreadOutputs` in `src/openpi/policies/bread_policy.py`). Data pipeline + decision docs: https://github.com/BrianZhengJourney/bread-toaster. ## Contents - `10000/params` — orbax params (servable with openpi `create_trained_policy`) - `10000/assets` — **norm stats (quantile), computed on the 200 training episodes. The policy is meaningless without them; loaded automatically from the ckpt dir.** ## Inference contract (must match EXACTLY at deployment) | Item | Value | |---|---| | Obs images | `left_wrist_image`, `right_wrist_image` — uint8 HWC, resize-with-pad → 224×224 (done inside the transform stack). **No base/top camera: the base_0_rgb slot is zeroed + masked** (training top view was a human egocam; do not feed the RealSense) | | Obs state | 20D `[Lxyz, Lrot6d, Lgrip, Rxyz, Rrot6d, Rgrip]`, **relative_to_first**: per arm `T_rel = inv(T_arm,start) @ T_arm,t` (record each arm's grasp_site pose at rollout start, re-express every subsequent pose). Frame = URDF `grasp_site` (yam_linear_4310 canonical TCP). Gripper: 0=closed, 1=open | | Prompt | `take the bread out of the bowl and put the bread into the toaster` (exact string) | | Action | `(40, 14)` @30 Hz: per arm `[Δxyz(3, TCP frame), axis-angle Δrot(3), ABSOLUTE gripper target(1)]`, **stepwise-chained**: `delta_k = inv(T_{t+k-1}) @ T_{t+k}`; executor integrates `T_cmd,k = T_cmd,k-1 @ delta_k` starting from `T_current`. SO(3) composition only; denormalize exactly once | | Latency | UMI-style: feed the proprio sampled at image exposure time; start executing the chunk at step `ceil(latency × 30 Hz)` | ## Minimal loading example (openpi, branch `bread-r1`) ```python from openpi.training import config as _config from openpi.policies import policy_config policy = policy_config.create_trained_policy( _config.get_config("pi05_bread_r1_lora"), "/10000") out = policy.infer({ "left_wrist_image": left_uint8_hwc, "right_wrist_image": right_uint8_hwc, "state": rel_state_20d, "prompt": "take the bread out of the bowl and put the bread into the toaster", }) actions = out["actions"][:, :14] # (40, 14) ``` ## Provenance - Base: `gs://openpi-assets/checkpoints/pi05_base` · LoRA gemma_2b_lora + gemma_300m_lora · bs 32 · lr 2.5e-5 cosine · stopped at 10k/20k (plateau; lr was ~50% peak — resume from `10000` if undertrained on-robot) - Reward model for weights: SARM2 r4_bimanual (v3 7-stage labels, human-verified boundaries) - wandb: project `openpi`, run `r1_top200` (8d6mivlw) - Offline P0 check results: see the repo issue/notes accompanying this upload