Index
2026-08-07 — Progress

45K 최종 평가 파이프라인 정비 — 조용한 폴백 차단과 종료 지점 재검토

Cosmos Policy | Arm A/B mid-frame 가설 검증 · 30K 프로브 대기 중

TL;DR

11/11
검증 통과
48
무효될 뻔한 job
~6.7h
30K까지 (A)
24.4K
현재 iter (A)

1 배경 / 목적

30K 프로브까지 약 7시간, 45K 최종 평가까지 약 25~29시간이 남았다. 그 유휴 시간에 최종 평가 경로를 미리 밟아보기로 했다. 15K 프로브 때 DCP 로딩 버그를 45K가 아니라 2500에서 잡아 57 GPU-시간을 아낀 경험이 있어서다.

계획서에 남아 있던 메모: “submit_arm0.sh는 Arm 0 전용 하드코딩이므로 CKPT/CONFIG 전달하도록 수정 필요” — 이 한 줄이 실제로 무엇을 요구하는지 확인하는 것이 출발점이었다.

2 작업 내용

2.1 발견 — 에러가 아니라 조용한 폴백

scripts/eval_robocasa_seeds.sh가 srun 자식에게 넘기는 것은 네 개뿐이었다:

export TASK TRIALS ARM SEEDS # CKPT, CONFIG 없음

그리고 eval_robocasa.sh는 다음 기본값을 갖는다:

CKPT="${CKPT:-nvidia/Cosmos-Policy-RoboCasa-Predict2-2B}"

따라서 ARM=armAit45000 bash scripts/submit_arm0.sh는 에러 없이 실행되고, 24개 job 전부가 공개 체크포인트를 평가한 뒤 결과에 우리 arm 라벨을 붙인다. Arm 0 재현값이 66.9%였으므로 나오는 숫자는 ~67% — “우리 모델이 논문 수준을 재현했다”로 읽히는, 완전히 틀린 결과.

왜 위험한가: 파일명·로그·집계 어디에도 이상 신호가 없다. 크래시가 아니라 그럴듯한 성공으로 위장한다.

2.2 공용 리졸버로 차단

같은 arm→체크포인트 매핑이 eval_ckpt_job.sh와 submit_ckpt_evals.sh에 각각 하드코딩돼 있어 세 번째 사본이 생길 참이었다. 한 곳으로 모았다.

scripts/arm_ckpt.sh — resolve_arm_ckpt <spec> arm0 → CKPT/CONFIG 미설정 (public 체크포인트 = 의도된 기본 동작) arm<A|B>it<N> → EXP, CONFIG, CKPT_DIR, CKPT_PT 설정 그 외 → 에러로 거부

arm<A|B>it<N>은 프로브가 이미 run_id_note에 쓰던 문자열이라, 프로브 · 최종 평가 · collector가 하나의 규칙을 공유하게 됐다 (--arm armAit45000 하나로 집계).

eval_robocasa_seeds.sh는 .pt가 없으면 변환 명령을 알려주며 즉시 실패한다. 여기서 변환하지 않는 이유: 24개 job이 같은 3.7GB 파일에 동시에 쓰게 된다.

2.3 순서를 강제하는 드라이버

scripts/submit_final_eval.sh 1. 변환 먼저, 로그인에서 1회 — arm 하나라도 해당 iter 미도달이면 *아무것도 제출하지 않고* 중단 2. 그다음 arm당 24 job fan-out (3 seed x 50 trial = Arm 0과 동일 프로토콜) DRY_RUN=1 변환/존재확인만 ARMS=A 한쪽만 (B를 30K에서 죽인 경우)

2.4 라이브 경로를 깨지 않았는지

eval_ckpt_job.sh와 submit_ckpt_evals.sh도 리졸버를 쓰도록 바꿨는데, 이 둘은 7시간 뒤 30K 프로브를 자동 제출해야 하는 라이브 경로다. 경로 문자열이 한 글자라도 틀리면 [ -d ... ] 검사가 조용히 실패하고 30K 프로브는 영원히 제출되지 않는다.

sbm과 마커 디렉토리를 스텁으로 바꾼 사본으로, 이미 존재하는 iter_000022500에 대해 탐지→제출 경로가 실제로 발화하는지 확인했다.

3 결과

검증 항목기대결과
bash 문법 (5개 스크립트)통과✅
리졸버 arm0CKPT/CONFIG 미설정✅
리졸버 armAit15000 / armBit45000올바른 config + 경로✅
리졸버 armCit1, armA_45000거부✅
seeds, .pt 없음exit 1 + 변환 명령 출력✅
seeds, .pt 있음 (A/B)CKPT/CONFIG가 srun까지 전달✅
seeds, arm0CKPT 미설정 유지✅
submit_final_eval.sh ITER=45000미도달 중단, 제출 0건✅
submit_final_eval.sh ITER=15000 DRY_RUN변환 스킵, 제출 0건✅
프로브 탐지 (iter 22500, 스텁)A/B 둘 다 제출 발화✅
프로브 멱등성 (마커 재검사)nothing new to submit✅

라이브 큐 부작용 0건 — 테스트 중 잘못 생성된 srun 할당이 없는지 squeue로 확인했다.

학습 상태 (08-07 10:15)

ArmJobiter속도QOS30K45K90Kwall limit
A (stock)72438 (n21)~24,3804.27 s/itcore-own16:5008-08 10:4008-10 16:0008-13 05:11
B (mid-frame)72439 (n2)~24,7905.04 s/itcore-own17:3008-08 14:3008-11 05:3008-12 23:21
여유 확인: core-own이라 preempt 불가. 90K도 wall limit 안에 들어간다 (A 61h / B 42h 여유). 체크포인트 150G, NAS 여유 65T — 제약 아님.

4 Takeaway

이 실험에서 가장 위험한 실패 모드는 크래시가 아니라 “그럴듯한 숫자”다

지금까지 겪은 함정 6개 중 4개(wandb TLS, output root, HF 경로 오인, DCP 포맷)는 시끄럽게 죽어서 금방 잡혔다. 나머지 2개 — sacct가 실패를 COMPLETED로 보고하는 것, 그리고 이번의 public 체크포인트 폴백 — 는 성공한 것처럼 보인다. 평가 경로에서 default 값은 안전장치가 아니라 함정이다.

유휴 7시간의 값: 45K 시점에 발견했다면 48개 job × 30분을 버리고 재제출했을 것이고, 최악의 경우 잘못된 67%를 결과로 믿었을 것이다. 이제 45K 시점에 판단할 것이 “어떻게 돌리지”가 아니라 “결과가 무엇을 말하나”로 좁혀졌다.

5 Next Steps

✅ 종료 지점 = 90K — 08-07 10:25 확정 (30K 프로브 도착 전)

45K는 논문의 step 수를 맞춘 것이지 sample 수가 아니다. 우리 global batch는 200, 논문은 800.

종료점본 샘플논문 대비AB7일 안?
45K9.0M25%08-08 10:4008-08 14:30✅
90K18.0M50%08-10 16:0008-11 05:30✅ (여유 61h/42h)
180K36M100%8.9일10.5일❌ (resume 1회)

가설 (a)가 맞다면 — B의 목적함수가 더 어려워 늦게 배운다면 — 45K에서 끊는 것은 구조적으로 B에게 불리하다. 그래서 45K를 1차 헤드라인으로 고정하고 90K까지 계속 돌려 2차(라벨 명시)로 병기하기로 했다.

이 결정이 사전 등록으로 유효한 이유 3가지: (1) 30K 데이터 도착 전에 정했고, (2) 근거(샘플 예산이 논문의 25%)가 실험 시작 전부터 참이며 결과와 무관하고, (3) 두 arm에 대칭으로 적용된다.
함께 바꾸지 않은 것 — 30K kill 기준: 종료점을 늘렸다고 B의 kill 기준까지 완화하면, 그건 B가 뒤진 것을 본 뒤에 B를 살리는 방향으로 규칙을 고친 것이 되어 정확히 사전 등록이 막으려던 일이다. 종료점 변경은 대칭이라 방어 가능하지만 kill 기준 완화는 아니다. → 30K에서 격차가 유지·확대되면 예정대로 scancel 72439, 그 경우 A만 90K까지 간다.
bash scripts/submit_final_eval.sh # 08-08, ITER=45000 (1차) ITER=90000 bash scripts/submit_final_eval.sh # 08-11, 2차 프로브도 60K/75K/90K 자동 추가 (submit_ckpt_evals.sh 기본 ITERS) — 측정 추가일 뿐, 판정 규칙은 건드리지 않았다

B를 30K에서 죽이는 경우의 보고 원칙

kill 결정은 프로브(6 task × 1 seed × 20 trial, 노이즈 ±3.6pt)로 내린다. 정당한 중간분석이며 1차 지표를 오염시키지 않는다. 다만 그 경우 B의 24-task 수치는 존재하지 않는다. 30K 프로브를 최종 결과처럼 쓰지 말고 “자원 제약으로 중간분석에서 중단, 24-task 측정 없음”이라고 그대로 적는다.

남은 미해결

per-component 지표(action_l1_loss) 없음 — wandb를 껐기 때문. 이번 실험에서는 포기.
GPU 메모리 40% 유휴 (105/178 GiB) → batch 50 가능했음. 다음 실험에 반영.