LeRobot documentation
Agregar un benchmark
Agregar un benchmark
Un benchmark es un simulador que LeRobot controla en un solo lugar, lerobot.sim, para que cada forma de usarlo se comporte de la misma manera: lerobot-eval (un entorno por lotes, --env.type=<benchmark>), rollout y grabación (un robot simulado, --robot.type=sim --robot.env.type=<benchmark>), localmente o servido por lerobot-env-server desde su propia imagen de Docker. Consulte Simulación: local o servida para ver cómo se utiliza.
Qué añadir
| Componente | Ubicación | Qué añadir |
|---|---|---|
| Integración | src/lerobot/sim/integrations/<benchmark>.py | El gym.Env, las fábricas env_fns(), el adaptador canonical_observation() y las conventions() para ese simulador |
| Config | src/lerobot/envs/configs.py | Una subclase de EnvConfig cuyo sim_settings() mapea sus opciones a los kwargs de la fábrica |
| Configuración del servidor | docker/sim/configs/<benchmark>.yaml | Los kwargs de la tarea y la fábrica que utilizan el servidor y la CI |
| Imagen del simulador | docker/Dockerfile.sim | Una etapa <benchmark>_native: dependencias nativas fijas (incluida cualquier herramienta de CUDA, ya que la base es Ubuntu sin modificaciones) y revisiones de recursos; la etapa final añade el servidor |
| Manifiesto de CI | benchmarks/benchmarks.yaml | Nombre, tareas, revisión del punto de control, cámara, rename_map y parity opcional; el resto toma valores predeterminados a partir del nombre |
| Dependencias | pyproject.toml | Un grupo de dependencias opcionales para uso local |
| Documentación | docs/source/<benchmark>.mdx, _toctree.yml | Una página para el usuario |
| Origen | docs/source/<benchmark>.mdx | Repositorios de origen, revisiones de código y activos fijadas con sus licencias, y una tasa de éxito publicada para un punto de control que puedes ejecutar |
Ambas rutas exponen el mismo comportamiento del entorno:
native simulator → LocalVectorEnv, locally or on an env server → canonical NumPy observations → batched env or sim robot → one-time image/tensor preparation → saved policy preprocessing → policy → saved action postprocessing → native simulator
Coloca la orientación de la imagen, la conversión de cuaterniones y el ordenamiento del estado en el adaptador canonical_observation() de ese simulador, y sus convenciones de control en su conventions(), para que la evaluación y el rollout coincidan. Reutiliza sim/integrations/utils.py solo para los mapeos compartidos por las integraciones; el código de entorno compartido no debe ramificarse en función de los nombres de los simuladores. Un nuevo benchmark no necesita un environment processor: las observaciones llegan a los propios procesadores de la política ya en formato canónico.
Cómo se ejecutan las evaluaciones
lerobot-eval evalúa cada benchmark de la misma manera:
make_env()construye el diccionario anidado{suite: {task_id: vector env}}.eval_policy_all()ejecutan_episodesrollouts de cada tarea, una tarea a la vez (o--env.max_parallel_tasksa la vez).- Los resultados se agregan por episodio, tarea, suite y en general:
pc_success(tasa de éxito),avg_sum_rewardyavg_max_reward. Cada tasa de éxito incluye sus recuentos (n_successden_episodes) y un intervalo de Wilson del 95% en porcentaje (pc_success_ci95). El intervalo cubre solo el ruido de muestreo entre episodios; no dice nada sobre la variación entre ejecuciones de entrenamiento de la misma receta.
El éxito proviene de info["is_success"], que su entorno informa en cada step(). Su entorno también puede informar números propios. Los coloca en info["metrics"], un mapa de cada nombre a un float por entorno. Llegan a la entrada de cada episodio bajo per_episode[i]["metrics"], tomados en el paso en que el episodio terminó.
Lo que su entorno debe proporcionar
Estructura del entorno
env_fns() devuelve las fábricas de entorno de cada tarea, sin construirlas:
def env_fns(
task: str,
n_envs: int,
gym_kwargs: dict | None = None,
) -> dict[str, dict[int, list[Callable[[], gym.Env]]]]:
"""{suite: {task_id: [make_single_env] * n_envs}} for MyBenchmark."""Un benchmark de una sola tarea devuelve {"<task>": {0: [...]}}; uno de varias tareas (como LIBERO) devuelve {"libero_spatial": {0: [...], 1: [...], ...}, ...}. LocalVectorEnv llama a cada factoría make_single_env en el primer uso, localmente o en el servidor y, con --eval.use_async_envs=true, en un proceso separado por entorno.
El 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)| Atributo | Tipo | Por qué |
|---|---|---|
_max_episode_steps | int | Finaliza (trunca) un episodio |
task_description | str | Se pasa a las políticas VLA como una instrucción de lenguaje |
task | str | Identificador de respaldo si task_description no está establecido |
step() informa el éxito en info["is_success"], y cualquier otra cosa que mida en info["metrics"]. Las acciones son una Box continua de una dimensión.
Las observaciones son un diccionario que el adaptador canonical_observation() de la integración entiende. El adaptador predeterminado reutilizable mapea:
| Salidas de tu env | Clave canónica | En qué consiste |
|---|---|---|
"pixels" (un solo array) | observation.image | Imagen de una sola cámara, HWC uint8 |
"pixels" (dict) | observation.images.<cam> | Varias cámaras, cada una HWC uint8 |
"agent_pos" | observation.state | Vector de estado propioceptivo |
"environment_state" | observation.environment_state | Estado completo del entorno (p. ej., PushT) |
Cualquier otro array se pasa como observation.<key>. Renombra las salidas de tu simulador a estas claves dentro de gym.Env, o maneja su representación nativa en el adaptador de esa integración.
Simuladores basados en GPU (p. ej., MuJoCo con renderizado EGL): si su simulador asigna contextos de GPU/EGL durante __init__, difiera esa asignación a un auxiliar _ensure_env() que se llame en el primer reset()/step(), de modo que un entorno construido en un proceso de trabajador no herede manejos de GPU obsoletos. Consulte LiberoEnv._ensure_env() para ver el patrón.
Convenciones ( conventions() en la integración)
Devuelve la tasa de control del simulador, el controlador y los nombres de componentes ordenados desde conventions(kwargs), una función de las opciones del simulador (pueden depender de un modo de acción, como en RoboTwin). Rellenan la configuración que una configuración omite y nombran los componentes de estado y acción para robots, conjuntos de datos y puntos de control. semantics tiene por defecto <type>-<control>-v1. robot_type nombra el cuerpo simulado, registrado por un robot de simulación: el tipo que el robot real registra cuando lerobot tiene una clase para él (so_follower), de lo contrario un nombre corto (panda, sawyer); si se omite, los conjuntos de datos registran sim_robot.
La configuración ( src/lerobot/envs/configs.py )
Registra una configuración para que los usuarios puedan seleccionar tu benchmark con --env.type=<name> (y --robot.env.type=<name>). Su sim_settings() describe el simulador como la sección sim de un YAML de servidor; LocalVectorEnv se encarga del resto:
@EnvConfig.register_subclass("<benchmark_name>")
@dataclass
class MyBenchmarkEnvConfig(EnvConfig):
task: str = "<default_task>"
fps: int = <fps>
obs_type: str = "pixels_agent_pos"
@property
def gym_kwargs(self) -> dict:
return {"obs_type": self.obs_type}
def sim_settings(self) -> dict:
return {"type": "<benchmark_name>", "task": self.task, "kwargs": {"gym_kwargs": self.gym_kwargs}}Mantén sus valores predeterminados y los del YAML del servidor en concordancia: una evaluación servida rechaza un servidor que ejecuta un entorno diferente al que describe el comando. Las características provienen de la descripción del entorno cuando este se crea, por lo que la configuración no declara ninguna.
Admisión de puntos de control
--rename_map asigna alias a las claves de cámara del entorno para que coincidan con las claves entrenadas del checkpoint, igual que para cualquier robot; en CI proviene de la entrada rename_map en benchmarks/benchmarks.yaml. Las entradas del checkpoint deben existir después del renombrado, y las dimensiones de estado/acción deben coincidir; el renombrado no puede reparar los metadatos del checkpoint. El número y el orden de los canales RGB se verifican en la admisión. La altura/ancho de adquisición puede diferir de los metadatos de entrenamiento; el redimensionado corresponde a la preprocesación de la política.
Verificación y CI
- Comprueba el adaptador de observación de la integración frente a las salidas crudas de tu simulador, en particular la orientación de la cámara y el orden del estado, y verifica las acciones aplicadas por el envoltorio del entorno.
- Compare las secuencias de reinicio/paso con semilla localmente y servidas (
scripts/ci/check_sim_parity.py); establezcaparity: trueen la entrada del manifiesto de un simulador determinista para que CI lo ejecute. Verifique el congelamiento terminal, el éxito, la longitud del episodio, la renderización y la limpieza de recursos. - Ejecuta las guardas de importación con torch deshabilitado para el código del servidor y tu módulo nativo. Documenta los simuladores que requieren su propio runtime de torch, como RoboTwin y RoboMME.
- Ejecuta
lerobot-eval --env.type=<name> --env.task=<task> --eval.n_episodes=1 --policy.path=<checkpoint>localmente y, con--env.server.endpoint, contra el servidor. Inspecciona las descripciones de las tareas y las vistas de las cámaras renderizadas. - Ejecuta el trabajo de benchmark generado en el runner de GPU. Conserva el smoke de entrenamiento de LIBERO al modificar la integración compartida de evaluación/entrenamiento.
benchmarks/benchmarks.yaml genera la matriz a través de scripts/ci/benchmark_matrix.py; .github/workflows/benchmark_run.yml ejecuta cada entrada. Añada entradas al manifiesto en lugar de copiar trabajos de CI. La CI limita los episodios para verificar el pipeline de principio a fin; su metrics.json registra la revisión del checkpoint, la etiqueta de la imagen del simulador, el commit y el límite, y marca estas ejecuciones como smoke: sus tasas de éxito no son puntuaciones de política. Las imágenes del simulador tienen fijaciones y etiquetas de contenido separadas; las cachés de BuildKit solo persisten en ejecutores persistentes.
Cambiar un benchmark
La canonical_observation(), las conventions() y el envoltorio de entorno de una integración deciden qué ve la política y cómo se aplican sus acciones. Una orientación de imagen, un orden de estado o una tasa de control incorrectos no provocan un error: la política recibe entradas ligeramente incorrectas y su tasa de éxito disminuye. Un cambio en cualquiera de ellos conlleva:
- Una prueba de regresión que compara las salidas antiguas y nuevas sobre una observación registrada o sintética.
test_libero_numpy_adapter_parityentests/sim/integrations/test_libero.pyes el modelo: demuestra que el adaptador de LIBERO sin torch produce exactamente lo que hacía el procesador de LIBERO anterior. - El efecto esperado en las puntuaciones en la solicitud de extracción: ninguno, o qué puntuaciones deberían cambiar y por qué.
Dependencias ( pyproject.toml )
Agregue un nuevo grupo de dependencias opcionales para uso local:
mybenchmark = ["my-benchmark-pkg==1.2.3", "lerobot[scipy-dep]"]Reglas de fijación:
- Fija siempre los paquetes de benchmark a versiones exactas para garantizar la reproducibilidad (p. ej.
metaworld==3.0.0). - Añade marcadores de plataforma cuando sea necesario (p. ej.
; sys_platform == 'linux'). - Fija las dependencias transitarias frágiles si se conocen (p. ej., la imagen de Meta-World fija
mujoco==3.15.0, ya que MuJoCo 3.17 rompe sus soldaduras de mocap). - Restricciones del documento en la página de tu documento de benchmark. Cuando las dependencias entran en conflicto con las de LeRobot, la ruta servida es la compatible.
Escribir una página de documentación de un benchmark
Añade la página a la sección “Benchmarks” de docs/source/_toctree.yml. Cada página de benchmark debe incluir:
- Título y descripción — 1-2 párrafos sobre lo que evalúa el benchmark y por qué es importante.
- Enlaces — artículo, repositorio de GitHub, sitio web del proyecto (si está disponible).
- Origen y licencias — repositorios de origen, revisiones fijas de código y activos, y la licencia de cada uno. No añada un benchmark cuya licencia prohíba su uso.
- Imagen o GIF de resumen.
- Tareas disponibles — tabla de suites de tareas con recuentos y descripciones breves.
- Instalación —
pip install -e ".[<benchmark>]", o el comando del servidor. - Evaluación — comando
lerobot-evalrecomendado conn_episodespara resultados reproducibles. - Entradas y salidas de la política — claves de observación con formas, descripción del espacio de acciones.
- Entrenamiento — ejemplo del comando
lerobot-train. - Resultados de referencia — la tasa de éxito publicada de al menos un checkpoint preentrenado que puedas ejecutar, con su revisión y el comando
lerobot-evalque lo reproduce. Una integración que no se acerque a ese valor no está terminada.
Consulte docs/source/libero.mdx y docs/source/metaworld.mdx para ejemplos completos.