第十章 神經網路引數的反向傳播演算法
該系列文章為,觀看 “吳恩達機器學習” 系列視訊的學習筆記。雖然每個視訊都很簡單,但不得不說每一句都非常的簡潔扼要,淺顯易懂。非常適合我這樣的小白入門。
本章含蓋
- 10.1 代價函式
- 10.2 反向傳播演算法
- 10.3 理解反向傳播
- 10.4 梯度檢測
- 10.5 隨機初始化
- 10.6 組合到一起
- 10.7 無人駕駛
10.1 代價函式
為神經網路擬合引數的演算法

假設神經網路的訓練樣本有m個,每個包含一組輸入x和一組輸出訊號y;
L表示神經網路總層數;(:point_up_2: L = 4)
S_I表示每層的neuron個數(S_l表示輸出層神經元個數),S_L代表最後一層中處理單元的個數。
左邊為“二元分類”問題,這種情況下,我們會有一個輸出單元。
右邊為“多類別分類”問題,也就是說會有K個不同的類。輸出為 K維向量。其中,K >= 3
擬合神經網路引數的代價函式:
在神經網路中,我們使用的代價函式是邏輯迴歸中我們使用的代價函式的一般形式

:point_up_2:邏輯迴歸代價函式僅有一個輸出單元,即,y^(i)

:point_up_2:表示第 i 個輸出。即,K 維向量中的第 i 個元素。

這個求和項,主要是 K 個輸出單元之和。比如,我們有4個輸出單元,那麼程式碼函式,就是依次將每個輸出單元的代價
“正則項”就是(所有 θ 的平方和)* λ
10.2 反向傳播演算法
讓代價函式最小化的方法,即,“反向傳播演算法”

從一個樣本的情況說起:

:point_up_2:實現了,把向前傳播向量化。
為了計算“導數項”,我們將採用一種叫做“反向傳播(backpropagation)”的演算法


:point_up_2:表示第l(小寫L)層的第j個節點的誤差。
我們用δ來表示誤差,則:δ^(4) = a^(4)-y
j 表示輸出向量的第 j 個元素。
如,δ^(3) = (Θ (3)) T * δ^(4) * g’(z^(3)) 可以理解為:δ^(3) / ((Θ (3))T * δ^(4)) = g’(z^(3))。即,輸出的誤差/輸入的誤差 = 斜率 (注意,這裡輸入的誤差,是反向傳播的輸入誤差)

如果你把,δ、a、y 都看成向量,你可以這麼寫,那麼你就會得到一個向量化的表示式。這個時候,δ、a、y 分別表示一個向量,且維度相同,都等於輸出單元的個數。
『. *』向量乘法。MATLAB中的寫法。
注意,沒有 δ^(1),因為:對於輸入層,那只是表示我們在訓練集觀察到的,所以不會存在誤差。也就是說,我們是不想改變這些值的。
“反向傳播”名字的由來,是因為我們從輸出從開始計算δ,然後是倒數第二層(隱藏層),以此類推。。。我們類似於把輸出層的誤差,反向傳播給了第3層(即,倒數第二層),然後再傳到第二層,,,
然而,這個推導過程是出奇的麻煩和出奇的複雜。。。
在不太嚴謹的情況下:

:point_up_2:忽略了標準化項,或者 λ = 0;
m 個訓練集的情況下:

△ 表示 大寫的 δ

j = 0,對應的是“偏差項”,所以沒有標準化項:

在得到每個 ij 的偏導項之後,你就可以使用梯度下降或者另一種高階優化演算法
10.3 理解反向傳播

z2^(1)、 z2^(2)是輸入單元的加權和。
反向傳播的過程和前向傳播非常相似。只是這兩個演算法計算的方向不一樣而已。

只有一個輸出單元(即,K = 2),一個輸入樣本,且 λ = 0 時:

比起這個複雜的表示式,你可以把cost(i)近似地當成是“神經網路輸出值”與“實際值”的方差

就像邏輯迴歸中,實際中會偏向於選擇比較複雜的、帶對數形式的代價函式,但為了方便理解,可以把這個代價函式看作是某種方差函式。因此,cost(i)表示了神經網路樣本值的準確程度,也就是,神經網路的輸出值 和 實際觀測值y(i) 的接近程度。

反向傳播演算法,一種直觀的理解是:反向傳播演算法就是在計算這些 δ_j^(l) 項,我們可以把它看做是我們在第 l 層中 第 j 個單元中得到的啟用項的“誤差”。
它們(這些 δ^(l)_j )衡量的是,為了影響這些中間值,我們想要改變神經網路中的權重的程度,進而影響整個神經網路的輸出h(x),並影響所有的代價函式
注意,:point_up_2: δ 是不包括偏置單元的(bias unit)。這取決於你對“反向傳播”的定義,以及實現演算法的方式,你也可以用其他的方式,來計算包含偏置單元的 δ 值。偏置單元的輸出總是“+1”,並且始終如此,我們無法改變。這都取決於你對反向傳播的實現。我經常用的方式是,在最終的計算中,我會丟掉它們(即,δ^(j)_0),因為它們不會對偏導數造成影響。
10.4 梯度檢測
反向傳播演算法有一個不好的特性:很容易產生一些微妙的bug,當它與梯度下降或是其他演算法一同工作時,看起來它確實能正常執行,並且代價函式J(θ)在每次梯度下降的迭代中,也在不斷的減小。雖然在反向傳播的實現中,存在一些bug,但執行情況確實不錯。雖然J(θ)在不斷減小,但是到了最後,你得到的神經網路其實誤差將會比無bug的情況下高出一個量級,並且你很可能不知道你得到的結果,是由bug所導致的。那我們應該如何應對了?(←這個bug幾乎都是由於你的錯誤實現導致的)
有一種思想叫做“梯度檢驗”,它能解決幾乎所有這種問題。這種方法的思想是通過估計梯度值來檢驗我們計算的導數值是否真的是我們要求的。
“紅色的線”就是我們所求的“θ偏導數(藍色切線的斜率)”的近似值。注意,ε 是離 θ 很近的一個點,如果離的太遠,這個算出來的近似值誤差就會很大了。。。
ε 一般取值為:10^(-4) ;一般不會取更小的值了,雖然 ε 足夠小時,就可以看做是 θ點的偏導數,因為可能會引發很多數值問題。。
當 θ ∈ R(即,θ 是實數 時)


:point_up_2:單測差分。另一種估計偏導數的公式。

:point_up_2:雙側差分。它能得到更準確的結果
當 θ 為 向量引數的時候,θ ∈ R^n (E.g. θ is "unrolled" version of Θ (1),Θ (2),Θ^(3))

逐個元素的求偏導數。

最後,記得關閉“梯度檢測”,因為,它是一個計算量非常大的,也是非常慢的計算導數程式。相對地,反向傳播演算法,它是一個高效能的計算導數的方法。因此,一旦通過測試,反向傳播的實現是正確的,就應該關閉掉梯度檢驗。
當我們實現反向傳播,或類似梯度下降的演算法來計算複雜模型時,我經常使用梯度檢驗來幫助我確保我的程式碼是正確的。
10.5 隨機初始化
關於梯度下降,我們該如何對 θ 設定初始值呢?

有一種想法是將 θ 的初始值全部設為0。儘管在邏輯迴歸中,這麼做是被允許的,但實際上在訓練網路時,將所有的引數初始化為0,起不到任何作用
-
舉例:
如果我們將 θ 的初始值全部設為 0 的話,會導致同一層的a^(l)_j都是相同的(即 i 相同時,即,藍色線的權重總是相同,紅色線的權重總是相同,綠色線的權重總是相同),而且它們還有相同的輸入。也因為a^(l)_j都是相同,所有 δ^(l)_j 也都是一樣的了。
這意味著,即時在每一次的梯度下降更新中,以為δ
(l)_j是一樣的,導致更新後的a
(l)_j還是相同的(即 i 相同時,即,藍色線的權重總是相同,紅色線的權重總是相同,綠色線的權重總是相同,雖然它們都不再等於0)。又因為,:point_up_2:圖中 兩個隱藏單元的輸入引數都是相同的,而藍色線的權重總是相同,紅色線的權重總是相同,綠色線的權重總是相同。這意味著,即時進行了一次迭代,但這兩個隱藏單元依然是相同的函式。這意味著,這個神經網路計算不出什麼有趣的函式。因為,若每層的隱藏單元都有一樣的輸入時,那麼每層的神經單元總是相同的函式。。。這是一種高度冗餘的現象,所有的單元都在計算相同的特徵,這也導致最後的輸出單元也只計算了一種特徵。這種做法是阻止了神經網路去學習有趣的東西。
為了解決這個問題(:point_up_2:也叫做,對稱權重問題),在神經網路中,對引數進行初始化時,要使用隨機初始化的思想。

因此對於每一個 θ 值,我們將其初始化為一個範圍在 -ε 到 ε 之間的隨機值。
注意,這裡的 ε 和前面所說的“梯度檢測”的 ε 沒有任何關係。
總而言之,為了訓練神經網路,我們首先要將權重隨機初始化為一個接近 0 的,範圍在 -ε 到 ε 之間的數。然後進行反向傳播,再進行梯度檢驗,最後使用梯度下降或者其他高階優化演算法來最小化代價函式J,以計算出 θ 的最優值。
10.6 組合到一起
小結一下使用神經網路時的步驟:

網路結構:
第一件要做的事是選擇網路結構,即決定選擇多少層以及決定每層分別有多少個單元。 你可以選擇每一層有多少個隱藏單元,以及有多個隱藏層
① 第一層的單元數即我們訓練集的特徵數量。
② 最後一層的單元數是我們訓練集的結果的類的數量,即,要區分的類別個數。
③ 對於隱藏層的單元個數,以及隱藏層的數目,一個合理的預設選項是:只使用單個隱藏層
如果隱藏層數大於1,同樣也有一個合理的預設選項,那就是每一個隱藏層的單元個數相同。
通常情況下隱藏層單元的個數越多越好。 但需要注意,如果有多個隱藏層,計算量一般會比較大。當然一般來說,隱藏單元還是越多越好。
並且一般來說,每個隱藏層所包含的單元數量還應該和輸入的 x 維度相匹配,即和特徵的數目匹配,隱藏單元的數目可以和輸入特徵的數目相同,或者是它的2倍,或者是3、4倍。因此,隱藏單元的數目和輸入特徵數目相匹配或者比特徵數大幾倍都是有效的。
我們真正要決定的是隱藏層的層數和每個中間層的單元數。
訓練神經網路:

:point_up_2:更先進的實現,如,使用向量化方式。而不使用 for 迴圈。實際上有複雜的方法可以實現,並不一定要使用for迴圈,但我非常不推薦,在第一次實現反向傳播演算法的時候使用更復雜更高階的方法

- 引數的隨機初始化 。通常,我們將引數初始化為很小的值,接近於零。
- 利用正向傳播方法,對任意的輸入 x^(i),計算出對應的h_θ (x^(i)) ,也就是輸出 y 的向量
- 編寫計算代價函式 J(θ) 的程式碼
- 利用反向傳播方法計算所有偏導數
- 利用梯度檢驗方法檢驗這些偏導數 ,在確認偏導數的正確性後,將梯度檢驗關閉。
- 使用梯度下降或高階的優化演算法來最小化代價函式
注意,對於神經網路,代價函式 J(θ) 是一個非凸函式,就是說不是凸函式,因此理論上可能停留在區域性最小值的位置。實際上,梯度下降演算法和其他一些高階優化方法理論上都可能收斂於區域性最小值。但一般來講,在實際操作中,這不是大問題。儘管我們不能保證,這些優化演算法一定會得到全域性最優值。但通常來說,像梯度下降這類的演算法,在最小化代價函式 J(θ) 的過程中,還是表現得很不錯的。通常能夠得到一個很小的區域性最小值,儘管這可能不一定是全域性最優值。
有兩個引數的代價函式圖:

梯度下降的原理:我們從某個隨機的初始點開始,它將會不停的往下下降,那麼反向傳播演算法的目的就是算出梯度下降的方向,而梯度下降的作用就是沿著這個方向一點點的下降,一直到我們希望得到的點。:point_up_2:這個例子就是區域性最優點。所以當你在執行反向傳播演算法和梯度下降或者其他更高階的優化方法時,這幅圖片解釋了基本的原理。
反向傳播演算法能夠讓更復雜、強大、非線性的函式模型,跟你的資料很好的擬合。
10.7 無人駕駛
在這段視訊中,我想向你介紹一個具有歷史意義的神經網路學習的重要例子。那就是使用神經網路來實現自動駕駛,也就是說使汽車通過學習來自己駕駛。接下來我將演示的這段視訊是我從Dean Pomerleau那裡拿到的,他是我的同事,任職於美國東海岸的卡耐基梅隆大學。在這部分視訊中,你就會明白視覺化技術到底是什麼?在看這段視訊之前,我會告訴你視覺化技術是什麼。
在下面也就是左下方,就是汽車所看到的前方的路況影象。

在圖中你依稀能看出一條道路,朝左延伸了一點,又向右了一點,然後上面的這幅圖,你可以看到一條水平的選單欄(左上圖,第一條)顯示的是駕駛操作人選擇的方向。就是這裡的這條白亮的區段顯示的就是人類駕駛者選擇的方向。比如:最左邊的區段,對應的操作就是向左急轉,而最右端則對應向右急轉的操作。因此,稍微靠左的區段,也就是中心稍微向左一點的位置,則表示在這一點上人類駕駛者的操作是慢慢的向左拐。
這幅圖的第二部分(左上圖,第二條)對應的就是學習演算法選出的行駛方向。並且,類似的,這一條白亮的區段顯示的就是神經網路在這裡選擇的行駛方向,是稍微的左轉,並且實際上在神經網路開始學習之前,你會看到網路的輸出是一條灰色的區段,就像這樣的一條灰色區段覆蓋著整個區域這些均稱的灰色區域,顯示出神經網路已經隨機初始化了,並且初始化時,我們並不知道汽車如何行駛,或者說我們並不知道所選行駛方向。只有在學習演算法運行了足夠長的時間之後,才會有這條白色的區段出現在整條灰色區域之中。顯示出一個具體的行駛方向這就表示神經網路演算法,在這時候已經選出了一個明確的行駛方向,不像剛開始的時候,輸出一段模糊的淺灰色區域,而是輸出一條白亮的區段,表示已經選出了明確的行駛方向。

ALVINN (Autonomous Land Vehicle In a Neural Network)是一個基於神經網路的智慧系統,通過觀察人類的駕駛來學習駕駛,ALVINN能夠控制NavLab,裝在一輛改裝版軍用悍馬,這輛悍馬裝載了感測器、計算機和驅動器用來進行自動駕駛的導航試驗。實現ALVINN功能的第一步,是對它進行訓練,也就是訓練一個人駕駛汽車。

然後讓ALVINN觀看,ALVINN每兩秒將前方的路況圖生成一張數字化圖片,並且記錄駕駛者的駕駛方向,得到的訓練集圖片被壓縮為30x32畫素,並且作為輸入提供給ALVINN的三層神經網路,通過使用反向傳播學習演算法,ALVINN會訓練得到一個與人類駕駛員操縱方向基本相近的結果。一開始,我們的網路選擇出的方向是隨機的,大約經過兩分鐘的訓練後,我們的神經網路便能夠準確地模擬人類駕駛者的駕駛方向,對其他道路型別,也重複進行這個訓練過程,當網路被訓練完成後,操作者就可按下執行按鈕,車輛便開始行駛了。

每秒鐘ALVINN生成12次數字化圖片,並且將影象傳送給神經網路進行訓練,多個神經網路同時工作,每一個網路都生成一個行駛方向,以及一個預測自信度的引數,預測自信度最高的那個神經網路得到的行駛方向。比如這裡,在這條單行道上訓練出的網路將被最終用於控制車輛方向,車輛前方突然出現了一個交叉十字路口,當車輛到達這個十字路口時,我們單行道網路對應的自信度驟減,當它穿過這個十字路口時,前方的雙車道將進入其視線,雙車道網路的自信度便開始上升,當它的自信度上升時,雙車道的網路,將被選擇來控制行駛方向,車輛將被安全地引導進入雙車道路。
這就是基於神經網路的自動駕駛技術。當然,我們還有很多更加先進的試驗來實現自動駕駛技術。在美國,歐洲等一些國家和地區,他們提供了一些比這個方法更加穩定的駕駛控制技術。但我認為,使用這樣一個簡單的基於反向傳播的神經網路,訓練出如此強大的自動駕駛汽車,的確是一次令人驚訝的成就。