1. 程式人生 > >前項傳播和反向傳播

前項傳播和反向傳播

修正 計算 ria 定義 original 基本 而且 是我 eight

前向傳播

技術分享圖片

  如圖所示,這裏講得已經很清楚了,前向傳播的思想比較簡單。
  舉個例子,假設上一層結點i,j,k,…等一些結點與本層的結點w有連接,那麽結點w的值怎麽算呢?就是通過上一層的i,j,k等結點以及對應的連接權值進行加權和運算,最終結果再加上一個偏置項(圖中為了簡單省略了),最後在通過一個非線性函數(即激活函數),如ReLu,sigmoid等函數,最後得到的結果就是本層結點w的輸出。
最終不斷的通過這種方法一層層的運算,得到輸出層結果。

  對於前向傳播來說,不管維度多高,其過程都可以用如下公式表示:

  a2=σ(z2)=σ(a1?W2+b2)

  其中,上標代表層數,星號表示卷積,b表示偏置項bias,

σσ表示激活函數。

  假設神經網絡結構如下圖所示:有2個輸入單元;隱含層為2個神經元;輸出層也是2個神經元,隱含層和輸出層各有1個偏置。

技術分享圖片

  為了直觀,這裏初始化權重和偏置量,得到如下效果:

技術分享圖片

----前向傳播----

  隱含層神經元h1的輸入:

  技術分享圖片

  代入數據可得:

  技術分享圖片

  假設激勵函數用logistic函數,計算得隱含層神經元h1的輸出:

  技術分享圖片

  同樣的方法,可以得到隱含層神經元h2的輸出為:

  技術分享圖片

  對輸出層神經元重復這個過程,使用隱藏層神經元的輸出作為輸入。這樣輸出層神經元O1的輸出為:

  技術分享圖片

  代入數據:

  技術分享圖片

  輸出層神經元O1的輸出:

  技術分享圖片

  同樣的方法,可以得到輸出層神經元O2的輸出為:

  技術分享圖片

----統計誤差----

  假如誤差公式為:

  技術分享圖片

  如上圖,O1的原始輸出為0.01,而神經網絡的輸出為0.75136507,則其誤差為:

  技術分享圖片

  同理可得,O2的誤差為:

  技術分享圖片

  這樣,總的誤差為:

  技術分享圖片

反向傳播算法(Back propagation)

  BackPropagation算法是多層神經網絡的訓練中舉足輕重的算法。簡單的理解,它的確就是復合函數的鏈式法則,但其在實際運算中的意義比鏈式法則要大的多。要回答題主這個問題“如何直觀的解釋back propagation算法?” 需要先直觀理解多層神經網絡的訓練。

  機器學習可以看做是數理統計的一個應用,在數理統計中一個常見的任務就是擬合,也就是給定一些樣本點,用合適的曲線揭示這些樣本點隨著自變量的變化關系.

  深度學習同樣也是為了這個目的,只不過此時,樣本點不再限定為(x, y)點對,而可以是由向量、矩陣等等組成的廣義點對(X,Y)。而此時,(X,Y)之間的關系也變得十分復雜,不太可能用一個簡單函數表示。然而,人們發現可以用多層神經網絡來表示這樣的關系,而多層神經網絡的本質就是一個多層復合的函數。借用網上找到的一幅圖[1],來直觀描繪一下這種復合關系。

技術分享圖片

  其對應的表達式如下:

技術分享圖片

  上面式中的Wij就是相鄰兩層神經元之間的權值,它們就是深度學習需要學習的參數,也就相當於直線擬合y=k*x+b中的待求參數k和b。

  和直線擬合一樣,深度學習的訓練也有一個目標函數,這個目標函數定義了什麽樣的參數才算一組“好參數”,不過在機器學習中,一般是采用成本函數(cost function),然後,訓練目標就是通過調整每一個權值Wij來使得cost達到最小。cost函數也可以看成是由所有待求權值Wij為自變量的復合函數,而且基本上是非凸的,即含有許多局部最小值。但實際中發現,采用我們常用的梯度下降法就可以有效的求解最小化cost函數的問題。

  梯度下降法需要給定一個初始點,並求出該點的梯度向量,然後以負梯度方向為搜索方向,以一定的步長進行搜索,從而確定下一個叠代點,再計算該新的梯度方向,如此重復直到cost收斂。那麽如何計算梯度呢?

  假設我們把cost函數表示為H(W11,W12,?,Wij,?,Wmn)H(W11,W12,?,Wij,?,Wmn),那麽它的梯度向量[2]就等於?H=?H?W11e11+?+?H?Wmnemn?H=?H?W11e11+?+?H?Wmnemn, 其中eijeij表示正交單位向量。為此,我們需求出cost函數H對每一個權值Wij的偏導數。而BP算法正是用來求解這種多層復合函數的所有變量的偏導數的利器。

  我們以求e=(a+b)*(b+1)的偏導[3]為例。
  它的復合關系畫出圖可以表示如下:
技術分享圖片

  在圖中,引入了中間變量c,d。
  為了求出a=2, b=1時,e的梯度,我們可以先利用偏導數的定義求出不同層之間相鄰節點的偏導關系,如下圖所示。
技術分享圖片

  利用鏈式法則我們知道:

技術分享圖片

  鏈式法則在上圖中的意義是什麽呢?其實不難發現,?e/?a的值等於從a到e的路徑上的偏導值的乘積,而?e/?b的值等於從b到e的路徑1(b-c-e)上的偏導值的乘積加上路徑2(b-d-e)上的偏導值的乘積。也就是說,對於上層節點p和下層節點q,要求得?p/?q,需要找到從q節點到p節點的所有路徑,並且對每條路徑,求得該路徑上的所有偏導數之乘積,然後將所有路徑的 “乘積” 累加起來才能得到?p/?q的值。

  大家也許已經註意到,這樣做是十分冗余的,因為很多路徑被重復訪問了。比如上圖中,a-c-e和b-c-e就都走了路徑c-e。對於權值動則數萬的深度模型中的神經網絡,這樣的冗余所導致的計算量是相當大的。

  同樣是利用鏈式法則,BP算法則機智地避開了這種冗余,它對於每一個路徑只訪問一次就能求頂點對所有下層節點的偏導值。
正如反向傳播(BP)算法的名字說的那樣,BP算法是反向(自上往下)來尋找路徑的。

從  最上層的節點e開始,初始值為1,以層為單位進行處理。對於e的下一層的所有子節點,將1乘以e到某個節點路徑上的偏導值,並將結果“堆放”在該子節點中。等e所在的層按照這樣傳播完畢後,第二層的每一個節點都“堆放”些值,然後我們針對每個節點,把它裏面所有“堆放”的值求和,就得到了頂點e對該節點的偏導。然後將這些第二層的節點各自作為起始頂點,初始值設為頂點e對它們的偏導值,以”層”為單位重復上述傳播過程,即可求出頂點e對每一層節點的偏導數。

  以上圖為例,節點c接受e發送的1*2並堆放起來,節點d接受e發送的1*3並堆放起來,至此第二層完畢,求出各節點總堆放量並繼續向下一層發送。節點c向a發送2*1並對堆放起來,節點c向b發送2*1並堆放起來,節點d向b發送3*1並堆放起來,至此第三層完畢,節點a堆放起來的量為2,節點b堆放起來的量為2*1+3*1=5, 即頂點e對b的偏導數為5.

反向傳播具體計算過程推導

  為了方便起見,這裏我定義了三層網絡,輸入層(第0層),隱藏層(第1層),輸出層(第二層)。並且每個結點沒有偏置(有偏置原理完全一樣),激活函數為sigmod函數(不同的激活函數,求導不同),符號說明如下:
技術分享圖片

  對應網絡如下:

技術分享圖片

  其中對應的矩陣表示如下

技術分享圖片

首先我們先走一遍正向傳播,公式與相應的數據對應如下:

技術分享圖片

那麽:

技術分享圖片

同理可以得到:

技術分享圖片

那麽最終的損失為

技術分享圖片

,我們當然是希望這個值越小越好。這也是我們為什麽要進行訓練,調節參數,使得最終的損失最小。這就用到了我們的反向傳播算法,實際上反向傳播就是梯度下降法中鏈式法則的使用。

下面我們看如何反向傳播

  根據公式,我們有:

技術分享圖片

  這個時候我們需要求出C對w的偏導,則根據鏈式法則有:

技術分享圖片

  同理有:

技術分享圖片

  到此我們已經算出了最後一層的參數偏導了.我們繼續往前面鏈式推導:

  我們現在還需要求

技術分享圖片

  下面給出一個推導其它全都類似

技術分享圖片

  同理可得其它幾個式子:

  則最終的結果為:

技術分享圖片

  再按照這個權重參數進行一遍正向傳播得出來的Error為0.165

  而這個值比原來的0.19要小,則繼續叠代,不斷修正權值,使得代價函數越來越小,預測值不斷逼近0.5.我叠代了100次的結果,Error為5.92944818e-07(已經很小了,說明預測值與真實值非常接近了),最後的權值為:

技術分享圖片

  bp過程可能差不多就是這樣了,可能此文需要你以前接觸過bp算法,只是還有疑惑,一步步推導後,會有較深的理解。

上面的算法 python代碼實現如下:

#!/usr/bin/env python
#coding:utf-8


import numpy as np

def nonlin(x, deriv = False):
    if(deriv == True):
        return x * (1 - x)
    return 1 / (1 + np.exp(-x))


X = np.array([[0.35], [0.9]])
y = np.array([[0.5]])

np.random.seed(1)

W0 = np.array([[0.1, 0.8], [0.4, 0.6]])
W1 = np.array([[0.3, 0.9]])

print original , W0, \n, W1

for j in xrange(100):
    l0 = X
    l1 = nonlin(np.dot(W0, l0))
    l2 = nonlin(np.dot(W1, l1))
    l2_error = y - l2
    Error = 1 / 2.0 * (y-l2)**2
    print Error:, Error

    l2_delta = l2_error * nonlin(l2, deriv=True)

    l1_error = l2_delta * W1 #back propagation
    l1_delta = l1_error * nonlin(l1, deriv=True)

    W1 += l2_delta * l1.T
    W0 += l0.T.dot(l1_delta)
    print W0, \n, W1

參考文檔:
1.http://blog.csdn.net/lhanchao/article/details/51419150
2.https://www.zhihu.com/question/39022858

前項傳播和反向傳播