LeRobot documentation
프로세서 소개
프로세서 소개
로봇공학에서는 로봇과 인간이 생성하는 데이터와 머신러닝 모델이 기대하는 데이터 사이에 근본적인 불일치가 존재합니다. 로봇은 카메라 이미지와 관절 위치와 같은 원시 센서 데이터를 출력하며, 모델이 이를 처리하려면 정규화, 배치 처리, 디바이스 배치가 필요합니다. 인간의 언어 지시문은 수치 표현으로 토큰화되어야 하며, 서로 다른 로봇은 표준화가 필요한 서로 다른 좌표계를 사용합니다.
이 문제는 모델 출력에도 해당합니다. 모델은 엔드 이펙터(end-effector) 위치를 출력할 수 있지만 로봇은 조인트 공간(joint-space) 명령을 필요로 하거나, 텔레오퍼레이터(teleoperator)는 상대적 움직임을 생성하지만 로봇은 절대 명령을 기대하는 경우가 있습니다. 모델 예측 값은 정규화(normalized)되어 있는 경우가 많으며, 이를 실제 세계의 스케일로 되돌리는 변환이 필요합니다.
크로스 도메인 번역은 또 다른 복잡성을 추가합니다. 하나의 로봇 구성에서 수집된 학습 데이터는 다른 하드웨어에 배포하기 위해 적응이 필요하며, 특정 카메라 구성으로 학습된 모델은 새로운 배치에서도 작동해야 하고, 다른 명명 규칙을 가진 데이터셋은 조화가 필요합니다.
여기서 프로세서가 등장합니다. 프로세서는 이러한 격차를 메우는 범용 번역기 역할을 하며, 센서에서 모델, 그리고 액추에이터로 이어지는 데이터 흐름이 원활하게 이루어지도록 보장합니다. 프로세서는 원시 환경 데이터를 모델이 처리할 수 있는 입력으로 변환하고 그 역방향 변환에 필요한 모든 전처리 및 후처리 단계를 처리합니다.
이것은 좋아하는 정책을 다음과 같이 사용할 수 있음을 의미합니다:
import torch
from lerobot.datasets import LeRobotDataset
from lerobot.policies import make_pre_post_processors
from lerobot.policies.your_policy import YourPolicy
from lerobot.processor import RobotProcessorPipeline, PolicyProcessorPipeline
dataset = LeRobotDataset("hf_user/dataset", episodes=[0])
sample = dataset[10]
model = YourPolicy.from_pretrained(
"hf_user/model",
)
model.eval()
model.to("cuda")
preprocessor, postprocessor = make_pre_post_processors(model.config, pretrained_path="hf_user/model", dataset_stats=dataset.meta.stats)
preprocessed_sample = preprocessor(sample)
action = model.select_action(preprocessed_sample)
postprocessed_action = postprocessor(action)프로세서(Processor)란 무엇인가요?
로봇공학에서는 데이터가 다양한 형태로 제공됩니다: 카메라에서 수집된 이미지, 센서에서 수집된 관절 위치, 사용자로부터의 텍스트 명령 등입니다. 각 유형의 데이터는 모델이 이를 효과적으로 사용할 수 있도록 특정 변환이 필요합니다. 모델은 이 데이터가 다음과 같은 상태여야 합니다:
- 정규화: 신경망 처리에 적합한 범위로 스케일링
- 배치 처리: 배치 처리를 위한 적절한 차원으로 구성
- 토큰화: 텍스트를 수치 표현으로 변환
- 디바이스 배치: 올바른 하드웨어(CPU/GPU)로 이동
- 타입 변환: 적절한 데이터 유형으로 캐스팅
Processors는 데이터에 적용할 수 있는 조합 가능하고 재사용 가능한 단계들을 통해 이러한 변환을 처리하며, 이러한 단계들은 파이프라인으로 연결될 수 있습니다. 각 스테이션이 데이터에 특정 변환을 수행하는 모듈형 조립 라인이라고 생각하면 됩니다.
핵심 개념
EnvTransition: 범용 데이터 컨테이너
EnvTransition는 모든 프로세서에 흐르는 기본 데이터 구조입니다.
로봇-환경 상호작용의 전체를 나타내는 타입이 지정된 딕셔너리입니다:
- 관찰: 모든 센서 데이터(이미지, 상태, 고유수용감각)
- ACTION: 실행할 동작 또는 실행된 동작
- REWARD: 강화 학습 신호
- DONE/TRUNCATED: 에피소드 경계 표시자
- INFO: 임의의 메타데이터
- COMPLEMENTARY_DATA: 작업 설명, 인덱스, 패딩 플래그, 단계 간 데이터
Batch converters는 COMPLEMENTARY_DATA에 index, episode_index, frame_index와 같은 인덱싱 메타데이터를 유지합니다.
batch_to_transition / transition_to_batch 왕복 변환 과정에서 frame_index는 원래의 스칼라 또는 텐서 값을 유지합니다.
입력에 frame_index가 없으면 변환기가 이를 추가하지 않습니다.
ProcessorStep: 기본 구성 요소
ProcessorStep은 전이를 처리하는 단일 변환 단위입니다. 두 개의 필수 메서드를 가진 추상 베이스 클래스입니다:
from lerobot.processor import ProcessorStep, EnvTransition
class MyProcessorStep(ProcessorStep):
"""Example processor step - inherit and implement abstract methods."""
def __call__(self, transition: EnvTransition) -> EnvTransition:
"""Transform the transition - REQUIRED abstract method."""
# Your processing logic here
return transition
def transform_features(self, features):
"""Declare how this step transforms feature shapes/types - REQUIRED abstract method."""
return features # Most processors return features unchanged__call__는 프로세서 단계의 핵심입니다. EnvTransition을 입력으로 받아 수정된 EnvTransition을 반환합니다.
transform_features는 이 단계가 특징의 형태/타입을 어떻게 변환하는지 선언하는 데 사용됩니다.
DataProcessorPipeline: 범용 오케스트레이터
DataProcessorPipeline[TInput, TOutput]은 여러 ProcessorStep 인스턴스를 연결합니다:
from lerobot.processor import RobotProcessorPipeline, PolicyProcessorPipeline
# For robot hardware (unbatched data)
robot_processor = RobotProcessorPipeline[RobotAction, RobotAction](
steps=[step1, step2, step3],
name="robot_pipeline"
)
# For model training/inference (batched data)
policy_processor = PolicyProcessorPipeline[dict[str, Any], dict[str, Any]](
steps=[step1, step2, step3],
name="policy_pipeline"
)RobotProcessorPipeline와 PolicyProcessorPipeline
가장 큰 차이점은 처리하는 데이터 구조에 있습니다:
| 측면 | RobotProcessorPipeline | PolicyProcessorPipeline |
|---|---|---|
| 입력 | dict[str, Any] - 개별 로봇 값 | dict[str, Any] - 배치된 텐서 |
| 출력 | dict[str, Any] - 개별 로봇 명령 | torch.Tensor - 정책 예측 |
| 사용 사례 | 실시간 로봇 제어 | 모델 학습/추론 |
| 데이터 형식 | 배치되지 않은, 이질적인 | 배치, 동질 |
| 예시 | {"joint_1": 0.5} | {"observation.state": tensor([[0.5]])} |
로봇 하드웨어 인터페이스에는 RobotProcessorPipeline을(를) 사용합니다:
# Robot data structures: dict[str, Any] for observations and actions
robot_obs: dict[str, Any] = {
"joint_1": 0.5, # Individual joint values
"joint_2": -0.3,
"camera_0": image_array # Raw camera data
}
robot_action: dict[str, Any] = {
"joint_1": 0.2, # Target joint positions
"joint_2": 0.1,
"gripper": 0.8
}모델 학습 및 배치 처리에 PolicyProcessorPipeline를 사용합니다:
# Policy data structures: batch dicts and tensors
policy_batch: dict[str, Any] = {
"observation.state": torch.tensor([[0.5, -0.3]]), # Batched states
"observation.images.camera0": torch.tensor(...), # Batched images
"action": torch.tensor([[0.2, 0.1, 0.8]]) # Batched actions
}
policy_action: torch.Tensor = torch.tensor([[0.2, 0.1, 0.8]]) # Model output tensor변환 함수
LeRobot은 lerobot.processor.converters에서 서로 다른 데이터 형식을 연결하기 위한 변환 함수를 제공합니다. 이러한 함수는 로봇 하드웨어 데이터 구조, 정책 모델 형식, 그리고 프로세서 파이프라인을 통해 흐르는 내부 EnvTransition 표현 사이의 핵심적인 변환을 처리합니다.
| 카테고리 | 함수 | 설명 |
|---|---|---|
| 로봇 하드웨어 변환기 | robot_action_to_transition | Robot dict → EnvTransition |
observation_to_transition | 로봇 관측 → EnvTransition | |
transition_to_robot_action | EnvTransition → Robot dict | |
| 정책/학습 변환기 | batch_to_transition | Batch dict → EnvTransition |
transition_to_batch | EnvTransition → 배치 딕 | |
policy_action_to_transition | Policy 텐서 → EnvTransition | |
transition_to_policy_action | EnvTransition → Policy 텐서 | |
| 유틸리티 | create_transition | 기본값으로 전환 빌드 |
identity_transition | 패스-스루 컨버터 |
핵심 통찰은 로봇 하드웨어 변환기가 개별 값과 사전(dict)을 다루는 반면, 정책/학습 변환기는 배치된 텐서와 모델 출력을 다룬다는 점입니다. 변환기 함수가 구조적 차이를 자동으로 처리하므로, 프로세서 단계는 데이터 형식 호환성에 대한 걱정 없이 핵심 변환에만 집중할 수 있습니다.
프로세서 예제
다음 예제는 정책 학습 및 추론을 위한 실제 프로세서 구성을 보여줍니다.
정책 학습 및 추론을 위한 프로세서의 예시입니다:
# Training data preprocessing (optimized order for GPU performance)
training_preprocessor = PolicyProcessorPipeline[dict[str, Any], dict[str, Any]](
steps=[
RenameObservationsProcessorStep(rename_map={}), # Standardize keys
AddBatchDimensionProcessorStep(), # Add batch dims
TokenizerProcessorStep(tokenizer_name="...", ...), # Tokenize language
DeviceProcessorStep(device="cuda"), # Move to GPU first
NormalizerProcessorStep(features=..., stats=...), # Normalize on GPU
]
)
# Model output postprocessing
training_postprocessor = PolicyProcessorPipeline[torch.Tensor, torch.Tensor](
steps=[
DeviceProcessorStep(device="cpu"), # Move to CPU
UnnormalizerProcessorStep(features=..., stats=...), # Denormalize
],
to_transition=policy_action_to_transition,
to_output=transition_to_policy_action,
)프로세서가 포함된 로봇과 정책 간의 상호작용
가장 일반적인 실전 시나리오는 두 가지 파이프라인 유형을 결합합니다. 로봇 하드웨어가 정책 처리가 필요한 관측값을 생성하고, 정책의 출력은 로봇과 호환되는 후처리(postprocessing)가 필요합니다.
# Real deployment: Robot sensors → Model → Robot commands
with torch.no_grad():
while not done:
raw_obs = robot.get_observation() # dict[str, Any]
# Add your robot observation to policy observation processor
policy_input = policy_preprocessor(raw_obs) # Batched dict
policy_output = policy.select_action(policy_input) # Policy tensor
policy_action = policy_postprocessor(policy_output)
# Add your robot action to policy action processor
robot.send_action(policy_action)Feature Contracts: 형태 및 유형 변환
Processor는 데이터를 변환하는 것뿐만 아니라 데이터 구조 자체를 변경할 수도 있습니다. transform_features() 메서드는 이러한 변경 사항을 선언하며, 이는 데이터셋 기록 및 정책 생성에 있어 매우 중요합니다.
왜 Feature Contracts가 중요한가
데이터셋 또는 정책을 구축할 때, LeRobot은 다음 사항을 알아야 합니다:
- 처리 후 존재할 데이터 필드
- 각 필드가 가질 형태와 타입
- 기대하는 데이터 구조에 맞게 모델을 구성하는 방법
# Example: A processor that adds velocity to observations
class VelocityProcessor(ObservationProcessorStep):
def observation(self, obs):
new_obs = obs.copy()
if "observation.state" in obs:
# concatenate computed velocity field to the state
new_obs["observation.state"] = self._compute_velocity(obs["observation.state"])
return new_obs
def transform_features(self, features):
"""Declare the new velocity field we're adding."""
state_feature = features[PipelineFeatureType.OBSERVATION].get("observation.state")
if state_feature:
double_shape = (state_feature.shape[0] * 2,) if state_feature.shape else (2,)
features[PipelineFeatureType.OBSERVATION]["observation.state"] = PolicyFeature(
type=FeatureType.STATE, shape=double_shape
)
return features기능 사양 함수
create_initial_features()와 aggregate_pipeline_dataset_features()는 데이터셋 생성의 핵심 문제를 해결합니다. 즉, 데이터가 처리되기 전에 최종 데이터 구조를 정확히 결정하는 것입니다.
프로세서 파이프라인은 새로운 특징(속도 필드 등)을 추가하거나, 텐서 모양을 변경(이미지 크롭 등)하거나, 키 이름을 변경할 수 있으므로, 데이터셋은 적절한 저장 공간을 할당하고 스키마를 정의하기 위해 사전에 완전한 출력 사양을 알아야 합니다.
이 함수들은 로봇 하드웨어 사양(create_initial_features())으로 시작하여 전체 파이프라인 변환을 시뮬레이션(aggregate_pipeline_dataset_features())함으로써, LeRobotDataset.create()에 전달되는 최종 특징 사전(feature dictionary)을 계산합니다. 이를 통해 프로세서의 출력과 데이터셋이 저장할 것으로 기대하는 값이 완벽하게 일치하도록 보장합니다.
from lerobot.datasets import aggregate_pipeline_dataset_features
# Start with robot's raw features
initial_features = create_initial_features(
observation=robot.observation_features, # {"joint_1.pos": float, "camera_0": (480,640,3)}
action=robot.action_features # {"joint_1.pos": float, "gripper.pos": float}
)
# Apply processor pipeline to compute final features
final_features = aggregate_pipeline_dataset_features(
pipeline=my_processor_pipeline,
initial_features=initial_features,
use_videos=True
)
# Use for dataset creation
dataset = LeRobotDataset.create(
repo_id="my_dataset",
features=final_features, # Knows exactly what data to expect
...
)공통 Processor 단계
LeRobot은 여러 등록된 프로세서 스텝을 제공합니다. 가장 일반적으로 사용되는 핵심 프로세서는 다음과 같습니다:
필수 프로세서
normalizer_processor: 데이터셋 통계(평균/표준편차 또는 최소값/최대값)를 사용하여 관찰/행동을 정규화device_processor: 선택적 dtype 변환과 함께 텐서를 CPU/GPU로 이동to_batch_processor: 모델 호환성을 위해 전환에 배치 차원을 추가rename_observations_processor: 매핑 딕셔너리를 사용하여 관찰 키 이름 변경tokenizer_processor: 자연어 작업 설명을 토큰과 어텐션 마스크로 토큰화
다음 단계
- 직접 Processor 구현하기 - 사용자 정의 processor 단계 만들기
- 파이프라인 디버깅 - 파이프라인 문제 해결 및 최적화
- 로봇 및 텔레오퍼레이터용 프로세서 - 실제 환경 통합 패턴
요약
Processors는 로봇공학에서 데이터 변환 문제를 해결하기 위해 다음을 제공합니다:
- 모듈형 변환: 조합 가능하고 재사용 가능한 처리 단계
- 형식 안전성: 컴파일 시간 검사 기능이 있는 범용 파이프라인
- 성능 최적화: GPU 가속 연산
- Robot/Policy 구분: 서로 다른 데이터 구조를 위한 개별 파이프라인
- 포괄적인 생태계: 일반적인 작업을 위한 30개 이상의 등록된 프로세서
핵심 통찰: RobotProcessorPipeline는 배치되지 않은 로봇 하드웨어 데이터를 처리하고, PolicyProcessorPipeline는 배치된 모델 데이터를 처리합니다. 데이터 구조에 맞는 도구를 선택하세요!