Why this page exists: this codebase was scaffolded against a
published spec, not real model weights, and several of those
assumptions turned out to be wrong. Every fix documented here was found
by actually running something — inspecting real ONNX graphs, running
real photos through the real pipeline, building the real Docker image,
and load-testing the real server — not by code review alone.
Final results (current state)
Everything below reflects the service after every fix in this document was applied — this is where the numbers landed, not a before/after comparison. The rest of the page is the journey that got here; this section is the destination.Accuracy
Production embedder (arcface_w600k_r50.onnx, InsightFace buffalo_l),
full production pipeline, 45 pairwise comparisons across 10 test photos:
Clean bimodal separation, zero ambiguous pairs — every same-person pair
scored above every cross-identity pair. Full data in
§3c.
Correctness under concurrency
Full data in §6.
Throughput & latency (native, 10-core Apple Silicon, CPU-only)
Peak sustained throughput: ~1,944 RPM at concurrency≈16, scaling
cleanly up to that point, then degrading gracefully (not erroring) beyond
the 10-core ceiling. Extrapolated per-vCPU estimates for cloud sizing are
in Models → Expected throughput — flagged
there as extrapolation, not a measurement on real cloud hardware.
Docker parity
Confirms the containerized build is numerically equivalent to native
(differences are float/compiler noise, not a regression) and, separately,
that it runs standalone with the models baked in and zero volume mounts
(see Deployment → Baking in models).
Build health
1. Model I/O verification
Goal: confirm the embedder’s actual tensor contract before trusting any code that depends on it. Method: loadedarcface_w600k_r50.onnx with the onnx and
onnxruntime Python packages and printed the real input/output names,
shapes, and dtypes directly from the graph.
No mismatches. See Models → Embedder
for the full contract table.
2. Local build (Phase 2)
Built from source on macOS (arm64): Homebrewcmake/opencv@5.0.0/jsoncpp,
Drogon v1.9.7 from source, ONNX Runtime 1.19.2 (prebuilt release).
One real compile bug found: FaceAligner.cpp failed with
no member named 'estimateAffinePartial2D' in namespace 'cv' — OpenCV 5
moved that function (and boundingRect) into a new geometry module that
its own umbrella opencv2/opencv.hpp doesn’t include by default, even
though the module is built. Fixed with a version-gated include
(#if CV_VERSION_MAJOR >= 5) so both OpenCV 4 (Docker) and OpenCV 5
(Homebrew) compile correctly. See
Architecture → FaceAligner.
Result: clean build, binary linked against all expected libraries
(OpenCV 5.0.0, Drogon, ONNX Runtime, OpenSSL, jsoncpp).
3. Embedder validation — three models tested, two discarded
Method: a Python harness (scripts/run_similarity_test.py) mirroring
the production pipeline exactly — detect → align (ArcFace 5-point
template) → normalize → embed → L2-normalize → cosine similarity — run
against a manual test set of 11 personal photos (10 usable; 1 failed
detection), producing all 45 pairwise comparisons per model.
3a. VirtuoTuring (original embedder) — discarded
- Summary
- Full pairwise table
Same-person pairs scored lower on average than cross-identity
pairs. No threshold separates anything in this distribution.
3b. ONNX Model Zoo arcfaceresnet100-8.onnx — discarded
First replacement candidate, from the official high-trust onnx/models
GitHub org — but an old export (opset 8, ~2019).
- Summary
- Degenerate-input sanity check
Even more compressed than VirtuoTuring — worse separation, not
better.
3c. InsightFace buffalo_l / w600k_r50 — adopted
Actively-maintained, MIT-licensed, opset 11. Passed the same sanity check
cleanly before being trusted:
- Summary
- Full pairwise table
Clean bimodal separation — this is what a working embedder looks like.
COMPARE_THRESHOLD (default
0.4) sits in the gap between the 0.52–0.67 same-person cluster and the
0.01–0.32 cross-identity cluster with margin on both sides.
4. Detection bug — full-resolution phone photos
How it was found: aligned crops from the initial VirtuoTuring test looked visually wrong (badly off-center, wrong zoom level) before the embedder was even implicated. Drawing the raw detector bbox/landmarks directly onto the pixel grid OpenCV actually sees (not a viewer-rendered preview, which can apply its own EXIF-rotation handling) isolated the cause to detection, not alignment. Root cause: YuNet’s accuracy degrades badly on raw phone-camera resolutions. At the productiondetectorScoreThreshold=0.8:
Fix:
detectFaces() now detects on a 640px-longest-side copy and maps
bbox/landmarks back to full-resolution coordinates. See
Architecture → InferenceEngine.
5. Docker build — three real bugs found by actually running the image
Building the image and confirming it compiles was not sufficient — it took running the container to surface all three of these.1
Silently-broken apt-get install
Runtime stage listed
libjsoncpp26 and libssl3 — neither exists on
Ubuntu 24.04 (real names: libjsoncpp25, libssl3t64). A ||
fallback masked the failure, so the entire package install silently
no-opped — including the correctly-named OpenCV packages. Container
built “successfully” with zero OpenCV libraries, crashed on start:
error while loading shared libraries: libopencv_imgcodecs.so.406: cannot open shared object file. Fixed the names and removed the
fallback.2
OpenCV too old for the detector model
Ubuntu 24.04’s apt OpenCV is 4.6.0; YuNet’s
2023mar model requires
≥4.8.0 — fails at runtime, not build time, with Layer with requested id=-1 not found. Switched the builder stage to compile
OpenCV 4.10.0 from source. See Deployment → Why OpenCV is built from
source for the full
writeup.3
Missing .dockerignore
Build context was uploading
models/, third_party/, build/, and
personal test photos on every docker build. Added .dockerignore.Docker vs. native correctness check
Ran the same same-person/cross-identity/v1/compare cases against the
containerized service over real HTTP after all three fixes:
Differences are consistent with float/compiler noise across platforms, not
a correctness regression.
6. Concurrency / load test — the most serious bug found
Context: asked to estimate expected RPM. Sequential single-client latency (~300ms p50) doesn’t answer that — a real concurrent load test was required, and it immediately surfaced a correctness bug, not just a capacity ceiling. Method: a Python harness firing concurrentPOST /v1/embed requests
at increasing concurrency (1→32 threads), 12 seconds sustained per level,
against the native macOS build (10 cores).
- Before fix
- After fix
Throughput collapsed under load instead of plateauing — a
correctness bug, not a capacity limit.
cv::FaceDetectorYN was shared as a single instance
across all worker threads, and detectFaces() calls setInputSize()
(mutates object state) immediately before detect() — concurrent requests
raced on that shared state. The tell in the server logs:
cv::FaceDetectorYN instance
(thread_local in threadLocalDetector()). Ort::Session (the embedder)
was left shared — Run() is genuinely documented thread-safe, unlike
FaceDetectorYN. Verified by rerunning the identical load test (table
above) and by rebuilding + smoke-testing the Docker image against the fix.
See Models → Concurrency for the extrapolated
RPM-per-vCPU estimates built on this data, and
Architecture → InferenceEngine for the
code-level explanation.
Summary: bugs found, by how they were caught
The pattern across all six: the bug was invisible until the specific
condition that triggers it was actually exercised. This is the reasoning
behind every “verify, don’t assume” note elsewhere in these docs.