Index
2026-08-10 — Analysis

preempt가 저장 중에 떨어져 체크포인트를 파괴했다 — save_top_k=0의 실패 모드

X-WAM | depth-vs-pointmap A/B · ab_depth 4,479 step 손실

TL;DR

6/9
손상 파일
4,479
손실 step
13h
큐 대기
+1.7h
보험 비용

1배경 — 왜 이걸 들여다보게 됐나

ab_depth / ab_pm는 depth-vs-pointmap A/B의 두 arm이고 --qos=extra로 돈다. 이 클러스터에서 preempt는 예외가 아니라 기본값이라, sbmr 자동 재제출과 save_interval=500을 이미 걸어뒀다. 대비는 해뒀다고 생각했다.

08-09 오후 두 arm이 연달아 preempt됐고, 13시간이 지나도 큐에서 움직이지 않았다. 진행 상황을 확인하다가 ab_depth의 체크포인트가 읽을 수 없는 상태인 걸 발견했다.

gate_base.sh 헤더의 논리에 구멍이 있었다. save_top_k=0을 비용으로 정당화하고 있었다 — 저장 1회가 96 GB / ~2.7분인데 save_top_k=1이면 192 GB / ~5분 20초. 맞는 계산이지만 사본이 하나뿐이라는 사실이 빠져 있었다.

2진단 — mtime 불균일에서 시작

첫 단서는 파일 mtime이었다. ab_depth는 rank_0만 12:55이고 나머지는 13:26. 크기도 rank_5/6이 다른 shard와 달랐다.

torch는 zip 아카이브로 저장하므로 zipfile.ZipFile()이 end-of-central-directory 레코드만 읽어 잘림을 즉시 잡는다 — 96 GB를 로드할 필요가 없고 밀리초면 끝난다.

파일ab_depth (76102)판정ab_pm (75912)판정
rank_0 optim10.01 GBOK10.01 GBOK
rank_1 optim10.01 GBOK10.01 GBOK
rank_2 optim10.01 GBOK10.01 GBOK
rank_3 optim10.01 GBBadZipFile10.01 GBOK
rank_4 optim10.01 GBBadZipFile10.01 GBOK
rank_5 optim6.67 GB잘림10.01 GBOK
rank_6 optim6.67 GB잘림10.01 GBOK
rank_7 optim10.01 GBBadZipFile10.01 GBOK
model_states11.78 GB잘림38.89 GBOK
크기 차이 자체가 증거다. 두 arm은 아키텍처가 동일하다(둘 다 use_depth=true, 같은 base, 같은 레시피). model_states가 38.89 GB여야 하는데 11.78 GB라는 건 해석의 여지가 없다. ZeRO는 모든 shard가 있어야 로드되므로 멀쩡한 3개는 쓸모가 없다.

3근본 원인 — 두 윈도우가 겹친다

preempt 결정 | |<------------- grace ~5.5분 ------------->| | SIGTERM SIGKILL | | | [ 저장 ~2.7분 : last.ckpt 제자리 덮어쓰기 ] | ^ | 여기서 죽으면 유일본 파괴

저장이 grace의 절반을 차지한다. 그 사이에 preempt가 들어오면 last.ckpt는 새 데이터로 덮어써지다가 중단되고, 이전 상태는 이미 사라진 뒤다. ab_depth는 5회 preempt 중 정확히 이 창에 걸렸다.

왜 ab_pm은 살았나

운이다. 같은 종류의 preempt였지만 저장 중이 아니었을 뿐이다. 두 arm의 차이는 설정이 아니라 타이밍이고, 그게 바로 이 설정이 위험한 이유다 — 실패가 확률적이라 몇 번 무사히 넘어가면 안전해 보인다.

4왜 막혀 있었나 — 내 job이 내 job을 막는다

13시간 대기의 원인은 다른 사용자가 아니었다. AssocGrpGRES, core 계정 70/72이고 그 중 17장이 전부 내 것이었다.

jobGPUQOS경과 / 남은 시간
cosmos_armA4own18h 36m / 6d 05h
cosmos_armB4own18h 34m / 6d 05h
rc24_D (flux2 4b)8extra1h 18m / 22h
ev_armA_150001extra27m / 3h 33m
own QOS로 6일 예약을 걸면 preempt는 면하지만 같은 계정의 다른 실험이 들어올 자리도 같이 막는다. cosmos 두 개가 8장을 6일간 점유하는 동안 A/B 두 arm(각 8장)은 대기다.

결정: 아무것도 내리지 않고 대기. rc24_D가 ~22시간 뒤 끝나면 슬롯이 난다.

5조치

손상본 격리 (삭제 아님)

CORRUPT_last.ckpt.76102로 이동. 그대로 두면 재개 시 crash → sbmr 재제출 루프로 13시간 기다려 얻은 슬롯을 날린다.

save_top_k 0 → 1

step 체크포인트가 last.ckpt와 별도로 남으므로, 찢어진 last가 있어도 최대 500 step 뒤처진 로드 가능한 사본이 남는다.

PENDING job을 취소하지 않고 고쳤다. train_ab.sh는 worker가 launch 시점에 읽고, 제출 라인에 AB_SAVE_TOP_K가 없어서 기본값이 그대로 적용된다. 취소·재제출했으면 13시간치 queue age를 버렸을 것이다.

watcher 확장

구버전 tmp/ab_watch.sh는 step 정체를 51회 잡아냈지만 로그 파일에만 썼고, 그동안 체크포인트가 죽어 있는 건 아무도 몰랐다. 새 버전은 매 사이클 zip 무결성을 검사하고, 새 job이 뜨면 [resume] 라인을 출력한다.

resume 검증이 왜 필요한가: ab_pm이 11.5k가 아니라 0부터 다시 시작하면 몇 시간 동안 완벽히 정상적인 학습처럼 보인다. 손실을 발견했을 땐 이미 늦다.

6부수 발견 — 1.76× 비대칭은 transient였다

100-step 스모크에서 pointmap arm의 depth_loss가 depth arm의 1.76배로 나왔고, 나는 이걸 "구조적"이라고 설명했다 — sim depth는 매끈한 grayscale이라 image VAE가 쉽게 처리하는 반면 pointmap은 chroma를 세 축에 나눠 쓴다는 것. 실제 학습이 이를 반박한다.

step 구간depthpmpm/depth
0 – 1k0.17150.21361.25×
1k – 2k0.08220.07630.93×
2k – 3k0.07020.06150.88×
3k – 4k0.06670.05660.85×

2k–4.16k 매칭 108개 로그 지점 기준 pm 0.0587 vs depth 0.0682, t = −40. 포인트맵 arm이 gradient를 더 먹는 게 아니라 덜 먹는다. 1.76×는 초기 transient였고, 스모크가 1 GPU / batch 1이었던 것도 겹쳤다.

실무적 결론: weight-matched 세 번째 arm은 필요 없을 가능성이 높다. 두 weight를 1.0으로 둔 채 표현 비교에 집중할 수 있다.

나머지 loss (2k–4.16k)

lossdepthpmΔt
video0.17480.1741−0.0007−2.9
action0.06310.0635+0.00040.4
proprio0.04710.0452−0.0018−2.0

video_loss 차이 0.4%는 통계적으로 잡히지만 크기가 무의미하고, 애초에 depth 브랜치가 trunk를 공유하니 0일 수 없다 — 그 커플링이 실험 대상 자체다. action_loss는 아직 차이 없음(t=0.4) → 4k step 시점에 SR을 예측할 신호는 없다.

7Takeaway

extra QOS에서 save_top_k=0은 체크포인트가 없는 것과 같은 실패 모드를 갖는다. 저장 윈도우가 grace 윈도우의 절반을 차지하므로 preempt 1회당 유일본을 잃을 확률이 무시할 수준이 아니다. +1.7시간은 5시간 손실 앞에서 명백히 싼 보험이다.
파일이 존재한다는 것과 로드된다는 것은 다르다. watcher가 step 정체는 51번 잡았는데 체크포인트가 죽은 건 13시간 뒤 손으로 찾았다. 감시는 "진행"뿐 아니라 "복구 가능성"도 봐야 한다.
자기 job이 자기 job을 막는다. 계정 GPU cap은 사용자별이 아니라 계정별이고, own 장기 예약은 스스로의 큐를 막는 형태로 되돌아온다.

8Next

항목상태
rc24_D 종료 후 A/B 슬롯 확보 (~22h)대기
ab_pm step ~11,500 재개 → 20k 완주대기
ab_depth step 0 재시작 → 20k5h 손실 확정
gate_base.sh도 같은 save_top_k=0 문제 — arm D 진행 중이라 판단 필요미결
원자적 저장(임시 경로 → rename)이 근본 수정. save_top_k=1은 확률만 낮춘다보류
arm B의 24번째 task(PnPCounterToStove) 평가미착수