Files
scene-actor-extraction/docs/gallery-scope.md
T
dtourolle 4925443e56 docs: four focused findings pages (best model, gallery scope, expansion, deep dive)
Splits the rep4 write-up's key findings into their own linkable pages:
- best-model.md: calibration curves first (discriminative power, independent
  of any threshold), then F1 on the benchmark — LVFace-B Glint360K wins both.
- gallery-scope.md: whole vs. cast-restricted gallery, isolated from model and
  expansion choice — restriction wins on every axis, but isn't a shipped
  runtime feature yet.
- pose-expansion.md: the training-set expand_gallery effect, and the held-out
  replication attempt that found it doesn't reproduce (5 films, 2 models,
  after catching and fixing a replay-timeout truncation bug and a bbox
  first-match-instead-of-best-match bug in the comparison harness itself). An
  honest null result, with the methodology errors documented since they're
  exactly the kind that manufacture a false "it works!" finding.
- lvface-deep-dive.md: the winning model's held-out generalization gap, its
  two failure modes (frozen-bbox ghost tracks), and a verified case (cross-
  checked against Jellyfin's independent cast metadata) where LVFace
  correctly identified an actor that X-Ray's ground truth failed to credit.

Adds a "report-highlights" artifact-registry package (scripts/artifacts/
push_artifacts.sh, pull_artifacts.sh) for hand-picked illustrative frames that
aren't reproducible via the automated best/worst montage selection, and wires
pulling it into scripts/docs/build_site.sh.
2026-07-19 19:40:19 +02:00

57 lines
2.8 KiB
Markdown

# Whole gallery vs. limited (cast-restricted) gallery
Two ways to run the matcher: **full** scores every detected face against the
entire library gallery (2418 actors across the 9-film benchmark set); **restricted**
pre-filters each film's gallery down to just its Jellyfin-credited cast (typically
~15 top-billed actors) before the matcher ever runs.
## The result
Averaged across all 4 models and both expansion settings, on the 4 rep4 training
films:
| scope | F1 | P | R | total misID (8 evals) |
|---|---|---|---|---|
| full | 71.2% | 91.1% | 59.0% | 1073 |
| **restricted** | **74.5%** | 92.2% | **62.9%** | **329** |
This is not a precision/recall trade — restriction wins on every axis at once:
**+3.3pp F1, +3.9pp recall, and less than a third the total misIDs.** Fewer
candidates in the matcher's search space means fewer opportunities for a
look-alike false match (an actor who happens to share enough facial structure
with someone in the film, but isn't actually in it), and the recall gain shows
it isn't costing real detections to get there.
Per-model, every single model's best-scoring combo in the full 16-way matrix is
a `restricted` variant — see the full table in `rep4-optimizer-results.md`. Two
combos hit **zero** true out-of-cast misidentifications:
`arcface_w600k_mbf_restricted_exp` (F1 76.5%) and, in full mode,
`LVFace-B_Glint360K_full_noexp` (F1 72.4%) — restriction isn't the only way to
reach misid=0, but it's the more reliable one.
## Why this isn't the shipped default
Cast-restriction is implemented today only as an **offline optimizer technique**
(`scripts/optimizer/cast_restrict.py`): it pre-builds a filtered gallery file
per film, using Jellyfin's own cast list, before the benchmark ever calls the
matcher. There's no runtime "restrict matching to this title's credited cast"
switch in the shipped application — `scene_analyze` always matches against
whatever single gallery file it's given.
Building that as a real feature would need, at minimum:
- A live Jellyfin cast lookup at analysis time (the title is already known —
`run_from_jellyfin.py` already does this same lookup for its own
`filter_gallery`-based restriction path, just not wired into `scene_analyze`
itself as a first-class option).
- A decision on the *fallback*: what happens to a real, uncredited cameo
(see the Germar Terrell Gardner case in the LVFace deep-dive) if the gallery
never includes them at all?
- Regenerating the restricted-gallery cache whenever the title's Jellyfin cast
list changes.
This is why the shipped `src/config.hpp` defaults use the `full`-mode winner
(`LVFace-B_Glint360K_full_exp`, F1 75.3% training / 67.4% held-out macro) rather
than the higher-scoring `restricted_exp` (78.3%) — the 78.3% number describes a
capability the app doesn't have yet, not what actually ships.