check_noop = 0.0 — 실제 5B 체크포인트에서 geometry를 켜되 zero-init인 상태가 끈 것과 비트 단위로 일치Phase 0에서 MetaView zero-shot으로 DROID exo→wrist 생성은 불가로 확정됐습니다. 원인은 모델이 pose 조건을 각도 크기와 무관하게 약하게 반영한다는 것이었고, 정지 9장과 연속 49프레임 두 방식으로 확인됐습니다.
그래서 Phase 1은 방향을 바꿨습니다: zero-shot을 포기하고, MetaView의 기하 메커니즘(PRoPE + 멀티뷰 3D 토큰)을 Wan2.2 비디오 백본에 처음부터 통합해서 학습합니다. 최종 목적은 WAM의 backbone으로 쓰면서 3D consistency와 wrist view 품질을 올려 action 예측 정확도를 높이는 것입니다.
Wan2.2-TI2V-5B에 X-WAM을 scaffold로 얹고, DiT 블록 30개 각각에 zero-init residual geometry branch를 삽입합니다.
| 구성 | 내용 | PRoPE |
|---|---|---|
| query | wrist 토큰 (180개) | ✗ pose-free |
| key/value 1 | 3D 토큰 — frozen DA3, 기하 (1216개) | ✓ |
| key/value 2 | exo t=0 VAE latent — 외형 (120개) | ✓ |
| exo 토큰 | branch에서 query로 쓰이지 않음 | — |
proprio 슬롯을 재사용해서 (proprio_dim=6) X-WAM 패치를 2개에서 1개로 줄였습니다.읽기 전용인 두 소스를 조인합니다: NVIDIA PointWorld-DROID(재최적화된 exo extrinsic·intrinsic·metric depth)와 droid_raw(RGB 영상 — wrist는 여기에만 존재).
| 항목 | 값 | 비고 |
|---|---|---|
| PointWorld 에피소드 | 42,935 | 약 6 TB |
| clip 인덱스 | 641,022 | 에피소드당 14.9 |
| PointWorld ⋈ droid_raw | 100% | 표본 300 전부 wrist MP4 존재 |
| 학습 부분집합 | 10,000 clip | 8,381 에피소드 / 13개 랩 / success 87% · failure 13% |
| 3D 토큰 캐시 | 140 GB | 26분 47초, CPU 인덱스 17분 47초 |
| process_res | 격자 | 토큰 | clip당 | 전체 641k라면 |
|---|---|---|---|---|
| 840 (DA3 기본) | (36,60) | 4320 | 53.1 MB | 34 TB |
| 448 (채택) | (19,32) | 1216 | 14.9 MB | 9.6 TB |
| 336 | (14,24) | 672 | 8.3 MB | 5.3 TB |
dim은 어느 설정이나 6144. 840은 우리 192×320을 2.6배 업샘플하므로 원본에 없는 정보를 만들지 못합니다. 전체 인덱스를 캐시했다면 34 TB — 랩 전체가 공유하는 GPFS 여유가 67 TB인 상황에서 불가능했습니다.
| Task | 산출물 | 테스트 | 상태 |
|---|---|---|---|
| 1 | src/wam/pointworld.py — PointWorld 기하 reader | 4 | 완료 |
| 2 | src/wam/droid_dataset.py — 2-소스 조인 | 10 | 완료 |
| 3 | src/wam/encoders/ — DA3 + VGGT-Omega | 5 | 완료 |
| 4 | src/wam/precompute_tokens.py + 캐시 | 4 | 완료 |
| 5 | src/wam/geometry_branch.py — 핵심 메커니즘 | 9 | 완료 |
| 5b | src/wam/camera_token.py | 5 | 완료 |
| 6 | src/wam/model.py + X-WAM 패치 — 5B 배선 | 3 + check_noop | 완료 |
| 7 | src/wam/train.py — M1 학습 | — | 스모크 디버깅 |
| 8, 9 | M2 ablation, M3 | — | 대기 |
check_noop = 0.0branches[0].to_out을 교란하면 diff 1.448e-02. 이게 없으면 0.0이 "제대로 배선됨"과 "한 번도 실행 안 됨"을 구분하지 못합니다.이 프로젝트는 Task마다 구현 → 독립 리뷰 → fix 라운드 → 범위 한정 재리뷰 구조로 진행했습니다. 아래는 학습을 돌리기 전에 잡힌 결함 전부입니다.
| # | 결함 | 어떻게 잡혔나 | 결과였을 일 |
|---|---|---|---|
| 1 | EXTRINSICS_ARE_C2W 규약이 뒤집힘 (계획서는 True, 정답 False) | exo1→exo2 워프를 두 규약으로 돌려 육안 비교 (cov 19.7%/err 72.0 뒤죽박죽 vs 25.9%/43.4 정합) | 모든 기하가 그럴듯하게 틀림 |
| 2 | 정합 테스트가 ±1을 판별 못 함 (세 오프셋 Δ≤0.0004) | 구현자가 스스로 보고 → controller_info/success(길이 168, index 167만 True)로 재증명 | offset이 틀려도 통과 |
| 3 | 테스트 판정이 os.scandir 순서에 걸림 | CLVR(0.016) 대신 AUTOLab(0.064)이 뽑히면 실패 | 유령 버그 추적 |
| 4 | worker에서 cd ""가 무동작 (git 없음, set -e 미발동) | 구현자 진단 | 잘못된 디렉토리에서 실행 |
| 5 | key 그룹 하나가 통째로 빠져도 전 테스트 통과 | 리뷰어가 실제로 k=k_ref만으로 바꿔 확인 | 메커니즘 절반이 미검증 |
| 6 | QK-norm 누락 (계획서 코드가 원본의 RMSNorm 4개를 전부 빠뜨림) | 리뷰어가 MetaView_dit.py:327-331과 대조 | M2가 "기하+외형"이라 쓰고 "기하만" 측정 |
| 7 | backbone freeze가 camera token을 학습 불가로 | 리뷰어가 init_new_weights()와 LoRA 대상 범위를 대조 | proprio loss가 내려갈 수 없는데 video loss는 정상 |
| 8 | peft가 unfreeze를 되돌림 | #7 수정 중 새 테스트가 첫 실행에 잡음 | Critical 수정이 무효인 채 커밋 |
| 9 | run_depth=True면 30블록 중 10개가 hook 없이 | 구현자 진단, 소스로 재확인 | 메커니즘 1/3이 조용히 사라짐 |
| 10 | action_num: 0이 생성 시점 ZeroDivisionError | 스모크 크래시 | 즉시 발견 |
| 11 | M1이 641k clip, M2가 10k clip으로 학습될 뻔 | 구현자가 precompute_tokens.py docstring과 대조 | 메커니즘 + 데이터 64배가 동시에 바뀐 무의미한 비교 |
구현자들이 zero-init을 일부러 깨서 테스트가 실제로 실패하는지 확인했고, 리뷰어들도 mutant를 만들어 대조했습니다. "초록불"과 "이 테스트가 뭘 잡는지"는 다른 질문입니다.
RMSNorm 효과를 확인하는 테스트에서 제가 "tokens_3d를 ×100"이라고 지시했습니다. 구현자는 그대로 쓰지 않고 정규화 없는 mutant에 1배~100만배를 쓸어봤고, ×100에서는 diff 1.6e-2로 여전히 반응해 테스트가 무의미하게 통과한다는 걸 찾았습니다. ×1000이 실제 판별점(diff 0.0)이었습니다. 제가 나중에 같은 숫자를 다시 지시했을 때도 근거를 들어 거부했습니다.
exo-ref 참여 테스트에서 +5.0 균일 교란을 줬는데, elementwise_affine=False인 LayerNorm은 평균을 빼므로 균일 이동이 상쇄됩니다. 그래서 배선이 올바른 코드에서도 통과했습니다 — 아무것도 검증하지 못하는 테스트였습니다. 랜덤 재추출로 고쳤습니다.
check_noop = 0.0이 이 Task의 핵심 산출물이었는데, 리뷰어가 0.0은 "완벽히 배선됨"과 "한 번도 실행 안 됨"을 구분하지 못한다고 지적했습니다. 이 교훈은 이 프로젝트의 모든 동등성 검사에 적용됩니다.
Task 7 스모크 2회 실패. (1) action_num: 0 → 수정 완료. (2) Can't pickle local object 'main.<locals>.collate' — DataLoader 워커가 클로저를 pickle 못 함. 모듈 레벨로 이동 필요. 수정 중.
VGGT-Omega HF 접근 요청 — huggingface.co/facebook/VGGT-Omega가 gated=manual이라 실명 라이선스 동의가 필요합니다.
추가로, 로그인 노드의 활성 HF 신원이 kinam0252(타인)이라 승인받으셔도 토큰 교체가 필요합니다. DA3만으로 M1·M2 완주는 가능하므로 지금 막히진 않으나, 계획된 인코더 ablation은 그때까지 불가합니다.
geometry hook이 torch_checkpoint 바깥에 있어 gradient checkpointing 시 30개 branch 활성값이 상주합니다. M1의 peak memory 수치로 M2가 들어갈지 판단해야 합니다.
flash_attn 미설치로 SDPA fallback 중 — 5B 모델에 540 비디오 토큰 + M2에서 1216 3D 키가 붙으므로 처리량 손해가 실질적입니다. M1의 s/it 측정 후 설치 여부를 판단합니다.
| 단계 | 내용 | 판정 지표 |
|---|---|---|
| M1 | baseline — geometry branch off | 기준 수치 확보 |
| M2 | 동일 config에 branch만 on | wrist LPIPS |
| M2b | camera token 예측 pose를 PRoPE로 되먹임 | 설계 부채 상환 |
| M3 | M2 결과에 따라 분기 (LoRA 스케일 / aux loss) | 조건부 |
| Phase 2 | action head — camera token이 이미 인터페이스 | 미착수 |