Index
2026-08-21 03:10 — Progress (중간 정리)

WM 실패 물리 finetune — 데이터 구축 · 4건의 장애 · ft5000 추세 · E2 진단

cosmos | 08-20 06:00 → 08-21 03:00 | 플랜: plan · Phase 0 상세: phase0 · FD replay 선행: v4

TL;DR

54.6 GB
LeRobot v3 (1,900 ep)
4
장애 원인 확정·수정
8%→46%
v4 every4 beats_copy
0→12→27%
v4 open_loop beats_copy
base / succ / mix
+4%p
H4 격차 (기준 +15%p)

1 배경 / 목적

FD replay v4–v6에서 base Cosmos3-Nano는 재접지 1–2 s(N=2)에선 낙하·전도를 재현하지만 3–4 s(N=4)에서 붕괴하고 편향이 under-commit("어떻게 집든 집히고 안 떨어지는" 세계)임이 정량화됐다. 이 플랜은 RoboLab 성공+실패 rollout으로 WM을 FD 모드로 finetune해 (H1) 더 긴 horizon에서 실패 사건 재현, (H2) 성공 충실도 유지, (H3) 같은 맥락·다른 액션 → 다른 결과, (H4) FT-succ 대조로 "실패 데이터 기여" 분리, (H5) unseen 태스크 일반화를 사전 등록 기준으로 검증한다.

사용자 합의: 기존 2,400 ep로 즉시 시작 + 재수집 병행, own 4 GPU × 2 run(FT-mix 먼저), 인터페이스는 base FD와 동일 고정.

2 구축한 것 (Phase 0 · 평가 인프라 · Phase 2 선행)

구성내용상태
변환기 robolab_to_lerobot.py4패널 센서 mp4 → per-view h264 3개 + DROID 피처 parquet, `episode_id`로 keep-ranges 키. NaN trace 3 ep 게이트. CPU sbatch 2샤드×30 worker ≈ 15분/샤드완료 성공 261 / 실패 1,639 ep, 54.6 GB
정합성 테스트 test_wm_dataset_parity.py학습 샘플 vs FD 추론 경로: action max|Δ| 7.7e-5–1.6e-4 · 비디오 mean|Δ| 2.1–3.5/255 · JSON 프롬프트 문자열 동일8/8 통과
Split build_wm_split.pytest-A 52 ep(seen task) / test-B 15 unseen 태스크 259 ep(쌓기 5·drop-rich 6·grasp_miss 2) / val 79 / train 1,513(195 succ/1,318 fail), seed 고정확정
keep-ranges build_event_keep_ranges.py공식 use_filter_dict로 split + 사건 가중(gripper 전이 + contact detector ±2 s): 실패 train 1,285 ep, 중앙값 18 사건/ep, 사건 윈도우 44%완료
실험 config action_fd_robolab_{mix,succ}_nano공식 레시피 deepcopy + 델타: mode=forward_dynamics · ee_pose 10D quantile · chunk 16 · JSON 프롬프트 · action head 로드 · lr 5e-5 cosine · loss_scale 10 · 혼합 2:1:1(rank 양자화) · augment=bc · decoder-cache clear · repeat=16 · loader timeout 900운영 중
평가 E1기존 코호트 v4/v5/v6b + testB 신규 24 ep; LPIPS 스코어러 빈 구간 fallback 추가 후 base 4 코호트 재계산; run_wm_eval_e1.sh, wm_score_all.sh, wm_eval_summary.pybase 기준선 확보
평가 E2 fd_counterfactual_prep.py / _metrics.py같은 재접지 프레임 + 액션 편집 쌍: suppress_release 40쌍, early_release 15쌍; 추가 진단 fd_action_shuffle_prep.py 48쌍base·ft 채점
ckpt 파이프라인새 DCP ckpt → export_fd_ckpt.sh(137 GB → HF 30 GB) → E1(v4 e2/e4, testB e2) + E2 잡 자동 제출(tag ft<N>)ft1000–ft6000
Phase 2: 물체 pose 로거 robolab_object_pose_logger.pyRoboLab WorldState 기반 run_episode 훅 → objpose_<run>_env<k>.npz [T,n_obj,3]; 스모크 4/4 (banana z 0.02→0.21)검증
Phase 2: 재수집 sweep4 샤드×30 태스크, NUM_ENVS=10, 영상 전량+trace+objpose, RUN_TAG 고정 → preempt/TIMEOUT 후 resume(watcher)진행 330/1,200 ep

3 장애 4건과 원인 (운영 기록)

#증상원인 (확정 근거)수정
1스모크 87812: 40 s/iter, GPU util 10%공식 aug ColorJitter(hue)가 51프레임 float 텐서에 HSV 변환 → 1스레드 5.1 s/샘플(벤치)augment=bc(crop+brightness/contrast) 1.4 s/샘플, worker 10, -c 48
2같은 스모크 iter 25 hang → 30분 후 NCCL watchdog(당시 추정) 메인 OpenMP 풀 생성 후 fork → worker 데드락. ※ 사후에 #4와 같은 rollover 주기(24 step)였음이 밝혀짐OMP_NUM_THREADS=1 (유지)
387870 iter 1000 ckpt 저장 중 OOMKilled(300 GB); 88016도 RSS +13 GB/100 iterlerobot VideoDecoderCache가 mp4 경로마다 decoder+file handle 영구 보관(상한 없음). 로그인 재현 worker 1.9→9.2 GiB/160샘플; pyav 백엔드는 평탄factory wrapper에서 샘플마다 _default_decoder_cache.clear() → RSS 40–50 GiB 평탄; --mem 950GB
488154 iter 3470, 88887 iter 5470 hang(CPU 92→8%)성공 데이터셋 epoch rollover: 79,031 윈도우 / rank당 32 = 2,470 step 주기(1000+2470, 3000+2470; 스모크 24+1). 실패 데이터셋은 10–25× 커서 해당 없음_RepeatDataset repeat=16(epoch 39.5k step), DataLoader timeout 900(15분 내 종료), wm_watch_train.sh 자동 resume 재제출
비용: 재시작 3회로 약 1,000+470+470 iter(≈3.3 h) 손실, 하지만 ckpt 1000/2000/3000/5000에서 resume해 학습 자체는 연속. 쿡북·프레임워크 문서에 없던 항목들이라 memory(cosmos3-sft-dataloader-pitfalls)에 기록.

4 결과 — E1 (사건 정렬 replay, LPIPS 통일 스코어러) · 최종 ft8000

표 읽는 법. 모든 수치는 base → ft8000(FT-mix 최종 체크포인트, iter 8000). advanced=예측이 사건 이후 GT 쪽으로 나아간 비율, beats_copy=마지막 재접지 프레임을 그대로 유지하는 관성 베이스라인보다 GT에 가까운 비율(주지표), d_post=사건 이후 LPIPS 중앙값(낮을수록 좋음). every2/every4/open_loop = 2·4청크마다 재접지 / 전혀 재접지 없음(8.5 s 전부 상상).

4.1 최종 표 — 코호트 × 재접지 간격 (base → ft8000)

코호트 (n)조건advancedbeats_copy (주지표)d_post 중앙값
v4 seen (48)every2 (1.1–2.1 s)81% → 90%50% → 62%0.248 → 0.174
every4 (3.2–4.3 s)50% → 83%8% → 46%0.342 → 0.256
open_loop (8.5 s)19% → 69%0% → 27%0.488 → 0.340
testB unseen 15 태스크 (24)every2 (1.1–2.1 s)71% → 88%38% → 71%0.286 → 0.205
every4 (3.2–4.3 s)33% → 83%4% → 46%0.400 → 0.268
open_loop (8.5 s)46% → 83%0% → 29%0.488 → 0.340
v5 block · 놓음 앵커 (24)every2 (1.1–2.1 s)83% → 62%54% → 42%0.173 → 0.183
every4 (3.2–4.3 s)50% → 50%4% → 21%0.295 → 0.221
open_loop (8.5 s)42% → 54%0% → 17%0.459 → 0.294
v6b block · 접촉 앵커 (16)every2 (1.1–2.1 s)100% → 100%100% → 100%0.177 → 0.128
every4 (3.2–4.3 s)100% → 100%94% → 100%0.248 → 0.169
open_loop (8.5 s)56% → 100%0% → 56%0.503 → 0.319
핵심. 재접지가 드물수록(=상상 구간이 길수록) 개선폭이 크다. v4 every4 beats_copy 8% → 46%, open_loop 0% → 27%(8.5 s를 통째로 상상하는 조건에서 base는 단 한 건도 관성 베이스라인을 못 이겼다). unseen 15태스크(testB)에서도 every2 38→71% · every4 4→46%로 같은 방향 — 태스크 암기가 아니다. 예외는 v5 block(놓음 앵커) every2로 54→42% 하락인데, 이 코호트의 실패 사건 절반은 gap 0.14–0.17로 장면이 거의 안 변해 "정지"가 사실상 정답인 경우다(§6.2b).

4.2 체크포인트 추세 — 과적합 없이 8000까지 단조 개선

ckptv4 every2 adv / copy / d_postv4 every4 adv / copy / d_posttestB every2 adv / copy / d_post
base81% / 50% / 0.24850% / 8% / 0.34271% / 38% / 0.286
ft100081% / 56% / 0.21358% / 17% / 0.309
ft200079% / 58% / 0.19465% / 21% / 0.30183% / 54% / 0.225
ft300081% / 60% / 0.19065% / 29% / 0.28388% / 58% / 0.213
ft400081% / 62% / 0.18775% / 40% / 0.26983% / 67% / 0.211
ft500085% / 62% / 0.18479% / 42% / 0.26283% / 67% / 0.214
ft600086% / 64% / 0.18186% / 45% / 0.26488% / 71% / 0.204
ft700088% / 62% / 0.17881% / 44% / 0.25688% / 71% / 0.210
ft800090% / 62% / 0.17483% / 46% / 0.25688% / 71% / 0.205
0%20%40%60%80%100%baseft1000ft2000ft3000ft4000ft5000ft6000ft7000ft8000checkpoint (FT-mix, iter)v4 every2 62%v4 every4 46%testB every2 71%v4 seen · every2v4 seen · every4testB unseen · every2
Figure 1. beats_copy rate(예측이 관성 베이스라인보다 실제 결과에 가까운 비율) — iter 8000까지 단조 상승하고 정체·하락 없음. every4(3–4 s 상상)가 8%→46%로 최대 개선. testB는 ft1000 미실행.

4.3 실패 모드별 (v4 n=12/모드, testB n=8/모드) — every4 기준, base → ft8000

코호트 · 모드advancedbeats_copyd_post
v4 · drop (n=12)42% → 83%8% → 58%0.382 → 0.291
v4 · grasp_miss (n=12)58% → 92%0% → 25%0.303 → 0.209
v4 · stack_disturb (n=12)67% → 75%25% → 83%0.319 → 0.304
v4 · success (n=12)33% → 83%0% → 17%0.310 → 0.228
testB · drop (n=8)38% → 88%0% → 50%0.403 → 0.297
testB · stack_disturb (n=8)38% → 62%12% → 62%0.352 → 0.287
testB · success (n=8)25% → 100%0% → 25%0.421 → 0.226
v5 block · stack_disturb (n=16)69% → 38%6% → 31%0.279 → 0.248
v5 block · success (n=8)12% → 75%0% → 0%0.331 → 0.186
v6b contact · stack_disturb (n=16)100% → 100%94% → 100%0.248 → 0.169
가설 판정 (E1 대리지표 기준). H1(실패 물리 재현) 충족 — v4 every4 beats_copy +38%p(사전 등록 기준 +30%p), drop 8→58% · stack_disturb 25→83% · grasp_miss 0→25%. H2(성공 충실도 유지) 충족 — success 모드도 악화 없이 개선(v4 every4 adv 33→83%, d_post 0.310→0.228). H5(unseen 태스크 일반화) 충족 — testB 전 모드 개선, every4 beats_copy 4→46%. H4(FT-mix vs FT-succ) 보류 — 대조 학습을 GPU 양보로 iter 3213에서 중단(재개 예정). 사건 단위 육안/VLM 판정도 남음.

5 결과 — E2 (액션 편집 counterfactual) 와 액션 셔플 진단 · 최종 ft8000

셀 = div(편집 전후 예측 차이, 액션 민감도) / direction_ok(변화 방향이 물리적으로 옳은 비율) / beats_copy(원본 액션 예측의 충실도).
kind (쌍 수)baseft2000ft5000ft8000
suppress_release (40) — 실패 release에서 그리퍼 닫힘 유지0.054 / 88% / 62%0.030 / 82% / 75%0.026 / 70% / 78%0.026 / 80% / 80%
early_release (15) — 성공 배치 64스텝 전 열기0.171 / 80% / 40%0.073 / 73% / 80%0.037 / 53% / 93%0.024 / 47% / 93%
shuffle_actions (48) — 다른 에피소드 액션 전체 투입0.269 / 96% / 54%0.245 / 100% / 73%0.246 / 100% / 73%
관찰: 원본 액션 예측의 충실도(beats_copy)는 계속 좋아지는데(suppress 62→80%, early_release 40→93%), 그리퍼 채널만 바꾼 편집에 대한 예측 변화(div)는 base의 절반 이하로 줄고(0.054→0.026, 0.171→0.024), early_release의 direction_ok는 우연 수준(80→47%)까지 떨어진다.
진단: 액션 전체를 바꾸면 ft8000도 base만큼 예측이 바뀌고(div 0.246 vs base 0.269) 실제 액션이 결과를 더 잘 설명하는 비율이 96→100%(원본 예측 충실도 beats_copy 54→73%) → "액션을 무시한다"는 기각. E2의 div 감소는 팔 궤적은 원본인 채 그리퍼 스칼라만 바꾼 편집에 둔감해진 것(FT는 팔 궤적+시각 맥락으로 예측). §6 FAQ에서 확인했듯 데이터에는 짧은 그리퍼 펄스가 흔해(305회/112 ep) 이 편집 자체는 OOD가 아니며, 오히려 "그런 펄스는 대개 결과를 바꾸지 않는다"를 학습한 쪽에 가깝다. "놓으면 떨어진다"를 제대로 묻는 E2는 Phase 2b(sim에서 편집 액션을 실제 실행 → GT)로 재설계.

6 영상 비교 — GT vs base vs FT-mix(ft5000; 블록 코호트 §6.2b는 최종 ft8000)

비교 기준과 지표 정의. GT = 같은 에피소드의 실제 sim 영상(사건 정렬 8청크 = 128프레임 @15 Hz). 모델은 N청크마다 실제 프레임으로 재접지되고(패널 헤더의 파란 눈금) 그 사이를 상상한다(N=2: 1.1–2.1 s, N=4: 3.2–4.3 s). 판정 구간은 사건(노란 마커) 이후 프레임(사건이 윈도우 끝이면 마지막 청크). 주지표는 LPIPS(AlexNet perceptual distance, 320×270): d_post=LPIPS(예측, GT) 평균 · gap=LPIPS(마지막 재접지 프레임, GT)=관성(copy) 베이스라인의 d_post · beats_copy=d_post<gap · advanced=d_post<d_pre(정지 장면보다 실제 결과 쪽). PSNR은 보조(아래 표): 흐릿한 평균 예측을 과대평가하고 정확한 사건의 작은 위치 오차를 과벌하기 때문에 주지표로 쓰지 않는다 — 실제로 정지 프레임(copy)의 PSNR이 모든 생성 영상보다 높게 나온다. 최종 H1 판정은 사건 단위(떨어뜨렸나/무너졌나) 육안·VLM 판정으로 한다.

6칸 레이아웃: 윗줄 GT · base N=2 · ft5000 N=2, 아랫줄 copy(관성: 마지막 N=2 재접지 프레임 유지) · base N=4 · ft5000 N=4. 하단 두 띠는 그리퍼 채널: 위 = WM에 입력된 그리퍼 명령(초록=열림 / 빨강=닫힘, 모든 WM 패널에 동일 입력), 아래 = sim 그리퍼 관절의 실제 위치(연속값 0–1, 초록 0=열림 → 빨강 1=끝까지 닫힘); 흰 세로선이 현재 프레임이고 맨 아래 줄에 현재 값이 글자로 표시된다 — 즉 그 시점에 그리퍼가 닫혀야 하는지(명령)와 실제로 얼마나 닫혔는지를 같이 볼 수 있다. 달성값은 손가락이 물체에 막히는 지점에서 멈추므로 블록을 잡으면 ≈0.47, 큐브 ≈0.33, 캔 ≈0.25에서 멈추고, 빈손으로 닫히거나(파지 실패) 얇은 물체(머그 손잡이·주걱)를 잡으면 ≈1.0까지 간다 — 예: StackYellowOnRed env2는 0.47(블록 파지) → 1.0(블록이 빠져나감) → 0(놓음)으로 사건이 그대로 읽힌다. (초기 버전은 이 값을 0.5로 이진화해 '블록 파지 중'을 열림으로 표시하는 오류가 있어 연속값으로 교체했다.) 캡션의 수치는 LPIPS d_post(낮을수록 GT에 가까움) base → ft5000. 선정: 모드별 every4 개선폭 상위 2개 + 최대 악화 1개(정직성).

그리퍼 채널 FAQ (영상을 보다 생기는 질문 3가지).
  1. 왜 "WM 입력 명령"과 "sim 달성"이 다른가? 명령은 정책(Cosmos3-Nano-Policy)의 그리퍼 출력을 RoboLab 클라이언트가 >0.5로 이진화한 0/1 신호이고(policies/cosmos3/client.py::_postprocess_chunk), WM(FD)은 이 명령을 액션으로 받는다. 달성은 물리 결과 — 닫히는 데 0.3–0.5 s가 걸리고, 물체 폭에서 멈춘다(블록 0.47). 그래서 둘은 원래 같을 수 없고, 그 차이가 바로 사건이다: 명령 '닫힘'인데 달성이 1.0으로 치솟으면 빈손(파지 실패/낙하), 0.47에 머물면 파지 유지.
  2. GT(actual sim)에서 이동 중 그리퍼가 순간적으로 열렸다 닫히는 이유? 정책 자체의 동작이다. 112개 에피소드 궤적을 세어 보면 ≤10스텝(≤0.67 s)짜리 짧은 명령 펄스가 305회(62/112 에피소드에 1회 이상, 평가 윈도우 안에 55회), 전부(305/305) 파지/놓기 전환점 ±2 s 안에 있고 72%(220/305)가 액션 청크 경계(32스텝마다 재계획)에 걸쳐 있다 — 연속 그리퍼 출력이 전환 근처에서 0.5 문턱을 오르내리고, 새 청크의 앞부분이 이전 청크 끝과 다르게 예측될 때 0/1이 뒤집힌다. sim 그리퍼는 그 펄스를 따라 실제로 조금 움직이고(달성 0.05–0.2까지 반응) WM도 같은 펄스를 입력으로 받는다. 즉 영상에서 보이는 "깜빡임"은 렌더링 버그가 아니라 데이터(정책)의 실제 특성이며, 학습 데이터에도 그대로 들어 있다.
  3. 왜 블록 쌓기는 전부 cfgoff인가? cfgon/cfgoff는 데이터 수집 때 정책의 CFG 스케일(3.0 / 1.0)이다. 블록 풀에는 cfgon 실패도 31개(cfgoff 39개) 있었는데, 코호트 선별(fd_replay_modes.py::stratify)이 RNG 없이 (event_kind, contact 강도, event_offset, task, tag, env_id) 순으로 정렬해 태스크당 채우기 때문에 동점에서 알파벳상 앞선 cfgoff가 먼저 뽑혔다 — 의도된 선택이 아니라 결정적 tie-break의 부산물이다(v4·v6b·testB에는 cfgon도 섞여 있음). 학습 데이터(54.6 GB)는 두 설정을 모두 포함한다.

6.1 v4 코호트 (seen task / unseen episode) — 9개

drop · BananaThenRubiksCube env5 — GT: 큐브를 그릇에 떨어뜨림. N=4에서 base는 장면이 뭉개지는데 ft5000은 큐브가 그릇에 들어간 결과를 그림. LPIPS d_post every4 0.449 → 0.301 (gap 0.367), every2 0.273 → 0.232
drop · BBQSauceInBin env0 — every2 0.287 → 0.146, every4 0.378 → 0.237 (gap 0.261)
stack_disturb · RecycleCartonsVerticalCrate env0 — every2 0.419 → 0.313, every4 0.490 → 0.369 (gap 0.434)
stack_disturb · OneBottleOnShelf env1 — every2 0.222 → 0.191, every4 0.317 → 0.243 (gap 0.267)
success · RubiksCube env1 — every2 0.237 → 0.142, every4 0.432 → 0.193 (gap 0.114: 배치가 작은 변화라 copy도 강한 기준)
success · FoodPacking1Cans env1 — every2 0.411 → 0.285, every4 0.527 → 0.377 (gap 0.380)
grasp_miss · GrabABagel env3 — every2 0.360 → 0.236, every4 0.473 → 0.252 (gap 0.296)
grasp_miss · ToolsPickingAllHammers env4 — every2 0.224 → 0.180, every4 0.339 → 0.217 (gap 0.139)
악화 사례 stack_disturb · PutMugsOnShelf env0 — every4 0.320 → 0.357 (v4 중 every4 최대 악화), every2는 0.225 → 0.151 개선

6.1b v4 실패 에피소드 전부 — 실패 모드별 (grasp_miss 12 · drop 12 · stack_disturb 12; 3×2 레이아웃, ft5000)

6.1의 9개 외에 v4 코호트의 실패 에피소드 36개를 모두 싣는다(6.1과 겹치는 7개는 같은 파일). 캡션 숫자 = 판정 구간 LPIPS d_post base→ft5000, 괄호는 copy(관성) 베이스라인의 gap; C = copy를 이김(d_post<gap). every4(3.2–4.3 s 상상)가 물리 반영을 보기 가장 좋은 조건이다 — 사건 이후 64프레임 동안 실제 프레임 없이 그려야 하므로.

펼치기 — grasp_miss 12개 — beats_copy every2 17%→25% · every4 0%→25% · d_post 중앙값 every2 0.249→0.181 · every4 0.303→0.222

grasp_miss — 그리퍼가 닫히지만 물체를 놓침/미끄러짐(사건=집기 실패 시점). WM이 '들어올려진 물체'를 상상하면 틀림; 물체가 제자리에 남고 팔만 올라가야 정답

GrabABagel·env1 · grasp_miss — every2 0.214→0.176 · every4 0.268→0.209 (gap 0.092)
OneBottleOnShelf·env8 · grasp_miss — every2 0.376→0.317 · every4 0.468→0.417 (gap 0.304)
PutBowlOnShelfTop·env1 · grasp_miss — every2 0.204→0.155 · every4 0.288→0.197 (gap 0.137)
ReorientRedMug·env2 · grasp_miss — every2 0.200→0.181 C · every4 0.298→0.197 C (gap 0.238)
SmallPumpkinInBin·env3 · grasp_miss — every2 0.257→0.183 C · every4 0.282→0.208 C (gap 0.261)
ToolsPickingAllHammers·env4 · grasp_miss — every2 0.224→0.180 · every4 0.339→0.217 (gap 0.139)
ToolsPickingDrill·env2 · grasp_miss — every2 0.292→0.155 · every4 0.212→0.160 (gap 0.124)
GrabABagel·env3 · grasp_miss — every2 0.360→0.236 C · every4 0.473→0.252 C (gap 0.296)
ReorientRedMug·env5 · grasp_miss — every2 0.260→0.164 · every4 0.356→0.234 (gap 0.136)
SmallPumpkinInBin·env6 · grasp_miss — every2 0.241→0.203 · every4 0.309→0.248 (gap 0.172)
ToolsPickingDrill·env3 · grasp_miss — every2 0.386→0.285 · every4 0.360→0.292 (gap 0.257)
GrabABagel·env4 · grasp_miss — every2 0.223→0.163 · every4 0.297→0.227 (gap 0.112)
펼치기 — drop 12개 — beats_copy every2 75%→92% · every4 8%→58% · d_post 중앙값 every2 0.287→0.226 · every4 0.382→0.292

drop — 잡았던 물체를 이동 중/놓는 순간 떨어뜨림(사건=낙하 시작). WM은 물체가 그리퍼를 떠나 바닥/그릇으로 떨어지는 것을 그려야 함

RubiksCubeBehindBowl·env0 · drop — every2 0.287→0.209 · every4 0.318→0.248 (gap 0.188)
BBQSauceInBin·env0 · drop — every2 0.287→0.146 C · every4 0.378→0.237 C (gap 0.261)
BananaThenRubiksCube·env5 · drop — every2 0.273→0.232 C · every4 0.449→0.301 C (gap 0.367)
BlackItemsInBin·env2 · drop — every2 0.212→0.162 C · every4 0.283→0.232 (gap 0.217)
ClampInRightBin·env0 · drop — every2 0.293→0.239 C · every4 0.432→0.327 (gap 0.315)
CleanUpToys·env0 · drop — every2 0.228→0.165 C · every4 0.481→0.345 (gap 0.316)
DishesInBin·env0 · drop — every2 0.433→0.262 C · every4 0.488→0.398 C (gap 0.407)
FoodPacking1Cans·env3 · drop — every2 0.300→0.322 (악화) C · every4 0.379→0.327 C (gap 0.346)
FruitsGreenLimesOnPlate·env5 · drop — every2 0.318→0.293 C · every4 0.463→0.368 C (gap 0.377)
FruitsOnionToPlate·env1 · drop — every2 0.259→0.220 C · every4 0.385→0.284 (gap 0.275)
GreenSpoonsInPot·env1 · drop — every2 0.253→0.211 C · every4 0.349→0.243 C (gap 0.283)
MustardInRightBin·env6 · drop — every2 0.302→0.239 C · every4 0.344→0.258 C (gap 0.493)
펼치기 — stack_disturb 12개 — beats_copy every2 100%→92% · every4 25%→67% · d_post 중앙값 every2 0.225→0.200 · every4 0.319→0.335

stack_disturb — 쌓기/놓기 과정에서 아래 물체를 건드려 무너뜨리거나 밀어냄(사건=교란 시점). 기존 배치가 흐트러지는 결과를 그려야 함

BowlStackingRightOnLeft·env1 · stack_disturb — every2 0.214→0.187 C · every4 0.418→0.350 C (gap 0.400)
ButterAboveRaisin·env3 · stack_disturb — every2 0.220→0.209 C · every4 0.269→0.270 (악화) (gap 0.246)
OneBottleOnShelf·env0 · stack_disturb — every2 0.225→0.261 (악화) C · every4 0.286→0.323 (악화) C (gap 0.332)
PutBowlOnShelfTop·env0 · stack_disturb — every2 0.249→0.238 C · every4 0.315→0.319 (악화) C (gap 0.351)
PutMugsOnShelf·env0 · stack_disturb — every2 0.225→0.151 C · every4 0.320→0.357 (악화) (gap 0.272)
RecycleCartonsVerticalCrate·env0 · stack_disturb — every2 0.419→0.313 C · every4 0.490→0.369 C (gap 0.434)
StackWhiteMugs·env2 · stack_disturb — every2 0.258→0.320 (악화) C · every4 0.369→0.379 (악화) (gap 0.370)
BowlStackingRightOnLeft·env7 · stack_disturb — every2 0.285→0.153 C · every4 0.414→0.355 C (gap 0.359)
ButterAboveRaisin·env9 · stack_disturb — every2 0.248→0.183 C · every4 0.282→0.238 C (gap 0.270)
OneBottleOnShelf·env1 · stack_disturb — every2 0.222→0.191 C · every4 0.317→0.243 C (gap 0.267)
PutBowlOnShelfTop·env2 · stack_disturb — every2 0.214→0.139 C · every4 0.414→0.348 C (gap 0.352)
PutMugsOnShelf·env1 · stack_disturb — every2 0.208→0.281 (악화) · every4 0.285→0.311 (악화) (gap 0.254)

6.2 testB unseen 태스크 코호트 — 24개 전부 (2×2: GT · base N=2 / copy · ft5000 N=2)

펼치기 — drop 8 · stack_disturb 8 · success 8 (캡션: every2 d_post base→ft5000)
RubiksCubeBehindBowl·_env0 · drop — every2 0.296→0.206 (gap 0.188)
BlocksInBin·_env8 · drop — 0.464→0.334 (gap 0.458)
CondimentsInBin·_env0 · drop — 0.295→0.168 (gap 0.269)
DishesInBin·_env0 · drop — 0.433→0.271 (gap 0.407)
ElectronicsInBin·_env0 · drop — 0.355→0.253 (gap 0.307)
PutTwoMugsOnShelf·_env1 · drop — 0.227→0.164 (gap 0.144)
ThrowAwaySnacks·_env0 · drop — 0.404→0.348 (gap 0.484)
WhiteMugInCenterOfTable·_env1 · drop — 0.276→0.189 (gap 0.153)
BlockStackingOrderAgnostic·_env0 · stack_disturb — 0.168→0.209 (악화; gap 0.214)
BowlStackingLeftOnRight·_env1 · stack_disturb — 0.298→0.217 (gap 0.447)
ButterAboveRaisin·_env3 · stack_disturb — 0.221→0.210 (gap 0.246)
Stack3RubiksCube·_env1 · stack_disturb — 0.190→0.183 (gap 0.192)
StackYellowOnRed·_env2 · stack_disturb — 0.357→0.284 (gap 0.354)
BlockStackingOrderAgnostic·_env3 · stack_disturb — 0.261→0.233 (gap 0.369)
BowlStackingLeftOnRight·_env3 · stack_disturb — 0.210→0.233 (악화; gap 0.369)
ButterAboveRaisin·_env9 · stack_disturb — 0.248→0.183 (gap 0.270)
BlockStackingOrderAgnostic·_env1 · success — 0.145→0.125 (gap 0.075)
RubiksCubeBehindBowl·_env9 · success — 0.140→0.117 (gap 0.045)
Stack3RubiksCube·_env2 · success — 0.152→0.137 (gap 0.051)
FruitsMovingOrangeOrLime·_env6 · success — 0.468→0.234 (gap 0.326)
WhiteMugInCenterOfTable·_env0 · success — 0.295→0.221 (gap 0.259)
ElectronicsInBin·_env2 · success — 0.297→0.233 (gap 0.402)
BlocksInBin·_env0 · success — 0.353→0.269 (gap 0.209)
BowlStackingLeftOnRight·_env5 · success — 0.274→0.194 (gap 0.049)

6.2b 블록 쌓기/집기 코호트 (v5_block 24 · v6b_noleak 16) — base vs ft8000(최종 ckpt), 3×2 레이아웃

블록/큐브/그릇 쌓기 태스크(BlockStackingOrderAgnostic·BlockStackingSpecifiedOrder·Stack3RubiksCube·StackYellowOnRed·BowlStackingLeftOnRight)만 모은 두 코호트. v5_block: 그리퍼 명령(놓음) 앵커 — "놓았는데 안 버팀/무너짐" 16개 + 성공 대조군 8개, 8청크(사건 offset 112). v6b_noleak: 접촉 앵커 — 팔/들고 있던 블록이 타워를 치는 사건 16개, 13청크(사건 offset 144), 마지막 재접지 프레임이 접촉 1.07 s 전이라 모델이 충돌 프레임을 보지 못한 상태에서 붕괴를 그려야 한다(가장 엄격한 물리 테스트; gap 중앙값 0.32로 장면 변화가 큼). 이 두 코호트는 학습 완료 직후 평가했으므로 ft8000(최종) vs base. 캡션 표기는 6.1b와 같다.

해석. v6b(접촉→붕괴)는 16/16 모두 개선: every2 d_post 중앙값 0.177→0.128, every4 0.248→0.169, 전부 copy를 이김 — "팔이 타워를 치면 무너진다"를 base보다 일관되게 그린다. v5_block 실패(놓음 앵커)는 혼재: every4는 개선(copy 6→31%, d_post 0.279→0.248)이지만 every2는 중앙값 0.188→0.205로 소폭 악화(16개 중 7개 악화). 악화 건은 gap이 0.14–0.17로 작은 에피소드 — 사건이 장면을 거의 바꾸지 않아 "정지"가 거의 정답인데 FT가 더 역동적으로 그려 벌점을 받는 경우. v5 성공 대조군 8개는 every4 d_post 0.331→0.186(advanced 12→75%)으로 크게 개선 — 블록 장면 자체의 전반적 품질이 올라간 몫도 있음(H2: 성공 능력 저하 없음).
펼치기 — v5_block: stack_disturb 16개 — beats_copy every2 81%→62% · every4 6%→31% · advanced every4 69%→38% · d_post 중앙값 every2 0.188→0.205 · every4 0.279→0.248

그리퍼 명령 앵커: 블록/그릇을 놓는 시점(=사건) 이후 무너지거나 미끄러지는 경우. 성공 대조군은 놓은 뒤 그대로 서 있는 경우.

BlockStackingOrderAgnostic·env0 (cfgoff) · stack_disturb — every2 0.168→0.207 (악화) C · every4 0.233→0.221 (gap 0.214)
BlockStackingSpecifiedOrder·env0 (cfgoff) · stack_disturb — every2 0.128→0.180 (악화) · every4 0.193→0.168 (gap 0.144)
BowlStackingLeftOnRight·env1 (cfgoff) · stack_disturb — every2 0.299→0.265 C · every4 0.390→0.349 C (gap 0.447)
Stack3RubiksCube·env1 (cfgoff) · stack_disturb — every2 0.190→0.177 C · every4 0.313→0.269 (gap 0.192)
StackYellowOnRed·env2 (cfgoff) · stack_disturb — every2 0.358→0.276 C · every4 0.432→0.310 C (gap 0.354)
BlockStackingOrderAgnostic·env3 (cfgoff) · stack_disturb — every2 0.261→0.226 C · every4 0.402→0.337 C (gap 0.369)
BlockStackingOrderAgnostic·env4 (cfgoff) · stack_disturb — every2 0.179→0.173 · every4 0.223→0.196 (gap 0.155)
BlockStackingOrderAgnostic·env5 (cfgoff) · stack_disturb — every2 0.159→0.186 (악화) · every4 0.191→0.201 (악화) (gap 0.144)
BlockStackingOrderAgnostic·env6 (cfgoff) · stack_disturb — every2 0.156→0.195 (악화) · every4 0.220→0.226 (악화) (gap 0.166)
BlockStackingSpecifiedOrder·env1 (cfgoff) · stack_disturb — every2 0.159→0.210 (악화) · every4 0.244→0.222 (gap 0.209)
BlockStackingSpecifiedOrder·env2 (cfgoff) · stack_disturb — every2 0.187→0.170 C · every4 0.220→0.191 C (gap 0.200)
BlockStackingSpecifiedOrder·env3 (cfgoff) · stack_disturb — every2 0.276→0.226 C · every4 0.424→0.311 C (gap 0.334)
BlockStackingSpecifiedOrder·env4 (cfgoff) · stack_disturb — every2 0.148→0.203 (악화) · every4 0.217→0.219 (악화) (gap 0.161)
BowlStackingLeftOnRight·env3 (cfgoff) · stack_disturb — every2 0.211→0.246 (악화) C · every4 0.431→0.395 (gap 0.369)
BowlStackingLeftOnRight·env6 (cfgoff) · stack_disturb — every2 0.278→0.212 C · every4 0.411→0.369 (gap 0.321)
BowlStackingLeftOnRight·env7 (cfgoff) · stack_disturb — every2 0.234→0.141 C · every4 0.367→0.309 (gap 0.289)
펼치기 — v5_block: success 8개 — beats_copy every2 0%→0% · every4 0%→0% · advanced every4 12%→75% · d_post 중앙값 every2 0.144→0.120 · every4 0.331→0.186

그리퍼 명령 앵커: 블록/그릇을 놓는 시점(=사건) 이후 무너지거나 미끄러지는 경우. 성공 대조군은 놓은 뒤 그대로 서 있는 경우.

BlockStackingOrderAgnostic·env1 (cfgon) · success — every2 0.145→0.121 · every4 0.277→0.175 (gap 0.075)
Stack3RubiksCube·env2 (cfgon) · success — every2 0.152→0.130 · every4 0.385→0.197 (gap 0.051)
BowlStackingLeftOnRight·env5 (cfgoff) · success — every2 0.280→0.171 · every4 0.405→0.208 (gap 0.049)
StackYellowOnRed·env1 (cfgoff) · success — every2 0.142→0.114 · every4 0.441→0.277 (gap 0.073)
BlockStackingOrderAgnostic·env3 (cfgon) · success — every2 0.131→0.117 · every4 0.173→0.150 (gap 0.033)
BlockStackingOrderAgnostic·env2 (cfgoff) · success — every2 0.140→0.114 · every4 0.158→0.134 (gap 0.020)
BowlStackingLeftOnRight·env9 (cfgoff) · success — every2 0.123→0.118 · every4 0.188→0.163 (gap 0.025)
BowlStackingLeftOnRight·env0 (cfgon) · success — every2 0.347→0.234 · every4 0.411→0.262 (gap 0.118)
펼치기 — v6b_noleak: stack_disturb 16개 — beats_copy every2 100%→100% · every4 94%→100% · advanced every4 100%→100% · d_post 중앙값 every2 0.177→0.128 · every4 0.248→0.169

접촉 앵커: 이동 중인 팔(또는 들고 있는 블록)이 기존 타워를 치는 순간이 사건. 13청크 윈도우(9 pre + 4 post), 모델은 충돌 프레임을 보지 못함.

BlockStackingSpecifiedOrder·env8 (cfgon) · stack_disturb — every2 0.194→0.126 C · every4 0.305→0.167 C (gap 0.336)
BlockStackingOrderAgnostic·env0 (cfgon) · stack_disturb — every2 0.196→0.120 C · every4 0.272→0.168 C (gap 0.356)
Stack3RubiksCube·env7 (cfgon) · stack_disturb — every2 0.239→0.170 C · every4 0.302→0.226 C (gap 0.346)
BowlStackingLeftOnRight·env0 (cfgoff) · stack_disturb — every2 0.172→0.140 C · every4 0.249→0.177 C (gap 0.297)
StackYellowOnRed·env2 (cfgoff) · stack_disturb — every2 0.170→0.146 C · every4 0.268→0.211 C (gap 0.382)
BlockStackingSpecifiedOrder·env4 (cfgoff) · stack_disturb — every2 0.163→0.121 C · every4 0.225→0.167 C (gap 0.283)
BlockStackingSpecifiedOrder·env4 (cfgon) · stack_disturb — every2 0.190→0.141 C · every4 0.233→0.187 C (gap 0.259)
BlockStackingSpecifiedOrder·env5 (cfgoff) · stack_disturb — every2 0.217→0.127 C · every4 0.311→0.140 C (gap 0.284)
BlockStackingSpecifiedOrder·env6 (cfgoff) · stack_disturb — every2 0.176→0.117 C · every4 0.248→0.152 C (gap 0.318)
BlockStackingOrderAgnostic·env2 (cfgon) · stack_disturb — every2 0.206→0.134 C · every4 0.275→0.208 C (gap 0.352)
BlockStackingOrderAgnostic·env6 (cfgoff) · stack_disturb — every2 0.160→0.118 C · every4 0.229→0.145 C (gap 0.304)
BlockStackingOrderAgnostic·env4 (cfgon) · stack_disturb — every2 0.161→0.119 C · every4 0.195→0.132 C (gap 0.343)
StackYellowOnRed·env4 (cfgoff) · stack_disturb — every2 0.146→0.128 C · every4 0.184→0.157 C (gap 0.246)
BlockStackingOrderAgnostic·env0 (cfgoff) · stack_disturb — every2 0.164→0.122 C · every4 0.222→0.171 C (gap 0.330)
StackYellowOnRed·env6 (cfgoff) · stack_disturb — every2 0.178→0.153 C · every4 0.252→0.205 C (gap 0.325)
Stack3RubiksCube·env9 (cfgon) · stack_disturb — every2 0.190→0.135 C · every4 0.228→0.206 C (gap 0.302)

6.3 PSNR 보조 지표 (dB, 판정 구간 예측 vs GT; 괄호 = copy 베이스라인의 PSNR)

코호트 · 조건baseft8000copy(관성)
v4 ALL every215.2815.9217.68
v4 ALL every414.0215.2017.68
v4 ALL open_loop12.3114.3317.68
v4 drop every413.4514.9015.74
v4 stack_disturb every414.4114.9915.58
v4 grasp_miss every414.4815.6919.58
v4 success every413.7415.2119.81
testB ALL every214.7515.6817.29
testB ALL every413.5614.9717.29
testB ALL open_loop12.2314.3417.29
PSNR 읽는 법: base→ft8000에서 PSNR도 모든 코호트·조건에서 오르지만(+0.64 dB every2, +1.18 dB every4, +2.02 dB open_loop), 마지막 재접지 프레임을 그대로 두는 copy가 모든 생성 영상보다 PSNR이 높다(사건이 장면의 작은 영역만 바꾸고, 생성 영상은 전역 텍스처/소폭 정렬 차이로 벌점을 받기 때문). 같은 에피소드에서 LPIPS는 ft8000이 copy를 이기는 비율(beats_copy)이 every2 62%, every4 46%, open_loop 27%다 — 두 지표가 다른 것을 재므로 사건 재현은 LPIPS+사건 판정으로 본다.

7 Takeaway

의미

  • 실패 rollout을 섞어 FD finetune하면 WM이 "실패를 상상할 줄" 알게 된다. 사전 등록 기준(every4 사건 재현 대리지표 +30%p)을 넘겨 +38%p(8→46%), 상상 구간이 가장 긴 open_loop에서는 0→27%로 질적 차이가 생겼다 — base는 8.5 s를 통째로 상상할 때 관성 베이스라인을 한 번도 못 이겼다.
  • 공식 트레이너·데이터셋 클래스를 그대로 쓰고 인터페이스를 parity 테스트로 고정했으므로, base→FT의 개선은 데이터(성공+실패 rollout)에 귀속된다. iter 8000까지 단조 개선이고 정체·과적합 징후가 없어 더 긴 학습에 여지가 있다.
  • 성공 재현이 희생되지 않았다(H2): success 모드도 every4 adv 33→83%, d_post 0.310→0.228. "실패만 잘 그리는 모델"이 아니라 장면 동역학 전반이 좋아졌다.
  • H4 답: "실패 데이터 덕분"이라고 말할 수 없다(§9). 성공만 쓴 FT-succ가 base→FT 개선의 대부분을 재현하며, 두 모델의 격차는 every4에서 +4%p뿐이다. 실패 데이터의 순수 기여는 재접지가 없는 긴 상상 구간(open_loop +15~19%p)과 전도/붕괴(+16%p)에 국한된다. 이 발견 자체가 이번 실험의 가장 중요한 결과다 — 개선의 원인을 데이터 축으로 정확히 귀속시켰고, 다음 실험(혼합비·긴 horizon 중심 평가·sim 재실행 counterfactual)의 방향을 정했다.
  • 운영 지식: cosmos-framework SFT를 에피소드 단위 mp4 데이터셋으로 돌릴 때의 함정 4가지(aug hue, OMP, decoder cache, epoch rollover)와 그리퍼 채널 해석(명령 이진화 vs 달성 연속값)은 전부 재현·수정·기록됨.

8 Next Steps

완료

  • FT-mix(iter 8000)·FT-succ(iter 8000) 학습 + 전 코호트 × every2/every4/open_loop + E2 3종 평가·채점 — §4·§5·§9
  • RoboLab 재수집 sweep 완료: 1,200 에피소드(물체 pose 로깅 포함) → Phase 2 데이터 확보
  • 중간 DCP ckpt 정리(FT-mix 0.96 TB 회수), export는 전 tag 보존

H4 결과가 지시하는 다음 실험

  • 긴 horizon 중심 평가로 재설계: 실패 데이터의 기여가 드러나는 유일한 조건이 open_loop였다 → 재접지 없는 8.5 s 구간을 주 평가축으로 승격하고 사건 단위 판정을 붙인다
  • 혼합비 ablation: 현재 2:1:1(성공:실패-사건:실패-균일) → 실패 비중 상향 / 실패 사건 직전 구간 집중 샘플링
  • Phase 2b — sim 재실행 counterfactual: 편집한 액션을 RoboLab에서 실제로 실행해 GT를 만들고 비교(그리퍼 단일채널 편집의 한계 우회). 재수집분의 objpose로 물체 단위 판정도 가능
  • 사건 단위(육안/VLM) 판정으로 H1 확정 — LPIPS는 대리지표
  • v5 block every2 하락(base 54% → succ 46% → mix 42%) 원인 규명: gap이 작은 "거의 정지" 사건에서 FT가 과하게 움직이는지

로그: claude/260820/progress-wm_ft_phase0.md · claude/260821/analysis-wm_gripper_channel.md · claude/260825/exp-wm_ft_h4.md · 체크리스트 claude/plan.md · 요약 JSON tmp/wm_ft/eval_summary_h4.json

9 H4 — 실패 데이터가 기여했는가 (FT-mix vs FT-succ 대조)

4분할 비교 영상(GT · base · FT-succ · FT-mix, open_loop/every4 8개)은 별도 리포트에 있다 → H4 — 실패 데이터가 WM을 좋게 만들었나 (08-25)

설계. 두 run은 데이터만 다르다: FT-succ는 성공 rollout만(261 ep, repeat 16), FT-mix는 성공:실패-사건:실패-균일 = 2:1:1. 나머지(모델·인터페이스·lr·스케줄·8,000 iter·평가 파이프라인)는 동일하다. 따라서 두 열의 차이는 실패 데이터의 기여로 읽을 수 있다. 사전 등록 기준은 FT-mix − FT-succ ≥ +15%p(every4 beats_copy).

9.1 beats_copy (주지표) — base / FT-succ / FT-mix

코호트조건baseFT-succ (성공만)FT-mix (성공+실패)mix − succ
v4 seen (48)every250%60%62%+2%
every48%42%46%+4%
open_loop0%12%27%+15%
testB unseen (24)every238%67%71%+4%
every44%42%46%+4%
open_loop0%25%29%+4%
v5 block · 놓음 (24)every254%46%42%-4%
every44%17%21%+4%
open_loop0%12%17%+4%
v6b block · 접촉 (16)every2100%100%100%+0%
every494%100%100%+0%
open_loop0%38%56%+19%

9.2 d_post 중앙값 (낮을수록 GT에 가까움)

코호트조건baseFT-succ (성공만)FT-mix (성공+실패)
v4 seen (48)every20.2480.1890.174
every40.3420.2660.256
open_loop0.4880.3630.340
testB unseen (24)every20.2860.2120.205
every40.4000.3170.268
open_loop0.4880.3410.340
v5 block · 놓음 (24)every20.1730.1740.183
every40.2950.2400.221
open_loop0.4590.3070.294
v6b block · 접촉 (16)every20.1770.1340.128
every40.2480.1780.169
open_loop0.5030.3220.319

9.3 실패 모드별 every4 beats_copy (v4 n=12/모드, testB n=8/모드)

코호트 · 모드baseFT-succ (성공만)FT-mix (성공+실패)mix − succ
v4 · drop (n=12)8%67%58%-8%
v4 · grasp_miss (n=12)0%17%25%+8%
v4 · stack_disturb (n=12)25%67%83%+17%
v4 · success (n=12)0%17%17%+0%
testB · drop (n=8)0%50%50%+0%
testB · stack_disturb (n=8)12%62%62%+0%
testB · success (n=8)0%12%25%+12%

9.4 E2 액션 편집 — div / direction_ok / beats_copy

kindbaseFT-succ (성공만)FT-mix (성공+실패)
suppress_release (40)0.054 / 88% / 62%0.035 / 88% / 75%0.026 / 80% / 80%
early_release (15)0.171 / 80% / 40%0.106 / 73% / 93%0.024 / 47% / 93%
shuffle_actions (48)0.269 / 96% / 54%0.247 / 100% / 71%0.246 / 100% / 73%
판정: H4는 사전 등록 기준에 미달한다(기각). 기준은 every4 beats_copy에서 FT-mix − FT-succ ≥ +15%p였는데 실제는 v4 +4%p(42→46%) · testB +4%p(42→46%) · v5 +4%p · v6b ±0%p(둘 다 100% 천장)이다. 즉 base 대비 개선의 대부분은 실패 데이터가 아니라 RoboLab 도메인 적응(sim 렌더링·로봇 외형·장면 동역학에 모델을 맞춘 것)에서 온다 — 성공 rollout 261 ep만으로도 v4 every4 beats_copy가 8%→42%까지 올라간다.
다만 실패 데이터가 분명히 기여하는 지점이 둘 있다.
  1. 가장 긴 상상 구간(open_loop, 8.5 s 무재접지): v4 0→12→27%(+15%p), v6b 0→38→56%(+19%p) — 유일하게 사전 기준을 넘는 조건이다. 재접지가 자주 있으면 실제 프레임이 물리를 알려주지만, 없을 때는 "무엇이 실패로 이어지는가"를 모델이 스스로 알아야 한다.
  2. 전도/붕괴(stack_disturb): v4 every4 25→67→83%(+16%p). 반면 낙하(drop)는 FT-succ가 오히려 낫다(67% vs 58%) — 성공 데이터에도 물체를 놓는 장면이 많아 낙하 동역학은 충분히 학습되는 것으로 보인다.
대가: 액션 편집 민감도는 FT-succ가 더 잘 보존한다. 그리퍼 채널만 뒤집는 편집에서 FT-succ는 base에 가까운 반응을 유지하지만(early_release div 0.106 · direction_ok 73%), FT-mix는 거의 반응하지 않는다(div 0.024 · 47%). 액션 전체를 바꾸는 셔플 테스트에서는 둘 다 동일하게 강건하므로(div 0.247 vs 0.246, direction_ok 100%) "액션을 무시한다"는 뜻은 아니지만, 실패 윈도우를 많이 본 모델일수록 짧은 그리퍼 펄스는 대개 결과를 바꾸지 않는다는 데이터의 통계를 더 강하게 학습한 것으로 읽힌다(§6 FAQ의 펄스 305회 통계와 일치).
이 결과가 실험 설계에 주는 함의. 지금 프로토콜에서 "실패를 상상하는 능력"을 재는 대리지표(event-aligned LPIPS)는 도메인 적응과 실패 지식을 잘 분리하지 못한다 — 재접지가 잦은 조건에서는 실제 프레임이 물리를 대신 알려주기 때문이다. 실패 데이터의 기여를 제대로 보려면 (a) open_loop처럼 긴 상상 구간, (b) 사건 단위 판정(그 물체가 실제로 떨어졌는가/무너졌는가), (c) Phase 2b의 sim 재실행 counterfactual(편집한 액션의 진짜 결과와 비교)이 필요하다. 데이터 축도 다시 볼 만하다: 현재 혼합비 2:1:1은 실패 윈도우가 전체의 절반인데, 실패 비중을 더 올리거나 실패 사건 직전 구간만 샘플링하는 편이 open_loop 이득을 키울 수 있다.