Seite 1 von 3

Neuronales Netzwerk

Verfasst: 29.09.2004 22:08
von remi_meier
Hi Leutz
Nach einiger Zeit habe ich mich nun wieder an die guten alten Neuronalen Netzwerke gemacht :D
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()
Wenn es keine Fehler mehr gibt, werde ich mich vielleicht auch wieder an ein Tutorial machen :wink:
Sucht bitte Fehler! (coldarchon?)

greetz
remi

EDIT: Fehler behoben!

Verfasst: 30.09.2004 06:56
von Norbie
Ein Tutorial wäre cool.
Dann könnte ich entlich mein 50000000 Schichten Netzwerk aufbauen und Leben erzeugen. :mrgreen:

Verfasst: 30.09.2004 13:27
von remi_meier
OK:
http://mypage.bluewin.ch/remimeier/Tutorial/Tut3.pdf

LOL:
Zur gleichen Zeit an einem anderen Ort: http://purebasic.myforums.net/viewtopic.php?t=12627
Ich glaube langsam auch an ein globales Bewusstsein (auch wenn er einen Tag später war 8) )

greetz
remi

Verfasst: 30.09.2004 18:03
von DarkDragon
Kann mir einer mal erklären, was ein Neuronales Netzwerk ist? Und vielleicht gerade noch wozu man es braucht?

Verfasst: 30.09.2004 18:21
von Lars
[google]Neuronales Netzwerk[/google]

SCNR :wink:

Ein Neuronales Netzwerk ist eine Art, ein lernendes System zu
implementieren, vielleicht hat jemand Nerv, dir alles zu erklären,
ansonsten wirklich Google.

Verfasst: 30.09.2004 18:23
von MUDHead

Verfasst: 08.10.2004 18:53
von remi_meier
Noch kurz das nichtlineare XOR mit einem Neuronalen Netzwerk.

Code: Alles auswählen

;/ 3-schichtiges Neuronales Netzwerk für XOR
#LD = 15000   ;Anz. Lerndurchläufe
#TD = 400     ;Anz. Testdurchläufe
#LK = 0.8     ;Lernkonstante (Hier: gut wenn gross, einfach ausprobieren!)
#n  = 2       ;anzInputs
#v  = 30      ;Anz. verb. Neuronen
#a  = 1       ;Anz. Outputs

;Statistik
Dim Statist.f(#LD)

;Gewichte
Dim Gewichte1.f(#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)    ;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)  ;SollOutput

;- Initialisierung
Procedure Init_Gewichte()  ;Zufällig initialisieren, von -0.3 bis +0.3
  For z1 = 0 To #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
EndProcedure

;- Input generieren
Procedure XOREN(V1.l, V2.l)
  ProcedureReturn V1 ! V2  ;Versuche noch mit |, & und finde die Unterschiede im Diagramm heraus!
EndProcedure

Procedure Generiere_Input()  ;Inputs() und SollOutputs() füllen
  V1.l = Random(1)
  V2.l = Random(1)
  Inputs(1) = V1
  Inputs(2) = V2
  SollOutputs(1) = XOREN(V1, V2)
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   ;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 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    ;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))

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
  Statist(z) = Berechne_Fehler()    ;die Fehler in die Fehlerarrays füllen
  
  Gewichte_anpassen()  ;Aus Fehlern lernen!
Next

For z = 1 To #TD
  Generiere_Input()
  Berechne_Outputs()
  
  If Outputs(1) + 0.1 > SollOutputs(1) And Outputs(1) - 0.1 < SollOutputs(1)
    richtige + 1
  EndIf
Next

OpenWindow(0, 100, 100, 500, 200, #PB_Window_SystemMenu | #PB_Window_ScreenCentered,"XOR mit Neuronalem Netzwerk")
schritt = #LD / 400
Repeat
  z = 0
  x = 0
  StartDrawing(WindowOutput())
    DrawingMode(1)
    FrontColor(255,0,0)
    Locate(10, 20)
    DrawText("Max. Fehler")
    Locate(400, 160)
    DrawText("Zeit")
    FrontColor(100,100,0)
    Locate(200, 10)
    DrawText("Anzahl Richtige: "+StrF(richtige / #TD * 100.0,1)+"%")
    
    While z <= #LD
      Plot(x + 50, 150 - (Statist(z) * 100.0), $FF0000)
      x + 1
      z + schritt
    Wend
    LineXY(50, 150, 455, 150, $FF)
    LineXY(50, 50, 50, 150, $FF)
  StopDrawing()
  
Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseWindow(0)
EDIT: Kleiner Fehler ausgebessert

Verfasst: 10.11.2004 22:54
von Kaeru Gaman
@remi

danke, Danke, DANKE :praise: für das tutorial

werde feedback geben, wenn ichs durchgearbeitet und was damit gemacht habe...

PS: wenn's dich interessiert... ich kann dir 'n zip schicken mit nem PB-Prog, wo ich mich mit 'pseudo'-neuron-geschichten versucht habe...

(hat 'n paar recources..kann man schlecht posten...)

Verfasst: 11.11.2004 17:44
von remi_meier
Schick mal :mrgreen:
Ich glaube, du bist der Erste, der das Tutorial durcharbeitet, sonst hätte man einen relativ offensichtlichen Fehler leicht erkennen können :roll:.
Danke!

Verfasst: 21.11.2004 15:21
von Kaeru Gaman
so, nachdem ich jetzt meine HP oben habe (wenn's auch noch ne baustelle ist)
kann ich das oben genannte 'pseudo-neuro-programm' ja mal der allgemeinheit zugänglich machen:

Tease or Please zip - 225K

ACHTUNG: ist noch ein versionsbedingter lilBug drin!
in 3.30 rundete die integer-funktion. jetzt schneidet sie ab.
die exe funzt wie sie soll: der smily wechselt bei X.50
wird erneut compiliert, wechselt er bei X.00 - das ist so nicht beabsichtigt.
es wird allerdings kein update geben.
[edit] jetzt gibts eben doch eins, siehe unter feedback-spiele [/edit]
wenn ich wieder viel zeit hab, setze ich das modell in allgemein verwendbare procs um.

btw: der "mood" ist nurn dummy-img, ist noch nicht implementiert.