LeRobot入门教程 09:LeRobot 仿真 (LIBERO)

目录:00_LeRobot入门教程_目录.md

1. LIBERO 是什么

LIBERO 是机器人操作领域常用的仿真基准。它在 MuJoCo(通过 robosuite)里搭出厨房桌面场景,让 Franka Panda 机械臂完成「把白色马克杯放到左边盘子」这类操作,并配好了 40 条语言指令和对应的专家演示。

好处是:不用真机、不用机械臂、不用摄像头,一台带 GPU 的服务器就能把整条链路跑通。

2. 四个 suite

LIBERO 按难度分四个 suite,LiberoEnv(task=...) 里的 task 就是选 suite:

suite任务特点单条 episode 最长步数
libero_spatial空间关系:同样的物体,换位置280
libero_object物体泛化:换物体种类280
libero_goal目标泛化:换目标状态300
libero_10长程任务,10 步以上组合520

每个 suite 有 10 个任务(task_ids 就是选其中几个)。步数上限决定了跑一次评测最长要多久。

3. 手工搭一个环境

下面这段就是「用代码而不是命令行」建环境的写法,适合调试时看清每一步。

import numpy as np
from lerobot.envs import make_env
from lerobot.envs.configs import LiberoEnv

env_cfg = LiberoEnv(task="libero_spatial", task_ids=[0], observation_height=256, observation_width=256)
env = list(list(make_env(env_cfg, n_envs=1).values())[0].values())[0]
obs, info = env.reset()
print({k: getattr(v, "shape", None) for k, v in obs["pixels"].items()})

stderr:

[robosuite WARNING] No private macro file found! (__init__.py:7)

stderr:

WARNING:robosuite_logs:No private macro file found!

stderr:

[robosuite WARNING] It is recommended to use a private macro file (__init__.py:8)

stderr:

WARNING:robosuite_logs:It is recommended to use a private macro file

stderr:

[robosuite WARNING] To setup, run: python /root/miniconda3/lib/python3.12/site-packages/robosuite/scripts/setup_macros.py (__init__.py:9)

stderr:

WARNING:robosuite_logs:To setup, run: python /root/miniconda3/lib/python3.12/site-packages/robosuite/scripts/setup_macros.py
Creating LIBERO envs | suites=['libero_spatial'] | n_envs(per task)=1 | init_states=True
Restricting to task_ids=[0]
[info] using task orders [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Built vec env | suite=libero_spatial | task_id=0 | n_envs=1
Local assets not found. Downloading from HuggingFace Hub...
Assets already downloaded at /root/.cache/libero/assets
{'image': (1, 256, 256, 3), 'image2': (1, 256, 256, 3)}

4. make_env 返回的结构为什么要套两层 list()

env = list(list(make_env(env_cfg, n_envs=1).values())[0].values())[0]

看着别扭,是因为 make_env 为了支持「一次跑多个 suite、每个 suite 多个任务」,返回的是两层字典:

{ suite 名: { task_id: 向量化环境 } }

所以:

  1. .values() 拿到第一层(各 suite),[0] 取第一个 suite;
  2. 再 .values() 拿到第二层(各 task),[0] 取第一个 task;
  3. 结果才是真正能 reset() / step() 的那个环境。

如果以后要跑多个任务、多个并行环境,这个结构就有用了——现在为了看清,先按单任务写。

5. LiberoEnv 常用参数

参数本例取值默认值说明
tasklibero_spatiallibero_10选哪个 suite
task_ids[0]None(全部)只跑第 0 个任务,省时间
observation_height / observation_width256 / 256360 / 360图像分辨率,要和策略模型训练时一致
fps—20控制频率,必须匹配 robosuite 默认的 20 Hz
init_states—True每次 reset 回到固定的初始状态,评测才可复现
hard_reset—True硬复位:重建场景,比软复位干净但慢
control_mode—relative动作是相对当前位姿的增量
camera_name—agentview_image,robot0_eye_in_hand_image两路相机

reset() 之后打印出来的 {'image': (1, 256, 256, 3), 'image2': (1, 256, 256, 3)} 里,第一个 1 是并行环境的数量(n_envs=1),不是 batch 维意义上的 1。

6. 两路相机和 [::-1] 这个翻转

obs["pixels"] 下的 image / image2 分别对应 agentview 和 eye_in_hand(映射关系写在 LiberoEnv.features_map 里)。

obs["pixels"]["image"][0][::-1] 里的 [::-1] 是垂直翻转。robosuite 的离屏渲染器输出的图像是上下颠倒的,直接显示会看到「天花板视角」。取第 0 个并行环境、翻转、再用 imageio 拼成 GIF:

  • 这一段同时验证了三件事:MuJoCo 渲染通了、EGL 后端生效了、图像能正常取出来;
  • show() 里用 imageio.mimsave(..., format="GIF", fps=fps),新版 imageio 会提示 fps 已弃用、建议用 duration(毫秒),只是警告,不影响输出。
import io, imageio.v2 as imageio
from IPython.display import display, Image as IPImage

def show(frames, fps=10):
    b = io.BytesIO()
    imageio.mimsave(b, frames, format="GIF", fps=fps)
    display(IPImage(data=b.getvalue(), format="gif"))

show([obs["pixels"]["image"][0][::-1]])

stderr:

/root/miniconda3/lib/python3.12/site-packages/imageio/plugins/pillow.py:410: DeprecationWarning: The keyword `fps` is no longer supported. Use `duration`(in ms) instead, e.g. `fps=50` == `duration=20` (1000 * 1/50).
  warnings.warn(

09_LeRobot仿真_1.gif
光看一帧不够,得让环境真的动起来:

7. 用一个随机策略跑 30 步

光看一帧不够,得让环境真的动起来:

frames = [obs["pixels"]["image"][0][::-1].copy()]
for _ in range(30):
    a = np.random.uniform(-1, 1, (1,) + env.single_action_space.shape).astype(np.float32)
    obs, *_ = env.step(a)
    frames.append(obs["pixels"]["image"][0][::-1].copy())
show(frames)
env.close()

09_LeRobot仿真_0.gif

这段做了三件事:

  1. frames 先装入复位后的第一帧;
  2. 循环 30 次,每次从动作空间均匀采样一个动作 np.random.uniform(-1, 1, ...)——这是随机乱动,不是智能行为,机械臂会在桌面上瞎戳;
  3. 每步后把画面存下来,最后拼成 GIF。

为什么先跑随机动作:这是环境自检的标准动作。如果随机策略都能让画面连续变化、机械臂跟着动,说明仿真、渲染、动作空间都对上了。等下一册换成真策略,画面会明显「有目的」。

env.single_action_space.shape 是 (7,),和数据集里 action 的 7 维对上了——所以同一个策略模型既能吃真实数据,也能吃这个仿真环境。

最后 env.close() 释放 MuJoCo 的渲染上下文。忘了 close 会泄漏显存/内存,连续开几个环境就容易崩。

8. 常见问题

现象原因处理
一堆 [robosuite WARNING] No private macro file found!robosuite 找不到可选的宏配置文件无害,可忽略;想消掉就跑一次它提示的 setup_macros.py
Local assets not found. Downloading...第一次运行要下 LIBERO 资产正常,需要走加速通道(07 册《环境与网络》);下完会打印缓存路径
画面上下颠倒robosuite 离屏渲染的坐标系取图时 [::-1] 翻转
开几个环境后显存爆了忘了 env.close()每个环境用完就关,或用 with 管理