7.13. Non-Maximum-Suppression¶
Ein Erkennungsnetz erzeugt typischerweise mehrere überlappende Kandidatenrahmen um dasselbe reale Objekt: Jeder Anker in der Nähe des Objekts feuert mit einem ähnlichen Score, und der Post-Prozessor sieht sie alle. Die Non-Maximum-Suppression (NMS) ist der Schritt, der diese Ansammlung in einen einzigen Rahmen verwandelt.
Der Algorithmus ist kurz: Sortiere die Kandidatenrahmen nach Score, nimm den mit dem höchsten Score, unterdrücke jeden anderen Rahmen, der sich mit ihm über einen gewählten Schwellenwert hinaus überlappt, nimm dann aus dem Rest den nächsthöchsten und wiederhole das Ganze. Die Überlappungsmetrik ist die Intersection-over-Union (IoU) – die gemeinsame Fläche zweier Rahmen geteilt durch ihre kombinierte Fläche, ein Wert zwischen 0 (keine Überlappung) und 1 (identische Rahmen). Das Konstruktorargument nms_threshold jedes mitgelieferten Post-Prozessors ist die Grenze, oberhalb derer Rahmen als Duplikate eines bereits behaltenen Rahmens behandelt werden.
NMS reduziert eine Ansammlung überlappender Erkennungen auf die mit dem höchsten Score.¶
7.13.1. Soft-NMS¶
Die mitgelieferte Klasse ml.utils.NMS implementiert Soft-NMS, eine Verfeinerung, die den Score eines überlappenden Rahmens um einen Betrag verringert, der davon abhängt, wie stark er überlappt, anstatt den Rahmen vollständig zu verwerfen. Fällt der verringerte Score unter den Schwellenwert, wird der Rahmen verworfen; andernfalls überlebt er mit dem reduzierten Score und tritt in der nächsten Runde an.
Der Parameter nms_sigma steuert, wie aggressiv die Abschwächung ausfällt. Bei einem kleinen nms_sigma (der mitgelieferte Standardwert von 0.1) ist die Abschwächung steil: Ein stark überlappender Rahmen wird in seinem Score auf nahezu null getrieben, und Soft-NMS reduziert sich auf klassisches NMS. Bei einem größeren nms_sigma ist die Abschwächung sanft, und überlappende Rahmen verschiedener Objekte überleben häufiger, was wichtig ist, wenn reale Objekte derselben Klasse tatsächlich überlappen (eine Menschenmenge von Gesichtern, eine Ansammlung von Handflächen).
Setzt man nms_sigma auf <= 0, wird die Abschwächung vollständig deaktiviert: Überlappende Rahmen werden mit ihren ursprünglichen Scores durchgereicht, und nur der Score-Schwellenwert filtert sie.
7.13.2. Einen direkt erstellen¶
Jeder mitgelieferte Post-Prozessor erstellt pro Inferenz eine frische NMS, fügt ihr jeden Kandidaten hinzu und ruft am Ende get_bounding_boxes() auf. Ein benutzerdefinierter Post-Prozessor folgt demselben Muster:
from ml.utils import NMS
iw = model.input_shape[0][2]
ih = model.input_shape[0][1]
nms = NMS(iw, ih, inputs[0].roi)
for box, score, class_idx in candidates:
nms.add_bounding_box(box.xmin, box.ymin,
box.xmax, box.ymax,
score, class_idx)
result = nms.get_bounding_boxes(threshold=nms_threshold,
sigma=nms_sigma)
Der Konstruktor nimmt die Eingabebreite und -höhe des Netzes in Pixeln sowie den ROI des ursprünglichen Bildes entgegen, gegen das das Modell lief; add_bounding_box() nimmt Rahmenkoordinaten in diesem Netzeingabe-Pixelraum entgegen, und get_bounding_boxes() bildet die Überlebenden anhand des ROI zurück in Bildkoordinaten ab. Die Rückabbildung berücksichtigt die Normalisierungsdehnung automatisch – es wird derselbe ROI verwendet, den der Prädiktor gesehen hat, um die Rahmen zurückzuprojizieren –, sodass die zurückgegebenen Rahmen bereit sind, auf das erfasste Einzelbild gezeichnet zu werden.
Die Rückgabeform ist eine Liste von Listen pro Klasse, indiziert durch den an add_bounding_box übergebenen label_index. Leere Klassenlisten bleiben erhalten, sodass der Index dem Klassenindex des Modells entspricht; enumerate(result) durchläuft die Klassen zusammen mit ihren Erkennungen.