Index
2026-09-08 — Analysis

LingBot-VA all_low는 왜 하나도 못 했나 — 그리고 어떻게 고쳤나

FurnitureBench | 실패 에피소드 30개 + 액션 전처리 추적 | 이전 "부정 전이" 결론 철회

TL;DR

3.4×
rot1 실행 천장 부족
0.302
rot1 예측 최대 (천장 0.284)
19%
30-40% 구간 클립 프레임
86.6%
rot2 총 회전량 잔존
0.133
수정 후 one_leg (0 → 4/30)
p=0.005
클립본 0/80 대비

1무엇을 못 했나 — 실패 30 에피소드

실패 유형비율지표 근거
다리를 base 근처까지 가져갔으나 삽입 실패 (phase 3 정체)20/30leg_lift 0.11±0.10, leg_base_dist_min 0.12±0.06
다리를 아예 집지 못함6/30leg_lift ≤ 0.03 m
다리를 과도하게 튕겨냄ep9 등leg_lift 0.546 m = 데모 최대(0.17 m)의 3.2배
성공0/30전 에피소드 1000 step timeout
failure strip
정면 카메라, 에피소드 진행 15~99%. 위 2행은 성공(pi0.5 491 step, LingBot one_leg 단독 549 step) — t=45~60%에서 다리를 수직으로 세워 base 구멍 위에 정렬하는 장면이 뚜렷하다. 아래 3행은 all_low 실패 — 이 "다리 세우기"가 없고, 그리퍼가 다리를 박스 밖으로 쳐낸 뒤 빈 손으로 base 위를 배회한다.
pi0.5 b128 — 성공
491 step에 삽입 완료. 4배속.
all_low ep4 — 삽입 실패
base 위까지 가지만 다리가 서지 않아 들어가지 않는다.
all_low ep9 — 다리 튕김
leg_lift 0.55 m. 팔이 데모에 없는 각도로 꺾인다.
all_low ep2 — 못 집음
base만 0.35 m 밀고 다리는 한 번도 들지 못한다.
공통점: 실패는 "엉뚱한 곳으로 간다"가 아니라 "다리를 세우는 회전이 안 나온다"에 가깝다. 그리고 전 에피소드가 1000 step timeout — 방향이 아니라 크기의 문제라는 신호였다.

2왜 못 했나 — 액션 정규화 클리핑

wan_va/dataset/lerobot_latent_dataset.py:279-281 (학습) action_norm = (a - q01) / (q99 - q01) * 2 - 1 action_norm = np.clip(action_norm, -1.5, 1.5) # <- 학습 타깃이 여기서 잘린다 wan_va/wan_va_server.py:247 (추론, 역변환만) a = (n + 1) / 2 * (q99 - q01) + q01 => 모델이 낼 수 있는 물리 최대값 = 정규화 1.5에 대응하는 값으로 고정

회전 축은 분포 꼬리가 두껍다. all_low 354,849 프레임 기준으로 병진 축은 q99가 실제 최대와 거의 같은데, 회전 축은 q99가 실제 최대의 1/6~1/4밖에 담지 못한다. 대부분의 스텝은 회전이 0 근처이고 조립 구간에서만 큰 회전이 나오기 때문이다.

축q01 / q99 (현재 사용)q0.1 / q99.9실제 min / max
dx / dy / dz±0.11 ~ 0.11±0.12±0.12
rot1−0.162 / 0.195−0.338 / 0.628−0.655 / 1.310
rot2−0.424 / 0.451−0.900 / 1.384−1.273 / 1.832
clip analysis
좌·중: one_leg 데모의 회전 분포(로그 스케일)와 각 정규화가 만드는 실행 천장. 붉은 영역이 물리적으로 낼 수 없는 구간. 우: 클립된 프레임의 에피소드 내 위치 — 30~40% 구간에서 19%로, 정확히 "다리를 잡아 세우는" 동작 구간이다.
정규화 통계rot1 천장rot2 천장데모 요구부족 배수타깃 클립 비율one_leg 성공률
one_leg 단독0.6661.5880.965 / 1.7731.45× / 1.12×0.9% / 1.0%0.157
all_low (4가구 pooled)0.2840.6700.965 / 1.7733.40× / 2.65×2.1% / 2.9%0
데이터를 늘렸더니 필요한 회전이 잘려나갔다. 4가구를 합치면 one_leg의 큰 회전이 pooled 분포의 상위 0.25%로 희석돼 q99가 더 좁아진다. 왕복 검사(정규화→클립→역정규화)에서 에피소드 총 회전량은 one_leg 통계로는 99.1% 보존되지만 all_low 통계로는 86.6~89.1%만 남는다.

3결정적 확인 — 모델 출력이 천장에 붙어 있다

scripts/lingbot/diagnose_action_head.py(신규)로 teacher-forcing에서 flow matching을 역산해(x0 = x_t − σ·v) 모델이 만드는 물리 단위 액션을 직접 측정했다. job 113061/113062, 각 20 에피소드, σ=0.5. 먼저 all_low 3000 checkpoint:

측정dxdydzrot1rot2rot3grip
물리 단위 MAE0.0080.0070.0060.0200.0290.1370.059
모델 예측 |최대|0.1220.1220.0850.3020.7061.8511.068
실행 천장 (clip 1.5)0.1690.1690.1170.2840.6702.6281.500
데모 요구 최대0.1200.1200.0800.9651.7731.6731.000

두 모델 비교 — 같은 one_leg 에피소드, 각자의 정규화

모델rot1 예측최대 / 천장rot2 예측최대 / 천장rot1 MAErot2 MAE타깃 클립 비율one_leg 성공률
all_low 3000 (pooled q01/q99)0.302 / 0.2840.706 / 0.6700.01390.02282.11% / 2.79%0 / 30
one_leg 5000 (자체 q01/q99)0.677 / 0.6661.652 / 1.5880.01670.03100.39% / 0.12%0.157
one_leg 데모가 요구하는 값0.9651.773———1.0
두 모델 모두 자기 천장에 붙어 포화한다. 그런데 one_leg 모델은 all_low 모델보다 rot1을 2.2배, rot2를 2.3배 크게 낼 수 있다. 반면 MAE는 사실상 같다(rot1 0.014 vs 0.017) — 학습 품질 차이가 아니라 표현 가능한 범위의 차이만 존재한다. 성공률 0 vs 0.157의 차이가 여기서 나온다.
학습은 정상이었다. 물리 단위 MAE가 rot1 0.020으로 작다 — 모델은 주어진 타깃을 정확히 맞춘다. 그런데 예측 최대치가 천장에 소수점 셋째 자리까지 붙어 있다. 과제에 필요한 회전이 애초에 학습 타깃에 없었다.

4왜 pi0.5는 멀쩡했나

pi0.5(openpi)도 같은 분위수 통계를 쓴다 — assets/pi05_furniture_all_low_b128/.../norm_stats.json의 q99 rot1 = 0.1944로 우리 값 0.1947과 사실상 같다. 차이는 클리핑 유무 하나다.

openpi transforms.py:141-145 _normalize_quantile return (x - q01) / (q99 - q01 + 1e-6) * 2.0 - 1.0 # 클립 없음 → 정규화 5.3까지 그대로 학습/출력 LingBot lerobot_latent_dataset.py:281 action_aligned = np.clip(action_aligned, -1.5, 1.5) # 여기서 잘림
그래서 같은 데이터가 정반대 결과를 냈다. pi0.5는 one_leg 0.24 → 0.36으로 좋아졌고, LingBot은 0.157 → 0이 됐다. 멀티태스크 학습의 문제가 아니라, 두 파이프라인 중 하나만 꼬리를 자른 결과다.

4.5수정과 검증 — one_leg 0 → 0.133

수정: 분위수는 q1/q99 그대로 두고(openpi/pi0.5와 동일) 클립만 제거했다. lerobot_latent_dataset.py의 무조건 np.clip(±1.5)를 action_clip 설정 기반으로 바꾸고 furniture 계열에 None을 지정(libero/robotwin은 기존 1.5 유지). 클립 제거해도 정규화 RMS는 0.319→0.362로 거의 변하지 않는다(|n|>5는 0.005%). 재학습 113262(own QOS 8 GPU, 6 h 45 m, 3000→4000).

단계rot1 예측 최대rot2 예측 최대rot1 MAE
클립본 30000.302 (천장 0.284)0.706 (천장 0.670)0.0139
수정본 3100 (교정 100 step)0.9181.7410.0148
데모 요구0.9651.773—
교정 100 step 만에 회전 범위가 95~98% 복원됐고 MAE는 그대로다. 정확도를 잃지 않고 잘려 있던 구간만 되살아났다 — 진단이 옳았다는 직접 증거.

최종 평가 (checkpoint 4000)

모델one_leg 성공phaseleg_lift
클립본 all_low 30000/302.530.108±0.096 (최대 0.546)
수정본 all_low 40004/30 = 0.1333.030.128±0.044
one_leg 단독 50004/30 = 0.1332.830.132±0.071
pi0.5 b128 40k18/50 = 0.363.320.141±0.031
Fisher exact (양측)p해석
수정본 4/30 vs 클립본 all_low one_leg 누적 0/800.0048유의 — 수정이 성공을 만들었다
수정본 4/30 vs 클립본 3000 단일 0/300.112단일 비교는 검정력 부족
수정본 4/30 vs one_leg 단독 4/301.0통합 모델 = 단독 모델 (동등)
수정본 4/30 vs pi0.5 18/500.038pi0.5가 여전히 우위

다른 가구

가구클립본 3000수정본 4000부품 조립
cabinetphase 2.80 (1:1, 2:4, 3:1, 4:4)phase 3.50 (3:5, 4:5)4 → 6개
lampphase 2.90phase 3.000 → 1개
round_tablephase 3.20phase 3.002 → 0개
완전 조립 성공은 one_leg에서만 나왔다. 다부품 가구는 max_steps 1000이 데모 길이와 비슷해 두 번째 부품까지 갈 시간이 없다 — 1500으로 올린 재평가가 필요하다. cabinet은 phase 1~2 구간이 사라지고 절반이 부품을 조립해 실질 개선이 뚜렷하다.

5Takeaway

6수정안과 다음 단계

방안내용효과 / 비용
A (권장)norm_stat을 q0.1/q99.9로 재계산 + 클립 1.5 → 3.0rot1 천장 1.74 / rot2 3.9 → 데모 전 구간 커버. latent 재추출 불필요, 액션 정규화만 바뀜
B클립만 상향현재 q01/q99 유지 시 rot1은 8 이상 필요 → 학습 스케일 불균형 우려
C가구별 정규화구조 변경 크고 태스크 임베딩 필요