Pretraining mit SDA
(EN google-translate)
(PL google-translate)
|
|
SDA -- Stacked Denoising Autoencoders
Beim SDA-Verfahren wird das Eingangspattern mit einem zusätzlichen Rauschen überlagert. Dieses Rauschen soll durch das hin- und zurückgespiegelte Propagieren durch das Netz entfernt werden.
Dies bedeutet aber, wenn das Verfahren gelingt, dass nur die besonderen Merkmale der Pattern durch das Netz durchgelassen werden und unnütze Signale unterdrückt werden.
Wieder anders gesagt: Die einzelnen Verbindungsschichten werden so belernt, dass sie die typischen an ihnen anliegenden Pattern sogar bis zu einem gewissen Grad rekonstruieren können, wenn diese fehlerhaft / verrauscht dargeboten werden.
Die Eingangspattern sollten aus den üblichen zu lernenden gelabelten Pattern resultieren. D.h. an der Eingangsschicht liegt das an, was auch sonst dargeboten wird, also in unserem Fall ein TicTacToe-Spielstand. Zuerst wird das Pre-Training auf die Gewichte zwischen Eingangs- und erster versteckten Neuronen-Schicht durchgeführt. Danach wird es auf die Gewichte der ersten und der zweiten verdeckten Schicht angewendet usw. Weil immer die vorhergehende Schicht bereits vortrainiert wurde, müssen nicht Extra-Eingangspattern für das Trainieren der Zwischenschichten konstruiert werden. Es reicht immer die üblichen Pattern durchzupropagieren. Lediglich das Rauschen muß immer bei der gerade aktuellen Eingangsseite hinzugefügt werden.
Und so sieht die Gradienten-basierte Veränderung der Gewichte beim SDA-Verfahren für einen einzelnen Lernschritt aus:
Indices der Neuronen der aktuell betrachteten Eingangsschicht: i Anzahl der Eingangsneuronen: p Indices der Neuronen der aktuell betrachteten Ausgangsschicht: k Anzahl der Ausgangsneuronen: q Gewicht zwischen einem Eingangsneuron und einem Ausgangsneuron: wik Das eingespeiste Pattern ohne Rauschen wird: xx Die Werte am Ausgang der Neuronen der Eingangsschicht werden bezeichnet mit: nn ...und entsprechen der verrauschten Version von xx. Der Ausgang nach dem Vorwärtspropagieren wird bezeichnet mit: zz Das Pattern, das nach dem zurückpropagieren wieder beim Eingang vorliegt: yy Anzahl der Werte / Zugehörigkeit: xx, nn, yy gehören zum Eingang und haben p Werte mit Index i=0..p-1 zz gehört zum Ausgang und hat q Werte mit Index k=0..q-1 Dann gilt für ein beliebiges Gewicht der gerade betrachteten Verbindungsschicht:
Code 0-1: Bezeichnungen beim SDA-Verfahren
$ wneu_{ik} = walt_{ik} + lernfaktor \cdot \left(Q \cdot zz_k \cdot \left(1-zz_k\right) \cdot nn_i+\left(xx_i-yy_i\right) \cdot zz_k\right) $
Formel 0-1: Lernregel beim SDA-Verfahren.
$ Q= \sum _{i=0}^{p-1} walt_{ik} \cdot \left(xx_i-yy_i\right) $
Formel 0-2: Bedeutung von Q.
for(int k=0;k<ausgangs_layer.holeAnzahlNeuronen();k++) { double Q = 0.0; for(int i=0;i<eingangs_layer.holeAnzahlNeuronen();i++) { //holeGewichtAlt(int index_eingang, int index_ausgang) Q += holeGewichtAlt(i,k)*(xx[i]-yy[i]); } for(int i=0;i<eingangs_layer.holeAnzahlNeuronen();i++) { double wneu = holeGewichtAlt(i,k) + lernfaktor*(Q*zz[k]*(1.0-zz[k])*nn[i]+(xx[i]-yy[i])*zz[k]); //setzeGewicht(int index_eingang, int index_ausgang, double wert) setzeGewicht(i, k,wneu); } }
Code 0-2: In den nachfolgenden Projekten, findet sich obige Implementierung für die SDA-Lernregel: siehe Zeilen 190-204 in der Klasse "Gewichte".
public void macheBackpropagation(double[] soll_ausgang, double lernfaktor) { //1. Gewichte unmittelbar vor Ausgangsschicht belernen: // w_neu = w_alt + lernfaktor*x*Q // Q = f'(u)*(out_soll - out_ist) // u: gewichtete Summe == Eingang der Ausgangsschicht // f'(u): Ableitung der sigmoiden Funktion der aktuellen Ausgangsneuronen // x: Aktivierung des Neurons, von dem das aktuelle Gewicht ausgeht. for(int i=0;i<layer[layer.length-2].holeAnzahlNeuronen();i++) //vorhergehende Schicht { double x = layer[layer.length-2].holeAusgang(i); //Aktivierung des Neurons, wo die aktuelle Leitung startet for(int k=0;k<layer[layer.length-1].holeAnzahlNeuronen();k++) { double w_aktuell = w[w.length-1].holeGewicht(i, k); double Q = layer[layer.length-1].holeAusgangAbleitung(k)*(soll_ausgang[k] - layer[layer.length-1].holeAusgang(k)); double w_neu = w_aktuell + lernfaktor*x*Q; w[w.length-1].setzeGewicht(i,k,w_neu); //Immer das korrespondierende Q zu jedem Gewicht mit merken, da es für die nachfolgenden Backpropagierungsschritte benötigt wird! w[w.length-1].merkeKorrespondierendesQ(i,k,Q); } } //2. Gewichte für alle vorangehenden Zwischenschichten belernen // w_neu = w_alt + lernfaktor*x*Q // Q = f'(u)*Summe(vorangehendesQk*wneuk) //Summe der Produkte aller neuen Qs und neuen ws aller vom Zielneuron abgehenden Leitungen // u: gewichtete Summe == Eingang der Ausgangsschicht // f'(u): Ableitung der sigmoiden Funktion der aktuellen Ausgangsneuronen // x: Aktivierung des Neurons, von dem das aktuelle Gewicht ausgeht. for(int schicht = layer.length-3;schicht>=0;schicht--) //Hier z.B.: 4 Layer, 3 ws: schicht=1 0 { for(int i=0;i<layer[schicht].holeAnzahlNeuronen();i++) //vorhergehende Schicht { double x = layer[schicht].holeAusgang(i); //Aktivierung des Neurons, wo die aktuelle Leitung startet for(int k=0;k<layer[schicht+1].holeAnzahlNeuronen();k++) { double w_aktuell = w[schicht].holeGewicht(i, k); double summeQw=0.0; for(int p=0;p<layer[schicht+2].holeAnzahlNeuronen();p++) summeQw+=w[schicht+1].holeGewicht(k,p)*w[schicht+1].holeQ(k,p); double Q = layer[schicht+1].holeAusgangAbleitung(k)*summeQw; double w_neu = w_aktuell + lernfaktor*x*Q; w[schicht].setzeGewicht(i,k,w_neu); //Immer das korrespondierende Q zu jedem Gewicht mit merken, da es für die nachfolgenden Backpropagierungsschritte benötigt wird! w[schicht].merkeKorrespondierendesQ(i,k,Q); } } } }
Code 0-3: Der Vollständigkeit halber sei auch die implementierte Backpropagation-Regel für das Fine-Tuning mit angegeben: siehe Zeilen 84-131 in der Klasse "Netz".
Ergänzung aus dem Unterricht:
|
Bild 0-1: Backtracking für Ausgangs-Verbindungsschicht.
Bild 0-2: Backtracking für Zwischen-Verbindungsschicht.
|
Bild 0-3: Vorwärts-Rückwärts-Propagierung (Encoding / Decoding)
Bild 0-4: Durchführen des SDA-Lernschritts mit den Ergebnissen aus der Vorwärts-Rückwärts-Propagierung.
TicTacToe und Deep Learning
|
|
TicTacToe35_Neuro_DeepLearning_DEEEEEP.zip
TicTacToe36_Neuro_mehr_Pretraining.zip
Ergebnisse:
**************************************** **** TicTacToe34_Neuro_DeepLearning **** **************************************** MIT Pre-Training: SDA Fehler zu Beginn: 2.763058507320894 ... am Ende: 0.028231118919433668 SDA Fehler zu Beginn: 1.1856504677026982 ... am Ende: 0.03130818018416652 SDA Fehler zu Beginn: 0.6321134781296878 ... am Ende: 0.039251778755574965 Start Fine-Tuning fehler = 0.03337222600483036 Echte Fehler: von 900 sind 23.0 falsch. fehler = 0.027289134062207464 Echte Fehler: von 900 sind 6.0 falsch. NULL FEHLER ERSTES MAL NACH 219540 SCHRIITEN! OHNE Pre-Training: Start Fine-Tuning fehler = 0.04550619929493047 Echte Fehler: von 900 sind 109.0 falsch. fehler = 0.03433224544873166 Echte Fehler: von 900 sind 47.0 falsch. fehler = 0.0298075423863876 Echte Fehler: von 900 sind 17.0 falsch. NULL FEHLER ERSTES MAL NACH 398014 SCHRIITEN! ************************************************ **** TicTacToe35_Neuro_DeepLearning_DEEEEEP **** ************************************************ 9,9,9,9,9,9,9-Netz MIT Pre-Training: NULL FEHLER ERSTES MAL NACH 7073877 SCHRIITEN! 9,9,9,9,9,9,9-Netz OHNE Pre-Training: NULL FEHLER ERSTES MAL NACH 24941950 SCHRIITEN! ******************************************** **** TicTacToe36_Neuro_mehr_Pretraining **** ******************************************** 9,9,9,9,9,9,9-Netz MIT Pre-Training: SDA Fehler zu Beginn: 2.517800122000871 ... am Ende: 0.08212722329337914 SDA Fehler zu Beginn: 1.079696242195671 ... am Ende: 0.0642301257378609 SDA Fehler zu Beginn: 0.5633722552154168 ... am Ende: 0.14978189605178832 SDA Fehler zu Beginn: 0.5510060587360196 ... am Ende: 0.04319369263624905 SDA Fehler zu Beginn: 0.5515231637120703 ... am Ende: 0.013878004882203152 SDA Fehler zu Beginn: 0.6505741359085077 ... am Ende: 0.01592400723910906 Start Fine-Tuning fehler = 0.03799268723454107 Echte Fehler: von 900 sind 68.0 falsch. fehler = 0.029757944145807045 Echte Fehler: von 900 sind 33.0 falsch. fehler = 0.027656180706206002 Echte Fehler: von 900 sind 38.0 falsch. fehler = 0.027996441778316287 Echte Fehler: von 900 sind 26.0 falsch. lernfaktor = 0.1000200048090007 fehler = 0.027394148139482263 Echte Fehler: von 900 sind 31.0 falsch. fehler = 0.025325394232452517 Echte Fehler: von 900 sind 20.0 falsch. fehler = 0.02319232489533295 Echte Fehler: von 900 sind 12.0 falsch. NULL FEHLER ERSTES MAL NACH 748016 SCHRIITEN!
Code 0-4: Ergebnisse, die mit den obigen Beispielprojekten mit und ohne Pretraining gewonnen wurden.
Fazit
|
Erstellen eines neuronalen Tic-Tac-Toe-Spielers
|
2.: TicTacToe08b_Turnier_P_korrigiert_NEURO.zip
Hinweise:
|
Bild 0-5: Verlauf eines Turniers des Neurospielers (X, rot) gegen den optimalen Spieler (O, grün).
Offene Fragen / TODOs
|