7.1. Was ist ein neuronales Netz

Ein neuronales Netz ist ein Algorithmus, dessen Verhalten aus Beispielen gelernt wird, anstatt von Hand programmiert zu werden. Dieselbe Netzarchitektur lernt anhand einer Million Gesichtsbilder, Gesichter zu erkennen. Dieselbe Architektur lernt anhand einer Million Handbilder, Hände zu erkennen. Dieselbe Architektur lernt anhand eines beschrifteten Satzes, der viele Objektkategorien abdeckt, sie alle gleichzeitig zu erkennen. Nur die Gewichte ändern sich zwischen den Zielen, und die Gewichte werden durch einen externen Trainingsprozess erzeugt, der die Vorhersagen des Netzes mit beschrifteten Beispielen vergleicht und die Gewichte anpasst, bis sie übereinstimmen.

7.1.1. Der Mechanismus

Ein neuronales Netz ist ein Stapel von Schichten. Jede Schicht multipliziert die Ausgabe der vorherigen Schicht mit einer Matrix von Gewichten, addiert einen Bias-Vektor und wendet eine nichtlineare Funktion auf das Ergebnis an. Die Ausgabe einer Schicht ist die Eingabe der nächsten. Ein aufgenommenes Bild tritt am oberen Ende des Stapels ein, fließt durch Dutzende oder Hunderte von Schichten nach unten und tritt am unteren Ende als Tensor aus, dessen Einträge beschreiben, was im Bild zu sehen war.

Was die Gewichte der einzelnen Schichten tun, hängt davon ab, worauf das Netz trainiert wurde. Eine Gewichtsmatrix einer frühen Schicht in einem Sehnetz könnte auf eine kurze horizontale Kante ansprechen; eine etwas tiefere könnte auf eine Ecke ansprechen; eine noch tiefere könnte auf eine kreisförmige Augenform ansprechen; die tiefsten Schichten könnten auf ganze Gesichtsanordnungen ansprechen. Nichts davon wurde von Hand geschrieben. Der Trainingsprozess iterierte über Millionen von beschrifteten Beispielen, schob die Gewichte entlang einer Verlustfunktion bergab, und die Hierarchie Kante-dann-Ecke-dann-Auge-dann-Gesicht ergab sich aus den Daten.

Ein vertikaler Stapel aus neun beschrifteten Kästchen, die die Schichten eines kleinen Klassifizierungsnetzes darstellen. Das oberste Kästchen ist mit "Input image" beschriftet und hat eine Tensorform von (192, 192, 3). Ein Pfeil führt nach unten zu einem "Conv + ReLU"-Kästchen mit der Form (96, 96, 32). Ein weiterer Pfeil führt zu einem zweiten "Conv + ReLU"-Kästchen mit der Form (48, 48, 64). Es folgt ein "MaxPool"-Kästchen mit der Form (24, 24, 64). Zwei weitere "Conv + ReLU"-Kästchen folgen mit den Formen (12, 12, 128) und (6, 6, 256). Ein "Global average pool"-Kästchen hat die Form (256,). Ein "Fully connected"-Kästchen hat die Form (1000,). Das unterste Kästchen ist mit "Class scores" beschriftet und hat die Form (1000,). Der Tensorfluss verläuft von oben nach unten.

Ein kleines Klassifizierungsnetz als Stapel von Schichten. Der Eingabetensor tritt oben mit der Form des aufgenommenen Bildes ein und fließt durch die Schichten nach unten, wobei jede die Dimensionen des Tensors transformiert. Der Ausgabetensor am unteren Ende hat einen Eintrag pro Klasse. Erkennungs- und Schlüsselpunktnetze haben dieselbe Form als Stapel von Schichten; nur die Interpretation des Ausgabetensors ändert sich.

Die Architektur des Netzes – wie die Schichten angeordnet sind, welche Operationen sie verbinden – ist das, was das Netz kann. Die Gewichte sind das, was das Netz gelernt hat. Der Anteil der Kamera daran besteht darin, die durch das Training erzeugte Gewichtsdatei zu laden und dieselbe Arithmetik auszuführen, die der Trainer ausgeführt hat, aber auf dem aufgenommenen Einzelbild statt auf dem Trainingssatz.

7.1.2. Was hineingegeben wird, was herauskommt

Beide Enden des Netzes sind Tensoren – mehrdimensionale Arrays von Zahlen, dieselbe Art von Objekt, die das numpy-Kapitel gerade eingeführt hat. Der Eingabetensor für ein Sehnetz ist das aufgenommene Bild, neu angeordnet in das Layout, das das Netz erwartet: typischerweise eine 4-Tupel-Form (B, H, W, C), wobei B die Batch-Dimension ist (auf der Kamera immer 1, da jeweils ein Einzelbild verarbeitet wird), H und W die vom Netz erwartete Pixelhöhe und -breite sind und C die Kanalanzahl ist (3 für ein RGB-Netz, 1 für Graustufen).

Der Ausgabetensor hängt davon ab, wofür das Netz bestimmt ist:

  • Ein Klassifizierungsnetz erzeugt einen 1-D-Tensor von Konfidenzwerten, einen pro Klasse. Der Index des größten Werts ist die vorhergesagte Klasse. Der von MobileNet abgeleitete Personendetektor, der auf den meisten Kameras mitgeliefert wird, hat diese Form: zwei Werte, einen für „person“, einen für „not person“.

  • Ein Erkennungsnetz erzeugt einen 2-D-Tensor, dessen Einträge eine Liste von Begrenzungsrahmen sowie Klassenwahrscheinlichkeiten beschreiben. YOLOv8 hat diese Form: einen Tensor (84, N), wobei 4 der 84 Zeilen Box-Regressionswerte sind und die anderen 80 klassenweise Wahrscheinlichkeiten, wiederholt über N Ankerpositionen.

  • Ein Schlüsselpunktnetz erzeugt einen Tensor, dessen Einträge die Pixelpositionen benannter Landmarken sind. Das MediaPipe-Gesichtslandmarken-Modell hat diese Form: 468 Schlüsselpunkte pro erkanntem Gesicht.

  • Ein Segmentierungsnetz erzeugt einen 2-D-Tensor, dessen Einträge pixelweise Klassen-Labels sind – dieselben Dimensionen wie die Eingabe, mit einem Kategorieindex an jeder Position.

  • Ein Regressionsnetz erzeugt eine einzelne Zahl oder einen kurzen Vektor von Zahlen – eine Tiefenschätzung, einen Winkel, eine Temperatur.

Jede Form hat ihren eigenen Post-Prozessor auf der Kamera, der den rohen Ausgabetensor zurück in die Ergebnisform umwandelt, die der Rest der Anwendung verwendet – Begrenzungsrahmen, Schlüsselpunktlisten, Klassen-Labels, numerische Schätzungen. Der Post-Prozessor ist anwendungsseitiger Code, der das Ausgabelayout des Netzes kennt; das Netz selbst ist nur die Arithmetik, die den Tensor erzeugt.

7.1.3. Warum das auf einer Kamera funktioniert

Zwei Arten von Arithmetik machen dies für ein Bauteil der Mikrocontroller-Klasse praktikabel. Die erste ist die Quantisierung. Das Training erfolgt in 32-Bit-Gleitkommaarithmetik; die Inferenz kann in 8-Bit-Ganzzahlarithmetik laufen, bei den meisten Netzen fast ohne Genauigkeitsverlust. Acht-Bit-Gewichte benötigen ein Viertel des Speichers und laufen mehrmals schneller als die 32-Bit-Gleitkommazahlen. Jedes Modell, das mit der Kamera mitgeliefert wird, wurde bereits extern quantisiert.

Die zweite ist die Hardwarebeschleunigung. Dieselbe Arithmetik, die die CPU eines Mikrocontrollers mühsam Befehl für Befehl abarbeitet, führt ein Beschleuniger für neuronale Netze hundertfach gleichzeitig aus. Die neueren Kameras (die AE3 und die N6) tragen eine dedizierte Neural Processing Unit (NPU) – einen Tensorbeschleuniger auf dem SoC – die aus einem Modell, dessen Ausführung auf der CPU eine Sekunde gedauert hätte, eines macht, das in zehntel Millisekunden läuft. Das Kapitel über die Inferenz-Engines behandelt, wie der Anteil der Kamera daran aussieht.

7.1.4. Was das Kapitel behandelt

Das Training ist nicht die Aufgabe der Kamera. Ein trainiertes Modell kommt als .tflite-Datei auf der Kamera an; die Kamera lädt es, führt jedes aufgenommene Einzelbild hindurch und dekodiert den resultierenden Tensor in ein Ergebnis, auf das die Anwendung reagieren kann. Alles, was folgt, handelt von jedem dieser Schritte:

  • Laden und Untersuchen eines Modells;

  • die Flash-Partition, in der die Modelldateien liegen;

  • die vier Phasen eines Inferenzaufrufs;

  • die Engines, die die Arithmetik tatsächlich ausführen;

  • und die Post-Prozessoren, die einen Ausgabetensor zurück in eine Liste von Rahmen, Schlüsselpunkten oder Klassen umwandeln.

Die Detektoren im Bild-Kapitel waren jeweils auf ein bestimmtes Ziel zugeschnitten. Diejenigen, die der Rest dieses Kapitels behandelt, werden stattdessen aus Daten trainiert, wobei dieselbe Engine das jeweilige Modell ausführt, das das Skript lädt. Die damit einhergehende Änderung des Arbeitsablaufs – ein zielspezifischer Algorithmus, ersetzt durch eine zielspezifische Gewichtsdatei – ist das Nächste, das herausgearbeitet werden soll.