- Akku Tests und Balkonkraftwerk Speicher         
Ergebnis 1 bis 10 von 10

Thema: Inkas Anfrage bezüglich Code, im Thema Linienfolger

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650

    Inkas Anfrage bezüglich Code, im Thema Linienfolger

    Hallo!

    Leider habe ich den Code nicht mehr, den ich verwendet habe, um die untenstehenden Ausgaben zu erzeugen.
    Aber trotzdem will ich mal einen Anfang machen.


    Hier noch mal die Idee zum Linienfolger, wobei der ganz genaue Antrieb (mit Problemen etc.) jezt mal nicht so wichtig ist.
    Es geht hier nur um eine gedankliche Skizze, um die KNN-Funktion anhand eines Beispiels zu veranschaulichen.




    Ich bin mit dem Thema noch nicht durch, aber ich habe zumindest einmal den Linienfolgermechanismus mit einer Wahrheitstabelle getestet.
    Als Quellcode habe ich den genommen, wo MXT den Link auf die Beispielseite gesetzt hat.


    Es sind etwa 2400 bis 2800 Trainingszyklen notwendig, bis die vorgegebene Genauigkeit erreicht wurde. Die Werte, welche diese bestimmen, wurden aus dem Originalquelltext beibehalten.
    Das Training dauert, auf einem nodeMCU ESP-12E, ca. 5 Sekunden.


    Da es sich um analoge Berechnungen handelt, sind die Werte der Ausgabeneurone Fließkomma-Näherungswerte. Eine Berechnung im KNN stellt immer eine Annäherung dar.
    Würden die Ausgaben, ohne Nachkommastellen, gerundet, erhielte man das gewünschte Ergebnis, als "0" oder "1".


    Die Trainingszyklen variieren bei jedem Neustart, weil in den Berechnungen Zufallswerte mitspielen. So werden u.a. die Neuronengewichte Anfangs mit Zufallswerten und nicht mit immer gleichen festen Werten initialisiert.
    Die Fließkommaergebnisse variieren genau so, weil es Näherungswerte sind und eben in den Berechnungen Zufallswerte mitspielen.


    Hier ein Schema, für das Netz aus 2 Input, 2 Hidden und 2 Output Neurons (ich hatte auf die Schnelle keine runden Symbole):
    Klicke auf die Grafik für eine größere Ansicht

Name:	beispNN.jpg
Hits:	8
Größe:	22,5 KB
ID:	34563



    Im Input haben wir 2 Eingänge. Der Erste, für den linken Sensor. Der Zweite für den rechten Sensor. In der Mitte der Sensoren soll die schwarze Linie verlaufen.


    Im Output haben wir 2 Ausgänge.
    Der Erste, für den linken Motor, der langsam vorwärts fährt oder steht (0); oder schneller vorwärts fährt (1).
    Der Zweite, für den rechten Motor, der langsam vorwärts fährt oder steht (0); oder schneller vorwärts fährt (1).




    1. Wenn sich der linke Sensor neben der schwarzen Linie befindet (0), kann der linke Motor laufen (1).
    2. Wenn sich der rechte Sensor neben der schwarzen Linie befindet (0), kann der rechte Motor laufen (1).
    3. Wenn sich der linke Sensor auf der schwarzen Linie befindet (1), kann der linke Motor stehen oder langsam drehen (0).
    4. Wenn sich der rechte Sensor auf der schwarzen Linie befindet (1), kann der rechte Motor stehen oder langsam drehen (0).


    Das Ergebnis des neuronalen Netzes sieht dazu so aus; zum Vergleich wird Target (das Muster, auf das zuvor trainiert wurde) mit ausgegeben; Target ist eine Vorgabe und wird nicht durch das neuronale Netz erzeugt:


    Input 0 0 Target 1 1 Output 0.98662 0.98579
    Input 1 0 Target 0 1 Output 0.01587 0.99852
    Input 0 1 Target 1 0 Output 0.99999 0.00660
    Input 1 1 Target 1 0 Output 0.99995 0.01100


    Input sind die Werte des linken und rechten Lichtsensors, auf die das KNN eine Ausgabe (Output) für den linken und rechten Motor erzeugen würde, um das Fahrzeug zu steuern.


    Das stellt für mich jetzt den einfachsten Fall einer solchen Steuerung dar, den man mit einem KNN umsetzen kann. Sozusagen das Notwendigste. Das Trainingsset ist als Wahrheitstabelle fest vorgegeben und wird durch die CPU so lange abgearbeitet, bis die richtigen Reaktionen der Ausgänge, auf die Eingangssignale, stattfinden.
    Verwendet habe ich 2 Eingangsneuronen, 2 versteckte Neuronen und 2 Ausgangsneuronen.


    Mit einem versteckten Neuron funktioniert es auch. Die Ergebnisse sind dann etwas genauer, die Trainingsphase dauert aber ca. 9 Sekunden, bei ca. 9000 Zyklen:


    Input 0 0 Target 1 1 Output 0.98612 0.98504
    Input 1 0 Target 0 1 Output 0.01456 0.99999
    Input 0 1 Target 1 0 Output 1.00000 0.00847
    Input 1 1 Target 1 0 Output 1.00000 0.00998


    Mit 10 versteckten Neuronen, ca. 900 Trainingszyklen, bei 4 Sekunden:


    Input 0 0 Target 1 1 Output 0.98621 0.98668
    Input 1 0 Target 0 1 Output 0.01535 0.99720
    Input 0 1 Target 1 0 Output 0.99992 0.00877
    Input 1 1 Target 1 0 Output 0.99469 0.00908


    Mit 20 versteckten Neuronen, ca. 800 Trainingszyklen, bei 4 Sekunden:


    Input 0 0 Target 1 1 Output 0.98555 0.98742
    Input 1 0 Target 0 1 Output 0.01570 0.99923
    Input 0 1 Target 1 0 Output 0.99999 0.00424
    Input 1 1 Target 1 0 Output 0.99645 0.01238


    Mit 50 versteckten Neuronen dauern die Berechnungen ca. 12 Sekunden, bei ca. 650 Trainingszyklen:


    Input 0 0 Target 1 1 Output 0.98657 0.98793
    Input 1 0 Target 0 1 Output 0.01528 0.99561
    Input 0 1 Target 1 0 Output 0.99999 0.00667
    Input 1 1 Target 1 0 Output 0.99218 0.01062






    Der Code müsste dafür so modifiziert werden, wenn der auf einem nodeMCU ausgeführt wird.
    Nur die Ausgabe entspricht nicht der, die ich hatte, weil ich dafür den Code
    noch weiter geändert habe, bloß diesen geänderten Code habe ich nicht mehr.


    Code:
    /******************************************************************
       ArduinoANN - An artificial neural network for the Arduino
       All basic settings can be controlled via the Network Configuration
       section.
       See robotics.hobbizine.com/arduinoann.html for details.
     ******************************************************************/
    
    
    #include <math.h>
    
    
    /******************************************************************
       Network Configuration - customized per network
     ******************************************************************/
    
    
    const float LearningRate = 0.3;
    const float Momentum = 0.9;
    const float InitialWeightMax = 0.5;
    const float Success = 0.0004;
    
    
    const int InputNodes = 2;
    const int HiddenNodes = 2;
    const int OutputNodes = 2;
    const int PatternCount = 4;  //zu trainierende Muster
    
    const byte Input[PatternCount][InputNodes] =
    {
      { 0, 0 },
      { 1, 0 },
      { 0, 1 },
      { 1, 1 } 
    }; 
    
    
    
    const byte Target[PatternCount][OutputNodes] =
    {
      { 1, 1 },  
      { 0, 1 }, 
      { 1, 0 }, 
      { 1, 0 }
    };
    
    
    /******************************************************************
       End Network Configuration
     ******************************************************************/
    
    
    
    
    int i, j, p, q, r;
    int ReportEvery1000;
    int RandomizedIndex[PatternCount];
    long  TrainingCycle;
    float Rando;
    float Error;
    float Accum;
    
    
    
    
    float Hidden[HiddenNodes];
    float Output[OutputNodes];
    float HiddenWeights[InputNodes + 1][HiddenNodes];
    float OutputWeights[HiddenNodes + 1][OutputNodes];
    float HiddenDelta[HiddenNodes];
    float OutputDelta[OutputNodes];
    float ChangeHiddenWeights[InputNodes + 1][HiddenNodes];
    float ChangeOutputWeights[HiddenNodes + 1][OutputNodes];
    
    
    void setup() {
      Serial.begin(9600);
      randomSeed(analogRead(3));
      ReportEvery1000 = 1;
      for ( p = 0 ; p < PatternCount ; p++ )
      {
        RandomizedIndex[p] = p ;
      }
    }
    
    
    void loop ()
    {
    
    
    
    
      /******************************************************************
        Initialize HiddenWeights and ChangeHiddenWeights
      ******************************************************************/
    
    
      for ( i = 0 ; i < HiddenNodes ; i++ )
      {
        for ( j = 0 ; j <= InputNodes ; j++ )
    
    
        {
          ChangeHiddenWeights[j][i] = 0.0 ;
          Rando = float(random(100)) / 100;
          HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
        }
      }
      /******************************************************************
        Initialize OutputWeights and ChangeOutputWeights
      ******************************************************************/
    
    
      for ( i = 0 ; i < OutputNodes ; i ++ )
      {
        for ( j = 0 ; j <= HiddenNodes ; j++ )
        {
          ChangeOutputWeights[j][i] = 0.0 ;
          Rando = float(random(100)) / 100;
          OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
        }
      }
      Serial.println("Initial/Untrained Outputs: ");
      toTerminal();
      /******************************************************************
        Begin training
      ******************************************************************/
    
    
      for ( TrainingCycle = 1 ; TrainingCycle < 2147483647 ; TrainingCycle++)
      {
         yield();
    
    
        /******************************************************************
          Randomize order of training patterns
        ******************************************************************/
    
    
        for ( p = 0 ; p < PatternCount ; p++)
        {
          q = random(PatternCount);
          r = RandomizedIndex[p] ;
          RandomizedIndex[p] = RandomizedIndex[q] ;
          RandomizedIndex[q] = r ;
        }
        Error = 0.0 ;
        /******************************************************************
          Cycle through each training pattern in the randomized order
        ******************************************************************/
        for ( q = 0 ; q < PatternCount ; q++ )
        {
          p = RandomizedIndex[q];
    
    
          /******************************************************************
            Compute hidden layer activations
          ******************************************************************/
    
    
          for ( i = 0 ; i < HiddenNodes ; i++ )
          {
            Accum = HiddenWeights[InputNodes][i] ;
            for ( j = 0 ; j < InputNodes ; j++ )
            {
              Accum += Input[p][j] * HiddenWeights[j][i] ;
            }
            Hidden[i] = 1.0 / (1.0 + exp(-Accum)) ;
          }
    
    
          /******************************************************************
            Compute output layer activations and calculate errors
          ******************************************************************/
    
    
          for ( i = 0 ; i < OutputNodes ; i++ )
          {
            Accum = OutputWeights[HiddenNodes][i] ;
            for ( j = 0 ; j < HiddenNodes ; j++ )
            {
              Accum += Hidden[j] * OutputWeights[j][i] ;
            }
            Output[i] = 1.0 / (1.0 + exp(-Accum)) ;
            OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]) ;
            Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]) ;
          }
    
    
          /******************************************************************
            Backpropagate errors to hidden layer
          ******************************************************************/
    
    
          for ( i = 0 ; i < HiddenNodes ; i++ )
          {
            Accum = 0.0 ;
            for ( j = 0 ; j < OutputNodes ; j++ ) {
              Accum += OutputWeights[i][j] * OutputDelta[j] ;
            }
            HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]) ;
          }
    
    
    
    
          /******************************************************************
            Update Inner-->Hidden Weights
          ******************************************************************/
    
    
    
    
          for ( i = 0 ; i < HiddenNodes ; i++ )
          {
            ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i] ;
            HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i] ;
            for ( j = 0 ; j < InputNodes ; j++ )
            {
              ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i];
              HiddenWeights[j][i] += ChangeHiddenWeights[j][i] ;
            }
          }
    
    
          /******************************************************************
            Update Hidden-->Output Weights
          ******************************************************************/
    
    
          for ( i = 0 ; i < OutputNodes ; i ++ )
          {
            ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i] ;
            OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i] ;
            for ( j = 0 ; j < HiddenNodes ; j++ )
            {
              ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i] ;
              OutputWeights[j][i] += ChangeOutputWeights[j][i] ;
            }
          }
        }
    
    
        /******************************************************************
          Every 1000 cycles send data to terminal for display
        ******************************************************************/
        ReportEvery1000 = ReportEvery1000 - 1;
        if (ReportEvery1000 == 0)
        {
          Serial.println();
          Serial.println();
          Serial.print ("TrainingCycle: ");
          Serial.print (TrainingCycle);
          Serial.print ("  Error = ");
          Serial.println (Error, 5);
    
    
          toTerminal();
    
    
          if (TrainingCycle == 1)
          {
            ReportEvery1000 = 999;
          }
          else
          {
            ReportEvery1000 = 1000;
          }
        }
    
    
    
    
        /******************************************************************
          If error rate is less than pre-determined threshold then end
        ******************************************************************/
    
    
        if ( Error < Success ) break ;
      }
      Serial.println ();
      Serial.println();
      Serial.print ("TrainingCycle: ");
      Serial.print (TrainingCycle);
      Serial.print ("  Error = ");
      Serial.println (Error, 5);
    
    
      toTerminal();
    
    
      Serial.println ();
      Serial.println ();
      Serial.println ("Training Set Solved! ");
      Serial.println ("--------");
      Serial.println ();
      Serial.println ();
      ReportEvery1000 = 1;
      while(1){yield();}
    }
    
    
    void toTerminal()
    {
    
    
      for ( p = 0 ; p < PatternCount ; p++ )
      {
        Serial.println();
        Serial.print ("  Training Pattern: ");
        Serial.println (p);
        Serial.print ("  Input ");
        for ( i = 0 ; i < InputNodes ; i++ )
        {
          Serial.print (Input[p][i], DEC);
          Serial.print (" ");
        }
        Serial.print ("  Target ");
        for ( i = 0 ; i < OutputNodes ; i++ )
        {
          Serial.print (Target[p][i], DEC);
          Serial.print (" ");
        }
        /******************************************************************
          Compute hidden layer activations
        ******************************************************************/
    
    
        for ( i = 0 ; i < HiddenNodes ; i++ )
        {
          Accum = HiddenWeights[InputNodes][i] ;
          for ( j = 0 ; j < InputNodes ; j++ )
          {
            Accum += Input[p][j] * HiddenWeights[j][i] ;
          }
          Hidden[i] = 1.0 / (1.0 + exp(-Accum)) ;
        }
    
    
        /******************************************************************
          Compute output layer activations and calculate errors
        ******************************************************************/
    
    
        for ( i = 0 ; i < OutputNodes ; i++ )
        {
          Accum = OutputWeights[HiddenNodes][i] ;
          for ( j = 0 ; j < HiddenNodes ; j++ )
          {
            Accum += Hidden[j] * OutputWeights[j][i] ;
          }
          Output[i] = 1.0 / (1.0 + exp(-Accum)) ;
        }
        Serial.print ("  Output ");
        for ( i = 0 ; i < OutputNodes ; i++ )
        {
          Serial.print (Output[i], 5);
          Serial.print (" ");
        }
      }
    
    
    
    
    }

    MfG


    - - - Aktualisiert - - -

    Zur Frage, was muss wo gestellt werden oder eingetragen werden, ist ein Grundverständnis notwendig.

    in Input[PatternCount][InputNodes] werden die möglichen Eingangszustände vorgegeben, bei 2 Eingängen sind es eben 4 Stück (PatternCount = 4).
    in Target[PatternCount][OutputNodes] werden zu den Eingangszuständen, die Ausgangszustände vorgegeben.

    Das Netz wird trainiert, indem die Eingangszustände "eingeübt" werden. Dafür werden bei jedem Durchlauf immer die Ergebnisse an den Ausgabeneuronen mit den Werten in Target[x][y] verglichen und dann Korrekturen durchgeführt. Wenn eine vorgegebene Genauigkeit erreicht ist, ist das Training beendet. Ab dem Zeitpunkt kann dann jeder der möglichen Eingangszustände auf den trainierten Ausgangszustand "übersetzt" werden. Und zwar ohne, dass die Trainingsdaten für die Ausgänge hinzugezogen werden.
    So wie es vorliegt, mit einer verdeckten Schicht, ähnelt das Ganze mehr einem Logikgatter mit beliebig vielen Eingängen und beliebig vielen Ausgängen. Die Logik ist aber nicht fest verdrahtet, sondern frei wählbar. Das Programm rechnet dann so lange, bis es alle Eingangszustände auf die gewünschten Ausgangszustände abbilden kann.
    Geändert von Moppi (16.12.2019 um 07:43 Uhr) Grund: Fehler im Quelltext behoben

Ähnliche Themen

  1. [ERLEDIGT] Eine Bitte bezüglich des Code-Tag Buttons
    Von TobiKa im Forum Anregungen/Kritik/Fragen zum Forum und zum Wiki RN-Wissen
    Antworten: 4
    Letzter Beitrag: 23.03.2011, 15:44
  2. Anfrage
    Von pota20 im Forum Allgemeines zum Thema Roboter / Modellbau
    Antworten: 0
    Letzter Beitrag: 15.11.2009, 15:08
  3. Anfrage Unterstützung
    Von BenniX im Forum Bauanleitungen, Schaltungen & Software nach RoboterNetz-Standard
    Antworten: 3
    Letzter Beitrag: 08.07.2008, 08:25
  4. Nur eine I2C Anfrage?
    Von franzlst im Forum Schaltungen und Boards der Projektseite Mikrocontroller-Elektronik.de
    Antworten: 2
    Letzter Beitrag: 21.02.2007, 01:06
  5. Anfrage SPI - I2S
    Von olafk im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 10.09.2005, 14:19

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress