EgoWM — Grounded egocentric hand + camera + depth on Wan 2.1
Fine-tuning a video foundation model (Wan 2.1-1.3B) with metric-grounded heads for hand pose, camera pose, and depth on 33k egocentric hand-object interaction clips.
Latest (2026-07-13): v36_sgdr13 step 3000 = 61.00 mm abs / rr 35.9 / PA 10.55 / wrist 43.4 / pix 20.81 / depth 0.151 on ARCTIC-lite (N=40). On 150-clip: 60.04 mm (first sub-61!). Thirteenth stacked SGDR delivered −0.62 mm on 40-clip / −1.09 mm on 150-clip. Wrist broke 44 mm floor. Notebook 132→66.0 (−50% — first below 50% of baseline!), s05 121→70.2 (−42%). v13 → v36: −32% abs on 150-clip. Gap to Iter 206 oracle: 7.0 mm on 40-clip / 6.0 mm on 150-clip.
Showcase
Training convergence — v10_scale on ARCTIC

v10_scale converged from 189 mm at step 500 to 159 mm at step 3000. Depth head continued improving through the end (SSI residual 0.60 → 0.24). Path to the Iter 206 oracle bound (54 mm) still requires either a bigger model or smarter architecture; the current 159 mm is a 28% improvement over v9b and 25% over v8d at 1/8 the training compute.
Full training arc — all 6 metrics × 6 ckpts

Six panels showing every metric across the v10_scale checkpoint series (step 500 → 3000), with v9b baseline (red dashes), v8d step 3000 (gray dots), and reference oracles (dashed lines) for context. Best v10 ckpt marked with gold star.
Multi-model comparison — v8d → v9b → v10 → v11 → v12 → v13 on same clips (6 columns)
Three ARCTIC val clips, six models predicting on the same frames. Columns left → right: v8d step 3000 (yellow) · v9b step 200 (orange) · v10 step 3000 (red-orange) · v11 step 3000 (dark red) · v12_gtmask step 3000 (purple) · v13_stable step 3000 (teal, FINAL 90mm). Per-column MPJPE ticker updates each frame. GT skeleton overlaid in green/cyan on all columns. The training arc is visible left-to-right: v8d predictions are stiffest (mean-collapsed), v9b begins to track, v10 refines, v11 refines further after pixel-focused finetune, v12 becomes tightest after the training-time GT off-frame mislabel fix, and v13 crisply follows GT after rotation-matrix loss + trunk freeze killed the axis-angle mean-collapse.
Earlier versions (for reference)
5-column (v8d → v12)
4-column (v8d → v11)
3-column (v8d → v10)
4-panel gallery
Each card shows one clip with a 2×2 grid video: 1. Raw RGB (input) 2. GT + v10 skeleton overlay (green/cyan GT, red/salmon pred) 3. Predicted depth heatmap (turbo colormap on pmap Z channel) 4. 3D camera path + right-hand wrist trajectory (rotating view)
Per-clip metrics (abs MPJPE, rr, PA, pixel err) shown below each video. Best single clip is s08 capsulemachine_use_01 · abs 106 mm · pixel 27 px (essentially 2× oracle territory on the good clips).
Reports
| Date | Report | One-liner |
|---|---|---|
| 2026-07-12 | 📖 v22→v33 SGDR arc | 74.9→62.91 mm push (−12 mm) via 10 stacked SGDR cycles. Warm-start compounding with cosine warm restarts. Wrist broke 7 whole-mm floors (54→44 mm). Gap to Iter 206 oracle now 7.9 mm on 150-clip. |
| 2026-07-12 | 📖 v17→v21 arc summary | 78.9→75.0 push via layered adaptive weights. Big win: v18 layered per-clip + keyword boost. Nulls: v19 re-scoring, v20 low-LR, temporal smoothing. h2o cross-source improved -11 mm. |
| 2026-07-11 | 📖 v13→v16 arc summary | 12 mm push via diagnostic-driven training. What worked: v15d rebalance, continued specialist training. What didn't: v14 PnP, v15c 6D-rot, v15a multi-res. |
| 2026-07-11 | 🥇 v13 failure by category | Notebook cluster + s05 dominate the tail — informed v15d/v16 rebalance strategy. |
| 2026-07-11 | 🔍 v13 gap diagnostic | Where do the remaining 36 mm live? Per-clip distribution now compact (median 85, min 29, no bimodality); worst clips are "notebook" static-hand typing; h2o PA regressed 22→28 (shape overfit); v14 direction: Somantis-style 2D + s* + PnP lift. |
| 2026-07-11 | 🥇 v13 final report | v13_stable s3000 = 90/45/13/67/35/0.21. Beats v12 champion by −26 mm abs, −33 mm rr (−42%). |
| 2026-07-10 | 🚧 v13 diagnostic (initial) | Why v12's 116 mm was unacceptable: axis-angle MSE mean-collapse, trunk drift, HO3Dv3 pollution, val NaN. |
| 2026-07-10 | 🥇 v12 final report | v12_gtmask s3000 = 116 mm / 34 px / 0.27. Training-time fix compounds better than eval-time filter. Superseded by v13. |
| 2026-07-10 | 🏆 Live leaderboard | Long-term multi-model comparison. v12 step 3000 currently leads at 116 mm / 34 px. |
| 2026-07-10 | 🎞️ Gallery (12 clips) | Per-clip 4-panel videos with metric annotations. |
| 2026-07-10 | 📖 12-hour arc summary | Full 12h autonomous exploration recap: v11 launch → per-source → best/worst → depth → GT filter → v12 retrain. Champion: v11 + GT filter at 124 mm / 39 px. |
| 2026-07-10 | 🏆 GT off-frame filter finding | 25 mm FREE improvement (149 → 124 mm) by filtering frames where GT wrist projects outside camera view. Pixel error 93 → 39 px (58%!). No retraining. |
| 2026-07-10 | 🌊 Depth quality analysis | v11 pred depth vs DA3 GT: AbsRel 0.33, δ<1.25 0.17 across 4 clips. Depth is uniform across best/worst clips — failure mode of worst clips is not depth quality. |
| 2026-07-10 | 🔬 Failure mode analysis | Per-clip metrics on 150 clips: BEST clips at oracle (64 mm / 14 px), WORST at total failure (500 mm / 2761 px). Median performance ~130 mm — mean dragged by 3% tail. |
| 2026-07-10 | 🧭 Iter 209 Direction (post-v10) | What v10 achieved + Gap analysis + v11-v15 backlog with expected impact per recipe. |
| 2026-07-10 | v10 Scale Training log | Full-scale 7-head training on 33k pool with per-head GT masking. |
| 2026-07-10 | v10 Overfit Sanity Test | 2-clip overfit: every loss ≥60% drop. Pipeline confirmed. |
| 2026-07-10 | 3-way Benchmark | Fair v8d/v9a/v9b eval that motivated Iter 208. |
| 2026-07-10 | Iter 208 Blueprint | Architecture + parameter-reuse plan reusing VGGT's 32.65 M point_head. |
Headline numbers (ARCTIC-lite protocol, N=40 clips)
| Model | Steps | abs MPJPE ↓ | rr MPJPE | PA MPJPE | wrist trans | pixel err | depth log-res |
|---|---|---|---|---|---|---|---|
| v36_sgdr13 (LEADER) 🥇 | 3000 | 61.00 mm | 35.9 mm | 10.55 mm | 43.4 mm | 20.81 px | 0.151 |
| v35_sgdr12 | 3000 | 61.62 mm | 36.0 mm | 10.59 mm | 44.0 mm | 20.82 px | 0.160 |
| v34_sgdr11 | 3000 | 62.61 mm | 36.5 mm | 10.70 mm | 44.6 mm | 21.9 px | 0.155 |
| v33_sgdr10 | 3000 | 62.91 mm | 36.9 mm | 10.72 mm | 44.5 mm | 21.7 px | 0.152 |
| v32_sgdr9 | 3000 | 63.70 mm | 37.2 mm | 10.83 mm | 44.8 mm | 21.8 px | 0.151 |
| v31_sgdr8 | 3000 | 64.67 mm | 37.5 mm | 10.9 mm | 45.4 mm | 22.7 px | 0.156 |
| v30_sgdr7 | 3000 | 65.26 mm | 37.6 mm | 10.95 mm | 45.9 mm | 22.8 px | 0.152 |
| v29_sgdr6 | 3000 | 66.00 mm | 37.8 mm | 11.0 mm | 46.4 mm | 22.9 px | 0.149 |
| v28_sgdr5 | 3000 | 66.04 mm | 38.0 mm | 11.1 mm | 46.3 mm | 23.4 px | 0.150 |
| v27_sgdr4 | 3000 | 67.18 mm | 38.4 mm | 11.1 mm | 47.2 mm | 24.1 px | 0.146 |
| v27_sgdr4 | 2500 | 68.7 mm | 38.6 mm | 11.1 mm | 48.4 mm | 24.4 px | 0.153 |
| v26_sgdr3 | 3000 | 68.95 mm | 38.8 mm | 11.2 mm | 48.7 mm | 24.9 px | 0.148 |
| v26_sgdr3 | 3500 | 70.18 mm | 38.5 mm | 11.1 mm | 50.2 mm | 24.7 px | 0.156 |
| v26_sgdr3 | 500 | 70.30 mm | 39.1 mm | 11.1 mm | 50.2 mm | 25.3 px | 0.163 |
| v25_sgdr2 | 3000 | 70.67 mm | 39.3 mm | 11.2 mm | 50.2 mm | 25.7 px | 0.152 |
| v25_sgdr2 | 3500 | 70.91 mm | 38.9 mm | 11.2 mm | 50.6 mm | 25.2 px | 0.160 |
| v24_sgdr | 3500 | 72.02 mm | 39.3 mm | 11.2 mm | 51.6 mm | 26.4 px | 0.162 |
| v24_sgdr | 3000 | 72.6 mm | 39.6 mm | 11.3 mm | 51.9 mm | 26.8 px | 0.156 |
| v24_sgdr | 500 | 73.3 mm | 40.4 mm | 11.4 mm | 52.6 mm | 26.7 px | 0.168 |
| v22_bigscore | 2500 | 74.89 mm | 40 mm | 11.4 mm | 54 mm | 27 px | 0.162 |
| v22_bigscore | 2000 | 75.2 mm | 40 mm | 11.4 mm | 55 mm | 27 px | 0.161 |
| v18_adaptive | 2500 | 75.0 mm | 40 mm | 11.2 mm | 55 mm | 28 px | 0.174 |
| v21_h2o (h2o boost) | 1000 | 75.6 mm | 40 mm | 11.3 mm | 55 mm | 28 px | 0.176 |
| v18_adaptive | 1500 | 75.4 mm | 41 mm | 11.4 mm | 55 mm | 29 px | 0.178 |
| v18_adaptive | 1000 | 75.3 mm | 40 mm | 11.3 mm | 56 mm | 29 px | 0.184 |
| v18_adaptive | 2000 | 76.2 mm | 40 mm | 11.3 mm | 56 mm | 28 px | 0.170 |
| v18_adaptive | 500 | 81 mm | 41 mm | 11.5 mm | 61 mm | 29 px | 0.172 |
| v17_cosine | 1500 | 78.3 mm | 40 mm | 11.3 mm | 59 mm | 28 px | 0.159 |
| v17_cosine | 1000 | 78.6 mm | 41 mm | 11.4 mm | 59 mm | 30 px | 0.164 |
| v17_cosine | 500 | 82 mm | 40 mm | 11.3 mm | 63 mm | 30 px | 0.172 |
| v16_more_boost | 1000 | 78.9 mm | 41 mm | 11.5 mm | 60 mm | 31 px | 0.161 |
| v16_more_boost | 500 | 79 mm | 41 mm | 11 mm | 60 mm | 33 px | 0.18 |
| v15c_rot6d (null) | 500 | 79 mm | 40 mm | 11 mm | 60 mm | 32 px | 0.18 |
| v15d_rebalance | 1000 | 80.5 mm | 41 mm | 11.5 mm | 61 mm | 32 px | 0.19 |
| v15d_rebalance | 1500 | 80.7 mm | 41 mm | 11 mm | 62 mm | 31 px | 0.18 |
| v15d_rebalance | 500 | 82 mm | 40 mm | 12 mm | 62 mm | 33 px | 0.19 |
| v15a_multires (v13 head) | 1000 | 83 mm | 42 mm | 12 mm | 64 mm | 36 px | 0.17 |
| v15a_multires (v13 head) | 3000 | 86 mm | 42 mm | 12 mm | 64 mm | 31 px | 0.18 |
| v13_stable (FINAL) | 3000 | 90 mm | 45 mm | 13 mm | 67 mm | 35 px | 0.21 |
| v13_stable | 2500 | 91 mm | 46 mm | 13 mm | 69 mm | 36 px | 0.25 |
| v13_stable | 2000 | 94 mm | 45 mm | 13 mm | 73 mm | 39 px | 0.18 |
| v13_stable | 1500 | 91 mm | 46 mm | 14 mm | 69 mm | 37 px | 0.22 |
| v13_stable | 1000 | 101 mm | 48 mm | 13 mm | 79 mm | 42 px | 0.25 |
| v13_stable | 500 | 105 mm | 55 mm | 15 mm | 77 mm | 43 px | 0.24 |
| v12_gtmask (previous champ) | 3000 | 116 mm | 78 mm | 14 mm | 72 mm | 34 px | 0.27 |
| v12_gtmask | 2500 | 116 mm | 80 mm | 14 mm | 72 mm | 36 px | 0.28 |
| v12_gtmask | 1500 | 116 mm | 80 mm | 14 mm | 72 mm | 38 px | 0.29 |
| v12_gtmask | 2000 | 119 mm | 80 mm | 14 mm | 73 mm | 36 px | 0.27 |
| v12_gtmask | 1000 | 119 mm | 82 mm | 14 mm | 72 mm | 38 px | 0.31 |
| v12_gtmask | 500 | 122 mm | 82 mm | 14 mm | 75 mm | 41 px | 0.31 |
| v11_pushpix (previous) | 3000 | 149 mm | 87 mm | 14 mm | 103 mm | 93 px | 0.28 |
| v11_pushpix (best wrist) | 2000 | 149 mm | 89 mm | 14 mm | 100 mm | 94 px | 0.31 |
| v11_pushpix | 2500 | 152 mm | 89 mm | 14 mm | 107 mm | 96 px | 0.30 |
| v11_pushpix | 1500 | 164 mm | 88 mm | 14 mm | 129 mm | 98 px | 0.31 |
| v11_pushpix | 1000 | 157 mm | 90 mm | 14 mm | 108 mm | 99 px | 0.33 |
| v11_pushpix | 500 | 154 mm | 87 mm | 14 mm | 115 mm | 103 px | 0.30 |
| v10_scale (FINAL) 🏁 | 3000 | 159 mm | 89 mm | 15 mm | 121 mm | 105 px | 0.24 |
| v10_scale | 2500 | 159 | 91 | 15 | 123 | 106 | 0.32 |
| v10_scale | 2000 | 160 | 93 | 15 | 117 | 107 | 0.37 |
| v10_scale | 1500 | 183 | 96 | 15 | 149 | 110 | 0.45 |
| v10_scale | 1000 | 165 | 96 | 15 | 131 | 115 | 0.42 |
| v10_scale | 500 | 189 | 87 | 15 | 162 | 120 | 0.60 |
| v8d step 3000 (baseline) | 3000 | 211 | 102 | 13 | 110 | — | — |
| v9b step 200 (baseline) | 200 | 222 | 92 | 13 | 130 | 327 | — |
| v9a step 200 (baseline) | 200 | 226 | 94 | 14 | 132 | 335 | — |
| oracle Iter 206 (GT-2D + s*) | oracle | 54 | — | — | — | 0 | — |
| oracle Iter 204 (GT-orient + GT-trans) | oracle | 17 | — | 13 | — | — | — |
| PA-MPJPE floor (shape only) | oracle | — | — | 13 | — | — | — |
Sorted with best model (lowest absolute MPJPE) at top of each group.
What's in this repo
EgoWM/
├── egowm/ — Wan-DiT trunk + MANO + heads (production ~2400 LoC)
├── data_engine/ — trainers, evals, viz, manifests
├── benchmark/ — long-term leaderboard (LVP-style)
│ ├── protocols/ — metrics + protocol registry
│ ├── results/ — one JSON per (model, protocol) run
│ ├── scripts/ — leaderboard, gallery, arc builders
│ └── gallery/ — rendered videos + posters
├── report/ — public deployable (this folder)
│ ├── README.md — the page you are reading
│ ├── iters/*.md — per-iteration reports
│ ├── gallery/ — same assets as benchmark/gallery/
│ ├── build.py — markdown → HTML
│ └── *.html — pre-built for Cloudflare Workers
└── docs/ — internal engineering log (private, not deployed)
How to add a model to the leaderboard
- Train your model somewhere (preserving the head interface — see
egowm/models/anddata_engine/train_egowm_*.py). - Run the shared eval:
bash python data_engine/eval_v10_scale.py \ --ckpt path/to/your.pt \ --n-clips 40 --source-filter arctic \ --out benchmark/results/your_model.arctic-lite.json - Tag with
model,step,protocolfields in the JSON. - Rebuild:
bash python benchmark/scripts/leaderboard.py # leaderboard python benchmark/scripts/build_gallery.py --ckpt path/to/your.pt \ --model-name "Your Model" # gallery python benchmark/scripts/build_training_arc.py # training arc - Commit
benchmark/results/*.json,benchmark/gallery/*, and the built HTML.
Contributor
Reports and code authored during 2026-06-25 → 2026-07-10 by Haoran Geng (@geng-haoran) with Claude Opus 4.7 (1M context) as pair-programmer.