Answer M1: tract loads both face graphs once their dims are pinned

Neither InsightFace export parses as shipped -- SCRFD fails at its input
node, ArcFace at the first Conv -- which is the same wall dr-segment hit
on YOLO's dynamic export. Both load cleanly with the input dims frozen,
so the pure-Rust runtime holds for the face pipeline too.

tools/fix-face-model-shapes.sh does the freezing, and exists so the
artefact is reproducible rather than a binary someone once produced. It
takes two forms because the two graphs need different ones: ArcFace's
batch is a named dim_param, SCRFD's H and W are dynamic but unnamed.

Also notes YuNet loading with no intervention, which matters for the
licence question in faces.md 2.3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-26 19:51:02 +02:00
co-authored by Claude Opus 5
parent ec740115b6
commit 72410f39c6
9 changed files with 435 additions and 1 deletions
+28
View File
@@ -678,6 +678,34 @@ argument:
| **M9** | YuNet as a drop-in detector: M4 and M6, re-run | §2.3's question 3, and the model file is already on disk. If the answer is "close enough", half the licence problem disappears. Needs its own decode path — its outputs are not SCRFD's. |
| **M10** | Peak RSS during an indexing sweep | NFR-RES-2. Two loaded graphs plus a proxy plus a batch of crops, on a phone. |
### 12.1 M1 result — **PASS, conditionally** · 2026-08-26
Measured, not extrapolated. Both InsightFace graphs **fail to load in tract as shipped**, exactly as
§4.1 predicted and for the reason it gave:
```
scrfd_500m_bnkps.onnx Translating node #0 "input.1" Source ToTypedTranslator
arcface_w600k_mbf.onnx Failed analyse for node #139 "Conv_0" ConvHir
```
Both **load cleanly once their input dimensions are pinned** — SCRFD's unnamed H/W to 640, ArcFace's
`None` batch to 1 — by `tools/fix-face-model-shapes.sh`, which rewrites the declared dims and touches
no weights. The frozen SCRFD reports the layout §4.2 specifies, which is the second half of the
answer: nine outputs, three strides, last dims 1/4/10, and `12800 = 80 × 80 × 2` confirming two
anchors per location at stride 8.
Two things worth carrying forward:
**SCRFD's outputs were already static.** The export was made at 640 and only its input forgot to say
so, so pinning to 640 is not a choice this project is making — it is the shape the graph was always
going to run at. §12's "320 as a faster option" would need a different export, not a different flag.
**YuNet loads with no intervention at all**, at a fixed `[1, 3, 640, 640]`, with twelve outputs in
three strides — `cls`/`obj`/`bbox`/`kps`, which is a *different layout* from SCRFD's and confirms why
§4.2's load-time check has to look at shapes rather than count outputs. Combined with its permissive
licence (§2.3) that makes M9 more interesting than it looked: the permissive detector is also the one
with no shape-fixing step in front of it.
---
## 13. Order
+1 -1
View File
@@ -9,7 +9,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
| Metric | Value |
|---|---|
| Source files scanned | 227 |
| Source files scanned | 230 |
| TRACES tags found | 621 |
| Requirements defined | 177 |
| Requirements covered | 91 |