Freedam
IngénieriePartie 6 sur 7 · 19 min de lectureMis à jour le

Un visage n’est pas un nom

La plupart des erreurs de recherche dans un gestionnaire de médias numériques (digital asset manager) se corrigent facilement avec une autre requête. La reconnaissance faciale est différente, car un résultat erroné affirme aussi quelque chose sur une personne. Les articles précédents traitent de l’architecture de recherche, de la détection de quasi-doublons, des index multilingues et de la mesure de la recherche ; celui-ci se concentre sur les contraintes supplémentaires liées à l’identité.

Si une photothèque indique qu’une personne apparaît sur une photographie, elle peut aussi laisser entendre que cette personne se trouvait à un endroit, avec d’autres personnes, à une date donnée. La requête de distance cosinus est simple ; l’exigence plus difficile est de rendre les décisions d’identité auditables et d’expliquer les éléments qui fondent le seuil.

Cet article décrit le pipeline et la mesure qui fonde son seuil de similarité par défaut de 0,6, sur une photothèque de 22 944 médias. Sans la distribution de similarité sous-jacente, cette valeur serait une constante arbitraire.

Trois tâches, trois coûts d’erreur différents

Avant de choisir un modèle ou un seuil, nous séparons trois tâches qui demandent chacune une définition différente de l’exactitude.

Trois tâches de recherche de personnes et ce que chacune paie en cas d’erreur LA TÂCHE UNE FAUSSE CORRESPONDANCE COÛTE UN OUBLI COÛTE « Toutes les photos validées du PDG, pour la presse. » une équipe communication, pressée la mauvaise personne publiée sous le nom d’un autre une deuxième recherche « Le lot de chaque intervenant, parmi 4 000 images. » un photographe d’événement, qui livre quelques images à écarter une image que personne ne livre, et que personne ne remarque « Trouvez toutes les images où je figure. Je retire mon consentement. » un ancien salarié, ou son avocat la photo d’un autre détruite une image qui devrait être supprimée, encore dans la photothèque Seule la troisième tâche coûte cher dans les deux colonnes ; un système réglé pour les deux premières se trompe dans les deux cas.
Le même index, la même métrique de distance, trois définitions incompatibles d’un bon résultat. La dernière ligne est celle qui décide de l’architecture.

Les deux premières lignes sont des compromis de recherche qui peuvent utiliser des seuils différents. La troisième est une demande d’audit : quelqu’un doit savoir ce que la photothèque enregistre sur une personne et quelles parties ont été confirmées par un humain.

L’auditabilité façonne donc l’architecture autant que la précision.

Séparer la détection de la reconnaissance

On emploie souvent ces termes ensemble, mais ils décrivent des opérations différentes.

La détection répond à la question de savoir si une région contient un visage et où elle se trouve. Elle produit une boîte englobante (bounding box) et un score de confiance, sans attribuer d’identité.

La reconnaissance compare un visage détecté à des références connues et peut l’attribuer à une personne : une erreur est alors une affirmation d’identité incorrecte, et non une boîte englobante imprécise.

Les systèmes qui traitent ces deux opérations comme une seule étape de pipeline aboutissent à une architecture où la confiance de détection et la confiance d’identité sont le même nombre, et où il n’existe aucun point du flux où un humain puisse intervenir, faute de jonction à cet endroit. freedam conserve cette jonction. La détection est automatique et produit une géométrie anonyme. La reconnaissance est une étape distincte, menée contre un ensemble qu’une personne a constitué.

Le pipeline, avec la jonction entre géométrie anonyme et identité AUTOMATIQUE · SANS IDENTITÉ IDENTITÉ aperçu W_1024 pas l’original, fichier maître InsightFace buffalo_l, 640 x 640 sur votre propre matériel boîte + score + 512 nombres anonyme, et personnel un humain nomme quelqu’un seule étape qui fait d’un visage une personne une Person nommée avec un ensemble de référence les visages suivants sont comparés à cet ensemble Tout ce qui est à gauche de la boîte ambre se fait sans que personne décide quoi que ce soit de l’identité. Tout ce qui est à droite existe parce que quelqu’un a saisi un nom. La jonction est le produit : elle permet de répondre à « qui a décidé ça ? » par une personne et un horodatage plutôt que par une version de modèle.
La détection reste anonyme, et l’identité n’entre que lorsqu’une personne associe un visage détecté à un nom.

Le détecteur est un sidecar InsightFace auto-hébergé, qui exécute le pack de modèles buffalo_l avec une taille de détection de 640 par 640, sur CPU. Son endpoint /detect accepte les octets d’une image et renvoie des boîtes, des scores de détection et des embeddings ArcFace de dimension 512. Les images restent à l’intérieur du déploiement, ce qui est une propriété importante pour le traitement des photographies de salariés et de clients.

Le sidecar accepte jusqu’à 50 visages par image, tandis que l’application en conserve au plus 20. La détection s’exécute sur sa propre file avec un délai maximal de cinq minutes, trois tentatives et des délais d’attente de 10, 60 et 300 secondes. Un échec ne bloque pas le reste de l’ingestion : les médias restent donc disponibles même quand le traitement des visages se termine plus tard.

Choisir l’entrée du détecteur

Le rappel (recall) sur les visages dépend en partie de la version de l’image transmise au détecteur : cette entrée en amont mérite donc la même attention qu’une décision de texte au moment de l’indexation.

Le détecteur reçoit l’aperçu W_1024 plutôt que le fichier d’origine. Les originaux d’une photothèque professionnelle font souvent 40 ou 80 mégapixels : utiliser l’aperçu borne le coût de transfert et de traitement, et reste sous la limite d’import du sidecar.

Le coût probable est du rappel sur les petits visages. La distribution mesurée des tailles de visages détectés sur une photothèque est présentée ci-dessous.

Largeurs de visages détectés et scores de détection mesurés sur une photothèque de 22 944 médias LARGEUR DU VISAGE DÉTECTÉ, EN PIXELS DE L’APERÇU DE 1024 PIXELS 0 150 300 450 600 750 min. 9 10e perc. 115 médiane 247 moyenne 265 max. 708 CE QUI A ÉTÉ TROUVÉ 20 549 images dans la photothèque 741 contiennent un visage détecté (3,6 %) 774 visages au total : 708 images avec un, 33 avec deux SCORE DE DÉTECTION minimum 0,506 · moyenne 0,760 · maximum 0,909 aucun visage n’a été stocké sans embedding la plupart des images de cette photothèque ne contiennent aucune personne Le visage de 9 pixels est le cas intéressant. Aussi petit dans l’aperçu, il faisait peut-être 35 pixels dans l’original. Un visage deux fois plus petit est absent de ce tableau : rien en aval ne peut retrouver une personne jamais montrée au détecteur.
Mesuré sur une réplique d’une photothèque. Cette distribution ne couvre que les visages détectés : elle ne peut donc pas mesurer les visages perdus à cause de l’aperçu.

Nous n’avons pas pu mesurer directement le coût en rappel, car la réplique contient la base de données mais pas les fichiers d’origine. Une comparaison rigoureuse ferait passer les mêmes images en pleine définition et en W_1024 : cet article rapporte donc la distribution des tailles détectées, sans avancer de chiffre de rappel pour les visages que l’aperçu a pu faire perdre.

Réduire une image ne peut pas ajouter de détail visuel : le compromis favorise donc un traitement borné, au prix probable d’une perte de rappel sur certains petits visages, dont l’ampleur reste non mesurée.

L’embedding est un gabarit biométrique

Pour chaque visage détecté, le sidecar renvoie 512 nombres à virgule flottante, normalisés, issus de la tête de reconnaissance ArcFace. En base de données, cela devient une colonne vector(512) à côté de la boîte englobante, de la probabilité de détection et d’une similarité de reconnaissance nullable, avec un index HNSW sur la distance cosinus limité aux lignes qui ont réellement un embedding.

Ces 512 nombres sont un gabarit biométrique. Ils ne sont pas visualisables directement comme une image, mais ils peuvent identifier une personne et exigent des contrôles d’accès, une politique de rétention et un cycle de suppression adaptés aux données biométriques, et non ceux d’une colonne de cache générique.

Une vignette recadrée de 150 par 150 est stockée aussi, avec 20 % de marge autour de la boîte, une qualité JPEG de 85 et les métadonnées supprimées, de sorte qu’un relecteur puisse voir à quel visage une ligne se rapporte sans ouvrir l’original.

Sur la photothèque mesurée, la table faces, l’index HNSW et le stockage des vecteurs hors ligne occupent 3,3 Mo pour 774 visages, soit environ 4,3 Ko par visage. C’est peu comparé aux médias eux-mêmes, mais la sensibilité des données n’a aucun rapport avec leur taille de stockage.

Pourquoi nous ne regroupons pas les visages automatiquement

Les outils photo grand public regroupent souvent les embeddings par similarité, présentent chaque groupe comme une personne sans nom et demandent à l’utilisateur d’en fournir un. Nous avons choisi de ne pas faire du regroupement le point de départ, parce qu’il crée des groupes d’identité avant qu’une personne ait affirmé que le sujet doit exister dans la photothèque.

freedam ne le fait pas, et la raison est la troisième ligne de la figure 1.

Regrouper des inconnus ou comparer à un ensemble de référence posé par un humain REGROUPER D’ABORD, NOMMER ENSUITE Le système propose des identités de lui-même. Chaque personne de la photothèque devient une entité durable, nommée ou non, que quelqu’un se soit ou non interrogé sur elle. « Qui a décidé que c’est la même personne ? » n’a pour réponse qu’une version de modèle. AMORCER D’ABORD, COMPARER ENSUITE Les visages détectés restent non attribués. Une personne n’existe que parce que quelqu’un l’a créée et lui a associé un visage. La comparaison ne porte que sur des visages déjà attribués par un humain. « Qui a décidé ? » reçoit pour réponse un id utilisateur et un horodatage. Le modèle de droite est moins bon en démo et meilleur face aux questions. Il ne peut pas montrer un mur de tous les gens de votre photothèque, parce qu’il ne sait pas qui s’y trouve. C’est voulu : ici, une identité est affirmée par une personne, pas produite par un paramètre de clustering.
Les deux approches utilisent les mêmes embeddings et la même distance. Elles ne diffèrent que sur qui a le droit d’affirmer que deux visages sont la même personne.

Cette conception appelle une réserve importante.

La décision humaine a lieu une fois par personne, pas une fois par visage. Quelqu’un sélectionne un visage, lui donne un nom, et une Person est créée. À partir de ce moment, la personne a un ensemble de référence, et les visages détectés ensuite sont comparés à cet ensemble automatiquement : tout ce qui dépasse le seuil de similarité est attribué sans confirmation supplémentaire. Il existe aussi une correspondance en masse facultative au moment de l’attribution, qui rattache d’un seul coup à la nouvelle personne les visages non attribués existants.

Un humain ne confirme pas chaque visage. Un humain crée une personne à partir d’un visage confirmé, puis le système étend cette décision aux visages similaires automatiquement. Cela offre moins de garanties qu’une confirmation visage par visage, mais garde la première affirmation d’identité hors d’une étape de regroupement automatique.

Cela rend le seuil de similarité particulièrement important.

Mesurer le seuil de 0,6

Le seuil est un réglage du tenant, face_recognition.recognition_threshold, qui vaut 0,6 par défaut et est borné à l’intervalle de zéro à un. Les visages dont la similarité cosinus avec le visage de référence d’une personne est supérieure ou égale à ce seuil sont attribués à cette personne.

La valeur par défaut n’a de sens qu’avec la distribution qui la fonde. Nous avons donc comparé toutes les paires possibles parmi les 774 visages de la photothèque mesurée : 299 151 paires, sans échantillonnage.

Similarité cosinus sur les 299 151 paires de visages, avec deux modes séparés PART DES 299 151 PAIRES, PAR SIMILARITÉ COSINUS 0 2 % 4 % 6 % 8 % quatre barres tronquées à 8 % ; valeurs réelles 7,6 ; 23,3 ; 29,0 ; 16,6 % -0,2 0,0 0,2 0,4 0,6 0,8 1,0 0,167 paire la plus haute de visages d’une même photo 0,6 par défaut creux PAIRES À PARTIR DE 0,3031 295 0,3531 162 0,4030 814 0,5029 170 0,6023 691 0,7013 016 0,804 391 sur 299 151 Deux modes, presque rien entre les deux. Le mode de gauche : paires de personnes différentes, pic juste au-dessus de zéro. Le mode de droite : paires d’une même personne. Le creux entre les deux, vers 0,30, contient 133 paires : 0,04 %. Un seuil situé n’importe où dans ce creux se comporte pareil : le choix est sûr, pas chanceux.
Toutes les paires de 774 visages réels, de façon exhaustive, sans échantillonnage. Les quatre barres les plus hautes sont tronquées pour garder le mode de droite lisible ; leurs vrais pourcentages sont indiqués à côté.

Les similarités forment deux populations. Les paires interprétées comme des personnes différentes se regroupent juste au-dessus de zéro, avec une médiane de 0,029, tandis que les paires d’une même personne se regroupent autour de 0,65 à 0,70. Un creux près de 0,30 contient 0,04 % de toutes les paires.

Ces étiquettes restent une interprétation : nous avons donc cherché une source structurelle de non-correspondances connues.

Les paires de détections de visages distincts dans une même photographie fournissent des non-correspondances sans nécessiter de noms. Il y a 33 paires de ce type dans cette photothèque, allant de -0,021 à 0,167 avec une moyenne de 0,057 ; aucune n’atteint 0,35 ni ne s’approche du seuil de 0,6.

C’est un petit échantillon issu d’une seule photothèque et d’un seul style visuel, mais il apporte un appui indépendant à l’emplacement de la population de plus faible similarité.

Le même tableau contient aussi 1 647 paires dont la similarité cosinus est exactement de 1,0 entre médias différents, ce qui indique des photographies répétées. Cela offre un lien accessoire avec le travail sur les quasi-doublons et montre aussi que des médias répétés peuvent affecter les distributions de paires de visages.

Ce qui change quand le seuil bouge

La distribution nous permet aussi de mesurer si déplacer le seuil change l’accessibilité ou surtout le nombre d’attributions automatiques.

Abaisser le seuil change à peine l’accessibilité mais augmente fortement les liens tracés VISAGES AVEC AU MOINS UNE CORRESPONDANCE, SUR 774 PAIRES LIÉES 0,80 728 4 391 0,70 747 13 016 0,60 758 23 691 0,50 763 29 170 0,35 766 31 162 DE 0,60 À 0,35 8 visages de plus deviennent accessibles. Soit 1,0 % du corpus. LE MÊME CHANGEMENT trace 7 471 liens de plus entre visages. Soit 32 % d’affirmations en plus.
L’accessibilité sature presque immédiatement. Tout ce qui se trouve sous les premiers centièmes du réglage ne sert qu’à densifier le graphe, pas à permettre de retrouver quelqu’un.

À 0,6, 758 des 774 visages ont au moins une correspondance dans la photothèque. Abaisser le seuil à 0,35 porte ce nombre à 766, tandis que le nombre de paires acceptées comme étant la même personne passe de 23 691 à 31 162.

Sur ce corpus, le seuil modifie le volume d’affirmations bien plus que l’accessibilité. Au niveau du creux, la plupart des visages qui ont une autre correspondance sont déjà accessibles : abaisser la valeur crée donc surtout des attributions d’identité automatiques supplémentaires, et par conséquent davantage d’occasions de fausses correspondances.

La valeur par défaut de 0,6 se situe au-dessus du creux, sur le flanc montant de la population des paires d’une même personne. Par rapport à 0,35, elle renonce à huit visages accessibles tout en refusant 7 471 attributions de paires supplémentaires. Nous la traitons donc comme une limite sur les affirmations automatiques plutôt que comme un simple réglage du rappel.

Les seize visages sans correspondance à aucun seuil n’apparaissent qu’une seule fois : aucun réglage de similarité ne peut donc les relier à une autre référence. L’interface doit laisser une place à ces visages uniques plutôt que de laisser croire que tout visage détecté peut être identifié automatiquement.

Un ensemble de référence qui s’enrichit peut modifier des résultats antérieurs

Attribuer un visage à une personne agrandit l’ensemble de référence de cette personne, et un ensemble de référence plus grand peut faire correspondre des visages qui ne correspondaient à rien jusque-là. Un visage photographié de profil peut manquer l’unique référence de face à laquelle il était comparé, puis correspondre sans difficulté une fois qu’une photo de profil a été ajoutée. Après toute attribution, le système réévalue donc les visages non attribués dans le voisinage du visage nouvellement attribué, et une commande distincte compare chaque visage non attribué de la photothèque à chaque personne connue.

En conséquence, ajouter une référence peut modifier les correspondances d’images déjà présentes dans la photothèque, sans nouvel import ni nouvelle exécution de la détection. L’identité est représentée par un ensemble qui grandit plutôt que par une référence fixe.

Cela aide à retrouver des photographies plus anciennes quand une meilleure référence devient disponible, mais cela signifie aussi qu’une revue de protection des données doit tenir compte de la correspondance rétroactive. Un seuil prudent importe ici, car une nouvelle référence peut déclencher des attributions automatiques sur toute la photothèque existante.

Les noms de personnes utilisent le moteur de recherche habituel

Quand une personne a un nom, ce nom est écrit dans le document de recherche du média : le même document texte par langue que dans le premier article, construit par le même constructeur, indexé par le même index BM25 par langue, fusionné avec les mêmes scores vectoriels par la même fusion de rangs réciproques (reciprocal rank fusion). Les noms sont dédoublonnés sans tenir compte de la casse, et le champ porte un poids configurable comme tous les autres champs : une organisation qui juge les personnes plus importantes que les noms de fichiers peut donc le dire numériquement.

Les visages sans nom ne contribuent ni au document de recherche ni au dictionnaire : ils ne peuvent donc pas être retrouvés par une requête de nom. Cela est garanti par l’absence d’entrée d’index plutôt que par une exclusion au moment de la requête.

La conséquence est que rechercher le nom d’un collègue utilise la mécanique que toute cette série décrit, avec toutes ses propriétés : les garanties de rappel sous plafond, le compte rendu d’exhaustivité, la fusion multilingue, le panneau qui la mesure. Il n’y a pas de sous-système distinct de recherche de visages à analyser, pas de second modèle de pertinence, pas de classement parallèle à garder cohérent avec le premier.

La frontière est donc simple : la détection produit une géométrie anonyme, un humain introduit un nom, et le chemin de recherche textuelle existant retrouve ce nom confirmé.

Ce que nous dirions à quiconque construit cela

  • Séparez la détection de la reconnaissance dans l’architecture, pas seulement dans le vocabulaire. S’il n’y a pas de jonction entre la géométrie anonyme et l’identité affirmée, une décision humaine n’a nulle part où exister, et il est impossible de répondre à « qui a décidé ça ? ».
  • Concevez pour la demande de retrait, pas pour la démo. La tâche dont la réponse est coûteuse à la fois dans la colonne des fausses correspondances et dans celle des oublis est celle qui fixe votre architecture. Tout le reste est un seuil.
  • Publiez la distribution, ou ne publiez pas le seuil. Une valeur de similarité par défaut sans les distributions d’imposteurs et d’authentiques qui la fondent est une constante magique, et elle sera copiée dans le système de quelqu’un d’autre, où elle signifie autre chose.
  • Cherchez les étiquettes que vos données vous offrent gratuitement. Deux visages dans une même photographie sont deux personnes différentes. Ce seul fait structurel a produit un jeu de validation sans annotation, sans coût et sans aucune possibilité d’erreur d’étiquetage.
  • Vérifiez si votre seuil est un réglage du rappel. Le nôtre déplace l’accessibilité de 1 % et le volume d’affirmations de 32 % sur le même intervalle. Ce sont des produits différents, et le réglage ressemble au premier.
  • Sachez qu’un ensemble de référence rend l’identité rétroactive. Quand l’ajout d’un visage change ce que le système dit d’images importées il y a des années, c’est un comportement réel qui a un public réel, et ce doit être un choix documenté plutôt qu’une découverte.
  • Décidez tôt à quoi est rattaché le cycle de vie d’un gabarit. Donner aux données biométriques un cycle de vie indépendant, ou les lier à quelque chose que vous contrôlez déjà, sont deux choix défendables. Dériver vers l’un des deux sans avoir choisi ne l’est pas.
  • Dites ce que vous ne pouvez pas faire. Nous n’avons pas pu mesurer le coût d’une détection sur un aperçu réduit : cet article ne contient donc pas ce chiffre. Un article qui en aurait inventé un vaudrait moins qu’un article qui reconnaît le manque.

Où cela se trouve dans le produit

La détection de visages et la recherche de personnes s’exécutent dans le même déploiement que tout le reste : le sidecar InsightFace, l’instance PostgreSQL qui contient les vecteurs, les workers de files. Aucune image et aucun gabarit n’est envoyé à un service tiers, ce qui explique en grande partie pourquoi tout le système est praticable à auto-héberger, et ce qui distingue une fonctionnalité qu’une équipe juridique peut valider d’une autre qu’elle ne peut pas valider.

Une fois qu’une personne est nommée, elle est recherchable partout où la recherche s’applique : la galerie, l’API REST, le SDK TypeScript et tout agent IA connecté via MCP. Qui a le droit de lancer ces recherches est une question de contrôle d’accès et non une question de visages : la réponse vient du même modèle de permissions que celui qui régit tous les autres médias de la photothèque.

Tous les chiffres de cet article proviennent d’une seule photothèque, dont les 299 151 paires ont été comparées et non échantillonnées. Un autre mélange de photographie, d’éclairage et de cadrage peut produire une autre distribution et un autre seuil : la partie transposable est donc la méthode, qui consiste à calculer la distribution locale des paires et à utiliser des non-correspondances connues structurellement pour valider son interprétation.

Dans la suite de cette série : la recherche conversationnelle, où un modèle de langage est placé devant tout cela et chargé d’une seule tâche, qui n’a rien à voir avec le fait de regarder des images.

Pour les développeurs

À lire aussi