2015-11-17 11 views
5

Ich habe viel über Neural Networks gelesen und sie mit Backpropagation, in erster Linie this Coursera course, mit zusätzlichen Lesen von here und here. Ich dachte, ich hätte ein ziemlich gutes Verständnis des Kernalgorithmus, aber mein Versuch, ein Backpropagation-trainiertes neuronales Netz aufzubauen, hat nicht ganz geklappt und ich bin mir nicht sicher warum.Neuronale Netzwerk Backpropagation Implementation Probleme

Der Code ist in C++ mit noch keiner Vektorisierung.

Ich wollte eine einfache 2 Eingabe Neuronen, 1 verstecktes Neuron, 1 Ausgabe Neuron, Netzwerk, um die UND-Funktion zu modellieren. Nur um zu verstehen, wie die Konzepte funktionierten, bevor Sie zu einem komplexeren Beispiel übergingen. Mein Vorwärts-Ausbreitungscode funktionierte, als ich die Werte für die Gewichte und Verzerrungen manuell codierte.

float NeuralNetwork::ForwardPropagte(const float *dataInput) 
{ 
     int number = 0; // Write the input data into the input layer 
     for (auto & node : m_Network[0]) 
     { 
      node->input = dataInput[number++]; 
     } 

     // For each layer in the network 
     for (auto & layer : m_Network) 
     { 
      // For each neuron in the layer 
      for (auto & neuron : layer) 
      { 
       float activation; 
       if (layerIndex != 0) 
       { 
        neuron->input += neuron->bias; 
        activation = Sigmoid(neuron->input); 
       } else { 
        activation = neuron->input; 
       } 

       for (auto & pair : neuron->outputNeuron) 
       { 
        pair.first->input += static_cast<float>(pair.second)*activation; 
       } 
      } 
     } 

     return Sigmoid(m_Network[m_Network.size()-1][0]->input); 
} 

Einige dieser Variablen sind ziemlich schlecht genannt, aber im Grunde genommen neuron-> outputNeuron ist ein Vektor von Paaren. Der erste ist ein Zeiger auf das nächste Neuron und der zweite ist der Gewichtswert. neuron -> input ist der "z" -Wert in der neuronalen Netzwerkgleichung, die Summe aller Werte * activation + bais. Sigmoid ist gegeben durch:

float NeuralNetwork::Sigmoid(float value) const 
{ 
    return 1.0f/(1.0f + exp(-value)); 
} 

Diese beiden scheinen wie vorgesehen zu funktionieren. Nach einem Durchlauf über das Netzwerk werden alle Werte von 'z' oder 'neuron -> input' auf Null (oder nach Backpropagation) zurückgesetzt.

Ich trainiere dann das Netzwerk nach dem untenstehenden Psudo-Code. Der Trainingscode wird mehrmals ausgeführt.

for trainingExample=0 to m // m = number of training examples 
    perform forward propagation to calculate hyp(x) 
    calculate cost delta of last layer 
     delta = y - hyp(x) 
    use the delta of the output to calculate delta for all layers 
    move over the network adjusting the weights based on this value 
    reset network 

Der eigentliche Code ist hier:

void NeuralNetwork::TrainNetwork(const std::vector<std::pair<std::pair<float,float>,float>> & trainingData) 
{ 
    for (int i = 0; i < 100; ++i) 
    { 
     for (auto & trainingSet : trainingData) 
     { 
      float x[2] = {trainingSet.first.first,trainingSet.first.second}; 
      float y  = trainingSet.second; 
      float estimatedY = ForwardPropagte(x); 

      m_Network[m_Network.size()-1][0]->error = estimatedY - y; 
      CalculateError(); 
      RunBackpropagation(); 
      ResetActivations(); 
     } 
    } 
} 

Mit der Backpropagation Funktion gegeben durch:

void NeuralNetwork::RunBackpropagation() 
{ 
    for (int index = m_Network.size()-1; index >= 0; --index) 
    { 
     for(auto &node : m_Network[index]) 
     { 
      // Again where the "outputNeuron" is a list of the next layer of neurons and associated weights 
      for (auto &weight : node->outputNeuron) 
      { 
       weight.second += weight.first->error*Sigmoid(node->input); 
      } 
      node->bias = node->error; // I'm not sure how to adjust the bias, some of the formulas seemed to point to this. Is it correct? 
     } 
    } 
} 

und die Kosten berechnet:

void NeuralNetwork::CalculateError() 
{ 
    for (int index = m_Network.size()-2; index > 0; --index) 
    { 
     for(auto &node : m_Network[index]) 
     { 
      node->error = 0.0f; 

      float sigmoidPrime = Sigmoid(node->input)*(1 - Sigmoid(node->input)); 

      for (auto &weight : node->outputNeuron) 
      { 
       node->error += (weight.first->error*weight.second)*sigmoidPrime; 
      } 
     } 
    } 
} 

ich zufällig die Gewichte und führen Sie es auf den Daten s et:

x = {0.0f,0.0f} y =0.0f 
    x = {1.0f,0.0f} y =0.0f 
    x = {0.0f,1.0f} y =0.0f 
    x = {1.0f,1.0f} y =1.0f 

Natürlich soll ich nicht Ausbildung und Prüfung mit den gleichen Daten gesetzt, aber ich wollte nur den Grund backpropagation algortithm bis bekommen und läuft. Wenn ich diesen Code ausführen Ich sehe die Gewichte/Vorurteile sind wie folgt:

Layer 0 
    Bias 0.111129 
    NeuronWeight 0.058659 
    Bias -0.037814 
    NeuronWeight -0.018420 
Layer 1 
    Bias 0.016230 
    NeuronWeight -0.104935 
Layer 2 
    Bias 0.080982 

Der Trainingssatz läuft und die mittlere quadratische Fehler von Delta [outputLayer] sieht ungefähr wie:

Error: 0.156954 
Error: 0.152529 
Error: 0.213887 
Error: 0.305257 
Error: 0.359612 
Error: 0.373494 
Error: 0.374910 
Error: 0.374995 
Error: 0.375000 

... remains at this value for ever... 

und die endgültige Gewichte wie folgt aussehen: (sie bei roughtly diesen Wert am Ende immer)

Layer 0 
    Bias 0.000000 
    NeuronWeight 15.385233 
    Bias 0.000000 
    NeuronWeight 16.492933 
Layer 1 
    Bias 0.000000 
    NeuronWeight 293.518585 
Layer 2 
    Bias 0.000000 

ich akzeptiere, dass dies wie ein ganz Umwegen neuronale Netze des Lernens und die Umsetzung ist scheinen mag (an der m oment) sehr unoptimal. Aber kann irgendjemand irgendeinen Punkt ausmachen, an dem ich eine ungültige Annahme mache, oder ist entweder die Implementierung oder die Formel falsch?

EDIT

Danke für das Feedback für die Bias-Werte, I hielt sie auf die Schicht Eingang angelegt wird, und beendet die Eingangsschicht durch die Sigmoid-Funktion übergeben. Außerdem war meine Sigmoid Primefunktion ungültig. Aber das Netzwerk funktioniert immer noch nicht. Ich habe den Fehler aktualisiert und oben mit dem, was jetzt passiert, ausgegeben.

+2

Warum haben Sie so viele Vorurteile? 2-1-1 Netzwerk sollte insgesamt 5 Parameter haben: 2 Gewichte zwischen Eingangsneuronen und einem versteckten; 1 Gewicht zwischen der Vorspannung in der Eingangsschicht und dem versteckten Neuron; 1 Gewicht zwischen versteckter Schicht und Ausgangsneuron; 1 Gewicht zwischen Bias in versteckter Schicht und Ausgangsneuron. Insgesamt 5 Gewichte. Sogar dein Code zeigt dir so - du und ohne diese 2 redundanten Vorurteile – lejlot

+0

Danke für deine Hilfe bei den Voreingenommenheiten, siehe meine Antwort auf Galloguille für weitere Erklärungen. Ich habe das behoben, aber ich habe immer noch Probleme mit dem neuronalen Netzwerk, das die Gewichte immer auf die Werte w11 (15.385233), w12 (16.492933), w21 (293.518585) trainiert. Alle Verzerrungen werden Null. Offensichtlich gibt es noch ein anderes Problem mit dem Code. – Davors72

Antwort

1

Ich löste mein Problem (jenseits der anfänglichen Verzerrungen/signed Prime Problem oben). Ich begann, die Gewichte zu subtrahieren anstatt sie zu addieren. In den Quellen, die ich betrachtete, hatten sie ein Minuszeichen innerhalb der Delta-Wert-Berechnung, die ich nicht habe, aber ich behielt ihr Format des Hinzufügens des negierten Werts zu den Gewichtungen bei. Außerdem war ich verwirrt darüber, was ich mit dem Gewicht tun sollte, und habe eine Quelle falsch gelesen, die besagt, sie dem Fehler zuzuordnen. Ich sehe jetzt, dass die Intuition es als normales Gewicht behandelt, aber multipliziert mit der Bias-Konstante von 1 statt von z. Nachdem ich diese Änderungen hinzugefügt hatte, konnten 1000 einfache Bitmuster wie OR und AND modelliert werden.

4

Wie lejilot sagte, haben Sie eine Menge Vorurteile dort. Sie benötigen keine Vorspannung in der letzten Schicht, es ist eine Ausgangsschicht und eine Vorspannung muss mit seinem Eingang verbunden sein, aber nicht mit seinem Ausgang. Werfen Sie einen Blick auf das folgende Bild:

In diesem Bild kann man sehen, dass es nur eine Vorspannung pro Schicht ist, mit Ausnahme der letzten, wo es keine Notwendigkeit einer Vorspannung ist.

Here you can read ein sehr intuitiver Ansatz für neuronale Netze. Es ist in Python, aber es kann Ihnen helfen, einige Konzepte von neuronalen Netzen besser zu verstehen.

+0

Danke für Sie, und Lejlot's, helfen Sie mit den Voreingenommenheiten, ich habe vergessen, sie von den Input-Layer-Berechnungen auszuschließen. In meinem Beispiel ist die Verzerrung, die an jeden der Knoten "angehängt" ist, der Bias-Wert * wichtung, der auf die Funktion von der vorherigen Schicht angewendet wird. Wie ich verstanden habe, wird der Bias-Wert auf die Funktion angewendet, um die Kurve "zu verschieben" [http://stackoverflow.com/questions/2480650/role-of-bias-in-neural-networks], und ich habe mich falsch beworben die Sigmoid-Funktion, um die Eingangsneuronen gleichmäßig zu machen. Daher die zusätzlichen Vorurteile. – Davors72

Verwandte Themen