Index
2026-08-14 — Analysis

pi0.5 × MolmoSpace Finetuning 준비 상태 전수 점검

MolmoBot | RoboCasa pi0.5 코드 · MolmoSpace 데이터 · action 규약 정합성 검토

TL;DR

15k
완료된 step (68392)
0.0027
final loss
30,464
LeRobot episodes
9.63 TB
HF 원본 train 전체
44 TB
NAS 여유 (89% 사용)

1배경/목적

MolmoSpace(allenai/molmobot-data) 데이터로 pi0.5 finetuning을 하려는 요청. 요구사항: (1) 기존 RoboCasa pi0.5 finetuning 코드 확보, (2) 데이터 위치·완전성 확인 및 필요 시 다운로드, (3) RoboCasa 방식에서 데이터셋만 교체해 학습하되 action 값이 pi0.5 pretrained weight 규약과 정확히 맞는지 보장.

2조사 결과 — 코드 3곳

A. RoboCasa pi0.5 finetuning 코드 (레퍼런스)

~/repos/Robotics/openpi (robocasa-benchmark fork). 사용 config는 pi05_pretrain_human300 (config.py:1275) — pi05=True, max_token_len=200, groot-스타일 LeRobot 데이터(action 12차원), pi05_base init, batch 64. 결과물: ~/ckpts/pi05_robocasa_pretrain_human300_step75000.

Action 처리: 12차원 action/state를 model action_dim(32)으로 zero-pad → 추론 시 앞 12차원 슬라이스. norm stats는 groot 데이터 자체 통계, pi0.5라 quantile(q01/q99) 정규화 적용.

이 fork의 pi05 경로는 카메라 3뷰(base+wrist+right) 필수(robocasa_policy.py:71-75). MolmoSpace 데이터는 2뷰(exo+wrist)라 그대로 이식 불가 — 이식하려면 transform 수정 필요.

B. 선행 완료 작업 — scenemem (2026-08-04 학습 완주)

config : pi05_mlspaces_franka (scenemem/openpi config.py:1041) init : gs://openpi-assets/checkpoints/pi05_droid/params (11.58 GiB 캐시 완료) action : 절대 joint position(7) + gripper(1) — MolmoSpaces 컨트롤러 native norm : DROID *state* stats를 state/action 양쪽에 재사용 (quantile). DROID actions stats는 joint velocity라 사용 금지 model : action_horizon=15 (pi05_droid·eval 하네스와 일치), SigLIP encoder freeze, EMA 0.999 train : 15k step, batch 256, job 68392 COMPLETED (16h18m), loss 1.82 → 0.0027 ckpt : scenemem/openpi/checkpoints/pi05_mlspaces_franka/franka_2cam_15k/{5000,10000,14999}
사용자가 걱정한 "action 값이 pi0.5와 맞는가"는 이 선행 작업에서 이미 해소 — norm stats 합성 후 --check로 largest |normalized action| = 3.88 검증, 학습 loss 정상 수렴. 함정 19개(assets CWD 상대경로, gsutil 파손, wandb TLS 등)가 scenemem/claude/context.md에 문서화되어 있음.

C. AllenAI 공식 MolmoBot-Pi0 (미사용 상태의 제3 경로)

MolmoBot-Pi0/pi05_mlspaces_finetune config가 이미 존재: pi05_droid init, action = joint velocity(joint_pos_rel/0.2) + gripper/255, DROID norm stats(gs://) 재사용. 단 venv 미구축(uv sync 필요), PyTorch 학습은 JAX ckpt→safetensors 변환 필요, 입력이 raw h5+mp4 포맷(LeRobot 변환본 사용 불가).

3데이터 현황

위치내용상태
HF allenai/molmobot-datatrain split 전체 inflated 9.63 TB (9 config)원본
scenemem/pi05-mlspaces/data/lerobot/mlspaces/franka_2camLeRobot 변환본 30,464 ep / 4.08M frames (2 cam)학습에 사용됨
scenemem/pi05-mlspaces/data/molmobot-data-train/raw h5+mp4, Franka 4 config: Pick 20/753 · PnP 20/1598 · NextTo 5/592 · Color 5/92 shards부분 (50 shards)
~/Dataset/molmobot_data/scripts/bulk_download / validate_trajectories / calculate_stats.py (오늘 HF에서 확보)확보
NAS 여유 44 TB(89% 사용). 풀 다운로드(9.6 TB)는 부담이 크고, bulk_download.py가 shard 단위 resume을 지원하므로 필요 config/part만 증분 추가가 맞다. 데이터 확장 시 LeRobot 재변환(96-shard 파이프라인) 재실행 필요.

4Action 규약 대조표

RoboCasa fork (레퍼런스)scenemem (완료)MolmoBot-Pi0 공식
init weightpi05_basepi05_droidpi05_droid
action 공간robocasa 12차원 (native)절대 joint pos 7 + gripper 1joint velocity 7 + gripper 1
norm statsgroot 데이터 자체 통계DROID state stats 재사용DROID stats 재사용 (gs://)
정규화pi0.5 공통: quantile (q01/q99), action_dim 32 zero-pad 후 앞 N차원 슬라이스
카메라3뷰 필수2뷰 (exo+wrist)2뷰 (exo+wrist)
학습 프레임워크JAXJAXPyTorch (ckpt 변환 필요)

pi0.5 pretrained weight 활용 관점에서는 pi05_droid init + DROID stats 재사용(scenemem·공식 공통)이 정석 — MolmoSpace는 DROID-스타일 Franka 시뮬 데이터이므로 pi05_base보다 pi05_droid가 가까운 init이다.

5최종 체크포인트 검증 (오늘 실행)

step 14999 체크포인트에 대해 validate_checkpoint.py(open-loop action L1, zero-motion 베이스라인 대비, 128 샘플 / 127 에피소드, horizon 15)를 실행. 15fps 데이터라 "현재 자세 유지"(zero-motion)만 해도 강한 예측기이므로, 이를 이기는지가 학습 여부의 판정 기준(1.5x 미만이면 실패).

=== step 14999 === L1 model 0.01930 zero-motion 0.07853 -> 4.07x better RMSE model 0.07139 zero-motion 0.18232 gripper L1: 0.034 vs 0.278 (8.1x) | 모든 joint 차원에서 2.4~8x 우위 horizon별 L1: model 0.012→0.025 (평탄) vs zero-motion 0.035→0.115 (증가) → 청크 후반까지 실제 motion을 추적함. 결과: pi05-mlspaces/eval/val_14999.{json,txt}
검증 통과. 15k 학습이 실제로 데모 동작을 학습했음을 확인 (스모크 step 9는 0.15x로 zero-motion보다 나빴던 것과 대조적). action 파이프라인(절대 joint pos + DROID state stats + quantile norm)이 올바르게 작동했다는 실증. 단 train-split 프레임이므로 fit/sanity 확인이며, 일반화는 bench-v2에서 측정해야 함.

6Takeaway & Next

권장 방향

경로 1 (scenemem 이어가기)을 권장. 목표했던 finetuning이 이미 완주됐고 action 정합성 검증까지 끝났다. 남은 것은 체크포인트 품질 검증과 bench-v2 평가다. 새로 학습해야 한다면(다른 데이터 구성·하이퍼파라미터) 같은 파이프라인 재사용이 최소 비용.

경로 3 (RoboCasa fork 이식)은 "robocasa에서 한 것과 똑같이"라는 표현에 문자 그대로는 부합하지만, 카메라 3뷰 요구·groot 포맷 변환·norm stats 재산출이 전부 새로 필요해서 실익이 없다. RoboCasa365와의 비교 실험이 목적일 때만 고려.

7방향 전환 — 공식 MolmoBot-Pi0 경로 독자 셋업 (오후 업데이트)

사용자 결정: scenemem 선행작업은 데이터 누락(50/3,035 shards만 사용)·오류 가능성으로 배제. AllenAI 공식 pi05_mlspaces_finetune(pi05_droid init) 경로로 처음부터 셋업.

규약 검증 체인 (전부 코드+실데이터 실측)

항목검증 결과
카메라 2뷰pi05_droid 사전학습 자체가 2뷰 (exterior+wrist, 3번째 슬롯 zero+mask=False — DroidInputs 코드). RoboCasa fork의 3뷰 요구는 그 fork 자체 선택
arm ÷0.2물리 변환 아님 — per-step max joint delta 0.2 rad 정규화 규약. 공식 eval 설정 max_joint_delta: 0.2로 왕복 닫힘. 데이터 p99(|delta|)=0.2305≈캡. ÷0.2 후 p99 0.473 ∈ DROID action q99(0.448~0.79)
gripper ÷255MolmoSpace는 완전 이진 {0,255}(중간값 0%), 유지형 커맨드, 255=닫힘. DROID는 연속 bimodal(mean 0.45/std 0.44) — 이진은 그 두 mode 위의 부분집합. 방향 일치, quantile norm이 {0,1}→{-1,+1}
state 의미Franka 관절 지문 일치 (dim3 항상 음수 [-2.89,-1.15] vs DROID [-2.77,-0.45]; dim5 양수 [+1.33,+2.79] vs [+1.17,+3.47]). gripper state ÷0.824033=MAX_MLSPACES_GRIP_WIDTH. pi0.5는 continuous state 미사용(if not self.pi05) — discrete 토큰만, 8개 정수(패딩 전), 사전학습과 동일 코드 경로
padding 8→32사전학습 규약 그대로 — pi05_droid norm stats dims 8-31이 정확히 전부 0 (zero-pad로 사전학습됨). PadStatesAndActions는 openpi 표준 transform
E2E 파이프라인실데이터 48샘플×16스텝: 정규화 action \|a\|>3 = 0% (max 2.21), gripper 정확히 {-1,+1}, prompt 'Task: ..., State: 158 122 ...' pi0.5 정식 포맷, NaN 없음

셋업 완료 상태

항목상태
데이터: FrankaPnP OmniCam part1 전체 (train 660/660 shards 1.53TB + val) → ~/Dataset/molmobot_data/raw221,111 ep / 58.1M frames (scenemem의 14배). 4h35m (hf_transfer)
후처리: valid_trajectory_index.json (배포 h5에 mask 내장 확인 — 300/300, valid 98.5%)✅ 34초, 38,789 houses
venv (uv sync 8GB) + transformers 패치
pi05_droid JAX→PyTorch 변환 (7.2GB safetensors) + 로드 검증✅ missing 0 / unexpected 0
DROID norm stats prefetch (gsutil 파손 우회)
학습 스크립트 MolmoBot-Pi0/scripts/train_pi05_mlspaces.sh (auto-resume 내장 → sbmr 호환)✅ 작성
login 100-step 학습 스모크 (GPU 1, batch 16)loss 1.45→1.22, VRAM peak 34.5GB, 3m05s, NaN 없음
본 학습 제출 — job 80517 (--qos=own 8 GPU / 96 CPU / 1600GB / 2일, 20k steps, batch 256)✅ 제출됨 (제출 시점 클러스터 118/120 → PENDING)
디버깅으로 해결한 이슈 2건 — (a) opencv 이중 설치: opencv-python(non-headless)이 headless와 같은 cv2/ 디렉토리를 덮어써 libGL 부재로 bootstrap 중간 실패 → sys.path 오염 → spawn된 dataloader 워커가 typing→cv2/typing 섀도잉으로 전멸, 부모 90분 hang. headless 단독 + uv override(opencv-python; sys_platform=='never')로 수정. (b) torch cu126: B200 sm_100 커널 부재로 no kernel image — pytorch cu128 인덱스 핀으로 수정 (2.7.1+cu128). 둘 다 pyproject.toml에 영구 반영.
기타 함정: bulk_download.py --part 필터는 --max_part_shards 없이는 미적용 (part0 2TB를 받을 뻔). convert 스크립트는 실패해도 exit 0 + checkpoint 루트 경로 필요. 다운로드는 hf_transfer로 2.7배 개선 (660 shards 4h35m).