TL;DR
- Pi0.5 mix 학습 도중 stats.json 검증 시행 → 5개 dataset 모두 byte-exact 동일 stats (실제 분포와 전혀 다름) 발견.
- main(mg30_real_h50) gripper dim 6: 실측 ±1 binary, stats q01=−0.925 → unnormalize 범위 [−0.925, q99]로 제한 → gripper full close/open 명령 생성 불가.
- 이전 Pi0.5 실험 전체 (B0/B1/B2/ref + mix) 동일 bug 영향 — close-task SR=0의 결정적 원인 후보.
- Fix:
scripts/recompute_stats_action_state.py로 parquet 직접 재계산. 4 dataset 각각 10초.
- Jobs 2077/2078/2079 scancel → 2355/2356/2357 재제출 (학습 코드/recipe 동일, stats만 변수).
−0.925
stats q01[6] (실측 −1.0)
1 배경/목적 (왜)
2026-05-13 14시경, Pi0.5 P3 mix 학습 Jobs 2077/2078/2079가 실행 중인 상황에서 "Action normalization 하나요?" 질문으로 검증 시작.
Pi0.5 config (configuration_pi05.py:65-71):
normalization_mapping = {
"VISUAL": IDENTITY,
"STATE": QUANTILES, # q01/q99로 [-1,1] mapping + clamp
"ACTION": QUANTILES,
}
Action에 QUANTILES normalize 적용. mix 학습에서 processor_kwargs["dataset_stats"]에는 main(real) stats만 들어감 — aux 분포는 무시. normalize 공식:
clamp(2.0 * (action - q01) / (q99 - q01) - 1.0, -1.0, 1.0)
이 q01/q99가 정확하지 않으면 training 시 clamp로 보정되지만 inference시 unnormalize가 잘못된 범위로 복원되어 실제 action 명령이 의도한 값을 벗어난다.
2 작업 내용 (어떻게)
1단계 — 5개 dataset stats.json 비교
대상: main mg30_real_h50, aux × 3 dreamgen_robocasa_p3_{init0,mid,random}_v2_droid, aux dreamgen_robocasa_p3_init0_v2 (OLD non-droid)
5개 모두 byte-exact 동일 stats (q01[0]=−0.806, q99[0]=+0.775). 서로 다른 dataset임에도 분포가 완전히 동일할 수는 없음 → 어딘가에서 복사된 template stats.
2단계 — DAVIAN robocasa-H50 stats 비교
DAVIAN robocasa-H50 stats: q01[0]=−0.748. 우리 −0.806과 다름 → 우리 stats는 DAVIAN 것도 아닌, 출처 불명 표준 template으로 추정.
3단계 — 실측 vs stats.json 직접 비교 (parquet np.quantile)
| Dataset | stats q01[0] | 실측 q01[0] | stats q99[0] | 실측 q99[0] |
| main mg30_real_h50 | −0.806 | −1.000 | +0.775 | +1.000 |
| aux p3_init0_droid | −0.806 | −0.602 | +0.775 | +0.615 |
| aux p3_random_droid | −0.806 | −0.602 | +0.775 | +0.591 |
| aux p3_init0 (OLD) | −0.806 | −0.980 | +0.775 | +0.580 |
4단계 — gripper dim 6 집중 분석 (가장 심각)
| dim | 의미 | 실측 q01 | stats q01 | −1 포화율 | +1 포화율 |
| 0–2 | eef pos | −1.000 | −0.806~−0.703 | 1–2% | 1–2% |
| 6 | gripper | −1.000 | −0.925 | 65.20% | 34.80% |
gripper는 open(−1) / close(+1) binary action — 98% 포화. stats q01=−0.925 → QUANTILES unnormalize 시 model 출력 −1.0 → unnormalize = −0.925까지밖에 안 나옴. 실제 gripper close/open 명령이 경계값에 도달하지 못함 → close-task SR=0의 결정적 원인 후보.
5단계 — Fix 도구 작성
scripts/recompute_stats_action_state.py: 4 dataset의 parquet 직접 읽어 action+state 재계산. (VISUAL은 Pi0.5 IDENTITY 라 skip.) min/max/mean/std/count + q01/q10/q50/q90/q99 (lerobot v3.0 표준). 기존 stats.json → .bak 백업 후 덮어쓰기. ~10초 / dataset.
6단계 — 재제출
scancel 2077 2078 2079
# 재계산 (~10초 each)
python scripts/recompute_stats_action_state.py
# 동일 launch script로 재제출 (코드 변경 없음 — dataset.meta.stats 자동 reload)
sbmr 5 "bash scripts/launch_pi05_b2_p3_mix_new_idm.sh" P3_VARIANT=init0 --qos=own → Job 2355
sbmr 5 "bash scripts/launch_pi05_b2_p3_mix_new_idm.sh" P3_VARIANT=mid --qos=own → Job 2356 (PD)
sbmr 5 "bash scripts/launch_pi05_b2_p3_mix_new_idm.sh" P3_VARIANT=random --qos=extra → Job 2357 (PD)
3 결과 (수치)
새 stats (실측 일치, 대표값)
| Dataset | q01[0:3] (eef pos) | q99[0:3] | 변화 |
| main mg30_real_h50 | [−1.000, −1.000, −1.000] | [+1.000, +1.000, +1.000] | −1.0 포화 정상 반영 |
| aux p3_init0_droid | [−0.602, −0.619, −0.467] | [+0.615, +0.699, +0.473] | 좁은 분포 정상 반영 |
| aux p3_mid_droid | [−0.563, −0.595, −0.390] | [+0.646, +0.633, +0.450] | |
| aux p3_random_droid | [−0.602, −0.595, −0.456] | [+0.591, +0.646, +0.441] | |
재제출 현황
| Old Job | New Job | Variant | QOS | 변수 |
| 2077 (cancelled) | 2355 CF | init0 | core-own | stats.json 정확도만 |
| 2078 (cancelled) | 2356 PD | mid | core-own | stats.json 정확도만 |
| 2079 (cancelled) | 2357 PD | random | core-extra | stats.json 정확도만 |
학습 코드/하이퍼파라미터/dataset/seed 동일. 변수는 stats.json 정확도 하나만.
4 Takeaway
Pi0.5 close-task SR 낮은 결정적 원인 후보 발견: stats 부정확 → unnormalize 범위 제한 → gripper ±1 boundary 도달 불가 → gripper full close/open 실패. HANDOFF doc §11의 "controller drift로 GT actions도 left=0.105까지밖에 못 닫음" 증상과 일치.
이전 Pi0.5 실험 전체 영향: B0/B1/B2 baseline + mix(1198–1200) + ref 트랙 전부 동일 부정확 stats 사용. 절대 SR 모두 underperform 가능성. 같은 stats 부정확성을 공유한 실험끼리의 상대 비교는 valid.
추가 해석
aux 분포 (±0.6)가 main stats (±1.0)으로 normalize되는 구조: mix 학습에서 main stats만 정책에 전달되므로, aux의 좁은 분포(±0.6)는 normalize 후 [−0.6, +0.6] 영역에 매핑 → 학습 신호가 부드러워지는 효과. main stats가 정확하면 이 구조는 문제 없음.
IDM eval에는 영향 없음: IDM(Pixel, Latent 트랙)은 action stats를 Pi0.5 QUANTILES 방식으로 사용하지 않음 → IDM eval 수치는 모두 valid.
5 Next Steps
- 2355/2356/2357 학습 정상 시작 검증: RUNNING 전환 + mix 로그 4줄 + step 1000 in-loop SR 확인.
- stats fix vs no-fix SR 비교: 학습 완료 후 24-task eval — 특히 close-task family (CloseDoubleDoor, CloseSingleDoor, CloseDrawer) SR 향상 여부 주목. stats fix 가설 검증 핵심.
- 기존 ckpt re-evaluation 옵션: 1198/1199/1200 마지막 ckpt에 대해 eval 시점에 새 stats로 unnormalize 적용 → inference만 재실행. 학습 재실행 없이 stats fix 효과 격리 측정 가능.
- HF dataset 동기화: local stats.json만 수정.
huggingface-cli upload Keh0t0/<repo> meta/stats.json 으로 HF push 권장 (private).
핵심 파일
scripts/recompute_stats_action_state.py
/home/nas_main/taewoongkang/Dataset/robocasa/mg30_real_h50/meta/stats.json.bak
/home/nas_main/.cache/huggingface/lerobot/Keh0t0/dreamgen_robocasa_p3_*_v2_droid/meta/stats.json.bak