Nach einiger Zeit habe ich mich nun wieder an die guten alten Neuronalen Netzwerke gemacht

Hab nun endlich ein 3-schichtiges Netzwerk hinbekommen (hoffe das alles stimmt)! Um es auf 4 Schichten zu erweitern wäre nun auch nur noch ein Kinderspiel. Konnte noch nicht viel damit rumspielen und hab deshalb nur mal wieder das alte, einfache Problem des Ellipsen- und Boxenunterscheidens geproggt. Das 2-schichtige Netz konnte das zwar auch und musste auch nicht so viel lernen, aber es soll ja nur ein Anfangsbeispiel sein (3-schichtige N. können nun auch nichtlineare Probleme lösen)!
Vorsicht! Braucht ziemlich lange zum berechnen, deshalb vielleicht die #LD-Konstante runter setzen!
So, nun der Code:
Code: Alles auswählen
;/ 3-schichtiges Neuronales Netzwerk
; Eingabeschicht - Verborgene Schicht - Ausgabeschicht
; - Jedes Neuron der Eingabeschicht ist mit jedem Neuron der verborgenen Schicht verbunden
; - Jedes Neuron der verborgenen Schicht ist mit jedem Neuron der Ausgabeschicht verbunden
; - Jedes Neuron der verb.- und der Ausgabeschicht hat ein Verschiebungsgewicht (Gewicht wo immer Input = 1)
; - Weniger fehleranfällig, für nichtlineare Probleme der Form: y = f(x), braucht mehr Training
; als Aktivierungsfunktion habe ich diesmal die nichtlineare sigmoide Funktion gewählt:
; 1 / (1 + e^(-Aktivierung))
; sie bleibt zwischen 0 und 1, wird aber 0 und 1 nie erreichen!
; Zu #LD: für einen Fehler von 10% müsste die Anzahl Lerndurchläufe 10 mal
; grösser sein, als die Anzahl an Gewichten!!! (Anz.Gewichte = #v * (#n * #n + #a)
; #Toleranz = 0.01 ;Zum herausfinden, wann genug gelernt wurde (habs auskommentiert)
#LD = 77100 ;Anz. Lerndurchläufe
#TD = 400 ;Anz. Testdurchläufe
#LK = 0.1 ;Lernkonstante
#n = 16 ;Wurzelvon(Anz. Inputs), Seitenlänge des Bildes
#v = 300 ;Anz. verb. Neuronen
#a = 1 ;Anz. Outputs, Achtung, wenn verändert, dann muss auch Generiere_Input() angepasst werden
;Gewichte
Dim Gewichte1.f(#n * #n, #v) ;Gewichte von Inputs nach verb. Schicht
Dim Gewichte2.f(#v, #a) ;Gewichte von verb. Schicht nach Outputs
;Outputs der Neuronen
Dim Inputs.f(#n * #n) ;Inputneuronen
Dim VNeurons.f(#v) ;Verb. Neuronen
Dim VFehler.f(#v) ;Um die Fehler zu speichern (Fehler = Abweichung vom berechneten Solloutput)
Dim Outputs.f(#a) ;Outputneuronen
Dim OFehler.f(#a) ;Um die Fehler zu speichern (Fehler = Abweichung vom Solloutput)
Dim SollOutputs.f(#a) ;Array mit den Bildern (1011110000011101)
;- Initialisierung
Procedure Init_Gewichte() ;Zufällig initialisieren, von -0.3 bis +0.3
For z1 = 0 To #n * #n ;von 0, da Verschiebungsgewicht auch initialisiert werden muss
For z2 = 0 To #v
Gewichte1(z1, z2) = Random(600) / 1000.0 - 0.3
Next
Next
For z1 = 0 To #v
For z2 = 0 To #a
Gewichte2(z1, z2) = Random(600) / 1000.0 - 0.3
Next
Next
VNeurons(0) = 1
Inputs(0) = 1
EndProcedure
;- Input generieren
Global Image.l
Image = CreateImage(#PB_Any, #n, #n)
Procedure Generiere_Input()
StartDrawing(ImageOutput())
DrawingMode(0)
Box(0, 0, #n, #n, 0) ;Image löschen
DrawingMode(4)
zufall = Random(1)
If zufall = 0 ;Ellipse
Ellipse(Random(4) + 6, Random(4) + 6, Random(4) + 3, Random(4) + 3, $FFFFFF)
SollOutputs(1) = 1.0 ;Outputneuron = 1
ElseIf zufall = 1 ;Box
Box(Random(6), Random(6), Random(5) + 5, Random(5) + 5, $FFFFFF)
SollOutputs(1) = 0.0 ;Outputneuron = 0
EndIf
For z = 1 To #n * #n ;Inputs()-Array füllen
x = (z % #n) + 1
y = z / #n
farbe = Point(x, y)
If farbe > 0
Inputs(z) = 1.0
Else
Inputs(z) = 0.0
EndIf
Next
StopDrawing()
EndProcedure
;- Berechnen/Lernen/Anpassen
Procedure Berechne_Outputs() ;Vorwärts
For z1 = 1 To #v ;für jedes Neuron der verb. Schicht
VNeurons(z1) = 0 ;mit 0 initialisieren
For z2 = 1 To #n * #n ;für jedes Neuron der Inputsschicht
VNeurons(z1) = VNeurons(z1) + Inputs(z2) * Gewichte1(z2, z1) ;Aktivierung aufsummieren
Next
For z3 = 1 To #v ;und noch die Verschiebungsgewichte
VNeurons(z1) = VNeurons(z1) + Gewichte1(0, z3)
Next
VNeurons(z1) = 1.0 / (1.0 + Pow(2.718, -VNeurons(z1))) ;Aktivierungsfunktion (sigmoide Funktion) => Output
Next
For z1 = 1 To #a ;für jedes Neuron der Ausgabeschicht
Outputs(z1) = 0 ;mit 0 initialisieren
For z2 = 1 To #v ;für jedes Neuron der verb. Schicht
Outputs(z1) = Outputs(z1) + VNeurons(z2) * Gewichte2(z2, z1) ;Aktivierung aufsummieren
Next
For z3 = 1 To #a ;und noch die Verschiebungsgewichte
Outputs(z1) = Outputs(z1) + Gewichte2(0, z3)
Next
Outputs(z1) = 1.0 / (1.0 + Pow(2.718, -Outputs(z1))) ;Aktivierungsfunktion (sigmoide Funktion) => Output
Next
EndProcedure
Procedure.f Berechne_Fehler() ;Rückwärts 1, gibt den MaximalFehler zurück
Protected MaxFehler.f ;um zu erkennen, wann der maximale Fehler innerhalb der Toleranz #Toleranz liegt
For z = 1 To #a ;Fehler für 2. Gewichtsschicht
OFehler(z) = (SollOutputs(z) - Outputs(z)) * Outputs(z) * (1.0 - Outputs(z)) ;fülle Fehler-Array der Outputschicht
; If Abs(OFehler(z)) > Abs(MaxFehler) ;Maximaler Fehler herausfinden
; MaxFehler = OFehler(z)
; EndIf
Next
For z1 = 1 To #v ;für jedes Neuron der verb. Schicht
Fehler1.f = 0 ;mit 0 initialisieren
For z2 = 1 To #a ;Fehler 1 berechnen
Fehler1 = Fehler1 + OFehler(z2) * Gewichte2(z1, z2) ;Fehler aufsummieren
Next
VFehler(z1) = VNeurons(z1) * (1.0 - VNeurons(z1)) * Fehler1 ;fülle Fehlerarray der verb. Schicht
Next
ProcedureReturn MaxFehler
EndProcedure
Procedure Gewichte_anpassen() ;Rückwärts 2
;2. Gewichteschicht anpassen
For z1 = 0 To #a ;für jedes Neuron der Ausgabeschicht
For z2 = 0 To #v ;für jedes Neuron der verb. Schicht
Gewichte2(z2, z1) = Gewichte2(z2,z1) + (#LK * OFehler(z1)) * VNeurons(z2) ;die altbekannte Delta-Regel
Next
Next
;1. Gewichteschicht anpassen
For z1 = 0 To #v ;für jedes Neuron der verb. Schicht
For z2 = 0 To #n * #n ;für jedes Neuron der Eingabeschicht
Gewichte1(z2, z1) = Gewichte1(z2, z1) + (#LK * VFehler(z1)) * Inputs(z2) ;die altbekannte Delta-Regel
Next
Next
EndProcedure
;- LERNE
Init_Gewichte() ;Gewichte auf Zufallswerte (nahe beieinander (-0.3 bis +0.3))
; anzInToleranz = 0
For z = 1 To #LD
Generiere_Input() ;Inputs()-Array füllen und Solloutput generieren
Berechne_Outputs() ;die Outputs der verschiedenen Schichten (verb.- und Ausgabe-) errechnen
Berechne_Fehler() ;die Fehler in die Fehlerarrays füllen
; bereich.f = Berechne_Fehler()
; If Abs(bereich) <= #Toleranz
; anzInToleranz + 1
; EndIf
; If anzInToleranz >= 300
; Break
; EndIf
Gewichte_anpassen() ;Aus Fehlern lernen!
Next
OpenConsole()
PrintN("Training beendet!")
PrintN("")
;- TESTE
richtige = 0
OpenWindow(0,200,200,200,200,#PB_Window_SystemMenu,"")
For z = 1 To #TD
Generiere_Input()
StartDrawing(WindowOutput())
DrawImage(UseImage(Image),0,0,32,32)
StopDrawing()
Berechne_Outputs()
If (SollOutputs(1) > 0.8 And Outputs(1) > 0.8) Or (SollOutputs(1) < 0.2 And Outputs(1) < 0.2) ;hat ers auf 0.2 genau herausgefunden?
richtige + 1
EndIf
Next
PrintN("Test:")
PrintN("Richtige von " + Str(#TD) + ": " + Str(richtige))
PrintN("In Prozent: " + StrF(richtige / #TD * 100.0))
Input()

Sucht bitte Fehler! (coldarchon?)
greetz
remi
EDIT: Fehler behoben!