MetaView의 3D 메커니즘(카메라 조건부 attention + 멀티뷰 3D 토큰)을 비디오 생성 모델로 확장해 WAM의 backbone으로 쓰는 것. 3D consistency를 확보하고 wrist view를 더 잘 생성해서 action 예측 정확도를 높이는 것이 최종 목표다.
구조는 Wan2.2 5B(X-WAM SFT) 위에 geometry branch를 30개 블록 전부에 병렬로 붙인 것. wrist 비디오 토큰이 query가 되고, key/value는 두 그룹이다 — exo 첫 프레임의 DA3 3D 토큰(기하)과 exo t=0 VAE latent(외형). 카메라는 PRoPE로 들어간다.
P_qᵀ, k에 P_k⁻¹를 걸어야
qᵀk가 P_q P_k⁻¹ — 즉 query 카메라 대비 key 카메라 — 를 담는다.
한쪽에만 걸면 상대항이 아예 없다. 이 한 문장이 아래 모든 결과를 관통한다.
네 arm 모두 8,000스텝 완주, 정합 검증점 129개. 아래는 step ≥ 1000의 112개 평균.
| arm | 카메라가 들어가는 방식 | wrist LPIPS | exo1 | exo2 | wrist PSNR | vs M1 |
|---|---|---|---|---|---|---|
| M1 | branch 없음 | 0.2579 | 0.0599 | 0.0542 | 18.52 | — |
| M2 | PRoPE key만 | 0.2622 | 0.0621 | 0.0567 | 18.45 | 48/112 |
| M4 | additive camera token | 0.2560 | 0.0573 | 0.0516 | 18.54 | 56/112 |
| M3 | PRoPE q+k, GT wrist pose | 0.1438 | 0.0532 | 0.0492 | 21.74 | 112/112 |
후반부(step ≥ 6000, n=32)에서 격차는 더 벌어진다: M1 0.2568 / M2 0.2546 / M4 0.2524 / M3 0.1150. 수렴 속도가 아니라 도달점의 차이다.
테스트 65개, 비트 정확한 check_noop, 양성 대조까지 전부 초록인 상태였다.
드러난 건 "카메라 파라미터가 어떻게 들어가고 있냐"는 질문을 받았을 때다.
구현이 명세와 맞는지는 검증했지만, 명세가 논문의 메커니즘과 맞는지는 아무도 안 봤다.
M3는 GT wrist pose를 먹으므로 배포 불가다(미래 wrist pose = 예측 대상 = action). M4는 VGGT 방식으로 camera token이 뷰 내용에서 카메라를 인지하게 하고 PRoPE를 완전히 걷어냈다.
exo_camera_broadcast는 exo 뷰 하나당 벡터 하나를 그 뷰의 모든 3D 토큰에
똑같이 더한다. 그런데 PRoPE가 3D 토큰에 위치를 부여하던 유일한 장치였고, M4는 그걸 껐다.
남은 건 위치 정보 없는 선형 투영 + 뷰당 상수이고, attention은 순열 불변이다.
같은 exo 뷰의 3D 토큰을 아무렇게나 섞어도 출력이 동일하다. camera token이 구분하는 건 exo1인가 exo2인가, 딱 1비트다.
| arm | 키가 나르는 것 | 쿼리가 나르는 것 |
|---|---|---|
| M2 | PRoPE — 토큰별 위치×카메라 | 없음 |
| M3 | PRoPE — 토큰별 | PRoPE — GT wrist pose |
| M4 | 뷰당 상수 1개 | camera token |
| arm | 보고된 rot_deg | wrist만 | exo1 | exo2 |
|---|---|---|---|---|
| M1 | 4.71 | 4.71 | — | — |
| M3 | 4.08 | 4.08 | — | — |
| M4 | 3.66 | 5.17 | 2.03 | 3.78 |
M4의 전체 3.66°가 최고로 보이지만, 뷰별로 쪼개면 wrist는 5.17°로 M1의 4.71°보다 나쁘다. 좋아 보인 건 쉬운 exo 두 개(그중 exo1은 타깃이 정확히 상수 0) 덕분이다. 설계 §4.3이 정확히 이 실패 모드를 예측하고 지표를 만들어뒀고, 지표가 잡았다.
M3의 44%는 "카메라대로 재투영한다"와 "pose를 클립 지문으로 써서 암기했다" 양쪽과 양립한다. 가르려면 학습 때 준 적 없는 카메라를 주고 생성해야 한다. 같은 클립을 같은 노이즈로 궤적만 바꿔 재생성했다(168개 영상, held-out 6 + 한 번도 안 본 6클립).
| 궤적 | 앵커 보존 | M1 held | M3 held | M1 unseen | M3 unseen |
|---|---|---|---|---|---|
| offset (강체 0.15 m) | ✓ | 0.0001 | 0.0096 | 0.0002 | 0.0111 |
| random_dir (거리 동일, 방향 무작위) | ✓ | 0.0000 | 0.0630 | 0.0000 | 0.0982 |
| static (정지) | ✓ | 0.0000 | 0.1118 | 0.0000 | 0.2035 |
| jitter (σ=2 cm) | ✓ | 0.0000 | 0.1234 | 0.0000 | 0.1061 |
| swap (다른 클립) | ✗ | 0.0012 | 0.1519 | 0.0008 | 0.2189 |
| reverse (되감기) | ✗ | 0.0001 | 0.2201 | 0.0005 | 0.2746 |
수치는 vs_gt_traj LPIPS — 같은 클립·같은 노이즈·진짜 카메라로 만든
생성물 대비 변화량. 0이면 카메라 치환이 아무것도 안 바꿨다는 뜻이다.
wrist_viewmats를 안 읽고 proprio 토큰 1·2는 예측 타깃이라 노이즈로 대체되므로,
실제 입력은 토큰 0 하나뿐이고 앵커 보존 궤적은 그걸 건드리지 않는다. 반응은 M3의 메커니즘에
귀속된다.
offset(어디에 있나) ≪ random_dir(어디로 가나) <
static/jitter(움직이나 / 매끄럽나).offset은
flow를 전혀 안 바꾸고, random_dir은 방향만, static/jitter는 크기 자체를
바꾼다 — 반응 크기가 정확히 그 순서다. M3는 카메라를 "장면 안에 나를 배치하는
정보"가 아니라 "프레임 사이 화면이 어떻게 흐를지 예측하는 정보"로 쓴다.
절대 위치가 무시되는 이유도 코드에 있다: latent_mask[:, :, 0] = 1이
모든 뷰의 첫 프레임을 clean하게 준다(wrist 포함). 절대 위치는 이미 그 이미지 안에 있어
중복이고, 첫 프레임이 말해주지 않는 건 "카메라가 다음에 어디로 가는가"뿐 — M3는 정확히 그
부분만 골라 썼다.
생성 품질: 한 번도 안 본 에피소드에서 M3 gt의 wrist LPIPS는 0.1308
(M1 0.2422). unseen은 에피소드 단위로 제외했다 — 같은 에피소드의 다른 창은 같은 장면·로봇·
카메라 리그라 unseen이 아니다. 641,022개 중 subset의 8,381개 에피소드를 통째로 빼고 남은 441,671개에서
64개를 뽑아 전부 디코딩 검증(64/64)했다.
droid_dataset.py:167은 Task 2 이래로 이렇게 기록해뒀다 — wrist↔exo1은
droid_raw의 원시 캘리브레이션, exo1↔exo2는 PointWorld의 bundle-adjusted
캘리브레이션. "알려진, 수용된 불일치이며 일치한다고 증명되지 않았다." 그런데 branch는
매 logit에서 이 둘을 곱한다.
exo1 첫 프레임을 metric depth와 원본 픽셀 intrinsics로 unproject → PointWorld 상대 pose로 exo2에 재투영 → 실제 exo2와 비교. 40 clips.
| pose | PSNR | NCC | coverage |
|---|---|---|---|
| 참 pose | 13.14 | 0.6058 | 0.236 |
| +1° | 12.92 | 0.5820 | 0.236 |
| +2° | 12.58 | 0.5472 | 0.236 |
| +5° | 11.77 | 0.4552 | 0.234 |
| +10° | 10.98 | 0.3603 | 0.229 |
| identity | 9.42 | 0.1369 | 0.846 |
Phase 0의 워프는 이 질문에 답한 적 없다 —
exo_to_wrist(exo_pose, wrist_pose)로 두 pose 모두 droid_raw에서 읽어 한 캘리브레이션
안의 컨벤션(w2c vs c2w)만 확인했다. 그리고 이 검증은 qᵀk의 key 쪽만
본다 — wrist 뷰로 워프하려면 wrist intrinsics가 필요한데 파이프라인에 없다.
학습 없이 샘플링만. unseen 6클립. 기준선 M3 gt vs_real LPIPS = 0.1308, M1 = 0.2422 →
기하 메커니즘 전체의 값어치 = 0.1114. 아래 비율은 전부 이 값 대비다.
| pose 오차 | vs_real | Δ | 이득 유지율 |
|---|---|---|---|
| 0° (GT) | 0.1308 | — | 100% |
| 2° | 0.1564 | +0.0256 | 77% |
| 5° | 0.2448 | +0.1140 | −2% |
| 8° (M4 달성치) | 0.2937 | +0.1629 | −46% |
| 15° | 0.3638 | +0.2330 | −109% |
달성치와의 격차 — 보고된 rot_deg_wrist는 토큰 0이 GT로 고정된 채 평균에 들어가므로
예측이 필요한 프레임의 오차는 보고값의 1.5배다:
어느 arm도 근처에 못 갔고 격차가 3~4배다. 마진 문제가 아니다.
카메라와 PRoPE는 건드리지 않고 내용만 바꿨다. 뷰를 넘나들지 않고 뷰 안에서 섞는다 — 넘나들면 어느 camera token과 짝지어지는지도 바뀌어 "내용"과 "카메라"가 뒤섞인다.
| tokens_3d | vs_real | Δ | 메커니즘 대비 |
|---|---|---|---|
| gt | 0.1308 | — | — |
| shuffle (뷰 안 순열) | 0.1387 | +0.0079 | 7% |
| other (다른 클립 내용) | 0.1394 | +0.0085 | 8% |
| zero (상수) | 0.2251 | +0.0943 | 85% |
tokens_3d(DA3)만 바꿨다. branch의 key/value는
두 그룹이고(k = cat([k_3d, k_ref]), 1216개 + 120개),
두 번째 ref는 x[:, exo_ref_slice(...)] —
비디오 시퀀스에서 직접 오는 exo t=0 VAE latent로 안 바꿨다.
게다가 exo 뷰는 메인 DiT 시퀀스에도 있고 t=0가 clean하게 주어지므로 global attention으로도 접근된다.zero가 85%인 것이 (a) 쪽 정황이다 — 내용이 중복이라면 DA3를 상수로 채워도
ref에서 읽으면 되는데 무너졌으니, DA3 그룹은 내용이 아니라 키의 90%를 차지하는 attention
기질로서 필요했던 셈이다. 깨끗한 실험은 ref도 같이 바꾸는 것이다.
정정과 별개로 이유는 셋이 남는다. (1) 정보가 중복이다 — DA3는 exo 첫 프레임의 특징이고 exo latent는 같은 프레임의 VAE 인코딩, 같은 이미지의 두 표현이다. (2) query 해상도가 10.14°/patch다 — 내용의 정밀도가 애초에 활용될 수 없다. (3) "다른 클립"이 무의미한 게 아니다 — 같은 DROID 테이블탑이라 "책상이 있고 팔이 있다" 수준의 통계는 전이된다. 무작위 노이즈가 아니다.
그리고 zero에서 깨지는 건 PRoPE가 키와 값을 둘 다 회전시키는데
(_apply_to_kv(k_3d), (v_3d)) 모든 키가 같은 벡터가 되어
attention이 선택할 대상이 없어지는 것이다.
메커니즘은 3D 내용보다 카메라 pose에 13배 민감하다.
네 실험이 각각 다른 경로로 같은 곳을 가리킨다.
| 실험 | 말하는 것 |
|---|---|
| 4 arm ablation | 카메라가 정확하고(내용) 상대 변환으로(형태) 들어가야 한다. 둘 중 하나만 깨져도 0. 직렬이다 |
| 반사실 궤적 | M3는 카메라를 따르지만 배치가 아니라 프레임 간 flow를 쓴다 — 조대한 정보 |
| 캘리브레이션 | 기하는 정확하지만 query 격자가 10°/patch — ray 수준 검색은 불가능 |
| 프로브 | DA3의 장면 특이적 내용은 8%, pose 정확도가 13배 더 중요 |
그리고 M3의 oracle 성격도 날카로워진다. wrist 카메라의 미래 운동 = action이므로, M3가 받은 건 "카메라 정보"가 아니라 사실상 정답 action이고, M3가 한 일은 "주어진 앵커 프레임에서 알려준 운동대로 렌더링"이다.
zero는 "제거"가 아니라 "상수 채움"이다. 3D 키 608개가 여전히 존재하고
내용만 균일하다. 균일한 키가 attention을 희석해 해로울 수 있으므로 85%는 제거 비용의
상한이다.ref까지 바꾸는 실험이 남아 있고, 그때까지 "3D 토큰은 통로"는 가설이다.통과하는 게이트는 그 게이트가 무엇을 배제하는지 확인하기 전까지 증거가 아니다.
M2는 65개 테스트와 비트 정확한 check_noop을 통과한 채 메커니즘의 절반만 돌고 있었다.
M4는 137개 테스트와 6개 검증 지표를 통과한 채 순열 불변이었다. 두 번 다 "구현이 명세와 맞는가"는
검증됐고 "명세가 물리와 맞는가"는 아무도 안 봤다.
메커니즘을 옮길 때는 그것이 무엇을 전제하는지 다시 유도해야 한다. 설계 §3에서 VGGT 소스를 직접 읽고 구조는 정확히 옮겼지만 "모든 프레임이 관측된다"는 전제는 명시조차 안 했다.
19시간짜리 학습 전에 30분짜리 프로브를 돌렸어야 했다. 이번에 순열 불변성은 단위 테스트 수준의 코드 10줄로 즉시 드러났고, pose 임계값과 3D 토큰 기여도는 학습 없이 30분에 나왔다. 셋 다 M4를 설계하는 시점에 가능했다.