2016-09-23 98 views
2

我一直在學習反向傳播過去的兩個星期,做了數學背後,以爲我瞭解的話題不夠好,我自己的實現(沒有任何線性代數軟件包等)。顯然,我錯了。下面你可以找到我能想到的最簡單的示例網絡:2個隱藏單元和1個輸出單元。我嘗試學習XOR函數。但是,這根本不起作用。預測總是在0.5左右。我不確定我在哪裏搞砸了。也許有人可以幫忙?反向傳播不工作的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

恐怕這太寬泛了。你調試了嗎?你能展示一個[MCVE]嗎?這裏是一個真棒和使用該方法反向傳播一個非常簡單的XOR神經網絡實現,好運:https://vimeo.com/19569529 –

+0

我知道這是怎樣的一個寬泛的問題,但是這是最起碼的,並完整的例子,我能想到的。我目前正在紙上做一些微積分(再次),但到目前爲止,似乎正確計算了正向通過。 backprop步驟必須存在問題。感謝視頻,我今天已經找到了一個。我只是在評論中找到了源代碼。也許這會有所幫助 – user1228633

+0

在你的''做學習'循環中,你是這樣做的:'float * input =&examples [k] [0]'並且在稍後嘗試使用它作爲數組。但是,'examples [i] [j]'是一個浮點數,而不是一個指向float的指針(讀取:不是數組)。看起來像在你的''學習循環'中,你可能需要這個:'float * input =&examples [k]'。由於讀取數組的末尾(很可能是下一個),您可能會收到與您的預期輸出不符的錯誤輸入。這就是我要說的,除非我失去了一些東西...... – Altainia

回答

2

我已經採取了另一種外觀和代碼,並與一些參數發揮各地,並且事實證明,所有的代碼實際上是正確的。

問題是,只有2個隱藏節點,這個問題很難學,而且你使用的時期數(1000)與你使用的學習速率(0.1)相結合,僅僅意味着它還沒有收斂。

試着讓它訓練大約4000-6000個紀元(或者,最好是,直到你的錯誤的絕對值降到某個閾值以下),然後試着將權重更新加1.0而不是0.1。那麼你應該得到更好的結果。

它也可能有助於隨機初始化的權重爲位於[-0.1,0.1]而不是[0.0,0.1]。儘管如此,這不應該產生巨大的影響。

+1

感謝您的評論,但這是輸出層的錯誤(增量)。從我的角度來看,這是正確的(雖然我看到了你的問題),它是誤差函數的導數(我用RMSE)乘以激活函數的導數(這裏是sigmoid)。只要看看例如[鏈接](http://neuralnetworksanddeeplearning.com/chap2.html)等式30/bp 1或查看相應的維基百科文章[鏈接](https://en.wikipedia.org/wiki/Backpropagation)。 – user1228633

+1

感謝您的回覆!看來你是對的。隨着學習速度的提高,我需要大約1000個時期來保證100%的準確性。一方面說明:我使用'std :: normal_distribution d(0,0.1);'爲重量初始化,這意味着我已經有正負權重。 – user1228633