7.12. Post-traitements

Un réseau de détection n’émet pas de boîtes. Il émet un ou plusieurs tenseurs dont la disposition dépend de l’architecture contre laquelle le modèle a été entraîné – un tenseur 2-D de prédictions candidates pour un détecteur de la famille YOLO, une paire de tenseurs (boxes, scores) pour un détecteur MediaPipe, une liste plate de coordonnées de points clés pour un réseau de pose. L’application ne peut lire aucun de ceux-ci directement ; ce qu’elle veut – une liste de boîtes, une liste de points clés, une ventilation par classe – doit être décodé à partir du tenseur brut.

Ce décodeur est un post-traitement. Le module ml.postprocessing les regroupe par écosystème d’origine.

7.12.1. Darknet

ml.postprocessing.darknet décode les modèles de l’ère YOLO d’origine. YOLO v2 a introduit les notions de grille et d”ancre que la plupart des détecteurs ultérieurs ont héritées sous une forme ou une autre, donc la disposition de la v2 est le point de départ le plus clair.

YOLO v2 commence par diviser l’image d’entrée en une grille grossière – une disposition 13 par 13 pour l’entrée canonique de 416 pixels, plus petite pour les modèles plus petits – et entraîne le réseau de sorte que chaque cellule de la grille soit responsable de la détection de tout objet dont le centre tombe en son sein. La disposition spatiale du tenseur de sortie reflète la disposition de l’entrée : une position en sortie par cellule dans l’image.

À chaque cellule de la grille, le réseau ne prédit pas une boîte à partir de rien. Il choisit parmi plusieurs formes de référence présélectionnées appelées ancres – des paires (width, height) fixes dérivées hors ligne par regroupement des tailles de boîtes dans le jeu de données d’entraînement de sorte qu’elles couvrent les objets typiques que le modèle est censé voir. La tâche du réseau à chaque cellule est de prédire, pour chaque ancre, un petit décalage du centre de la boîte dans la cellule, une mise à l’échelle de la largeur et de la hauteur de l’ancre, un score d”objectness (la probabilité que quelque chose s’y trouve), et un vecteur de probabilité par classe. Une grille 13 par 13 avec les 5 ancres par défaut et 20 classes émet donc 13 * 13 * 5 * (4 + 1 + 20) = 21,125 nombres par inférence.

YoloV2 décode cette disposition : il parcourt les cellules, applique les décalages et les mises à l’échelle de chaque ancre pour récupérer les coordonnées absolues des boîtes, combine l’objectness avec la probabilité de classe pour un score par classe, applique le seuil, et pousse les survivantes vers la NMS. La classe prend un argument de constructeur anchors= lorsque le modèle a été entraîné avec une table d’ancres personnalisée et se rabat sinon sur une valeur par défaut intégrée. Des variantes ajustées pour des ensembles de classes spécifiques sont fournies dans le même sous-module.

7.12.2. Ultralytics

ml.postprocessing.ultralytics décode les générations YOLO plus récentes. YoloV8 lit une sortie en ordre colonne où chaque colonne est une prédiction d’ancre contenant les coordonnées de la boîte et un vecteur de score par classe – le canal d’objectness que portaient les sorties YOLO antérieures a été supprimé dans la v8, et les scores de classe sont autonomes. La présentation détaillée de YOLOv8 parcourt le décodage tenseur par tenseur. Les versions plus anciennes de l’ère Ultralytics sont fournies dans le même sous-module pour les modèles entraînés avec leurs dispositions.

7.12.3. MediaPipe

ml.postprocessing.mediapipe décode la famille légère sur appareil de Google. BlazeFace est le détecteur de visages présenté dans hello-blazeface : un détecteur rapide basé sur des ancres qui émet des boîtes et six coordonnées de repère par visage, retournées sous forme de tuples (box, score, keypoints) avec les repères attachés à chaque boîte plutôt que comme une liste de sortie séparée. Les modèles de détection de main, de repères et de pose de la même famille sont fournis aux côtés de celui-ci et suivent la même forme de retour à points clés attachés.

7.12.4. En choisir un

Le bon post-traitement est déterminé par l’architecture contre laquelle le modèle a été entraîné, et non par ce que l’application veut. Un .tflite YOLOv8 ne se décode correctement qu’à travers YoloV8 ; un .tflite BlazeFace seulement à travers BlazeFace. Choisir le post-traitement fait partie du choix du modèle. Lorsque l’architecture d’un modèle n’est représentée par aucun post-traitement fourni, écrire le vôtre est simple.

Les réseaux de classification font exception. Leur unique tenseur de sortie est déjà ce que l’application veut – une liste de scores par classe – et aucun post-traitement n’est nécessaire. Charger le modèle sans postprocess= et lire le résultat de la prédiction comme un ndarray plat est la bonne voie, comme l’a présenté l’E/S de tenseurs.