LeRobot documentation
새 벤치마크 추가
새 벤치마크 추가
이 가이드는 LeRobot에 새로운 시뮬레이션 벤치마크를 추가하는 방법을 단계별로 안내합니다. 순서대로 단계를 따르며 기존 벤치마크를 템플릿으로 사용하세요.
LeRobot의 벤치마크는 Gymnasium 환경의 집합으로, 서드파티 시뮬레이터(LIBERO, Meta-World 등)를 표준 gym.Env 인터페이스 뒤에 래핑합니다. lerobot-eval CLI은 모든 벤치마크에 걸쳐 균일하게 평가를 실행합니다.
기존 벤치마크 한눈에 보기
시작하기 전에, 이미 통합된 몇 가지 벤치마크를 소개합니다(모든 항목은 문서 사이드바의 Benchmarks 섹션에 나열되어 있습니다):
| 벤치마크 | Env 파일 | Config 클래스 | 작업 | 액션 차원 | 프로세서 |
|---|---|---|---|---|---|
| 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.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단계(env-specific 변환이 필요한 경우)만 처리하면 됩니다.
환경 구조
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()은 모든 suite와 task를 순회합니다.- 각 작업마다
rollout()을 통해n_episodes개의 롤아웃을 실행합니다. - 결과는 에피소드, 태스크, 스위트, 전체 순으로 계층적으로 집계됩니다.
- Metrics에는
pc_success(성공률),avg_sum_reward,avg_max_reward가 포함됩니다. 모든 성공률은 해당 카운트(n_episodes중n_success)와 퍼센트 단위의 95% Wilson 구간(pc_success_ci95)과 함께 보고되며, 이는 task, suite, 전체 수준에서 적용됩니다. 해당 구간은 에피소드 간 샘플링 노이즈만을 반영하며, 동일한 레시피의 학습 실행 간 변동성에 대해서는 아무런 정보를 제공하지 않습니다.
핵심 부분: env는 모든 step() 호출 시 info["is_success"]를 반환해야 합니다. eval 루프가 작업이 완료되었는지 여부를 파악하는 방식입니다.
환경에서 제공해야 하는 것
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" (dict) | observation.images.<cam> | HWC uint8 형식의 여러 카메라 |
"agent_pos" | observation.state | 고유수용성 상태 벡터 |
"environment_state" | observation.env_state | 전체 환경 상태 (예: PushT) |
"robot_state" | observation.robot_state | 중첩된 로봇 상태 dict (예: LIBERO) |
시뮬레이터가 다른 키 이름을 사용하는 경우 두 가지 옵션이 있습니다:
- 권장 사항:
gym.Env래퍼 내부에서 표준 키로 이름을 변경하세요. - 대안:
preprocess_observation()실행 후 관측값을 변환하는 env 프로세서를 작성합니다(아래 3단계 참조).
Actions
Actions은 gym.spaces.Box의 연속형 numpy 배열입니다. 차원은 벤치마크에 따라 달라지며(LIBERO는 7, Meta-World는 4 등), 정책은 input_features / output_features 설정을 통해 서로 다른 action 차원에 적응합니다.
기능 선언
각 EnvConfig 하위 클래스는 정책이 무엇을 기대해야 하는지를 알려주는 두 개의 딕셔너리를 선언합니다:
features— 특징 이름을PolicyFeature(type, shape)(예: action dim, image 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 | 예 | 벤치마크와 create_envs()를 CLI에 등록합니다 |
src/lerobot/processor/env_processor.py | 선택 사항 | 사용자 정의 관찰/행동 변환 |
src/lerobot/envs/utils.py | 선택 사항 | 새로운 원시 관찰 키가 필요한 경우에만 |
pyproject.toml | 보통 | 벤치마크별 종속성을 선언합니다 |
docs/source/<benchmark>.mdx | 예 | 사용자 대상 문서 페이지 |
docs/source/_toctree.yml | 예 | docs 사이드바에 페이지를 추가합니다 |
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()를 참고하세요.
중첩된 dict 구조를 반환하는 팩토리 함수도 제공합니다:
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>를 통해 사용자가 벤치마크를 선택할 수 있도록 config dataclass를 등록합니다. 각 config는 두 가지 메서드를 통해 환경 생성 및 프로세서 로직을 관리합니다:
create_envs(n_envs, use_async_envs)—{suite: {task_id: VectorEnv}}를 반환합니다. 기본 클래스의 기본값은 단일 작업 환경에gym.make()를 사용합니다. 다중 작업 벤치마크는 이 메서드를 오버라이드합니다.get_env_processors()—(preprocessor, postprocessor)를 반환합니다. 기본 클래스의 기본값은 identity(no-op) 파이프라인을 반환합니다. 벤치마크에 관찰/행동 변환이 필요한 경우 오버라이드하세요.
@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이름은 사용자가 CLI(--env.type=<name>)에서 전달하는 값입니다.features는 정책(policy)에 환경이 무엇을 생성하는지를 알려줍니다.features_map은 원시 관찰 키를 LeRobot 규약 키로 매핑합니다.factory.py에 변경 사항이 필요하지 않습니다 — 팩토리가 자동으로cfg.create_envs()와cfg.get_env_processors()에 위임합니다.
3. Env 프로세서 (선택 사항 — 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]"]고정 규칙:
- Always pin benchmark packages to exact versions for reproducibility (e.g.
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]"을 실행하여 의존성 그룹이 정상적으로 설치되는지 확인합니다. - Smoke test 환경 생성 — Python에서 설정을 사용하여
make_env()를 호출하고, 반환된 dict가 예상된{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로 전환되는지 확인합니다. 이는 eval 루프가 성공률을 계산하는 데 사용하는 값입니다.
벤치마크 문서 페이지 작성
각 벤치마크 .mdx 페이지에는 다음을 포함해야 합니다:
- 제목 및 설명 — 벤치마크가 무엇을 테스트하는지, 그리고 왜 중요한지에 대한 1~2단락 분량의 내용.
- 링크 — 논문, GitHub 저장소, 프로젝트 웹사이트(사용 가능한 경우).
- 개요 이미지 또는 GIF.
- 사용 가능한 작업 — 작업 스위트의 개수와 간단한 설명이 포함된 표.
- 설치 —
pip install -e ".[<benchmark>]"및 추가 단계(환경 변수, 시스템 패키지). - 평가 — 재현 가능한 결과를 위해
n_episodes를 사용하는lerobot-eval명령을 권장합니다.batch_size는 기본적으로 auto로 설정되며, 필요한 경우에만 명시하세요. 해당되는 경우 단일 작업 및 다중 작업 예시를 포함하세요. - 정책 입력 및 출력 — 형태가 포함된 관찰 키, 액션 공간 설명.
- 권장 평가 에피소드 — 각 작업당 표준으로 사용되는 에피소드 수.
- 학습 —
lerobot-train명령어 예시. - 공개된 결과 재현 — 사전 학습된 모델 링크, 평가 명령어, 결과 테이블(사용 가능한 경우).
완전한 예제는 docs/source/libero.mdx 및 docs/source/metaworld.mdx를 참고하세요.