ein_neuronales_netz_fuer_den_nxt_roboter
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
ein_neuronales_netz_fuer_den_nxt_roboter [2024/01/26 10:36] – [Der Backpropagation-Algorithmus] torsten.roehl | ein_neuronales_netz_fuer_den_nxt_roboter [2024/01/26 11:20] (aktuell) – [Quellcode] torsten.roehl | ||
---|---|---|---|
Zeile 42: | Zeile 42: | ||
^Step^Beschreibung^ | ^Step^Beschreibung^ | ||
- | |1.|< | + | |1.|< |
- | |2.|< | + | * w1ij='' |
- | |3.|< | + | * w2ij='' |
- | |4.|< | + | </ |
- | |5.|< | + | |2.|< |
- | |6.|< | + | * x0=1.0 |
- | |7.|< | + | * h0=1.0 |
- | |8.|< | + | </ |
- | |9.|< | + | |3.|< |
- | |10.|< | + | </ |
+ | |4.|< | ||
+ | hj=11+e−∑Ai=0w1ijxi | ||
+ | </ | ||
+ | |5.|< | ||
+ | oj=11+e−∑Bi=0w2ijhi | ||
+ | </ | ||
+ | |6.|< | ||
+ | δ2j=oj(1−oj)(yj−oj) | ||
+ | |||
+ | </ | ||
+ | |7.|< | ||
+ | |||
+ | δ1j=hj(1−hj)C∑i1δ2iw2ji | ||
+ | </ | ||
+ | |8.|< | ||
+ | Δw2ij=ηδ2jhi | ||
+ | * für alle i=0, ..., B, j=1, ..., C | ||
+ | </ | ||
+ | |9.|< | ||
+ | Δw1ij=ηδ1jhi | ||
+ | * für alle i=0, ..., A, j=1, ..., B | ||
+ | </ | ||
+ | |10.|< | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | 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 yj 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 // | ||
+ | |||
==== 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. | ||
+ | |||
+ | |{{ : | ||
+ | |Abb. 4 Der Aufbau des Lego NXT Roboters| | ||
+ | |||
+ | |{{ : | ||
+ | |Abb. 5:Das Backpropagation-Netzwerk | | ||
+ | |||
+ | {{: | ||
+ | |||
+ | 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**: | ||
+ | - **Rechtskurve**: | ||
+ | - **Linkskurve**: | ||
+ | - **Rückwärtsbewegung**: | ||
+ | Diese Regeln werden in Trainingsmuster übersetzt. | ||
+ | |||
+ | |{{ : | ||
+ | |Abb. 6 Lernregeln| | ||
+ | |||
+ | |{{ : | ||
+ | |Abb. 7 Input-Output-Vektoren| | ||
+ | |||
+ | Die Input-Output-Vektorpaare sind diese Trainigsmuster, | ||
+ | |||
+ | |||
+ | |||
==== 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 (// | ||
=== Quellen === | === Quellen === | ||
+ | <Code Java linenums:1 | Listing 1: Die Main-Klasse> | ||
+ | import lejos.nxt.*; | ||
+ | import lejos.nxt.LCD; | ||
+ | |||
+ | public class Main { | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | // | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | // | ||
+ | // und des Input- und Output-Vektors | ||
+ | | ||
+ | int i, white; | ||
+ | int inp[] = { 0, 0, 0 }; | ||
+ | int out[] = { 0, 0 }; | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | // Trainieren des bpn (Backpropagation-Netzwerks) in 500 Epochen | ||
+ | for (i = 0; i < 500; i++) { | ||
+ | bpn.train(1); | ||
+ | System.out.println(bpn.trainedEpochs); | ||
+ | } | ||
+ | |||
+ | | ||
+ | | ||
+ | // | ||
+ | | ||
+ | white = s2.readValue(); | ||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | while (!Button.ENTER.isPressed()) { | ||
+ | |||
+ | | ||
+ | |||
+ | if (s1.isPressed()==true) | ||
+ | inp[0] = 1; // Sensor 1 an | ||
+ | else | ||
+ | inp[0] = 0; // Sensor 1 aus | ||
+ | |||
+ | if (s2.readValue() > white + 15) | ||
+ | | ||
+ | else | ||
+ | | ||
+ | |||
+ | if (s3.isPressed()==true) | ||
+ | | ||
+ | else | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | if (out[0] == 1) | ||
+ | | ||
+ | else | ||
+ | Motor.A.backward(); | ||
+ | |||
+ | if (out[1] == 1) | ||
+ | Motor.C.forward(); | ||
+ | else | ||
+ | Motor.C.backward(); | ||
+ | |||
+ | Thread.sleep(500); | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | public void buttonPressed(Button b) { | ||
+ | | ||
+ | } | ||
+ | | ||
+ | public void buttonReleased(Button b) { | ||
+ | | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | <Code Java linenums:1 | Listing 1: Die Methods-Klasse> | ||
+ | class Methods { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | byte i, j; | ||
+ | // Initialisieren der zufälligen Gewichte zwischen 0.1 und 0.9 | ||
+ | | ||
+ | |||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | | ||
+ | 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++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | | ||
+ | int i, j; | ||
+ | | ||
+ | |||
+ | // Initialisieren der Input-Vekoren | ||
+ | | ||
+ | |||
+ | // Berechnen der Werte im Hidden-Layer | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | // Berechnen der Output-Werte | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | // Berechnen der delta2 Fehler | ||
+ | | ||
+ | out_j = 0.1; | ||
+ | else if( out[j] == 1 ) | ||
+ | out_j = 0.9; | ||
+ | else | ||
+ | out_j = out[j]; | ||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | // Berechnen der delta1 Fehler | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | // Anpassen der Gewichte w2 | ||
+ | | ||
+ | |||
+ | |||
+ | // Anpassen der Gewichte w1 | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | int i, j; | ||
+ | | ||
+ | |||
+ | |||
+ | // Initialisieren der Input-Werte | ||
+ | | ||
+ | |||
+ | // Berechnen der Wete im Hidden-Layer | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | // Berechnen der Output-Werte | ||
+ | | ||
+ | sum = 0; | ||
+ | | ||
+ | |||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | // Übertragen des Outputs auf das Array out[] | ||
+ | | ||
+ | | ||
+ | else | ||
+ | | ||
+ | } | ||
+ | | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | <WRAP center round info 60%> | ||
+ | FIXME Der Quellcode enthält noch Fehler | ||
+ | </ | ||
+ | ==== Quellen ==== | ||
+ | * Download des orginales Artikels erschienen in JavaWorld 2005 | ||
+ | * [[https:// | ||
ein_neuronales_netz_fuer_den_nxt_roboter.1706265400.txt.gz · Zuletzt geändert: 2024/01/26 10:36 von torsten.roehl