Allgemeine Beschreibung


In den letzten Jahren haben Faltungsnetzwerke (Convolutional Neural Networks) eindrucksvolle Leistung bei vielen Aufgaben aus dem Bereich Maschinelles Sehen geliefert, u.a. bei der Objekterkennung. Dieser Versuch gibt eine Einführung in diese äußerst leistungsstarke Methode aus dem Bereich des Maschinellen Lernens und erlaubt, praktische Erfahrung beim Umsetzen einer einfachen Objekterkennung mit TensorFlow zu sammeln.

Teilbereiche

Dieser Versuch befasst sich mit einigen praktischen Aspekten des Deep Learning im Rahmen des Maschinellen Sehens. Dazu gehört, ein neuronales Netz mit vielen Ebenen (deep network) zu konstruieren, es mit dem Gradientenverfahren zu trainieren und Regularisierung zu verwenden, um die Resultate zu verbessern. In diesem Versuch beschäftigen wir uns mit der häufig verwendeten Bildklassifizierungsaufgabe und dem CIFAR10 Datensatz, der aus 50.000 \(32\times32\) RGB-Bildern aus 10 verschiedenen Klassen besteht. Die Zielsetzung ist, dass das trainierte neuronale Netz automatisch entscheidet, zu welcher der 10 Klassen ein neues, für das Netz unbekanntes Bild gehört. Als Erstes betrachten wir das einfache Mehrlagige Perzeptron, das wir dann zu einem Faltungsnetzwerk (Convolutional Neural Network) erweitern, welches sich besser für die Verarbeitung von Bildern eignet. Im Anschluss geht es darum, verschiedene Methoden zur Verbesserung des Trainings auszuprobieren und dabei praktische Erfahrung im Bereich des Deep Learnings zu sammeln.

In diesem Versuch verwenden wir das weit verbreitete TensorFlow-Framework und programmieren in Python. Sollte Python noch nicht installiert sein, empfehlen wir die Anaconda-Distribution.

 

TensorFlow kann so installiert werden, dass es mit der GPU kompatibel ist, d.h. dass Quellcode auf einer Nvidia-Grafikkarte ausgeführt werden kann. Das Ausführen von TensorFlow auf einer GPU führt zu einer deutlichen Geschwindigkeitssteigerung und ist daher generell empfehlenswert. Für den Fall, dass keine Nvidia-GPU installiert ist, oder die Installation der GPU-kompatiblen TensorFlow-Version zu aufwändig ist, haben wir den Versuch so konzipiert, dass er auch unter Verwendung einer CPU gut beherrschbar ist.

Die untenstehende Grafik enthält Beispielbilder aus jeder der 10 Klassen des Datensatz CIFAR10. Weitere Informationen über den Datensatz sind der Webseite zu entnehmen.

 

 

Dieser Versuch umfasst die folgenden Inhalte:

  • Konstruktion eines Deep Learning-Modells in TensorFlow
  • Implementierung eines Mehrlagigen Perzeptrons (MLP)
  • Implementierung eines Faltungsnetzwerks (Convolutional Neural Network-CNN)
  • Anwendung der beiden Netztypen auf die Klassifizierung von Bildern
  • Optimierung der Netzwerkparameter mit Hilfe der Cross-Entropy-Kostenfunktion
  • Verbesserung der Leistung der neuronalen Netze durch
    • Geschickte Initialisierung der Netzwerkparameter
    • Künstliche Vergrößerung des Datensatzes (Data Augmentation)
    • Stabilisierung des Trainings mit Hilfe von Batch Normalization
    • Regularisierung des Netzwerks mit Hilfe der Dropout-Technik

Die Datei cifar10_data.py enthält Quellcode, der den Datensatz CIFAR10 herunterlädt, extrahiert und einliest. Der Download nimmt ca. 300 MB Festplattenplatz ein. Die Funktionen in dieser Datei müssen nicht verändert werden; es ist aber möglich, mit der Anzahl der Trainingsbilder und der Bildgröße zu experimentieren. Die bereitgestellte Funktion erstellt einen TensorFlow-Datensatz (tf.data.FixedLengthRecordDataset), dekodiert die rohen Binärdaten und erstellt Mini-Batches aus mehreren Bildern.

Im Folgenden betrachten wir die Algorithmen des Maschinellen Lernens, die in diesem Versuch Verwendung finden werden.

 

Linearer Klassifizierer

Sei \(x\in\mathbb{R}^{D}\) die Eingabe für den Klassifizierer (z.B. ein Bild, das zu einem Vektor umgeformt wurde). Ein linearer Klassifizierer nutzt dann eine Gewichtsmatrix \(W\in\mathbb{R}^{C\times D}\) und einen Bias-Vektor \(b\in\mathbb{R}\), wobei \(C\) die Anzahl der Klassen ist. Die unbearbeitete Ausgabe \(q\in\mathbb{R}^{C}\) des linearen Klassifizierer (oft logits genannt) ist dann gegeben durch

$$q(x)=W\cdot x+b$$

und die Klassifizierungsentscheidung ist

$$\hat{c}=\arg\max_{c\in\{1,\dots,C\}}q_{c}(x).$$

 

Üblicherweise wird die Softmax-Funktion verwendet, um die logits \(z\) zu dem Klassifizierungsergebnis \(\hat{y}\) zu konvertieren, welche als A-posteriori-Wahrscheinlichkeiten für die verschiedenen Klassen interpretiert werden kann. Für die Klasse \(c\in\{1,\dots,C\}\) ist die Softmax-Aktivierung gegeben durch

$$\hat{y}_{c}=\frac{\exp q_{c}}{\sum_{k\in\{1,\dots,C\}}\exp q_{k}}.$$

 

Mehrlagiger Perzeptron

In einem Mehrlagigen Perzeptron sind ein oder mehrere Hidden Layer übereinander angeordnet, wobei jedes davon einen versteckten Aktivierungsvektor

$$q^{(i)}=W^{(i)}z_{i-1}+b^{(i)},$$

$$z^{(i)}=f(q^{(i)}),$$

produziert, wobei \(i\) der Layerindex, und$f$ eine nicht-lineare Aktivierungsfunktion ist (wie z.B. tanh oder ReLU). Es ist zu beachten, dass \(z^{(0)}\) lediglich die Eingabe für das Netzwerk ist, also \(z^{(0)}:=x\). Nach dem obersten Hidden Layer wird ein weiterer linearer Klassifizierer genutzt, um das finale Ergebnis des Netzwerks zu berechnen. Die Nicht-Linearitäten werden benötigt, damit das Netzwerk ausdrucksstärker wird und damit es nicht-lineare Abhängigkeiten lernen kann. Ohne die Aktivierungsfunktionen wäre das Netzwerk als Ganzes linear, da die Komposition mehrerer linearen Funktionen wiederum linear ist.

 

Kostenfunktion

Um ein neuronales Netz optimieren zu können, müssen wir zunächst eine Kostenfunktion definieren, die von dem Berechnungsergebnis des Netzwerks \(\hat{y}\in\mathbb{R}^{C}\) und dem Referenzwert (Ground Truth) \(y\) abhängt. Hier gehen wir davon aus, dass der Referenzwert \(y\) im One-Hot-Format vorliegt, d.h. \(y\in\mathbb{R}^{C}\), wobei \(y_{c}\in\{0,1\}\ \forall c\in\{1,\dots,C\}\) und \(\sum_{c=1}^{C}y_{c}=1\), was bedeutet, dass genau eine Komponente des Vektors \(1\) ist und alle anderen Einträge \(0\) sind.

Für die Klassifizierung in mehr als zwei Klassen wird üblicherweise die Cross-Entropy-Kostenfunktion im Anschluss an die Softmax-Aktivierungsfunktion verwendet. Die Cross-Entropy-Kostenfunktion \(\mathcal{L}_{CE}\) ist wie folgt definiert:

$$\mathcal{L}_{CE}(y,\hat{y};W,b)=-\sum_{c=1}^{C}y_{c}\log\hat{y}_{c}$$

 

Fehler-Rückpropagierung

Zur Optimierung des neuronalen Netzwerks müssen wir die Gradienten der Kostenfunktion mit Hinblick auf die Netzwerkparameter berechnen. In der Praxis übernimmt TensorFlow die Aufgabe, die Ableitungen zu berechnen, weshalb hier nur die Hauptidee kurz beschrieben wird. Um die Gradienten zu erhalten, verwenden wir die Fehler-Rückpropagierungsmethode, die im Grunde eine Anwendung der Kettenregel aus der Differentialrechnung ist. Gegeben sei die partielle Ableitung \(\frac{\partial\mathcal{L}}{\partial z_{j}^{(i)}}\) der Kostenfunktion nach der versteckten Aktivierung \(z_{j}^{(i)}\) des versteckten Knoten \(j\) in Layer \(i\). Wir wollen nun die partielle Ableitung \(\frac{\partial\mathcal{L}}{\partial z_{k}^{(i-1)}}\) der Kostenfunktion nach dem versteckten Knoten \(k\) der versteckten Aktivierung \(z_{k}^{(i-1)}\) im darunterliegenden Layer \(i-1\) berechnen. Wenn wir nun die Kettenregel anwenden, erhalten wir

$$\frac{\partial\mathcal{L}}{\partial z_{k}^{(i-1)}}=\sum_{j}\frac{\partial\mathcal{L}}{\partial z_{j}^{(i)}}\frac{\partial z_{j}^{(i)}}{\partial q_{j}(i)}\frac{\partial q_{j}^{(i)}}{\partial z_{k}^{(i-1)}}=\sum_{j}\frac{\partial\mathcal{L}}{\partial z_{j}^{(i)}}f'(q_{j}^{(i)})w_{jk}^{(i)}.$$

Wenn wir diese Gleichung nun in Matrix/Vektorform umwandeln, erhalten wir

$$\frac{\partial\mathcal{L}}{\partial z^{(i-1)}}=W^{(i),T}\left(\frac{\partial\mathcal{L}}{\partial z^{(i)}}\odot f'(z^{(i)})\right),$$

wobei \(\odot\) die komponentenweise Multiplikation bezeichnet.

Diese Gleichung kann nun verwendet werden, um die Gradienten von Layer \(i\) zum Layer \(i-1\) zurückzupropagieren. Um diesen Prozess zu starten, muss zunächst die Ableitung \(\frac{\partial\mathcal{L}}{\partial\hat{y}_{i}}\) der Kostenfunktion \(\mathcal{L}\) nach dem Berechnungsergebnis des Netzwerks \(\hat{y}\) bestimmt werden, was durch einfache analytische Herleitungen möglich ist (hier ausgelassen). Ähnlich wie wir zuvor die Gradienten von Layer \(i\) zu Layer \(i-1\) zurückpropagiert haben, können wir die Gradienten in Bezug auf die versteckten Aktivierungen nutzen, um die Gradienten in Bezug auf die Netzwerkparameter zu berechnen.

 

Gradient Descent

Sobald wir die Gradienten \(\frac{\partial\mathcal{L}}{\partial w_{i}}\) mit Bezug auf die Netzwerkparameter \(w_{i}\) berechnet haben, können wir die Netzwerkparameter in Richtung des negativen Gradienten unter Verwendung einer Lerngeschwindigkeit \(\lambda\) anpassen:

$$w^{new}=w^{old}-\lambda\frac{\partial L}{\partial w}_{\vert w^{old}}$$

Um eine höhere Effizienz zu erreichen, berechnen wir den Gradient nur pro Mini-Batch (bestehend aus ein paar wenigen Bildern), anstatt auf dem gesamten Datensatz auf einmal.

 

Convolutional Neural Networks

Das Mehrlagige Perzeptron ist für die Verarbeitung von Bilddaten nicht gut geeignet. Wenn man mit großen Bildern arbeitet, wird die Anzahl der Netzwerkparameter sehr schnell zu groß und MLPs erlangen keine gute Generalisierungsfähigkeit. Faltungsnetzwerke (Convolutional Neural Networks – CNNs) schaffen Abhilfe, indem sie Faltungs-Layer (convolutional layer) statt der vollständig verbundenen Layer verwenden. Die Faltungs-Layer behandeln die Eingabebilder als 3-dimensionale Tensoren (Höhe, Breite und RGB) und geben einen neuen Tensor aus, bei dem die räumliche Anordnung beibehalten wird, während die Eingabekanäle (anfangs RGB) durch das gefilterte Ergebnis ersetzt werden. Zu diesem Zweck wendet ein Faltungs-Layer mehrere Filter mit einer begrenzten Kernel-Größe (z.B. \(3\times3\)) an. Die Filter werden systematisch über das Bild gefahren. Die Parameter, die den Filter definieren, sind dabei für das gesamte Bild gleich. Dieser Vorgang kann durch die sog. Faltungsoperation (convolution) effizient umgesetzt werden. Eine weitere wichtige Komponente in Faltungsnetzwerken sind die sog. Pooling Layer. Ein Max-Pooling Layer reduziert die räumliche Auflösung der Eingabe, indem es jeden Block einer bestimmten Größe (z.B. \(2\times2\)) durch den maximalen Wert innerhalb dieses Blocks ersetzt, wobei das Maximum für jede Dimension separat berechnet wird. Indem die Tensorgröße verringert wird, erlaubt Max-Pooling eine höhere Recheneffizienz. Durch die Berechnung des Maximums wird zudem eine gewisse Robustheit gegen räumliche Verschiebungen erzielt.

Um ein komplettes Faltungsnetzwerk zu konstruieren, werden in der Regel mehrere Faltungs-Layer sowie Max-Pooling-Layer abwechselnd übereinander angeordnet. Der resultierende Feature-Tensor wird dann in einen eindimensionalen Vektor umgeformt und als Eingabe für einen linearen Klassifizierer verwendet.

In diesem Versuch werden wir verschiedene Netzwerke trainieren, sodass sie Bilder in eine der 10 CIFAR10-Klassen einordnen. Der zur Verfügung gestellte Quelltext ist ausführbar und trainiert ein einfaches lineares Modell.

Im ersten Schritt ist es nötig, sich mit dem Quelltext vertraut zu machen. Anschließend implementieren wir einfache Strategien zur künstlichen Vergrößerung des Datensatzes, um eine höhere Generalisierungsfähigkeit der Modelle zu erreichen.

Im nächsten Schritt soll das einfache lineare Modell zu einem Mehrlagigen Perzeptron (MLP) mit einem einzelnen Hidden Layer erweitert werden. Die Parameterinitalisierung soll dabei so angepasst werden, dass sie gut mit der ReLU Non-Linearität zusammenspielt. An dieser Stelle soll erforscht werden, wie gut die vollständig verbundenen MLP sich für die Verarbeitung von Bilddaten eignen und ob sich Weight Decay als nützlich erweist.

Im darauffolgenden Schritt soll ein Faltungsnetzwerk implementiert werden, welches sich besser für die Verarbeitung von Bilddaten eignet. Zu diesem Zweck müssen zunächst allgemeine Funktionen für die Faltungs- sowie die Pooling-Layer implementiert werden. Diese Layer werden dann übereinandergestapelt, um ein vollständiges Netzwerk zu erhalten. Anschließend soll nun die Batch Normalization-Methode eingesetzt werden, um den Trainingsprozess zu beschleunigen.

Abschließend wollen wir uns die Pooling-Layer noch näher anschauen, und überlegen, ob sie durch schrittweise Faltungen ersetzt werden sollen. Wir werden zudem die Menge der verwendeten Daten erhöhen und ein größeres Netzwerk mit Hilfe der Dropout-Technik als Regularisierungmethode trainieren.

Dieser Versuch erlaubte es, mit verschiedenen Modellen des Maschinellen Lernens zu experimentieren, nämlich ein lineares Modell, ein MLP und ein CNN. Dabei wurden die Grundlagen des Deep Learning vermittelt sowie Fähigkeiten, dieses Wissen praktisch auf einfache  Klassifizierungsprobleme anzuwenden. Mit Hilfe dieses Versuchs sollte es nun möglich sein, einfache Klassifizierungsaufgaben für Bilddaten lösen zu können.