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:29] – [Neural Networks] torsten.roehl | ein_neuronales_netz_fuer_den_nxt_roboter [2024/01/26 11:20] (aktuell) – [Quellcode] torsten.roehl | ||
---|---|---|---|
Zeile 19: | Zeile 19: | ||
|Abb. 2: Das Perzeptron mit einfacher Aktivierungsfunktion| | |Abb. 2: Das Perzeptron mit einfacher Aktivierungsfunktion| | ||
- | Die Inputwerte ($x_1$, $x_2$, $x_3$, ..., $x_n$) und die Verbindungsgewichte ($w_1$, | + | Die Inputwerte ($x_1$, $x_2$, $x_3$, ..., $x_n$) und die Verbindungsgewichte ($w_1$, |
+ | === Beispiel | ||
+ | Wenn $x_i$ das // | ||
<color # | <color # | ||
==== Backpropagation-Netzwerke ==== | ==== Backpropagation-Netzwerke ==== | ||
+ | Ein Backpropagation-Netzerk (**Backpropagation** engl. für Fehlerrückführung) ist ein neuronales Netz, in dem die Neuronen in Ebenen angeordnet sind, wobei jedes Neuron eines Layers (einer Ebene) mit jedem Neuron des darüber liegenden Layers verbunden ist.\\ Des weiteren feuern die Neuronen nur in eine Richtung, auf die nächsthöhere Ebene. In diesem Fall fließt die Aktivität vom // | ||
+ | |||
+ | |{{ : | ||
+ | |Abb. 3: Ein typisches neuronales Netzwerk mit 3 Layers (Schichten)| | ||
+ | |||
+ | |||
+ | Den Gewichten in einem // | ||
+ | |||
+ | Diese werden genutzt, um die Gewichte, die mit dem Output-Layer verbunden sind, so neu zu berechnen, dass die Fehler reduziert werden. Aus den Fehlerwerten der Output-Neuronen werden nun Fehlerabschätzungen der Hidden-Neuronen berechnet. Aus diesen Fehlerwerten werden die Gewichte zwischen Input- und Hidden-Layer neu justiert. | ||
+ | |||
+ | Nach jeder Runde " | ||
==== Der Backpropagation-Algorithmus==== | ==== Der Backpropagation-Algorithmus==== | ||
+ | Ausgehend von einem Satz von Inputvektoren und den zugehörigen Oututvektoren (Vektorenpaar), | ||
+ | |||
+ | Sei A die Anzahl der Neuronen auf dem Input-Layer, | ||
+ | |||
+ | |||
+ | ^Step^Beschreibung^ | ||
+ | |1.|< | ||
+ | * $w1_{ij}$='' | ||
+ | * $w2_{ij}$='' | ||
+ | </ | ||
+ | |2.|< | ||
+ | * $x_0=1.0$ | ||
+ | * $h_0=1.0$ | ||
+ | </ | ||
+ | |3.|< | ||
+ | </ | ||
+ | |4.|< | ||
+ | \begin{equation} | ||
+ | </ | ||
+ | |5.|< | ||
+ | \begin{equation} | ||
+ | </ | ||
+ | |6.|< | ||
+ | \begin{equation} \delta 2_j = o_j(1-o_j)(y_j-o_j) \end{equation} | ||
+ | |||
+ | </ | ||
+ | |7.|< | ||
+ | |||
+ | \begin{equation} \delta 1_j = h_j(1-h_j) \sum_{i_1}^C \delta2_i\; | ||
+ | </ | ||
+ | |8.|< | ||
+ | \begin{equation} \Delta w2_{ij} = \eta \delta 2_jh_i \end{equation} | ||
+ | * für alle i=0, ..., B, j=1, ..., C | ||
+ | </ | ||
+ | |9.|< | ||
+ | \begin{equation} \Delta w1_{ij} = \eta \delta 1_jh_i \end{equation} | ||
+ | * 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 $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 // | ||
+ | |||
+ | |||
==== 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.1706264974.txt.gz · Zuletzt geändert: 2024/01/26 10:29 von torsten.roehl