Umsetzung eines Backpropagation Algorithmus
Als Beispiel für die Umsetzung des Backpropagation-Verfahrens zum Belernen eines Neuronalen Netzes wird ein Netz mit zwei Einangsneuronen, einer Zwischenschicht mit vier Neuronen und einer Ausgangsschicht mit einem Neuron verwendet.
Das Netz soll entsprechend den vorangegangenen Ausführungen die Antivalenz-Logik lernen. Es werden folgende Bezeichnungen verwendet:
|
Bild 0-1: Netz für das der Backpropagation Algorithmus umgesetzt werden soll.
|
Das Backpropagatioverfahren wird für das Netz direkt innerhalb einer Klasse umgesetzt werden, um die Komplexität der Darstellung möglichst gering zu halten. Ebensowenig werden Verknüpfungstabellen verwendet, um die Vernetzung darzustellen, sondern die Verknüpfung wird unmittelbar in der Ausgangsberechnung und beim Backpropagationschritt sichtbar. Der folgende Quellcode stellt also obiges Neuronale Netz dar und einen auf diesem Netz wirkenden Backpropagation-Algorithmus.
import java.util.Random; public class Backpropagation { public static double[] u = new double[7]; public static double n10,n11,n20,n21,n22,n23,n30; public static double sigmoid(double u) { return 1.0 / ( 1.0 + Math.exp(-u) ); } public static double ableitung_sigmoid(double u) { return Math.exp(-u) / ( ( 1.0 + Math.exp(-u) )*( 1.0 + Math.exp(-u) ) ); } public static double netz(double in0, double in1,double[] w) { u[0] = in0*w[0]+in1*w[1]; u[1] = in0*w[2]+in1*w[3]; n10 = sigmoid(u[0]); n11 = sigmoid(u[1]); u[2] = n10*w[4]+n11*w[5]; u[3] = n10*w[6]+n11*w[7]; u[4] = n10*w[8]+n11*w[9]; u[5] = n10*w[10]+n11*w[11]; n20 = sigmoid(u[2]); n21 = sigmoid(u[3]); n22 = sigmoid(u[4]); n23 = sigmoid(u[5]); u[6] = n20*w[12]+n21*w[13]+n22*w[14]+n23*w[15]; n30 = sigmoid(u[6]); return n30; } public static double berechneFehler(double in0, double in1, double sollout, double[] w) { double ausgang = netz(in0,in1,w); return (ausgang-sollout)*(ausgang-sollout); } public static double berechneFehler(double[] w) { double ausgang; double fehler = 0.0; double fehler_aktuell = 0.0; fehler_aktuell = berechneFehler(0.0,0.0,0.0,w); ausgang = netz(0.0,0.0,w); System.out.println("in: 0 0 sollout: 0, istwert:"+ausgang); fehler += fehler_aktuell; fehler_aktuell = berechneFehler(0.0,1.0,1.0,w); ausgang = netz(0.0,1.0,w); System.out.println("in: 0 1 sollout: 1, istwert:"+ausgang); fehler += fehler_aktuell; fehler_aktuell = berechneFehler(1.0,0.0,1.0,w); ausgang = netz(1.0,0.0,w); System.out.println("in: 1 0 sollout: 1, istwert:"+ausgang); fehler += fehler_aktuell; fehler_aktuell = berechneFehler(1.0,1.0,0.0,w); ausgang = netz(1.0,1.0,w); System.out.println("in: 1 1 sollout: 0, istwert:"+ausgang); fehler += fehler_aktuell; return fehler; } public static void backpropagation(double in0, double in1, double sollout, double lernfaktor, double[] w) { //Übung: Korrektheit der Implementierung prüfen: double[] Q = new double[w.length]; double istout = netz(in0,in1,w); //hier wird auch u[0..6] bstimmt! //Zuleitungen zu Ausgangsschicht: Q[12] = ableitung_sigmoid(u[6])*(sollout - istout); w[12] += lernfaktor*Math.abs(n20)*Q[12]; Q[13] = ableitung_sigmoid(u[6])*(sollout - istout); w[13] += lernfaktor*Math.abs(n21)*Q[13]; Q[14] = ableitung_sigmoid(u[6])*(sollout - istout); w[14] += lernfaktor*Math.abs(n22)*Q[14]; Q[15] = ableitung_sigmoid(u[6])*(sollout - istout); w[15] += lernfaktor*Math.abs(n23)*Q[15]; //Zuleitung zu Zwischenschicht: Q[4] = ableitung_sigmoid(u[2])*(w[12]*Q[12]); w[4] += lernfaktor*Math.abs(n10)*Q[4]; //nur die hinführenden, nicht alle Q[5] = ableitung_sigmoid(u[2])*(w[12]*Q[12]); w[5] += lernfaktor*Math.abs(n11)*Q[5]; Q[6] = ableitung_sigmoid(u[3])*(w[13]*Q[13]); w[6] += lernfaktor*Math.abs(n10)*Q[6]; //nur die hinführenden, nicht alle Q[7] = ableitung_sigmoid(u[3])*(w[13]*Q[13]); w[7] += lernfaktor*Math.abs(n11)*Q[7]; Q[8] = ableitung_sigmoid(u[4])*(w[14]*Q[14]); w[8] += lernfaktor*Math.abs(n10)*Q[8]; //nur die hinführenden, nicht alle Q[9] = ableitung_sigmoid(u[4])*(w[14]*Q[14]); w[9] += lernfaktor*Math.abs(n11)*Q[9]; Q[10] = ableitung_sigmoid(u[5])*(w[15]*Q[15]); w[10] += lernfaktor*Math.abs(n10)*Q[10]; //nur die hinführenden, nicht alle Q[11] = ableitung_sigmoid(u[5])*(w[15]*Q[15]); w[11] += lernfaktor*Math.abs(n11)*Q[11]; //Zuleitung zu Eingangsschicht: Q[0] = ableitung_sigmoid(u[0])*(w[4]*Q[4]+w[6]*Q[6]+w[8]*Q[8]+w[10]*Q[10]); w[0] += lernfaktor*Math.abs(in0)*Q[0]; //nur die hinführenden, nicht alle Q[1] = ableitung_sigmoid(u[1])*(w[5]*Q[5]+w[7]*Q[7]+w[9]*Q[9]+w[11]*Q[11]); w[1] += lernfaktor*Math.abs(in1)*Q[1]; //nur die hinführenden, nicht alle Q[2] = ableitung_sigmoid(u[0])*(w[4]*Q[4]+w[6]*Q[6]+w[8]*Q[8]+w[10]*Q[10]); w[2] += lernfaktor*Math.abs(in0)*Q[2]; //nur die hinführenden, nicht alle Q[3] = ableitung_sigmoid(u[1])*(w[5]*Q[5]+w[7]*Q[7]+w[9]*Q[9]+w[11]*Q[11]); w[3] += lernfaktor*Math.abs(in1)*Q[3]; //nur die hinführenden, nicht alle } public static void main(String[] args) { double[] w = new double[16]; Random random = new Random(0); for(int i=0;i<w.length;i++) w[i] = 2.0*random.nextDouble()-1.0; //[-1,+1] for(int i=0;i<2000;i++) { backpropagation(0.0,0.0,0.0,1.0,w); backpropagation(0.0,1.0,1.0,1.0,w); backpropagation(1.0,0.0,1.0,1.0,w); backpropagation(1.0,1.0,0.0,1.0,w); if(i%100==0) System.out.println("Fehler = "+berechneFehler(w)); } } }
Code 0-1: Neuronales Netz zur Realisierung eines NAND-Gatters mit Backpropagation Algorithmus.
Übung
|