Archiv Januar 2018

Neuronale Netze — eine Einführung

Manche Leser werden sich schon gefragt haben, ob ich Fortschritte bei meinem neuronalen Maschinenübersetzungsprojekt gemacht habe. Die habe ich tatsächlich. Ich habe wie in der Anleitung beschrieben OpenNMT mit den Standardeinstellungen installiert und erfolgreich ausgeführt. Die Ergebnisse waren allerdings nicht ideal. Dies ist jedoch nicht unerwartet, da sehr viel Finetuning und außerdem umfangreiche, hochwertige Trainingskorpora notwendig sind, um eine Übersetzungsengine mit einigermaßen brauchbarer Qualität zu erhalten. Als Machbarkeitsstudie bin ich jedoch mit den bisherigen Ergebnissen sehr zufrieden. Im nächsten Schritt plane ich, die einzelnen Komponenten der Engine besser abzustimmen und außerdem das Trainingskorpus zu verbessern. Bevor ich im nächsten Blogbeitrag jedoch damit beginne, die NMÜ-Engine in ihre Komponenten zu zerlegen, muss ich wohl zuerst das Grundprinzip der neuronalen Netze erklären. Ich habe dieses Beispiel auch auf der 58. ATA-Konferenz vorgestellt, die Folien zum Vortrag können Sie hier herunterladen.

Neuronen und neuronale Einheiten

Im Folgenden bezeichnet der Begriff „neuronales Netzwerk“ ein künstliches neuronales Netz (KNN), im Gegensatz zu biologischen neuronalen Netzen.

Die Idee der KNN sind nicht neu, sondern wurde in den 1940ern konzipiert, als Forscher versuchten, Modelle des menschlichen Gehirns zu erstellen. Damals war allerdings die Leistung der besten Computer noch viel zu schwach, um die Ideen auch in die Tat umzusetzen. Die Leistung herkömmlicher Computer ist erst im letzten Jahrzehnt ausreichend, um neuronale Netze auf dem Computer sinnvoll zu modellieren.

Wie biologische Gehirne, die aus Neuronen bestehen, bestehen auch KNN aus einzelnen künstlichen Neuronen, deren Funktion der von biologischen Neuronen mehr oder weniger ähnlich ist, wie in den Abbildungen unten illustriert. Abb. 1 zeigt ein biologisches Neuron, dessen genaue Funktionsweise sehr kompliziert, aber hier im Detail unwichtig ist. Grob ausgedrückt besteht ein Neuron aus einem Zellkörper, Dendriten und einem Axon. Das Neuron empfängt über die Dendriten Eingangssignale. Wenn diese Signale einen bestimmten Schwellenwert überschreiten, findet im Nukleus ein elektrochemischer Prozess statt und das Neuron gibt über das Axon ein Ausgangssignal ab.

Biologisches Neuron

Abb. 1: Biologisches Neuron. Quelle: Bruce Blaus, https://commons.wikimedia.org/wiki/File:Blausen_0657_MultipolarNeuron.png


Künstliches Neuron

Abb. 2: Künstliches Neuron

Abb. 2 zeigt ein Modell eines sehr einfachen künstlichen Neurons. Es erhält ebenfalls Eingaben (mit x1 und x2 gekennzeichnet), und je nach den Eingangssignalen überträgt das Neuron über eine Aktivierungsfunktion (der weiße Kreis in Abb. 2) ein Ausgangssignal. Die Aktivierungsfunktion kann eine einfache Schwellenwertfunktion sein, wobei das Neuron ausgeschaltet ist und erst dann eine Ausgabe ausgibt, wenn die Summe der Eingaben einen Schwellenwert erreicht oder überschreitet. Die Aktivierungsfunktion kann aber auch viel komplexer sein. Das bis jetzt beschriebene künstliche Neuron führt jedoch keine besonders interessante Funktion aus. Die Sache wird erst dann interessant, wenn die Eingangssignale je nach ihrer Bedeutung unterschiedlich gewichtet werden. Ein künstliches neuronales Netz „lernt“, indem die Gewichte der einzelnen Eingangssignale (in Abb. 2 mit w1 und w2 gekennzeichnet) in das jeweilige Neuron angepasst werden. In Abb. 2 ist also Eingabe x1 doppelt so wichtig wie Eingabe x2, wie durch die relative Dicke der Pfeile angedeutet.

Schichten und Netzwerke

Ähnlich wie biologische Gehirne werden diese Neuronen in ein neuronales Netz zusammengefügt, wie in Abb. 3 illustriert. Genauer stellt Abb. 3 ein sogenanntes Feedforward-Netz oder vorwärtsgerichtetes Netz dar.

künstliches neuronales Netz

Abb. 3: Künstliches neuronales Netz. Adaptiert von: Cburnett, https://commons.wikimedia.org/wiki/File:Artificial_neural_network.svg

Im Allgemeinen bestehen KNN aus einer Eingabeschicht, einer oder mehreren verdeckten oder verborgenen Schichten und einer Ausgabeschicht. Jede Schicht setzt sich aus einem oder mehreren der oben beschriebenen künstlichen Neuronen zusammen. Neuronale Netze mit mehr als einer verdeckten Schicht werden als „deep“ bezeichnet. Jedes Neuron ist mit einem oder mehreren anderen Neuronen verbunden (in Abb. 3 durch die Pfeile illustriert), und jede Verbindung ist je nach Bedeutung unterschiedlich gewichtet. In einem Feedforward-Netz, wie in Abb. 3, ist jedes Neuron nur mit Einheiten in der zeitlich gesehen nächsten Schicht verbunden, nicht mit Neuronen der gleichen Schicht oder zeitlich vorangehender Schichten. In Abb. 3 ist der Zeitablauf von links nach rechts durch den roten Pfeil gekennzeichnet. Es gibt auch sogenannte rekurrente und convolutional Netze, bei denen die Verbindungen komplexer sind. Die Grundidee bleibt jedoch die gleiche. Die mittlere Schicht in Abb. 3 wird als verdeckt bezeichnet, da sie im Gegensatz zu den Eingabe- und Ausgabeschichten keine direkte Verbindung zur Außenwelt aufweist.

Training und Lernen

Das so zusammengesetzte neuronale Netzwerk „lernt“, indem die einzelnen Gewichte angepasst werden, die zum Beispiel Ziffern zwischen -1,0 und +1,0 sind, wobei natürlich andere Werte möglich sind. Die Gewichte werden anhand eines bestimmten Trainingsalgorithmus angepasst.

Das Training eines neuronalen Netzwerk erfolgt üblicherweise folgendermaßen: Ein Satz von Eingabedaten wird in die Eingabeschicht des neuronalen Netzes gespeist. Danach fließen diese Eingaben je nach den Gewichten (Verbindungen) und Aktivierungsfunktionen durch das Netz zur Ausgabeschicht. Die Ausgabe der Ausgabeschicht wird dann anhand einer vorbestimmten Metrik mit der gewünschten Ausgabe verglichen. Je nach Differenz zwischen der tatsächlichen Ausgabe und der gewünschten Ausgabe werden dann die Gewichte im gesamten Netzwerk nach einem Algorithmus angepasst. Danach wird der gesamte Prozess wiederholt, üblicherweise mehrere Tausend bis Millionen Mal, bis die Ausgabe den Erwartungen entspricht. Es gibt zahlreiche Algorithmen zur Anpassung der Gewichte, auf deren Beschreibung hier jedoch verzichtet wird.

Ein Beispiel

Sehen wir uns nun als konkretes Beispiel ein relativ einfaches neuronales Netz zur Erkennung von handgeschriebenen Ziffern an. Beispiele möglicher Eingaben sind in Abb. 4 gezeigt. Ich habe dieses einfache Feedforward-Netz für Andrew Ngs Kurs auf Coursera, Machine Learning, programmiert. Ich kann den ausgezeichneten Online-Kurs nur wärmstens empfehlen.

Beispielhafte handschriftliche Eingabe

Abb. 4: Beispielhafte handschriftliche Eingabe

Die Architektur dieses neuronalen Netzes ist genau wie in Abb. 3 gezeigt, mit 400 Eingabeeinheiten, da die Bilddateien jeweils eine Größe von 20 x 20 grauen Pixeln (= 400 Pixel) haben. Die verdeckte Schicht besteht aus 25 Neuronen und die Ausgabeschicht aus 10 Neuronen, eines für jede Ziffer von 0 bis 9. Das bedeutet, dass es 10.000 Verbindungen (Gewichte) zwischen der Eingabeschicht und der verdeckten Schicht gibt (400 x 25) und 250 Verbindungen zwischen der verdeckten Schicht und der Ausgabeschicht gibt (25 x 10). Insgesamt hat das Netz also 10.250 Parameter! Für die technisch Interessierten, die Aktivierungsfunktion ist eine Sigmoidfunktion.

KNN zur Erkennung von handschriftlichen Ziffern

Abb. 5: KNN zur Erkennung von handschriftlichen Ziffern

Das Training erfolgte wie oben beschrieben. Ich gab Batches mit mehreren Tausend grauen 20×20-Bildern ein, wie in Abb. 4 gezeigt, und die Gewichte wurden mittels Backpropagation je nachdem angepasst, wie weit die Ausgabe von der tatsächlichen Ziffer von 0 bis 9 entfernt war. Das Ergebnis nach Abschluss des Lernvorgangs war erstaunlich, insbesondere angesichts der Tatsache, dass das ganze Programm nur aus ein paar Dutzend Codezeilen besteht.

Aber wie funktioniert es wirklich?

Es ist wirklich erstaunlich und auch etwas beängstigend, dass dieses Konzept so gut funktioniert, denn ich hatte nur die Aktivierungsfunktion, die einzelnen Neuronen und die Anzahl der Neuronen in jeder Schicht und deren Verbindungen programmiert und angegeben, dass die Gewichte über Backpropagation angepasst werden sollten. Das Programm tat den Rest. Wie funktioniert das Ganze also wirklich?

Autopsie eines neuronalen Netzes

Autopsie eines neuronalen Netzes

Ehrlich gesagt hatte ich auch nach einigen komplizierten wahrscheinlichkeitstheoretischen und statistischen Ensemble-Berechnungen keine Ahnung, warum diese relativ einfachen Schichten mit relativ einfachen Aktivierungsfunktionen es schafften, handschriftliche Ziffern zu erkennen, die nicht einmal besonders deutlich geschrieben waren. Deshalb habe ich das obige neuronale Netz nach erfolgreichem Training schichtweise „seziert“.

Die erste Menge an Gewichten zwischen der Eingabeschicht und der verdeckten Schicht fungiert quasi als Filter, die im Wesentlichen wichtige Muster oder Strukturen aus der Eingabe herausfiltern. Wenn man nur diese erste Gewichtsmenge grafisch darstellt, erhält man eine Grafik mit 25 „Filtern“, wie in Abb. 6 gezeigt. Diese Filter bilden die Eingabe auf die 25 verdeckten Neuronen in der mittleren, verdeckten Schicht ab. Abb. 7 zeigt das Ergebnis der Abbildung einer bestimmten Eingabe, in diesem Fall eine handschriftliche „0“, auf die verdeckte Schicht.

erster Satz von Gewichten

Abb. 6: Erster Satz von Gewichten, der als „Filter“ fungiert.

Abbildung einer 0 auf verdeckte Neuronen

Abb. 7: Abbildung einer 0 auf verdeckte Neuronen.

Die Ausgabe der verdeckten Schicht wird dann durch einen weiteren Filter geleitet, wie in Abb. 8 gezeigt, und schließlich über diesen Gewichtssatz auf die Ausgabeschicht abgebildet. Abb. 8 zeigt, wie die Ziffer „0“ richtig auf das Ausgabeneuron für die „0“ abgebildet wird (unten im Bild, da das Programm die Ziffern vertikal von 1 oben bis 9 und dann 0 unten anzeigt).

Abbildung einer Eingabe auf eine Ausgabe über eine verdeckte Schicht.

Abb. 8: Abbildung einer Eingabe, hier einer 0, auf eine Ausgabe über Faltungen der Gewichte über eine verdeckte Schicht.

Weitere Beispiele dieser Abbildung oder Filterung von Eingaben auf Ausgaben über die internen Gewichte sind in meinen Folien für ATA58 und in Fig. 9 visualisiert.

Mapping of input to output

Abb. 9: Abbildung einer Eingabe, hier einer 2, auf eine Ausgabe.

Nochmals, die internen Gewichte fungieren als eine Art Filter, um die interessierenden Merkmale herauszukristallisieren. Naiverweise hatte ich erwartet, dass diese Merkmale oder Muster bei handschriftlichen Ziffern vertikalen oder horizontalen Linien, zum Beispiel bei den Ziffern 1, 4 oder 7, oder verschiedenen Bögen oder Kreisen für Ziffern wie 3 oder 8 oder 0 entsprechen. Dies ist jedoch offensichtlich nicht der Fall, wie man aus der grafischen Darstellung der ersten Gewichte in Abb. 6 sehen kann. Die Strukturen, die das Netz herausfiltert, sind augenscheinlich viel komplexer als einfache Linien oder Bögen. Dies ist auch der Grund für den „Umweg“ über die verdeckte Schicht. Eine direkte Abbildung von der Eingabe auf die Ausgabe würde auch mit einer internen Faltung nicht ausreichen, alle zur Unterscheidung der einzelnen Ziffern notwendigen Informationen aus der Eingabe herauszuholen. Gleichermaßen sind für kompliziertere Aufgaben mehr als eine verdeckte Schicht notwendig. Die Anzahl der verdeckten Schichten und der Neuronen sowie deren Verbindungen/Gewichte wächst mit der Komplexität der Aufgabe.

Fazit

Ziel dieses Beitrags war, die innere Arbeitsweise eines einfachen neuronalen Netzwerks visuell zu erläutern. Neuronale Netze für andere Anwendungen, auch für die maschinelle Übersetzung, funktionieren im Prinzip sehr ähnlich. Natürlich haben diese Netze meist mehr als eine verdeckte Schicht, samt komplizierter Vor- und Nachbearbeitung von Eingabe- und Ausgabedaten, ausgeklügeltere Aktivierungsfunktionen und eine komplexere Architektur, wie rekurrente oder convolutional Netze. Das Grundprinzip bleibt jedoch gleich: Die zugrundeliegende Funktion eines künstlichen neuronalen Netzes ist ganz einfach die Mustererkennung. Nicht mehr und nicht weniger. Gut trainierte KNN können außerordentliche Leistungen erbringen, die oftmals die von Menschen weit übersteigen, da künstliche neuronale Netze weder ermüden noch die Konzentration verlieren. Allerdings sollte man nicht vergessen, dass sie ebenso außerordentlich schlechte Leistungen erbringen, wenn die gestellte Aufgabe über ihr Training hinausgeht. In diesen Fällen erkennen sie Muster, die eigentlich nicht vorhanden sind, und in anderen Fällen kann die Aufgabe einfach nicht in Form einer Mustererkennung gelöst werden, egal wie komplex die Muster sind. Anders ausgedrückt sind künstliche neuronale Netze sicher weit mehr als die Summe ihrer Programmzeilen, aber nie mehr als die Summe ihres Trainings. (Zumindest bis zur sogenannten technischen Singularität.)