Benutzer-Werkzeuge

Webseiten-Werkzeuge


ein_neuronales_netz_fuer_den_nxt_roboter

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
ein_neuronales_netz_fuer_den_nxt_roboter [2024/01/26 10:48] – [Der Backpropagation-Algorithmus] torsten.roehlein_neuronales_netz_fuer_den_nxt_roboter [2024/01/26 11:20] (aktuell) – [Quellcode] torsten.roehl
Zeile 53: Zeile 53:
 </WRAP>| </WRAP>|
 |4.|<WRAP>Durchlaufen der Aktivierungen der Input-Neuronen zu den Hidden-Neuronen mit der Aktivierungsfunktion |4.|<WRAP>Durchlaufen der Aktivierungen der Input-Neuronen zu den Hidden-Neuronen mit der Aktivierungsfunktion
-\begin{equation}  h_j= \frac{1}{1+ e^{-\sum_{i=0}^{A} w1_{ij}x_i }\end{equation}+\begin{equation}  h_j= \frac{1}{1 + e^{- \sum_{i=0}^{A} w1_{ij}\;x_i} \end{equation}
 </WRAP>| </WRAP>|
-|5.|<WRAP>+|5.|<WRAP>Durchlaufen der Aktivierungen der Hidden-Neuronen zu den Output-Neuronen: 
 +\begin{equation}  o_j= \frac{1}{1 + e^{- \sum_{i=0}^{B} w2_{ij}\;h_i} } \end{equation}
 </WRAP>| </WRAP>|
-|6.|<WRAP>+|6.|<WRAP>Berechnen der Fehlerwerte der Neuronen auf dem Output-Layer, bezeichnet mit δ$2_j$. Die Fehlerwerte basieren auf dem berechneten Output ($o_j$) und dem Ziel-Output $y_j$: 
 +\begin{equation} \delta 2_j = o_j(1-o_j)(y_j-o_j) \end{equation} 
 </WRAP>| </WRAP>|
-|7.|<WRAP>+|7.|<WRAP>Berechnen der Fehlerwerte Der Hidden-Neuronen, bezeichnet als δ1: 
 + 
 +\begin{equation} \delta 1_j = h_j(1-h_j) \sum_{i_1}^C \delta2_i\;w2_{ji} \end{equation}
 </WRAP>| </WRAP>|
-|8.|<WRAP>+|8.|<WRAP>Justieren der Gewichte zwischen Hidden- und Output-Layer. Der Lernfaktor sei η; seine Funktion ist die gleiche wie beim Lernen des Perzeptrons. Ein angemessener Wert für η ist z.B. 0.35: 
 +\begin{equation} \Delta w2_{ij} = \eta \delta 2_jh_i \end{equation} 
 +    * für alle i=0, ..., B, j=1, ..., C
 </WRAP>| </WRAP>|
-|9.|<WRAP>+|9.|<WRAP>Justieren der Gewichte zwischen Input- und Hidden-Layer: 
 +\begin{equation} \Delta w1_{ij} = \eta \delta 1_jh_i \end{equation} 
 +  * für alle i=0, ..., A, j=1, ..., B
 </WRAP>| </WRAP>|
 |10.|<WRAP>Ab Schritt 4 alles wiederholen, bis alle Input-Output-Paare dem Netzwerk "präsentiert" worden sind. Dann ist eine //"Epoche"// vervollständigt.  Die Schritte 4-10 für eine gewünschte Zahl an Epochen wiederholen. |10.|<WRAP>Ab Schritt 4 alles wiederholen, bis alle Input-Output-Paare dem Netzwerk "präsentiert" worden sind. Dann ist eine //"Epoche"// vervollständigt.  Die Schritte 4-10 für eine gewünschte Zahl an Epochen wiederholen.
 </WRAP>| </WRAP>|
 +
 +
  
 Die Aktivierungsfunktion ist s-förmig. Damit die berechneten //Outputs// werte von 0.0 oder 1.0 annehmen, müssten die Gewichte unendlich groß sein. Deshalb werden die Ziel-Outputs (Oben in Schritt 4 und 7 als $y_j$ dargestellt) auf 0.1 und 0.9 gesetzt. Die S-Förmigkeit der Aktivierungsfunktion ist deshalb wichtig, weil sie differenzierbar sein muss. Ansonsten könnten die Gewichtsupdates im //Backpropagationprozess// nicht berechnet werden. Die Aktivierungsfunktion ist s-förmig. Damit die berechneten //Outputs// werte von 0.0 oder 1.0 annehmen, müssten die Gewichte unendlich groß sein. Deshalb werden die Ziel-Outputs (Oben in Schritt 4 und 7 als $y_j$ dargestellt) auf 0.1 und 0.9 gesetzt. Die S-Förmigkeit der Aktivierungsfunktion ist deshalb wichtig, weil sie differenzierbar sein muss. Ansonsten könnten die Gewichtsupdates im //Backpropagationprozess// nicht berechnet werden.
Zeile 72: Zeile 83:
  
 ==== Das Backpropagation-Netzwerk für den NXT ==== ==== Das Backpropagation-Netzwerk für den NXT ====
 +Das Netzwerk kann von der Theorie nicht eins zu eins auf den NXT-Roboter bertragen werden, sondern es muss an dessen Hardware angepasst werden. Der Roboter hat drei Inputs (zwei Touch-Sensoren und ein Licht-Sensor) und zwei Outputs (Motor A und Motor C). Es kann also ein 3-Layer Netzwerk verwendet werden (Wie in Grafik 5), in welchem die Indizes der Neuronen mit 0 beginnen, damit Java-Arrays verwendet werden können.
 +
 +|{{ :inf:msr:nn_7.png? |}}|
 +|Abb. 4 Der Aufbau des Lego NXT Roboters|
 +
 +|{{ :inf:msr:nn_6.png? |}}|
 +|Abb. 5:Das Backpropagation-Netzwerk |
 +
 +{{:inf:hinweis.gif?|}}Dass hier ein 3-Layer-Netzwerk mit 3 Neuronen im Hidden-Layer verwendet wird, ist im Grunde eine willkürliche Entscheidung. Allerdings ist ein einfaches Netzwerk für den Lerneffekt sinnvoll. 
 +
 +Die Input-Output-Vektor-Paare (Ziel-Outputs) können nicht willkürlich festgelegt werden, da sie von den Input- und Output-Möglichkeiten des Roboters abhängen. 
 +
 +
 +Grundlegende Bewegungsregeln:
 +  - **Vorwärtsbewegung**: Sensor 1 aus, Sensor 2 auf weißer Oberflächte, Sensor 3 aus → Motoren A und C laufen vorwärts
 +  - **Rechtskurve**: Sensor 3 an → Motor A läuft vorwärts, Motor B läuft rückwärts
 +  - **Linkskurve**: Sensor 1 an → Motor A läuft rückwärts, Motor B läuft vorwärts
 +  - **Rückwärtsbewegung**: Sensor 2 auf schwarzer Oberfläche→ Motoren A und B laufen rückwärts
 +Diese Regeln werden in Trainingsmuster übersetzt. 
 +
 +|{{ :inf:msr:nn_4.png? |}}|
 +|Abb. 6 Lernregeln|
 +
 +|{{ :inf:msr:nn_5.png? |}}|
 +|Abb. 7 Input-Output-Vektoren|
 +
 +Die Input-Output-Vektorpaare sind diese Trainigsmuster, anhand derer das Netzwerk lernt. Abhängig von den Zuständen seiner Input-Sensoren wird der Roboter also lernen, sich vorwärts zu bewegen, eine Rechtskurve zu machen, usw. Doch was würde zum Beispiel passieren, wenn beide Touch-Sensoren aktiviert sind? Für diesen Fall hat der Roboter kein Lernmuster, doch würde das Netzwerk ein bestimmtes Verhalten berechnen.
 +
 +
 +
 ====  Quellcode==== ====  Quellcode====
 +Abschließend noch der vollständige Quellcode um mit dem Experimentieren anzufangen zu können. Das Programm ist in zwei Java-Klassen aufgeteilt, eine Klasse für die Berechnungen (//Methods//) und eine für die Ausführung (Main).
 === Quellen === === Quellen ===
  
  
 +<Code Java linenums:1 | Listing 1: Die Main-Klasse>
 +import lejos.nxt.*;
 +import lejos.nxt.LCD;
 + 
 +public class Main {
 +   public static Methods bpn = new Methods();
 + 
 +   public static void main(String args[]) throws InterruptedException {
 + 
 +   //Initialisieren der Sensoren
 +  
 +   TouchSensor s1 = new TouchSensor(SensorPort.S1);
 +   LightSensor s2 = new LightSensor(SensorPort.S2);
 +   TouchSensor s3 = new TouchSensor(SensorPort.S3);
 + 
 +   //Initialisieren der Zählvariable i, des Weißstandarts
 +   // und des Input- und Output-Vektors
 +  
 +   int i, white;
 +   int inp[] = { 0, 0, 0 };
 +   int out[] = { 0, 0 };
 + 
 +   Sound.beep();
 +   System.out.println("Train");
 + 
 +   // Trainieren des bpn (Backpropagation-Netzwerks) in 500 Epochen
 +   for (i = 0; i < 500; i++) {
 +      bpn.train(1);
 +      System.out.println(bpn.trainedEpochs);
 +   }
 + 
 +   Sound.twoBeeps();
 +  
 +   //Definieren des Weißstandards und der Motorgeschwindigkeiten
 +  
 +   white = s2.readValue();
 + 
 +   Motor.A.setSpeed(300);
 +   Motor.C.setSpeed(300); 
 +   Sound.twoBeeps();
 + 
 +   while (!Button.ENTER.isPressed()) {
 + 
 +       System.out.println(s2.readValue());
 + 
 +       if (s1.isPressed()==true)
 +          inp[0] = 1; // Sensor 1 an
 +       else
 +          inp[0] = 0; // Sensor 1 aus
 + 
 +       if (s2.readValue() > white + 15)
 +           inp[1] = 1; // Sensor 2 schwarz
 +       else
 +           inp[1] = 0; // Sensor 2 weiß
 + 
 +       if (s3.isPressed()==true)
 +           inp[2] = 1; // Sensor 3 an
 +       else
 +           inp[2] = 0; // Sensor 3 aus
 + 
 +       bpn.test(inp, out);
 + 
 +       if (out[0] == 1)
 +           Motor.A.forward();
 +       else
 +          Motor.A.backward();
 + 
 +      if (out[1] == 1)
 +          Motor.C.forward();
 +      else
 +          Motor.C.backward();
 + 
 +      Thread.sleep(500);
 + 
 +   
 +  
 + 
 + 
 +   Motor.A.stop();
 +   Motor.C.stop();
 +   Sound.beep();
 +  
 +   Button.ESCAPE.addButtonListener(new ButtonListener() {
 +      public void buttonPressed(Button b) {
 +           LCD.drawString("Program stop", 0, 3);
 +      }
 +      
 +      public void buttonReleased(Button b) {
 +         System.exit(0);
 +      }
 +   });
 + 
 + 
 + 
 +}
 +
 +
 +</Code>
 +
 +<Code Java linenums:1 | Listing 1: Die Methods-Klasse>
 +class Methods {
 + public static int data1[][] = {{0,0,0}, {1,1}};
 + public static int data2[][] = {{1,0,0}, {1,0}};
 + public static int data3[][] = {{0,0,1}, {0,1}};
 + public static int data4[][] = {{0,1,0}, {0,0}};
 +  
 + public static double input[] = {0,0,0,1};
 + public static double w1[][] = {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}};
 + public static double hidden[] = {0,0,1};
 + public static double w2[][] = {{0,0}, {0,0}, {0,0}};
 + public static double output[] = {0,0};
 + public static double delta2[] = {0,0};
 + public static double delta1[] = {0,0,0};
 + 
 + public static int trainedEpochs = 0;
 +   
 + public Methods() {
 + byte i, j;
 + // Initialisieren der zufälligen Gewichte zwischen 0.1 und 0.9
 + for(i=0; i
 + 
 + for(i=0;
 + }
 + 
 + 
 + public static void train(int e) {
 +    for(int i=0; i
 +      learn( data1[0], data1[1] );
 +      learn( data2[0], data2[1] );
 +      learn( data3[0], data3[1] );
 +      learn( data4[0], data4[1] );
 +      trainedEpochs++;
 +      }
 + }
 + 
 + 
 + public static void learn( int inp[], int out[] ) {
 + int i, j;
 + double sum, out_j; 
 + 
 + // Initialisieren der Input-Vekoren
 + for(i=0; i
 + 
 + // Berechnen der Werte im Hidden-Layer
 + for(j=0; j for(i=0; i
 + 
 + 
 + hidden[j] = 1 / ( 1 + Math.exp(-sum));
 + 
 + 
 + // Berechnen der Output-Werte
 + for(j=0; j for(i=0; i
 + 
 + 
 + output[j] = 1 / (1 + Math.exp(-sum));
 + }
 + 
 + 
 + // Berechnen der delta2 Fehler
 + for(j=0; j
 + out_j = 0.1;
 + else if( out[j] == 1 )
 + out_j = 0.9;
 + else
 + out_j = out[j];
 + delta2[j] = output[j]*(1-output[j])*(out_j-output[j]);
 + }
 + 
 + 
 + // Berechnen der delta1 Fehler
 + for(j=0; j for(i=0; i
 + 
 + 
 + delta1[j] = hidden[j]*(1-hidden[j])*sum;
 + }
 + 
 + 
 + // Anpassen der Gewichte w2
 + for(i=0; i
 + 
 + 
 + // Anpassen der Gewichte w1
 + for(i=0; i
 + 
 + 
 + public static void test(int inp[], int out[]) {
 + int i, j;
 + double sum;
 + 
 + 
 + // Initialisieren der Input-Werte
 + for(i=0; i
 + 
 + // Berechnen der Wete im Hidden-Layer
 + for(j=0; j for(i=0; i
 + 
 + 
 + hidden[j] = 1 / ( 1 + Math.exp(-sum));
 + }
 + 
 + 
 + // Berechnen der Output-Werte
 + for(j=0; j
 + sum = 0;
 + for(i=0; i
 + 
 + output[j] = 1 / (1 + Math.exp(-sum));
 + }
 + 
 + 
 + // Übertragen des Outputs auf das Array out[]
 +     for(i=0; i= 0.5 )
 +         out[i] = 1;
 +     else
 +         out[i] = 0;
 + }
 +    
 + 
 +}
 +
 +
 +
 +</Code>
 +
 +<WRAP center round info 60%>
 +FIXME Der Quellcode enthält noch Fehler 
 +</WRAP>
  
  
 +==== Quellen ====
 +  * Download des orginales Artikels erschienen in JavaWorld 2005
 +          * [[https://www.informatics4kids.de/addons-i4k/doc/article/neural_network_lego.pdf|A neural network for Java Lego robots]]
  
ein_neuronales_netz_fuer_den_nxt_roboter.1706266121.txt.gz · Zuletzt geändert: 2024/01/26 10:48 von torsten.roehl