LeRobot documentation
Adicionando um Benchmark
Adicionando um Benchmark
Um benchmark é um simulador que o LeRobot opera em um único local, lerobot.sim, para que todas as formas de uso se comportem da mesma maneira: lerobot-eval (um ambiente em lote, --env.type=<benchmark>), rollout e gravação (um robô de simulação, --robot.type=sim --robot.env.type=<benchmark>), localmente ou servido por lerobot-env-server a partir de sua própria imagem Docker. Consulte Simulação: local ou servida para saber como é usado.
O que adicionar
| Componente | Localização | O que adicionar |
|---|---|---|
| Integração | src/lerobot/sim/integrations/<benchmark>.py | O gym.Env, as fábricas env_fns(), o adaptador canonical_observation() e as convenções conventions() para esse simulador |
| Config | src/lerobot/envs/configs.py | Uma subclasse de EnvConfig cujo sim_settings() mapeia suas opções para os kwargs da fábrica |
| Configuração do servidor | docker/sim/configs/<benchmark>.yaml | Os kwargs de tarefa e fábrica usados pelo servidor e pelo CI |
| Imagem do simulador | docker/Dockerfile.sim | Uma etapa <benchmark>_native: dependências nativas fixadas (incluindo qualquer toolkit CUDA, já que a base é Ubuntu puro) e revisões de ativos; a etapa final adiciona o servidor |
| Manifesto de CI | benchmarks/benchmarks.yaml | Nome, tarefas, revisão do checkpoint, câmera rename_map e parity opcional; o restante é definido por padrão a partir do nome |
| Dependências | pyproject.toml | Grupo de dependências opcionais para uso local |
| Documentação | docs/source/<benchmark>.mdx, _toctree.yml | Uma página voltada para o usuário |
| Proveniência | docs/source/<benchmark>.mdx | Repositórios de origem, revisões de código e ativos fixados com suas licenças, e uma taxa de sucesso publicada para um checkpoint que você pode executar |
Ambos os caminhos expõem o mesmo comportamento de ambiente:
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
Coloque a orientação da imagem, a conversão de quaterniões e a ordem do estado no adaptador canonical_observation() daquele simulador, e suas convenções de controle em seu conventions(), para que a avaliação e o rollout estejam em concordância. Reutilize sim/integrations/utils.py apenas para mapeamentos compartilhados pelas integrações; o código de ambiente compartilhado não deve fazer ramificações com base nos nomes dos simuladores. Um novo benchmark não precisa de um environment processor: as observações chegam aos próprios processadores da política já em forma canônica.
Como as execuções de avaliação funcionam
lerobot-eval avalia todos os benchmarks da mesma forma:
make_env()constrói o dicionário aninhado{suite: {task_id: vector env}}.eval_policy_all()executan_episodesrollouts de cada tarefa, uma tarefa por vez (ou--env.max_parallel_taskspor vez).- Os resultados são agregados por episódio, tarefa, suíte e no geral:
pc_success(taxa de sucesso),avg_sum_rewardeavg_max_reward. Cada taxa de sucesso vem acompanhada de suas contagens (n_successden_episodes) e de um intervalo de Wilson de 95% em porcentagem (pc_success_ci95). O intervalo cobre apenas o ruído de amostragem entre episódios; não diz nada sobre a variação entre execuções de treinamento da mesma receita.
O sucesso vem de info["is_success"], que seu ambiente relata a cada step(). Seu ambiente também pode relatar números próprios. Ele os coloca em info["metrics"], um mapa de cada nome para um float por ambiente. Eles chegam à entrada de cada episódio sob per_episode[i]["metrics"], obtidos no passo em que o episódio terminou.
O que seu ambiente deve fornecer
Estrutura do ambiente
env_fns() retorna as fábricas de ambiente de cada tarefa, sem instanciá-las:
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."""Um benchmark de tarefa única retorna {"<task>": {0: [...]}}; um de múltiplas tarefas (como LIBERO) retorna {"libero_spatial": {0: [...], 1: [...], ...}, ...}. O LocalVectorEnv chama cada fábrica make_single_env no primeiro uso, localmente ou no servidor e, com --eval.use_async_envs=true, em um processo separado por ambiente.
O 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 | Encerra (trunca) um episódio |
task_description | str | Passado às políticas VLA como uma instrução de linguagem |
task | str | Identificador de fallback caso task_description não esteja definido |
step() relata sucesso em info["is_success"], e qualquer outra coisa que mede em info["metrics"]. As ações são uma Box contínua unidimensional.
As observações são um dict que o adaptador canonical_observation() da integração compreende. O adaptador padrão reutilizável mapeia:
| Saídas do seu env | Chave canônica | O que é |
|---|---|---|
"pixels" (array único) | observation.image | Imagem de câmera única, HWC uint8 |
"pixels" (dict) | observation.images.<cam> | Várias câmeras, cada uma HWC uint8 |
"agent_pos" | observation.state | Vetor de estado proprioceptivo |
"environment_state" | observation.environment_state | Estado completo do ambiente (ex.: PushT) |
Qualquer outro array é passado como observation.<key>. Renomeie as saídas do seu simulador para essas chaves dentro do gym.Env, ou trate sua representação nativa no adaptador dessa integração.
Simuladores baseados em GPU (por exemplo, MuJoCo com renderização EGL): se o seu simulador alocar contextos de GPU/EGL durante o __init__, adie essa alocação para um auxiliar _ensure_env() chamado no primeiro reset()/step(), para que um ambiente construído em um processo de worker não herde handles de GPU obsoletos. Veja LiberoEnv._ensure_env() para o padrão.
Convenções ( conventions() na integração)
Retorna a taxa de controle, o controlador e os nomes ordenados dos componentes do simulador a partir de conventions(kwargs), uma função das opções do simulador (elas podem depender de um modo de ação, como no RoboTwin). Elas preenchem as configurações que uma configuração omite e nomeiam os componentes de estado e ação para robôs, conjuntos de dados e checkpoints. semantics tem como padrão <type>-<control>-v1. robot_type nomeia o corpo simulado, registrado por um robô de simulação: o tipo que o robô real registra quando o lerobot possui uma classe para ele (so_follower), caso contrário, um nome curto (panda, sawyer); se omitido, os conjuntos de dados registram sim_robot.
A configuração ( src/lerobot/envs/configs.py )
Registre uma configuração para que os usuários possam selecionar seu benchmark com --env.type=<name> (e --robot.env.type=<name>). Seu sim_settings() descreve o simulador como a seção sim de um YAML de servidor; LocalVectorEnv faz o 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}}Mantenha os padrões e os do YAML do servidor em conformidade: uma avaliação servida recusa um servidor que executa um ambiente diferente do descrito pelo comando. Os recursos vêm da descrição do ambiente quando ele é criado, portanto a configuração não declara nenhum.
Admissão de checkpoint
--rename_map cria aliases para as chaves de câmera do ambiente, mapeando-as para as chaves treinadas no checkpoint, como para qualquer robô; no CI, ele vem do campo rename_map da entrada em benchmarks/benchmarks.yaml. As entradas do checkpoint devem existir após a renomeação, e as dimensões de estado/ação devem corresponder; a renomeação não pode reparar metadados do checkpoint. A contagem e o layout dos canais RGB são verificados na admissão. A altura/largura de aquisição pode diferir dos metadados de treinamento; o redimensionamento pertence ao pré-processamento da política.
Verificação e CI
- Verifique o adaptador de observação da integração contra as saídas brutas do seu simulador, especialmente a orientação da câmera e a ordem do estado, e verifique as ações aplicadas pelo wrapper do ambiente.
- Compare as sequências de reset/step com seed localmente e servidas (
scripts/ci/check_sim_parity.py); definaparity: truena entrada do manifesto de um simulador determinístico para que o CI o execute. Verifique o congelamento do terminal, o sucesso, o comprimento do episódio, a renderização e a limpeza de recursos. - Execute os guards de importação com torch desativado para o código do servidor e seu módulo nativo. Documente os simuladores que precisam de seu próprio runtime de torch, como RoboTwin e RoboMME.
- Execute
lerobot-eval --env.type=<name> --env.task=<task> --eval.n_episodes=1 --policy.path=<checkpoint>localmente e, com--env.server.endpoint, contra o servidor. Inspecione as descrições das tarefas e as visualizações renderizadas das câmeras. - Execute o job de benchmark gerado no runner de GPU. Preserve o smoke de treinamento do LIBERO ao alterar a integração compartilhada de avaliação/treinamento.
benchmarks/benchmarks.yaml gera a matriz por meio de scripts/ci/benchmark_matrix.py; .github/workflows/benchmark_run.yml executa cada entrada. Adicione entradas ao manifesto em vez de copiar jobs de CI. O CI limita os episódios para verificar o pipeline de ponta a ponta; seu metrics.json registra a revisão do checkpoint, a tag da imagem do simulador, o commit e o limite, e marca essas execuções como smoke: suas taxas de sucesso não são pontuações de política. As imagens do simulador têm pins e tags de conteúdo separados; o cache do BuildKit persiste apenas em runners persistentes.
Alterando um benchmark
A canonical_observation(), as conventions() e o wrapper de ambiente de uma integração decidem o que a política vê e como suas ações são aplicadas. Uma orientação de imagem, ordem de estado ou taxa de controle incorreta não causa uma falha: a política recebe entradas ligeiramente incorretas e sua taxa de sucesso diminui. Uma alteração em qualquer um deles vem acompanhada de:
- Um teste de regressão que compara as saídas antigas e novas em uma observação gravada ou sintética.
test_libero_numpy_adapter_parityemtests/sim/integrations/test_libero.pyé o modelo: ele mostra que o adaptador LIBERO sem torch produz exatamente o que o processador LIBERO anterior fazia. - O efeito esperado nas pontuações no pull request: nenhum, ou quais pontuações devem mudar e por quê.
Dependências ( pyproject.toml )
Adicione um novo grupo de dependências opcionais para uso local:
mybenchmark = ["my-benchmark-pkg==1.2.3", "lerobot[scipy-dep]"]Regras de fixação:
- Sempre fixe os pacotes de benchmark em versões exatas para reprodutibilidade (por exemplo,
metaworld==3.0.0). - Adicione marcadores de plataforma quando necessário (por exemplo,
; sys_platform == 'linux'). - Fixe as dependências transitórias frágeis, se conhecido (por exemplo, a imagem do Meta-World fixa
mujoco==3.15.0, pois o MuJoCo 3.17 quebra seus soldas de mocap). - Restrições do documento na página do documento do seu benchmark. Quando as dependências conflitam com as do LeRobot, o caminho servido é o suportado.
Escrevendo uma página de documentação de benchmark
Adicione a página à seção “Benchmarks” de docs/source/_toctree.yml. Cada página de benchmark deve incluir:
- Título e descrição — 1 a 2 parágrafos sobre o que o benchmark testa e por que ele é importante.
- Links — paper, repositório no GitHub, site do projeto (se disponível).
- Proveniência e licenças — repositórios de origem, revisões fixas de código e ativos, e a licença de cada um. Não adicione um benchmark cuja licença proíba o uso.
- Imagem ou GIF de visão geral.
- Tarefas disponíveis — tabela de suítes de tarefas com contagens e descrições breves.
- Instalação —
pip install -e ".[<benchmark>]", ou o comando do servidor. - Avaliação — comando
lerobot-evalrecomendado comn_episodespara resultados reproduzíveis. - Entradas e saídas da política — chaves de observação com formas, descrição do espaço de ações.
- Treinamento — exemplo do comando
lerobot-train. - Resultados de referência — a taxa de sucesso publicada de pelo menos um checkpoint pré-treinado que você pode executar, com sua revisão e o comando
lerobot-evalque o reproduz. Uma integração que não se aproxima disso não está concluída.
Veja docs/source/libero.mdx e docs/source/metaworld.mdx para exemplos completos.