2013-04-09 46 views
2

目前我正在嘗試爲我的網絡實施彈性傳播。我基礎上,encog實現這樣做,但有一件事我不明白:彈性傳播的實施

The documentation的RPROP和iRPROP +說,當改變> 0:weightChange = - 符號(梯度)*三角洲

第298行和第366行的The source code沒有減號!

因爲我認爲兩者在某些情況下是正確的:爲什麼兩者之間存在差異?

而關於漸變:我在輸出層使用tanh作爲激活。這是否是正確的梯度計算?

gradientOutput = (1 - lastOutput[j] * lastOutput[j]) * (target[j] - lastOutput[j]); 

回答

3

在重新閱讀相關文章並在教科書中查找之後,我認爲在這一點上encog的文檔是不正確的。爲什麼不嘗試在源代碼中臨時添加減號?如果您使用相同的初始權重,您應該收到完全相同的結果,因爲文檔是正確的。但最終它只是重要的是你如何使用weightUpdate變量。如果文檔的作者用於從權重中減去weightUpdate而不是添加它,這將起作用。

編輯:我在我原來的答案中重新討論了關於梯度計算的部分。

首先,下面簡要說明如何設想輸出圖層中權重的梯度。首先,計算輸出與目標值之間的誤差。

你現在試圖做的是「責備」上一層中的那些神經元,這些神經元是活躍的。想象一下輸出神經元會說:「好吧,我在這裏有一個錯誤,誰負責?」。負責任的是前一層的神經元。根據輸出與目標值相比太小或太大,它將增加或減少前一層中每個神經元的權重,具體取決於它們的活躍程度。

x是隱藏層中神經元的激活。

o是輸出神經元的激活。

φ是輸出神經元φ'的導數函數。

編輯2:更正了以下部分。增加了反向傳播的矩陣式計算。

在每個輸出神經元j中的錯誤是:

(1)δ出來,J =φ'(O Ĵ)(T - ØĴ

梯度爲的重量與所述輸出神經元j連接的隱藏神經元i:

(2)GRAD I,J = X 出,J

在每個隱藏神經元i與權重w的backpropagated錯誤:

(3)δ藏,我 =φ'(x)的*ΣW I,J out,j

通過重複應用公式2和3,可以反向傳播到輸入層。

寫在循環,關於一個訓練樣本:

在每個輸出神經元j中的錯誤是:

for(int j=0; j < numOutNeurons; j++) { 
    errorOut[j] = activationDerivative(o[j])*(t[j] - o[j]); 
} 

爲重量的梯度連接的隱藏神經元i與輸出神經元Ĵ :

for(int i=0; i < numHidNeurons; i++) { 
    for(int j=0; j < numOutNeurons; j++) { 
    grad[i][j] = x[i] * errorOut[j]   
    }  
} 

在每個隱藏神經元i的backpropagated錯誤:

for(int i=0; i < numHidNeurons; i++) { 
    for(int j=0; j < numOutNeurons; j++) { 
    errorHid[i] = activationDerivative(x[i]) * weights[i][j] * errorOut[j]   
    }  
} 

在完全連接多層感知沒有迴旋之類的,你可以可以使用標準矩陣運算,這是快了很多東西。

假設每個樣本是排在你輸入矩陣的列是它的屬性,您可以通過網絡傳播的輸入是這樣的:

activations[0] = input; 
for(int i=0; i < numWeightMatrices; i++){ 
    activations[i+1] = activations[i].dot(weightMatrices[i]); 
    activations[i+1] = activationFunction(activations[i+1]); 
} 

反向傳播就變成了:

n = numWeightMatrices; 
error = activationDerivative(activations[n]) * (target - activations[n]); 
for (int l=n-1; l >= 0; l--){ 
    gradient[l] = activations[l].transposed().dot(error); 
    if (l > 0) { 
    error = error.dot(weightMatrices[l].transposed()); 
    error = activationDerivative(activations[l])*error; 
    } 
} 

我省略了上述解釋中的偏倚神經元。在文獻中,建議將偏倚神經元建模爲每個總是1.0的激活矩陣中的附加列。你將需要處理一些切片分配。當使用矩陣反向傳播循環時,不要忘記在每一步之前將偏差位置的誤差設置爲0!

+0

你確定(1.0 - hiddenActivation [i] * hiddenActivation [i])是否正確?我使用了(1.0 - lastOutput [j] * lastOutput [j])進行簡單的反向傳播,並且工作正常。我在問,因爲它仍然不能按預期工作:/ – user1406177 2013-04-13 13:24:52

+0

對不起,還有一個錯誤;我花了一些時間,糾正它,並增加了關於如何使用矩陣運算的建議。 – schreon 2013-04-13 16:20:44

+0

謝謝你的幫助。反向傳播現在可以完美運行。我仍然有彈性傳播的問題。我複製了encog的實現並使用了整個框架,但它們的實現似乎有問題。 – user1406177 2013-04-13 19:20:55

0
private float resilientPropagation(int i, int j){ 
    float gradientSignChange = sign(prevGradient[i][j]*gradient[i][j]); 
    float delta = 0; 
    if(gradientSignChange > 0){ 
     float change = Math.min((prevChange[i][j]*increaseFactor), maxDelta); 
     delta = sign(gradient[i][j])*change; 
     prevChange[i][j] = change; 
     prevGradient[i][j] = gradient[i][j]; 
    } 
    else if(gradientSignChange < 0){ 
     float change = Math.max((prevChange[i][j]*decreaseFactor), minDelta); 
     prevChange[i][j] = change; 
     delta = -prevDelta[i][j]; 
     prevGradient[i][j] = 0; 
    } 
    else if(gradientSignChange == 0){ 
     float change = prevChange[i][j]; 
     delta = sign(gradient[i][j])*change; 
     prevGradient[i][j] = gradient[i][j]; 
    } 
    prevDelta[i][j] = delta; 
    return delta;  
} 


gradient[i][j] = error[j]*layerInput[i]; 
weights[i][j]= weights[i][j]+resilientPropagation(i,j);