# Neuronales Netz mit backpropagation-Lernalgorithmus mit On-Neuron



## minzee (9. Feb 2015)

Ein paar Leute wissen vielleicht, dass ich mit KI herumexperimentiere.  Dazu gibt es auch ein anderes Thema (http://www.java-forum.org/codeschnipsel-u-projekte/164889-backpropagation-netz.html) mit etwas Java-Code. Aber mit Java werde ich in diesem Fall nicht glücklich. Es kann keine Mehrfachvererbung und AspectJ scheint mir auch keine Lösung. Nachdem ich hier in einem anderen Thema schon über einen PHP-Programmierer gestolpert bin, habe ich das Programm nun nach PHP übersetzt. PHP kann zwar auch keine Mehrfachvererbung, aber es kann Traits.

Ich habe das Ergebnis meines Programms mit http://www.wi.hs-wismar.de/~laemmel/files/backprop.xls verglichen. Das ist ein EXCEL-Sheet vom Universitäts-Professor Uwe Lämmel. Es verwendet Makros. Infos zu Thema siehe Vorw 

Mein Programm liefert das gleiche Ergebnis wie das EXCEL-Sheet. Grundsätzlich scheint es also hoffentlich zu funktionieren. Aber vielleicht seht ihr trotzdem noch irgendetwas, was man besser machen kann. Oder vielleicht hat sich doch noch irgendwo ein Fehler eingeschlichen.

Der Code ist leider zu lange für eine einzige Nachricht, darum habe ich ihn auf die folgenden 2 Nachrichten aufgeteilt. Freue mich über jedes Feedback


----------



## minzee (9. Feb 2015)

```
<?php
   error_reporting(-1);
   
   define('DEBUG', true);
   
   /**
    * Unabsichtliches Setzen oder Auslesen von nicht definierten Eigenschaften verhindern.
    */
   trait T
   {
      function __get($name)
      {
         throw new Exception('get');
      }
      function __set($name, $value)
      {
         throw new Exception('set');
      }
   }
   
   interface IPropagationFunc
   {
      function f(ILearnable $neuron);
      function fPrimeW(ILearnable $neuron, $i);
      function fPrimeO(ILearnable $neuron, $i);
   }
   
   interface ILearnableFunc
   {
      function f($x);
      function fPrime($x);
   }
   
   interface IActivationFunc extends ILearnableFunc
   {
   }
   
   interface IOutputFunc extends ILearnableFunc
   {
   }
   
   class LinearFunc implements IPropagationFunc
   {
      private $weights;
       
      /**
       * Lineare Funktion
       */
      function __construct(array &$weights)
      {
         $this->weights = &$weights;
      }
      /**
       * Funktion
       * @param ILearnable $neuron Zu diesem Neuron wird net berechnet.
       * @return number 
       */
      function f(ILearnable $neuron)
      {
         $net = 0;
         $count = count($neuron->predecessors);
         for($p = 0; $p < $count; ++$p)
         {
            $predecessor = $neuron->predecessors[$p];
            $net += $predecessor->getO() * $this->weights[$predecessor->getId()][$neuron->getId()];
         }
         return $net;
      }
      /**
       * Partielle Ableitung der Funktion nach dem Gewicht einer eingehenden Verbindung.
       * @param ILearnable $neuron 
       * @param int i Nummer des Vorgängers aus der Liste der Vorgänger.
       * @return number Ausgabe des Vorgängers
       */
      function fPrimeW(ILearnable $neuron, $i) 
      {
         return $neuron->predecessors[$i]->getO();
      }
      /**
       * Partielle Ableitung der Funktion nach der Ausgabe eines bestimmten Vorgängers.
       * @param ILearnable $neuron 
       * @param int $i Nummer des Vorgängers aus der Liste der Vorgänger.
       * @return number Gewicht der eingehenden Verbindung
       */
      function fPrimeO(ILearnable $neuron, $i)
      {
         return $this->weights[$neuron->predecessors[$i]->getId()][$neuron->getId()];
      }
   }
   
   /**
    * Logistische Funktion
    */
   class SigmoidFunc implements IActivationFunc
   {
      private $c;
      
      function __construct($c)
      {
         $this->c = $c;
      }
      /**
       * Funktion
       * @param number $x
       * @return number (0, 1)
       */
      function f($x)
      {
         return 1 / (1 + exp(-$this->c * $x));
      }
      /**
       * Ableitung der Funktion
       * @param number $x Ergebnis der propagation-Funktion
       * @return number > 0
       */
      function fPrime($x)
      {
         $exp = exp(-$this->c * $x);
         return $this->c * $exp / pow(1 + $exp, 2);
      }
   }
   
   /**
    * Identität
    */
   class IdentityFunc implements IOutputFunc
   {
      /**
       * Funktion
       * @param number $x
       * @return number x
       */
      function f($x)
      {
         return $x;
      }
      /**
       * Ableitung der Funktion
       * @param number $x Ergebnis der activation-Funktion
       * @return int 1
       */
      function fPrime($x)
      {
         return 1;
      }
   }
     
   interface IUpdateable 
   {
   }
   
   interface ILearnable 
   {
   }
   
   abstract class Neuron 
   {
      use T;
      
      protected $id;     // eindeutige Neuron-ID
      protected $o;      // output
      public $layer = 0; // Hilfsvariable, um die Neuronen Schichten zuordnen zu können.
   
      function getId()
      {
         return $this->id;
      }
      /**
       * @return null|number
       */
      function getO()
      {
         return $this->o;
      }
   }

   trait TUpdate 
   {
      public $successors = [];
   }
   
   trait TLearn
   {
      public $predecessors = [];
      
      private $pF; // propagation-function
      private $aF; // activation-functioin
      private $oF; // output-function
      
      private $net;
      private $a;
      
      private $errSig; // Fehlersignal
      
      function __construct($id, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
      {
         $this->id = $id;
         $this->pF = $pF;
         $this->aF = $aF;
         $this->oF = $oF;
      }
      /**
       * Ausgang berechnen. 
       */
      function setO()
      {
         $this->net = $this->pF->f($this);
         $this->a = $this->aF->f($this->net);
         $this->o = $this->oF->f($this->a);
         
         if(DEBUG)
         {
            echo "Neuron ", $this->id, " net: ", $this->net, "\n";
            echo "Neuron ", $this->id, " o: ", $this->o, "\n";
         }
      }
      /**
       * Fehlersignal setzen.
       * @param number $err Fehler
       */
      function _setErrSig($err)
      {
         $this->errSig = $err * $this->oF->fPrime($this->a) * $this->aF->fPrime($this->net);
         
         if(DEBUG)
         {
            echo "Neuron ", $this->id, " fSig: ", $this->errSig, "\n";
         }
      }
      /**
       * @return null|number
       */
      function getErrSig()
      {
         return $this->errSig;
      }
   }
   
   class InputNeuron extends Neuron implements IUpdateable
   {
      use TUpdate;
      
      function __construct($id)
      {
         $this->id = $id;
      }
      function setO($o)
      {
         $this->o = $o;
      }
   }
   
   class HiddenNeuron extends Neuron implements IUpdateable, ILearnable
   {
      use TUpdate;
      use TLearn;
      
      /**
       * Fehlersignal setzen. 
       * @param array $weights
       */
      function setErrSig(array &$weights)
      {
         $err = 0;
         for($s = 0; $s < count($this->successors); ++$s)
         {
            $successor = $this->successors[$s];
            $err += $weights[$this->id][$successor->id] * $successor->getErrSig();
         }
         $this->_setErrSig($err); // falls oF = Identität und aF = sigmoide Funktion => sum(w[s] * errSig[s]) * 1 * c * o * (1 - o)
      }
   }
   
   class OutputNeuron extends Neuron implements ILearnable
   {
      use TLearn;
      
      /**
       * Fehlersignal setzen.
       * @param number $target Sollwert
       */
      function setErrSig($target)
      {
         $this->_setErrSig($target - $this->o); // falls oF = Identität und aF = sigmoide Funktion => (t - o) * 1 * c * o * (1 - o)
      }
   }
   
   class OnNeuron extends Neuron implements IUpdateable
   {
      use TUpdate;
      
      function __construct($id)
      {
         $this->id = $id;
         $this->o = 1;
      }
   }
   
   /**
    * Helper-Klasse
    */
   class Layers
   {
      use T;

      /**
       * Aufgrund der Gewichtsmatrix eruieren, ob ein Neuron ein Eingabe-Neuron ist.
       * @param array $weights Gewichtsmatrix
       * @param int $x Neuron-ID (Spalte der Gewichtsmatrix)
       * @return boolean
       */
      private static function isInputNeuron(array &$weights, $x)
      {
         $count = count($weights);
         for($y = 0; $y < $count; ++$y)
         {
            if($weights[$y][$x] != 0)
            {
               return false;
            }
         }
         return true;
      }
      /**
       * Aufgrund der Gewichtsmatrix eruieren, ob ein Neuron ein Ausgabe-Neuron ist.
       * @param array $weights Gewichtsmatrix
       * @param int $y Neuron-ID (Zeile der Gewichtsmatrix)
       * @return boolean
       */
      private static function isOutputNeuron(array &$weights, $y)
      {
         $count = count($weights);
         for($x = 0; $x < $count; ++$x)
         {
            if($weights[$y][$x] != 0)
            {
               return false;
            }
         }
         return true;
      }
      /**
       * Basierend auf der Matrix ein Array von Neuronen erzeugen.
       * @param array $weights Gewichtsmatrix
       * @return array
       */
      private static function createNeurons(array &$weights, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
      {
         $neurons = [];
         $count = count($weights);
         for($i = 0; $i < $count; ++$i)
         {
            if(self::isInputNeuron($weights, $i))
            {
               $neurons[] = new InputNeuron($i);
            }
            elseif(self::isOutputNeuron($weights, $i))
            {
               $neurons[] = new OutputNeuron($i, $pF, $aF, $oF);
            }
            else
            {
               $neurons[] = new HiddenNeuron($i, $pF, $aF, $oF);
            }
         }      
         return $neurons;
      }
      /**
       * In den Neuronen Beziehungen (Vorgänger, Nachfolger) zu anderen Neuronen definieren.
       * @param array $weights Gewichtsmatrix
       * @param array $neurons
       */
      private static function defineNeuronRelations(array &$weights, array &$neurons)
      {     
         $countI = count($weights);
         for($i = 0; $i < $countI; ++$i)
         {
            $neuron = $neurons[$i];
            
            // Nachfolger definieren (für input-Neuronen und verdeckte Neuronen):
            if($neuron instanceof IUpdateable)
            {
               $countX = count($weights[$i]);
               for($x = 0; $x < $countX; ++$x)
               {
                  if($weights[$i][$x] != 0)
                  {
                     $neuron->successors[] = $neurons[$x];
                  }
               }
            }
            
            // Vorgänger definieren (für verdeckte Neuronen und output-Neuronen):
            if($neuron instanceof ILearnable)
            {
               $countY = count($weights[$i]);
               for($y = 0; $y < $countY; ++$y)
               {
                  if($weights[$y][$i] != 0)
                  {
                     $neuron->predecessors[] = $neurons[$y];
                  }
               }
            }
         }
      }
      /**
       * Neuronen Ebenen zuordnen.
       * @param array $neurons
       */
      private static function defineNeuronLayers(array &$neurons)
      {
         $countI = count($neurons);
         for($i = 0; $i < $countI; ++$i)
         {
            $neuron = $neurons[$i];
            if($neuron instanceof IUpdateable)
            {
               $successors = $neuron->successors;
               $countS = count($successors);
               for($s = 0; $s < $countS; ++$s)
               {
                  $successor = $successors[$s];
                  $successor->layer = max($neuron->layer + 1, $successor->layer);
               }
            }
         }
      }
      /**
       * Ebenen zurückgeben.
       * @param array $weights Gewichtsmatrix
       * @return array layers Ebenen und ihre Neuronen
       */
      static function get(array &$weights, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF)
      {
         // Basierend auf der Matrix ein Array von Neuronen erzeugen:
         $neurons = self::createNeurons($weights, $pF, $aF, $oF);
         
         // In den Neuronen Beziehungen (Vorgänger, Nachfolger) zu anderen Neuronen definieren:
         self::defineNeuronRelations($weights, $neurons);
         
         // In den Neuronen definieren, in welcher Ebene sie sich befinden:
         self::defineNeuronLayers($neurons);
      
         // Ebenen-Liste erzeugen:
         $count = count($neurons);
         for($i = 0; $i < $count; ++$i)
         {
            $neuron = $neurons[$i];
            $layers[$neuron->layer][] = $neuron;
         }
         
         if(DEBUG)
         {
            // Neuronen-Typen:
            for($i = 0; $i < $count; ++$i)
            {
               $neuron = $neurons[$i];
               if($neuron instanceof InputNeuron)
               {
                  echo "Neuron ", $i, " ist ein input-Neuron.\n";
               }
               elseif($neuron instanceof HiddenNeuron)
               {
                  echo "Neuron ", $i, " ist ein Neuron einer verdeckten Schicht.\n";
               }
               else
               {
                  echo "Neuron ", $i, " ist ein output-Neuron.\n";
               }
            }
         
            // Beziehungen:
            for($i = 0; $i < $count; ++$i)
            {
               $neuron = $neurons[$i];
               if($neuron instanceof IUpdateable)
               {
                  echo "Nachfolger von Neuron ", $neuron->getId(), ": ";
                  $countS = count($neuron->successors);
                  for($s = 0; $s < $countS; ++$s)
                  {
                     echo $neuron->successors[$s]->getId(), " ";
                  }
                  echo "\n";
               }
               if($neuron instanceof ILearnable)
               {
                  echo "Vorgänger von Neuron ", $neuron->getId(), ": ";
                  $countP = count($neuron->predecessors);
                  for($p = 0; $p < $countP; ++$p)
                  {
                     echo $neuron->predecessors[$p]->getId(), " ";
                  }
                  echo "\n";
               }              
            }

            // Layer:
            $countL = count($layers);
            for($l = 0; $l < $countL; ++$l) // layers
            {
               echo "Ebene ", $l, ": ";
               $countN = count($layers[$l]);
               for($n = 0; $n < $countN; ++$n) // neurons
               {
                  $neuron = $layers[$l][$n];
                  echo $neuron->layer, "/", $neuron->getId(), " ";
               }
               echo "\n";
            }
         }
         
         return $layers;
      }
   }
```


----------



## minzee (9. Feb 2015)

```
class BackpropagationNet
   {
      use T;

      private $weights;
      private $layers;
      private $onNeuron;
      
      /**
       * Gewichte der Verbindungen von On-Neuronen werden mit 0.5 definiert.
       * @param boolean $on ob mit On-Neuron
       */
      function __construct(array &$weights, IPropagationFunc $pF, IActivationFunc $aF, IOutputFunc $oF, $on)
      {
         // Neuronen erzeugen und in den Schichten ablegen:
         $this->layers = Layers::get($weights, $pF, $aF, $oF);
         
         // Gewichtsmatrix expandieren, falls mit On-Neuron gearbeitet werden soll:
         if($on)
         {
            $this->addOnNeuron($weights);
         }
         
         $this->weights = &$weights;
      }
      /**
       * Gewichtsmatrix um ein On-Neuron erweitern.
       */
      private function addOnNeuron(array &$weights)
      {
         $count = count($weights);
         
         // Spalte an existierende Zeilen anghängen:
         for($y = 0; $y < $count; ++$y)
         {
            $weights[$y][] = 0;
         }
         
         // Zeile anhängen:
         $weights[$count] = array_fill(0, $count + 1, 0);
         
         // Neues Neuron-Objekt:
         $this->onNeuron = new OnNeuron($count);
         
         // Verbindungen des On-Neurons zu den verdeckten Neuronen und Ausgabe-Neuronen:
         $countL = count($this->layers);
         for($l = 1; $l < $countL; ++$l)
         {
            $countN = count($this->layers[$l]);
            for($n = 0; $n < $countN; ++$n)
            {
               $neuron = $this->layers[$l][$n];
               
               // Verbindungsgewicht in Matrix setzen:
               $weights[$count][$neuron->getId()] = 0.5;
               
               // Dem On-Neuron einen Nachfolger hinzufügen:
               $this->onNeuron->successors[] = $neuron;
               
               // Dem aktuellen Neuron einen Vorgänger hinzufügen:
               $neuron->predecessors[] = $this->onNeuron;
            }
         } 
      }
      /**
       * Werte der Neuronen der Eingabeschicht setzen.
       * @param array $inputs
       * @throws Exception falls die Anzahl der inputs-Werte nicht der Anzahl der Eingabe-Neuronen entspricht
       */
      function setInputs(array $inputs)
      {
         // Anzahl der Eingabe-Neuronen:
         $count = count($this->layers[0]);
         
         // Kontrolle, ob Anzahl der Eingabe-Werten mit der Anzahl der Eingabe-Neuronen übereinstimmt:
         if(count($inputs) != $count)
         {
            throw new Exception('invalid count inputs');
         }
         
         // Eingänge setzen:
         for($n = 0; $n < $count; ++$n)
         {
            $this->layers[0][$n]->setO($inputs[$n]);
            
            if(DEBUG)
            {
               echo "Neuron ", $this->layers[0][$n]->getId(), " in: ", $this->layers[0][$n]->getO(), "\n";
            }
         }
      }
      /**
       * Setzt die Ausgabe der Neuronen der verdeckten Schicht und Ausgabeschicht.
       */
      function setOutputs()
      {
         $countLayers = count($this->layers);
         for($l = 1; $l < $countLayers; ++$l) 
         {
            // Anzahl der Neuronen der aktuellen Schicht:
            $countNeurons = count($this->layers[$l]);
            
            // Ausgänge der Neuronen der aktuellen Schicht berechen:
            for($n = 0; $n < $countNeurons; ++$n)
            {
               $this->layers[$l][$n]->setO(); 
            }
         }
         // In der Eingabeschicht müssen keine Ausgaben berechnet werden.
         // Sie entsprechen unverändert den Eingaben.
      }
      /**
       * Passt die Gewichte ausgehender Verbindungen an.
       * @param Neuron neuron
       * @param number LerningRate
       */
      function updateWeights(Neuron $neuron, $learningRate)
      {
         if(DEBUG)
         {
            echo "Gewichte ausgehender Verbindungen von Neuron ", $neuron->getId(), ":\n";
         }
         
         $count = count($neuron->successors);
         for($s = 0; $s < $count; ++$s)
         {
            $successor = $neuron->successors[$s];
            $deltaW = $learningRate * $neuron->getO() * $successor->getErrSig();
            $this->weights[$neuron->getId()][$successor->getId()] += $deltaW;
            
            if(DEBUG)
            {
               echo "   zu Nachfolger ", $successor->getId(), " deltaW: ", $deltaW, "\n";
               echo "   zu Nachfolger ", $successor->getId(), " w: ", $this->weights[$neuron->getId()][$successor->getId()], "\n";
            }
         }
      }
      /**
       * Gibt den Netzfehler zurück.
       * @param array $targets Werte des Musters
       * @return number
       */
      function getError(array &$targets)
      {
         $err = 0;
         
         // Ausgabeebene:
         $l = count($this->layers) - 1; 
         
         // Anzahl der Ausgabe-Neuronen:
         $count = count($this->layers[$l]);
         
         // Fehler aufsummieren:
         for($n = 0; $n < $count; ++$n)
         {
            $err += pow($targets[$n] - $this->layers[$l][$n]->getO(), 2);
         }
         
         return $err;
      }
      /**
       * 1 Muster lernen.
       * @param number $learningRate
       * @param array $targets Werte des Musters
       * @return number 
       *    Trainingsfehler (Fehler beim Lernen, bezogen auf das gesamten Netz)
       *    Summe aus den quadartischen Fehlern aller Ausgabe-Neuronen
       * @throws Exception falls die Anzahl der target-Werte nicht der Anzahl der Ausgabe-Neuronen entspricht
       */
      function learn($learningRate, array &$targets)
      {
         $l = count($this->layers) - 1;     // Ausgabe-Schicht
         $count = count($this->layers[$l]); // Anzahl der Ausgabe-Neuronen
         if(count($targets) != $count)
         {
            throw new Exception("invalid count target");
         }
         
         // Ausgabeschicht:
         for($n = 0; $n < $count; ++$n)
         {
            $this->layers[$l][$n]->setErrSig($targets[$n]); // fSig = c * o * (1 - o) * (t - o)
         }
         
         // Verdeckte Schichten:
         for($l = count($this->layers) - 2; $l > 0; --$l) 
         {         
            $count = count($this->layers[$l]);
            for($n = 0; $n < $count; ++$n)
            {
               $neuron = $this->layers[$l][$n];
               
               // Zuerst muss das Fehlersignal des aktuellen Neurons berechnet werden (benötigt die alten Gewichte zu seinen Nachfolgern):
               $neuron->setErrSig($this->weights); // fSig = c * o * (1 - o) * Sum(w[successor] * fSig[successor])

               // Danach können die Gewichte der Verbindungen zu seinen Nachfolgern aktualisiert werden:
               $this->updateWeights($neuron, $learningRate); // je successor: w[successor] += lernrate * o * fSig[successor]
            }
         }
         
         // Eingabeschicht:
         $count = count($this->layers[0]);
         for($n = 0; $n < $count; ++$n)
         {
            $this->updateWeights($this->layers[0][$n], $learningRate); // je successor: w[successor] += lernrate * o * fSig[successor]
         }
         
         // On-Neuron:
         if($this->onNeuron != null)
         {
            $this->updateWeights($this->onNeuron, $learningRate);
         }
         
         // Nach den Aktualisierungen der Gewichte die Ausgaben neu berechnen:
         $this->setOutputs();
         
         // Noch bestehenden Fehler zurückgeben:
         return $this->getError($targets);
      }
   }
   
   function dump(array &$weights)
   {
      for($y = 0; $y < count($weights); ++$y)
      {
         for($x = 0; $x < count($weights[$y]); ++$x)
         {
            echo $weights[$y][$x], " ";
         }
         echo "\n";
      }
   }
     
   // Konstante c für logarithmische Funktion:
   $c = 1;
   
   // Lernrate:
   $learningRate = 0.5;
   
   // Architektur:
   //    0             1  Eingabeschicht
   //     \\         //
   //      \ \     / /
   //       \  \ /  /
   //        \  2  /      verdeckte Schicht
   //         \ | /
   //          \|/
   //           3         Ausgabeschicht
   //    Die Neuronen 2 und 3 hängen an einem On-Neuron.
   
   // Gewichte:
   $weights = // connection [from][to]
   [  
   //   0    1            2                    3
      [0.0, 0.0, -0.693072371801492,  0.757039433217412], // 0
      [0.0, 0.0,  0.373419505445732, -0.22438301746938],  // 1
      [0.0, 0.0,  0.0,               -0.732313332093937], // 2
      [0.0, 0.0,  0.0,                0.0]                // 3
   ];
   // Wenn die Gewichte in die EXCEL-Tabelle kopiert werden, die Punkte durch Kommas ersetzen!
   // -0,693072371801492  0,757039433217412
   //  0,373419505445732 -0,22438301746938
   //                    -0,732313332093937
   //
   //  0,5                0,5
      
   // Eingaben (Muster):
   $patterns = 
   [
      [0.0, 0.0],
      [0.0, 0.1],
      [1.0, 0.0],
      [1.0, 1.0]
   ];
      
   // Sollwerte für Ausgaben:
   $targets = 
   [
      [0.0], 
      [1.0], 
      [1.0], 
      [0.0]
   ];
   
   // Funktionen:
   $pF = new LinearFunc($weights);
   $aF = new SigmoidFunc($c);
   $oF = new IdentityFunc();
   
   // neuronales Netz mit backpropagation-Lernalgorithmus:
   $net = new BackpropagationNet($weights, $pF, $aF, $oF, true);
   
   // Netz-Fehler:
   $err = 0;
   
   // TODO: hier fehlt noch die Lernschleife

            // Eingabe-Neuronen setzen:
            $net->setInputs($patterns[3]);

            // Schichtweise von oben nach unten die Ausgaben der Neuronen definieren:
            $net->setOutputs();
            
            // Muster lernen:
            $err += $net->learn($learningRate, $targets[3]);

   if(DEBUG)
   {   
      dump($weights);
   }
?>
```

Das ist aktuell aber nur ein einziger Lerndurchlauf. Ich weiß leider nämlich noch nicht, wie man den Netzfehler berechnet. Damit habe ich noch Probleme.

Debug-Ausgabe:

```
Neuron 0 ist ein input-Neuron.
Neuron 1 ist ein input-Neuron.
Neuron 2 ist ein Neuron einer verdeckten Schicht.
Neuron 3 ist ein output-Neuron.
Nachfolger von Neuron 0: 2 3 
Nachfolger von Neuron 1: 2 3 
Nachfolger von Neuron 2: 3 
Vorgänger von Neuron 2: 0 1 
Vorgänger von Neuron 3: 0 1 2 
Ebene 0: 0/0 0/1 
Ebene 1: 1/2 
Ebene 2: 2/3 
Neuron 0 in: 1
Neuron 1 in: 1
Neuron 2 net: 0.18034713364424
Neuron 2 o: 0.54496497527562
Neuron 3 net: 0.63357129882945
Neuron 3 o: 0.65329880174484
Neuron 3 fSig: -0.14797183717054
Neuron 2 fSig: 0.026871346189312
Gewichte ausgehender Verbindungen von Neuron 2:
   zu Nachfolger 3 deltaW: -0.040319734292565
   zu Nachfolger 3 w: -0.7726330663865
Gewichte ausgehender Verbindungen von Neuron 0:
   zu Nachfolger 2 deltaW: 0.013435673094656
   zu Nachfolger 2 w: -0.67963669870684
   zu Nachfolger 3 deltaW: -0.073985918585268
   zu Nachfolger 3 w: 0.68305351463214
Gewichte ausgehender Verbindungen von Neuron 1:
   zu Nachfolger 2 deltaW: 0.013435673094656
   zu Nachfolger 2 w: 0.38685517854039
   zu Nachfolger 3 deltaW: -0.073985918585268
   zu Nachfolger 3 w: -0.29836893605465
Gewichte ausgehender Verbindungen von Neuron 4:
   zu Nachfolger 2 deltaW: 0.013435673094656
   zu Nachfolger 2 w: 0.51343567309466
   zu Nachfolger 3 deltaW: -0.073985918585268
   zu Nachfolger 3 w: 0.42601408141473
Neuron 2 net: 0.22065415292821
Neuron 2 o: 0.55494080458488
Neuron 3 net: 0.38193304448282
Neuron 3 o: 0.59433924502693
0 0 -0.67963669870684 0.68305351463214 0 
0 0 0.38685517854039 -0.29836893605465 0 
0 0 0 -0.7726330663865 0 
0 0 0 0 0 
0 0 0.51343567309466 0.42601408141473 0
```


----------



## minzee (9. Feb 2015)

Vielleicht noch eine Info dazu. Beschrieben ist dieses Thema im Buch "Künstliche Intelligenz", ISBN 978-3-446-42758-7. Es ist u. a. vom schon erwähnten Professor Uwe Lämmel. Falls ihr euch noch nicht mit KI beschäftigt habt, euch das Thema aber interessiert, kann ich dieses Buch empfehlen. Natürlich würde ich mich dann freuen, wenn ihr euch dieses PHP-Programm dann angucken und mir ein Feedback geben würdet.


----------

