7.16. Zusammenfassung¶
Dieses Kapitel hat die Teile von ml durchlaufen, auf die eine OpenMV-Anwendung zurückgreift, wenn ein Inferenzschritt Teil der Pipeline ist:
Konzepte – was ein neuronales Netz in arithmetischer Hinsicht ist (ein Stapel trainierbarer Operatoren, der einen Tensor auf einen Tensor abbildet), was sich durch maschinelles Lernen gegenüber der klassischen Bildverarbeitung geändert hat (der von Menschen geschriebene Zusammenfassungsalgorithmus ist verschwunden und wurde durch Gewichte ersetzt, die aus gelabelten Daten gelernt wurden), und das Hello-Demo, das in wenigen Zeilen Python einen Gesichtsdetektor ausgeführt hat.
Das ml-Modul – das
ml.Model-Objekt und seine Eigenschaften zum Inspizieren von Eingabe- und Ausgabetensoren, die Modelldateipfade, die es akzeptiert, und wo diese Dateien liegen: eine schreibgeschützte ROMFS-Partition zur Ausführung direkt aus dem Flash, oder jedes andere MicroPython-Dateisystem, wenn das Modell beim Laden in den RAM kopiert werden kann.Die Inferenz-Pipeline – die drei Stufen, die
predict()nacheinander ausführt (Vorverarbeitung, Engine-Dispatch, Nachverarbeitung), dasNormalization-Handle auf Stufe eins, das Nachverarbeitungs-Handle auf Stufe drei, und die Quantisierungsarithmetik, die die ganzzahligen Tensoren, die die Kamera ausführt, mit den reellwertigen Zahlen verknüpft, gegen die das Netz trainiert wurde.Inferenz-Engines – TFLM (der Operator-Interpreter, den die meisten Kameras ausführen), CMSIS-NN (die SIMD-Kernel-Bibliothek darunter auf Cortex-M) und die NPUs (Arms Ethos-U55 auf der AE3 gepaart mit dem Vela-Offline-Compiler, STs Neural-ART auf der N6 gepaart mit STAI und STEdgeAI). Die Engine wird durch die Kamera festgelegt; das Skript wählt sie nicht aus.
Dekodieren der Ausgabe – die Nachverarbeiter, die rohe Ausgabetensoren in Boxen, Schlüsselpunkte oder Listen pro Klasse umwandeln, die
NMS-Klasse, die überlappende Kandidaten zusammenfasst, die YOLOv8-Durchführung, die zeigt, wie man das Dekodieren schnell hält, indem man vor dem Dequantisieren einen Schwellenwert anwendet, und das Protokoll zum Schreiben eines benutzerdefinierten Decoders, wenn der Katalog ein Modell nicht abdeckt.
7.16.1. Was jetzt erreichbar ist¶
Drei Dinge, auf die das Kapitel vorbereitet:
Ein trainiertes Modell laden und ausführen. Alles in
/rom/funktioniert ohne weitere Vorbereitung; alles, was extern als kompatible.tflitebereitgestellt wird, funktioniert, nachdem das Offline-Tool für die Zielkamera (Vela für die AE3, STEdgeAI für die N6) das richtige Layout erzeugt hat.Jeden Ausgabetensor dekodieren. Wenn die Architektur im Katalog enthalten ist, ist der richtige Nachverarbeiter mechanisch:
YoloV8für ein YOLOv8-Modell,BlazeFacefür BlazeFace und so weiter. Wenn nicht, deckt das writing-your-own-Protokoll den Vertrag ab, und die YOLOv8-Durchführung ist die sauberste Referenz zum Kopieren.Über Leistung nachdenken. Ein Modell, das auf einer NPU mit 30 FPS läuft, läuft auf einem Cortex-M7 möglicherweise mit 3 FPS; das Verhältnis hängt davon ab, wie viel des Netzes die Kamera vom CPU abnehmen kann. Quantisierung, ROMFS-Platzierung, NPU-Kompilierung und die Operatorabdeckung der Ziel-Engine sind die vier Hebel, und das Kapitel hat jeden von ihnen behandelt.
7.16.2. ML lässt sich mit dem Rest der Kamera kombinieren¶
Eine Inferenz läuft selten isoliert. Das image-Modul erfasst und verarbeitet das Einzelbild vor, das ml-Modul führt das Netz aus, und ulab.numpy erledigt jegliche numerische Arbeit, für die keine der beiden Seiten eine eingebaute Funktion hat. Ein typisches Erkennungsskript kombiniert alle drei: Erfassung mit csi, optionale Anpassung des Einzelbilds mit image, Ausführung von predict(), Nachverarbeitung des Ergebnisses mit dem richtigen Modul aus ml.postprocessing und Rückgriff auf ulab.numpy für jegliche benutzerdefinierte Berechnung, die die Anwendung zusätzlich zu den vom Nachverarbeiter zurückgegebenen Boxen wünscht. Die drei Module teilen sich dasselbe Speichermodell; die Grenzen zwischen ihnen sind, wo immer möglich, ohne Kopiervorgang (zero-copy).