perf(data-only-viz): swap Multi-HMR to ViT-S 672

Multi-HMR ViT-S is the only S variant published (672x672 only).
Camera bench on M5 MPS: 3.8 fps median (228 ms/frame), no speedup
vs ViT-L — bottleneck is SMPL-X head, not DINOv2 backbone.
Heartbeat moved before no-detect early-return so FPS metric stays
meaningful with empty camera view.
This commit is contained in:
L'électron rare
2026-05-13 14:27:16 +02:00
parent 29ea203c67
commit 8e05bc5751
4 changed files with 38 additions and 29 deletions
+14 -7
View File
@@ -40,10 +40,10 @@ data_only_viz/.venv/bin/python -m data_only_viz.main \
## Architecture
```
webcam Mac (cv2 idx 0, 896x896)
webcam Mac (cv2 idx 0, 672x672)
|
v
Multi-HMR ViT-L (PyTorch MPS, ~317M params)
Multi-HMR ViT-S (PyTorch MPS, ~31.5M params)
|
v
humans = [{v3d (10475,3), j3d, transl, shape, expression, ...}, ...]
@@ -81,9 +81,16 @@ AVLiveBody Swift
## FPS attendu
- Multi-HMR ViT-L MPS : ~150-200 ms / frame = 5-7 fps
- ViT-B (`multiHMR_672_B.pt`) : ~80 ms = 12 fps si on accepte moins
de precision
- Multi-HMR ViT-S MPS mesure 2026-05-13 :
- bench headless (dummy 672x672, 20 iter) : 199 ms median = 5.0 fps
- bench camera live (30 s real capture) : 228 ms median = 3.8 fps
(overhead capture/pre/tensor ~30 ms)
- Pas de speedup significatif vs ViT-L : le bottleneck n'est PAS le
backbone DINOv2 sur MPS — probablement la tete SMPL-X (identique
entre variantes S/B/L) et l'absence de SDPA fused / xFormers sur MPS.
La piste "ViT-S pour gagner du FPS" est invalidee par mesure.
- Fallback ViT-L (`multiHMR_896_L.pt`) : ~150-200 ms = 5-7 fps si
precision insuffisante avec ViT-S
- TCP sender throttle a 12 fps cible
- RealityKit render : 60 fps Cocoa, interpole entre frames Multi-HMR
@@ -92,7 +99,7 @@ AVLiveBody Swift
```
~/.cache/av-live-multihmr/
├── checkpoints/
│ └── multiHMR_896_L.pt (1.28 GB)
│ └── multiHMR_672_S.pt (124 MB)
├── models/
│ ├── smplx/
│ │ ├── SMPLX_NEUTRAL.npz (108 MB)
@@ -109,7 +116,7 @@ AVLiveBody Swift
| Symptome | Verification |
|----------|--------------|
| Pas de mesh visible | `ls ~/.cache/av-live-multihmr/checkpoints/multiHMR_896_L.pt` |
| Pas de mesh visible | `ls ~/.cache/av-live-multihmr/checkpoints/multiHMR_672_S.pt` |
| `Multi-HMR load failed` | `~/.cache/av-live-multihmr/models/smplx/SMPLX_NEUTRAL.npz` present ? |
| `TCP refused on :57130` | Lancer l'app Swift AVANT le worker Python |
| FPS trop bas | Switcher vers ViT-B en editant `CKPT` dans `multi_hmr_worker.py` |
+19 -17
View File
@@ -6,7 +6,7 @@ sys.path au runtime. Chaque humain renvoye contient deja les vertices
SMPL-X decodes (cle `v3d`, shape (10475, 3)) ; pas besoin du decoder
SMPL-X separe en hot path (il reste utile pour les tests).
Cadence cible : 8-12 fps sur M5 (ViT-L). Lissage One Euro sur les
Cadence cible : 8-12 fps sur M5 (ViT-S). Lissage One Euro sur les
shapes/expression pour limiter le jitter trame-a-trame.
"""
from __future__ import annotations
@@ -27,11 +27,11 @@ from .tracker import IoUTracker
LOG = logging.getLogger("multi_hmr")
CACHE = Path.home() / ".cache" / "av-live-multihmr"
CKPT = CACHE / "checkpoints" / "multiHMR_896_L.pt"
CKPT = CACHE / "checkpoints" / "multiHMR_672_S.pt"
SMPLX_PATH = CACHE / "models" / "smplx" / "SMPLX_NEUTRAL.npz"
MULTIHMR_REPO = CACHE / "multi-hmr"
IMG_SIZE = 896
IMG_SIZE = 672
N_VERTS = 10475
@@ -191,14 +191,28 @@ class MultiHMRWorker:
continue
t_post_start = time.monotonic()
t_now = time.monotonic()
# Count frame + heartbeat regardless of detection — keeps the
# FPS metric meaningful when nobody is in the camera view.
frame_count += 1
persons_count += len(humans) if humans else 0
if t_now >= next_heartbeat:
fps = frame_count / 5.0
avg = persons_count / max(1, frame_count)
LOG.info(
"hb: %.1f fps, %.2f persons/frame (%d frames)",
fps, avg, frame_count)
frame_count = 0
persons_count = 0
next_heartbeat = t_now + 5.0
if not humans:
with self.state.lock():
self.state.persons_smplx = []
inf_ms = (t_post_start - t_inf_start) * 1e3
LOG.debug("frame (no detect): inf=%.1fms", inf_ms)
time.sleep(self.period)
continue
t_now = time.monotonic()
# Tracking via bbox approximee depuis verts projetes (xy)
bboxes = []
n_keep = min(len(humans), self.num_persons)
@@ -263,18 +277,6 @@ class MultiHMRWorker:
dt_total,
)
frame_count += 1
persons_count += len(persons)
if t_now >= next_heartbeat:
fps = frame_count / 5.0
avg = persons_count / max(1, frame_count)
LOG.info(
"hb: %.1f fps, %.2f persons/frame (%d frames)",
fps, avg, frame_count)
frame_count = 0
persons_count = 0
next_heartbeat = t_now + 5.0
dt = time.monotonic() - t_cap_start
if dt < self.period:
time.sleep(self.period - dt)
+4 -4
View File
@@ -11,16 +11,16 @@ if [ ! -d "$CACHE/multi-hmr" ]; then
git clone --depth=1 https://github.com/naver/multi-hmr.git "$CACHE/multi-hmr"
fi
CKPT="$CACHE/checkpoints/multiHMR_896_L.pt"
CKPT="$CACHE/checkpoints/multiHMR_672_S.pt"
if [ ! -f "$CKPT" ]; then
echo "==> Telechargement checkpoint multiHMR_896_L (ViT-L)"
echo "==> Telechargement checkpoint multiHMR_672_S (ViT-S)"
# Source primaire : Naver Labs Europe ; fallback : HuggingFace mirror
if ! curl -fL --progress-bar \
"https://download.europe.naverlabs.com/ComputerVision/MultiHMR/multiHMR_896_L.pt" \
"https://download.europe.naverlabs.com/ComputerVision/MultiHMR/multiHMR_672_S.pt" \
-o "$CKPT"; then
echo "==> Fallback HuggingFace"
curl -fL --progress-bar \
"https://huggingface.co/naver/multiHMR_896_L/resolve/main/multiHMR_896_L.pt" \
"https://huggingface.co/naver/multiHMR_672_S/resolve/main/multiHMR_672_S.pt" \
-o "$CKPT"
fi
fi
@@ -1578,7 +1578,7 @@ RealityKit ARView : mesh skinné en couleur par pid
- Pas de mesh affiché : vérifier `~/.cache/av-live-multihmr/checkpoints/multiHMR_*.pt` existe
- Pas de SMPL-X : vérifier `~/.cache/av-live-multihmr/models/smplx/SMPLX_NEUTRAL.npz`
- TCP refused : l'app Swift doit tourner AVANT le worker Python
- FPS bas : passer à ViT-S (`multiHMR_896_S_*.pt`) qui est plus rapide
- Precision insuffisante : passer à ViT-L (`multiHMR_896_L.pt`) qui est plus précis (default est ViT-S depuis 2026-05-13)
```
- [ ] **Step 3: Commit final**