16정책 학습과 추론
ACT·Diffusion·SmolVLA 같은 모방학습 정책을 학습하고, 실제 팔에서 추론·평가하는 루프를 만듭니다.
정책(policy)이란#
정책은 "지금 보이는 것(관측)" 을 받아 "다음에 할 행동" 을 내놓는 함수입니다. 모방학습에서는 이 함수를 신경망으로 만들고, 15장에서 모은 시연 데이터로 사람의 행동을 흉내 내도록 학습시킵니다.
입력: 카메라 영상(front, side …) + 팔로워 관절 상태 (+ 작업 문장)
↓ [정책 신경망]
출력: 다음 관절 목표값 (action) — 한 개 또는 한 묶음(chunk)학습이 끝나면 리더 암 대신 정책이 action 을 만들어 팔로워에 보냅니다. 13장의 텔레오퍼레이션 루프에서 "사람" 자리만 신경망으로 바뀐 것입니다.
어떤 정책을 고를까#
Seeed 위키(DM · RS)의 Training and Evaluation 절은 ACT, SmolVLA, Pi0, Pi0.5, GR00T N1.5 를 다룹니다. 위키는 --policy.type 으로 act, diffusion, pi0, pi0fast, sac, smolvla 등을 바꿔 쓸 수 있다고도 적습니다.
| 정책 | 종류 | 위키 예시 설정 | 특징 · 요구 사항 |
|---|---|---|---|
| ACT | 처음부터 학습 | --policy.type=act, --steps=300000 | 가장 무난한 출발점. 행동을 묶음(chunk)으로 예측 |
| Diffusion Policy | 처음부터 학습 | --policy.type=diffusion | 같은 장면에 정답이 여러 개인 작업에 강함 (위키는 타입 이름만 언급) |
| SmolVLA | 사전학습 모델 미세조정 | --policy.path=lerobot/smolvla_base, --batch_size=64, --steps=20000 | 약 450M 파라미터, 언어 지시를 함께 입력 |
| Pi0 / Pi0.5 | 사전학습 VLA 미세조정 | --policy.type=pi0·pi05, pretrained_path=lerobot/pi0_base·pi05_base, --steps=3000, --batch_size=32 | Physical Intelligence 의 VLA, bfloat16 · gradient checkpointing 사용 |
| GR00T N1.5 | 사전학습 모델 미세조정 | --policy.type=groot | NVIDIA 의 오픈 파운데이션 모델. CUDA GPU + flash-attn 필수 |
VLA(Vision-Language-Action) 는 영상과 *문장*을 함께 이해해 행동을 내는 큰 모델입니다. "빨간 블록을 상자에 넣어" 같은 지시를 바꿔 가며 여러 작업을 한 모델로 할 수 있지만, GPU·시간이 훨씬 많이 듭니다. 위키도 GR00T 에 대해 "ACT / Pi0 를 먼저 돌려 본 뒤 시도하라" 고 권합니다.
ACT 는 설정이 단순하고, 데이터 50 에피소드 정도로 결과를 볼 수 있으며, 위키의 기본 예시이기도 합니다. ACT 로 성공률을 확보한 다음 다른 정책과 비교하세요. 같은 데이터로 정책만 바꿔 보면 "데이터 문제인지 모델 문제인지" 를 가르기 쉬워집니다.
ACT 는 다음 행동 하나가 아니라 앞으로의 여러 스텝을 한 묶음으로 예측합니다. 한 스텝씩 예측하면 작은 오차가 누적돼 팔이 떨리기 쉬운데, 묶음으로 예측하면 궤적이 부드러워지고 사람 시연의 "머뭇거림" 에도 덜 흔들립니다. 겹치는 묶음들을 평균 내어(temporal ensembling) 더 매끄럽게 만들기도 합니다.
README 의 커뮤니티 쇼케이스에는 GR00T 계열 모델, Gemma 해커톤 프로젝트 등 reBot 으로 VLA 를 돌린 사례가 소개되어 있으니 아이디어를 얻을 때 둘러보세요.
학습 명령 — ACT#
위키(DM)의 ACT 학습 예시입니다. 로컬 데이터셋(15장에서 push_to_hub=false 로 녹화)이라면 repo_id 를 녹화 때와 똑같이 쓰고 --policy.push_to_hub=false 를 붙입니다.
lerobot-train \
--dataset.repo_id=seeed_rebot_b601_dm/test \
--policy.type=act \
--output_dir=outputs/train/act_rebot_test \
--job_name=act_rebot_test \
--policy.device=cuda \
--wandb.enable=false \
--policy.push_to_hub=false \
--steps=300000| 인자 | 뜻 |
|---|---|
--dataset.repo_id | 학습할 데이터셋 (Hub 면 ${HF_USER}/rebot_test 형태) |
--policy.type | 정책 종류. 데이터셋에 저장된 관절 수·카메라 수에 자동으로 맞춰집니다 |
--output_dir | 체크포인트가 쌓이는 폴더 |
--policy.device | cuda(NVIDIA GPU), Apple Silicon 이면 mps |
--steps | 학습 스텝 수. 위키는 기본값이 더 크다고 설명하며, 체크포인트가 중간중간 저장되므로 넉넉히 잡아도 된다고 안내 |
--wandb.enable | true 면 Weights & Biases 로 학습 곡선 확인 (wandb login 필요) |
- RTX 50 시리즈: PyTorch 프리뷰(CUDA 12.8+)가 필요하고, 학습 명령에
--dataset.video_backend=pyav를 추가합니다. - 학습이 끊겼다면 이어서:
lerobot-train --config_path=outputs/train/act_rebot_test/checkpoints/last/pretrained_model/train_config.json --resume=true - 메모리가 부족하면
--batch_size부터 줄이세요(위키 SmolVLA 팁).
SmolVLA 는 처음부터가 아니라 사전학습 모델에서 출발합니다.
pip install -e ".[smolvla]"
lerobot-train \
--policy.path=lerobot/smolvla_base \
--dataset.repo_id=${HF_USER}/mydataset \
--batch_size=64 \
--steps=20000 \
--output_dir=outputs/train/my_smolvla \
--job_name=my_smolvla_training \
--policy.device=cuda \
--wandb.enable=truePi0·Pi0.5·GR00T 의 전체 옵션과 LoRA 같은 PEFT 미세조정, 여러 GPU 학습(accelerate launch --multi_gpu)은 위키의 해당 탭을 그대로 따르세요. 옵션이 많고 버전에 따라 자주 바뀝니다.
GPU 와 시간 감각#
| 상황 | 위키에 적힌 참고치 |
|---|---|
| ACT, 50 에피소드, RTX 3060(8GB) 노트북 | 약 6시간 |
| ACT, 50 에피소드, RTX 4090 / A100 | 약 2~3시간 |
| SmolVLA, 20k 스텝, A100 1장 | 약 4시간 |
| GR00T N1.5 | CUDA GPU + flash-attn 필수 |
GPU 가 없다면 위키는 공식 튜토리얼의 Colab 노트북을 권합니다. CPU 로도 명령은 돌지만 현실적인 시간이 아닙니다. Jetson(JetPack 6.0/6.1)은 위키가 지원하는 환경으로, 주로 추론 쪽에 씁니다.
학습 곡선(loss)이 잘 내려가도 실물에서 실패할 수 있습니다. 손실은 "시연을 얼마나 잘 흉내 내는가" 이지 "작업을 얼마나 잘 하는가" 가 아니기 때문입니다. 실패 원인의 대부분은 데이터(카메라 이동, 일관성 없는 시연, 부족한 위치 다양성)에 있습니다. 15장의 수집 원칙으로 돌아가세요.
추론과 평가#
위키 방식 — lerobot-record 에 정책 넣기#
Seeed 위키(포크 버전)는 녹화 명령에 --policy.path 를 넣어 정책이 팔을 움직이는 장면을 평가 데이터셋으로 녹화합니다.
lerobot-record \
--robot.type=seeed_b601_dm_follower \
--robot.port=/dev/ttyACM0 \
--robot.can_adapter=damiao \
--robot.cameras='{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30, fourcc: "MJPG"}, side: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30, fourcc: "MJPG"} }' \
--robot.id=follower1 \
--display_data=false \
--dataset.repo_id=seeed/eval_test123 \
--dataset.single_task="Put lego brick into the transparent box" \
--policy.path=outputs/train/act_rebot_test/checkpoints/last/pretrained_model| 규칙 | 이유 |
|---|---|
평가 데이터셋 이름은 eval_ 로 시작 | 학습 데이터와 구분해 저장. 같은 이름 폴더가 있으면 File exists 오류 → 지우고 다시 |
카메라 이름(front, side)을 녹화 때와 똑같이 | 다르면 mean is infinity ... 오류(정규화 통계를 못 찾음) |
single_task 를 녹화 때와 같게 | 언어 지시를 쓰는 VLA 에서 특히 중요 |
--policy.path | 로컬 체크포인트 경로 또는 Hub 모델 이름(${HF_USER}/act_rebot_test) |
upstream LeRobot 의 새 방식#
LeRobot 공식 문서의 최신 버전은 정책 배포에 **lerobot-rollout** 을 쓰고, --strategy.type 으로 base(기록 없이 빠른 확인), episodic(에피소드 단위 평가 녹화), sentry(연속 녹화·자동 업로드), highlight, dagger(사람 개입 수집)를 고릅니다. 느린 VLA(Pi0, Pi0.5, SmolVLA)는 --inference.type=rtc 로 부드럽게 실행할 수 있다고 안내합니다. 쓰고 있는 LeRobot 버전의 문서를 따르세요. 위키 포크와 upstream 의 명령이 다릅니다.
비동기 추론#
큰 모델은 추론에 시간이 걸려 팔이 멈칫거립니다. 위키의 Async Inference 는 정책 서버(GPU PC)와 로봇 클라이언트(팔 옆 PC)를 나누고, 행동 묶음을 미리 받아 두는 방식입니다(python -m lerobot.async_inference.policy_server / robot_client, --actions_per_chunk=50, --fixed_update_fps=30 등). 위키는 이 통신에 인증이 없고 pickle 역직렬화를 쓰므로 공용 인터넷에 노출하지 말라고 경고합니다.
- 정책이 팔을 움직이는 동안 전원 스위치(비상 정지)에 손을 둡니다. 사람이 아니라 신경망이 명령을 내므로 예상 밖 동작이 나올 수 있습니다.
- 첫 실행은 짧게(
episode_time_s를 줄여서), 작업 공간을 비우고, 깨지거나 무거운 물체 없이. - 학습 때와 카메라 위치·조명·물체가 같아야 합니다. 다르면 이상한 곳으로 손을 뻗습니다.
- 팔로워 전원(RS 48V / DM 24V)과 캘리브레이션 id 가 학습 데이터 수집 때와 같은지 확인합니다.
실패 분석과 보강 루프#
성공률은 감이 아니라 숫자로 봅니다. 평가 프로토콜을 정해 두세요 — 예: 물체 위치 5곳 × 2회 = 10회, 매번 같은 리셋 자세에서 시작.
| 회차 | 위치 | 결과 | 실패 단계 | 메모 |
|---|---|---|---|---|
| 1 | A | 성공 | — | |
| 2 | B | 실패 | 접근 | 블록 왼쪽 2 cm 를 집음 |
| 3 | C | 실패 | 집기 | 그리퍼가 일찍 닫힘 |
| 실패 패턴 | 흔한 원인 | 처방 |
|---|---|---|
| 특정 위치에서만 실패 | 그 위치 시연 부족 | 그 위치 에피소드 10개 추가 |
| 물체 근처에서 머뭇거림·진동 | 시연마다 접근 방식이 다름 | 접근 방향을 통일해 재수집 |
| 엉뚱한 곳으로 뻗음 | 카메라 이동·조명 변화 | 카메라 고정, 수집 환경 재현 |
| 집었다가 놓침 | 그리퍼 닫힘 타이밍·힘 | 닫은 뒤 잠깐 멈추는 시연, 잡기 쉬운 물체로 시작 |
| 처음부터 안 움직임 | 카메라 이름·task 불일치, 잘못된 체크포인트 | 명령 인자 재확인 |
정책이 실패하는 장면에서 사람이 개입해 바로잡은 시연을 추가하는 방식을 DAgger 라고 합니다. upstream 의 dagger 전략이 이를 지원합니다. 핵심은 같습니다 — 정책이 약한 곳의 데이터를 보강해서 다시 학습합니다.
시뮬레이터로 "닫힌 루프" 체험하기#
정책의 본질은 매 순간 다시 보고 다시 결정하는 것(닫힌 루프)입니다. 녹화된 동작을 그대로 재생하는 것(열린 루프)과 비교해 봅시다.
- 시뮬레이터에서 큐브를 켜고, 15장의 Playground 집기 코드를 실행하면서 녹화 탭으로 녹화합니다.
- 큐브를 다른 곳으로 옮긴 뒤 녹화 탭의 재생을 누르세요. 팔은 예전 큐브 자리로 가서 허공을 집습니다 — 이것이 열린 루프(
lerobot-replay와 같은 원리)입니다. - 이제 Python 탭에서 아래 "손으로 만든 정책" 을 실행합니다. 매 단계 관측(
arm.cube())을 다시 읽고 행동을 정합니다.
def policy(obs):
"""관측 → 행동. 학습된 신경망 대신 규칙으로 만든 아주 단순한 정책"""
cube, tcp = obs["cube"], obs["tcp"]
dx, dy = cube[0] - tcp[0], cube[1] - tcp[1]
dist_xy = (dx*dx + dy*dy) ** 0.5
if dist_xy > 0.01: # 아직 큐브 위가 아니면 → 수평으로 다가가기
step = min(0.05, dist_xy)
return ("move", tcp[0] + dx/dist_xy*step, tcp[1] + dy/dist_xy*step, cube[2] + 0.08)
if tcp[2] > cube[2] + 0.015: # 큐브 위면 → 내려가기
return ("move", cube[0], cube[1], cube[2] + 0.01)
return ("grasp",)
arm.home(); arm.open()
for t in range(20): # 최대 20 스텝의 닫힌 루프
obs = {"cube": arm.cube(), "tcp": arm.fk()}
act = policy(obs)
print(t, act[0], [round(v, 3) for v in act[1:]])
if act[0] == "grasp":
arm.close(); arm.wait(0.3)
x, y, z = arm.fk()
arm.move_to(x, y, z + 0.06, t=1.0, down=True)
break
if not arm.move_to(act[1], act[2], act[3], t=0.5, down=True):
print("IK 실패 — 도달 불가 위치"); break- 큐브 위치를 바꿔 다시 실행해 보세요. 이번에는 새 위치를 따라갑니다. 학습된 정책도 이와 같이 매 프레임 카메라를 보고 다음 행동(묶음)을 정합니다. 차이는 규칙 대신 시연에서 배운 신경망이라는 점입니다.
Sim-to-Real VLA 코스 (Seeed × NVIDIA)#
README 의 B601-RS 로드맵 Isaac Sim Simulation 항목과 쇼케이스에는 Seeed 스토어의 "Learning Physical AI - A Sim-to-Real VLA Pipeline with Seeed reBot Arm and NVIDIA Isaac" 코스가 링크되어 있습니다(페이지). 시뮬레이션에서 데이터를 만들고 VLA 를 학습해 실물 reBot 으로 옮기는 흐름을 다루는 것으로 소개됩니다. 커리큘럼·가격·형식은 페이지에서 직접 확인하세요.
관련 오픈소스로 rebot-arm-dli-isaacsim 이 있습니다. README 에 따르면 NVIDIA 의 SO-101 Sim-to-Real 워크플로를 reBot B601-RS 에 맞춘 프로젝트로,
- 실물 reBot Arm 102 리더로 Isaac Sim 4.5 속 B601-RS 를 60 Hz 로 조종하고(물리 120 Hz),
- 손목
front· 고정side카메라로 LeRobot Dataset v3 를 녹화하며, - 물체 위치·질량·조명·손목 카메라에 도메인 무작위화를 겁니다.
시뮬레이션 데이터 → 정책 학습 → 실물 추론의 다리는 20장에서 Isaac Sim · MuJoCo 와 함께 자세히 봅니다.
정리#
- 정책 = 관측(영상 + 관절 상태 + 문장) → 행동. 텔레오퍼레이션의 사람 자리를 신경망이 대신합니다.
- 위키가 다루는 정책: ACT(첫 선택), SmolVLA(
lerobot/smolvla_base, 20k 스텝), Pi0/Pi0.5(3000 스텝, batch 32), GR00T N1.5(CUDA + flash-attn). Diffusion 도--policy.type으로 선택 가능. - 학습:
lerobot-train --policy.type=act ..., 로컬 데이터면--policy.push_to_hub=false, RTX 50 은--dataset.video_backend=pyav. ACT 50 에피소드 ≈ RTX 3060 노트북 6시간, 4090/A100 2~3시간. - 평가(위키 포크):
lerobot-record --policy.path=..., 데이터셋은eval_접두어, 카메라 이름·task 는 학습 때와 동일. upstream 최신은lerobot-rollout. - 성공률을 숫자로 재고, 실패 패턴별로 데이터를 보강해 다시 학습하는 루프를 돕니다.
확인 문제#
- ACT 가 다음 행동을 하나씩이 아니라 "묶음(chunk)" 으로 예측해서 얻는 장점은 무엇인가요?
- 로컬에 녹화한
seeed_rebot_b601_dm/test로 ACT 를 학습할 때 반드시 맞춰야 할 인자 두 가지는? - 평가 실행 시
mean is infinity ...오류가 났습니다. 가장 먼저 의심할 것은? - 학습 loss 는 잘 내려갔는데 실물 성공률이 낮습니다. 하이퍼파라미터를 바꾸기 전에 확인해야 할 것은?
- 시뮬레이터 실습에서 녹화 재생(열린 루프)은 큐브를 옮기면 실패하고, 규칙 정책(닫힌 루프)은 성공했습니다. 차이의 이유는?
- 여러 스텝의 궤적을 한 번에 내므로 작은 오차의 누적과 떨림이 줄고, 시연의 머뭇거림에도 덜 흔들려 동작이 부드러워집니다.
--dataset.repo_id를 녹화 때와 똑같이(seeed_rebot_b601_dm/test) 쓰고, Hub 업로드를 끄는--policy.push_to_hub=false를 붙입니다.--robot.cameras의 카메라 이름(예:front,side)이 데이터 수집 때와 다른지 확인합니다.- 데이터 품질입니다 — 카메라·조명이 수집 때와 같은지, 시연이 일관됐는지, 실패 위치의 시연이 충분한지 확인하고 필요하면 보강 수집합니다.
- 재생은 예전 행동을 그대로 반복할 뿐 현재 상황을 보지 않습니다. 정책은 매 스텝 관측(큐브 위치)을 다시 읽고 행동을 정하므로 바뀐 위치를 따라갑니다.