Sonntag, 4. Februar 2018
Neuronale Netze - Künstliche Intelligenz Youtube: https://youtu.be/VEfV1abmqpU Die Künstliche Intelligenz (Author Dr. D. Selzer-McKenzie) Bei einem künstlichen neuronalen Netzwerk (gewöhnlich kurz neuronales Netzwerk genannt) handelt es sich um eine sich an biologischen Neuronen und Synapsen orientierende Abstraktion. Obwohl neuronale Netzwerke bereits seit Jahrzehnten erforscht werden, sind meines Erachtens viele Implementierungen neuronalen Netzwerkcodes allgemein nicht sehr gut erklärt. Ich erläutere, was künstliche neuronale Netzwerke sind, außerdem werde ich C#-Code für die Implementierung eines neuronalen Netzwerks vorstellen. Um einen besseren Eindruck davon zu bekommen, können Sie sich die beiden Abbildungen nachstehend ansehen. Sie können sich neuronale Netzwerke als numerische Eingabe-Ausgabemechanismen vorstellen. Das neuronale Netzwerk in erster Abbildung umfasst drei Eingaben x0, x1 und x2 mit den jeweiligen Werten 1.0, 2.0 und 3.0. Das neuronale Netzwerk beinhaltet zwei Ausgaben y0 und y1 mit den Werten 0.72 bzw. -0.88. In dem der ersten Abbildung dargestellten neuronalen Netzwerk gibt es eine Schicht sogenannter verdeckter Neuronen. Dieses Netzwerk kann als dreischichtiges, vollständig verbundenes Feedforward-Netzwerk mit drei Eingaben, zwei Ausgaben und vier verdeckten Neuronen beschrieben werden. Leider gibt es keine einheitliche Terminologie zu neuronalen Netzwerken. Die zweite Abbildung zeigt die Ausgabe des vorgestellten Demoprogramms. In dem neuronalen Netzwerk wird sowohl eine sigmoide Aktivierungsfunktion als auch eine Tanh-Aktivierungsfunktion verwendet. Diese Funktionen sind durch die beiden Gleichungen mit den griechischen Buchstaben phi in erster Abbildung angedeutet. Die Ausgaben eines neuronalen Netzwerks hängen von den Werten einer Reihe numerischer Gewichtungen und Biase ab. In diesem Beispiel gibt es insgesamt 26 Gewichtungen und Biase mit den Werten 0.10, 0.20 ... -5.00. Nachdem die Gewichtungs- und Biaswerte in das neuronale Netzwerk geladen wurden, lädt das Demoprogramm die drei Eingabewerte (1.0, 2.0, 3.0) und führt dann entsprechend den Nachrichten zu den Summen Eingabe-zu-Verdeckt und Verdeckt-zu-Ausgabe eine Reihe von Berechnungen durch. Zum Schluss zeigt das Demoprogramm die beiden Ausgabewerte an (0.72, -0.88). Ich werde Sie schrittweise durch das Programm führen, das die in der zweiten Abbildung gezeigte Ausgabe generiert hat. Hier werden gewisse Programmierkenntnisse vorausgesetzt, es wird jedoch nicht davon ausgegangen, dass Sie sich mit neuronalen Netzwerken auskennen. Das Demoprogramm ist in der Programmiersprache C# codiert, es sollte jedoch problemlos möglich sein, den Democode in einer anderen Sprache wie z. B. Visual Basic .NET oder Python umzugestalten. Bei dem vorgestellten Programm handelt es sich im Wesentlichen um ein Lernprogramm und eine Plattform zum eigenen Experimentieren. Praktische Probleme lassen sich mit diesem Programm nicht direkt lösen, ich werde Ihnen daher erläutern, wie Sie den Code erweitern können, um wichtige Probleme zu beheben. Sie werden hier sicher sehr interessante Informationen finden, und vielleicht können Sie mit den hier beschriebenen Programmiertechniken Ihre Coding-Fähigkeiten ausbauen. Aufbau eines Modells eines neuronalen Netzwerks Künstliche neuronale Netzwerke sind auf dem Verhalten biologischer neuronaler Netzwerke basierend aufgebaut. Die Kreise in der ersten stellen Neuronen dar, in denen eine Verarbeitung erfolgt, und die Pfeile stehen für den Informationsfluss sowie für numerische Werte, die sogenannten Gewichtungen. In vielen Situationen werden Eingabewerte direkt in Eingabeneuronen kopiert, ohne dass eine Gewichtung erfolgt, und sie werden auch direkt ohne jegliche Verarbeitung ausgegeben. Die erste tatsächliche Aktion erfolgt somit in den Neuronen der verdeckten Schicht. Nehmen wir an, dass die Eingabewerte 1.0, 2.0 und 3.0 von den Eingabeneuronen ausgegeben werden. In der ersten Abbildung sehen Sie einen Pfeil zur Darstellung eines Gewichtungswerts zwischen jedem der drei Eingabeneuronen und der vier verdeckten Neuronen. Nehmen wir an, die drei abgebildeten Gewichtungspfeile, die auf das oberste verdeckte Neuron zeigen, tragen die Bezeichnungen w00, w10 und w20. Bei dieser Notation stellt der erste Index den Index des Quelleneingabeneurons dar und der zweite Index den Index des verdeckten Zielneurons. Die Neuronenverarbeitung erfolgt in drei Schritten: Im ersten Schritt wird eine gewichtete Summe berechnet. Nehmen wir an, es gilt Folgendes: w00 = 0.1, w10 = 0.5 und w20 = 0.9. Die gewichtete Summe für das oberste verdeckte Neuron lautet wie folgt: (1.0)(0.1) + (2.0)(0.5) + (3.0)(0.9) = 3.8. Im zweiten Verarbeitungsschritt wird ein Biaswert hinzugefügt. Angenommen, der Biaswert beträgt -2.0. Die angepasste gewichtete Summe lautet dann: 3.8 + (-2.0) = 1.8. Im dritten Schritt wird auf die angepasste gewichtete Summe eine Aktivierungsfunktion angewandt. Nehmen wir an, bei der Aktivierungsfunktion handelt es sich um die durch 1.0 / (1.0 * Exp(-x)) definierte Sigmoidfunktion, wobei Exp für die Exponentialfunktion steht. Die Ausgabe des verdeckten Neurons lautet dann 1.0 / (1.0 * Exp(-1.8)) = 0.86. Diese Ausgabe wird nun Teil der gewichteten Summe, die in jedes Neuron der Ausgabeschicht eingegeben wird. In Abbildung 1 ist dieser drei Schritte umfassende Prozess durch die Gleichung mit dem griechischen Buchstaben phi angedeutet: Es werden gewichtete Summen (xw) berechnet, ein Bias (b) wird hinzugefügt, und eine Aktivierungsfunktion (phi) wird angewandt. Nach Berechnung der Werte für alle verdeckten Neuronen werden die Werte für die Neuronen der Ausgabeschicht auf dieselbe Weise berechnet. Für die Berechnung der Werte der Ausgabeneuronen kann dieselbe Aktivierungsfunktion verwendet werden wie bei der Berechnung der Werte der verdeckten Neuronen, es kann aber auch eine andere Aktivierungsfunktion eingesetzt werden. In dem in der zweiten dargestellten Demoprogramm wird als Verdeckt-zu-Ausgabe-Aktivierungsfunktion die hyperbolisch-tangente Funktion verwendet. Nachdem die Werte für alle Neuronen der Ausgabeschicht berechnet wurden, werden diese Werte in den meisten Situationen weder gewichtet noch verarbeitet, sondern einfach als endgültige Ausgabewerte des neuronalen Netzwerks ausgegeben. Interne Struktur Grundlegend für das Verständnis der hier dargestellten Implementierung eines neuronalen Netzes ist eine genaue Betrachtung von der dritten Abbildung. Auf den ersten Blick mag diese Abbildung extrem kompliziert erscheinen. Sie können mir aber glauben, das Ganze ist nicht annähernd so kompliziert, wie es zunächst scheint. In der dritten Abbildung sind insgesamt acht Arrays und zwei Matrizen dargestellt. Der erste Array trägt die Bezeichnung this.inputs. In diesem Array sind die Eingabewerte des neuronalen Netzwerks, in diesem Beispiel 1.0, 2.0 und 3.0 enthalten. Als Nächstes kommt die Gruppe der Gewichtungswerte, mit denen die Werte in der sogenannten verdeckten Schicht berechnet werden. Diese Gewichtungen sind in einer 3 x 4-Matrix mit der Bezeichnung i-h weights (E-V-Gewichtungen) gespeichert. E-V steht dabei für Eingabe-zu-Verdeckt. Beachten Sie in der ersten Abbildung, dass die Demoversion des neuronalen Netzwerks vier verdeckte Neuronen umfasst. Die Zeilenanzahl in der Matrix i-h weights (E-V-Gewichtungen) entspricht der Eingabenanzahl und die Spaltenanzahl der Anzahl verdeckter Neuronen. Die Abbildung vier zeigt die interne SAtruktur des neuronalen Netzes. Das Array mit der Bezeichnung i-h sums (E-V-Summen) ist ein Arbeitsarray für die Berechnung. Die Länge des Arrays i-h sums (E-V-Summen) entspricht immer der Anzahl verdeckter Neuronen (vier in diesem Beispiel). Das nächste Array trägt die Bezeichnung i-h-biases (E-V-Biase). Biase in neuronalen Netzen sind zusätzliche Gewichtungen zur Berechnung der Neuronen in den verdeckten Schichten und Ausgabeschichten. Die Länge des Arrays i-h biases (E-V-Biase) entspricht der Länge des Arrays i-h-sums (E-V-Summen), die wiederum der Anzahl verdeckter Neuronen entspricht. Das Array mit der Bezeichnung i-h outputs (E-V-Ausgaben) stellt ein Zwischenergebnis dar. Die Werte in diesem Array werden als Eingaben für die nächste Schicht verwendet. Die Länge des Arrays i-h sums (E-V-Summe) entspricht der Anzahl verdeckter Neuronen. Als Nächstes kommt eine Matrix mit der Bezeichnung h-o weights (V-A-Gewichtungen). Dabei steht V-A für Verdeckt-zu-Ausgabe. Die Matrix h-o weights (V-A-Gewichtungen) hat hier die Größe 4 x 2, da es vier verdeckte Neuronen und zwei Ausgaben gibt. Die Länge der Arrays h-o sums, h-o biases und this.outputs entspricht der Ausgabenanzahl (zwei in diesem Beispiel). Im Array mit der Bezeichnung weights (Gewichtungen) unten in der dritten Abbildung sind alle Eingabe-zu-Verdeckt- und Verdeckt-zu-Ausgabe-Gewichtungen und -Biase aufgeführt. In diesem Beispiel weist das Gewichtungsarray die folgende Länge auf: (3 * 4) + 4 + (4 * 2) + 2 = 26. Allgemein gilt: Ist Ni die Anzahl der Eingabewerte (number of input values), Nh die Anzahl verdeckter Neuronen (number of hidden neurons) und No die Anzahl der Ausgaben (number of outputs), lautet die Länge des Gewichtungsarrays wie folgt: Nw = (Ni * Nh) + Nh + (Nh * No) + No. Berechnung der Ausgaben Nachdem die im vorherigen Abschnitt beschriebenen acht Arrays und zwei Matrizen erstellt wurden, kann ein neuronales Netz anhand der Eingaben, Gewichtungen und Biase die Ausgabe berechnen. Im ersten Schritt werden die Eingabewerte in das Array this.inputskopiert. Im nächsten Schritt werden dem Gewichtungsarray Werte zugewiesen. Für die Demo können Sie beliebige Gewichtungswerte verwenden. Als Nächstes werden die Werte aus dem Gewichtungsarray in die Matrix i-h-weights (E-V-Gewichtungen), das Array i-h-biases (E-V-Biase), die Matrix h-o-weights (V-A-Gewichtungen) und das Array h-o-biases (V-A-Biase) kopiert. Diese Beziehung soll in der dritten Abbildung veranschaulicht werden. Die Werte im Array i-h sums (E-V-Summen) werden in zwei Schritten berechnet. Im ersten Schritt werden die gewichteten Summen berechnet. Zu diesem Zweck werden die Werte im Eingabearray (inputs) mit den Werten in der entsprechenden Spalte der Matrix i-h weights (E-V-Gewichtungen) multipliziert. So werden beispielsweise für die gewichtete Summe für das verdeckte Neuron [3] (bei dem ich eine nullbasierte Indexierung verwende) jeder Eingabewert und die Werte in Spalte [3] der Matrix i-h weights (E-V-Gewichtungen) verwendet: (1.0)(0.4) + (2.0)(0.8) + (3.0)(1.2) = 5.6. Im zweiten Schritt bei der Berechnung von E-V-Summenwerten wird dm aktuellen E-V-Summenwert jeder einzelne Biaswert hinzugefügt. Ein Beispiel: Da i-h biases (E-V-Biase) [3] den Wert -7.0 hat, lautet der Wert von i-h sums (E-V-Summen) [3] 5.6 + (-7.0) = -1.4. Nachdem alle Werte im Array i-h sums (E-V-Summen) berechnet wurden, wird die Eingabe-zu-Verdeckt-Aktivierungsfunktion auf die Summen angewandt. Daraus ergeben sich die Eingabe-zu-Verdeckt-Ausgabewerte. Es gibt viele mögliche Aktivierungsfunktionen. Die einfachste Aktivierungsfunktion wird als Schrittfunktion bezeichnet. Bei dieser Funktion wird einfach für jeden Eingabewert größer Null 1.0 und für jeden Eingabewert kleiner oder gleich Null 0.0 zurückgegeben. Eine andere häufig eingesetzte Aktivierungsfunktion, die auch in diesem Artikel verwendet wird, ist die Sigmoidfunktion. Diese ist wie folgt definiert: f(x) = 1.0 / (1.0 * Exp(-x)). Die Kurve der Sigmoidfunktion ist in Abbildung 4 dargestellt. Die Sigmoidfunktion Beachten Sie, dass die Sigmoidfunktion einen Wert im Bereich größer Null und kleiner Eins zurückgibt. In unserem Beispiel gilt Folgendes: Wenn der Wert für i-h sums(E-V-Summen) [3] nach Hinzufügen des Biaswerts -1.4 lautet, erhält i-h outputs (E-V-Ausgaben) [3] den Wert 1.0 / (1.0 * Exp(-(-1.4))) = 0.20. Nachdem alle Eingabe-zu-Verdeckt-Ausgabeneuronenwerte berechnet wurden, werden diese Werte als Eingaben für die Berechnung der Neuronen der Verdeckt-zu-Ausgabe-Schicht verwendet. Diese Berechnungen funktionieren wie die Eingabe-zu-Verdeckt-Berechnungen: Es werden vorab gewichtete Summen berechnet, Biase hinzugefügt und anschließend wird eine Aktivierungsfunktion angewandt. In diesem Beispiel verwende ich eine hyperbolische Tangentenfunktion, kurz Tanh-Funktion genannt, für die Verdeckt-zu-Ausgabe-Aktivierungsfunktion. Die Tanh-Funktion ist der Sigmoidfunktion sehr ähnlich. Die Kurve der Tanh-Funktion weist eine ähnliche S-Form wie die Kurve der Sigmoidfunktion auf, die Tanh-Funktion gibt jedoch einen Wert im Bereich (-1,1) und nicht im Bereich (0,1) zurück. Kombinieren von Gewichtungen und Biasen Keine der Implementierungen neuronaler Netzwerke, die ich im Internet gesehen habe, wahrt getrennte Gewichtungs- und Biasarrays. Stattdessen werden die Gewichtungen und Biase in der Gewichtungsmatrix kombiniert. Wie ist dies möglich? Denken Sie daran, dass die Berechnung des Werts des Eingabe-zu-Verdeckt-Neurons [3] (i0 * w03) + (i1 * w13) + (i2 * w23) + b3 entsprach, wobei i0 den Eingabewert [0] hat, w03 die Gewichtung für die Eingabe [0] und Neuron [3] und b3 der Biaswert für das Verdeckt-Neuron [3] ist. Wenn Sie eine zusätzliche, gefälschte Eingabe [4] mit einem Platzhalterwert von 1,0 und eine zusätzliche Gewichtungszeile für die Biaswerte erstellen, ändert sich die zuvor beschriebene Berechnung folgendermaßen: (i0 * w03) + (i1 * w13) + (i2 * w23) + (i3 * w33), wobei i3 der Platzhaltereingabewert 1.0 und w33 der Bias ist. Das Argument für diesen Ansatz besteht darin, dass dieser das neuronale Netzwerkmodell vereinfacht. Ich bin anderer Meinung. Meiner Meinung nach ist ein neuronales Netzwerkmodell durch die Kombination von Gewichtungen und Biasen schwieriger zu verstehen, und die Implementierung ist fehleranfälliger. Anscheinend bin ich jedoch der einzige, der diese Meinung vertritt. Sie sollten daher Ihre eigene Entwurfsentscheidung treffen. Implementierung Ich habe das in den Abbildungen 1, 2 und 3 gezeigte neuronale Netzwerk mittels Visual Studio implementiert. Ich habe eine C#-Konsolenanwendunge namens NeuralNetworks erstellt. Im Projektmappen-Explorer-Fenster habe ich mit der rechten Maustaste auf die Datei Program.cs geklickt und diese zu NeuralNetworksProgram.cs umbenannt. Dadurch wurde auch der vorlagengenerierte Klassenname zu NeuralNetworksProgram geändert.
Neuronale Netze - Künstliche Intelligenz
Youtube: https://youtu.be/VEfV1abmqpU
Die Künstliche Intelligenz (Author Dr. D. Selzer-McKenzie)
Bei einem künstlichen neuronalen Netzwerk
(gewöhnlich kurz neuronales Netzwerk genannt) handelt es sich
um eine sich an biologischen Neuronen und Synapsen orientierende
Abstraktion. Obwohl neuronale Netzwerke bereits seit Jahrzehnten
erforscht werden, sind meines Erachtens viele Implementierungen
neuronalen Netzwerkcodes allgemein nicht sehr gut erklärt.
Ich erläutere, was künstliche neuronale Netzwerke sind, außerdem
werde ich C#-Code für die Implementierung eines
neuronalen Netzwerks vorstellen.
Um einen besseren Eindruck davon zu bekommen, können Sie
sich die beiden Abbildungen nachstehend ansehen. Sie können
sich neuronale Netzwerke als numerische Eingabe-Ausgabemechanismen
vorstellen. Das neuronale Netzwerk in erster Abbildung umfasst
drei Eingaben x0, x1 und x2 mit den jeweiligen
Werten 1.0, 2.0 und 3.0. Das neuronale Netzwerk beinhaltet
zwei Ausgaben y0 und y1 mit den Werten 0.72 bzw. -0.88.
In dem der ersten Abbildung dargestellten neuronalen Netzwerk
gibt es eine Schicht sogenannter verdeckter Neuronen.
Dieses Netzwerk kann als dreischichtiges, vollständig
verbundenes Feedforward-Netzwerk mit drei Eingaben,
zwei Ausgaben und vier verdeckten Neuronen beschrieben
werden. Leider gibt es keine einheitliche Terminologie
zu neuronalen Netzwerken.
Die zweite Abbildung zeigt die Ausgabe des vorgestellten Demoprogramms.
In dem neuronalen Netzwerk wird sowohl eine sigmoide Aktivierungsfunktion
als auch eine Tanh-Aktivierungsfunktion verwendet. Diese Funktionen
sind durch die beiden Gleichungen mit den griechischen
Buchstaben phi in erster Abbildung angedeutet. Die Ausgaben eines
neuronalen Netzwerks hängen von den Werten einer Reihe
numerischer Gewichtungen und Biase ab. In diesem Beispiel gibt
es insgesamt 26 Gewichtungen und Biase mit den
Werten 0.10, 0.20 ... -5.00. Nachdem die Gewichtungs- und Biaswerte
in das neuronale Netzwerk geladen wurden, lädt das Demoprogramm
die drei Eingabewerte (1.0, 2.0, 3.0) und führt dann entsprechend
den Nachrichten zu den Summen Eingabe-zu-Verdeckt und Verdeckt-zu-Ausgabe
eine Reihe von Berechnungen durch. Zum Schluss zeigt das
Demoprogramm die beiden Ausgabewerte an (0.72, -0.88).
Ich werde Sie schrittweise durch das Programm führen,
das die in der zweiten Abbildung gezeigte Ausgabe generiert hat.
Hier werden gewisse Programmierkenntnisse vorausgesetzt, es
wird jedoch nicht davon ausgegangen, dass Sie sich mit neuronalen
Netzwerken auskennen. Das Demoprogramm ist in der
Programmiersprache C# codiert, es sollte jedoch problemlos
möglich sein, den Democode in einer anderen Sprache wie z. B. Visual Basic .NET
oder Python umzugestalten. Bei dem vorgestellten Programm handelt
es sich im Wesentlichen um ein Lernprogramm und eine Plattform
zum eigenen Experimentieren. Praktische Probleme lassen sich mit
diesem Programm nicht direkt lösen, ich werde Ihnen daher
erläutern, wie Sie den Code erweitern können, um wichtige Probleme
zu beheben. Sie werden hier sicher sehr interessante Informationen
finden, und vielleicht können Sie mit den hier beschriebenen
Programmiertechniken Ihre Coding-Fähigkeiten ausbauen.
Aufbau eines Modells eines neuronalen Netzwerks
Künstliche neuronale Netzwerke sind auf dem Verhalten biologischer
neuronaler Netzwerke basierend aufgebaut. Die Kreise in der
ersten stellen Neuronen dar, in denen eine Verarbeitung erfolgt,
und die Pfeile stehen für den Informationsfluss sowie für
numerische Werte, die sogenannten Gewichtungen. In vielen Situationen
werden Eingabewerte direkt in Eingabeneuronen kopiert, ohne dass
eine Gewichtung erfolgt, und sie werden auch direkt ohne jegliche
Verarbeitung ausgegeben. Die erste tatsächliche Aktion erfolgt
somit in den Neuronen der verdeckten Schicht. Nehmen wir an,
dass die Eingabewerte 1.0, 2.0 und 3.0 von den Eingabeneuronen ausgegeben
werden. In der ersten Abbildung sehen Sie einen Pfeil zur Darstellung
eines Gewichtungswerts zwischen jedem der drei Eingabeneuronen und
der vier verdeckten Neuronen. Nehmen wir an, die drei abgebildeten
Gewichtungspfeile, die auf das oberste verdeckte Neuron zeigen,
tragen die Bezeichnungen w00, w10 und w20. Bei dieser Notation
stellt der erste Index den Index des Quelleneingabeneurons dar
und der zweite Index den Index des verdeckten Zielneurons.
Die Neuronenverarbeitung erfolgt in drei Schritten: Im ersten Schritt
wird eine gewichtete Summe berechnet. Nehmen wir an, es
gilt Folgendes: w00 = 0.1, w10 = 0.5 und w20 = 0.9. Die gewichtete
Summe für das oberste verdeckte Neuron lautet
wie folgt: (1.0)(0.1) + (2.0)(0.5) + (3.0)(0.9) = 3.8. Im zweiten
Verarbeitungsschritt wird ein Biaswert hinzugefügt. Angenommen, der
Biaswert beträgt -2.0. Die angepasste gewichtete Summe
lautet dann: 3.8 + (-2.0) = 1.8. Im dritten Schritt wird auf die
angepasste gewichtete Summe eine Aktivierungsfunktion angewandt. Nehmen
wir an, bei der Aktivierungsfunktion handelt es sich um
die durch 1.0 / (1.0 * Exp(-x)) definierte Sigmoidfunktion, wobei Exp für
die Exponentialfunktion steht. Die Ausgabe des verdeckten Neurons
lautet dann 1.0 / (1.0 * Exp(-1.8)) = 0.86. Diese Ausgabe wird nun Teil
der gewichteten Summe, die in jedes Neuron der Ausgabeschicht
eingegeben wird. In Abbildung 1 ist dieser drei Schritte umfassende
Prozess durch die Gleichung mit dem griechischen Buchstaben phi angedeutet:
Es werden gewichtete Summen (xw) berechnet, ein Bias (b) wird hinzugefügt,
und eine Aktivierungsfunktion (phi) wird angewandt.
Nach Berechnung der Werte für alle verdeckten Neuronen werden die Werte
für die Neuronen der Ausgabeschicht auf dieselbe Weise berechnet. Für die
Berechnung der Werte der Ausgabeneuronen kann dieselbe Aktivierungsfunktion
verwendet werden wie bei der Berechnung der Werte der verdeckten Neuronen,
es kann aber auch eine andere Aktivierungsfunktion eingesetzt werden.
In dem in der zweiten dargestellten Demoprogramm wird als
Verdeckt-zu-Ausgabe-Aktivierungsfunktion die hyperbolisch-tangente
Funktion verwendet. Nachdem die Werte für alle Neuronen der Ausgabeschicht
berechnet wurden, werden diese Werte in den meisten Situationen weder
gewichtet noch verarbeitet, sondern einfach als endgültige Ausgabewerte
des neuronalen Netzwerks ausgegeben.
Interne Struktur
Grundlegend für das Verständnis der hier dargestellten Implementierung
eines neuronalen Netzes ist eine genaue Betrachtung von der dritten Abbildung.
Auf den ersten Blick mag diese Abbildung extrem kompliziert erscheinen.
Sie können mir aber glauben, das Ganze ist nicht annähernd so kompliziert,
wie es zunächst scheint. In der dritten Abbildung sind insgesamt acht
Arrays und zwei Matrizen dargestellt. Der erste Array trägt
die Bezeichnung this.inputs. In diesem Array sind die Eingabewerte
des neuronalen Netzwerks, in diesem Beispiel 1.0, 2.0 und 3.0 enthalten.
Als Nächstes kommt die Gruppe der Gewichtungswerte, mit denen die Werte
in der sogenannten verdeckten Schicht berechnet werden. Diese
Gewichtungen sind in einer 3 x 4-Matrix mit der
Bezeichnung i-h weights (E-V-Gewichtungen) gespeichert.
E-V steht dabei für Eingabe-zu-Verdeckt. Beachten Sie in der
ersten Abbildung, dass die Demoversion des neuronalen Netzwerks
vier verdeckte Neuronen umfasst. Die Zeilenanzahl in der
Matrix i-h weights (E-V-Gewichtungen) entspricht der Eingabenanzahl
und die Spaltenanzahl der Anzahl verdeckter Neuronen.
Die Abbildung vier zeigt die interne SAtruktur des neuronalen Netzes.
Das Array mit der Bezeichnung i-h sums (E-V-Summen) ist ein Arbeitsarray
für die Berechnung. Die Länge des Arrays i-h sums (E-V-Summen)
entspricht immer der Anzahl verdeckter Neuronen (vier in diesem Beispiel).
Das nächste Array trägt die Bezeichnung i-h-biases (E-V-Biase).
Biase in neuronalen Netzen sind zusätzliche Gewichtungen zur Berechnung der
Neuronen in den verdeckten Schichten und Ausgabeschichten. Die Länge des
Arrays i-h biases (E-V-Biase) entspricht der Länge des
Arrays i-h-sums (E-V-Summen), die wiederum der Anzahl
verdeckter Neuronen entspricht.
Das Array mit der Bezeichnung i-h outputs (E-V-Ausgaben) stellt
ein Zwischenergebnis dar. Die Werte in diesem Array werden als Eingaben
für die nächste Schicht verwendet. Die Länge des Arrays i-h sums (E-V-Summe)
entspricht der Anzahl verdeckter Neuronen.
Als Nächstes kommt eine Matrix mit der Bezeichnung h-o weights (V-A-Gewichtungen).
Dabei steht V-A für Verdeckt-zu-Ausgabe. Die Matrix h-o weights (V-A-Gewichtungen)
hat hier die Größe 4 x 2, da es vier verdeckte Neuronen und zwei Ausgaben gibt.
Die Länge der Arrays h-o sums, h-o biases und this.outputs entspricht der
Ausgabenanzahl (zwei in diesem Beispiel).
Im Array mit der Bezeichnung weights (Gewichtungen) unten in der dritten
Abbildung sind alle Eingabe-zu-Verdeckt- und Verdeckt-zu-Ausgabe-Gewichtungen
und -Biase aufgeführt. In diesem Beispiel weist das Gewichtungsarray die
folgende Länge auf: (3 * 4) + 4 + (4 * 2) + 2 = 26. Allgemein gilt:
Ist Ni die Anzahl der Eingabewerte (number of input values), Nh die Anzahl
verdeckter Neuronen (number of hidden neurons) und No die Anzahl der
Ausgaben (number of outputs), lautet die Länge des Gewichtungsarrays
wie folgt: Nw = (Ni * Nh) + Nh + (Nh * No) + No.
Berechnung der Ausgaben
Nachdem die im vorherigen Abschnitt beschriebenen acht Arrays und zwei
Matrizen erstellt wurden, kann ein neuronales Netz anhand der Eingaben,
Gewichtungen und Biase die Ausgabe berechnen. Im ersten Schritt werden die
Eingabewerte in das Array this.inputskopiert. Im nächsten Schritt werden dem
Gewichtungsarray Werte zugewiesen. Für die Demo können Sie beliebige Gewichtungswerte
verwenden. Als Nächstes werden die Werte aus dem Gewichtungsarray in die
Matrix i-h-weights (E-V-Gewichtungen), das Array i-h-biases (E-V-Biase),
die Matrix h-o-weights (V-A-Gewichtungen) und das Array h-o-biases (V-A-Biase) kopiert.
Diese Beziehung soll in der dritten Abbildung veranschaulicht werden.
Die Werte im Array i-h sums (E-V-Summen) werden in zwei Schritten berechnet.
Im ersten Schritt werden die gewichteten Summen berechnet. Zu diesem Zweck
werden die Werte im Eingabearray (inputs) mit den Werten in der entsprechenden
Spalte der Matrix i-h weights (E-V-Gewichtungen) multipliziert. So werden
beispielsweise für die gewichtete Summe für das verdeckte Neuron [3]
(bei dem ich eine nullbasierte Indexierung verwende) jeder Eingabewert und die
Werte in Spalte [3] der Matrix i-h weights (E-V-Gewichtungen)
verwendet: (1.0)(0.4) + (2.0)(0.8) + (3.0)(1.2) = 5.6. Im zweiten Schritt
bei der Berechnung von E-V-Summenwerten wird dm aktuellen E-V-Summenwert
jeder einzelne Biaswert hinzugefügt. Ein Beispiel:
Da i-h biases (E-V-Biase) [3] den Wert -7.0 hat, lautet der Wert
von i-h sums (E-V-Summen) [3] 5.6 + (-7.0) = -1.4.
Nachdem alle Werte im Array i-h sums (E-V-Summen) berechnet wurden,
wird die Eingabe-zu-Verdeckt-Aktivierungsfunktion auf die Summen angewandt.
Daraus ergeben sich die Eingabe-zu-Verdeckt-Ausgabewerte. Es gibt viele
mögliche Aktivierungsfunktionen. Die einfachste Aktivierungsfunktion wird als
Schrittfunktion bezeichnet. Bei dieser Funktion wird einfach für jeden
Eingabewert größer Null 1.0 und für jeden Eingabewert kleiner oder
gleich Null 0.0 zurückgegeben. Eine andere häufig eingesetzte
Aktivierungsfunktion, die auch in diesem Artikel verwendet wird, ist die
Sigmoidfunktion. Diese ist wie folgt definiert: f(x) = 1.0 / (1.0 * Exp(-x)).
Die Kurve der Sigmoidfunktion ist in Abbildung 4 dargestellt.
Die Sigmoidfunktion
Beachten Sie, dass die Sigmoidfunktion einen Wert im Bereich größer Null
und kleiner Eins zurückgibt. In unserem Beispiel gilt Folgendes:
Wenn der Wert für i-h sums(E-V-Summen) [3] nach Hinzufügen des
Biaswerts -1.4 lautet, erhält i-h outputs (E-V-Ausgaben) [3]
den Wert 1.0 / (1.0 * Exp(-(-1.4))) = 0.20.
Nachdem alle Eingabe-zu-Verdeckt-Ausgabeneuronenwerte berechnet wurden, werden
diese Werte als Eingaben für die Berechnung der Neuronen der Verdeckt-zu-Ausgabe-Schicht
verwendet. Diese Berechnungen funktionieren wie die Eingabe-zu-Verdeckt-Berechnungen:
Es werden vorab gewichtete Summen berechnet, Biase hinzugefügt und anschließend
wird eine Aktivierungsfunktion angewandt. In diesem Beispiel verwende ich eine
hyperbolische Tangentenfunktion, kurz Tanh-Funktion genannt, für die
Verdeckt-zu-Ausgabe-Aktivierungsfunktion. Die Tanh-Funktion ist der
Sigmoidfunktion sehr ähnlich. Die Kurve der Tanh-Funktion weist eine
ähnliche S-Form wie die Kurve der Sigmoidfunktion auf, die Tanh-Funktion gibt
jedoch einen Wert im Bereich (-1,1) und nicht im Bereich (0,1) zurück.
Kombinieren von Gewichtungen und Biasen
Keine der Implementierungen neuronaler Netzwerke, die ich im Internet gesehen habe,
wahrt getrennte Gewichtungs- und Biasarrays. Stattdessen werden die Gewichtungen
und Biase in der Gewichtungsmatrix kombiniert. Wie ist dies möglich? Denken Sie
daran, dass die Berechnung des Werts des
Eingabe-zu-Verdeckt-Neurons [3] (i0 * w03) + (i1 * w13) + (i2 * w23) + b3 entsprach,
wobei i0 den Eingabewert [0] hat, w03 die Gewichtung für die Eingabe [0] und
Neuron [3] und b3 der Biaswert für das Verdeckt-Neuron [3] ist. Wenn Sie eine
zusätzliche, gefälschte Eingabe [4] mit einem Platzhalterwert von 1,0 und eine
zusätzliche Gewichtungszeile für die Biaswerte erstellen, ändert sich die
zuvor beschriebene Berechnung folgendermaßen:
(i0 * w03) + (i1 * w13) + (i2 * w23) + (i3 * w33), wobei i3 der
Platzhaltereingabewert 1.0 und w33 der Bias ist. Das Argument für diesen
Ansatz besteht darin, dass dieser das neuronale Netzwerkmodell vereinfacht.
Ich bin anderer Meinung. Meiner Meinung nach ist ein neuronales Netzwerkmodell
durch die Kombination von Gewichtungen und Biasen schwieriger zu verstehen,
und die Implementierung ist fehleranfälliger. Anscheinend bin ich jedoch
der einzige, der diese Meinung vertritt. Sie sollten daher Ihre eigene
Entwurfsentscheidung treffen.
Implementierung
Ich habe das in den Abbildungen 1, 2 und 3 gezeigte neuronale Netzwerk
mittels Visual Studio implementiert. Ich habe eine C#-Konsolenanwendunge namens
NeuralNetworks erstellt. Im Projektmappen-Explorer-Fenster habe ich mit der
rechten Maustaste auf die Datei Program.cs geklickt und diese
zu NeuralNetworksProgram.cs umbenannt. Dadurch wurde auch der vorlagengenerierte
Klassenname zu NeuralNetworksProgram geändert.
Abonnieren
Kommentare zum Post (Atom)
Keine Kommentare:
Kommentar veröffentlichen
Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.