2012-08-16 91 views
3

目前,我遇到Backpropagation算法問題。 我試圖實現它並使用它來識別面孔的方向(左,右,下,直)。 基本上,我有N個圖像,讀取像素並將其值(0到255)更改爲從0.0到1.0的值。所有圖像都是32 * 30。 我有960神經元的輸入層,3神經元的隱藏層和4神經元的輸出層。例如,輸出< 0.1,0.9,0.1,0.1>表示該人向右看。 我遵循了pseudy-code。但是,它不能正確工作 - 它不會計算正確的權重,因此無法處理培訓和測試示例。 下面是代碼的部分:神經網絡反向傳播不能正確計算權重

// main function - it runs the algorithm 
    private void runBackpropagationAlgorithm() { 
     for (int i = 0; i < 900; ++i) { 
      for (ImageUnit iu : images) { 
       double [] error = calcOutputError(iu.getRatioMatrix(), iu.getClassification()); 
       changeHiddenUnitsOutWeights(error); 
       error = calcHiddenError(error); 
       changeHiddenUnitsInWeights(error,iu.getRatioMatrix()); 
      } 
     } 
    } 

    // it creates the neural network 
    private void createNeuroneNetwork() { 
      Random generator = new Random(); 
      for (int i = 0; i < inHiddenUnitsWeights.length; ++i) { 
       for (int j = 0; j < hiddenUnits; ++j) { 
        inHiddenUnitsWeights[i][j] = generator.nextDouble(); 
       } 
      } 
      for (int i = 0; i < hiddenUnits; ++i) { 
       for (int j = 0; j < 4; ++j) { 
        outHddenUnitsWeights[i][j] = generator.nextDouble(); 
       } 
      } 
     } 
    // Calculates the error in the network. It runs through the whole network. 
private double [] calcOutputError(double[][] input, double [] expectedOutput) { 
     int currentEdge = 0; 
     Arrays.fill(hiddenUnitNodeValue, 0.0); 
     for (int i = 0; i < input.length; ++i) { 
      for (int j = 0; j < input[0].length; ++j) { 
       for (int k = 0; k < hiddenUnits; ++k) { 
        hiddenUnitNodeValue[k] += input[i][j] * inHiddenUnitsWeights[currentEdge][k]; 
       } 
       ++currentEdge; 
      } 
     } 
     double[] out = new double[4]; 
     for (int j = 0; j < 4; ++j) { 
      for (int i = 0; i < hiddenUnits; ++i) { 
       out[j] += outHddenUnitsWeights[i][j] * hiddenUnitNodeValue[i]; 
      } 
     } 
     double [] error = new double [4]; 
     Arrays.fill(error, 4); 
     for (int i = 0; i < 4; ++i) { 
      error[i] = ((expectedOutput[i] - out[i])*(1.0-out[i])*out[i]); 
      //System.out.println((expectedOutput[i] - out[i]) + " " + expectedOutput[i] + " " + out[i]); 
     } 
     return error; 
    } 

// Changes the weights of the outgoing edges of the hidden neurons 
private void changeHiddenUnitsOutWeights(double [] error) { 
     for (int i = 0; i < hiddenUnits; ++i) { 
      for (int j = 0; j < 4; ++j) { 
       outHddenUnitsWeights[i][j] += learningRate*error[j]*hiddenUnitNodeValue[i]; 
      } 
     } 
    } 

// goes back to the hidden units to calculate their error. 
private double [] calcHiddenError(double [] outputError) { 
     double [] error = new double[hiddenUnits]; 
     for (int i = 0; i < hiddenUnits; ++i) { 
      double currentHiddenUnitErrorSum = 0.0; 
      for (int j = 0; j < 4; ++j) { 
       currentHiddenUnitErrorSum += outputError[j]*outHddenUnitsWeights[i][j]; 
      } 
      error[i] = hiddenUnitNodeValue[i] * (1.0 - hiddenUnitNodeValue[i]) * currentHiddenUnitErrorSum; 
     } 
     return error; 
    } 

// changes the weights of the incomming edges to the hidden neurons. input is the matrix of ratios 
private void changeHiddenUnitsInWeights(double [] error, double[][] input) { 
     int currentEdge = 0; 
     for (int i = 0; i < input.length; ++i) { 
      for (int j = 0; j < input[0].length; ++j) { 
       for (int k = 0; k < hiddenUnits; ++k) { 
        inHiddenUnitsWeights[currentEdge][k] += learningRate*error[k]*input[i][j]; 
       } 
       ++currentEdge; 
      } 
     } 
    } 

作爲算法工作,它計算越來越大的權重,這最終接近無窮大(NaN值)。我檢查了代碼。唉,我沒能解決我的問題。 我會非常感謝任何想嘗試幫助我的人。

+0

你是否在其中規定了'精確'問題?我的意思是,你確定這不僅僅是一個浮點問題嗎? 除此之外,我猜你的背籃或隱藏的體重不能正確計算。除非你在較小的樣本上測試這個NN並證明它工作正常。 – Shark 2012-08-16 16:33:58

+0

我認爲這不是浮點問題。我嘗試了一個例子,運行9000次的算法。輸出仍然是一個數組NaN值。在第5次迭代之後,值變得無限。我無法理解爲什麼會發生這種情況。 – 2012-08-16 16:58:09

+0

它是否正確地學習XOR問題?調試這樣的東西非常簡單。 – 2012-08-16 17:51:55

回答

2

您的代碼缺少的傳遞函數。這聽起來像你想要softmax輸出的邏輯功能。您需要在calcOutputError

// Logistic transfer function for hidden layer. 
for (int k = 0; k < hiddenUnits; ++k) { 
    hiddenUnitNodeValue[k] = logistic(hiddenUnitNodeValue[k]); 
} 

// Softmax transfer function for output layer. 
sum = 0; 
for (int j = 0; j < 4; ++j) { 
    out[j] = logistic(out[j]); 
    sum += out[j]; 
} 
for (int j = 0; j < 4; ++j) { 
    out[j] = out[j]/sum; 
} 

以下,其中物流功能

public double logistic(double x){ 
    return (1/(1+(Math.exp(-x))); 
} 

注意,SOFTMAX傳遞函數爲您提供了總和輸出爲1,所以他們可以被解釋爲概率。

此外,您計算輸出圖層的誤差梯度不正確。它應該簡單地是

for (int i = 0; i < 4; ++i) { 
    error[i] = (expectedOutput[i] - out[i]); 
} 
3

我沒有檢查你的所有代碼。我只想給你一些一般性的建議。我不知道你的目標是(1)學習面孔的方向還是(2)實現你自己的神經網絡。

如果是(1),您應該考慮使用those庫中的一個。他們只是工作,給你更靈活的配置選項。例如,標準反向傳播是神經網絡最差的優化算法之一。收斂取決於學習速度。我看不到您在實施中選擇了哪個值,但可能會過高。還有其他優化算法不需要學習率或在訓練過程中對其進行調整。另外,隱藏層中的3個神經元很可能不夠用。大多數用於圖像的神經網絡有數百甚至數千個隱藏單元。我建議你首先嚐試用完全開發的庫來解決你的問題。如果它確實有效,那麼嘗試實施自己的ANN或者開心。 :)

在情況下(2)您應該先嚐試解決一個更簡單的問題。以一個非常簡單的仿真數據集,然後採取standard benchmark,然後與您的數據一起嘗試。驗證反向傳播實現的有效方法是與numerical differentation method進行比較。

0

我還沒有測試過你的代碼,但我幾乎可以肯定,你開始與大權重。 這些主題的大部分介紹都將它放在「初始權值隨機值」,而忽略了算法實際上對某些初始值發散(轉到Inf)。

嘗試使用較小的起始值,例如在-1/5和1/5之間並將其縮小。

另外做一個矩陣乘法的方法,你(只)使用了4次,更容易看到那裏是否有問題。

0

我有一個神經網絡處理灰度圖像類似的問題。您有960個輸入值,範圍介於0和255之間。即使在初始權重較小的情況下,您也可能輸入大量的神經元,反向傳播算法陷入困境。

嘗試將每個像素值除以255,然後將其傳遞到神經網絡中。這對我來說很有用。剛開始使用非常小的初始權重還不夠,我相信由於評論中提出了浮點精度問題。

正如另一個答案中所建議的,測試您的算法的一個好方法是查看您的網絡是否可以學習像XOR這樣的簡單函數。

而對於它的價值,隱層3個神經元是很多我的目的(識別人臉圖像的性別)

0

我寫了一個完整的新的神經網絡庫,它的工作原理。可以肯定的是,在我以前的嘗試中,我錯過了使用傳遞函數及其派生物的想法。謝謝你們!