跳转至

添加新基准测试

本指南将引导您向 LeRobot 添加新的仿真基准测试。按顺序遵循这些步骤,并使用现有基准测试作为模板。

LeRobot 中的基准测试是一组 Gymnasium 环境,它们在标准 gym.Env 接口后面包装第三方模拟器(如 LIBERO 或 Meta-World)。然后 lerobot-eval CLI 在所有基准测试中统一运行评估。

现有基准测试概览

在深入之前,这里是已经集成的内容:

基准测试 环境文件 配置类 任务 动作维度 处理器
LIBERO envs/libero.py LiberoEnv 5 个套件共 130 个 7 LiberoProcessorStep
Meta-World envs/metaworld.py MetaworldEnv 50 (MT50) 4 None
IsaacLab Arena Hub 托管 IsaaclabArenaEnv 可配置 可配置 IsaaclabArenaProcessorStep

使用 src/lerobot/envs/libero.pysrc/lerobot/envs/metaworld.py 作为参考实现。

整体架构

数据流

在评估期间,数据经过四个阶段:

1. gym.Env  ──→  原始观测(numpy 字典)

2. 预处理  ──→  标准 LeRobot 键 + 任务描述
   (envs/utils.py 中的 preprocess_observation, env.call("task_description"))

3. 处理器  ──→  环境特定然后策略特定的转换
   (env_preprocessor, policy_preprocessor)

4. 策略  ──→  select_action()  ──→  动作张量
   然后反向:policy_postprocessor → env_postprocessor → numpy 动作 → env.step()

大多数基准测试只需要关心阶段 1(以正确格式生成观测)和可选的阶段 3(如果需要环境特定的转换)。

环境结构

make_env() 返回一个嵌套的向量化环境字典:

dict[str, dict[int, gym.vector.VectorEnv]]
#    ^套件       ^任务ID

单任务环境(例如 PushT)看起来像 {"pusht": {0: vec_env}}。 多任务基准测试(例如 LIBERO)看起来像 {"libero_spatial": {0: vec0, 1: vec1, ...}, ...}

评估如何运行

所有基准测试都由 lerobot-eval 以相同方式评估:

  1. make_env() 构建嵌套的 {suite: {task_id: VectorEnv}} 字典。
  2. eval_policy_all() 遍历每个套件和任务。
  3. 对于每个任务,它通过 rollout() 运行 n_episodes 次推演。
  4. 结果按层次聚合:回合、任务、套件、总体。
  5. 指标包括 pc_success(成功率)、avg_sum_rewardavg_max_reward

关键部分:您的环境必须在每次 step() 调用时返回 info["is_success"]。这是评估循环如何知道任务是否完成的方式。

您的环境必须提供什么

LeRobot 不强制执行严格的观测模式。相反,它依赖于所有基准测试遵循的一组约定。

环境属性

您的 gym.Env 必须设置这些属性:

属性 类型 原因
_max_episode_steps int rollout() 使用它来限制回合长度
task_description str 作为语言指令传递给 VLA 策略
task str 如果未设置 task_description,则为后备标识符

成功报告

您的 step()reset() 必须在 info 字典中包含 "is_success"

info = {"is_success": True}   # 或 False
return observation, reward, terminated, truncated, info

观测

最简单的方法是将模拟器的输出映射到 preprocess_observation() 已经理解的标准键。在您的 gym.Env 内部执行此操作(例如在 _format_raw_obs() 辅助函数中):

您的环境应输出 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)

如果您的模拟器使用不同的键名,您有两个选择:

  1. 推荐:在您的 gym.Env 包装器内部将它们重命名为标准键。
  2. 替代方案:编写一个环境处理器,在 preprocess_observation() 运行后转换观测(见下面的步骤 4)。

动作

动作是 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")。

分步指南

Tip

至少,您需要两个文件:一个 gym.Env 包装器和一个带有 create_envs() 覆盖的 EnvConfig 子类。其他所有内容都是可选的或文档。不需要更改 factory.py

检查清单

文件 必需 原因
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):
        ...  # 返回 (observation, info) — info 必须包含 {"is_success": False}

    def step(self, action: np.ndarray):
        ...  # 返回 (obs, reward, terminated, truncated, info) — info 必须包含 {"is_success": <bool>}

    def render(self):
        ...  # 返回 RGB 图像作为 numpy 数组

    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]]:
    """为 MyBenchmark 创建 {suite_name: {task_id: VectorEnv}}。"""
    ...

参见 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):
        ...  # 根据 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):
        """为多任务基准测试或自定义环境创建覆盖。"""
        from lerobot.envs.<benchmark> import create_<benchmark>_envs
        return create_<benchmark>_envs(task=self.task, n_envs=n_envs, ...)

    def get_env_processors(self):
        """如果您的基准测试需要观测/动作转换,则覆盖。"""
        from lerobot.processor import PolicyProcessorPipeline
        from lerobot.processor.env_processor import MyBenchmarkProcessorStep
        return (
            PolicyProcessorPipeline(steps=[MyBenchmarkProcessorStep()]),
            PolicyProcessorPipeline(steps=[]),
        )

关键点:

  • register_subclass 名称是用户在 CLI 上传递的内容(--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()
        # 您的转换在这里
        return processed

    def transform_features(self, features):
        return features  # 如果形状改变则更新

    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.mdxdocs/source/metaworld.mdx 的完整示例。

6. 目录(docs/source/_toctree.yml

将您的基准测试添加到"基准测试"部分:

- 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"

验证您的集成

完成上述步骤后,确认一切正常:

  1. 安装pip install -e ".[mybenchmark]" 并验证依赖组安装干净。
  2. 冒烟测试环境创建 — 在 Python 中使用您的配置调用 make_env(),检查返回的字典是否具有预期的 {suite: {task_id: VectorEnv}} 形状,并且 reset() 返回具有正确键的观测。
  3. 运行完整评估lerobot-eval --env.type=<name> --env.task=<task> --eval.n_episodes=1 --policy.path=<any_compatible_policy> 以端到端地执行完整管道。(batch_size 默认为基于 CPU 核心的自动调整;传递 --eval.batch_size=1 以强制单个环境。)
  4. 检查成功检测 — 验证当任务实际完成时 info["is_success"] 翻转为 True。这是评估循环用于计算成功率的内容。

编写基准测试文档页面

每个基准测试 .mdx 页面应包括:

  • 标题和描述 — 1-2 段关于基准测试测试什么以及为什么重要。
  • 链接 — 论文、GitHub 仓库、项目网站(如果可用)。
  • 概览图像或 GIF。
  • 可用任务 — 任务套件表,包含计数和简要描述。
  • 安装pip install -e ".[<benchmark>]" 加上任何额外步骤(环境变量、系统包)。
  • 评估 — 推荐的 lerobot-eval 命令,包含用于可重现结果的 n_episodesbatch_size 默认为自动;仅在需要时指定。包括单任务和多任务示例(如果适用)。
  • 策略输入和输出 — 带形状的观测键、动作空间描述。
  • 推荐的评估回合 — 每个任务多少回合是标准的。
  • 训练 — 示例 lerobot-train 命令。
  • 重现已发布结果 — 链接到预训练模型、评估命令、结果表(如果可用)。

参见 docs/source/libero.mdxdocs/source/metaworld.mdx 的完整示例。