LeRobot documentation
添加新基准
添加新基准
本指南将指导您向 LeRobot 添加新的仿真基准测试。请按顺序执行以下步骤,并参考现有的基准测试作为模板。
LeRobot 中的基准测试(benchmark)是一组 Gymnasium 环境,它们通过标准的 gym.Env 接口封装第三方模拟器(如 LIBERO 或 Meta-World)。随后,lerobot-eval CLI 会在所有基准测试上统一执行评估。
现有基准测试一览
在开始之前,这里列出了一些已经集成的基准测试(它们全部列在文档侧边栏的 Benchmarks 下):
| 基准测试 | Env 文件 | 配置类 | 任务 | 动作维度 | 处理器 |
|---|---|---|---|---|---|
| LIBERO | envs/libero.py | LiberoEnv | 5 个测试套件中的 130 个 | 7 | LiberoProcessorStep |
| Meta-World | envs/metaworld.py | MetaworldEnv | 50 (MT50) | 4 | 无 |
| IsaacLab Arena | Hub 托管 | IsaaclabArenaEnv | 可配置 | 可配置 | IsaaclabArenaProcessorStep |
请参考 src/lerobot/envs/libero.py 和 src/lerobot/envs/metaworld.py 作为参考实现。
各部分如何协同工作
数据流
在评估过程中,数据会经历四个阶段:
1. gym.Env ──→ raw observations (numpy dicts)
2. Preprocessing ──→ standard LeRobot keys + task description
(preprocess_observation in envs/utils.py, env.call("task_description"))
3. Processors ──→ env-specific then policy-specific transforms
(env_preprocessor, policy_preprocessor)
4. Policy ──→ select_action() ──→ action tensor
then reverse: policy_postprocessor → env_postprocessor → numpy action → env.step()大多数基准测试只需关注阶段 1(以正确的格式生成观测值),并可选地关注阶段 3(如果需要针对特定环境的转换)。
环境结构
make_env() 返回一个包含向量化环境的嵌套字典:
dict[str, dict[int, gym.vector.VectorEnv]]
# ^suite ^task_id单任务环境(例如 PushT)的结构为 {"pusht": {0: vec_env}}。
多任务基准(例如 LIBERO)的结构为 {"libero_spatial": {0: vec0, 1: vec1, ...}, ...}。
评估的运行方式
所有基准测试均由 lerobot-eval 以相同方式评估:
make_env()会构建嵌套的{suite: {task_id: VectorEnv}}字典。eval_policy_all()会遍历所有套件和任务。- 对于每个任务,它通过
rollout()运行n_episodes次 rollout。 - 结果按层级进行汇总:episode、task、suite、overall。
- 指标包括
pc_success(成功率)、avg_sum_reward和avg_max_reward。每个成功率都会附带其计数(n_episodes中的n_success)以及以百分比表示的 95% Wilson 区间(pc_success_ci95),并分别在任务、套件和总体层面进行报告。该区间仅涵盖回合间的采样噪声,并不反映同一配方在不同训练运行之间的差异。
关键部分:你的 env 必须在每次 step() 调用时返回 info["is_success"]。评估循环正是通过它来判断任务是否已完成。
您的环境必须提供的内容
LeRobot 不强制要求严格的观测模式。相反,它依赖于一套所有基准测试都遵循的约定。
Env 属性
您的 gym.Env 必须设置以下属性:
| 属性 | 类型 | 为什么 |
|---|---|---|
_max_episode_steps | int | rollout() 使用此参数来限制回合长度 |
task_description | str | 作为语言指令传递给 VLA 策略 |
task | str | 如果未设置 task_description,则使用此回退标识符 |
成功报告
您的 step() 和 reset() 必须在 info 字典中包含 "is_success":
info = {"is_success": True} # or False
return observation, reward, terminated, truncated, info观察
最简单的方法是将模拟器的输出映射到 preprocess_observation() 已经能够识别的标准键。请在你的 gym.Env 中执行此操作(例如,在 _format_raw_obs() 辅助函数中):
| 您的 env 应输出 | LeRobot 将其映射到 | 它是什么 |
|---|---|---|
"pixels"(单个数组) | observation.image | 单摄像头图像,HWC uint8 |
"pixels"(字典) | observation.images.<cam> | 多个摄像头,每个均为 HWC uint8 |
"agent_pos" | observation.state | 本体感觉状态向量 |
"environment_state" | observation.env_state | 完整的环境状态(例如 PushT) |
"robot_state" | observation.robot_state | 嵌套的机器人状态字典(例如 LIBERO) |
如果您的模拟器使用了不同的键名,您有两个选择:
- 推荐:在您的
gym.Env包装器中,将它们重命名为标准键。 - 替代方案:编写一个 env 处理器,在
preprocess_observation()运行后对观测值进行转换(参见下文第 3 步)。
操作
动作是 gym.spaces.Box 中的连续 numpy 数组。其维度取决于所使用的基准测试(例如 LIBERO 为 7,Meta-World 为 4 等)。策略通过其 input_features / output_features 配置来适应不同的动作维度。
功能声明
每个 EnvConfig 子类都声明了两个字典,用于告知策略预期接收的内容:
features— 将特征名称映射到PolicyFeature(type, shape)(例如动作维度、图像形状)。features_map— 将原始观测键映射到 LeRobot 约定键(例如,将"agent_pos"映射到"observation.state")。
逐步
At minimum, you need two files: a **gym.Env wrapper** and an **EnvConfig subclass** with a `create_envs()` override. Everything else is optional or documentation. No changes to `factory.py` are needed.
检查清单
| 文件 | 必需 | 为什么 |
|---|---|---|
src/lerobot/envs/<benchmark>.py | 是的 | 将模拟器封装为标准的 gym.Env |
src/lerobot/envs/configs.py | 是的 | 在 CLI 中注册你的基准测试及其 create_envs() |
src/lerobot/processor/env_processor.py | 可选 | 自定义观察/动作转换 |
src/lerobot/envs/utils.py | 可选 | 仅当您需要新的原始观测键时 |
pyproject.toml | 通常 | 声明基准测试特定的依赖项 |
docs/source/<benchmark>.mdx | 是的 | 面向用户的文档页面 |
docs/source/_toctree.yml | 是的 | 将您的页面添加到文档侧边栏 |
1. gym.Env 包装器(src/lerobot/envs/<benchmark>.py)
创建一个 gym.Env 子类,用于封装第三方模拟器:
class MyBenchmarkEnv(gym.Env):
metadata = {"render_modes": ["rgb_array"], "render_fps": <fps>}
def __init__(self, task_suite, task_id, ...):
super().__init__()
self.task = <task_name_string>
self.task_description = <natural_language_instruction>
self._max_episode_steps = <max_steps>
self.observation_space = spaces.Dict({...})
self.action_space = spaces.Box(low=..., high=..., shape=(...,), dtype=np.float32)
def reset(self, seed=None, **kwargs):
... # return (observation, info) — info must contain {"is_success": False}
def step(self, action: np.ndarray):
... # return (obs, reward, terminated, truncated, info) — info must contain {"is_success": <bool>}
def render(self):
... # return RGB image as numpy array
def close(self):
...基于 GPU 的模拟器(例如使用 EGL 渲染的 MuJoCo): 如果你的模拟器在 __init__ 期间分配 GPU/EGL 上下文,请将此分配延迟到在首次调用 reset()/step() 时执行的 _ensure_env() 辅助函数中。这可以避免在 AsyncVectorEnv 生成工作进程时继承过期的 GPU 句柄。有关该模式的示例,请参阅 LiberoEnv._ensure_env()。
同时提供一个工厂函数,返回嵌套的字典结构:
def create_mybenchmark_envs(
task: str,
n_envs: int,
gym_kwargs: dict | None = None,
env_cls: type | None = None,
) -> dict[str, dict[int, Any]]:
"""Create {suite_name: {task_id: VectorEnv}} for MyBenchmark."""
...请参阅 create_libero_envs()(多套件、多任务)和 create_metaworld_envs()(按难度分组的任务)作为参考。
2. 配置文件(src/lerobot/envs/configs.py)
注册一个配置数据类,以便用户可以使用 --env.type=<name> 选择您的基准测试。每个配置通过两个方法拥有其环境创建和处理器逻辑:
create_envs(n_envs, use_async_envs)— 返回{suite: {task_id: VectorEnv}}。基类的默认实现使用gym.make()创建单任务环境。多任务基准测试会重写此方法。get_env_processors()— 返回(preprocessor, postprocessor)。基类的默认实现返回恒等(无操作)流水线。如果您的基准测试需要对观测/动作进行转换,请重写此方法。
@EnvConfig.register_subclass("<benchmark_name>")
@dataclass
class MyBenchmarkEnvConfig(EnvConfig):
task: str = "<default_task>"
fps: int = <fps>
obs_type: str = "pixels_agent_pos"
features: dict[str, PolicyFeature] = field(default_factory=lambda: {
ACTION: PolicyFeature(type=FeatureType.ACTION, shape=(<action_dim>,)),
})
features_map: dict[str, str] = field(default_factory=lambda: {
ACTION: ACTION,
"agent_pos": OBS_STATE,
"pixels": OBS_IMAGE,
})
def __post_init__(self):
... # populate features based on obs_type
@property
def gym_kwargs(self) -> dict:
return {"obs_type": self.obs_type, "render_mode": self.render_mode}
def create_envs(self, n_envs: int, use_async_envs: bool = True):
"""Override for multi-task benchmarks or custom env creation."""
from lerobot.envs.<benchmark> import create_<benchmark>_envs
return create_<benchmark>_envs(task=self.task, n_envs=n_envs, ...)
def get_env_processors(self):
"""Override if your benchmark needs observation/action transforms."""
from lerobot.processor import PolicyProcessorPipeline
from lerobot.processor.env_processor import MyBenchmarkProcessorStep
return (
PolicyProcessorPipeline(steps=[MyBenchmarkProcessorStep()]),
PolicyProcessorPipeline(steps=[]),
)要点:
register_subclass名称是用户在命令行中传入的内容(--env.type=<name>)。features告知策略环境会产生什么。features_map将原始观测键映射到 LeRobot 约定键。- 无需对
factory.py进行任何更改 — 工厂会自动委托给cfg.create_envs()和cfg.get_env_processors()。
3. 环境处理器(可选 — src/lerobot/processor/env_processor.py)
仅当您的基准测试需要 preprocess_observation() 无法处理的观察转换(例如图像翻转、坐标转换)时才需要此步骤。在此处定义处理器步骤,并在您的配置中从 get_env_processors() 返回它(参见步骤 2):
@dataclass
@ProcessorStepRegistry.register(name="<benchmark>_processor")
class MyBenchmarkProcessorStep(ObservationProcessorStep):
def _process_observation(self, observation):
processed = observation.copy()
# your transforms here
return processed
def transform_features(self, features):
return features # update if shapes change
def observation(self, observation):
return self._process_observation(observation)有关完整示例(图像旋转、四元数到轴角转换),请参阅 LiberoProcessorStep。
4. 依赖项(pyproject.toml)
添加一个新的可选依赖组:
mybenchmark = ["my-benchmark-pkg==1.2.3", "lerobot[scipy-dep]"]固定规则:
- 始终将基准测试包固定到确切版本以确保可复现性(例如
metaworld==3.0.0)。 - 在需要时(例如
; sys_platform == 'linux')添加平台标记。 - 如果已知,请固定脆弱的传递依赖(例如,对于 Meta-World 使用
gymnasium==1.1.0)。 - 在您的基准测试文档页面中记录约束条件。
用户通过以下方式安装:
pip install -e ".[mybenchmark]"5. 文档(docs/source/<benchmark>.mdx)
按照下一节的模板编写面向用户的页面。完整的示例请参见 docs/source/libero.mdx 和 docs/source/metaworld.mdx。
6. 目录(docs/source/_toctree.yml)
将您的基准测试添加到“Benchmarks”部分:
- sections:
- local: libero
title: LIBERO
- local: metaworld
title: Meta-World
- local: envhub_isaaclab_arena
title: NVIDIA IsaacLab Arena Environments
- local: <your_benchmark>
title: <Your Benchmark Name>
title: "Benchmarks"验证您的集成
完成上述步骤后,确认一切正常运行:
- 安装 —
pip install -e ".[mybenchmark]"并验证依赖组是否干净地安装。 - 创建冒烟测试环境 — 在 Python 中调用
make_env()并传入你的配置,检查返回的字典是否具有预期的{suite: {task_id: VectorEnv}}结构,并且reset()返回的观察值包含正确的键。 - 运行完整评估 — 使用
lerobot-eval --env.type=<name> --env.task=<task> --eval.n_episodes=1 --policy.path=<any_compatible_policy>来端到端地测试完整流程。(batch_size默认根据 CPU 核心数自动调整;传入--eval.batch_size=1可强制使用单个环境。) - 检查成功检测 — 验证当任务实际完成时,
info["is_success"]是否变为True。评估循环使用此值来计算成功率。
编写基准测试文档页面
每个基准测试的 .mdx 页面应包含:
- 标题和描述 — 1-2 段文字,说明该基准测试的内容及其重要性。
- 链接 — 论文、GitHub 仓库、项目网站(如有)。
- 概览图片或 GIF。
- 可用任务 — 任务套件表格,包含数量及简要描述。
- 安装 —
pip install -e ".[<benchmark>]"以及任何额外步骤(环境变量、系统软件包)。 - 评估 — 推荐用于可复现结果的
lerobot-eval命令,并指定n_episodes。batch_size默认为自动;仅在需要时指定。如适用,请包含单任务和多任务示例。 - 策略的输入和输出 — 带有形状的观测键,动作空间描述。
- 推荐的评估回合数 — 每个任务的标准回合数。
- 训练 —
lerobot-train命令示例。 - 复现已发表的结果 — 预训练模型的链接、评估命令、结果表格(如有)。
请参阅 docs/source/libero.mdx 和 docs/source/metaworld.mdx 以获取完整示例。