Startseite
  Über...
  Archiv
  Gästebuch
  Kontakt
  Abonnieren


http://myblog.de/mycode

Gratis bloggen bei
myblog.de





Simples Neuronales Netz Teil 2

In diesem Teil geht es um etwas in die Materie.
Ich werde einen Pseudocode schreiben und
erklärenwie genau das ganze aufgebaut sein kann.

Zunächst einmal:
Ich nutze als Aktivierungsfunktiondie Tangens Hyperbolicus.
Er ist relativ leicht abzuleitenund ermöglicht, im Gegensatz zur Sigmoid-Funktion, dem Netznegative Werte zu produzieren.

Als Trainingsbeispiel nehmen wir den Sinus, daes hierbei pro Zeitschritt nur einen Eingang und einen Ausgang erzeugt und relativ einfach ist, einen'desired Output' (d.h. der gewünschte Ausgang für das Training) zu erzeugen.Zunächst definieren wir eine Neuronen-Klasse

Ein Neuron braucht folgende Werte:
Class Neuron:
VariablenInput[]
Weights[]
Bias
Sum
Result
Error

Funktionen
Propagate()

In Pseudocode für die Propagate-Funktion:
For i = 0 to Input.Length:
Sum = Sum + Input[i]*Weights[i]
EndFor
Result = Tanh(sum)

Das war es auch schon mit dem Neuron.
Normalerweise könnte man die Neuronen jetzt
in einem 2-Dimensionalen Array ablegen, wenn jede Schicht gleich viele Neuronen hat.
Da das nicht so ist, legen wir noch eine Layer-Klasse an,
welche ein Array vom Typ Neuron beinhaltet.

So können wir im Main-Code ein Array erzeugen, welches
unterschiedlich viele Neuronen besitzt.

Class Layer:
Neuron[]

Nun kann man das ganze schon Initialisieren.

Folgendes gilt zu beachten:
Wir nutzen Neuronen auch für den Eingang somit sollten
alle Eingangsneuronen einen Eingang mit einer Gewichtung von 1
besitzen (wir haben so viele Eingangsneuronen wie Eingabe-Werte).
Da Neuronen nur einen Ausgang besitzen haben wir in der Letzten Schicht so viele Neuronen wie Ausgaben benötigt werden.

Für unseren Sinus benutzen wir zunächst 3 Schichten:

Eingang, Hidden, Hidden.

Die Anzahl der Neuronen sind:
1-6-1

Also können wir im Hauptprogramm sagen:
Layer[] = new Layer[3]
Layer[0].Neuron[] = new Neuron[1]
Layer[1].Neuron[] = new Neuron[6]
Layer[2].Neuron[] = new Neuron[1]

Die Gewichtungen werden Standardmäßig zufällig gewählt.

Für den nächsten Schritt brauchen wir 3 Schleifen um die Vorwärts-Propagation zu starten.

For i = 0 to Layer.Length
For j = 0 to Layer[i].Neuron.Length
If i = 0 Set Input-Values
Else
For k = 0 to Layer[i-1].length
Layer[i].Neuron[j].Input[k] = Layer[i-1].Neuron[k].Result
EndFor
EndIf
Layer[i].Neuron[j].Propagate()
EndFor
EndFor

Fertig. So wird das ganze nach vorne Propagiert.

Der nächste Schritt besteht aus dem Korrigieren der Gewichtungen für
jedes Neuron.
Dafür berechnen wir Rückwärts den Fehler jedes Neurons
Wir unterscheiden dabei: Letze Schicht und Restliche Schichten.

In der Letzten Schicht (die wir zuerst berechnen) berechnen wir den Fehler direkt.Dazu benötigen wir, wie im letzten Teil erwähnt, die Ableitung.

Tanh hat die Ableitung: 1-tanh(x)²

Der Fehler berechnet sich aus der Multiplikation der Ableitung mit der Differenz zwischen DesiredOutput und CurrentOutput, also
1-tanh(x)²* 1/2(DO-CO)²

Da wir tanh(x) schon in jedem Knoten berechnet habe (es ist der Result-Wert) vereinfacht das uns die ganze Sache erheblich.

For each Neuron in OutputLayer
Error = (1-Result²)*1/2(DesiredOutput-Result)²

Sieht simpel aus oder?Da hier der Result-Wert gleichzeitig die Ausgabe ist können wir ihn auch direkt für die Abweichung benutzen. Daher DesiredOutput-Result.

Für alle anderen Layer muss natürlich der Fehler gewichtet zurückpropagiert werden.

Der Fehler für den Aktuellen Knoten ist die Summe aller
(Fehler der nächsten Schicht * der Gewichtung) Aktuellen Knotens.
Anschließend wird auch hier mit der Ableitung multipliziert.

Hört sich zunächst kompliziert an. Technisch gesehen ist es aber relativ einfach:

For i = Layer.Length-1 to 0
For j = 0 to Layer[i].Neuron.Length
Sum = 0
For k = 0 to Layer[i+1].Neuron.Length
Sum = Sum + Layer[i+1].Neuron[k].Error
*Layer[i+1].Neuron[k].Weights[j]
EndFor
Error = Sum * (1-Result²)
EndFor
EndFor

Es ist relativ Simpel. Da der Index des Neurons in der
betrachteten Schicht auch der korrespondierende Index für
die Gewichtung aller Neuronen in der nächsten Schicht ist.

Allgemein betrachtet:
Wir berechnen den Fehler an den Ausgangsneuronen direkt.
Dann gehen wir von Schicht zu Schicht rückwärts.
Für jeden Knoten in der Schicht Summieren wir alle Fehlerder nächsten Schicht multipliziert mit der Gewichtung auf und berechnen daraus den Fehler.

Um es noch mehr zu veranschaulichen:
Wir haben Knoten X in der vorletzten Schicht
und die Knoten Y und Z in der letzten Schicht.
Wir gewichten erstmal die Fehler in Y und Z mit den Gewichten
X zu Y und X zu Z und addieren sie.
Fertig.

Ein letzter Schritt fehlt noch: Das Update der Gewichte.
Dafür brauchen wir noch eine Variable.
Diese nennt sich Lernrate und bestimmt, wir stark das Gewicht angepasst wird.

Zu groß und das Netz springt um den optimalen Wert herum.
Zu klein und es dauert zu lange.

In jedem Knoten wird jedes Gewicht so neu berechnet:

Weight = Weight + LearningRate*Error*Input

Der Input bezieht sich auf den Input des zu ändernden Gewichtes.

Genauso verhält es sich mit dem Bias:

Bias = Bias + LearningRate*Error

Da der Bias standardmäßig 1 ist, muss kein gesondertes Gewicht geändert werden. Wir ändern den Bias-Wert direkt.
Das Netzwerk ist nun in der Lage zu lernen.
Nach jeder Runde kann dann das gelernte mit dem gesamten Zahlenbereich getestet werden. (Anstatt Sinus mit 1er Schritten, Sinus mit 0.1er Schritten z.B.)

Am besten packt man die einzelnen Schritte in mehrere
Funktionen.Init()
While Error>DesiredError
Propagate(Input)
BackPropagate(DesiredOutput)
Test(Input)
EndLoop

Natürlich gibt es noch einige Sachen bezüglich der Parameter (Anzahl der Neuronen in der Hidden-Schicht, Lernrate, Fehler-Größe

Wählt man z.B. die Fehler-Toleranz zu klein, wird das Netzwerk übertrainiert. D.h. Statt einer Sinus-Kurve in der Test-Phase erhaltenwir eine Zickzack-Kurve.

Das selbe kann bei zu vielen Neuronen passieren.
Eine zu hohe Toleranz und zu wenig Neuronen führt zu einer
zu hohen Verallgemeinerung und die Werte werden nicht genau genug.

Die Lernrate haben wir bereits angesprochen.
Wichtig ist auch: In der Test-Phase wird NIE zurückpropagiert.
17.3.16 13:15
 


bisher 0 Kommentar(e)     TrackBack-URL

Name:
Email:
Website:
E-Mail bei weiteren Kommentaren
Informationen speichern (Cookie)



 Smileys einfügen



Verantwortlich für die Inhalte ist der Autor. Dein kostenloses Blog bei myblog.de! Datenschutzerklärung
Werbung