Transcription
Hallo zusammen.
In diesem Video gehe ich auf die Struktur von neuronalen Netzen sowie auf die Neuronenansicht ein. Dazu zeige ich euch verschiedene Arten von Aktivierungsfunktionen, die man in neuronalen Netzen verwenden kann.
Zum Abschluss des Videos zeige ich euch ein kleines, leicht nachvollziehbares Beispiel. Ich bin sicher, jeder von euch hat schon mal ein neuronales Netz gesehen, welches so oder so ähnlich aussieht wie das hier gezeigte.
Jedes einzelne dieser farbigen Kreise steht für ein einzelnes Neuron und die weißen Linien für die Verbindung zwischen diesen Neuronen. Ich hatte den grundlegenden Aufbau eines solchen Netzes bereits in meinem Supervised Learning Video beschrieben, aber gehen wir es hier trotzdem noch einmal kurz durch.
Die Spalten an grünen Neuronen auf der linken Seite werden als Input-Layer bezeichnet. Wie der Name schon sagt, sind diese Neuronen für die Eingangswerte des neuronalen Netzes verantwortlich.
Die nächsten beiden orangenen Spalten von Neuronen werden als Hidden Layer 1 und 2 bezeichnet. "Hidden" kann mit "versteckt" oder "verborgen" übersetzt werden. Diese Neuronen, oder anders gesagt, die Werte dieser Neuronen in diesen Layern, sind in der Regel von außen nicht sichtbar und häufig nur schwer zu interpretieren.
Am Ende des neuronalen Netzes finden sich die Neuronen des Output-Layers, welches für die Ausgabe des neuronalen Netzes zuständig ist.
Betrachten wir solch ein neuronales Netz nun einmal Stück für Stück und beginnen ganz links mit einem grünen Neuron aus dem Input-Layer. In diesem Neuron sind die Eingangswerte des neuronalen Netzes, also die einzelnen Features \(X_i\), hinterlegt, wie hier etwa das Feature \(X_1\).
Die Ausgabe dieses Neurons, hier dargestellt durch den Pfeil rechts, ist eben dieses Feature \(X_1\) und hat meistens nicht nur ein einzelnes, sondern mehrere Features und entsprechend mehrere solcher Neuronen. Diese sind über die weißen Linien mit anderen Neuronen verbunden, wie hier mit einem orangenen Neuron aus einem Hidden Layer.
Die Features dienen als Eingangswerte für dieses Neuron. Die Features werden dabei zusätzlich mit Gewichten versehen. Ich komme später noch genauer auf diese Gewichte zu sprechen.
An dieser Stelle will ich aber bereits sagen, dass diese Gewichte die Parameter sind, die später beim Training des neuronalen Netzes optimiert werden.
In den zuvor gezeigten Modellen dieser Videoreihe habe ich für diese Parameter stets das Z-Symbol verwendet. Jedoch findet man in der Literatur zu neuronalen Netzen häufig die Bezeichnung "Gewichte" bzw. "Weights" mit dem Symbol \(W\). Da übernehme ich in diesem Video diese Notation.
Auf das Training von neuronalen Netzen gehe ich in einem späteren Video genauer ein.
Kommen wir aber nun zurück zur Betrachtung der Neuronen in jedem Layer.
Außer dem Output-Layer finden sich ein zusätzliches Neuron, das sogenannte Bias-Neuron. Theoretisch kann man auch neuronale Netze ohne Bias-Neuronen verwenden, aber das ist eher unüblich.
Das Bias-Neuron ist ebenfalls mit jedem Neuron im folgenden Layer verbunden, und da auch mit dem hier wieder dargestellten orangenen Neuron, weil auch hier der Wert \(X_0\) gewichtet wird.
Der Wert \(X_0\) ist aber kein Feature im eigentlichen Sinne, sondern wirklich ein Setzen, sodass effektiv nur das Gewicht \(W_0\) als zusätzlicher Eingangswert fungiert.
Das orangene Neuron hat jetzt nicht einfach nur einen Wert, der den Eingangswerten gebildet wird, sondern einen Funktionswert, der von \(Z\) abhängt, wobei \(Z\) die Summe der Eingangswerte aus den anderen Neuronen ist.
Die Funktion \(g\) wird auch als Aktivierungsfunktion bezeichnet und dient in erster Linie dazu, eine Nichtlinearität in das Modell einfließen zu lassen.
Auf die Bedeutung von Aktivierungsfunktionen und auch das Bias-Neuron komme ich in einem späteren Video noch zu sprechen.
Der Funktionswert \(g(Z)\) ist gleichzeitig auch der Ausgangswert des Neurons und dient somit als Eingangswert für weitere Neuronen, die mit diesem Neuron verbunden sind.
Er wird häufig auch als Aktivierung bzw. im Englischen "activation" bezeichnet.
Schauen wir uns im Folgenden einmal unterschiedliche Aktivierungsfunktionen an, dann wird auch die Verwendung des Begriffs "Aktivierung" in diesem Zusammenhang deutlicher.
Die einfachste Aktivierungsfunktion ist einfach eine lineare Funktion. Wie ich eben bereits sagte, dient die Aktivierungsfunktion dazu, eine gewisse Nichtlinearität in das Modell einfließen zu lassen. Daher wird die lineare Aktivierungsfunktion in der Regel nicht verwendet.
Betrachten wir nun einmal eine Runde mit einer linearen Aktivierungsfunktion. So wird der Eingangswert \(Z\) genauso wieder herausgegeben.
Deutlich interessanter ist die nächste Aktivierungsfunktion, die ReLU. Bei dieser Funktion ergeben alle Eingangswerte kleiner gleich 0 einen Funktionswert von 0 und alle Werte darüber einen Funktionswert von 1.
Dies ist auch noch einmal rechts beispielhaft an zwei einer Runde dargestellt.
Betrachten wir einmal das obere Neuron. So hat dieses bei einem Eingangswert von \(Z\) kleiner gleich 0 einen Ausgangswert von 0. Das heißt, dass eine Runde gewissermaßen deaktiviert ist, denn es hat keinerlei Einfluss auf die folgenden Neuronen.
Das lediglich den Wert 1 übergibt. Anders ist es beim unteren Neuron, welches bei einem Eingangswert von \(Z\) größer als 0 steht, es gibt eine 1 an die folgenden über. Diese 1 würde dann natürlich später noch mit einem Gewicht multipliziert.
In diesem Sinne kann man das eine Runde als aktiviert betrachten, da die Berechnung der folgenden beeinflusst.
Früher wurde meist eine logistische Aktivierungsfunktion verwendet, welche wir bereits aus der logistischen Regression kennen und die im Gegensatz zur Binary Step-Funktion einen Übergang zwischen dem Funktionswert 0 und 1 bildet.
Man kann diese Funktion in die hier dargestellten drei Teile gliedern.
Im blauen Teil, den ich etwa bei \(Z\) = -5 ansetze, liegt der Funktionswert nahe bei Null. Man kann also im weiteren Sinne hier auch von einem deaktivierten Neuron sprechen.
Im grünen Bereich der logistischen Funktion, der ab etwa \(Z\) größer 5 beginnt, liegt der Funktionswert nahe bei 1 und das Neuron ist gewissermaßen aktiviert.
Im orangefarbenen Bereich zwischen diesen beiden Werten liegt der Funktionswert \(g(Z)\) logischerweise im Bereich zwischen 0 und 1.
Wenn man im Terminus der Aktivierung von Neuronen bleiben möchte, könnte man hier sagen, dass das Neuron teilweise aktiviert ist.
Beachtet, dass ich die Werte -5 bzw. 5 hier etwas willkürlich gewählt habe. Dies sind keine festen Größen in der Literatur und dienen hier nur der Veranschaulichung der logistischen Funktion.
Eine Variante der logistischen Funktion ist die Funktion Tangens Hyperbolikus, welcher sich ebenfalls in drei Abschnitte gliedert.
Der Verlauf der Funktion endet der logistischen Funktion jedoch, liegt der Wertebereich der Funktion Tangens Hyperbolikus im Bereich -1 und 1 und nicht im Bereich 0 und 1.
Zudem steigt die Funktion etwas schneller an, weshalb ich die Grenzen bei etwa -3 bzw. 3 lege. Auch hier sind dies von mir selbst gewählte Werte und keine feststehenden Größen.
Zudem kann man bei dieser Funktion nicht wirklich von einer Deaktivierung des Neurons sprechen, da der Funktionswert in diesem Bereich -1 und eben nicht 0 beträgt.
Am Schluss möchte ich euch nun die heutzutage am häufigsten verwendete Aktivierungsfunktion ReLU vorstellen, was abgekürzt für "Rectified Linear Unit" steht.
Es hat sich herausgestellt, dass diese Funktion deutlich bessere Konvergenzeigenschaften beim Training eines neuronalen Netzes vorweist als die eben gezeigte und zuvor häufig verwendete logistische Funktion.
Auch bei dieser Funktion ergibt sich ein Funktionswert von 0 für alle Eingangswerte \(Z\) kleiner gleich 0. Für alle Eingangswerte \(Z\) größer als 0 handelt es sich bei ReLU um eine simple lineare Funktion, welche den Eingang wieder exakt so herausgibt.
Springen wir jetzt einmal zurück zu den Neuronen und klicken noch einmal auf das gesamte neuronale Netz.
Das eben gezeigte Beispiel mit den grünen Neuronen aus dem Input-Layer und den orangenen Neuronen aus einem Hidden Layer entspricht beispielhaft diesem Abschnitt aus dem neuronalen Netz.
Beachtet, dass Bias-Neuronen bei der Darstellung eines neuronalen Netzes in dieser Form im Allgemeinen nicht mit abgebildet werden.
Gehen wir nun einen Layer weiter, so ändert sich an der internen Berechnung der Neuronen im Grunde nichts.
Die Funktionswerte der Neuronen aus Layer 1 dienen inklusive der entsprechenden Gewichtung als Eingangswert für die Aktivierungsfunktion des Neurons in Layer 2.
Auch für den Output Layer ändert sich hier im Grunde nichts, aber werfen wir trotzdem noch einmal einen genaueren Blick darauf, da es sich um die Ausgabe des neuronalen Netzes handelt.
Die Summe der gewichteten Funktionswerte bzw. der Aktivierungswerte, den hohen inklusive des Bias-Neurons, werden aufaddiert und sind der Input \(\tilde{Z}\) der Aktivierungsfunktion \(g\).
Der Funktionswert \(g(\tilde{Z})\) ist dann sowohl der Ausgabewert des Neurons als auch die Ausgabe des neuronalen Netzes, welche sich hier einmal mit \(\tilde{Y}_1\) bezeichnet.
Geht man jetzt also das neuronale Netz von hinten bis vorne durch, gelangt man von den Eingaben, also den Features \(X_i\) aus den grünen Neuronen, hin zu den blauen Neuronen, welche die Ausgabe \(\tilde{Y}\) des neuronalen Netzes darstellen.
So lässt sich das gesamte neuronale Netz auch als Funktion darstellen. Wie das aussieht, zeige ich euch gleich.
Vorher möchte ich aber noch ein paar Sätze über die Struktur eines neuronalen Netzes verlieren.
Generell können sich in einem Layer beliebig viele Neuronen befinden. Das gilt sowohl für den Input-Layer, den Hidden Layer als auch für den Output-Layer.
Generell ist jedes Neuron mit jedem Neuron davor und dahinterliegenden Layer verbunden, wobei es aber auch Techniken gibt, gewisse Verbindungen oder Neuronen zu entfernen, respektive zu ignorieren.
Zudem ist bei klassischen neuronalen Netzen, wie es hier zu sehen ist, ein Neuron immer nur mit dem davor und dahinter liegenden Layer verbunden. Eine direkte Verbindung zwischen etwa Input und Hidden Layer 2 ist in diesem Fall nicht möglich.
Es gibt jedoch viele spezielle Arten von neuronalen Netzen, bei denen das Überspringen von Layern oder auch Verbindungen in den gleichen Layern möglich ist.
Der Index wird über die einzelnen Neuronen durchnummeriert, während das hoch 1 für den ersten Hidden Layer steht.
Auch diese Neuronen werden in einem Vektor \(A^{(1,2)}\) zusammengefasst.
Betrachten wir jetzt einmal das erste Neuron genauer. An dieser Stelle wiederhole ich mich irgendwie nicht, aber die Gleichungen sind an dieser Stelle noch einmal wichtig, um die gesamte Berechnung des neuronalen Netzes nachvollziehbar niederzuschreiben.
Die Gewichte \(W\) dieses Neurons erhalten einen zusätzlichen Index und ebenfalls eine hochgestellte 1. Der erste Index steht dabei für die Position des verbundenen Neurons im hinterlegenden Layer.
In diesem Beispiel ist das das gerade betrachtete Neuron \(A^{(1)}\). Der zweite Index steht für die Position des nachfolgenden Neurons im vorliegenden Layer, in diesem Fall das Neuron \(A^{(1)}\).
Die hochgestellte 1 steht wiederum für den ersten Hidden Layer.
Wie eben bereits gesehen, werden die Gewichte mit den jeweiligen Features multipliziert und anschließend summiert.
Die Gewichte füge ich anschließend einer Matrix \(W^{(1)}\) zu. An dieser Stelle sollten wir auch nicht das Bias-Neuron vergessen.
Wir wissen, die Gewichtung in einen Vektor \(B^{(1)}\) hinzufügen. In der Gleichung für das Neuron \(A^{(1)}\) fehlt dann nur noch die Anwendung der Aktivierungsfunktion \(g\).
Wie ihr seht, ist dies die gleiche Formel, die ihr bereits zu Beginn des Videos gesehen habt. Lediglich die Notation des Neurons \(A^{(1)}\) wurde hinzugefügt und es gibt ein paar mehr Indizes.
Exakt die gleichen Schritte können wir nun für die beiden verbliebenen Neuronen des ersten Layers durchführen und die entsprechenden Gewichte in die Matrix \(W\) und den Vektor \(B\) schreiben.
Mittels dieser Notation ist es jetzt möglich, die drei links dargestellten Funktionsgleichungen in einer einzelnen Funktionsgleichung zusammenzufassen.
Hierbei ist die Aktivierungsfunktion \(g\) so definiert, dass bei einem vektoriellen Eingangswert die Funktion auf jeden einzelnen Eintrag des Vektors angewendet wird.
So lässt sich der erste Berechnungsschritt in diesem neuronalen Netz zu der kleinen Funktionsgleichung rechts unten zusammenfassen.
Die gleichen Schritte können wir für den folgenden Layer anwenden. Zunächst multiplizieren wir die Gewichtsmatrix \(W^{(2)}\) mit den Werten aus dem ersten Layer \(A^{(1)}\).
Anschließend addieren wir auch hier die Gewichte aus den Verbindungen mit dem Bias-Neuron. Das Ergebnis dieser Berechnung ist wiederum der Eingangswert für die Aktivierungsfunktion \(g\).
Die Definition der Matrix \(W^{(2)}\) und des Vektors \(B^{(2)}\) habe ich hier noch einmal aufgeführt.
Betrachten wir nun einmal die Ausgabe unseres neuronalen Netzes. Fassen wir die Neuronen des Output-Layers zum Vektor \(\tilde{Y}\) zusammen.
Die Berechnung dieses Vektors erfolgt jetzt analog zu den beiden vorherigen. Auch hier habe ich einmal die Definition für die Matrix \(W^{(3)}\) und den Vektor \(B^{(3)}\) aufgeführt.
Sind übrigens auch unterschiedliche Aktivierungsfunktionen \(g\) in den einzelnen Layern möglich. Von der Notation her müsste man daher jeder Funktion noch einen zusätzlichen Index verpassen, worauf ich aber an dieser Stelle der Einfachheit halber verzichtet habe.
Zudem ist es eher ungewöhnlich, unterschiedliche Aktivierungsfunktionen in einem neuronalen Netz zu verwenden.
Wir könnten diese Funktionsgleichung anschließend von oben nach unten ineinander einsetzen und erhalten diese längere Funktionsgleichung für den Vektor \(\tilde{Y}\).
Das mag jetzt gar nicht so spektakulär aussehen, aber schließlich bedeutet das Folgendes: Das neuronale Netz auf der linken Seite lässt sich zu der einen geraden Funktionsgleichung auf der rechten Seite zusammenfassen.
Das bedeutet, ein neuronales Netz ist letztlich auch nichts anderes als eine Funktion mit einem Eingabewert \(X\), einem Ausgabewert \(\tilde{Y}\) und einer großen Menge an Parametern, an dieser Stelle versteckt in den Matrizen und den Vektoren \(B\).
Jedoch können die Funktionsvorschriften für neuronale Netze sehr umfangreich und komplex werden. Setzt das kleine neuronale Netz links, die Funktionsgleichung rechts, bereits recht lang und durch die ganzen Funktionsauswertungen der Aktivierungsfunktion \(g\) auch nicht wirklich leicht nachzuvollziehen.
Angesichts dessen verwendet man gerne die abstrakte Darstellung eines neuronalen Netzes, wie auf der linken Seite, und verzichtet auf die explizite Darstellung der Funktionsgleichung.
Allgemein kann die Funktionsgleichung für ein neuronales Netz wie folgt geschrieben werden, wobei \(n\) für die Anzahl der Neuronen steht.
Bleiben wir jetzt aber noch einmal kurz bei dem neuronalen Netz links und zählen einmal die Parameter aus.
Insgesamt befinden sich in diesem neuronalen Netz bzw. in der obigen Funktionsgleichung 29 Parameter. In dem Netz von Anfang des Videos waren es sogar 103 Parameter gewesen.
In der Regel verwendet man noch deutlich größere Netze mit einer noch viel größeren Anzahl an Parametern.
Zur Erinnerung: Diese Parameter werden später durch das Training optimiert, um die verwendeten Datenpunkte so exakt wie möglich abzubilden.
Die orange eingerahmte Funktionsgleichung ist, wenn wir einmal im Terminus der vorigen Videos bleiben, nichts anderes als die Modellfunktion \(f(X)\) des links dargestellten neuronalen Netzes.
Der Vektor \(W\) als Index der Modellfunktion ist so definiert, dass er alle Parameter des neuronalen Netzes beinhaltet. In diesem Fall wären das als ein Vektor mit 29 Einträgen.
Genauso lässt sich eine Kostenfunktion für das neuronale Netz definieren, worauf ich an dieser Stelle aber auch nicht genauer eingehen möchte.
Deshalb schreibe ich an dieser Stelle nur eine allgemeingültige Funktion, in der jetzt Input die ausgewertete Modellfunktion am Datenpunkt \(X_i\) sowie den \(Y\)-Wert \(Y_i\) des Datenpunktes übergeben wird.
Durch die große Anzahl an Parametern tendieren neuronale Netze schnell zum Overfitting. Das gleiche Phänomen haben wir bereits in vorigen Videos, beispielsweise bei der Polynomregression, beobachtet.
Eine Möglichkeit, Overfitting zu reduzieren, habe ich in meinem letzten Video vorgestellt.
Bei der Anwendung von neuronalen Netzen ist es da wichtig, eine Form der Regularisierung zu verwenden, weshalb ich dies hier in der Kostenfunktion mittels der Funktion mit den beiden hier dargestellten Funktionen.
Es ist nun möglich, neuronale Netze zu trainieren und damit die Parameter des Netzes so anzupassen, dass unbekannte Datenpunkte möglichst exakt vorhergesagt werden können.
Zum Abschluss des Videos stelle ich euch ein wirklich kleines, minimales Beispiel für ein neuronales Netz vor, welches sich leicht nachvollziehen lässt.
Ich habe dieses Beispiel aus dem Machine Learning Kurs von Andrew Ng übernommen.
Betrachten wir einmal dieses neuronale Netz mit zwei Input-Neuronen in grün und einem zugehörigen lila Neuron.
Es gibt keine Hidden Layer und der Input-Layer ist direkt mit dem einzigen Output-Layer verbunden.
Die durch dieses neuronale Netz repräsentierte Funktion hat also einen zweidimensionalen Input und einen skalaren Output.
Wir nehmen an, dass das Netz bereits trainiert wurde und ich gebe die Gewichte an den Verbindungen der Neuronen an. Dann lässt sich der Output \(\tilde{Y}\) des neuronalen Netzes durch die links oben gezeigte Gleichung bestimmen.
Als Aktivierungsfunktion verwenden wir eine logistische Funktion. Wir können jetzt eine solche Tabelle aufstellen, um den Output des neuronalen Netzes bei unterschiedlichen Inputs festzuhalten.
Zusätzlich wird angenommen, dass \(X_1\) und \(X_2\) lediglich die Werte 0 oder 1 annehmen können.
Beginnen wir nun einmal, unterschiedliche Werte einzusetzen und starten mit \(X_1\) und \(X_2 = 0\). Damit ergibt sich für \(\tilde{Y}_0\) der Funktionswert \(g(-30)\), welcher, wenn wir die untere Funktion betrachten, in etwa gleich Null ist.
Für \(X_1 = 0\) und \(X_2 = 1\) ergibt sich für \(\tilde{Y}\) der Funktionswert \(g(-10)\), welcher ebenfalls in etwa Null ist.
Das gleiche Ergebnis erhalten wir für den umgekehrten Fall \(X_1 = 1\) und \(X_2 = 0\).
Interessanter wird es jetzt für \(X_1\) und \(X_2 = 1\). Dann ist \(\tilde{Y}\) = 0, welcher ungefähr 1 ist.
Betrachtet man einmal die Werte für \(X_1\), \(X_2\) und \(\tilde{Y}\), so fällt auf, dass wir mit diesem neuronalen Netz eine Unverknüpfung modellieren.
Niemand würde natürlich auf diese Weise eine Unverknüpfung implementieren, was verdeutlicht einmal die Funktionsweise eines neuronalen Netzes und ist zudem leicht nachzuvollziehen, was meistens nur bei kleinen neuronalen Netzen möglich ist.
Wir können uns die Funktion links oben auch einmal in einem 3-dimensionalen Plot anschauen.
Die rote Kugel in der linken unteren Ecke liegt bei \(X_1\) und \(X_2 = 0\). Hier sehen wir auch noch einmal, dass der Funktionswert fast gleich Null ist.
Selbiges gilt für die beiden roten Kugeln für jeweils \(X_1\) und \(X_2 = 1\), der hat die andere Variable weiterhin gleich Null.
In der rechten oberen Ecke findet sich dann der Funktionswert \(f(1)\) und \(X_1 = 1\).
Schieben wir einmal die Z-Achse dort hinüber und drehen die Kamera ein wenig, wird auch deutlich, dass der Funktionswert hier dann hart zugleich 1 liegt.
Aus dieser Position lässt sich auch leichter die typische Form der logistischen Funktion erkennen.
In diesem Video habe ich euch die Grundlagen von neuronalen Netzen erläutert.
Vor allem in englischer Sprache gibt es auf YouTube noch viele weitere ausgezeichnete Videos über neuronale Netze. Eine Auswahl davon findet ihr in der Videobeschreibung.
In meinem nächsten Video zeige ich euch umfangreichere Beispiele für neuronale Netze.
Vielen Dank fürs Zuschauen und bis zum nächsten Mal!