LeRobot documentation
정책 추가
정책 추가
이 가이드는 커스텀 정책을 구현하고 LeRobot의 학습, 평가, 배포 도구와 함께 작동하도록 설정하는 과정을 안내합니다. 두 가지 경로가 있습니다:
- 플러그인(트리 외부) — 정책을 독립적인
lerobot_policy_*패키지로 배포합니다. 더 빠르고 PR이 필요 없으며 반복 작업이 쉽습니다. 실험, 내부 사용 또는 독립적으로 게시하려는 경우에 적합합니다. - 트리 내부(LeRobot에 기여) — 정책을
src/lerobot/policies/에 직접 추가합니다. PR이 필요하지만, 이를 통해 해당 정책은 라이브러리의 1급 시민이 됩니다.
플러그인 루트는 일반적으로 올바른 시작점입니다. 정책이 안정화되고 라이브러리와 함께 배포하는 것이 명확한 가치를 가질 때 트리 내부로 승격하세요.
어떤 경우든 기본 구성 요소는 동일합니다: 설정 클래스, 정책 클래스, 프로세서 팩토리입니다. 이 가이드의 첫 번째 절반은 이러한 공유된 부분을 다루며, 두 번째 절반은 경로별 스캐폴딩(Path A, Path B)를 다룹니다.
톤에 대한 참고: robot-learning은 활발하게 발전 중인 분야이며, “정책(policy)의 형태”는 새로운 아키텍처마다 달라질 수 있습니다. 여기 설명된 관례는 lerobot-train과 lerobot-eval이 매우 다른 모델들에서도 일관되게 작동할 수 있게 하기 위해 존재합니다. 새로운 정책이 실제로 이 관례에 맞지 않는다면, 이를 제기해 주세요(PR이나 이슈로). 관례는 신성하지 않습니다.
정책의 구조
모든 정책은 세 가지 구성 요소로 이루어져 있습니다. 아래 이름은 my_policy를 플레이스홀더로 사용합니다. 자신의 정책 이름으로 교체하세요. 이 이름은 핵심적인 역할을 합니다. @PreTrainedConfig.register_subclass에 전달하는 문자열, MyPolicy.name 클래스 속성, 그리고 make_<name>_pre_post_processors 팩토리 함수(각 항목에 대한 자세한 내용은 아래를 참조)와 정확히 일치해야 합니다.
구성 클래스
PreTrainedConfig를 상속하고 정책 유형을 등록하세요. 아래는 템플릿입니다. 정책의 아키텍처와 학습 요구 사항에 맞게 매개변수와 메서드를 필요에 따라 수정하세요.
# configuration_my_policy.py
from dataclasses import dataclass, field
import torch
from lerobot.configs import PreTrainedConfig
from lerobot.optim import AdamWConfig
from lerobot.optim import CosineDecayWithWarmupSchedulerConfig
@PreTrainedConfig.register_subclass("my_policy")
@dataclass
class MyPolicyConfig(PreTrainedConfig):
"""Configuration class for MyPolicy.
Args:
n_obs_steps: Number of observation steps to use as input
horizon: Action prediction horizon
n_action_steps: Number of action steps to execute
hidden_dim: Hidden dimension for the policy network
# Add your policy-specific parameters here
"""
dtype: torch.dtype | None = torch.bfloat16
horizon: int = 50
n_action_steps: int = 50
hidden_dim: int = 256
optimizer_lr: float = 1e-4
optimizer_weight_decay: float = 1e-4
def __post_init__(self):
super().__post_init__()
if self.n_action_steps > self.horizon:
raise ValueError("n_action_steps cannot exceed horizon")
def validate_features(self) -> None:
"""Validate input/output feature compatibility.
Call this explicitly from your policy's __init__ — the base class does not.
"""
if not self.image_features:
raise ValueError("MyPolicy requires at least one image feature.")
if self.action_feature is None:
raise ValueError("MyPolicy requires 'action' in output_features.")
def get_optimizer_preset(self) -> AdamWConfig:
return AdamWConfig(lr=self.optimizer_lr, weight_decay=self.optimizer_weight_decay)
def get_scheduler_preset(self):
"""Return a LRSchedulerConfig from lerobot.optim, or None."""
return None
@property
def observation_delta_indices(self) -> list[int] | None:
"""Relative timestep offsets the dataset loader provides per observation.
Return `None` for single-frame policies. For temporal policies that consume
multiple past or future frames, return a list of offsets, e.g. `[-20, -10, 0, 10]` for
3 past frames at stride 10 and 1 future frame at stride 10.
"""
return None
@property
def action_delta_indices(self) -> list[int]:
"""Relative timestep offsets for the action chunk the dataset loader returns."""
return list(range(self.horizon))
@property
def reward_delta_indices(self) -> None:
return None@register_subclass에 전달하는 문자열은 MyPolicy.name(다음 섹션)과 일치해야 하며, 사용자가 CLI에서 --policy.type로 제공하는 값입니다. get_optimizer_preset의 기본값은 lerobot.optim의 AdamW로 설정하십시오. 실제로 다른 값이 필요한 경우가 아니라면 변경하지 마십시오. PreTrainedConfig에는 이미 dtype: torch.dtype | None이 선언되어 있습니다. 정책에 기본 정밀도를 지정하려면 torch.dtype 값(예: dtype: torch.dtype | None = torch.bfloat16)으로 다시 선언하십시오.
Policy 클래스
PreTrainedPolicy를 상속받고 두 개의 클래스 속성을 설정하세요. 두 속성 모두 __init_subclass__에서 확인됩니다:
# modeling_my_policy.py
import torch
import torch.nn as nn
from typing import Any
from lerobot.policies import PreTrainedPolicy
from lerobot.utils.constants import ACTION
from .configuration_my_policy import MyPolicyConfig
class MyPolicy(PreTrainedPolicy):
config_class = MyPolicyConfig # must match the string in @register_subclass
name = "my_policy"
def __init__(self, config: MyPolicyConfig, dataset_stats: dict[str, Any] = None):
super().__init__(config, dataset_stats)
config.validate_features() # not called automatically by the base class
self.config = config
self.model = ... # your nn.Module here
def reset(self):
"""Reset per-episode state. Called by lerobot-eval at the start of each episode."""
...
def get_optim_params(self) -> dict:
"""Return parameters to pass to the optimizer (e.g. with per-group lr/wd)."""
return {"params": self.parameters()}
def predict_action_chunk(self, batch: dict[str, torch.Tensor], **kwargs) -> torch.Tensor:
"""Return the full action chunk (B, chunk_size, action_dim) for the current observation."""
...
def select_action(self, batch: dict[str, torch.Tensor], **kwargs) -> torch.Tensor:
"""Return a single action for the current timestep (called every step at inference)."""
...
def forward(self, batch: dict[str, torch.Tensor]) -> tuple[torch.Tensor, dict | None]:
"""Compute the training loss.
Returns `(loss, output_dict)`. `output_dict` may be `None`; everything in it must be
logging-friendly Python natives (no tensors with gradients).
`batch["action_is_pad"]` is a bool mask of shape (B, horizon) that marks
timesteps padded because the episode ended before `horizon` steps; you
can exclude those from your loss.
"""
actions = batch[ACTION]
action_is_pad = batch.get("action_is_pad")
...
return loss, {"some_loss_component": some_loss_component.item()}train/eval 루프에서 호출되는 메서드:
| 메서드 | 사용 | 기능 |
|---|---|---|
reset() -> None | lerobot-eval | 각 에피소드 시작 시 에피소드별 상태를 초기화합니다. |
select_action(batch, **kwargs) -> Tensor | lerobot-eval | 다음 동작 (B, action_dim)을 반환합니다. 매 스텝마다 호출됩니다. |
predict_action_chunk(batch, **kwargs) -> Tensor | 정책 자체 | 액션 청크 (B, chunk_size, action_dim)을 반환합니다. 현재 베이스 클래스에서는 추상적으로 정의되어 있으며, 정책이 청킹을 지원하지 않으면 NotImplementedError를 발생시킵니다. |
forward(batch, reduction="mean") -> tuple[Tensor, dict \| None] | lerobot-train | (loss, output_dict)을 반환합니다. 샘플별 가중치를 지원하려면 reduction="none"을 허용해야 합니다. |
get_optim_params() -> dict | 옵티마이저 | 단일 정책의 경우 self.parameters()를 반환하고, 다중 옵티마이저 정책의 경우 이름이 지정된 파라미터 딕셔너리를 반환합니다(그룹별 학습률 예제는 modeling_act.py의 get_optim_params를 참조하세요). |
update() -> None (선택 사항) | lerobot-train | 정의된 경우 if defined 각 옵티마이저 스텝 이후에 호출됩니다. EMA, 타깃 네트워크, 리플레이 버퍼(TDMPC는 이 기능을 사용합니다)에 사용하세요. |
Batches는 lerobot.utils.constants의 상수를 키로 하는 평탄한 딕셔너리입니다: OBS_STATE (observation.state.<motor>), OBS_IMAGES (observation.images.<camera>), OBS_LANGUAGE, ACTION 등. 상수를 재사용하고 새로운 접두사를 만들지 마세요.
모델이 sharded multi-GPU training이 필요한 수준으로 충분히 크다면, sharding이 적용되는 반복 블록 클래스인 FSDP wrap units도 선언해야 합니다:
class MyPolicy(PreTrainedPolicy):
...
_fsdp_wrap_modules = ["MyTransformerBlock"]이 하나의 선언으로 --parallelism.dp_shard=N은 정책에서 바로 작동합니다(사용자는 여전히 --accelerator.fsdp.wrap_modules로 이를 재정의할 수 있습니다). wrap 소스가 없으면, sharded 실행은 설계상 시작 시점에 실패합니다.
Processor 함수
LeRobot는 정책을 중심으로 입력을 정규화하고 출력을 역정규화하기 위해 PolicyProcessorPipeline을 사용합니다. 구체적인 참고 예로는 processor_act.py 또는 processor_diffusion.py를 확인하세요.
여기서 특히 주의하세요: 프로세서가 재현성(reproducibility) 문제의 가장 흔한 원인입니다. 정규화 모드(IDENTITY와 MEAN_STD, MIN_MAX, QUANTILES/QUANTILE10 중 하나)나 정규화 대상 특징이 서로 일치하지 않으면 학습과 평가는 에러 없이 진행되지만, 결과가 조용히 망가집니다. 체크포인트가 학습된 방식과 모드가 일치하는지, 필요한 통계 값이 존재하는지(예: QUANTILES에는 q01/q99가 필요함), 그리고 전처리 및 후처리 프로세서가 일관되게 유지되는지 확인하세요.
# processor_my_policy.py
from typing import Any
import torch
from lerobot.processor import PolicyAction, PolicyProcessorPipeline
def make_my_policy_pre_post_processors(
config,
dataset_stats: dict[str, dict[str, torch.Tensor]] | None = None,
) -> tuple[
PolicyProcessorPipeline[dict[str, Any], dict[str, Any]],
PolicyProcessorPipeline[PolicyAction, PolicyAction],
]:
preprocessor = ... # build your PolicyProcessorPipeline for inputs
postprocessor = ... # build your PolicyProcessorPipeline for outputs
return preprocessor, postprocessor중요 — 함수 이름: LeRobot은 이름으로 프로세서를 찾습니다. 함수는 반드시 make_{policy_name}_pre_post_processors로 호출되어야 합니다(@PreTrainedConfig.register_subclass에 전달한 문자열과 일치해야 함).
선택 사항: 체크포인트에서 로드된 프로세서 조정
make_{policy_name}_pre_post_processors는 프로세서가 처음부터 구축될 때만 실행됩니다. 체크포인트가 관여하는 경우(파인튜닝, 재개, 평가)에는 LeRobot이 대신 가중치 옆에 직렬화된 파이프라인을 로드하고 호출자의 오버라이드를 적용합니다.
정책이 로드된 파이프라인을 조정해야 하는 경우, 동일한 모듈에 make_{policy_name}_pre_post_processors_from_pretrained라는 선택적 두 번째 함수를 추가하세요. LeRobot은 동일한 네이밍 컨벤션을 통해 해당 함수를 찾아 일반 load 대신 호출합니다. 특별한 조정이 필요 없는 정책은 해당 함수를 생략하면 됩니다.
from lerobot.processor import load_pretrained_policy_processors
from lerobot.utils.constants import (
POLICY_POSTPROCESSOR_DEFAULT_NAME,
POLICY_PREPROCESSOR_DEFAULT_NAME,
)
def make_my_policy_pre_post_processors_from_pretrained(
config,
pretrained_path: str,
*,
revision: str | None = None,
dataset_stats: dict[str, dict[str, torch.Tensor]] | None = None,
dataset_meta: Any | None = None,
preprocessor_overrides: dict[str, Any] | None = None,
postprocessor_overrides: dict[str, Any] | None = None,
preprocessor_config_filename: str = f"{POLICY_PREPROCESSOR_DEFAULT_NAME}.json",
postprocessor_config_filename: str = f"{POLICY_POSTPROCESSOR_DEFAULT_NAME}.json",
) -> tuple[
PolicyProcessorPipeline[dict[str, Any], dict[str, Any]],
PolicyProcessorPipeline[PolicyAction, PolicyAction],
]:
preprocessor, postprocessor = load_pretrained_policy_processors(
pretrained_path,
revision=revision,
preprocessor_overrides=preprocessor_overrides,
postprocessor_overrides=postprocessor_overrides,
preprocessor_config_filename=preprocessor_config_filename,
postprocessor_config_filename=postprocessor_config_filename,
)
... # reconcile the loaded pipelines with the current `config`
return preprocessor, postprocessor작동하는 예제는 processor_evo1.py(re-pads 정규화 통계), processor_groot.py(원본 업스트림 체크포인트 처리), processor_molmoact2.py(오버라이드 키 이름 변경)를 참고하세요.
액션 외에 예측 반환(상상된 프레임, 하위 작업, 박스)
정책은 수행하는 동작 외에도 예상하거나 믿는 내용을 반환할 수 있습니다. 예를 들어, 월드 모델의 상상된 프레임, 예측된 서브태스크 또는 바운딩 박스 등이 있습니다. --display_data는 이를 Rerun 또는 Foxglove에서 실시간으로 표시합니다. select_action와 predict_action_chunk는 배치(batch)를 입력으로 받아, 단순한 동작 텐서(모든 정책의 기본값) 또는 PolicyOutput (lerobot.lerobot_types)를 반환합니다. PolicyOutput은 입력 배치와 동일한 키 구조를 가진 배치로, "action" 키 아래에 동작이, "prediction" 키 아래에 PolicyPrediction가 포함됩니다. 예측 값은 동작과 마찬가지로 배치 처리되며, 환경별로 하나의 값을 가지며, 모든 항목은 해당 항목이 가리키는 대상에 따라 키가 지정됩니다:
observation: observation 키별 예측된 미래 observation ("observation.images.top"->[B, C, H, W]프레임).prediction.images.top으로 표시됩니다.language: 환경별로 하나씩, 어노테이션 스타일("subtask","plan","memory")에 따라 지정되며, 어노테이션 파이프라인의 언어 컬럼 스타일입니다.prediction.subtask로 표시됩니다.boxes: 관찰 이미지 키에 따라 그려지며, 각 환경마다 annotation VQA 스키마({"detections": [{"label", "bbox": [x1, y1, x2, y2]}]}, 이미지 비율 0~1)에서 하나의 bbox 답변을 가집니다.
호출자는 policy_output_to_transition를 사용하여 두 가지 반환 유형을 정규화합니다. 이 함수는 PolicyOutput을 프로세서가 사용하는 EnvTransition으로 변환하므로, 예측하는 것이 있는 정책만 변경됩니다. 뷰어는 첫 번째 환경을 표시합니다.
from lerobot.utils.constants import ACTION, PREDICTION
class MyPolicy(PreTrainedPolicy):
def select_action(self, batch, **kwargs) -> Tensor | PolicyOutput:
if not self._action_queue:
chunk, extras = self.model.sample(batch)
self._action_queue.extend(chunk.transpose(0, 1))
if self.config.return_prediction: # a config field of your choosing
# The prediction goes with the step that computed it; the others return a bare action.
prediction = {
"observation": {"observation.images.top": extras.next_frames}, # [B, C, H, W]
"language": {"subtask": extras.subtasks}, # list[str], one per env
"boxes": {
"observation.images.top": [
{"detections": [{"label": "cube", "bbox": xyxy}]} for xyxy in extras.cube_xyxy
]
},
}
return {ACTION: self._action_queue.popleft(), PREDICTION: prediction}
return self._action_queue.popleft()- prediction은 해당 단계의 값을 포함합니다. chunk에 걸쳐 있는 예측, 예를 들어 상상된 클립과 같은 경우, 조각별로 반환됩니다. 각 단계는 해당 동작에 대응하는 부분을 반환합니다.
- 각 항목은 다시 반환될 때까지 계속 표시됩니다. 카메라의 박스를 지우려면 빈
detections를 반환하세요. - Predicting은 정책의 config를 통해 선택적으로 활성화되며, 비활성화 상태에서는 비용이 발생하지 않아야 합니다.
- 예측은 동작을 변경하지 않으며, 후처리(postprocessor)를 통과하는 것은 동작뿐입니다. 정책을 유도해야 하는 텍스트, 예를 들어 다음 하위 작업은
generate_text(아래)를 통해 처리됩니다.
텍스트 지원 정책
Language policies는 두 개의 프로세서 단계 간에 레시피 렌더링을 공유합니다:
RenderTrainingMessagesStep는 데이터셋의 언어 주석을 렌더링된 메시지로 변환합니다.RenderRuntimeMessagesStep은 사용자 프롬프트를 렌더링된 메시지로 변환합니다.
정책별 프로세서가 채팅 포맷팅과 토큰화를 적용합니다.
policy config는 lerobot.datasets.recipe에서 가져온 해결된 recipe: TrainingRecipe | None을 저장합니다. 선택적인 recipe_path를 사용하여 YAML 레시피를 로드할 수 있으며, 프로세서 생성 전에 이를 해결해야 합니다. 해결된 레시피는 레시피 기반 학습을 활성화하고, None은 학습 렌더러를 no-op로 만듭니다. 배포가 로컬 YAML 경로에 의존하지 않도록 설정과 프로세서에 해결된 레시피를 직렬화합니다. 레시피 기반 렌더링은 현재 레시피가 lerobot.datasets 아래에 위치하기 때문에 dataset extra가 필요합니다.
policy 네이티브 채팅 포맷팅 및 토큰화 전에 두 렌더러를 모두 배치하세요:
input_steps = [
RenderRuntimeMessagesStep(config.recipe),
RenderTrainingMessagesStep(config.recipe),
# observation transforms
# policy-native roles, image placement, chat template, and tokenization
# device placement
]동일한 파이프라인이 학습 및 추론을 위해 저장되고 로드됩니다. 런타임 렌더링은 명시적인 query_kind에 대해서만 실행됩니다. 학습 렌더링은 런타임 쿼리를 건너뛰고, 레시피가 구성된 경우 원시 주석 또는 액션 타겟을 가진 샘플을 처리합니다. 일반적인 관찰 전용 입력은 그대로 통과합니다. 액션 텐서 없이 주석된 텍스트 전용 학습이 지원됩니다. 주석 없이 학습하려면 태스크 폴백을 활성화하기 위해 액션 타겟이 필요합니다.
공유 팩토리는 프로세서만 구성하거나 로드합니다. 언어 레시피의 파인튜닝은 활성 config와 데이터셋 통계로부터 프로세서를 구성하므로, 저장된 프로세서가 새로운 레시피를 오버라이드할 수 없습니다. Resume 및 추론은 저장된 파이프라인을 로드하며, 여기에는 해당 레시피와 통계가 포함됩니다. 비언어 학습은 기존 구성 및 체크포인트 로드 동작을 유지합니다. 새로운 팩토리는 정규화 및 상대 동작 설정을 자체적으로 파생합니다. 새로운 팩토리는 구성된 장치를 사용하며, 기존 데이터셋 배치 전처리에서는 학습 rename map을 적용합니다.
messages_rendered에는 네이티브 채팅 포맷팅이나 토큰화 전에 레시피가 확장된 의미론적 메시지가 포함됩니다. 학습 사이드카는 이 동일한 목록을 인덱싱합니다. 메시지 헬퍼는 lerobot.utils.language에 있습니다.
인터랙티브 롤아웃은 query_kind와 query_text를 추가합니다. 런타임 렌더링은 다음을 지원합니다:
vqa: 호출자의 질문을 사용자 메시지로 유지합니다.next_subtask:${subtask}을 감독하는 어시스턴트 턴을 포함하지 않고, 체크포인트 레시피를 렌더링합니다.
정책은 기존 정책 API를 통해 디코더를 노출합니다:
class MyPolicy(PreTrainedPolicy):
def supports_text_generation(self) -> bool:
return True
def generate_text(self, batch) -> str:
token_ids = self.model.generate(**batch)
return self.tokenizer.decode(token_ids, skip_special_tokens=True)generate_text는 모델이 사용할 수 있는 프로세서 출력을 소비합니다. 호출자의 프롬프트를 다시 구성하거나 재토큰화해서는 안 됩니다. 학습 중에 정책 네이티브 토크나이저는 target_message_indices를 사용하여 선택된 어시스턴트 스팬만 감독합니다. 레시피를 언어 정책의 config에 저장하여 체크포인트와 함께 직렬화되고 배포 시 학습에 사용된 프롬프트가 재구성되도록 하세요.
경로 A: 트리 외부 플러그인
정책을 배포하는 가장 빠른 방법: 정책을 독립적인 Python 배포 패키지로 패키징하여 LeRobot과 함께 설치합니다. PR이 필요하지 않으며, 릴리스 주기를 직접 관리할 수 있고, 자신의 네임스페이스로 PyPI에 게시할 수 있습니다.
패키지 구조
lerobot_policy_ 접두사(중요!) 뒤에 정책 이름을 붙여 패키지를 생성하세요:
lerobot_policy_my_policy/
├── pyproject.toml
└── src/
└── lerobot_policy_my_policy/
├── __init__.py
├── configuration_my_policy.py
├── modeling_my_policy.py
└── processor_my_policy.pypyproject.toml
[project]
name = "lerobot_policy_my_policy"
version = "0.1.0"
dependencies = [
# your policy-specific dependencies
]
requires-python = ">= 3.12"
[build-system]
build-backend = # your-build-backend
requires = # your-build-system패키지 __init__.py
패키지의 __init__.py에서 클래스를 노출하고 lerobot이 없는 경우를 방지하세요:
# __init__.py
"""Custom policy package for LeRobot."""
try:
import lerobot # noqa: F401
except ImportError:
raise ImportError(
"lerobot is not installed. Please install lerobot to use this policy package."
)
from .configuration_my_policy import MyPolicyConfig
from .modeling_my_policy import MyPolicy
from .processor_my_policy import make_my_policy_pre_post_processors
__all__ = [
"MyPolicyConfig",
"MyPolicy",
"make_my_policy_pre_post_processors",
]설치 및 사용
cd lerobot_policy_my_policy
pip install -e .
# Or install from PyPI if published
pip install lerobot_policy_my_policy설치 후, 정책은 LeRobot의 학습 및 평가 도구와 자동으로 통합됩니다:
lerobot-train \
--policy.type my_policy \
--dataset.repo_id lerobot/pusht \
--env.type pusht \
--steps 200000 \
--policy.push_to_hub false경로 B: 인트리 기여
정책이 안정화되었고 라이브러리에 포함할 명확한 가치가 있다면, LeRobot에 직접 반영할 수 있습니다. 먼저 일반적인 기여 가이드와 PR 템플릿을 읽어보세요. 모든 PR이 충족해야 하는 테스트/품질 기준(pre-commit run -a, pytest, 커뮤니티 리뷰 규칙 등)이 여기에 명시되어 있습니다. 아래 내용은 그 위에 추가되는 정책 전용 레이어입니다.
트리 내부 레이아웃
src/lerobot/policies/my_policy/
├── __init__.py # re-exports config + modeling + processor factory
├── configuration_my_policy.py # MyPolicyConfig + @register_subclass
├── modeling_my_policy.py # MyPolicy(PreTrainedPolicy)
├── processor_my_policy.py # make_my_policy_pre_post_processors
└── README.md # symlink → ../../../../docs/source/policy_my_policy_README.md두 가지 참고 사항:
- 소스 옆의
README.md는docs/source/policy_<name>_README.md로 향하는 심볼릭 링크입니다 — 실제 파일은docs/아래에 있습니다. 기존 정책(act, smolvla, diffusion, …)은 모두 이렇게 구성되어 있으므로, 해당 심볼릭 링크 중 하나를 복사하세요. 정책 README는 관례적으로 최소한의 내용, 즉 논문 링크와 BibTeX 인용 정보를 포함합니다. - 사용자 대상 튜토리얼 — 설치할 항목, 학습 방법, 하이퍼파라미터, 벤치마크 수치 — 은
docs/source/<my_policy>.mdx에 별도로 있으며,_toctree.yml의 “Policies” 아래에 등록됩니다.
파일 이름이 중요합니다. 팩토리는 이름 기반으로 지연 가져오기를 수행하며, 프로세서가 make_<policy_name>_pre_post_processors 규칙에 따라 발견됩니다.
연결
정책에 대해 두 가지 위치가 인식해야 합니다. 모두 이름으로 지정해야 합니다.
policies/__init__.py—MyPolicyConfig를 재수출하고__all__에 추가합니다. 이 import가 정책을 등록하는 부분입니다:@PreTrainedConfig.register_subclass("my_policy")가 실행되고, 이후로는 팩토리가 컨벤션에 따라 모든 것을 해석합니다. 모델링 클래스는 재수출하지 마세요. 팩토리를 통해 지연 로드되므로(import lerobot이 빠르도록 유지됩니다).templates/lerobot_modelcard_template.md와 루트README.md입니다. 이 템플릿은 정책으로 학습된 모든 체크포인트의 모델 카드로 렌더링되는 파일입니다.model_name브랜치에 정책을 한 줄로 설명하고,policy_docs에 매핑하여 카드가 MDX 가이드로 링크되도록 하세요. 또한diagrams에 아키텍처 이미지를 선택적으로 추가할 수 있습니다. 그런 다음 루트README.md의 모델 테이블에 정책을 올바른 카테고리에 추가하고, 문서 페이지로 링크를 걸어야 합니다.
구조적으로 유사한 기존 정책을 복제하세요. 차이점은 작습니다.
무겁거나 선택적인 의존성
대부분의 정책은 무거운 백본(트랜스포머, 디퓨저, 특정 VLM SDK)이 필요합니다. 해당 백본이 이미 존재하는 경우, 트리에 아키텍처를 다시 구현하는 것보다 transformers 또는 diffusers 등에서 로드하는 방식을 우선적으로 사용하세요.
관례는 2단계 게이팅입니다: 모듈 상단에 TYPE_CHECKING으로 가드된 import와, 생성자 내의 require_package 런타임 체크입니다. modeling_diffusion.py가 표준 참고 예입니다:
from typing import TYPE_CHECKING
from lerobot.utils.import_utils import _diffusers_available, require_package
if TYPE_CHECKING or _diffusers_available:
from diffusers.schedulers.scheduling_ddim import DDIMScheduler
else:
DDIMScheduler = None # keeps the symbol bindable at import time
class DiffusionPolicy(PreTrainedPolicy):
def __init__(self, config):
require_package("diffusers", extra="diffusion")
super().__init__(config)
...이렇게:
import lerobot.policies는 추가 설치 없이도 계속 작동하며(해당 심볼은 단순히None에 바인딩됩니다).- 타입 체커는 실제 심볼을 확인합니다.
- 추가 항목 없이 정책을 인스턴스화하면
pip install 'lerobot[diffusion]'을 가리키는 명확한ImportError가 발생합니다.
[project.optional-dependencies] 섹션에 pyproject.toml 파일에 일치하는 extra를 추가하고, pip install 'lerobot[all]' 명령으로 모든 것이 설치되도록 유지하려면 all extra에 포함하세요.
모델링 파일을 복사하지 마세요 — 서브클래스로 만드세요
정책이 transformers에 이미 존재하는 백본을 수정해야 하는 경우(커스텀 컨디셔닝, 추가 입력, 서브모듈 교체 등)에는 해당 modeling_*.py의 사본을 벤더링하지 마세요. 대신 가장 작은 상위 유닛을 서브클래스로 상속받아 변경되는 부분만 오버라이드하세요. pi_gemma.py가 표준적인 참고 예시입니다. 이 파일은 약 2,000줄에 달하는 모델링 파일을 포크하는 대신, GemmaModel/PaliGemmaModel을 서브클래스로 상속하고 디코더 레이어의 포워드를 오버라이드하여 약 370줄로 PaliGemma/Gemma에 AdaRMS 컨디셔닝을 주입합니다. 로드된 네이티브 모델에 대한 모델 수술(레이어 절단, 토크나이저 확장, 히든 스테이트 캡처 등)도 허용됩니다(작동하는 예시로 evo1/internvl3_embedder.py, eo1/modeling_eo1.py, groot/groot_n1_7.py를 참고하세요). 복사된 모델링 파일이 포함된 PR이 제출되면 리뷰어는 이 패턴을 요구할 것입니다. 유일한 허용 예외는 transformers에 전혀 존재하지 않는 모델입니다.
벤치마크 및 공개된 체크포인트
새로운 정책은 작동하는 체크포인트와 재현할 수 있는 숫자 하나 이상이 함께 제공될 때 훨씬 더 쉽게 검토할 수 있으며, 훨씬 더 유용합니다.
트리 내 벤치마크를 하나 이상 선택하세요. LeRobot은 벤치마크별 Docker 이미지와 함께 시뮬레이션 벤치마크를 제공합니다(LIBERO, LIBERO-plus, Meta-World, RoboTwin 2.0, RoboCasa365, RoboCerebra, RoboMME, VLABench 등). 정책의 모달리티에 맞는 벤치마크를 선택하세요. VLA는 보통 LIBERO 또는 VLABench를, 이미지 전용 BC는 LIBERO 또는 Meta-World를 사용합니다. 전체 목록은 문서 사이드바의 Benchmarks 섹션에 있습니다.
lerobot/<policy>_<benchmark> 아래에 Hub로 체크포인트 및 프로세서 업로드를 수행합니다(쓰기 권한이 없으면 자신의 네임스페이스를 사용하고, 유지보수자가 미러링할 수 있습니다). 가장 간단한 방법은 --policy.repo_id=<namespace>/<repo>와 --policy.push_to_hub=true를 사용하여 학습하는 것입니다. lerobot-train은 실행이 끝나면 모델, 두 개의 프로세서, 모델 카드를 게시합니다. 기존 체크포인트를 사후에 게시하려면 pretrained_model/ 디렉터리를 업로드(예: hf upload)하거나, 샤드 형식 체크포인트의 경우 lerobot-convert-dcp --push_to_hub=...를 사용합니다.
정책의 MDX에 결과를 보고할 때, 누구나 재실행할 수 있도록 정확한 lerobot-eval 명령어와 하드웨어를 포함하세요:
## Results
Evaluated on LIBERO with `lerobot/<policy>_libero`:
| Suite | Success rate | n_episodes |
| -------------- | -----------: | ---------: |
| libero_spatial | 87.5% | 50 |
| libero_object | 93.0% | 50 |
| libero_goal | 81.5% | 50 |
| libero_10 | 62.0% | 50 |
| **average** | **81.0%** | 200 |
Reproduce: `lerobot-eval --policy.path=lerobot/<policy>_libero --env.type=libero --env.task=libero_spatial --eval.n_episodes=50` (1× A100 40 GB).안정적인 성공률 추정을 위해 각 스위트당 n_episodes ≥ 50을 사용하세요.
정책이 실로봇 전용이고 시뮬레이션 벤치마크가 적용되지 않는 경우, 시뮬레이션 평가를 다음으로 교체하세요: Hub의 공개 학습 데이터셋, lerobot-train 명령어, 체크포인트, 그리고 lerobot-rollout --policy.path=...를 통해 10회 이상의 에피소드에서 측정한 실로봇 성공률.
PR 체크리스트
일반적인 기대 사항은 CONTRIBUTING.md와 PR 템플릿에 명시되어 있습니다. 이 외에도 리뷰어는 다음 사항들을 확인합니다:
-
MyPolicy과MyPolicyConfig는 위의 범위를 다루며,__init_subclass__는 해당 클래스를 인수로 받습니다. -
policies/__init__.py는 config를 재수출합니다(이것이 정책을 등록하며, 팩토리는 네이밍 컨벤션에 따라 modeling/processor를 해석합니다). -
make_my_policy_pre_post_processors은 네이밍 컨벤션을 따릅니다. - 선택적 의존성은
[project.optional-dependencies]extra와TYPE_CHECKING + require_package가드 뒤에 있습니다. -
tests/policies/업데이트; 하위 호환성 아티팩트 커밋 및 정책별 테스트. -
src/lerobot/policies/<name>/README.md을docs/source/policy_<name>_README.md에 심볼릭 링크로 연결하고, 사용자 대상docs/source/<name>.mdx를 작성하여_toctree.yml에 추가합니다. -
lerobot-train --policy.type my_policy ...는 최소 몇 단계 이상으로 end-to-end 실행되며,lerobot-eval또는lerobot-rollout로 로드하고 실행할 수 있는 체크포인트를 저장합니다. -
templates/lerobot_modelcard_template.md에는 설명 항목과 정책을 위한policy_docs링크가 있습니다. - 루트의
README.md에 있는 모델 테이블은 정책을 올바른 카테고리에 나열하고, 해당 문서 페이지로 연결합니다. - 공개된 체크포인트를 사용하여 정책 MDX에서 재현 가능한 벤치마크 평가(시뮬레이션 벤치마크 또는 실제 로봇 데이터셋 + 체크포인트)를 최소 한 가지 이상 수행해야 합니다.
깨끗한 PR을 가장 빠르게 만드는 방법은 자신과 가장 가까운 기존 정책의 디렉토리를 복사한 후 이름을 변경하고, 메서드 단위로 내용을 교체하는 것입니다. 모든 것이 완벽해질 때까지 기다리지 마세요. 초기에 draft PR을 열고 저희와 함께 반복적으로 개선해 나가세요. 리뷰어들은 완전히 병합된 브랜치보다 절반만 완성된 브랜치에 피드백을 주는 것을 훨씬 선호합니다.
예제 및 커뮤니티 기여
다음과 같은 정책 구현 예시를 확인해 보세요:
- DiTFlow Policy — flow-matching 목적을 사용하는 Diffusion Transformer 정책입니다. 이 예제에서 사용해 보세요: DiTFlow Example
LeRobot에 새로운 정책을 가져와 주셔서 감사합니다. main에 반영되는 모든 아키텍처와 커뮤니티가 공개하는 모든 플러그인은 다음 사용자에게 이 라이브러리를 조금 더 유용하게 만들어 주며, 로봇 학습이 나아가고 있는 방향을 조금 더 잘 반영해 줍니다. 여러분이 선보일 결과물을 기대하고 있습니다. 🤗