Spaces:
Running on Zero
Running on Zero
SyncWorld zero-shot robot simulator (ZeroGPU)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +19 -0
- README.md +73 -7
- app.py +656 -0
- assets/scenes/libero-black-bowl/calibration/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-black-bowl/calibration/pose.pkl +3 -0
- assets/scenes/libero-black-bowl/expert/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-black-bowl/expert/pose.pkl +3 -0
- assets/scenes/libero-black-bowl/thumb.jpg +0 -0
- assets/scenes/libero-bowl-plate/calibration/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-bowl-plate/calibration/pose.pkl +3 -0
- assets/scenes/libero-bowl-plate/expert/agentview_rgb/video.mp4 +0 -0
- assets/scenes/libero-bowl-plate/expert/pose.pkl +3 -0
- assets/scenes/libero-bowl-plate/thumb.jpg +0 -0
- assets/scenes/libero-drawer/calibration/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-drawer/calibration/pose.pkl +3 -0
- assets/scenes/libero-drawer/expert/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-drawer/expert/pose.pkl +3 -0
- assets/scenes/libero-drawer/thumb.jpg +0 -0
- assets/scenes/libero-soup/calibration/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-soup/calibration/pose.pkl +3 -0
- assets/scenes/libero-soup/expert/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-soup/expert/pose.pkl +3 -0
- assets/scenes/libero-soup/thumb.jpg +0 -0
- assets/scenes/libero-stove/calibration/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-stove/calibration/pose.pkl +3 -0
- assets/scenes/libero-stove/expert/agentview_rgb/video.mp4 +3 -0
- assets/scenes/libero-stove/expert/pose.pkl +3 -0
- assets/scenes/libero-stove/thumb.jpg +0 -0
- assets/scenes/peginsertion/calibration/pose.pkl +3 -0
- assets/scenes/peginsertion/calibration/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/peginsertion/expert/pose.pkl +3 -0
- assets/scenes/peginsertion/expert/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/peginsertion/thumb.jpg +0 -0
- assets/scenes/plugcharger/calibration/pose.pkl +3 -0
- assets/scenes/plugcharger/calibration/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/plugcharger/expert/pose.pkl +3 -0
- assets/scenes/plugcharger/expert/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/plugcharger/thumb.jpg +0 -0
- assets/scenes/pushcube/calibration/pose.pkl +3 -0
- assets/scenes/pushcube/calibration/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/pushcube/expert/pose.pkl +3 -0
- assets/scenes/pushcube/expert/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/pushcube/thumb.jpg +0 -0
- assets/scenes/scenes.json +72 -0
- assets/scenes/stackcube/calibration/pose.pkl +3 -0
- assets/scenes/stackcube/calibration/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/stackcube/expert/pose.pkl +3 -0
- assets/scenes/stackcube/expert/render_camera_rgb/video.mp4 +3 -0
- assets/scenes/stackcube/thumb.jpg +0 -0
- assets/scenes/stackpyramid/calibration/pose.pkl +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,22 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
assets/scenes/libero-black-bowl/calibration/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
assets/scenes/libero-black-bowl/expert/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
assets/scenes/libero-bowl-plate/calibration/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
assets/scenes/libero-drawer/calibration/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
assets/scenes/libero-drawer/expert/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
assets/scenes/libero-soup/calibration/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
assets/scenes/libero-soup/expert/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
assets/scenes/libero-stove/calibration/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
assets/scenes/libero-stove/expert/agentview_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
assets/scenes/peginsertion/calibration/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
assets/scenes/peginsertion/expert/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
assets/scenes/plugcharger/calibration/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
assets/scenes/plugcharger/expert/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
assets/scenes/pushcube/calibration/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
assets/scenes/pushcube/expert/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
assets/scenes/stackcube/calibration/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
assets/scenes/stackcube/expert/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
assets/scenes/stackpyramid/calibration/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
assets/scenes/stackpyramid/expert/render_camera_rgb/video.mp4 filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,13 +1,79 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 6.26.0
|
| 8 |
-
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: SyncWorld Simulator
|
| 3 |
+
emoji: 🦾
|
| 4 |
+
colorFrom: pink
|
| 5 |
+
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 6.26.0
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
+
short_description: Visually-calibrated zero-shot robot world simulator
|
| 10 |
+
python_version: "3.12"
|
| 11 |
+
startup_duration_timeout: 1h
|
| 12 |
+
models:
|
| 13 |
+
- yyuncong/SyncWorld
|
| 14 |
+
datasets:
|
| 15 |
+
- yyuncong/SyncWorld-Evaluation
|
| 16 |
---
|
| 17 |
|
| 18 |
+
# 🦾 SyncWorld — visual calibration turns a world model into a zero-shot simulator
|
| 19 |
+
|
| 20 |
+
Demo for **[SyncWorld: Visual Calibration Enables World Models as Zero-Shot Simulators](https://huggingface.co/papers/2609.09155)**
|
| 21 |
+
(UMass Embodied AGI) — [code](https://github.com/UMass-Embodied-AGI/SyncWorld) ·
|
| 22 |
+
[weights](https://huggingface.co/yyuncong/SyncWorld).
|
| 23 |
+
|
| 24 |
+
A pretrained action-conditioned video world model cannot be dropped into a new scene, because it
|
| 25 |
+
does not know how *this* camera sees *this* robot's action space. SyncWorld's fix is **visual
|
| 26 |
+
calibration**: prepend a short clip of the arm sweeping each degree of freedom, paired with the
|
| 27 |
+
actions that produced it, as extra fully-conditioning context. The model infers the unseen
|
| 28 |
+
camera↔robot mapping in-context and becomes a usable forward-dynamics simulator — with no
|
| 29 |
+
per-scene finetuning.
|
| 30 |
+
|
| 31 |
+
## What this Space does
|
| 32 |
+
|
| 33 |
+
Pick one of the authors' calibrated evaluation episodes, then either
|
| 34 |
+
|
| 35 |
+
- **replay the robot's own actions** — re-simulate the expert trajectory and compare against ground
|
| 36 |
+
truth, or
|
| 37 |
+
- **drive the arm yourself** — command a constant per-step end-effector twist
|
| 38 |
+
(Δx/Δy/Δz in cm/step, Δroll/Δpitch/Δyaw in °/step, plus the gripper) and watch the model render
|
| 39 |
+
a counterfactual rollout.
|
| 40 |
+
|
| 41 |
+
Each press generates one or more autoregressive 16-frame windows at 512 px, closed-loop (each
|
| 42 |
+
window conditions on the previously *generated* frames).
|
| 43 |
+
|
| 44 |
+
## Inference path
|
| 45 |
+
|
| 46 |
+
Ported 1:1 from the authors' reference script `examples/eval_gripperhead_fdm_rollout.py`, keeping
|
| 47 |
+
the trained recipe exactly:
|
| 48 |
+
|
| 49 |
+
| | |
|
| 50 |
+
|---|---|
|
| 51 |
+
| Conditioning items | `[6 per-DoF calibration segments × 5 frames] + [25 sparse history frames @ stride 3] + [current frame + 16 future frames]` |
|
| 52 |
+
| Actions | 7-D `[Δpos_cm(3), Δeuler_xyz_deg(3), gripper(1)]`, `backward_framewise` convention, translation scale 100.0, rotation scale 57.2958 |
|
| 53 |
+
| Resolution / fps | 512 px square, conditioning fps 15 |
|
| 54 |
+
| Sampler | rectified flow, UniPC, 20 steps (adjustable) |
|
| 55 |
+
| Caption | the FDM training constant `"A robot arm interacts with the scene."` |
|
| 56 |
+
| Backbone | 16B Cosmos-3 mixture-of-transformers (Qwen3-VL-8B understanding expert + diffusion expert), Wan2.2 4×16×16 video VAE |
|
| 57 |
+
|
| 58 |
+
Deviations forced by the target hardware: single-process inference (`parallel_dims=None`),
|
| 59 |
+
`torch.compile` disabled (ZeroGPU forks a fresh worker per call), the audio expert disabled
|
| 60 |
+
(unused by this checkpoint), and the VLM processor served from a local copy of the seven tokenizer
|
| 61 |
+
files in `nvidia/Cosmos3-Nano` instead of downloading that repo's 35 GB of weights.
|
| 62 |
+
|
| 63 |
+
## Bundled scenes
|
| 64 |
+
|
| 65 |
+
Ten episodes (5 ManiSkill + 5 LIBERO) copied verbatim from the authors' own evaluation set,
|
| 66 |
+
[`yyuncong/SyncWorld-Evaluation`](https://huggingface.co/datasets/yyuncong/SyncWorld-Evaluation),
|
| 67 |
+
each with its paired calibration sweep and pose track. Both the code and the data are released
|
| 68 |
+
under **OpenMDW-1.1**; see `ATTRIBUTIONS.md` / `NOTICE` in the upstream repo.
|
| 69 |
+
|
| 70 |
+
## Citation
|
| 71 |
+
|
| 72 |
+
```bibtex
|
| 73 |
+
@article{syncworld2026,
|
| 74 |
+
title = {SyncWorld: Visual Calibration Enables World Models as Zero-Shot Simulators},
|
| 75 |
+
author = {UMass Embodied AGI},
|
| 76 |
+
year = {2026},
|
| 77 |
+
url = {https://huggingface.co/papers/2609.09155}
|
| 78 |
+
}
|
| 79 |
+
```
|
app.py
ADDED
|
@@ -0,0 +1,656 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""SyncWorld — visual calibration turns a video world model into a zero-shot robot simulator.
|
| 2 |
+
|
| 3 |
+
Gradio / ZeroGPU demo for `yyuncong/SyncWorld` (paper 2609.09155, UMass Embodied AGI).
|
| 4 |
+
|
| 5 |
+
The inference path is ported 1:1 from the authors' reference script
|
| 6 |
+
`examples/eval_gripperhead_fdm_rollout.py` in
|
| 7 |
+
https://github.com/UMass-Embodied-AGI/SyncWorld — same config surgery, same
|
| 8 |
+
multi-item `[calib x 6] + [history] + [current+future]` batch, same sampler
|
| 9 |
+
call, same conditioning horizon (25 sparse history frames @ stride 3, 16
|
| 10 |
+
predicted frames, 512px, conditioning fps 15, 7-D `[dpos_cm, deuler_deg,
|
| 11 |
+
gripper]` actions in the `backward_framewise` convention).
|
| 12 |
+
"""
|
| 13 |
+
import os
|
| 14 |
+
import sys
|
| 15 |
+
|
| 16 |
+
os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
|
| 17 |
+
os.environ.setdefault("COSMOS_DEVICE", "cuda")
|
| 18 |
+
|
| 19 |
+
import spaces # noqa: F401 # MUST precede torch / any CUDA-touching import
|
| 20 |
+
|
| 21 |
+
from cosmos_framework.inference.common.init import init_script
|
| 22 |
+
|
| 23 |
+
init_script() # sets grad off, seeds, wires the cosmos logger (matches the reference script)
|
| 24 |
+
sys.excepthook = sys.__excepthook__ # undo init_script's distributed excepthook (Gradio needs the default)
|
| 25 |
+
|
| 26 |
+
import functools
|
| 27 |
+
import json
|
| 28 |
+
import math
|
| 29 |
+
import pickle
|
| 30 |
+
import shutil
|
| 31 |
+
import tempfile
|
| 32 |
+
import time
|
| 33 |
+
import types
|
| 34 |
+
from pathlib import Path
|
| 35 |
+
|
| 36 |
+
import gradio as gr
|
| 37 |
+
import imageio
|
| 38 |
+
import numpy as np
|
| 39 |
+
import torch
|
| 40 |
+
import torch.nn.functional as F
|
| 41 |
+
from huggingface_hub import hf_hub_download, snapshot_download
|
| 42 |
+
|
| 43 |
+
from cosmos_framework.configs.base.defaults.compile import CompileConfig
|
| 44 |
+
from cosmos_framework.data.vfm.action.calib_segments import build_calib_segment_indices
|
| 45 |
+
from cosmos_framework.data.vfm.action.datasets.gripperhead_fdm_dataset import NEUTRAL_CAPTION_SEED
|
| 46 |
+
from cosmos_framework.data.vfm.action.domain_utils import get_domain_id
|
| 47 |
+
from cosmos_framework.data.vfm.action.pose_utils import pose_abs_to_rel
|
| 48 |
+
from cosmos_framework.data.vfm.action.transforms import build_sequence_plan_from_mode
|
| 49 |
+
from cosmos_framework.inference.model import Cosmos3OmniConfig, Cosmos3OmniModel
|
| 50 |
+
from cosmos_framework.model.vfm.vlm.qwen3_vl.utils import tokenize_caption
|
| 51 |
+
|
| 52 |
+
HERE = Path(__file__).parent
|
| 53 |
+
DEVICE = "cuda"
|
| 54 |
+
OUT_DIR = Path(tempfile.gettempdir()) / "syncworld_out"
|
| 55 |
+
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
| 56 |
+
|
| 57 |
+
CKPT_REPO = "yyuncong/SyncWorld"
|
| 58 |
+
VAE_REPO = "Wan-AI/Wan2.2-TI2V-5B"
|
| 59 |
+
VAE_FILE = "Wan2.2_VAE.pth"
|
| 60 |
+
QWEN_REPO = "nvidia/Cosmos3-Nano"
|
| 61 |
+
# Only the processor / tokenizer artifacts at the repo root — NOT the 35GB of weights.
|
| 62 |
+
QWEN_FILES = [
|
| 63 |
+
"chat_template.json",
|
| 64 |
+
"merges.txt",
|
| 65 |
+
"preprocessor_config.json",
|
| 66 |
+
"tokenizer.json",
|
| 67 |
+
"tokenizer_config.json",
|
| 68 |
+
"video_preprocessor_config.json",
|
| 69 |
+
"vocab.json",
|
| 70 |
+
]
|
| 71 |
+
|
| 72 |
+
# ---------------------------------------------------------------- shipped recipe
|
| 73 |
+
# These are the trained checkpoint's conditioning + sampling defaults, i.e. the
|
| 74 |
+
# argparse defaults of the authors' eval script. They MUST match the checkpoint.
|
| 75 |
+
def _recipe(**over):
|
| 76 |
+
a = types.SimpleNamespace(
|
| 77 |
+
num_history_frames=25,
|
| 78 |
+
num_pred_frames=16,
|
| 79 |
+
history_frame_stride=3,
|
| 80 |
+
resolution=512,
|
| 81 |
+
fps=15.0,
|
| 82 |
+
use_calibration=True,
|
| 83 |
+
calib_null=False,
|
| 84 |
+
calib_segments=6,
|
| 85 |
+
calib_seg_len=5,
|
| 86 |
+
calib_frame_interval=3,
|
| 87 |
+
calib_positive_actions=False,
|
| 88 |
+
action_convention="backward_framewise",
|
| 89 |
+
action_rot_format="euler_xyz",
|
| 90 |
+
action_trans_scale=100.0,
|
| 91 |
+
action_rot_scale=57.2958,
|
| 92 |
+
action_cfg_scale=1.0,
|
| 93 |
+
num_steps=20,
|
| 94 |
+
seed=0,
|
| 95 |
+
)
|
| 96 |
+
for k, v in over.items():
|
| 97 |
+
setattr(a, k, v)
|
| 98 |
+
return a
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# ================================================================ model loading
|
| 102 |
+
# (ported from the reference script: _REWRITES / _config_from_dir /
|
| 103 |
+
# _patch_offline_vlm_processor / load_model)
|
| 104 |
+
_REWRITES = [
|
| 105 |
+
("cosmos3._src.vfm.configs.base.", "cosmos_framework.configs.base."),
|
| 106 |
+
("cosmos3._src.vfm.models.", "cosmos_framework.model.vfm."),
|
| 107 |
+
("cosmos3._src.vfm.tokenizers.", "cosmos_framework.model.vfm.tokenizers."),
|
| 108 |
+
("cosmos3._src.imaginaire.", "cosmos_framework."),
|
| 109 |
+
]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def _config_from_dir(d: Path, vae_path: str = "") -> Cosmos3OmniConfig:
|
| 113 |
+
cfg = d / "config.json" if (d / "config.json").exists() else d / "model" / "config.json"
|
| 114 |
+
if not cfg.exists():
|
| 115 |
+
raise FileNotFoundError(f"no config.json under {d}")
|
| 116 |
+
text = cfg.read_text()
|
| 117 |
+
for a, b in _REWRITES:
|
| 118 |
+
text = text.replace(a, b)
|
| 119 |
+
model_cfg = json.loads(text)["model"]
|
| 120 |
+
# The shipped config resolves the Wan2.2 video VAE through an object store
|
| 121 |
+
# (vae_path="pretrained/..." + bucket_name="bucket"). Point it at the local
|
| 122 |
+
# .pth and clear the bucket so loading is self-contained.
|
| 123 |
+
wan = (vae_path or "").strip()
|
| 124 |
+
if wan:
|
| 125 |
+
def _override_vae(o):
|
| 126 |
+
if isinstance(o, dict):
|
| 127 |
+
if "vae_path" in o: # the VIDEO tokenizer dict ("avae_path" is the audio one)
|
| 128 |
+
o["vae_path"] = wan
|
| 129 |
+
o["bucket_name"] = ""
|
| 130 |
+
for v in o.values():
|
| 131 |
+
_override_vae(v)
|
| 132 |
+
elif isinstance(o, list):
|
| 133 |
+
for v in o:
|
| 134 |
+
_override_vae(v)
|
| 135 |
+
_override_vae(model_cfg)
|
| 136 |
+
# Sound is DISABLED in the gripperhead FDM recipe, so the checkpoint has no
|
| 137 |
+
# sound expert; leaving sound_gen=True would make the build fetch an audio
|
| 138 |
+
# tokenizer that does not exist for this release.
|
| 139 |
+
if isinstance(model_cfg.get("config"), dict):
|
| 140 |
+
model_cfg["config"]["sound_gen"] = False
|
| 141 |
+
model_cfg["config"]["sound_tokenizer"] = None
|
| 142 |
+
return Cosmos3OmniConfig(model=model_cfg)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def _patch_offline_vlm_processor(qwen_assets: str):
|
| 146 |
+
"""Serve the VLM processor from a local dir instead of shelling out to `uvx hf download`
|
| 147 |
+
(which would pull the whole 35GB nvidia/Cosmos3-Nano repo)."""
|
| 148 |
+
import cosmos_framework.utils.checkpoint_db as _ckdb
|
| 149 |
+
|
| 150 |
+
_orig = _ckdb._hf_download
|
| 151 |
+
|
| 152 |
+
def _patched(cmd_args):
|
| 153 |
+
repo = str(cmd_args[0]) if cmd_args else ""
|
| 154 |
+
if "Cosmos3-Nano" in repo:
|
| 155 |
+
print(f"[boot] offline VLM processor: _hf_download({repo}) -> {qwen_assets}", flush=True)
|
| 156 |
+
return qwen_assets
|
| 157 |
+
return _orig(cmd_args)
|
| 158 |
+
|
| 159 |
+
_ckdb._hf_download = _patched
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def _load_model(checkpoint: str, vae_path: str, qwen_assets: str):
|
| 163 |
+
_patch_offline_vlm_processor(qwen_assets)
|
| 164 |
+
ckpt = Path(checkpoint)
|
| 165 |
+
wrapper = Cosmos3OmniModel.from_pretrained_dcp(
|
| 166 |
+
ckpt,
|
| 167 |
+
config=_config_from_dir(ckpt, vae_path),
|
| 168 |
+
compile_config=CompileConfig(enabled=False), # torch.compile is off: ZeroGPU forks a fresh worker
|
| 169 |
+
)
|
| 170 |
+
m = wrapper.model
|
| 171 |
+
# Single-process inference: null parallel_dims so every collective site takes
|
| 172 |
+
# its local no-op branch (the reference does the same for single-GPU eval).
|
| 173 |
+
if getattr(m, "parallel_dims", None) is not None:
|
| 174 |
+
m.parallel_dims = None
|
| 175 |
+
m.eval()
|
| 176 |
+
return m
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
# ================================================================ episode reading
|
| 180 |
+
# (ported: _read_video / _center_square_crop_np / _load_pose / _build_action /
|
| 181 |
+
# read_episode / _to_u8 / build_fdm_batch_multiitem / build_calib_eval_items /
|
| 182 |
+
# _gen_window)
|
| 183 |
+
def _read_video(path: str) -> np.ndarray:
|
| 184 |
+
import imageio.v3 as iio
|
| 185 |
+
|
| 186 |
+
try:
|
| 187 |
+
return iio.imread(path, plugin="pyav") # (T,H,W,C) uint8
|
| 188 |
+
except Exception:
|
| 189 |
+
return iio.imread(path)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
@functools.lru_cache(maxsize=4)
|
| 193 |
+
def _read_video_cached(path: str) -> np.ndarray:
|
| 194 |
+
return _read_video(path)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def _center_square_crop_np(a: np.ndarray) -> np.ndarray:
|
| 198 |
+
h, w = a.shape[1], a.shape[2]
|
| 199 |
+
if h == w:
|
| 200 |
+
return a
|
| 201 |
+
m = min(h, w)
|
| 202 |
+
top, left = (h - m) // 2, (w - m) // 2
|
| 203 |
+
return a[:, top:top + m, left:left + m]
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def _load_pose(leaf: str, thr: float = 0.6):
|
| 207 |
+
with open(os.path.join(leaf, "pose.pkl"), "rb") as f:
|
| 208 |
+
d = pickle.load(f)
|
| 209 |
+
mats = np.asarray(d["gripper_matrix"], dtype=np.float32) # (T,4,4)
|
| 210 |
+
gopen = np.asarray(d.get("gripper_open", np.ones(len(mats))), dtype=np.float32)
|
| 211 |
+
return mats, (gopen > thr).astype(np.float32)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def _build_action(mats, gopen, convention="backward_framewise", rot_format="euler_xyz",
|
| 215 |
+
trans_scale=100.0, rot_scale=57.2958) -> torch.Tensor:
|
| 216 |
+
"""abs poses -> per-step delta actions [dpos_cm(3), deuler_deg(3), gripper(1)]."""
|
| 217 |
+
poses_rel = pose_abs_to_rel(mats, rotation_format=rot_format, pose_convention=convention,
|
| 218 |
+
translation_scale=trans_scale, rotation_scale=rot_scale)
|
| 219 |
+
grip = gopen[1:].reshape(-1, 1)
|
| 220 |
+
return torch.from_numpy(np.concatenate([poses_rel, grip], axis=-1).astype(np.float32))
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def _frames_to_pm1(frames: np.ndarray, res: int) -> torch.Tensor:
|
| 224 |
+
v = torch.from_numpy(_center_square_crop_np(frames)).float().permute(0, 3, 1, 2) / 255.0
|
| 225 |
+
_, _, hh, ww = v.shape
|
| 226 |
+
th = res
|
| 227 |
+
tw = max(16, int(round((res * ww / hh) / 16) * 16)) # aspect preserving, /16 for the VAE
|
| 228 |
+
if (hh, ww) != (th, tw):
|
| 229 |
+
v = F.interpolate(v, size=(th, tw), mode="bilinear", align_corners=False)
|
| 230 |
+
return v * 2 - 1
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def read_episode(leaf: str, view: str, res: int):
|
| 234 |
+
frames = _read_video_cached(os.path.join(leaf, view, "video.mp4"))
|
| 235 |
+
v = _frames_to_pm1(frames, res)
|
| 236 |
+
mats, gopen = _load_pose(leaf)
|
| 237 |
+
n = min(len(v), len(mats))
|
| 238 |
+
# FDM training always emits NEUTRAL_CAPTION_SEED, so anything else is out of distribution.
|
| 239 |
+
return v[:n], mats[:n], gopen[:n], NEUTRAL_CAPTION_SEED
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
def _to_u8(x: torch.Tensor) -> torch.Tensor:
|
| 243 |
+
return ((x.clamp(-1, 1) + 1) / 2 * 255.0).round().clamp(0, 255).to(torch.uint8)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def build_fdm_batch_multiitem(model, video_u8_list, action_list, caption, device, fps=15.0,
|
| 247 |
+
mode: str = "forward_dynamics"):
|
| 248 |
+
"""N-item FDM batch: `[calib x K] + [history] + [current+future]`. Every item but the
|
| 249 |
+
last is fully conditioning; the last conditions on its current-frame latent and
|
| 250 |
+
generates the P future latents."""
|
| 251 |
+
maxD = model.config.max_action_dim
|
| 252 |
+
|
| 253 |
+
def pad(a):
|
| 254 |
+
p = torch.zeros(a.shape[0], maxD, device=device)
|
| 255 |
+
p[:, : a.shape[1]] = a.to(device)
|
| 256 |
+
return p
|
| 257 |
+
|
| 258 |
+
vids = [v.to(device) for v in video_u8_list]
|
| 259 |
+
acts = [pad(a) for a in action_list]
|
| 260 |
+
dims = [torch.tensor(int(a.shape[1]), dtype=torch.long, device=device) for a in action_list]
|
| 261 |
+
sizes = [torch.tensor([[v.shape[-2], v.shape[-1], v.shape[-2], v.shape[-1]]],
|
| 262 |
+
dtype=torch.float32, device=device) for v in vids]
|
| 263 |
+
cf = vids[-1]
|
| 264 |
+
sp = build_sequence_plan_from_mode(mode, video_length=cf.shape[1],
|
| 265 |
+
action_length=action_list[-1].shape[0], has_text=True,
|
| 266 |
+
num_condition_latent_frames=1)
|
| 267 |
+
sp.share_vision_temporal_positions = False # distinct time states per item — MUST match training
|
| 268 |
+
ids = tokenize_caption(caption, model.vlm_tokenizer, is_video=False,
|
| 269 |
+
use_system_prompt=model.vlm_config.use_system_prompt)
|
| 270 |
+
return {
|
| 271 |
+
model.input_video_key: [vids],
|
| 272 |
+
"action": [acts],
|
| 273 |
+
"raw_action_dim": [dims],
|
| 274 |
+
"image_size": [sizes],
|
| 275 |
+
"mode": [mode],
|
| 276 |
+
model.input_caption_key: [caption],
|
| 277 |
+
"text_token_ids": [torch.tensor(ids, dtype=torch.long, device=device).unsqueeze(0)],
|
| 278 |
+
"fps": torch.tensor([float(fps)], device=device),
|
| 279 |
+
"conditioning_fps": torch.tensor([float(fps)], device=device),
|
| 280 |
+
"domain_id": [torch.tensor(get_domain_id("gripperhead"), dtype=torch.long, device=device)],
|
| 281 |
+
"sequence_plan": [sp],
|
| 282 |
+
# NO is_preprocessed -> the uint8 items get normalized + re-stacked for the VAE
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def build_calib_items(calib_dir: str, args, view: str):
|
| 287 |
+
"""Load + per-DoF segment the calibration sweep into (K uint8 video items, K action blocks)."""
|
| 288 |
+
frames = _read_video_cached(os.path.join(calib_dir, view, "video.mp4"))
|
| 289 |
+
v = _frames_to_pm1(frames, args.resolution)
|
| 290 |
+
mats, gopen = _load_pose(calib_dir)
|
| 291 |
+
n = min(len(mats), len(v))
|
| 292 |
+
move_order = None
|
| 293 |
+
mrp = os.path.join(calib_dir, "move_range.pkl")
|
| 294 |
+
if os.path.isfile(mrp):
|
| 295 |
+
try:
|
| 296 |
+
with open(mrp, "rb") as f:
|
| 297 |
+
move_order = pickle.load(f).get("movement_order")
|
| 298 |
+
except Exception:
|
| 299 |
+
move_order = None
|
| 300 |
+
sub = list(range(0, n, args.calib_frame_interval)) or [0]
|
| 301 |
+
efficient = (args.calib_segments == 6) # 6 -> one segment per DoF; 12 -> both signs
|
| 302 |
+
seg_lists = build_calib_segment_indices(mats[sub], args.calib_seg_len, efficient, move_order,
|
| 303 |
+
positive_body_actions=bool(args.calib_positive_actions))
|
| 304 |
+
vids, acts = [], []
|
| 305 |
+
for seg in seg_lists:
|
| 306 |
+
real = [sub[i] for i in seg]
|
| 307 |
+
vids.append(_to_u8(v[real].permute(1, 0, 2, 3))) # (C,seg_len,H,W) uint8
|
| 308 |
+
acts.append(_build_action(mats[real], gopen[real], args.action_convention,
|
| 309 |
+
args.action_rot_format, args.action_trans_scale, args.action_rot_scale))
|
| 310 |
+
return vids, acts
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
def _gen_window(model, ep_frames, gen_frames, mats, gopen, caption, calib_v, calib_a,
|
| 314 |
+
start, args, device, custom_act=None):
|
| 315 |
+
"""Generate ONE 1+P frame window at frame `start`. Returns (pred_u8, gt_u8) as (P+1,H,W,C)."""
|
| 316 |
+
T = ep_frames.shape[0]
|
| 317 |
+
H, P, S = args.num_history_frames, args.num_pred_frames, args.history_frame_stride
|
| 318 |
+
clamp = lambda x: max(0, min(int(x), T - 1)) # noqa: E731
|
| 319 |
+
use_history, use_calib = H > 1, args.use_calibration
|
| 320 |
+
cf_idx = [clamp(start)] + [clamp(start + 1 + j) for j in range(P)]
|
| 321 |
+
cf_frames = torch.stack([gen_frames[clamp(start)]]
|
| 322 |
+
+ [ep_frames[clamp(start + 1 + j)] for j in range(P)], dim=1)
|
| 323 |
+
# custom-action mode: drive the window with a synthesized cm/deg action. The HISTORY
|
| 324 |
+
# action block stays real — it is observed context, not the commanded motion.
|
| 325 |
+
cf_act = (custom_act.to(torch.float32) if custom_act is not None else
|
| 326 |
+
_build_action(mats[cf_idx], gopen[cf_idx], args.action_convention,
|
| 327 |
+
args.action_rot_format, args.action_trans_scale, args.action_rot_scale))
|
| 328 |
+
items_v = list(calib_v) if use_calib else []
|
| 329 |
+
items_a = list(calib_a) if use_calib else []
|
| 330 |
+
if use_history:
|
| 331 |
+
hist_idx = [clamp(start - S * (H - i)) for i in range(H)]
|
| 332 |
+
hist_frames = torch.stack([gen_frames[i] for i in hist_idx], dim=1)
|
| 333 |
+
hist_act = _build_action(mats[hist_idx], gopen[hist_idx], args.action_convention,
|
| 334 |
+
args.action_rot_format, args.action_trans_scale, args.action_rot_scale)
|
| 335 |
+
items_v.append(_to_u8(hist_frames))
|
| 336 |
+
items_a.append(hist_act)
|
| 337 |
+
items_v.append(_to_u8(cf_frames))
|
| 338 |
+
items_a.append(cf_act)
|
| 339 |
+
batch = build_fdm_batch_multiitem(model, items_v, items_a, caption, device, fps=args.fps)
|
| 340 |
+
with torch.no_grad():
|
| 341 |
+
outputs = model.generate_samples_from_batch(
|
| 342 |
+
batch, guidance=1.0, action_guidance=args.action_cfg_scale,
|
| 343 |
+
seed=[args.seed], num_steps=args.num_steps)
|
| 344 |
+
dec = model.decode(outputs["vision"][0])[0].clamp(-1, 1) # (C,P+1,h,w)
|
| 345 |
+
pred_u8 = ((dec.float().permute(1, 2, 3, 0) + 1) / 2 * 255).round().clamp(0, 255).byte().cpu().numpy()
|
| 346 |
+
gt_win = torch.stack([ep_frames[clamp(start + i)] for i in range(P + 1)], dim=0)
|
| 347 |
+
gt_u8 = ((gt_win.float().permute(0, 2, 3, 1) + 1) / 2 * 255).round().clamp(0, 255).byte().cpu().numpy()
|
| 348 |
+
return pred_u8, gt_u8
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
# ================================================================ boot
|
| 352 |
+
_t = time.perf_counter()
|
| 353 |
+
print("[boot] fetching processor assets ...", flush=True)
|
| 354 |
+
QWEN_DIR = None
|
| 355 |
+
for _f in QWEN_FILES:
|
| 356 |
+
QWEN_DIR = os.path.dirname(hf_hub_download(QWEN_REPO, _f))
|
| 357 |
+
print(f"[boot] processor assets at {QWEN_DIR}", flush=True)
|
| 358 |
+
|
| 359 |
+
print("[boot] fetching Wan2.2 video VAE ...", flush=True)
|
| 360 |
+
VAE_PATH = hf_hub_download(VAE_REPO, VAE_FILE)
|
| 361 |
+
|
| 362 |
+
print(f"[boot] fetching {CKPT_REPO} (~31 GB) ...", flush=True)
|
| 363 |
+
CKPT_DIR = snapshot_download(CKPT_REPO)
|
| 364 |
+
print(f"[boot] checkpoint at {CKPT_DIR} ({time.perf_counter() - _t:.0f}s)", flush=True)
|
| 365 |
+
|
| 366 |
+
print("[boot] building + loading SyncWorld ...", flush=True)
|
| 367 |
+
MODEL = _load_model(CKPT_DIR, VAE_PATH, QWEN_DIR)
|
| 368 |
+
print(f"[boot] model ready ({time.perf_counter() - _t:.0f}s)", flush=True)
|
| 369 |
+
|
| 370 |
+
if not os.environ.get("SYNCWORLD_KEEP_CKPT"):
|
| 371 |
+
# The weights now live in (fake-)CUDA tensors that ZeroGPU packs to its own
|
| 372 |
+
# on-disk store; the 31 GB download is dead weight and would blow the Space's
|
| 373 |
+
# ephemeral disk once the pack copy lands.
|
| 374 |
+
try:
|
| 375 |
+
repo_root = Path(CKPT_DIR).parent.parent
|
| 376 |
+
if repo_root.name.startswith("models--"):
|
| 377 |
+
shutil.rmtree(repo_root, ignore_errors=True)
|
| 378 |
+
print(f"[boot] freed {repo_root}", flush=True)
|
| 379 |
+
except Exception as e: # pragma: no cover
|
| 380 |
+
print(f"[boot] WARN could not free checkpoint dir: {e!r}", flush=True)
|
| 381 |
+
|
| 382 |
+
# ================================================================ scenes
|
| 383 |
+
with open(HERE / "assets" / "scenes" / "scenes.json") as f:
|
| 384 |
+
SCENE_META = json.load(f)
|
| 385 |
+
SCENES = {}
|
| 386 |
+
for _slug, _m in SCENE_META.items():
|
| 387 |
+
_base = HERE / "assets" / "scenes" / _slug
|
| 388 |
+
SCENES[_m["label"]] = dict(
|
| 389 |
+
slug=_slug,
|
| 390 |
+
leaf=str(_base / "expert"),
|
| 391 |
+
calib=str(_base / "calibration"),
|
| 392 |
+
view=_m["view"],
|
| 393 |
+
num_frames=int(_m["num_frames"]),
|
| 394 |
+
thumb=str(_base / "thumb.jpg"),
|
| 395 |
+
expert_video=str(_base / "expert" / _m["view"] / "video.mp4"),
|
| 396 |
+
calib_video=str(_base / "calibration" / _m["view"] / "video.mp4"),
|
| 397 |
+
suite="ManiSkill" if _m["suite"].endswith("maniskill") else "LIBERO",
|
| 398 |
+
task=_m["task"],
|
| 399 |
+
)
|
| 400 |
+
SCENE_NAMES = sorted(SCENES)
|
| 401 |
+
MAX_FRAMES = max(v["num_frames"] for v in SCENES.values())
|
| 402 |
+
|
| 403 |
+
MODE_REPLAY = "Replay the robot's own actions"
|
| 404 |
+
MODE_DRIVE = "Drive the arm myself"
|
| 405 |
+
GRIP_KEEP, GRIP_OPEN, GRIP_CLOSE = "keep current", "open", "close"
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
def _write_mp4(frames_u8: np.ndarray, fps: int = 15) -> str:
|
| 409 |
+
d = tempfile.mkdtemp(dir=str(OUT_DIR))
|
| 410 |
+
p = os.path.join(d, "rollout.mp4")
|
| 411 |
+
imageio.mimwrite(p, list(frames_u8), fps=fps, macro_block_size=1, quality=9)
|
| 412 |
+
return p
|
| 413 |
+
|
| 414 |
+
|
| 415 |
+
def _estimate_duration(*a, **k):
|
| 416 |
+
"""ZeroGPU reservation: scales with rollout rounds x sampler steps."""
|
| 417 |
+
rounds = int(a[10]) if len(a) > 10 else 2
|
| 418 |
+
steps = int(a[11]) if len(a) > 11 else 20
|
| 419 |
+
return int(min(280, 45 + max(1, rounds) * (8 + max(1, steps) * 2.2)))
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
@spaces.GPU(duration=_estimate_duration)
|
| 423 |
+
def simulate(
|
| 424 |
+
scene: str,
|
| 425 |
+
action_mode: str = MODE_REPLAY,
|
| 426 |
+
start_frame: int = 0,
|
| 427 |
+
delta_x_cm: float = 0.0,
|
| 428 |
+
delta_y_cm: float = 0.0,
|
| 429 |
+
delta_z_cm: float = 0.0,
|
| 430 |
+
delta_rot_x_deg: float = 0.0,
|
| 431 |
+
delta_rot_y_deg: float = 0.0,
|
| 432 |
+
delta_rot_z_deg: float = 0.0,
|
| 433 |
+
gripper: str = GRIP_KEEP,
|
| 434 |
+
rollout_rounds: int = 2,
|
| 435 |
+
num_steps: int = 20,
|
| 436 |
+
action_guidance: float = 1.0,
|
| 437 |
+
seed: int = 0,
|
| 438 |
+
progress=gr.Progress(track_tqdm=True),
|
| 439 |
+
):
|
| 440 |
+
"""Roll out the SyncWorld world model on a visually-calibrated robot episode.
|
| 441 |
+
|
| 442 |
+
Args:
|
| 443 |
+
scene: name of a bundled calibrated episode (a ManiSkill or LIBERO tabletop scene).
|
| 444 |
+
action_mode: "Replay the robot's own actions" to re-simulate the expert trajectory,
|
| 445 |
+
or "Drive the arm myself" to command a constant per-step end-effector twist.
|
| 446 |
+
start_frame: index of the episode frame used as the current observation.
|
| 447 |
+
delta_x_cm: commanded per-step end-effector translation along body X, in centimetres.
|
| 448 |
+
delta_y_cm: commanded per-step end-effector translation along body Y, in centimetres.
|
| 449 |
+
delta_z_cm: commanded per-step end-effector translation along body Z, in centimetres.
|
| 450 |
+
delta_rot_x_deg: commanded per-step end-effector rotation about X, in degrees.
|
| 451 |
+
delta_rot_y_deg: commanded per-step end-effector rotation about Y, in degrees.
|
| 452 |
+
delta_rot_z_deg: commanded per-step end-effector rotation about Z, in degrees.
|
| 453 |
+
gripper: commanded gripper state ("keep current", "open" or "close").
|
| 454 |
+
rollout_rounds: number of autoregressive 16-frame windows to chain.
|
| 455 |
+
num_steps: rectified-flow sampler steps per window.
|
| 456 |
+
action_guidance: action classifier-free-guidance scale.
|
| 457 |
+
seed: sampler seed.
|
| 458 |
+
|
| 459 |
+
Returns:
|
| 460 |
+
A tuple of (predicted rollout mp4, ground-truth window mp4, markdown run report).
|
| 461 |
+
"""
|
| 462 |
+
t0 = time.perf_counter()
|
| 463 |
+
sc = SCENES.get(scene) or SCENES[SCENE_NAMES[0]]
|
| 464 |
+
args = _recipe(num_steps=int(num_steps), action_cfg_scale=float(action_guidance), seed=int(seed))
|
| 465 |
+
|
| 466 |
+
ep_frames, mats, gopen, caption = read_episode(sc["leaf"], sc["view"], args.resolution)
|
| 467 |
+
calib_v, calib_a = build_calib_items(sc["calib"], args, sc["view"])
|
| 468 |
+
t_prep = time.perf_counter() - t0
|
| 469 |
+
|
| 470 |
+
T = int(ep_frames.shape[0])
|
| 471 |
+
P = args.num_pred_frames
|
| 472 |
+
start = max(0, min(int(start_frame), T - 1))
|
| 473 |
+
rounds = max(1, min(int(rollout_rounds), 3))
|
| 474 |
+
drive = str(action_mode) == MODE_DRIVE
|
| 475 |
+
|
| 476 |
+
custom_row = None
|
| 477 |
+
if drive:
|
| 478 |
+
if gripper == GRIP_OPEN:
|
| 479 |
+
g = 1.0
|
| 480 |
+
elif gripper == GRIP_CLOSE:
|
| 481 |
+
g = 0.0
|
| 482 |
+
else:
|
| 483 |
+
g = float(gopen[start])
|
| 484 |
+
custom_row = torch.tensor(
|
| 485 |
+
[float(delta_x_cm), float(delta_y_cm), float(delta_z_cm),
|
| 486 |
+
float(delta_rot_x_deg), float(delta_rot_y_deg), float(delta_rot_z_deg), g],
|
| 487 |
+
dtype=torch.float32)
|
| 488 |
+
|
| 489 |
+
gen_frames = ep_frames.clone()
|
| 490 |
+
pred_acc, gt_acc = [], []
|
| 491 |
+
for r in range(rounds):
|
| 492 |
+
s = start + r * P
|
| 493 |
+
cact = custom_row.unsqueeze(0).repeat(P, 1) if custom_row is not None else None
|
| 494 |
+
pred_u8, gt_u8 = _gen_window(MODEL, ep_frames, gen_frames, mats, gopen, caption,
|
| 495 |
+
calib_v, calib_a, s, args, DEVICE, custom_act=cact)
|
| 496 |
+
if rounds > 1: # closed-loop write-back: the next round conditions on generated frames
|
| 497 |
+
for i in range(min(pred_u8.shape[0], gen_frames.shape[0] - s)):
|
| 498 |
+
fr = pred_u8[i].astype(np.float32) / 255.0 * 2.0 - 1.0
|
| 499 |
+
gen_frames[s + i] = torch.from_numpy(fr).permute(2, 0, 1).to(gen_frames)
|
| 500 |
+
skip = 0 if r == 0 else 1 # drop the 1-frame overlap between rounds
|
| 501 |
+
m = min(pred_u8.shape[0], gt_u8.shape[0])
|
| 502 |
+
pred_acc.extend(pred_u8[i] for i in range(skip, m))
|
| 503 |
+
gt_acc.extend(gt_u8[i] for i in range(skip, m))
|
| 504 |
+
|
| 505 |
+
pred = np.stack(pred_acc, 0)
|
| 506 |
+
gt = np.stack(gt_acc, 0)
|
| 507 |
+
pred_path = _write_mp4(pred)
|
| 508 |
+
gt_path = _write_mp4(gt)
|
| 509 |
+
dt = time.perf_counter() - t0
|
| 510 |
+
|
| 511 |
+
if drive:
|
| 512 |
+
act_desc = (f"commanded twist `Δpos = ({delta_x_cm:+.2f}, {delta_y_cm:+.2f}, "
|
| 513 |
+
f"{delta_z_cm:+.2f}) cm/step`, `Δrot = ({delta_rot_x_deg:+.2f}, "
|
| 514 |
+
f"{delta_rot_y_deg:+.2f}, {delta_rot_z_deg:+.2f}) deg/step`, gripper "
|
| 515 |
+
f"**{gripper}** — held for {rounds * P} steps")
|
| 516 |
+
else:
|
| 517 |
+
act_desc = f"the episode's own recorded actions for frames {start}…{min(start + rounds * P, T - 1)}"
|
| 518 |
+
report = (
|
| 519 |
+
f"**{sc['suite']} · `{sc['task']}`** · camera `{sc['view']}` · "
|
| 520 |
+
f"episode has {T} frames\n\n"
|
| 521 |
+
f"Conditioned on **6 per-DoF calibration segments** + **25 sparse history frames** "
|
| 522 |
+
f"(stride 3, from frame {max(0, start - 3 * 25)}) + current frame **{start}**.\n\n"
|
| 523 |
+
f"Action: {act_desc}.\n\n"
|
| 524 |
+
f"Generated **{len(pred)} frames** in {rounds} autoregressive window(s) × {args.num_steps} "
|
| 525 |
+
f"sampler steps · **{dt:.1f}s** total (scene prep {t_prep:.1f}s)."
|
| 526 |
+
)
|
| 527 |
+
return pred_path, gt_path, report
|
| 528 |
+
|
| 529 |
+
|
| 530 |
+
# ================================================================ UI
|
| 531 |
+
def _scene_preview(scene: str, start_frame: int):
|
| 532 |
+
sc = SCENES.get(scene) or SCENES[SCENE_NAMES[0]]
|
| 533 |
+
T = sc["num_frames"]
|
| 534 |
+
s = max(0, min(int(start_frame), T - 1))
|
| 535 |
+
try:
|
| 536 |
+
frame = _read_video_cached(sc["expert_video"])[s]
|
| 537 |
+
except Exception:
|
| 538 |
+
frame = None
|
| 539 |
+
info = (f"`{sc['suite']}` · `{sc['task']}` · camera `{sc['view']}` · **{T} frames** "
|
| 540 |
+
f"· current frame **{s}**")
|
| 541 |
+
return frame, sc["calib_video"], sc["expert_video"], info
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
THEME = gr.themes.Citrus()
|
| 545 |
+
|
| 546 |
+
DESC = """\
|
| 547 |
+
# 🦾 SyncWorld — a zero-shot robot simulator
|
| 548 |
+
|
| 549 |
+
[**SyncWorld**](https://huggingface.co/papers/2609.09155) shows that a pretrained video world model
|
| 550 |
+
becomes a usable robot simulator once you *visually calibrate* it: prepend a short clip of the arm
|
| 551 |
+
sweeping each degree of freedom, and the model infers the unseen camera↔robot mapping on the fly —
|
| 552 |
+
no per-scene finetuning.
|
| 553 |
+
|
| 554 |
+
Pick a calibrated scene, then either **replay the robot's own actions** or **drive the arm yourself**
|
| 555 |
+
with a per-step end-effector twist, and watch the model render what happens next.
|
| 556 |
+
|
| 557 |
+
*Model: [`yyuncong/SyncWorld`](https://huggingface.co/yyuncong/SyncWorld) (16B Cosmos-3 mixture-of-transformers,
|
| 558 |
+
Wan2.2 video VAE). Scenes and calibration clips are the authors' own evaluation episodes from
|
| 559 |
+
[`yyuncong/SyncWorld-Evaluation`](https://huggingface.co/datasets/yyuncong/SyncWorld-Evaluation) (OpenMDW-1.1).*
|
| 560 |
+
"""
|
| 561 |
+
|
| 562 |
+
with gr.Blocks(theme=THEME, title="SyncWorld — zero-shot robot simulator") as demo:
|
| 563 |
+
gr.Markdown(DESC)
|
| 564 |
+
|
| 565 |
+
with gr.Row():
|
| 566 |
+
with gr.Column(scale=5):
|
| 567 |
+
scene = gr.Dropdown(SCENE_NAMES, value=SCENE_NAMES[0], label="Calibrated scene")
|
| 568 |
+
info_md = gr.Markdown()
|
| 569 |
+
with gr.Row():
|
| 570 |
+
cur_img = gr.Image(label="Current frame (the model's last observation)",
|
| 571 |
+
height=232, interactive=False)
|
| 572 |
+
calib_vid = gr.Video(label="Calibration sweep (6 DoF)", height=232,
|
| 573 |
+
interactive=False, autoplay=True, loop=True)
|
| 574 |
+
start_frame = gr.Slider(0, MAX_FRAMES - 1, value=0, step=1,
|
| 575 |
+
label="Current frame index (clamped to the episode length)")
|
| 576 |
+
action_mode = gr.Radio([MODE_REPLAY, MODE_DRIVE], value=MODE_REPLAY, label="Actions")
|
| 577 |
+
with gr.Group():
|
| 578 |
+
gr.Markdown("**Commanded end-effector twist** — used in *Drive the arm myself* mode. "
|
| 579 |
+
"Held constant for every predicted step (the calibration sweeps cover "
|
| 580 |
+
"roughly ±3 cm/step and ±3 °/step).")
|
| 581 |
+
with gr.Row():
|
| 582 |
+
dx = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ X (cm/step)")
|
| 583 |
+
dy = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ Y (cm/step)")
|
| 584 |
+
dz = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ Z (cm/step)")
|
| 585 |
+
with gr.Row():
|
| 586 |
+
rx = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ rot X (°/step)")
|
| 587 |
+
ry = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ rot Y (°/step)")
|
| 588 |
+
rz = gr.Slider(-3.0, 3.0, value=0.0, step=0.05, label="Δ rot Z (°/step)")
|
| 589 |
+
gripper = gr.Radio([GRIP_KEEP, GRIP_OPEN, GRIP_CLOSE], value=GRIP_KEEP,
|
| 590 |
+
label="Gripper")
|
| 591 |
+
rollout_rounds = gr.Slider(1, 3, value=2, step=1,
|
| 592 |
+
label="Rollout windows (16 generated frames each)")
|
| 593 |
+
with gr.Accordion("Advanced", open=False):
|
| 594 |
+
num_steps = gr.Slider(4, 40, value=20, step=1, label="Sampler steps per window")
|
| 595 |
+
action_guidance = gr.Slider(1.0, 5.0, value=1.0, step=0.1,
|
| 596 |
+
label="Action guidance (CFG)")
|
| 597 |
+
seed = gr.Slider(0, 2**31 - 1, value=0, step=1, label="Seed")
|
| 598 |
+
run = gr.Button("Simulate", variant="primary")
|
| 599 |
+
|
| 600 |
+
with gr.Column(scale=5):
|
| 601 |
+
out_pred = gr.Video(label="SyncWorld rollout", autoplay=True, loop=True,
|
| 602 |
+
interactive=False, height=360)
|
| 603 |
+
out_gt = gr.Video(label="Ground truth for the same window (reference)",
|
| 604 |
+
autoplay=True, loop=True, interactive=False, height=240)
|
| 605 |
+
report_md = gr.Markdown()
|
| 606 |
+
|
| 607 |
+
with gr.Accordion("Full expert episode (reference)", open=False):
|
| 608 |
+
expert_vid = gr.Video(label="Expert demonstration", interactive=False, height=360)
|
| 609 |
+
|
| 610 |
+
INPUTS = [scene, action_mode, start_frame, dx, dy, dz, rx, ry, rz, gripper,
|
| 611 |
+
rollout_rounds, num_steps, action_guidance, seed]
|
| 612 |
+
OUTPUTS = [out_pred, out_gt, report_md]
|
| 613 |
+
|
| 614 |
+
# Every example row supplies the FULL input list. Gradio inserts its Progress
|
| 615 |
+
# object at the positional index of the `progress` parameter, so a short row
|
| 616 |
+
# would silently shift values into the wrong arguments.
|
| 617 |
+
EXAMPLES = [
|
| 618 |
+
# scene, mode, start, dx, dy, dz, rx, ry, rz, gripper, rounds, steps, cfg, seed
|
| 619 |
+
["ManiSkill · PushCube", MODE_REPLAY, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, GRIP_KEEP, 2, 20, 1.0, 0],
|
| 620 |
+
["LIBERO · put the bowl on the plate", MODE_REPLAY, 16, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, GRIP_KEEP, 2, 20, 1.0, 0],
|
| 621 |
+
["ManiSkill · StackCube", MODE_DRIVE, 32, 0.0, 1.2, 0.0, 0.0, 0.0, 0.0, GRIP_KEEP, 2, 20, 1.0, 0],
|
| 622 |
+
["ManiSkill · PushCube", MODE_DRIVE, 0, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, GRIP_KEEP, 2, 20, 1.0, 0],
|
| 623 |
+
["LIBERO · open the middle drawer", MODE_DRIVE, 24, 0.0, 0.0, -1.2, 0.0, 0.0, 0.0, GRIP_KEEP, 2, 20, 1.0, 0],
|
| 624 |
+
["LIBERO · alphabet soup into basket", MODE_DRIVE, 48, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, GRIP_CLOSE, 2, 20, 1.0, 0],
|
| 625 |
+
]
|
| 626 |
+
EXAMPLE_LABELS = [
|
| 627 |
+
"PushCube · replay the expert",
|
| 628 |
+
"LIBERO bowl→plate · replay the expert",
|
| 629 |
+
"StackCube · push +Y at 1.2 cm/step",
|
| 630 |
+
"PushCube · push +X at 1.5 cm/step",
|
| 631 |
+
"LIBERO drawer · pull −Z at 1.2 cm/step",
|
| 632 |
+
"LIBERO soup · close the gripper, hold still",
|
| 633 |
+
]
|
| 634 |
+
|
| 635 |
+
run.click(fn=simulate, inputs=INPUTS, outputs=OUTPUTS)
|
| 636 |
+
|
| 637 |
+
for _ev in (scene.change, start_frame.release):
|
| 638 |
+
_ev(fn=_scene_preview, inputs=[scene, start_frame],
|
| 639 |
+
outputs=[cur_img, calib_vid, expert_vid, info_md], show_progress="minimal")
|
| 640 |
+
|
| 641 |
+
gr.Examples(
|
| 642 |
+
examples=EXAMPLES,
|
| 643 |
+
example_labels=EXAMPLE_LABELS,
|
| 644 |
+
inputs=INPUTS,
|
| 645 |
+
outputs=OUTPUTS,
|
| 646 |
+
fn=simulate,
|
| 647 |
+
cache_examples=True,
|
| 648 |
+
cache_mode="lazy",
|
| 649 |
+
label="Examples",
|
| 650 |
+
)
|
| 651 |
+
|
| 652 |
+
demo.load(fn=_scene_preview, inputs=[scene, start_frame],
|
| 653 |
+
outputs=[cur_img, calib_vid, expert_vid, info_md])
|
| 654 |
+
|
| 655 |
+
if __name__ == "__main__":
|
| 656 |
+
demo.queue(max_size=12).launch(mcp_server=True, allowed_paths=[str(OUT_DIR), str(HERE / "assets")])
|
assets/scenes/libero-black-bowl/calibration/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4df8106071d26afbad4430d65b4a4ad87f036d25a19b9acd7c033f6c9db94b9b
|
| 3 |
+
size 130801
|
assets/scenes/libero-black-bowl/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f36ffe48457db0d8e3c8a7f98164b86e6ff04ddd09566b323967fd09dcc4d38c
|
| 3 |
+
size 33351
|
assets/scenes/libero-black-bowl/expert/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1fd11adb011caf6ecd364f3908fbedde20fac0973a66470ffda335dd39830dd7
|
| 3 |
+
size 147392
|
assets/scenes/libero-black-bowl/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c099ddae68aff7e093b72f7a2c8f31eeeb1e3fda88a176d50b4e2d7e8b880321
|
| 3 |
+
size 20164
|
assets/scenes/libero-black-bowl/thumb.jpg
ADDED
|
|
assets/scenes/libero-bowl-plate/calibration/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:df76bf0a3a6ea9c66884e93059338a39697d01b0381ff203bcefd267e2325f33
|
| 3 |
+
size 171469
|
assets/scenes/libero-bowl-plate/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a68fc4ce6960d7fb65192626ac2be4ad9426bf14ee188806c19057a43133c502
|
| 3 |
+
size 42567
|
assets/scenes/libero-bowl-plate/expert/agentview_rgb/video.mp4
ADDED
|
Binary file (97.7 kB). View file
|
|
|
assets/scenes/libero-bowl-plate/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:031a8f596b385be63492ac350721145051067df2d797333062ee9bd1bfc4cb35
|
| 3 |
+
size 11844
|
assets/scenes/libero-bowl-plate/thumb.jpg
ADDED
|
|
assets/scenes/libero-drawer/calibration/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c86ccd71e4cf1a410d7cd8e0defadc3b907ef64b42d60c4d40a7c3ca19a4756a
|
| 3 |
+
size 142168
|
assets/scenes/libero-drawer/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:df632260a5b759cf03f74c7f9604d869fb42627aa3ae010ccb67ff5aaf6f7ca5
|
| 3 |
+
size 34887
|
assets/scenes/libero-drawer/expert/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4d192f2e9079070ee653110ea023b74f8ccb2817b2ec65b334191fdbe5ececa5
|
| 3 |
+
size 142231
|
assets/scenes/libero-drawer/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aa11f6bdcceb3e83d6367738c1c08b123ffddccc9d1102fe5990ef08091af8b4
|
| 3 |
+
size 17988
|
assets/scenes/libero-drawer/thumb.jpg
ADDED
|
|
assets/scenes/libero-soup/calibration/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:99056f78f6dd0237eac3a61928dc7cc7538c64d010376c6740b9543a5d175231
|
| 3 |
+
size 199757
|
assets/scenes/libero-soup/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5e082d106c2b953cf904dff7909e11d6637f3dfcb7d87892f3d0927baac527a6
|
| 3 |
+
size 37959
|
assets/scenes/libero-soup/expert/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c6afa6a3984a1ecc4f2f409cc590d2e4b045f5bbc3f6f9c18602907eabc7d50e
|
| 3 |
+
size 158901
|
assets/scenes/libero-soup/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9a29645a254feda994d340368327851da72e0db55725803bd1f8031ce7028503
|
| 3 |
+
size 19268
|
assets/scenes/libero-soup/thumb.jpg
ADDED
|
|
assets/scenes/libero-stove/calibration/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e05506712a8c19a320c05d2b663e49a375f9f84bdeb35404130022b789cfd10b
|
| 3 |
+
size 178356
|
assets/scenes/libero-stove/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:551906131f26cb71feeeb75ac9caac4b0e5d6eb915228e61b65d6175dc41eb9b
|
| 3 |
+
size 35655
|
assets/scenes/libero-stove/expert/agentview_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ebd84ff43c9fd0a2c6968444e25dc1e6f21daf87d65a66ef6dc4fd446b90d041
|
| 3 |
+
size 299642
|
assets/scenes/libero-stove/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:432f2235bb96fc43306c83426be6d4a72fcce9a5273212f5a13044926104aea1
|
| 3 |
+
size 35143
|
assets/scenes/libero-stove/thumb.jpg
ADDED
|
|
assets/scenes/peginsertion/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b821226f7d54ce35d9c65e34ee3733e3b558c6d0b33ad3d820a84441b44eccc2
|
| 3 |
+
size 40263
|
assets/scenes/peginsertion/calibration/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ce685583a51a6ed10388767caa1194578ab91c8ba7564f59c66cd9f8a38643c7
|
| 3 |
+
size 401985
|
assets/scenes/peginsertion/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2f3dfb8b8fc36322257195fd800abd768cf954448ac9a961995cb3f87f3a3c35
|
| 3 |
+
size 23270
|
assets/scenes/peginsertion/expert/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:868e664dfdbb75df9d438c7eb9e0286c7e2b007b29224928b38a437f3c488d12
|
| 3 |
+
size 290856
|
assets/scenes/peginsertion/thumb.jpg
ADDED
|
|
assets/scenes/plugcharger/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b9b7a6ac349bff83a695e315bc02e662747d3fd96e2f65085396a0d1342754be
|
| 3 |
+
size 34887
|
assets/scenes/plugcharger/calibration/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:94cc01fd066e02b89376a7f71fc5fc25c5c09ce21116547610ed66740ab0967f
|
| 3 |
+
size 273092
|
assets/scenes/plugcharger/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2d35f4694d2270210e30323191372f10c3df808c4f5454ae63d796e850122b23
|
| 3 |
+
size 20454
|
assets/scenes/plugcharger/expert/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:94b64706f8606a3d31bcd7e34f55347a86c2a0e81c492d202224b8037bb7edf0
|
| 3 |
+
size 206705
|
assets/scenes/plugcharger/thumb.jpg
ADDED
|
|
assets/scenes/pushcube/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e150c2689746def363d24924317313239b155528148c5d212d475535d7a93b82
|
| 3 |
+
size 37959
|
assets/scenes/pushcube/calibration/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:74a428f128b46fadedd1327ea6c1882267f766520e7cdcdeb6fc00da0e9f9ce0
|
| 3 |
+
size 385927
|
assets/scenes/pushcube/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1feb82f1bf0301033fc5748f36a04023bea4119f4221165da87771dc11a19157
|
| 3 |
+
size 9574
|
assets/scenes/pushcube/expert/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:535f820fb0f05cc360e09bf46c8983868f28992521e4f4279ba7684f3aed88b7
|
| 3 |
+
size 168226
|
assets/scenes/pushcube/thumb.jpg
ADDED
|
|
assets/scenes/scenes.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"pushcube": {
|
| 3 |
+
"label": "ManiSkill \u00b7 PushCube",
|
| 4 |
+
"view": "render_camera_rgb",
|
| 5 |
+
"suite": "evaluation_maniskill",
|
| 6 |
+
"task": "PushCube-v1",
|
| 7 |
+
"num_frames": 72
|
| 8 |
+
},
|
| 9 |
+
"stackcube": {
|
| 10 |
+
"label": "ManiSkill \u00b7 StackCube",
|
| 11 |
+
"view": "render_camera_rgb",
|
| 12 |
+
"suite": "evaluation_maniskill",
|
| 13 |
+
"task": "StackCube-v1",
|
| 14 |
+
"num_frames": 108
|
| 15 |
+
},
|
| 16 |
+
"stackpyramid": {
|
| 17 |
+
"label": "ManiSkill \u00b7 StackPyramid",
|
| 18 |
+
"view": "render_camera_rgb",
|
| 19 |
+
"suite": "evaluation_maniskill",
|
| 20 |
+
"task": "StackPyramid-v1",
|
| 21 |
+
"num_frames": 177
|
| 22 |
+
},
|
| 23 |
+
"peginsertion": {
|
| 24 |
+
"label": "ManiSkill \u00b7 PegInsertionSide",
|
| 25 |
+
"view": "render_camera_rgb",
|
| 26 |
+
"suite": "evaluation_maniskill",
|
| 27 |
+
"task": "PegInsertionSide-v1",
|
| 28 |
+
"num_frames": 179
|
| 29 |
+
},
|
| 30 |
+
"plugcharger": {
|
| 31 |
+
"label": "ManiSkill \u00b7 PlugCharger",
|
| 32 |
+
"view": "render_camera_rgb",
|
| 33 |
+
"suite": "evaluation_maniskill",
|
| 34 |
+
"task": "PlugCharger-v1",
|
| 35 |
+
"num_frames": 157
|
| 36 |
+
},
|
| 37 |
+
"libero-bowl-plate": {
|
| 38 |
+
"label": "LIBERO \u00b7 put the bowl on the plate",
|
| 39 |
+
"view": "agentview_rgb",
|
| 40 |
+
"suite": "evaluation_libero",
|
| 41 |
+
"task": "put_the_bowl_on_the_plate",
|
| 42 |
+
"num_frames": 90
|
| 43 |
+
},
|
| 44 |
+
"libero-drawer": {
|
| 45 |
+
"label": "LIBERO \u00b7 open the middle drawer",
|
| 46 |
+
"view": "agentview_rgb",
|
| 47 |
+
"suite": "evaluation_libero",
|
| 48 |
+
"task": "open_the_middle_drawer_of_the_cabinet",
|
| 49 |
+
"num_frames": 138
|
| 50 |
+
},
|
| 51 |
+
"libero-soup": {
|
| 52 |
+
"label": "LIBERO \u00b7 alphabet soup into basket",
|
| 53 |
+
"view": "agentview_rgb",
|
| 54 |
+
"suite": "evaluation_libero",
|
| 55 |
+
"task": "pick_up_the_alphabet_soup_and_place_it_in_the_basket",
|
| 56 |
+
"num_frames": 148
|
| 57 |
+
},
|
| 58 |
+
"libero-black-bowl": {
|
| 59 |
+
"label": "LIBERO \u00b7 black bowl onto plate",
|
| 60 |
+
"view": "agentview_rgb",
|
| 61 |
+
"suite": "evaluation_libero",
|
| 62 |
+
"task": "pick_up_the_black_bowl_on_the_stove_and_place_it_on_the_plate",
|
| 63 |
+
"num_frames": 155
|
| 64 |
+
},
|
| 65 |
+
"libero-stove": {
|
| 66 |
+
"label": "LIBERO \u00b7 stove + moka pot",
|
| 67 |
+
"view": "agentview_rgb",
|
| 68 |
+
"suite": "evaluation_libero",
|
| 69 |
+
"task": "KITCHEN_SCENE3_turn_on_the_stove_and_put_the_moka_pot_on_it",
|
| 70 |
+
"num_frames": 272
|
| 71 |
+
}
|
| 72 |
+
}
|
assets/scenes/stackcube/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7788b705707d9566bed30098bc22c7ae9c59301da54bce0a5270b35fb12a8864
|
| 3 |
+
size 46407
|
assets/scenes/stackcube/calibration/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:dcabdaf8a0af444fc1dbca7ee60a435fcdb23202636962db976ca8ed92a42440
|
| 3 |
+
size 468760
|
assets/scenes/stackcube/expert/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0dc2b5f9e732b1f090e6a815f86582dcf7cba27feaa8c9124f0ac598cae69ab1
|
| 3 |
+
size 14182
|
assets/scenes/stackcube/expert/render_camera_rgb/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1ebf6d49490eb59a8d161be2f0c12f36202297cfee95b7f9f97da45e2ad19107
|
| 3 |
+
size 192343
|
assets/scenes/stackcube/thumb.jpg
ADDED
|
|
assets/scenes/stackpyramid/calibration/pose.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:393a570213981f6377fe153917d39b3ee3db73b7208a4c5bdcdf23d527b34359
|
| 3 |
+
size 37959
|