README: TERRA-vs-control inventory, and the 4 LIBERO cells
Browse files
README.md
CHANGED
|
@@ -1,48 +1,210 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
4 query tokens. **One directory = one model**, each with its own README (what it is, how to deploy it, what has been
|
| 5 |
-
measured). Every deployable directory holds merged weights (`model-*.safetensors`), the action head
|
| 6 |
-
(`action_decoder.pt`, required), `dataset_statistics.json` (un-normalisation), `ctrl_meta.json` and the processor.
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
```bash
|
| 11 |
git clone -b newton https://github.com/DingTianxingjian/Latent_Free.git latent_free && cd latent_free
|
| 12 |
huggingface-cli download Potestates/TERRA --include "<dir>/*" --local-dir .
|
| 13 |
```
|
| 14 |
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|---|---|---|---|---|---|
|
| 19 |
-
| `
|
| 20 |
-
| `
|
| 21 |
-
| `
|
| 22 |
-
|
|
| 23 |
-
|
|
| 24 |
-
|
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
pipeline_tag: robotics
|
| 3 |
+
tags:
|
| 4 |
+
- openvla
|
| 5 |
+
- vision-language-action
|
| 6 |
+
- robotics
|
| 7 |
+
- libero
|
| 8 |
+
---
|
| 9 |
|
| 10 |
+
# TERRA β post-trained policies (real robot + LIBERO)
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
+
OpenVLA-7B with TERRA latent-action phase 2 (`latp2_inv` labels), post-trained with a flow-matching action head and
|
| 13 |
+
4 query tokens. **One directory per policy**, each self-contained: merged weights (`model-*.safetensors`), the
|
| 14 |
+
action/latent head (`action_decoder.pt` β **required**, it is not inside the merged VLA weights),
|
| 15 |
+
`dataset_statistics.json` (action un-normalisation), `ctrl_meta.json`, processor/tokenizer, and its own `README.md`
|
| 16 |
+
with the measured numbers and the exact deployment loop.
|
| 17 |
+
|
| 18 |
+
**Code:** https://github.com/DingTianxingjian/Latent_Free β branch `newton`, public, no token needed.
|
| 19 |
|
| 20 |
```bash
|
| 21 |
git clone -b newton https://github.com/DingTianxingjian/Latent_Free.git latent_free && cd latent_free
|
| 22 |
huggingface-cli download Potestates/TERRA --include "<dir>/*" --local-dir .
|
| 23 |
```
|
| 24 |
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
## Which one do I test?
|
| 28 |
+
|
| 29 |
+
| I want to⦠| use | why |
|
| 30 |
+
|---|---|---|
|
| 31 |
+
| **press a coloured button** | **`press_button_terra_delta`** | the only policy **confirmed working on hardware** β it presses the requested button |
|
| 32 |
+
| **pick the can, place on plate** | **`piper_pick_can_openvla_delta`** | **3x better open loop** than the arm currently on the robot (1.05 vs 3.24 deg); simplest of the equals |
|
| 33 |
+
| the same, with our full method | `piper_pick_can_terra_delta` | statistically **indistinguishable** from the row above (1.13 vs 1.05, CI contains 0) β either is fine |
|
| 34 |
+
| **one model for both tasks** | `piper_multi_anchored_step5500` | **experimental**, and a retrain will supersede it β see its README |
|
| 35 |
+
| **compare the latent mechanism** in sim | the `libero_goal_frac10_*` **triplet** | ours / UniVLA's / **no latent at all**, identical otherwise |
|
| 36 |
+
| post-train a new task | `p2fft_20k` | the **base**, not a policy |
|
| 37 |
+
|
| 38 |
+
> ### β Two things that will break a deployment if you skip them
|
| 39 |
+
> 1. **Action space differs per directory.** `piper_pick_can_10k` emits **absolute** joint targets; everything with
|
| 40 |
+
> `delta` in the name emits **target minus measured joint angle** and must be sent as `q + a[:6]` with `q` re-read
|
| 41 |
+
> **every tick**; the `anchored` ones use `q` read **once per chunk** and a different call. Every `ctrl_meta.json`
|
| 42 |
+
> now records `"action_space"` explicitly and `PiperPolicy` prints it on load β **check the printed line.**
|
| 43 |
+
> 2. **Execute 1 chunk entry, then re-predict** (all per-step `delta` policies). The demos were teleoperated as a
|
| 44 |
+
> continuous 30 Hz command, so later chunk entries are mis-anchored for an arm that settles: drift is
|
| 45 |
+
> **0.855 deg/step on pick-can** and **~2 deg/step on press_button**, and it is opposite-signed on the two joints
|
| 46 |
+
> that carry the motion, so it **bends the direction** instead of just scaling it. This was seen on the robot:
|
| 47 |
+
> chunk 1 presses the button, chunk 2 "the direction is a bit off". Use an `anchored` checkpoint if you need
|
| 48 |
+
> multi-step chunks.
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
|
| 52 |
+
## Inventory β which directories are **ours (TERRA)** and which are **controls / baselines**
|
| 53 |
+
|
| 54 |
+
Every policy here shares the same interface (LoRA r32 + flow-matching head + 4 query tokens, chunk 12). What differs
|
| 55 |
+
is the **base** and the **latent channel**, which is exactly what each comparison is about.
|
| 56 |
+
|
| 57 |
+
### TERRA β ours (latent channel `tc_cont`, `latp2_inv` labels)
|
| 58 |
+
|
| 59 |
+
| dir | base | task / suite | number |
|
| 60 |
+
|---|---|---|---|
|
| 61 |
+
| `p2fft_20k` | openvla-7b, full fine-tune | **phase-2 base, not a policy** | β |
|
| 62 |
+
| `press_button_terra_delta` | `p2fft_20k` | press_button, per-step delta | 0.918Β° β
on hardware |
|
| 63 |
+
| `press_button_anchored_fwd_step1500` | `p2fft_20k` | press_button, anchored, fixed window | 0.96Β° at k=0, flat in k |
|
| 64 |
+
| `piper_pick_can_terra_delta` | `p2fft_20k` | pick-can, per-step delta | 1.126Β° |
|
| 65 |
+
| `piper_pick_can_10k` | `p2fft_20k` | pick-can, **absolute** β superseded | 3.24Β° |
|
| 66 |
+
| `piper_multi_anchored_step2500` / `step5500` | `p2fft_20k` | both tasks, anchored β experimental | see card |
|
| 67 |
+
| `libero_goal_full` | LoRA-scale phase 2 | LIBERO-Goal, full split | 94.4 % |
|
| 68 |
+
| `libero_10_full` | LoRA-scale phase 2 | LIBERO-Long, full split | 89.0 % |
|
| 69 |
+
| `libero_10_frac10_terra_p2fft20k` | `p2fft_20k` | LIBERO-Long, 10 % (43 demos) | 60.6 % |
|
| 70 |
+
| `libero_goal_frac10_terra` | **openvla-7b, no phase 2** | LIBERO-Goal, 10 % | 86.8 % |
|
| 71 |
+
|
| 72 |
+
### Baselines / controls β no latent, or somebody else's latent
|
| 73 |
+
|
| 74 |
+
| dir | what it controls for | number |
|
| 75 |
+
|---|---|---|
|
| 76 |
+
| `press_button_openvla_delta` | stock openvla-7b, **`--latent none`** β the whole package vs nothing | 1.920Β° (worse than not moving) |
|
| 77 |
+
| `piper_pick_can_openvla_delta` | the same, on pick-can | **1.054Β°** β here it is a good policy |
|
| 78 |
+
| `libero_goal_frac10_none` | **no latent at all**, identical otherwise (`latent_r2` β‘ 0) | 88.6 % |
|
| 79 |
+
| `libero_goal_frac10_univla_cont` | **UniVLA's** deployed latent through our interface | 89.4 % |
|
| 80 |
+
|
| 81 |
+
> **One honest caveat about the two `*_openvla_delta` controls.** They change the base **and** the latent branch at
|
| 82 |
+
> once (`INIT=none LATENT=none`), so where they separate, the effect belongs to *the whole package*, not specifically
|
| 83 |
+
> to the latent branch. The missing arm that would split those two β phase-2 base with `--latent none` β has not been
|
| 84 |
+
> run. The `libero_goal_frac10_*` triplet *is* clean in that sense (one factor, no phase 2 anywhere), and there the
|
| 85 |
+
> answer is that the latent channel changes nothing.
|
| 86 |
+
>
|
| 87 |
+
> **Which base a policy came from is not in most of these files.** `ctrl_meta.json` records the latent, the head
|
| 88 |
+
> and the dataset, but the training script never wrote the phase-2 init. The four directories published on
|
| 89 |
+
> 2026-11-12 (`libero_goal_frac10_*`, `libero_10_frac10_terra_p2fft20k`) now carry an explicit `"init"` field;
|
| 90 |
+
> for the others the base is stated in the table above and in each card, and nowhere in the weights.
|
| 91 |
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
## Real-robot policies β AgileX Piper
|
| 95 |
+
|
| 96 |
+
Open-loop error = mean |error| per joint in **degrees** on held-out episodes never trained on, chunk sampled from
|
| 97 |
+
noise through the deployment image path. Reproduce any row with
|
| 98 |
+
`envs/univla_vla/bin/python -m acdc_la.realrobot.piper_policy --checkpoint <dir> --replay <rlds root>` β it is
|
| 99 |
+
deterministic, and reproducing it is the check that your preprocessing matches ours.
|
| 100 |
+
|
| 101 |
+
### `press_button` β "press the {blue, orange, pink, red} button", 100 episodes, layout reshuffled per episode
|
| 102 |
+
|
| 103 |
+
| dir | base | action | `chunk[0]` | reads the instruction? | on the robot |
|
| 104 |
+
|---|---|---|---|---|---|
|
| 105 |
+
| **`press_button_terra_delta`** | our phase 2 | delta | **0.918** | **yes** β output moves 0.42 deg on a colour swap; true word wins 4/5 episodes | β
**presses the button** (chunk 1; slightly off centre) |
|
| 106 |
+
| `press_button_openvla_delta` | stock openvla-7b | delta | 1.920 | **no** β output moves **2.4e-7 deg**; true word wins 1/5 = chance | β not for deployment |
|
| 107 |
+
| *null: "stay where you are"* | | | *1.691* | | |
|
| 108 |
+
|
| 109 |
+
The control is *worse than not moving*, and its invariance to language is **exact, not approximate**: its instruction
|
| 110 |
+
signal is 0.28% of the query-token state, which is below bfloat16 machine epsilon (7.8e-3), so it cannot survive its
|
| 111 |
+
own forward pass. With 4 colours and per-episode layouts a policy that cannot read the colour can only learn an
|
| 112 |
+
average press β which is what its j1/j2 error looks like. Caveats: **5 held-out episodes, 3 of 4 colours, one seed
|
| 113 |
+
per arm, offline**; and the pair changes *both* the base and the latent branch, so the effect cannot be attributed to
|
| 114 |
+
the latent branch alone.
|
| 115 |
+
|
| 116 |
+
### `piper_pick_can` β "pick up the can and place it on the plate", 150 episodes, **one** instruction throughout
|
| 117 |
+
|
| 118 |
+
| dir | base | action | `chunk[0]` | ensembled | note |
|
| 119 |
|---|---|---|---|---|---|
|
| 120 |
+
| **`piper_pick_can_openvla_delta`** | stock openvla-7b | delta | **1.054** | 0.914 | the matched control β and here a perfectly good policy |
|
| 121 |
+
| **`piper_pick_can_terra_delta`** | our phase 2 | delta | **1.126** | 0.950 | ours; **not separated** from the row above |
|
| 122 |
+
| `piper_pick_can_10k` | our phase 2 | **absolute** | 3.24 | 3.69 | the arm tested on the robot first; **superseded** by the two above |
|
| 123 |
+
| *null: "stay where you are"* | | | *1.20* | | |
|
| 124 |
+
| *null: repeat the last command* | | | *2.06* | | |
|
| 125 |
+
| *between-demonstration floor* | | | *0.61* | | **nothing can beat this** |
|
| 126 |
+
|
| 127 |
+
**Delta vs absolute is the real win here: 3.24 β ~1.05 deg, 3x**, and it moves the policy from 2.7x *worse* than
|
| 128 |
+
doing nothing to better than it. **TERRA vs control is not a win for either side**: paired cluster bootstrap over the
|
| 129 |
+
8 held-out episodes (the independent unit β 353 steps is not the sample size) gives a difference of +0.072 deg,
|
| 130 |
+
95% CI **[-0.038, +0.189]**, sign test p = 0.727.
|
| 131 |
+
|
| 132 |
+
A null here is what the mechanism's own story predicts: **all 150 episodes carry the identical instruction**, so
|
| 133 |
+
there is nothing for a language-grounding advantage to do. The same pair separates 2.1x on `press_button`.
|
| 134 |
+
|
| 135 |
+
### `piper_multi_anchored_step2500`, `piper_multi_anchored_step5500` β β experimental
|
| 136 |
+
|
| 137 |
+
One model for **both** tasks (press_button x2 + pick-can mixture), using **chunk-ANCHORED** deltas
|
| 138 |
+
(`target[s+k] - q[s]`, `q` read once per chunk) so that executing several entries open loop is valid. Better than the
|
| 139 |
+
per-step parameterisation from k>=2, slightly worse at k=0. Trained with the old backward sample window (magnitudes
|
| 140 |
+
under-predicted ~0.8x). **`press_button_anchored_fwd_step1500` is the first checkpoint with the window fixed**
|
| 141 |
+
(press-button only, snapshot of a run still training): its error stops growing with chunk position β it levels
|
| 142 |
+
off near 3.5Β° instead of climbing to 13Β° β and it will supersede these for that task. Different deployment call
|
| 143 |
+
(`chunk_targets`, no ensembling) β read their READMEs.
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## LIBERO policies
|
| 148 |
+
|
| 149 |
+
Standard eval, 50 trials x 10 tasks = **500 episodes**, continuous flow head:
|
| 150 |
+
|
| 151 |
+
```bash
|
| 152 |
+
python -m acdc_la.downstream.vla.run_libero_eval_cont --pretrained_checkpoint <dir>
|
| 153 |
+
```
|
| 154 |
+
|
| 155 |
+
| dir | suite | demos | base | latent | success |
|
| 156 |
+
|---|---|---|---|---|---|
|
| 157 |
+
| `libero_goal_full` | Goal | full | LoRA-scale phase 2 | ours | **94.4 %** |
|
| 158 |
+
| `libero_10_full` | Long | full | LoRA-scale phase 2 | ours | **89.0 %** |
|
| 159 |
+
| `libero_10_frac10_terra_p2fft20k` | Long | 10 % (43) | **`p2fft_20k`** | ours | **60.6 %** |
|
| 160 |
+
| `libero_goal_frac10_univla_cont` | Goal | 10 % (43) | openvla-7b | **UniVLA's** | 89.4 % |
|
| 161 |
+
| `libero_goal_frac10_none` | Goal | 10 % (43) | openvla-7b | **none** | 88.6 % |
|
| 162 |
+
| `libero_goal_frac10_terra` | Goal | 10 % (43) | openvla-7b | ours | 86.8 % |
|
| 163 |
+
|
| 164 |
+
### The one result in this repo that is a clean, single-factor comparison β and it is negative
|
| 165 |
+
|
| 166 |
+
The three `libero_goal_frac10_*` rows differ **only** in the latent channel. The **no-latent control lands between
|
| 167 |
+
the two latent arms** (88.6 % against 89.4 % and 86.8 %), so at 10 % Goal demos through this interface the latent
|
| 168 |
+
channel is **decorative**: the action head reads what it needs from the visual features alone. 13 episodes in 500 is
|
| 169 |
+
~1.3Ο, one seed each, and a single 500-episode cell carries **Β±8 points at 95 %** once training randomness is
|
| 170 |
+
counted β so these three are one band, not a ranking.
|
| 171 |
+
|
| 172 |
+
What the triplet *does* settle: an earlier 9.2 % collapse on Goal with the same latent and no query tokens was an
|
| 173 |
+
**interface** failure, not the latent. What it does not cover: regimes where the visual features are insufficient.
|
| 174 |
+
LIBERO-Long at 10 % is that regime (nothing saturates there: 60.6 % for the best arm) but with one replicate per arm
|
| 175 |
+
it still cannot separate 60.6 / 58.7 / 56.4. The place where a matched control *does* separate is the real robot:
|
| 176 |
+
`press_button_openvla_delta` is 2.1x worse than ours and cannot read the instruction at all.
|
| 177 |
+
|
| 178 |
+
Not published here: the full-split 20k-phase-2 Long arm (89.8 %, our best Long number) and the remaining 10 % Long
|
| 179 |
+
replicates live on a cluster filesystem, not on this host.
|
| 180 |
+
|
| 181 |
+
---
|
| 182 |
+
|
| 183 |
+
## `p2fft_20k` β the phase-2 base (not a deployable policy)
|
| 184 |
+
|
| 185 |
+
The **base** every TERRA policy above is post-trained from: OpenVLA-7B fully fine-tuned for 20,000 steps on OXE to
|
| 186 |
+
predict our continuous latent action (`latp2_inv`). `vla_full.pt` (15,081,838,026 B) is the VLA state dict, and
|
| 187 |
+
**`action_decoder.pt` (105,268,830 B) is required too** β `finetune_libero_ctrl.py:273` initialises the post-training
|
| 188 |
+
heads from it, so a run without it starts from a random head and will not reproduce these policies.
|
| 189 |
+
|
| 190 |
+
```bash
|
| 191 |
+
huggingface-cli download Potestates/TERRA --include "p2fft_20k/*" --local-dir .
|
| 192 |
+
INIT=./p2fft_20k ... bash acdc_la/scripts/run_vla_post2_portable.sh
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
The matched control is `INIT=none LATENT=none`, which post-trains the official `openvla/openvla-7b` with everything
|
| 196 |
+
else identical β that is how "what did phase 2 buy" is measured, and it is what the two `*_openvla_delta`
|
| 197 |
+
directories are.
|
| 198 |
+
|
| 199 |
+
---
|
| 200 |
+
|
| 201 |
+
## One metric trap, worth repeating
|
| 202 |
+
|
| 203 |
+
`action_l1_1step` in every `train_log.jsonl` is **oracle-conditioned**: `FlowHeads.loss` scores a one-step
|
| 204 |
+
correction from a point that already contains the ground truth. On the pick-can pair it ranks the two arms
|
| 205 |
+
**backwards** (TERRA 0.0563 vs control 0.0648, i.e. TERRA "13% better", while both free-running read-outs favour the
|
| 206 |
+
control). Use it to track a single run or pick a checkpoint within one run β **never to compare two arms.** Rank with
|
| 207 |
+
`--replay`.
|
| 208 |
+
|
| 209 |
+
`HANDOFF_press_button.md` at the root of this repo is the brief for training the next real-robot task on a fresh
|
| 210 |
+
host. The full experiment ledger, including everything retracted or superseded, is `LEDGER.md` in the code repo.
|