Skip to content

Commit 91e58a6

Browse files
committed
docs(libero): LIBERO + LIBERO-plus integration page
Run commands (passthrough/parity/asset-audit/metasim-migration/OSC/policy), side-by-side native-vs-MetaSim videos (kinematic + dynamics), demo-replay parity tables + charts, OSC bitwise torque parity, policy robustness, and the details (config bootstrap, EGL global-context, perturbation encoding, MJB lossless, sticky-ori OSC, sm_120 split). Wired into the integrations toctree.
1 parent 1b26f32 commit 91e58a6

4 files changed

Lines changed: 211 additions & 0 deletions

File tree

36.1 KB
Loading
27.4 KB
Loading
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# LIBERO + LIBERO-plus → RoboVerse 1:1 integration
2+
3+
[LIBERO](https://github.com/Lifelong-Robot-Learning/LIBERO) (*Lifelong Robot
4+
Learning*, Liu et al. 2023) is a 130-task manipulation benchmark of robosuite /
5+
MuJoCo environments across five suites (`libero_spatial`, `libero_object`,
6+
`libero_goal`, `libero_10`, `libero_90`).
7+
[LIBERO-plus](https://github.com/sylvestf/LIBERO-plus) (*In-depth Robustness
8+
Analysis of VLA Models*, 2025) is a drop-in superset that expands every suite
9+
with thousands of **perturbation** variants — **10,120 tasks** across seven
10+
dimensions (object layout, camera viewpoint, robot init state, language rewrite,
11+
lighting, background texture, sensor noise).
12+
13+
RoboVerse integrates both as **passthrough** task packs: registration is lazy
14+
and import-safe, and the env is the *native* LIBERO(-plus) `OffScreenRenderEnv`,
15+
so observations / dynamics / 128×128 camera bytes are **bitwise-identical** to
16+
upstream. On top of that we verify a **pure-MetaSim native reproduction** (load
17+
the scene into MetaSim's own MuJoCo handler) and a **bitwise OSC_POSE controller
18+
port** so LIBERO EE-delta policies can run *inside* MetaSim.
19+
20+
## Status
21+
22+
| Capability | Result | Where |
23+
|---|---|---|
24+
| LIBERO passthrough | **130 / 130** tasks, obs+step bitwise (Δ=0) | `roboverse_pack/tasks/libero/` |
25+
| LIBERO-plus passthrough | **10,120 / 10,120** tasks, state/reward/done bitwise (Δ=0) | `roboverse_pack/tasks/libero_plus/` |
26+
| demo-replay parity | passthrough == native, Δ=0 (380 demos) | `scripts/parity_liberoplus_passthrough.py` |
27+
| asset audit | 7/7 perturbation dims genuinely applied, **0 silent fallback** | `scripts/audit_liberoplus_assets.py` |
28+
| MetaSim MuJoCo migration | 6/6 dims: state-set Δ=0, **engine Δ=0** | `scripts/migrate_liberoplus_metasim.py` |
29+
| OSC_POSE port | **bitwise** — per-state joint-torque Δ = 5.55e-15 N·m | `scripts/osc/` |
30+
| BC policy (closed-loop) | clean 100 % / light 0 % / camera 50 % / noise 75 %; passthrough==native Δ=0 | `scripts/policy/` |
31+
32+
MetaSim core changes: **0** (the passthrough reuses the unmodified upstream env;
33+
the MetaSim handler loads the scene MJCF verbatim).
34+
35+
## Environment setup
36+
37+
LIBERO pins `numpy<1.24` / `robosuite==1.4.0` / `bddl==1.0.1` / `mujoco==3.2.3`,
38+
which conflict with the default RoboVerse env — so install each in a **dedicated**
39+
conda env. The passthrough is a safe no-op in any env where LIBERO is not
40+
importable (registration registers nothing; the factory raises a clear error).
41+
42+
```bash
43+
# base LIBERO (130 tasks)
44+
conda create -n libero1to1 python=3.8 -y && conda activate libero1to1
45+
git clone https://github.com/Lifelong-Robot-Learning/LIBERO.git && pip install -e LIBERO
46+
47+
# LIBERO-plus (10,120 tasks) — a separate env; it is a drop-in replacement of LIBERO
48+
conda create -n liberoplus python=3.8 -y && conda activate liberoplus
49+
git clone https://github.com/sylvestf/LIBERO-plus.git && pip install -e LIBERO-plus
50+
# + extract the LIBERO-plus asset bundle (6 GB) into libero/libero/assets
51+
```
52+
53+
The LIBERO-plus passthrough **self-bootstraps** its config: it writes
54+
`~/.libero_plus/config.yaml` pointing at the installed LIBERO-plus package's
55+
bddl / asset / init roots and sets `LIBERO_CONFIG_PATH` (never clobbering a
56+
user-set value or the base `~/.libero`). No manual config editing needed.
57+
58+
## Usage
59+
60+
```python
61+
import roboverse_pack.tasks.libero # auto-registers Libero/<suite>__<task>
62+
import roboverse_pack.tasks.libero_plus # auto-registers LiberoPlus/<suite>__<task>
63+
from roboverse_pack.tasks.libero_plus import make_liberoplus_env
64+
65+
# build any of the 10,120 perturbation tasks by (suite, task index)
66+
env = make_liberoplus_env("libero_object", 7, seed=0)
67+
obs, reward, done, info = env.step([0.0] * 7) # native legacy-gym 4-tuple (kept for fidelity)
68+
```
69+
70+
## Reproduce — run commands
71+
72+
All commands assume `MUJOCO_GL=egl` (headless) and the dedicated env. The
73+
LIBERO-plus runs additionally take `LIBERO_CONFIG_PATH=$HOME/.libero_plus`.
74+
75+
```bash
76+
# --- passthrough bitwise tests (per env) ---
77+
MUJOCO_GL=egl python -m pytest tests/test_libero_passthrough.py -v # in libero1to1
78+
MUJOCO_GL=egl python -m pytest tests/test_liberoplus_passthrough.py -v # in liberoplus
79+
80+
# --- LIBERO-plus passthrough == native, all 7 perturbation dimensions ---
81+
LIBERO_CONFIG_PATH=$HOME/.libero_plus MUJOCO_GL=egl \
82+
python -m scripts.parity_liberoplus_passthrough --per-dim 1 --steps 8
83+
84+
# --- asset audit: prove every perturbation actually changes the render ---
85+
LIBERO_CONFIG_PATH=$HOME/.libero_plus MUJOCO_GL=egl \
86+
python -m scripts.audit_liberoplus_assets --suites libero_spatial libero_object libero_goal libero_10
87+
88+
# --- migrate the scene into MetaSim's own MuJoCo backend (state + engine 1:1) ---
89+
LIBERO_CONFIG_PATH=$HOME/.libero_plus MUJOCO_GL=egl \
90+
python -m scripts.migrate_liberoplus_metasim --suite libero_spatial
91+
92+
# --- OSC_POSE controller bitwise parity vs robosuite (for in-MetaSim control) ---
93+
LIBERO_CONFIG_PATH=$HOME/.libero_plus MUJOCO_GL=egl \
94+
python -m scripts.osc.parity_osc_vs_robosuite --steps 130 --precontact 40
95+
96+
# --- closed-loop BC policy: train (GPU env) then eval through the passthrough (CPU) ---
97+
python -m scripts.policy.train_bc_libero \
98+
--demos third_party/libero_datasets/libero_object/<task>_demo.hdf5 --epochs 100 \
99+
--out scripts/policy/ckpt/bc.pt
100+
LIBERO_CONFIG_PATH=$HOME/.libero_plus MUJOCO_GL=egl \
101+
python -m scripts.policy.eval_bc_liberoplus --ckpt scripts/policy/ckpt/bc.pt \
102+
--base <task> --suite libero_object --episodes 8
103+
```
104+
105+
## Side-by-side: native LIBERO vs MetaSim
106+
107+
Beyond "passthrough == native by construction", we load each task's own combined
108+
MJCF (Franka + objects + arena + camera) into **MetaSim's MuJoCo handler** and
109+
reproduce the demo — proving the MetaSim backend simulates the LIBERO scene 1:1.
110+
111+
**Stage 1 — kinematics** (per-frame `set_states`, geometry/pose 1:1):
112+
113+
<video controls width="640" src="../../_static/integrations/libero/sidebyside_kinematic_spatial_task0.mp4"></video>
114+
115+
**Stage 2 — dynamics** (MetaSim's engine steps under the captured ctrl):
116+
117+
<video controls width="640" src="../../_static/integrations/libero/sidebyside_dynamics_spatial_task0.mp4"></video>
118+
119+
Left = native LIBERO `agentview_rgb`, right = MetaSim render. Per-frame
120+
`max|qpos − recorded| = 0.0` (exact); the MetaSim engine step matches reference
121+
MuJoCo to `max|Δ| = 1.6e-4` (float accumulation). Residual pixel MAE ≈ 2.5–5/255
122+
is renderer config (lighting / anti-aliasing), not physics.
123+
124+
### Demo-replay parity (all 5 suites)
125+
126+
![replay parity](../../_static/integrations/libero/chart_replay_parity.png)
127+
![per-suite](../../_static/integrations/libero/chart_suites.png)
128+
129+
| suite | tasks | demos | pt-vs-native max\|Δ\| | success (pt / native) |
130+
|---|---|---|---|---|
131+
| libero_spatial | 10 | 50 | **0** | 41/50 · 41/50 |
132+
| libero_object | 10 | 50 | **0** | 43/50 · 43/50 |
133+
| libero_goal | 10 | 50 | **0** | 40/50 · 40/50 |
134+
| libero_10 | 10 | 50 | **0** | 37/50 · 37/50 |
135+
| libero_90 | 90 | 180 | **0** | 154/180 · 154/180 |
136+
137+
The load-bearing number is **passthrough-vs-native = 0** (bitwise across all
138+
380 demos). The ~65 non-successful replays diverge *identically* on both backends
139+
(LIBERO's intrinsic open-loop OSC_POSE replay non-determinism, not a RoboVerse gap).
140+
141+
### OSC_POSE controller parity
142+
143+
`scripts/osc/parity_osc_vs_robosuite.py` reports:
144+
145+
```
146+
(A) per-step torque parity at every real state incl. contact (130 states):
147+
joint-torque max|Δ| = 5.55e-15 N·m <- bitwise control-law faithfulness
148+
(B) pre-contact open-loop rollout on MJB-exact model (40 steps):
149+
arm-qpos max|Δ| = 1.25e-05 rad
150+
```
151+
152+
The ported `MujocoOSCPose` reuses robosuite's `control_utils` / `transform_utils`
153+
math verbatim, reimplementing only the sim-data access (`mj_fullM`, `mj_jacSite`,
154+
EE pose/vel, `qfrc_bias`) on MetaSim's dm_control `Physics`. It emits joint
155+
torques into the existing `dof_torque` path → additive, opt-in, zero blast radius.
156+
157+
### Real policy robustness (closed-loop, via the passthrough)
158+
159+
An ACT-style BC policy trained on **clean** `libero_object` demos, evaluated
160+
closed-loop on LIBERO-plus perturbations — exactly the robustness signal the
161+
benchmark measures:
162+
163+
| variant | clean | light | sensor-noise | camera |
164+
|---|---|---|---|---|
165+
| success | **8/8 = 1.00** | 0/8 | 6/8 | 4/8 |
166+
167+
`passthrough == native` under the policy: full-rollout state max\|Δ\| = **0**.
168+
169+
## Details and gotchas
170+
171+
- **Config bootstrap.** LIBERO-plus reads bddl/asset/init roots from
172+
`$LIBERO_CONFIG_PATH/config.yaml` (default `~/.libero`). Because base LIBERO and
173+
LIBERO-plus share the package name, the passthrough self-writes a dedicated
174+
`~/.libero_plus` config from the *installed* LIBERO-plus package so the 10k
175+
perturbation tasks resolve, without touching the base config.
176+
- **Perturbation encoding.** File-based dims (background texture `_table_N`,
177+
lighting `_light_N`, layout `_add_N`) are real BDDL files; parametric dims
178+
(camera `_view_…`, robot init `_initstate_…`, language `_language_N`, noise
179+
`_noise_N`) are synthetic descriptors that the env wrapper parses to apply the
180+
perturbation — so the passthrough must **not** `os.path.isfile` them; it uses
181+
the benchmark's authoritative `get_task_bddl_file_path`.
182+
- **Global EGL render context.** robosuite/MuJoCo share a process-global EGL
183+
context — two `OffScreenRenderEnv` alive at once clobber each other's GL
184+
textures, so a texture-only perturbation reads as "0 effect". **Render one env
185+
at a time** (build → render → close). This is required for any side-by-side or
186+
batched rendering, and is why the asset audit / parity harnesses are sequential.
187+
- **Sensor-noise is upstream-stochastic.** Noise (motion/gaussian/fog/glass blur)
188+
is added to `agentview_image` *after* render with an unseeded `np.random` — the
189+
physics/state/reward/done are unaffected (bitwise); only the corrupted image
190+
differs across interleaved runs. It reproduces when each env runs in isolation.
191+
- **Lossless model transfer.** `env.sim.model.get_xml()` → reload is lossy on
192+
mesh inertias; the binary `mujoco.mj_saveModel` / `from_binary_path` (MJB) path
193+
is lossless (inertials Δ=0) — use MJB when an exact MetaSim model is required.
194+
- **OSC sticky orientation goal.** robosuite only updates `goal_ori` when the
195+
orientation delta is non-zero (a *sticky* goal); the port must match this or it
196+
drifts under near-zero wrist deltas. With the fix the control law is bitwise.
197+
- **GPU split (sm_120).** The LIBERO sim env pins py3.8 / torch 2.4.1, which can't
198+
use an sm_120 GPU (RTX 5090). Train policies in an sm_120-capable env (torch
199+
≥2.7 / cu128) and run closed-loop eval with CPU inference in the sim env, or via
200+
a small sim↔policy socket bridge (`scripts/policy/bridge_*`).
201+
202+
## Scope notes (honest)
203+
204+
- The passthrough is **MuJoCo-only by design**: LIBERO is a robosuite/MuJoCo
205+
benchmark; porting its MJCF to SAPIEN/Newton needs asset re-authoring + a
206+
different contact model = an approximate cross-sim port, not 1:1.
207+
- The BC policy is a compact single-task demonstration (pipeline + robustness +
208+
passthrough==native), not a SOTA reproduction. The official
209+
`Sylvest/openvla-7b-oft-finetuned-libero-plus` checkpoint runs through the same
210+
bridge for absolute benchmark numbers.

docs/source/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Scenes <dataset_benchmark/dataset/scenes>
150150
Benchmark Overview <dataset_benchmark/benchmark/overview>
151151
Benchmark Results <dataset_benchmark/benchmark/results>
152152
Benchmark Usage <dataset_benchmark/benchmark/usage>
153+
LIBERO + LIBERO-plus Integration <dataset_benchmark/integrations/libero>
153154
ManiSkill Integration <dataset_benchmark/integrations/maniskill>
154155
mjlab Integration <dataset_benchmark/integrations/mjlab>
155156
RoboTwin Integration <dataset_benchmark/integrations/robotwin>

0 commit comments

Comments
 (0)