File size: 18,064 Bytes
804794f
 
 
 
 
 
 
 
1d5b722
804794f
ab00bc4
804794f
 
 
 
 
 
 
b7ab946
 
ab00bc4
 
 
7fb9a0d
ab00bc4
1d5b722
804794f
 
 
 
 
 
 
 
 
3970df9
804794f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b7ab946
 
 
 
 
 
 
 
 
 
 
 
 
 
804794f
 
 
 
 
 
 
 
 
 
 
3970df9
804794f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3970df9
804794f
 
 
 
 
 
 
 
 
 
 
 
 
ab00bc4
804794f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7fb9a0d
804794f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3970df9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804794f
 
 
 
 
 
 
b7ab946
 
 
 
 
804794f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b7ab946
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
---
pipeline_tag: robotics
tags:
- openvla
- vision-language-action
- robotics
- libero
---

# TERRA β€” post-trained policies (real robot + LIBERO)

OpenVLA-7B with TERRA latent-action phase 2 (`latp2_inv` labels), post-trained with a flow-matching action head and
4 query tokens. **One directory per policy**, each self-contained: merged weights (`model-*.safetensors`), the
action/latent head (`action_decoder.pt` β€” **required**, it is not inside the merged VLA weights),
`dataset_statistics.json` (action un-normalisation), `ctrl_meta.json`, processor/tokenizer, and its own `README.md`
with the measured numbers and the exact deployment loop.

**Code:** https://github.com/DingTianxingjian/Latent_Free β€” branch `newton`, public, no token needed.
Real-robot deployment wrapper: `acdc_la/realrobot/piper_policy.py`; LIBERO evaluator:
`acdc_la/downstream/vla/run_libero_eval_cont.py`.

```bash
git clone -b newton https://github.com/DingTianxingjian/Latent_Free.git latent_free && cd latent_free
huggingface-cli download Potestates/TERRA --include "<dir>/*" --local-dir .
```

---

## Which one do I test?

| I want to… | use | why |
|---|---|---|
| **press a coloured button** | **`press_button_terra_delta`** | the only policy **confirmed working on hardware** β€” it presses the requested button |
| **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 |
| 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 |
| **stack the bowls** | `piper_real3_anchored_fwd` | the only *policy* for this task; `stack_bowls_openvla_delta` is a **control**, and it ties "repeat the previous command" |
| **one model for both tasks** | `piper_multi_anchored_step5500` | **experimental**, and a retrain will supersede it β€” see its README |
| **compare the latent mechanism** in sim | the `libero_goal_frac10_*` **triplet** | ours / UniVLA's / **no latent at all**, identical otherwise |
| post-train a new task | `p2fft_20k` | the **base**, not a policy |

> ### ⚠ Two things that will break a deployment if you skip them
> 1. **Action space differs per directory.** `piper_pick_can_10k` emits **absolute** joint targets; everything with
>    `delta` in the name emits **target minus measured joint angle** and must be sent as `q + a[:6]` with `q` re-read
>    **every tick**; the `anchored` ones use `q` read **once per chunk** and a different call. Every `ctrl_meta.json`
>    now records `"action_space"` explicitly and `PiperPolicy` prints it on load β€” **check the printed line.**
> 2. **Execute 1 chunk entry, then re-predict** (all per-step `delta` policies). The demos were teleoperated as a
>    continuous 30 Hz command, so later chunk entries are mis-anchored for an arm that settles: drift is
>    **0.855 deg/step on pick-can** and **~2 deg/step on press_button**, and it is opposite-signed on the two joints
>    that carry the motion, so it **bends the direction** instead of just scaling it. This was seen on the robot:
>    chunk 1 presses the button, chunk 2 "the direction is a bit off". Use an `anchored` checkpoint if you need
>    multi-step chunks.

---

## The three action spaces on the Piper β€” getting this wrong drives the arm somewhere else

`ctrl_meta.json -> action_space` says which one a directory uses, `PiperPolicy` reads it and prints it on load.
(It used to be *absent* on the pick-can directories and inferred from the joint means; since 2026-11-12 all three
record it explicitly, so **a missing key now means an old copy** β€” re-download.)

| `action_space` | what `chunk[k]` is | the call | how many steps per chunk |
|---|---|---|---|
| `absolute` | the joint target itself | send `chunk[k]` directly | β€” |
| `delta` | target βˆ’ joints measured **at step k** | `to_joint_targets(a, q)`, `q` re-read **every tick** | **1** β€” the teleop lead adds up linearly and with opposite signs on j1/j2 (βˆ’0.74 / +0.75 deg per step on pick-can), so the direction bends |
| `delta_anchored` | `target[s+k]` βˆ’ joints read **once** at the chunk's start | `chunk_targets(chunk, q)`, `q` read once per chunk; **no ensembling** (the policy disables it) | 1, then try 2 and 4: tracking drift does not exist here, what limits N is the model's own error growing with k |

---

## Inventory β€” which directories are **ours (TERRA)** and which are **controls / baselines**

Every policy here shares the same interface (LoRA r32 + flow-matching head + 4 query tokens, chunk 12). What differs
is the **base** and the **latent channel**, which is exactly what each comparison is about.

### TERRA β€” ours (latent channel `tc_cont`, `latp2_inv` labels)

| dir | base | task / suite | number |
|---|---|---|---|
| `p2fft_20k` | openvla-7b, full fine-tune | **phase-2 base, not a policy** | β€” |
| `press_button_terra_delta` | `p2fft_20k` | press_button, per-step delta | 0.918Β° βœ… on hardware |
| **`piper_real3_anchored_fwd`** | `p2fft_20k` | **THE single robot model**: all 3 tasks (press_button x2 + pick-can + stack_bowls), **anchored**, fixed window | step 6000; `unnorm_key` **per task** β€” see its card |
| `press_button_anchored_fwd_step1500` | `p2fft_20k` | press_button, anchored, fixed window | 0.96Β° at k=0, flat in k |
| `piper_pick_can_terra_delta` | `p2fft_20k` | pick-can, per-step delta | 1.126Β° |
| `piper_pick_can_10k` | `p2fft_20k` | pick-can, **absolute** β€” superseded | 3.24Β° |
| `piper_multi_anchored_step2500` / `step5500` | `p2fft_20k` | both tasks, anchored β€” experimental | see card |
| `libero_goal_full` | LoRA-scale phase 2 | LIBERO-Goal, full split | 94.4 % |
| `libero_10_full` | LoRA-scale phase 2 | LIBERO-Long, full split | 89.0 % |
| `libero_10_frac10_terra_p2fft20k` | `p2fft_20k` | LIBERO-Long, 10 % (43 demos) | 60.6 % |
| `libero_goal_frac10_terra` | **openvla-7b, no phase 2** | LIBERO-Goal, 10 % | 86.8 % |

### Baselines / controls β€” no latent, or somebody else's latent

| dir | what it controls for | number |
|---|---|---|
| `press_button_openvla_delta` | stock openvla-7b, **`--latent none`** β€” the whole package vs nothing | 1.920Β° (worse than not moving) |
| `piper_pick_can_openvla_delta` | the same, on pick-can | **1.054Β°** β€” here it is a good policy |
| **`stack_bowls_openvla_delta`** | stock openvla-7b, **`--latent none`**, stack_bowls alone, per-step delta | **0.695Β°** β€” but *repeating the previous command* scores **0.667Β°** on the same episodes, so one step at a time it is **not distinguishable from doing the trivial thing** |
| `libero_goal_frac10_none` | **no latent at all**, identical otherwise (`latent_r2` ≑ 0) | 88.6 % |
| `libero_goal_frac10_univla_cont` | **UniVLA's** deployed latent through our interface | 89.4 % |

> **One honest caveat about the two `*_openvla_delta` controls.** They change the base **and** the latent branch at
> once (`INIT=none LATENT=none`), so where they separate, the effect belongs to *the whole package*, not specifically
> to the latent branch. The missing arm that would split those two β€” phase-2 base with `--latent none` β€” has not been
> run. The `libero_goal_frac10_*` triplet *is* clean in that sense (one factor, no phase 2 anywhere), and there the
> answer is that the latent channel changes nothing.
>
> **Which base a policy came from is not in most of these files.** `ctrl_meta.json` records the latent, the head
> and the dataset, but the training script never wrote the phase-2 init. The four directories published on
> 2026-11-12 (`libero_goal_frac10_*`, `libero_10_frac10_terra_p2fft20k`) now carry an explicit `"init"` field;
> for the others the base is stated in the table above and in each card, and nowhere in the weights.

---

## Real-robot policies β€” AgileX Piper

Open-loop error = mean |error| per joint in **degrees** on held-out episodes never trained on, chunk sampled from
noise through the deployment image path. Reproduce any row with
`envs/univla_vla/bin/python -m acdc_la.realrobot.piper_policy --checkpoint <dir> --replay <rlds root>` β€” it is
deterministic, and reproducing it is the check that your preprocessing matches ours.

### `press_button` β€” "press the {blue, orange, pink, red} button", 100 episodes, layout reshuffled per episode

| dir | base | action | `chunk[0]` | reads the instruction? | on the robot |
|---|---|---|---|---|---|
| **`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) |
| `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 |
| *null: "stay where you are"* | | | *1.691* | | |

The control is *worse than not moving*, and its invariance to language is **exact, not approximate**: its instruction
signal is 0.28% of the query-token state, which is below bfloat16 machine epsilon (7.8e-3), so it cannot survive its
own forward pass. With 4 colours and per-episode layouts a policy that cannot read the colour can only learn an
average press β€” which is what its j1/j2 error looks like. Caveats: **5 held-out episodes, 3 of 4 colours, one seed
per arm, offline**; and the pair changes *both* the base and the latent branch, so the effect cannot be attributed to
the latent branch alone.

### `piper_pick_can` β€” "pick up the can and place it on the plate", 150 episodes, **one** instruction throughout

| dir | base | action | `chunk[0]` | ensembled | note |
|---|---|---|---|---|---|
| **`piper_pick_can_openvla_delta`** | stock openvla-7b | delta | **1.054** | 0.914 | the matched control β€” and here a perfectly good policy |
| **`piper_pick_can_terra_delta`** | our phase 2 | delta | **1.126** | 0.950 | ours; **not separated** from the row above |
| `piper_pick_can_10k` | our phase 2 | **absolute** | 3.24 | 3.69 | the arm tested on the robot first; **superseded** by the two above |
| *null: "stay where you are"* | | | *1.20* | | |
| *null: repeat the last command* | | | *2.06* | | |
| *between-demonstration floor* | | | *0.61* | | **nothing can beat this** |

**Delta vs absolute is the real win here: 3.24 β†’ ~1.05 deg, 3x**, and it moves the policy from 2.7x *worse* than
doing nothing to better than it. **TERRA vs control is not a win for either side**: paired cluster bootstrap over the
8 held-out episodes (the independent unit β€” 353 steps is not the sample size) gives a difference of +0.072 deg,
95% CI **[-0.038, +0.189]**, sign test p = 0.727.

A null here is what the mechanism's own story predicts: **all 150 episodes carry the identical instruction**, so
there is nothing for a language-grounding advantage to do. The same pair separates 2.1x on `press_button`.

### `stack_bowls` β€” "stack the bowls", 100 episodes, **one** instruction throughout

| dir | base | latent | action | `chunk[0]` | ensembled |
|---|---|---|---|---|---|
| `stack_bowls_openvla_delta` | stock openvla-7b | **none** | per-step delta, single task | **0.695Β°** | 0.585Β° |
| `piper_real3_anchored_fwd` | `p2fft_20k` | `tc_cont` | **anchored**, 3-task mixture | not scored here | n/a (never ensemble anchored) |

**The floor on this task is 0.667Β°, not 0.** On the 5 held-out episodes (184 steps) *repeating the previous
command* scores **0.667Β°** and *not moving at all* **0.863Β°** β€” and the control's 0.695Β° is **not distinguishable**
from repeat-last (+0.031Β°, 95% paired cluster bootstrap over the 5 episodes **[-0.118, +0.184]**). Only temporal
ensembling beats it, by 0.079Β° [-0.147, -0.015], on an interval that one bad episode would swallow. Note the order
**flips** against pick-can, where stay-still (1.20Β°) was the easier null and repeat-last (2.06Β°) the harder: here the
motion is smooth and strongly drifting, so repeat-last is the one to beat.

**These two directories do not pair.** The control is `stack_bowls` **alone**, **per-step** delta, **backward**
sample window; `piper_real3_anchored_fwd` is a 350-episode **3-task mixture**, **chunk-anchored**, **forward**
window. Only the step count, LoRA, head, query tokens, rate and chunk match, so a difference between them cannot be
attributed to anything. Their `unnorm_key`s are also built from `anhdao69/data_real_4tasks`' episode order, which
differs from the control's, so **the held-out 5 episodes are probably not the same 5** β€” check the split first. The
control's per-step errors are in the code repo (`acdc_la/results/stack_bowls_openvla_delta_perstep.npz`) so a
properly matched TERRA arm can be compared **paired**. Neither has been on the robot.

### `piper_multi_anchored_step2500`, `piper_multi_anchored_step5500` β€” ⚠ experimental

One model for **both** tasks (press_button x2 + pick-can mixture), using **chunk-ANCHORED** deltas
(`target[s+k] - q[s]`, `q` read once per chunk) so that executing several entries open loop is valid. Better than the
per-step parameterisation from k>=2, slightly worse at k=0. Trained with the old backward sample window (magnitudes
under-predicted ~0.8x). **`press_button_anchored_fwd_step1500` is the first checkpoint with the window fixed**
(press-button only, snapshot of a run still training): its error stops growing with chunk position β€” it levels
off near 3.5Β° instead of climbing to 13Β° β€” and it will supersede these for that task. Measured on the 5 held-out
press_button episodes, mean error over the steps actually executed: **exec 2 / exec 4 = 1.50 / 2.28Β°** for the
window-fixed snapshot, 1.44 / 2.65Β° for `piper_multi_anchored_step5500` (old window), 1.66 / 3.50Β° for the
per-step `press_button_terra_delta` under ideal tracking. Both anchored models are **snapshots of runs still
training** (1500 of 3000, and step 5500) and **neither has been on the robot**. Different deployment call
(`chunk_targets`, no ensembling) β€” read their READMEs.

---

## LIBERO policies

Standard eval, 50 trials x 10 tasks = **500 episodes**, continuous flow head:

```bash
python -m acdc_la.downstream.vla.run_libero_eval_cont --pretrained_checkpoint <dir>
```

| dir | suite | demos | base | latent | success |
|---|---|---|---|---|---|
| `libero_goal_full` | Goal | full | LoRA-scale phase 2 | ours | **94.4 %** |
| `libero_10_full` | Long | full | LoRA-scale phase 2 | ours | **89.0 %** |
| `libero_10_frac10_terra_p2fft20k` | Long | 10 % (43) | **`p2fft_20k`** | ours | **60.6 %** |
| `libero_goal_frac10_univla_cont` | Goal | 10 % (43) | openvla-7b | **UniVLA's** | 89.4 % |
| `libero_goal_frac10_none` | Goal | 10 % (43) | openvla-7b | **none** | 88.6 % |
| `libero_goal_frac10_terra` | Goal | 10 % (43) | openvla-7b | ours | 86.8 % |

### The one result in this repo that is a clean, single-factor comparison β€” and it is negative

The three `libero_goal_frac10_*` rows differ **only** in the latent channel. The **no-latent control lands between
the two latent arms** (88.6 % against 89.4 % and 86.8 %), so at 10 % Goal demos through this interface the latent
channel is **decorative**: the action head reads what it needs from the visual features alone. 13 episodes in 500 is
~1.3Οƒ, one seed each, and a single 500-episode cell carries **Β±8 points at 95 %** once training randomness is
counted β€” so these three are one band, not a ranking.

What the triplet *does* settle: an earlier 9.2 % collapse on Goal with the same latent and no query tokens was an
**interface** failure, not the latent. What it does not cover: regimes where the visual features are insufficient.
LIBERO-Long at 10 % is that regime (nothing saturates there: 60.6 % for the best arm) but with one replicate per arm
it still cannot separate 60.6 / 58.7 / 56.4. The place where a matched control *does* separate is the real robot:
`press_button_openvla_delta` is 2.1x worse than ours and cannot read the instruction at all.

Not published here: the full-split 20k-phase-2 Long arm (89.8 %, our best Long number) and the remaining 10 % Long
replicates live on a cluster filesystem, not on this host.

---

## `p2fft_20k` β€” the phase-2 base (not a deployable policy)

The **base** every TERRA policy above is post-trained from: OpenVLA-7B fully fine-tuned for 20,000 steps on OXE to
predict our continuous latent action (`latp2_inv`). `vla_full.pt` (15,081,838,026 B) is the VLA state dict, and
**`action_decoder.pt` (105,268,830 B) is required too** β€” `finetune_libero_ctrl.py:273` initialises the post-training
heads from it, so a run without it starts from a random head and will not reproduce these policies.

```bash
huggingface-cli download Potestates/TERRA --include "p2fft_20k/*" --local-dir .
INIT=./p2fft_20k  ...  bash acdc_la/scripts/run_vla_post2_portable.sh
```

The matched control is `INIT=none LATENT=none`, which post-trains the official `openvla/openvla-7b` with everything
else identical β€” that is how "what did phase 2 buy" is measured, and it is what the two `*_openvla_delta`
directories are.

---

## One metric trap, worth repeating

`action_l1_1step` in every `train_log.jsonl` is **oracle-conditioned**: `FlowHeads.loss` scores a one-step
correction from a point that already contains the ground truth. On the pick-can pair it ranks the two arms
**backwards** (TERRA 0.0563 vs control 0.0648, i.e. TERRA "13% better", while both free-running read-outs favour the
control). Use it to track a single run or pick a checkpoint within one run β€” **never to compare two arms.** Rank with
`--replay`.

`HANDOFF_press_button.md` at the root of this repo is the brief for training the next real-robot task on a fresh
host. The full experiment ledger, including everything retracted or superseded, is `LEDGER.md` in the code repo.

---

*This card is version-controlled at `acdc_la/hf_cards/TERRA_root_README.md` in the code repo and is written
from both hosts. **Merge into it, do not overwrite it** β€” two hosts replaced each other's version of this file
on 2026-11-12 before anyone noticed.*