7.12. Post-Prozessoren

Ein Erkennungsnetz gibt keine Rahmen aus. Es gibt einen oder mehrere Tensoren aus, deren Layout von der Architektur abhängt, gegen die das Modell trainiert wurde – ein 2-D-Tensor von Kandidatenvorhersagen für einen Detektor der YOLO-Familie, ein Paar von (boxes, scores)-Tensoren für einen MediaPipe-Detektor, eine flache Liste von Schlüsselpunktkoordinaten für ein Pose-Netz. Die Anwendung kann keinen davon direkt lesen; was sie möchte – eine Liste von Rahmen, eine Liste von Schlüsselpunkten, eine Aufschlüsselung pro Klasse –, muss aus dem rohen Tensor dekodiert werden.

Dieser Dekoder ist ein Post-Prozessor. Das Modul ml.postprocessing gruppiert sie nach ihrem Quell-Ökosystem.

7.12.1. Darknet

ml.postprocessing.darknet dekodiert Modelle aus der ursprünglichen YOLO-Ära. YOLO v2 führte die Grid- und Anker-Ideen ein, die die meisten späteren Detektoren in irgendeiner Form übernommen haben, sodass das v2-Layout der sauberste Ausgangspunkt ist.

YOLO v2 beginnt damit, das Eingabebild in ein grobes Gitter zu unterteilen – ein 13-mal-13-Layout für die kanonische 416-Pixel-Eingabe, kleiner für kleinere Modelle – und trainiert das Netz so, dass jede Gitterzelle für die Erkennung jedes Objekts zuständig ist, dessen Mittelpunkt in sie fällt. Das räumliche Layout des Ausgabetensors spiegelt das Layout der Eingabe wider: eine Position in der Ausgabe pro Zelle im Bild.

An jeder Gitterzelle sagt das Netz keinen Rahmen aus dem Nichts vorher. Es wählt aus mehreren vorab gewählten Referenzformen, die Anker genannt werden – feste (width, height)-Paare, die offline durch Clustern der Rahmengrößen im Trainingsdatensatz abgeleitet werden, sodass sie die typischen Objekte abdecken, die das Modell voraussichtlich sehen wird. Die Aufgabe des Netzes an jeder Zelle besteht darin, für jeden Anker einen kleinen Versatz zum Rahmenmittelpunkt innerhalb der Zelle, eine Skalierung der Breite und Höhe des Ankers, einen Objectness-Score (die Wahrscheinlichkeit, dass überhaupt etwas vorhanden ist) und einen Wahrscheinlichkeitsvektor pro Klasse vorherzusagen. Ein 13-mal-13-Gitter mit den standardmäßigen 5 Ankern und 20 Klassen gibt daher 13 * 13 * 5 * (4 + 1 + 20) = 21,125 Zahlen pro Inferenz aus.

YoloV2 dekodiert dieses Layout: Es durchläuft die Zellen, wendet die Versätze und Skalierungen jedes Ankers an, um absolute Rahmenkoordinaten wiederherzustellen, kombiniert Objectness mit Klassenwahrscheinlichkeit zu einem Score pro Klasse, wendet den Schwellenwert an und reicht die Überlebenden an NMS weiter. Die Klasse nimmt ein Konstruktorargument anchors= entgegen, wenn das Modell gegen eine benutzerdefinierte Ankertabelle trainiert wurde, und greift andernfalls auf einen eingebauten Standard zurück. Auf bestimmte Klassensätze abgestimmte Varianten werden im selben Untermodul mitgeliefert.

7.12.2. Ultralytics

ml.postprocessing.ultralytics dekodiert die neueren YOLO-Generationen. YoloV8 liest eine spaltenweise Ausgabe, bei der jede Spalte eine Ankervorhersage ist, die Rahmenkoordinaten und einen Score-Vektor pro Klasse enthält – der Objectness-Kanal, den frühere YOLO-Ausgaben mitführten, wurde in v8 weggelassen, und die Klassen-Scores stehen für sich. Die YOLOv8-Durchführung geht den Dekodiervorgang Tensor für Tensor durch. Ältere Versionen aus der Ultralytics-Ära werden im selben Untermodul für Modelle mitgeliefert, die gegen ihre Layouts trainiert wurden.

7.12.3. MediaPipe

ml.postprocessing.mediapipe dekodiert Googles leichtgewichtige On-Device-Familie. BlazeFace ist der in hello-blazeface behandelte Gesichtsdetektor: ein schneller ankerbasierter Detektor, der pro Gesicht Rahmen und sechs Landmarkenkoordinaten ausgibt, zurückgegeben als (box, score, keypoints)-Tupel, wobei die Landmarken an jeden Rahmen angehängt sind statt als separate Ausgabeliste. Modelle für Handerkennung, Landmarken und Pose aus derselben Familie werden daneben mitgeliefert und folgen derselben Rückgabeform mit angehängten Schlüsselpunkten.

7.12.4. Den richtigen auswählen

Der richtige Post-Prozessor wird durch die Architektur bestimmt, gegen die das Modell trainiert wurde, nicht durch das, was die Anwendung möchte. Eine YOLOv8-.tflite dekodiert nur über YoloV8 korrekt; eine BlazeFace-.tflite nur über BlazeFace. Die Auswahl des Post-Prozessors ist Teil der Auswahl des Modells. Wenn die Architektur eines Modells nicht durch einen mitgelieferten Post-Prozessor repräsentiert wird, ist es unkompliziert, einen eigenen zu schreiben.

Klassifizierungsnetze sind die Ausnahme. Ihr einzelner Ausgabetensor ist bereits das, was die Anwendung möchte – eine Liste von Scores pro Klasse –, und es wird kein Post-Prozessor benötigt. Das Modell ohne postprocess= zu laden und das Predict-Ergebnis als flaches ndarray zu lesen, ist der richtige Weg, wie Tensor-I/O beschrieben hat.