← Index
2026-09-01 — Engineering

molmo-augment place 트랙 학습 통합

MolmoBot | 2-stage low-level VLA의 hand-off 배치 개선용 — 변환부터 학습 제출까지

TL;DR

15,027
변환·정리 완료 궤적 (원본 15,043)
1.46M
학습 가능 프레임
0.20
혼합 가중치 (place)
7건
발견·처리한 문제

1전체 흐름

HF 원본101 tar · 121 GB
→
변환house 레이아웃
index · stats 생성
→
정리카메라 누락 16편 제외
→
splittrain 14,567
val 460
→
학습mix@10k에서 이어서
10k step
출력 ~/Dataset/molmo_augment_place/ train/ house_N/{trajectories_batch_*.h5, episode_*.mp4} valid_trajectory_index.json · valid_trajectory_index.raw.json · aggregated_stats.json goal_im/<에피소드>/{wrist_camera,exo_camera_1,exo_camera_2}.png ← 아직 미사용 val/ (동일 구조, house 149개)

2만든 것 / 바꾼 것 / 안 바꾼 것

새로 만든 파일

파일역할
MolmoBot-Pi0/scripts/convert_molmo_augment.pytar → house 레이아웃 변환. shard를 하나씩 받아 풀고 tar는 즉시 삭제(디스크 피크 최소화). 같은 (house, batch)의 clip.h5를 병합하고 index·stats를 생성
MolmoBot-Pi0/scripts/split_augment_val.pyhouse 단위 val split. 편 단위로 나누면 같은 씬이 train/val에 섞여 누수가 생긴다
tmp/fix_index_cameras.py필요 카메라가 없는 궤적을 인덱스에서 제외(일회성)
tmp/verify_place_ds.py실제 로더로 전체 로드 검증(일회성)

수정한 파일

파일변경
scripts/train_pi05_mlspaces.shPLACE=1 모드 추가(A안 비율 + init을 mix/10000으로 자동 지정 + 10k step), INIT_CKPT를 env로 오버라이드 가능하게
변환본 h5의 obs_scene.task_descriptionPick up the X and place it next to the Y → Place the X next to the Y (우리 사본만)
변환본 valid_trajectory_index.json카메라 누락 16궤적 제외. 원본은 .raw.json으로 백업

일부러 안 바꾼 것

대상이유
HF Keh0t0/molmo-augment원본 무수정. 모든 조정은 우리 변환본에서
기존 MolmoBot-Data 5종무수정
prompt_templates config건드리면 안 된다. create_dataset_from_path가 모든 데이터셋에 같은 템플릿을 적용하므로, place 전용 템플릿을 넣으면 main PnP에서도 "Pick up"이 사라진다 — main은 집기가 실제로 들어 있으니 그건 틀린 라벨이 된다
모델 코드(DroidInputs 등)goal image 미연결 상태 유지. language-only 기준선 먼저
mp4 · goal png 바이너리그대로 복사만

3발견한 문제 7건과 처리

#문제그대로 뒀다면조치
1카메라 누락 편 — 일부 편에 wrist_camera_zed_mini·randomized_zed2_analogue_1이 없음(clip_meta.dropped_cameras)해당 샘플이 뽑히는 순간 KeyError로 학습 중단전수 스캔 후 16궤적(0.11%) 인덱스에서 제외
2h5 지시문에 "Pick up" 접두 잔존 — 친구분 08-31 수정은 augment.json에만 반영, 로더가 읽는 obs_scene은 그대로집는 동작이 없는 클립에 "집어라" 라벨로 학습변환 시 task_description을 place 형태로 재작성(문형 단일, 정규식 1개)
3디렉토리 구조 불일치 — webdataset tar vs 로더가 요구하는 house 레이아웃로드 불가변환 스크립트. 원본 traj 인덱스·mp4 파일명이 보존돼 있어 병합 시 키 충돌 없음(전수 확인)
4aggregated_stats.json 부재 — 정규화 통계로드 불가편별 stats/traj_K의 count/sum/sum_sq를 합산해 정확 재구성(근사 아님)
5프롬프트 폴백 ~11% — referral_expressions가 빈 편(12.7%)에서 템플릿이 task_description으로 떨어짐11%가 "Pick up" 문장으로 학습#2의 h5 재작성으로 자동 해소(폴백해도 place 문형). 실측 집기 접두 0/400
6씬 누수 위험 — 편 단위 split 시 같은 house가 train/val 양쪽에val 성능 과대평가house 단위 split(149 house / 460 궤적, 3.1%)
7디스크 — NAS 96% 사용, tar+추출 동시 보관 시 242 GB 필요여유 잠식shard 단위로 받아 풀고 즉시 삭제 → 피크 +1.2 GB, 최종 17T 여유 유지

4무시해도 되는 것들

확인은 했지만 조치가 불필요하거나 영향이 미미한 항목들이다.

항목규모판단
카메라 누락으로 제외한 궤적16 / 15,043 (0.11%)무시 가능. 학습량에 영향 없음
floor 라벨 17편0.11%버그 아님 — 실제 욕실 바닥 배치. procthor에서 바닥은 rigid body가 아니라 world 지오메트리라 body="world", z=0.0이 정상값(물체 시작 높이 0.052 m로 확인)
README와 실제 지시문 불일치문서만README는 Put the {obj}…, 실제는 Place the …. 우리는 h5를 재작성해 쓰므로 무관. 친구분께 알려만 두면 됨
ls house 수(4,822)와 인덱스(4,819) 차이3개모든 궤적이 제외된 house의 빈 디렉토리. 로더는 인덱스만 보므로 무해
goal image 해상도·카메라 불일치640×480 vs 624×352지금은 무관 — goal image를 안 쓰니까. 3번째 슬롯을 켤 때 다시 볼 항목
exo view의 이상한 화각—증강 탓 아님. randomized_* 카메라의 의도된 포즈 랜덤화이고 원본도 동일
.tars 잔여69 KBHF 캐시 메타만 남음

5혼합 비율과 근거

가중치는 DistributedWeightedDatasetSampler에서 weights/sum(weights)로 정규화된 뒤 ① 데이터셋을 확률로 뽑고 ② 그 안에서 균등 추출하는 데 쓰인다. 즉 가중치는 "학습 샘플이 그 데이터셋에서 나올 확률" 자체이고 데이터셋 크기와 무관하다. main은 1 − sum(aux).

데이터셋에피소드프레임기존(mix v2)이번(A안)
main PnP p1221,10958.2M0.350.30
Pick p0772,97156.2M0.200.15
PnP p0323,68483.3M0.100.10
NextTo p237,39211.5M0.200.15
Color p028,1777.4M0.150.10
place (신규)14,5671.42M—0.20
place 0.20은 과다 반복이 아니다. 10k step × batch 256 = 2.56M 샘플 중 20%면 512k 추출인데, place 프레임이 1.42M이므로 0.36 epoch이다. 0.35까지 올려도 0.62 epoch이라 여유가 있다 — place는 프레임 기준 전체의 0.7%로 가장 작은 데이터셋이다.
init을 pi05_droid가 아니라 pi05_mlspaces_mix/10000으로 잡은 이유: 이미 MolmoSpaces 도메인을 아는 상태라 10k step을 새 스킬(hand-off 배치)에만 쓸 수 있다. mix v2가 10k에서 3태스크 평균 최고(24.0%)였다는 A/B 결과도 이 지점을 가리킨다.

6현재 상태와 다음

# 제출 (job 105831, PENDING — own 8 GPU를 다른 세션 flexpi가 사용 중) PLACE=1 sbm "bash .../scripts/train_pi05_mlspaces.sh" --qos=own --gres=gpu:8 -c 96 --mem 1600GB \ --time 1-00:00:00 -J pi05place --container=nvcr.io/nvidia/cuda:12.8.0-devel-ubuntu22.04

-c 96은 GPU당 12 CPU로, 기본 8보다 높지만 NUMA-local 상한 안이다. dataloader worker가 8 rank × 8 = 64개라 코어당 1개는 빠듯해서 여유를 뒀다.

학습 시작 직후 확인할 것: 로그에 Using N/M houses 줄이 6개 나와야 한다(main + aux 5종). mix v1(job 83196)이 tyro dict 파싱 버그로 데이터셋이 조용히 누락된 채 12시간을 돌았던 전례가 있어, 이 줄 수가 곧 mixture가 제대로 붙었다는 증거다.

남은 작업

  1. 평가 수단 — PnP/NextTo HardBench는 "깨끗한 초기 상태에서 집기+놓기"를 재므로 hand-off 배치를 측정하지 못한다. 떼어둔 val 460궤적으로 open-loop action 오차를 재는 게 가장 싸고, 진짜 지표는 2-stage 파이프라인의 place 성공률이다.
  2. goal image 연결 — ① 로더가 goal_im/<에피소드>/를 읽도록(에피소드명은 house·batch·traj로 결정적 재구성 가능), ② DroidInputs에서 3번째 슬롯 zeros→goal / False_→True_ 두 줄, ③ goal dropout으로 goal 없이도 동작 유지. 토큰 수는 안 변한다.
  3. B안 검토 — A안에서 기존 태스크가 유지되면 place 가중치를 0.35까지 올려 hand-off 배치를 더 밀어붙인다.