Instructions to use angkul07/pi05-piper-dual-ea with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use angkul07/pi05-piper-dual-ea with LeRobot:
- Piper
How to use angkul07/pi05-piper-dual-ea with Piper:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Οβ.β
dual-arm Piper β 50/50 retargeted ego + teleop (mf_pi05_dual_ea)
A Οβ.β
(flow-matching) fine-tune of pi05_base for the AgileX Piper bimanual rig:
half of every training batch drawn from real teleoperation of the plate-handover task,
half from egocentric human video retargeted onto the same robot. Trained 2026-08-29/30.
What is in this repo
| path | step | size | what |
|---|---|---|---|
29999/ |
30,000 (final, fully annealed) | ~6.7 GB | params/ + assets/ (norm stats) |
15000/ |
15,000 (mid-run ladder pin) | ~6.7 GB | params/ + assets/ (norm stats) |
Optimizer state (train_state/, ~5.9 GB per step) is not uploaded β these
checkpoints serve inference and evaluation, not resumption. Four more ladder pins
(5k, 10k, 20k, 25k) exist off-Hub if the holdout scoring points between these two.
The assets/ folder holds the quantile norm stats computed over the sampled 50/50
mixture (asset id mf_dual_ea). They describe the blend, not either pool, and must
be used with these weights β substituting stats from any other run silently
normalizes against the wrong distribution.
Data
Two LeRobot v2.1 datasets, schema-aligned at build time (one 14-D joints-major
layout [right_j1-6, left_j1-6, right_gripper, left_gripper] in degrees, grippers
normalized [0,1], three cameras top / left-arm / right-arm, 480Γ640 h264, 20 Hz):
| pool | episodes | frames | tasks | source |
|---|---|---|---|---|
teleop_v21 |
86 | 138,120 (~1.92 h) | 1 (right_pick_handover_left_place) |
real dual-arm rig, 3 physical cameras |
ego_v21 |
377 | 141,302 (~1.96 h) | 241 | human video retargeted to Piper; 3 views synthesized from one egocentric camera |
The draw is a hard 64/64 per batch, so each half contributes exactly 50% of every gradient. Teleop episodes 78β85 (a contiguous tail, ~9.3%) were held out of training as the evaluation split; nothing was withheld from the ego half.
Recipe
- Model: Οβ.β
β LoRA
gemma_2b_loratrunk, full-rank action expert, EMA off,action_dim=32(padded; real width 14),action_horizon=50= 2.5 s of future at 20 Hz,max_token_len=200, image augmentation on (both stacks). - Schedule: 30,000 steps at batch 128, cosine 3.5e-5 β 3.5e-6, warmup 1,000. That is 3.84 M samples: ~15.3 passes over the teleop train split, ~13.6 over ego. Batch 128 @ 30k was chosen to match the exposure of the originally planned 60k @ 64 at roughly half the wall-clock; peak LR was deliberately not rescaled for the larger batch (first batch-128 run of this recipe β one variable at a time).
- Hardware: 4Γ H100 SXM 80 GB, pure data parallel (32 samples/GPU), 1.4β1.5 s/step, 12 h 33 m wall-clock (~$148 at $11.79/h).
- Prompt:
prompt_from_task=True. The teleop half is conditioned on the one task string above; the ego half carries its 241 distinct strings. Evals of the handover task should prompt withright_pick_handover_left_place.
Training curve
Per-step metrics (100-step window means; train_metrics.log, un-averaged, is the
source β also mirrored in W&B run 212iran7):
| step | loss | chunk_first | chunk_last | grad_norm |
|---|---|---|---|---|
| 200 | 0.0503 | 0.0216 | 0.0864 | 0.072 |
| 1,000 | 0.0387 | 0.0104 | 0.0672 | 0.055 |
| 5,000 | 0.0225 | 0.0078 | 0.0373 | 0.053 |
| 10,000 | 0.0147 | 0.0065 | 0.0238 | 0.043 |
| 15,000 | 0.0113 | 0.0055 | 0.0182 | 0.040 |
| 20,000 | 0.0087 | 0.0048 | 0.0138 | 0.039 |
| 25,000 | 0.0071 | 0.0045 | 0.0110 | 0.040 |
| 29,900 | 0.0062 | 0.0039 | 0.0095 | 0.042 |
Monotone descent end to end; grad norm flat at ~0.04 after warmup (peak 0.58 at
step 1, inside warmup, as on every run of this recipe); the early-stop stall guard
never fired. chunk_last (the hardest, furthest-future slice of the 50-step chunk)
tracks ~2.4Γ chunk_first throughout β the honest column to watch, since
chunk_first benefits most from the delta-action shortcut.
How to read these numbers β and how not to
The training loss cannot support capability claims. Under cosine decay the loss falls all the way to the last step because the LR does, and at ~14β15 epochs of a ~267k-frame corpus it cannot distinguish fitting from memorising. That is exactly why two checkpoints are published and the ladder was kept: the ship decision belongs to offline evaluation on the held-out teleop episodes (78β85), not to this table. The final checkpoint has now been scored on that holdout (see the evaluation section below); the other ladder pins remain unscored, so "29999 beats its own knee" is still an open question β the eval gives it an absolute score, not a within-run rank.
Known data caveats that no training recipe removes: the ego half's three views are crops of one egocentric frame (no real parallax, unlike teleop's three physical cameras), and gripper resting-aperture statistics were reconciled across the halves at the data layer before this run.
Holdout evaluation β checkpoint 29999
Offline eval (fd-studio suite) of the final checkpoint only, on the 8 held-out
teleop episodes (78β85, ~10.7 min, never seen in training), dense at every frame:
open-loop 50-step chunk prediction, errors in degrees (the robot's native units β
RobotOutputs un-normalises before comparison). Critical intervals were annotated by
gemini-3.7-flash (Vertex) from the upright top-camera video and verified to bracket
the ground-truth gripper transitions. CI-MSE is DTW-aligned within each interval.
| episode | frames | action MSE (degΒ²) | action MAE (deg) | grip acc R | grip acc L | CI-MSE mean | grasp | handover | place |
|---|---|---|---|---|---|---|---|---|---|
| 78 | 1,375 | 5.45 | 1.088 | 90.9% | 90.7% | 3.55 | 7.15 | 1.31 | 3.38 |
| 79 | 1,502 | 6.86 | 1.167 | 89.1% | 93.6% | 5.36 | 8.71 | 4.41 | 0.28 |
| 80 | 1,697 | 4.31 | 0.969 | 92.1% | 94.1% | 1.61 | 2.65 | 1.40 | 0.97 |
| 81 | 1,728 | 8.71 | 1.277 | 85.0% | 94.0% | 3.18 | 3.50 | 3.14 | β * |
| 82 | 1,325 | 6.02 | 1.172 | 89.4% | 92.6% | 4.46 | 7.72 | 2.84 | 4.09 |
| 83 | 1,295 | 10.29 | 1.422 | 86.9% | 92.0% | 4.65 | 1.91 | 3.52 | 11.43 |
| 84 | 1,711 | 10.16 | 1.226 | 89.9% | 92.2% | 2.15 | 1.88 | 1.31 | 4.47 |
| 85 | 1,578 | 6.66 | 1.200 | 80.6% | 94.5% | 2.58 | 4.89 | 2.63 | 0.82 |
| all | 12,211 | 7.32 | 1.186 | 88.0% | 93.0% | 3.40 | 4.80 | 2.57 | 3.63 |
* ep 81's place interval was dropped: the VLM's timestamps for that episode overrun its length (place labelled at frames 2370β2470 of 1,728), so its handover interval is also partially clipped. One defective annotation of eight; the aggregate row's per-interval means are computed over the valid intervals.
How to read this:
- Per-dim MAE ~1.2Β° is tight and uniform β episode means span only 0.97β1.42Β°, so no holdout episode is out-of-distribution for the policy; there is no collapse, freezing, or thrashing anywhere (the failure modes that sank earlier Οβ.β runs).
- The grasp phase is the hardest on aggregate (CI-MSE 4.80 vs 2.57 handover / 3.63 place) β precision-approach is where error concentrates, consistent with grasp intervals being the discriminative segment in prior FD evals. Per episode it varies: ep 83's error lives almost entirely in the place phase (11.43), and its grasp is actually the cleanest (1.91).
- The right arm is consistently worse than the left β higher joint MAE (its j2 is the worst dim at 2.20Β°) and lower gripper accuracy (88.0% vs 93.0%, dropping to 80.6% on ep 85). The right arm performs the pick, the harder role in this task.
- Best episode: 80 (MAE 0.969Β°, CI-MSE 1.61) β the side-by-side video below shows this episode; it was chosen as the middle holdout episode before scoring and happens to be the policy's best, so read it as the upper bound, not the average.
- Caveats: degrees-native numbers are not comparable to any YAM/radians eval; and with a single checkpoint scored there is no within-run reference β these are baseline absolutes for the family, not a comparison.
Artifacts in this repo (eval/):
per_episode.json Β·
offline_proxies.json Β·
ci_mse_results.txt Β·
annotations_gemini-3.7-flash.json Β·
side-by-side joint video, ep 80 (upright top
camera + all 14 dims GT vs prediction) Β·
val_episodes/ β the 8 holdout episodes' top-camera videos,
rotated upright, for reference alongside the numbers.
Usage
from openpi.training import config as _config
from openpi.policies import policy_config
cfg = _config.get_config("mf_pi05_dual_ea") # needs the configs/ tree from the repo below
policy = policy_config.create_trained_policy(cfg, "<download>/29999")
Config, robot spec (PIPER_DUAL, including the grippers_trailing joints-major
layout handling) and the full run documentation live in
angkul07/openpi, branch mf-piper-ea
(configs/mf/piper/dual_ego_vs_teleop.py, configs/mf/datasets_dual.py).
Reproduce
# on a box with /workspace/final_data/{teleop_v21,ego_v21} and 4 GPUs
export WANDB_PROJECT=mf-piper
./vast_run/run_yam.sh mf_pi05_dual_ea dual_ea