Index
2026-08-04 — Progress

WAM Backbone Phase 1 — 설계부터 구현 완료까지

MetaView 기하 메커니즘을 Wan2.2-TI2V-5B에 통합 · DROID 3뷰 비디오 생성 · M1/M2 ablation 준비

TL;DR

8/10
Task 완료
22
커밋
0.0
check_noop diff
11
잡힌 결함
140 GB
토큰 캐시
10,000
학습 clip

1 배경 / 목적

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 예측 정확도를 높이는 것입니다.

증명할 주장: 기하 메커니즘이 wrist view 품질과 cross-view 3D 정합을 측정 가능하게 개선한다 — M1(branch off) vs M2(branch on) ablation으로.

2 아키텍처

Wan2.2-TI2V-5B에 X-WAM을 scaffold로 얹고, DiT 블록 30개 각각에 zero-init residual geometry branch를 삽입합니다.

구성내용PRoPE
querywrist 토큰 (180개)✗ pose-free
key/value 13D 토큰 — frozen DA3, 기하 (1216개)
key/value 2exo t=0 VAE latent — 외형 (120개)
exo 토큰branch에서 query로 쓰이지 않음
wrist가 pose-free인 이유: 미래 wrist pose는 곧 우리가 예측하려는 action입니다. 조건으로 넣으면 학습과 배포가 갈립니다. 대신 camera token이 wrist pose를 지도학습되는 latent로 나릅니다 — X-WAM의 proprio 슬롯을 재사용해서 (proprio_dim=6) X-WAM 패치를 2개에서 1개로 줄였습니다.
key가 두 그룹인 이유: 3D foundation model은 기하용으로 학습돼 텍스처를 보존할 이유가 없습니다. MetaView가 source를 VAE latent(외형)와 DA3 feature(기하) 양쪽으로 인코딩하는 구조를 따랐습니다.

학습 대상

학습 · LoRA r=64
Wan2.2 qkvo, ffn
학습 · full
GeometryBranch ×30
학습 · full
camera token, view_emb
frozen
DA3 · VAE · text enc

3 데이터 파이프라인 (실측)

읽기 전용인 두 소스를 조인합니다: NVIDIA PointWorld-DROID(재최적화된 exo extrinsic·intrinsic·metric depth)와 droid_raw(RGB 영상 — wrist는 여기에만 존재).

항목비고
PointWorld 에피소드42,935약 6 TB
clip 인덱스641,022에피소드당 14.9
PointWorld ⋈ droid_raw100%표본 300 전부 wrist MP4 존재
학습 부분집합10,000 clip8,381 에피소드 / 13개 랩 / success 87% · failure 13%
3D 토큰 캐시140 GB26분 47초, CPU 인덱스 17분 47초

VAE 제약으로 확정된 값

9프레임 ← Wan2.2 VAE 시간 stride 4 → T ≡ 1 (mod 4). clip은 11프레임 192×320 ← 공간 stride 16. PointWorld depth의 180은 180/16 = 11.25로 불가 → latent 12×20 → patchify(1,2,2) → 6×10 = 60 패치/뷰/프레임 → 540 비디오 토큰

인코더 실측 (192×320, 실가중치 GPU)

process_res격자토큰clip당전체 641k라면
840 (DA3 기본)(36,60)432053.1 MB34 TB
448 (채택)(19,32)121614.9 MB9.6 TB
336(14,24)6728.3 MB5.3 TB

dim은 어느 설정이나 6144. 840은 우리 192×320을 2.6배 업샘플하므로 원본에 없는 정보를 만들지 못합니다. 전체 인덱스를 캐시했다면 34 TB — 랩 전체가 공유하는 GPFS 여유가 67 TB인 상황에서 불가능했습니다.

4 구현 결과

Task산출물테스트상태
1src/wam/pointworld.py — PointWorld 기하 reader4완료
2src/wam/droid_dataset.py — 2-소스 조인10완료
3src/wam/encoders/ — DA3 + VGGT-Omega5완료
4src/wam/precompute_tokens.py + 캐시4완료
5src/wam/geometry_branch.py — 핵심 메커니즘9완료
5bsrc/wam/camera_token.py5완료
6src/wam/model.py + X-WAM 패치 — 5B 배선3 + check_noop완료
7src/wam/train.py — M1 학습스모크 디버깅
8, 9M2 ablation, M3대기
핵심 검증 — check_noop = 0.0
실제 5B 체크포인트에서, geometry를 켜되 zero-init인 상태의 출력이 끈 것과 비트 단위로 동일합니다. 즉 hook이 backbone을 전혀 오염시키지 않았습니다.

양성 대조도 추가: branches[0].to_out을 교란하면 diff 1.448e-02. 이게 없으면 0.0이 "제대로 배선됨"과 "한 번도 실행 안 됨"을 구분하지 못합니다.

5 검증 층이 잡은 결함 11건

이 프로젝트는 Task마다 구현 → 독립 리뷰 → fix 라운드 → 범위 한정 재리뷰 구조로 진행했습니다. 아래는 학습을 돌리기 전에 잡힌 결함 전부입니다.

#결함어떻게 잡혔나결과였을 일
1EXTRINSICS_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)이 뽑히면 실패유령 버그 추적
4worker에서 cd ""가 무동작 (git 없음, set -e 미발동)구현자 진단잘못된 디렉토리에서 실행
5key 그룹 하나가 통째로 빠져도 전 테스트 통과리뷰어가 실제로 k=k_ref만으로 바꿔 확인메커니즘 절반이 미검증
6QK-norm 누락 (계획서 코드가 원본의 RMSNorm 4개를 전부 빠뜨림)리뷰어가 MetaView_dit.py:327-331과 대조M2가 "기하+외형"이라 쓰고 "기하만" 측정
7backbone freeze가 camera token을 학습 불가로리뷰어가 init_new_weights()와 LoRA 대상 범위를 대조proprio loss가 내려갈 수 없는데 video loss는 정상
8peft가 unfreeze를 되돌림#7 수정 중 새 테스트가 첫 실행에 잡음Critical 수정이 무효인 채 커밋
9run_depth=True30블록 중 10개가 hook 없이구현자 진단, 소스로 재확인메커니즘 1/3이 조용히 사라짐
10action_num: 0생성 시점 ZeroDivisionError스모크 크래시즉시 발견
11M1이 641k clip, M2가 10k clip으로 학습될 뻔구현자가 precompute_tokens.py docstring과 대조메커니즘 + 데이터 64배가 동시에 바뀐 무의미한 비교
11건 중 6건이 계획서(제가 쓴 spec/plan) 오류였고, #1·#5·#6·#7·#11은 크래시 없이 실험을 무의미하게 만들 종류였습니다. 전부 학습 전에 잡혔습니다.

6 검증 방법론에서 배운 것

1. 변이 테스트가 반복적으로 값어치를 했다

구현자들이 zero-init을 일부러 깨서 테스트가 실제로 실패하는지 확인했고, 리뷰어들도 mutant를 만들어 대조했습니다. "초록불"과 "이 테스트가 뭘 잡는지"는 다른 질문입니다.

2. 제가 준 숫자가 틀렸고 구현자가 측정으로 뒤집었다

RMSNorm 효과를 확인하는 테스트에서 제가 "tokens_3d를 ×100"이라고 지시했습니다. 구현자는 그대로 쓰지 않고 정규화 없는 mutant에 1배~100만배를 쓸어봤고, ×100에서는 diff 1.6e-2로 여전히 반응해 테스트가 무의미하게 통과한다는 걸 찾았습니다. ×1000이 실제 판별점(diff 0.0)이었습니다. 제가 나중에 같은 숫자를 다시 지시했을 때도 근거를 들어 거부했습니다.

3. 거짓 통과를 스스로 잡은 사례

exo-ref 참여 테스트에서 +5.0 균일 교란을 줬는데, elementwise_affine=False인 LayerNorm은 평균을 빼므로 균일 이동이 상쇄됩니다. 그래서 배선이 올바른 코드에서도 통과했습니다 — 아무것도 검증하지 못하는 테스트였습니다. 랜덤 재추출로 고쳤습니다.

4. "0이면 통과" 검사는 양성 대조 없이 무의미하다

check_noop = 0.0이 이 Task의 핵심 산출물이었는데, 리뷰어가 0.0은 "완벽히 배선됨"과 "한 번도 실행 안 됨"을 구분하지 못한다고 지적했습니다. 이 교훈은 이 프로젝트의 모든 동등성 검사에 적용됩니다.

7 현재 상태 / 다음

지금 막힌 것

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은 그때까지 불가합니다.

M2 전에 판단할 것

geometry hook이 torch_checkpoint 바깥에 있어 gradient checkpointing 시 30개 branch 활성값이 상주합니다. M1의 peak memory 수치로 M2가 들어갈지 판단해야 합니다.

flash_attn 미설치로 SDPA fallback 중 — 5B 모델에 540 비디오 토큰 + M2에서 1216 3D 키가 붙으므로 처리량 손해가 실질적입니다. M1의 s/it 측정 후 설치 여부를 판단합니다.

로드맵

단계내용판정 지표
M1baseline — geometry branch off기준 수치 확보
M2동일 config에 branch만 onwrist LPIPS
M2bcamera token 예측 pose를 PRoPE로 되먹임설계 부채 상환
M3M2 결과에 따라 분기 (LoRA 스케일 / aux loss)조건부
Phase 2action head — camera token이 이미 인터페이스미착수
판정을 LPIPS가 지는 이유: Phase 0에서 DROID의 PSNR 편차가 전 조건에 걸쳐 0.5dB 미만이었고 SSIM이 PSNR과 순위를 뒤집었습니다. 그리고 wrist는 pose·intrinsic이 없어 reprojection으로 정량화가 불가능합니다 — exo↔exo 수치는 branch가 exo를 직접 건드리지 않으니 거의 안 움직이는 게 정상입니다.