Neuronales Netzwerk

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Neuronales Netzwerk

Beitrag 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!
Zuletzt geändert von remi_meier am 08.10.2004 19:15, insgesamt 1-mal geändert.
Norbie
Beiträge: 134
Registriert: 29.08.2004 12:45
Wohnort: Chemnitz
Kontaktdaten:

Beitrag von Norbie »

Ein Tutorial wäre cool.
Dann könnte ich entlich mein 50000000 Schichten Netzwerk aufbauen und Leben erzeugen. :mrgreen:
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag 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
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Beitrag von DarkDragon »

Kann mir einer mal erklären, was ein Neuronales Netzwerk ist? Und vielleicht gerade noch wozu man es braucht?
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Lars
Beiträge: 347
Registriert: 31.08.2004 23:53
Wohnort: Shanghai
Kontaktdaten:

Beitrag 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.
Lars
The only problem with troubleshooting is, that sometimes the trouble shoots back.
P4 2,6Ghz, 512MB RAM, GeForce 6200, WinXP Pro SP2, PB V3.94
Benutzeravatar
MUDHead
Beiträge: 107
Registriert: 08.09.2004 11:00
Wohnort: Berlin

Beitrag von MUDHead »

Malus, qui potest rerum cognoscere.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag 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
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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...)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
remi_meier
Beiträge: 1078
Registriert: 29.08.2004 20:11
Wohnort: Schweiz

Beitrag 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!
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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.
Zuletzt geändert von Kaeru Gaman am 12.12.2004 05:00, insgesamt 8-mal geändert.
Antworten