2016-09-23 3 views
2

Ich habe die letzten zwei Wochen über Backpropagation gelernt, habe die Mathematik dahinter gemacht und dachte, dass ich das Thema gut genug für meine eigene Implementierung verstehe (ohne irgendwelche linearen Algebra-Pakete usw.). Anscheinend lag ich falsch. Im Folgenden finden Sie das einfachste Beispiel Netzwerk, das ich mir vorstellen kann: 2 versteckte Einheiten und 1 Ausgabeeinheit. Ich versuche die XOR-Funktion zu lernen. Das funktioniert aber überhaupt nicht. Die Vorhersage ist immer um 0.5. Ich bin mir nicht sicher, wo ich versagt habe. Vielleicht könnte jemand helfen?Backpropagation funktioniert nicht für XOR

float sigmoid(float pX) { 
    return 1.0f/(1.0f+exp(-1.0f*pX)); 
} 

int main(int argc, char const *argv[]) { 
// DEFINE XOR problem 
float examples[4][2] = { {0,0} , {0,1}, {1,0}, {1,1}}; 
float labels[4] = {0, 1, 1, 0}; 

/* I want to use a network with two hidden neurons and 1 output neuron 
*/ 

// Weights from input to hidden neurons 
float WInput[2][2]; 
float WInputBias[2]; 

// Weights from hidden to output neuron 
float WOutput[2]; 
float WOutputBias; 

// output of hidden layer to output neuron 
float hidden[2]; 

// error for hidden layer 
float error[2]; 

//output of network 
float yPred; 

// randomly init weights 
std::random_device rd; 
std::mt19937 gen(rd()); 
std::normal_distribution<float> d(0, 0.1); 
WInput[0][0] = d(gen); WInput[0][1] = d(gen); 
WInput[1][0] = d(gen); WInput[1][1] = d(gen); 
WInputBias[0] = d(gen); WInputBias[1] = d(gen); 
WOutput[0] = d(gen); WOutput[1] = d(gen); WOutputBias = d(gen); 

// do the learning 
for(unsigned int i = 0; i < 1000; ++i) { 
    for (unsigned int k = 0; k < 4; ++k) { 
     float * input = &examples[k][0]; 
     float label = labels[k]; 

     // Compute forward pass 
     hidden[0] = sigmoid(WInput[0][0]*input[0] + WInput[1][0]*input[1] + WInputBias[0]); 
     hidden[1] = sigmoid(WInput[0][1]*input[0] + WInput[1][1]*input[1] + WInputBias[1]); 
     yPred = sigmoid(WOutput[0]*hidden[0] + WOutput[1]*hidden[1] + WOutputBias); 

     std :: cout << "Target/Prediction: " << label << "/" << yPred << std :: endl; 

     // Backward pass with alpha = 0.1 
     float outputError = -(label - yPred)*yPred*(1-yPred); 
     WOutput[0] = WOutput[0] - 0.1f*outputError*hidden[0]; //hidden equals input from this layer 
     WOutput[1] = WOutput[1] - 0.1f*outputError*hidden[1]; 
     WOutputBias = WOutputBias - 0.1f*outputError; 

     error[0] = (WOutput[0]*outputError)*hidden[0]*(1-hidden[0]); 
     error[1] = (WOutput[1]*outputError)*hidden[1]*(1-hidden[1]); 

     WInput[0][0] = WInput[0][0] - 0.1f*error[0]*input[0]; 
     WInput[1][0] = WInput[1][0] - 0.1f*error[0]*input[1]; 
     WInput[0][1] = WInput[0][1] - 0.1f*error[1]*input[0]; 
     WInput[1][1] = WInput[1][1] - 0.1f*error[1]*input[1]; 
     WInputBias[0] = WInputBias[0] - 0.1f*error[0]; 
     WInputBias[1] = WInputBias[1] - 0.1f*error[1]; 

    } 
    std :: cout << std :: endl; 
    // getch(); 
} 
} 
+1

Ich fürchte, das ist zu breit. Hast du es debuggen? Kannst du ein [MCVE] zeigen? Hier ist eine ehrfürchtige und sehr einfache XOR Neural Network Implementation, die die BackPropagation-Methode verwendet, und viel Glück: https://vimeo.com/19569529 –

+0

Ich weiß, dass dies eine Art von breiter Frage ist, aber das ist die minimale und vollständiges Beispiel, an das ich denken könnte. Ich mache gerade einen Kalkül auf Papier (wieder), aber bisher scheint der Vorwärtsdurchlauf korrekt berechnet worden zu sein. Es muss ein Problem mit dem Backprop-Schritt geben. Danke für das Video, das habe ich heute schon gefunden. Ich habe gerade den Quellcode in den Kommentaren gefunden. Vielleicht hilft das. – user1228633

+0

In deiner '// mach die Lern'-Schleife machst du das:' float * input = & examples [k] [0] 'und versuche es später als Array zu verwenden. 'Examples [i] [j]' ist jedoch ein float, kein Zeiger auf einen float (read: kein Array). Es sieht so aus, als ob Sie in Ihrer '// Lernschleife 'stattdessen folgendes möchten:' float * input = & examples [k] '. Sie erhalten wahrscheinlich falsche Eingaben, die mit Ihren erwarteten Ausgaben nicht übereinstimmen, da Sie über das Ende eines Arrays hinaus gelesen haben (und höchstwahrscheinlich in das nächste). Das ist alles zu sagen, es sei denn, ich verpasse etwas ... – Altainia

Antwort

2

Ich habe einen anderen Blick und den Code genommen und spielte mit einigen Parametern, und es stellt sich heraus, dass der gesamte Code tatsächlich korrekt ist.

Das Problem ist, mit nur 2 versteckten Knoten ist dieses Problem ziemlich schwierig zu lernen, und die Anzahl der verwendeten Epochen (1000) kombiniert mit der Lernrate (0,1) bedeutet einfach, dass es noch nicht konvergiert .

Versuchen Sie, es für etwa 4000-6000 Epochen zu trainieren (oder, vorzugsweise, bis die absoluten Werte Ihrer Fehler unter einen bestimmten Schwellenwert fallen), und versuchen Sie, die Gewichtsaktualisierungen um 1,0 statt um 0,1 zu ändern. Dann sollten Sie bessere Ergebnisse erzielen.

Es kann auch helfen, die Gewichte zufällig auf [-0.1, 0.1] anstelle von [0.0, 0.1] zu initialisieren. Dies sollte jedoch keinen großen Unterschied machen.

+1

Danke für Ihren Kommentar, aber das ist der Fehler (Delta) der Ausgabeschicht. Aus meiner Sicht ist das korrekt (obwohl ich Ihr Problem sehe), es ist die Ableitung der Fehlerfunktion (ich benutzte RMSE) multipliziert mit der Ableitung der Aktivierungsfunktion (hier sigmoid). Schauen Sie sich z.B. [link] (http://neuralnetworksanddeeplearning.com/chap2.html) eq 30/bp 1 oder schau dir den entsprechenden Wikipedia-Artikel [link] (https://en.wikipedia.org/wiki/Backpropagation) an. – user1228633

+1

Danke für Ihre Antwort! Es scheint, dass Sie richtig sind. Mit erhöhter Lernrate benötige ich etwa 1000 Epochen für 100% Genauigkeit. Eine Randnotiz: Ich verwende 'std :: normal_distribution d (0, 0.1);' für die Gewichtsinitialisierung, was bedeutet, dass ich bereits positive und negative Gewichte habe. – user1228633

Verwandte Themen