神經網路入門 第二部分

查志強發表於2015-08-08

【原文:http://blog.sina.com.cn/s/blog_6a67b5c50100tspe.html

【翻譯】AI:神經網路入門 第二部分

 

英文原文連結:http://www.codeproject.com/KB/recipes/Backprop_ANN.aspx

作者:Sacha Barber

翻譯:本站(http://hi.baidu.com/ebfok)原創

說明:翻譯力求保持原貌,刪去了一些無關緊要的內容;水平有限,錯誤難免;轉載請註明出處。

-------------------------------------------------------------------------------------

什麼是XOR問題,如下面的真值表所示:

神經網路入門 <wbr>第二部分

新的神經網路是什麼樣的

能解決XOR問題的新的神經網路看起來就像是一個單層網路。我們面對的仍然是輸入/權值/輸出。新東西是隱含層。

神經網路入門 <wbr>第二部分

通過使用輸入和權值我們能計算出給定節點的啟用狀態。對隱含層來說這很容易辦到,因為它與輸入層是直接相連的。

輸出層與輸入層是隔離的,所以為了計算出輸出節點的啟用狀態,需要利用隱含層的輸出,也就是輸出層節點的輸入。

上面的整個過程可以看成是從一層到下一層的前向傳播過程。

這和單層網路仍是類似的,任何給定節點的啟用狀態也仍按下面的方法計算:

神經網路入門 <wbr>第二部分

wi  weight(i), Ii input(i)

學習的型別

有兩種學習型別:加強型和監督型

加強型學習

在加強型學習中,當訓練時,一組輸入提交到神經網路,輸出是0.75,期望輸出是1.0

誤差(1.0 - 0.75)被用來訓練。

當有2個輸出,總誤差是2個輸出誤差的和,這等於是說“所有輸出上的總誤差是1.76

注意這是說你錯得有多麼嚴重,而不是說你錯再什麼方向。

使用這種方法是用也得不到結果的。

監督型學習

監督型學習中網路被提供更多的資訊。不只是告訴網路錯得有多嚴重,而且還告訴錯再什麼方向。

學習演算法

訓練神經網路的步驟如下:

  • 隨機生成權值(和偏置)
  • 測試訓練集中的資料,看誤差有多大
  • 微調權值,以便改善輸出
  • 嘗試新的訓練集或者重複訓練原來的訓練集
  • 重複以上過程直到得到精確的輸出

本文就是按以上步驟來解決XOR問題的,這也被叫做“反向傳播”(BPBackProp

反向傳播利用輸出誤差來調節輸出層的權值,不僅如此,還能計算上一層的誤差,並用這個誤差來調整那裡的權值,餘類推。

採用S函式作為非線性傳遞函式是個技巧,之所以使用S函式,是因為它是可微分的。

神經網路入門 <wbr>第二部分

S函式完美地可微分,所以有

神經網路入門 <wbr>第二部分

delta_outputs[i] = outputs[i] * (1.0 - outputs[i]) * (targets[i] - outputs[i])

正是使用這種演算法才使得權值增量能在網路中反向傳播。

值得注意的地方

存在著這樣的凹部,兩邊十分陡峭,而往底部則傾斜得較輕微,梯度下降時,時間浪費在在凹部的兩邊上上下下的過程中。(想想球吧!)

神經網路入門 <wbr>第二部分

所以應該怎麼辦呢?可以加個動量項,就能抵消上面的那種來回往復的運動,並且加強任何一致的方向,這樣就能更加快速的下降到谷底。

神經網路入門 <wbr>第二部分

開始訓練

從下面這段程式碼開始:

/// 主訓練過程。期望輸出值以引數形式傳入。神經網路通過微調權值而更新。加入了動量項以確保訓練/// 朝正確的方向進行。我設法避免出現上面所說的凹部。

/// 引數:一個 double[] 陣列,包含了期望輸出值

private void train_network(double[] target)

{

    //得到動量值

    double[] delta_hidden = new double[nn.NumberOfHidden + 1];

    double[] delta_outputs = new double[nn.NumberOfOutputs];

 

    // 得到輸出層的delta值

    for (int i = 0; i < nn.NumberOfOutputs; i++)

    {

        delta_outputs[i] =

        nn.Outputs[i] * (1.0 - nn.Outputs[i]) * (target[i] - nn.Outputs[i]);

    }

    //得到隱含層的delta值

    for (int i = 0; i < nn.NumberOfHidden + 1; i++)

    {

        double error = 0.0;

        for (int j = 0; j < nn.NumberOfOutputs; j++)

        {

            error += nn.HiddenToOutputWeights[i, j] * delta_outputs[j];

        }

        delta_hidden[i] = nn.Hidden[i] * (1.0 - nn.Hidden[i]) * error;

    }

    // 更新隱含層和輸出層之間的權值

    for (int i = 0; i < nn.NumberOfOutputs; i++)

    {

        for (int j = 0; j < nn.NumberOfHidden + 1; j++)

        {

            //使用動量項,確保朝著正確的方向移動

            nn.HiddenToOutputWeights[j, i] += nn.LearningRate * delta_outputs[i] * nn.Hidden[j];

        }

    }

    //更新輸入層和隱含層之間的權值

    for (int i = 0; i < nn.NumberOfHidden; i++)

    {

        for (int j = 0; j < nn.NumberOfInputs + 1; j++)

        {

            //使用動量項,確保朝著正確的方向移動

            nn.InputToHiddenWeights[j, i] += nn.LearningRate * delta_hidden[i] * nn.Inputs[j];

        }

    }

}

 

 

最終的程式碼

 

本文中的程式碼如下面的類圖所示(Visual Studio 2005 C#, .NET v2.0

神經網路入門 <wbr>第二部分

值得人們花點時間研究下的主要的類有:

  • NN_Trainer_XOR : 訓練神經網路以解決XOR問題
  • TrainerEventArgs : 訓練事件引數,用於GUI
  • NeuralNetwork : 可調的神經網路
  • NeuralNetworkEventArgs : 訓練事件引數,用於GUI
  • SigmoidActivationFunction :S型啟用函式

程式演示

神經網路入門 <wbr>第二部分

由圖可見,XOR問題幾乎被解決了,但是不能達到100%的精度

訓練結果

 

 

神經網路入門 <wbr>第二部分

 

神經網路入門 <wbr>第二部分

神經網路入門 <wbr>第二部分

 

神經網路入門 <wbr>第二部分

神經網路入門 <wbr>第二部分


相關文章