Autos können selbstständig Verkehrszeichen erkennen, Handyfotos werden automatisch je nach dargestellter Person in Ordner sortiert und Apps verwenden Handy-Kameras, um Filter auf Fotos anzuwenden: Bilderkennung ist längst fester Bestandteil unseres Alltags.

Auch in der Prozessindustrie ersetzt immer öfter die Bilderkennung die visuelle Kontrolle durch Mitarbeiterinnen und Mitarbeiter. So sind diese für andere Aufgaben verfügbar und fehlerhafte Zustände werden schneller erkannt.

Im Folgenden lest ihr, wie ihr mit der Bibliothek PyTorch ein erstes eigenes neuronales Netz aufbaut und trainiert. Grundlage ist der MNIST-Datensatz (https://deepai.org/dataset/mnist), in dem handschriftliche Ziffern als Bilder enthalten sind, die erkannt werden sollen. Dazu wird ein Convolutional Neural Network aufgebaut. Viele der Grundlagen, wie das Erstellen des Trainingszyklus, sind in anderen Deep-Learning-Projekten leicht wiederzuverwenden.

2
3

Abbildung 1: Beispielhafte handschriftliche Ziffern (Ziffer 2 und 3 sollten jeweils erkannt werden)

Installieren von PyTorch mit Conda

In diesem Tutorial wird die Deep-Learning-Python-Bibliothek PyTorch genutzt. Da Deep Learning größere Anforderungen an die Hardware stellt, gibt es hier etwas mehr zu beachten als bei herkömmlichen Python-Bibliotheken.

Auf der offiziellen PyTorch-Dokumentationsseite (https://pytorch.org/get-started/locally/) gibt es ein einfaches Menü, wo der Installationsbefehl individuell zusammengestellt werden kann.

Für den Package-Manager Conda und ohne „Cuda“-fähige GPU, sieht der Befehl so aus:

conda install pytorch torchvision torchaudio cpuonly -c pytorch

Alternativ stehen zum Arbeiten auch Services wie Google Colab (https://colab.research.google.com/) in der Cloud zur Verfügung, in denen alle benötigten Komponenten schon vorinstalliert sind.

Verwendete Imports in diesem Post

Copy to Clipboard

Um den Code in den folgenden Abschnitten ausführen zu können, werden diese Imports benötigt.

Das „Hello World“-Datenset der Bilderkennung: MNIST

In vielen Programmiersprachen lernen Anfängerinnen und Anfänger zuerst ein Programm zu schreiben, was „Hello World“ auf der Konsole ausgibt. Da in Machine Learning die Anforderung an die Komplexität des Modells mit den Daten steigt, bietet es sich an, mit einem leicht zu „lernenden“ Datensatz anzufangen. In der Bilderkennung ist das der MNIST-Datensatz (https://deepai.org/dataset/mnist). Enthalten sind Bilder der Größe 28 mal 28 Pixel in schwarz-weiß mit jeweils einer handgeschriebenen ganzen Zahl zwischen 0 und 9.

Weil diese Daten so häufig verwendet werden, sind sie sogar schon in der torchvision-Bibliothek enthalten, die bereits installiert wurde (siehe oben).

Copy to Clipboard

Über den oben angezeigten Code werden die Daten getrennt als Trainings- und Testdatensatz heruntergeladen und jeweils in einem Objekt gespeichert.

Die gewählten Optionen bewirken das Folgende:

  • root: Pfad, an dem die Daten abgelegt werden.
  • train: Bestimmt, ob der Trainings- oder Testteil der Daten genutzt werden soll.
  • download: Gibt an, dass Daten aus dem Internet heruntergeladen werden sollen und nicht schon im root-Pfad abgelegt werden.
  • transform: Hier kann eine Funktion übergeben werden, die die Bilder transformiert. In diesem Tutorial belassen wir es bei einer einfachen Konvertierung in das Tensor-Array-Format von PyTorch.

Erstellen des DataLoaders mit PyTorch

Beim Training eines Bildklassifikationsmodells, ist der Datensatz in den meisten Fällen zu groß, um zusammen mit dem Modell selbst in den Arbeitsspeicher zu passen. Deswegen empfiehlt es sich, immer nur einen Teil der Trainingsdaten in den Speicher zu laden, diese zu verarbeiten und sie mit der nächsten Untermenge auszuwechseln. Diese Arbeit übernimmt in PyTorch der DataLoader. Da im Beispiel zwei Datensätze verwendet werden – Training und Test – werden zwei DataLoader benötigt:

Copy to Clipboard

Beim Erstellen der DataLoader Instanzen kann mit dem „batch_size“-Parameter die Anzahl von gleichzeitig geladenen Bildern eingestellt werden.

Wahl des Gerätes zum Training – CPU oder CUDA-fähige GPU

Das Thema Hardware in Bezug auf CPU und GPU, welches bei der Installation adressiert wurde, wird erneut wichtig. Im Beispiel-Code wurde nur die CPU-Bibliothek installiert, aber es bietet sich an, im Code zu überprüfen, ob eine „Cuda“-fähige GPU für die Berechnungen verfügbar ist. Dadurch wird sichergestellt, dass der geschriebene Code auf jeder Hardware optimiert läuft und die meist höhere Schnelligkeit der GPU für das Modell-Training nutzt.

Copy to Clipboard

Der Code dazu ist ein Einzeiler mit einem if-Statement, das überprüft, ob eine GPU verfügbar ist und diese dann als Gerät (device) auswählt. Zur Überwachung ist es gut, sich das Ergebnis ausgeben zu lassen. Wer eine teure GPU gekauft hat, möchte sicher gehen, dass diese auch wirklich verwendet wird.

So erstellt ihr ein eigenes PyTorch-Modell zur Bilderkennung

Nach diesen Vorbereitungen geht es nun daran das neuronale Netz an sich zu bauen. Dabei gibt es praktisch unendlich viele Möglichkeiten. Für Neueinsteigerinnen und Neueinsteiger, und die meisten Probleme, ist es empfehlenswert, ein vortrainiertes Modell mit einer von Expertinnen und Experten entwickelten Architektur auszuprobieren.

Das Erstellen eines eigenen Modells involviert das Erproben von einigen Kombinationen der verschiedenen Schichten. Es gibt Erfahrungswerte von Kombinationen und Mustern, die in vielen Fällen gute Ergebnisse liefern. Diese Muster finden sich in Architekturen wie VGG (https://arxiv.org/abs/1409.1556).

Copy to Clipboard

Die Klasse des Modells muss von der „torch.nn.Module“-Klasse erben, um die Methoden und Optimierungsfähigkeiten der Bibliothek zu nutzen. Im Konstruktor wird dann die neue Klasse an den Konstruktor der Module-Klasse übergeben. Außerdem ist es empfehlenswert, alle Schichten mit ihren Parametern zu initialisieren.

Folgenden Schichten wurden verwendet:

  • Convolutional-Schichten (nn.Conv2d), um räumliche Zusammenhänge auf Ausschnitten der Bilder zu erkennen
  • eine nichtlineare Aktivierungsfunktion (hier: nn.ReLU()), die die restlichen linearen Operatoren voneinander trennt, da das Modell ansonsten nur eine ineffektive, verschmolzene Schicht hätte
  • eine Flatten-Aktion, die quadratische Bilder in einen länglichen Vektor verwandelt, der mit den folgenden Schichten kompatibel ist
  • Fully-Connected-Schichten (in PyTorch nn.Linear), die alle Filter und räumlichen Zusammenhänge kombinieren und zehn Werte ausspielen, um die Wahrscheinlichkeit anzugeben, dass die jeweilige Zahl auf dem Bild abgebildet ist

Der auskommentierte Print-Befehl ist kein Fehler, sondern eine Möglichkeit herauszufinden, wie groß die erste lineare Schicht sein muss, da sich die Größe eines Bildes durch verschiedene Kernel- und Padding-Größen verändern kann.

Neben dem Konstruktor muss in der Modellklasse auch die forward-Methode implementiert werden, die einen Input „x“ erhält – in diesem Fall ein Bild der Größe 28 mal 28 Pixel. Diese Methode wird jedes Mal aufgerufen, wenn mit model(X) Daten in das Modell eingegeben werden.

Schließlich ist noch wichtig, das Modell auf die vorher definierte Hardware zu transferieren. Um auf der GPU trainieren zu wollen, müssen sowohl die Daten als auch das Modell auf der GPU zwischengespeichert sein.

Wahl einer Loss-Funktion und Optimierungsverfahren

Copy to Clipboard

Damit das Modell lernen kann, muss festgelegt werden, mit welcher Funktion der aktuelle Unterschied zwischen der Entscheidung des Modells und der tatsächlich abgebildeten Zahl berechnet wird – hier die Kreuzentropie. Außerdem wird ein Optimierungsverfahren festgelegt – die Standardkandidaten dafür sind Stochastic Gradient Descent (torch.optim.SGD) und der Adam Optimizer, der hier verwendet wurde.

Als Parameter, die optimiert werden sollen, werden die Parameter des Modells übergeben und eine Lernrate angegeben. 0.001 ist generell ein guter Startpunkt, um verschiedene Werte zu erproben.

Erstellen von Trainings- und Testschleifen mit Backpropagation und Evaluierung der Genauigkeit

Das wesentliche Training hat einige Grundbausteine, die auf jeden Fall verwendet werden müssen.

Copy to Clipboard

Der erste Befehl versetzt das Modell in den Trainingsmodus, was wichtig für einige Schichtarten ist, die unterschiedlich funktionieren. Je nachdem, ob gerade getestet oder trainiert wird. Selbst wenn keine dieser Schichten aktuell verwendet werden, ist es ratsam, sich anzugewöhnen, diesen Befehl aufzurufen.

Anschließend wird durch die gruppierten Datenmengen (batches) aus dem DataLoader iteriert, der vorher erstellt wurde. Das Model wird auf diesem Batch ausgewertet und mit der Loss-Funktion die Qualität der Antwort evaluiert. Daraufhin kann das gewählte Optimierungsverfahren (SGD, Adam etc) mittels Backpropagation das Modell um ein Inkrement verbessern, bevor der nächste Batch betrachtet wird.

Wer sich noch Statistiken zu der Präzision des Modells während des Trainings ausgeben lassen möchte, kann den Code erweitern, was zum Beispiel so aussehen kann:

Copy to Clipboard

Hier wurde noch eine fast äquivalente Schleife für die Testphase hinzugefügt. Darin wird nicht das Optimierungsverfahren verwendet.

Training des neuronalen Netzes über mehrere Epochen

Copy to Clipboard

Schließlich wird alles zusammen in Aktion genommen und über eine gewählte Anzahl an Epochen sowohl die Trainings- als auch Testphase durchgeführt. In jeder Epoche wird einmal auf dem gesamtem Trainingsdatensatz trainiert und evaluiert. Weil am Ende einer Epoche das Modell aber mehrfach verändert wurde, lohnt es sich die Daten erneut zu verwenden, da jetzt im neuen Kontext erneut Erkenntnisse gewonnen werden können. Wie bei vielen Machine-Learning-Modellen üblich, lautet die Grundregel, dass das Training beendet ist, wenn die Testgenauigkeit keine weitere Verbesserung zeigt. In unserem Test lag die Genauigkeit nach zehn Epochen bei circa 97 Prozent.

Fazit: Grundlagen für die große Welt des Deep Learnings und der Bilderkennung

Jetzt habt ihr euer erstes neuronales Netz vollständig selbst erstellt und trainiert, die Aufgabe der handschriftlichen Ziffernerkennung zu lösen!

Der oben beschriebene Trainingszyklus ist der Kern von Deep Learning und darauf aufbauend kann diese Basis auf diverse Anwendungsfälle angepasst und spezialisiert werden. Es kann immer wieder zu Herausforderungen kommen, die mit verschiedenen Techniken angegangen werden können. Themen wie die Vorverarbeitung der Daten (engl. preprocessing) und die geschickte Erhöhung der verfügbaren Bilder (engl. image augmentation) sowie Regularisierung sind empfehlenswert.

Jetzt teilen auf:

Jetzt kommentieren