Gesichtserkennung in einem Familienarchiv klingt nach einem gelösten Problem, bis man sich erinnert, dass sich die Gesichter in diesem Archiv verändern. Ein Neugeborenes und das zehnjährige Kind, das daraus wird, sehen für einen Menschen nicht nur anders aus — ihre Gesichts-Embeddings, die numerischen Vektoren, die ein Erkennungsmodell erzeugt, driften weit genug voneinander weg, dass eine einzelne Ähnlichkeitsschwelle nicht beide Enden dieser Reise gleichzeitig halten kann. Lässt man einen einzigen globalen Clustering-Durchlauf über das gesamte Archiv laufen, mit einer Schwelle locker genug, um ein Neugeborenes und ein Zehnjähriges als dieselbe Person zu erfassen, fängt sie auch verschiedene Personen. Zieht man sie eng genug an, um Fremde auseinanderzuhalten, wird jedes Kind, während es älter wird, in mehrere „Personen" aufgespalten.
Das ist das Kernproblem, um das es in diesem Beitrag geht: nicht „wie erkennt man ein Gesicht", was mit ausgereiften Modellen ein größtenteils gelöstes Problem ist, sondern „wie verfolgt man Identität durch die Art von Veränderung, die ein Gesicht über zwei Jahrzehnte Kindheit durchläuft", was ein völlig anderes Problem ist und viel weniger darüber geschrieben wurde.
Erst Fenster, dann verketten
Der Ansatz, der funktionierte, ist, aufzuhören, einen einzigen Clustering-Durchlauf zu bitten, zwanzig Jahre zu überspannen, und statt dessen viele kleine, einfache Clustering-Durchläufe zu bitten, jeweils ein halbes Jahr zu überspannen, und die Ergebnisse dann zu verketten.
Schritt eins: gieriges Clustering innerhalb von Halbjahresfenstern, bei einer strengen Ähnlichkeitsschwelle von 0,50 Cosinus. Innerhalb eines Sechsmonatsfensters ist die Altersdrift wirklich klein — ein Kind verändert seine Gesichtsstruktur in sechs Monaten nicht genug, um einen gut kalibrierten Clustering-Durchlauf zu gefährden, sodass eine strenge Schwelle sich strenge Werte leisten kann und dabei verlässlich bleibt.
Schritt zwei ist der eigentliche Trick. Nimm die Cluster aus jedem Halbjahresfenster und verkette sie über bis zu vier benachbarte Fenster, bei einer viel lockereren Schwelle von 0,42 Cosinus, wobei Union-Find genutzt wird, um Ketten transitiv zusammenzuführen. Die Logik: Altersdrift, die eine direkte Übereinstimmung über ein Jahrzehnt hinweg brechen würde, ist klein genug, um über einen einzelnen Halbjahr-zu-Halbjahr-Sprung überbrückt zu werden. Statt jemals einen einzigen Ähnlichkeitsvergleich zu benötigen, der „Neugeborenes bis Alter zehn" überspannt, braucht das System nur eine Kette kurzer Sprünge, jeder für sich einfach, die sich zufällig zur langen Distanz aufsummieren. Union-Find ist hier die richtige Struktur, weil Identität transitiv ist — wenn der Cluster von Fenster A mit dem von Fenster B verknüpft ist und B's mit C's, sollten A und C in derselben Gruppe landen, obwohl sie nie direkt verglichen wurden.
Die Kette bei vier benachbarten Fenstern zu kappen (zwei Jahre, bei der Größe des Halbjahresfensters) ist eine bewusste Grenze, kein Versehen. Lässt man die lockere 0,42-Schwelle unbegrenzt verketten, summieren sich Fehler auf: eine leicht zu großzügige Zusammenführung zwei Sprünge tief wird zur Grundlage für eine leicht zu großzügige Zusammenführung vier Sprünge tief, und irgendwann teilen sich zwei verschiedene Kinder eine Identität, weil die Kette den ganzen Weg dorthin einen weichen Merge nach dem anderen abgedriftet ist. Die Spannweite zu kappen hält den Worst-Case-Fehler jeder Kette begrenzt.
Müllcluster sind schlimmer als weniger Cluster
Die Verkettung erzeugt Kandidaten-Personen-Cluster, und nicht alle davon sind es wert, jemandem gezeigt zu werden. Ein Reinheits-Filter läuft nach der Verkettung und verwirft Cluster, die nicht intern konsistent genug aussehen, um vertrauenswürdig zu sein, und er ist aggressiv: Im Gründungsarchiv hat das die aufgeführten Cluster von 545 auf 281 reduziert. Das ist kein kleiner Feinschnitt, das verwirft mehr als die Hälfte der Rohausgabe. Die Alternative — jemandem 545 Kandidaten-„Personen" zu zeigen, von denen ein Drittel tatsächlich Fragmente oder Fehl-Zusammenführungen sind — ist schlechter, als ihnen weniger, sauberere zu zeigen. Niemand will nach einem Clustering-Algorithmus aufräumen; sie wollen eine Kurzliste, die größtenteils schon richtig ist.
Korrekturen müssen ein erneutes Clustering überleben
Nichts davon ist ein einmaliger Vorgang. Das Clustering läuft erneut, während ein Archiv wächst oder sich ein Modell verbessert, und jedes Mal wäre es unannehmbar, die menschlichen Korrekturen zu verlieren, die schon jemand vorgenommen hat — einen Cluster umbenennen, zwei zusammenführen, die tatsächlich dieselbe Person waren, einen aufteilen, der es nicht war. Also wird jede Korrektur in eine dauerhafte Override-Tabelle geschrieben, nach Namen indiziert, getrennt von der Clustering-Ausgabe selbst, und nach jedem erneuten Clustering wieder angewendet. Der Clustering-Algorithmus schlägt vor; die Override-Tabelle hat das letzte Wort. Das ist dasselbe Prinzip wie Versionskontrolle für automatisch generierten Code: Nie zulassen, dass die regenerierbare Ausgabe den Teil, den ein Mensch von Hand bearbeitet hat, still überschreibt.
Die ehrliche Grenze: Geschwister
Das Nützlichste, was ich über dieses System sagen kann, ist, wo es nicht versucht, clever zu sein. Geschwister messen in diesem Archiv etwa 0,33 Cosinus-Ähnlichkeit zueinander — näher als zwei zufällige Fremde, aber deutlich unter den 0,50- oder 0,42-Schwellen, die das Clustering tatsächlich verwendet. Das ist nah genug, dass ein aggressiveres System sich selbst überreden könnte, sie zusammenzuführen, und weit genug, dass es dabei manchmal falsch läge. Statt bei dieser Grenze zu wetten, behandelt das System eine knapp verfehlte Ähnlichkeit als Signal zu fragen, nicht als Anweisung zu handeln: Fälle wie dieser tauchen als vorgeschlagene Zusammenführung auf, die ein Mensch bestätigen muss, nie als automatische. Eine falsche automatische Zusammenführung verfälscht still die Zeitleisten zweier Personen gleichzeitig; ein abgelehnter Vorschlag kostet nichts.