在上一篇中,我們看到了神經網絡是怎樣使用梯度下降算法來學習它們的權值和偏置。然而,我們還有一些沒有解釋:我們沒有討論怎樣計算損失函數的梯度。本篇中將解釋著名的BP算法,它是一個快速計算梯度的算法。
反向傳播算法(Backpropagation algorithm,BP)是在1970s提出的,但是它的重要性直到一篇著名的1986年的論文才被接受。論文是David Rumelhart,Geoffrey Hinton,以及Ronald Williams合寫的。這篇論文描述了幾種神經網絡,其中的反向傳播算法工作得更快比早期的學習算法,這使得使用神經網絡能夠解決之前不能解決的問題。今天,反向傳播算法已經是神經網絡中最核心的算法。
BP算法的核心是網絡中的損失函數C分別關於任何權值w(或者偏置b)的偏導數的表達式。這個表達式告訴我們當我們改變權值和偏置的時候損失函數變化得有多快。BP算法不僅是一個快速學習的算法,它實際上給出了更細節的關於權值和偏置改變網絡的全部行為是怎樣變化的。
熱身:一個基於矩陣快速計算神經網絡輸出的方法
在討論反向傳播之前,讓我們先熱身一下,看一下一個快速基於矩陣的計算神經網絡輸出的算法。我們實際上已經簡短地看見了這個算法在上一張快結束的時候。特別地,這是熟悉在反向傳播中用到的符號的一種很自然的方法。
我們將使用來表示第(l-1)層的第k個神經元到第l層的第j個神經元之間連接的權值。例如下圖中的
表示第3層的第2個神經元與第2層的第4個神經元之間的連接的權值:
那么,對於偏置和激活,我們使用一個相似的符號。顯然地,我們使用表示第l層的第j個神經元。並且,我們使用
來表示第l層的第j個神經元的激活。就像下圖一樣:
我們能發現第l層的第j個神經元的激活和第l-1層的激活有關系,正如下面的式子:
這里的和表示第l-1層的所有神經元k。為了把表達式寫成一個矩陣形式,我們為每層l定義了一個權值矩陣。權值矩陣
的元素僅僅是和第l層的神經元連接的權值,即,第j行和第j列的元素是
。類似地,對於每一層l,我們定義一個偏置向量
。偏置向量的元素僅僅是值
,第l層的每個神經元的一個元素。最后,我們定義了一個激活向量
,它的組成是激活
。接下來我們要做的是向量化一個函數,例如
。簡單地說,如果我們有函數
,那么f的向量化形式有這樣的結果:
所以我們能夠把(23)式寫成:
這樣寫不僅在符號上簡單許多,而且有助於你從總體上理解這個式子:第l層的激活就是等於前一層(l-1)的激活和與l層神經元相連接的權值的積再加上該層的偏置,然后應用sigmoid函數。最關鍵的是,許多線性代數庫計算基於矩陣的形式會非常快。
當使用等式(25)來計算,我們計算了一個中間量
沿着這種方式。這個量表明是足夠有用的而值得重新命名:我們把
稱作到第l層神經元的權重輸入(weighted input)。等式(25)有時候會寫成權重輸入(weighted input)的形式,正如
。然后需要注意的是:
有
這樣的組成,即,
只是第l層的神經元j的到激活函數的權重輸入。
關於損失函數我們需要的兩個假設
BP算法的目標就是計算損失函數C關於任何網絡中的權重w或者偏置b的偏導數和
。這里還是以二次損失函數為例子。即:
這里的n是訓練樣本的總數;對所有單個訓練樣本x取和;y=y(x)是相應的期望輸出;L表示層數;是輸入為x的網絡的激活向量
。
第一個假設就是損失函數可以被寫成,單個的訓練樣本的損失函數為
。我們始終遵循這種假設。
我們需要這個假設的理由是因為反向傳播實際上讓我們做的是計算單個的訓練樣本的偏導數和
。然后通過平均所有的訓練樣本來計算
和
。實際上,我們可以假設訓練樣本x已經被固定,然后丟棄x下標,把損失
寫成
。
第2個假設是損失可以被寫成一個神經網絡的輸出的函數:
例如,二次損失函數滿足這個需求,因為單個訓練樣本x的二次損失可能被寫成:
Hadamard積,
反向傳播算法是基於普通的線性代數操作-像向量相加,用矩陣乘以一個向量。但是其中有一個操作用的比較少。假設s和t是兩個維數一樣的向量。那么我們使用來表示兩個元素的按位相乘。因此,
的組成為
。例如:
這種按位相乘有時被稱為Hadamard 積。好的矩陣庫通常提供了Hadamard積的快速的實現,這對於實現反向傳播信手拈來。
反向傳播背后的四個等式
反向傳播是關於理解在一個網絡改變損失函數時,權重和偏置是怎樣變化的。最終,這個意味着計算偏導數和
。但是為了計算那些,我們首先引進一個中間變量,
,我們把它稱為第l層的第j個神經元的error。BP將給出一個計算error
的過程,然后關聯
和
與
。
為了理解error是如何定義的,想象我們的神經網絡中有一個精靈:
這個精靈坐在第l層的第j個神經元上。當神經元的輸入進來時,精靈擾亂神經元的操作。它增加了一個小的變化到神經元的權重輸入,所以輸出不再是
,而是
。這個變化傳播到網絡中后面的層,最終導致損失函數改變了一個量
。
現在,這個精靈是一個好的精靈,並且正在幫助你改進損失函數,也就是他們正嘗試找到一個使得損失函數更小。假設
有一個很大的值(要么是正的要么是負的,指絕對值)。那么,精靈能夠通過選擇
有和
相反的符號來使損失函數減小得十分多。相反,如果
接近於0,那么精靈就不能通過擾亂權重輸入
來改進損失函數。到目前為止,精靈能夠告訴我們,神經元已經相當接近最優了。因此,存在一個啟發式
是神經元的error的一個度量。於是我們定義層l的的神經元j的error
為:
按照我們的傳統,我們使用來表示和層l關聯的error向量。反向傳播將告訴我們計算每層的
方法,然后把這些errors關聯到我們真實感興趣的量
和
。
你可能想知道為什么精靈正在改變權重輸入。當然,想象精靈正在改變輸出激活
,然后使用
來度量我們的error,這樣也許會更自然。事實上,如果你這樣做了將和下面的討論的結果是差不多的。但是,它將使陳述BP變得稍微有點代數上更復雜。因此,我們將堅持
作為我們error的度量。
攻克計划:
BP是基於四個基礎的等式。這些等式一起給了我們一個計算error(你可以將其翻譯為殘差)和損失函數的梯度的方法。
輸出層殘差
的一個等式
:的組成由下面的式子給定:
這是一個很自然的式子。右邊的第一項,,僅僅是度量作為第j個輸出激活的一個函數,損失函數變化得有多快。例如,如果C不依賴於一個特定輸出神經元j很多的話,那么
將是很小的,這也正是我們所期望的。右邊的第二項,
是度量激活函數
在點
上改變得有多快。我們能夠發現,(BP1)中的所有項都很容易計算。特別是,我們計算
同時也在計算網絡的行為,並且計算
也只是一個很小的花費。
的真實形式將取決於損失函數的形式。然而,被提供的損失函數是已知的,會存在一點小麻煩在計算
的時候。例如,如果我們使用二次損失函數,那么
,因此
,它是很容易被計算的。
等式(BP1)是一個分量方式的表達式。它是一個完美的表達式,但是不是我們想要的基於矩陣的BP表達式。然而,把它寫成一個矩陣的形式也是簡單的:
這里,被定義為偏導數
組成的一個向量。你可以把它想象成表達C關於輸出激活的一個變化率。所以,
,最后基於矩陣的形式為:
用下一層中的殘差
表示的殘差
的一個等式
:特別地
假設我們知道殘差在第
層。當我們應用轉置權值矩陣
時,我們可以直觀地把這個想成讓殘差向后穿過網絡,從而給了我們某種度量第l層的輸出的殘差的方法。當使用Hadamard積
時,它通過第l層的激活函數把殘差向后移動,給出了到達l層的權重輸入的殘差
。
組合BP2和BP1,我們能計算網絡中的任何層的殘差。我們首先通過BP1來計算
,然后應用等式BP2來計算
,然后再次使用等式BP2計算
,等等,用這樣的方式反向穿過網絡。
網絡中損失函數關於任何偏置的變化率的一個等式:
特別地:
也就是,殘差實際上等於變化率
。這個信息很有用,因為BP1和BP2已經告訴我們怎樣計算
。我們能夠重寫BP3:
損失函數關於任何權值的變化率的一個等式:
特別地:
這告訴我們怎樣利用量和
來計算偏導數
,前面兩個量我們已經知道怎么計算了。可以重寫為下面的形式:
其中是權重為w輸入的神經元的激活,
是從權重w的神經元的輸出殘差。可以簡化為下面的圖形:
等式(32)的一個很好的結果是當激活很小的時候,
,梯度項
也將趨向於很小。在這種情況下,我們將說權重學習得很慢,意味着在梯度下降過程中改變得很多。換句話說,BP4的一個結果就是從低-激活神經元輸出的權重學習得很慢。
從BP1-BP4中也可以看到其他的信息。先看看輸出層。考慮(BP1)中的項。回憶上一章中的sigmoid函數的圖,當
接近0或1的時候,
函數變得很平坦。當這個發生的時候,我們可以得到
。所以如果輸出神經元是低激活(
)或者高激活(
),那么最后一層中的權重將學習得很慢。這種情況下,通常是說輸出神經元已經飽和了,並且權重已經停止學習了(或者學習得很慢)。相似的結論對於輸出神經元中的偏置也是成立的。
對於非輸出層我們也能獲得一些相似的信息。特別是,注意BP2中的項。這意味着如果神經元接近飽和,則
可能變小。反過來,這也意味着輸入到一個飽和神經元的任何權重也將學習得很慢。
可以總結出來,我們已經知道,如果輸入神經元是低-激活或者輸出神經元已經飽和了,也就是要么是高激活,要么是低激活,那么一個權重將學習得很慢。剛才觀測到的這些信息沒有太多的讓人驚訝。但是,它們依舊幫助提升當一個神經網絡學習的時候發生了什么我們的思維模型。
四個基礎等式的證明
我們將證明四個基礎等式(BP1)-(BP4)。所有四個等式都是多元微積分的鏈式法則的結果。首先看(BP1)等式吧,它給出的是輸出殘差,。為了證明這個等式,回憶定義:
應用鏈式法則,我們可以重寫使用關於輸出激活的偏導數來表示
上面的偏導數:
和表示所有輸出層中的神經元k。當然,第k個神經元僅僅取決於當k=j時的第j個神經元的輸入權值的輸出激活
。因此當
時,
項就消失了。所以可以簡化前面的等式為:
因為,右邊的第2項能夠被寫成
,等式就變成:
這便是BP1的形式。接下來BP2和BP3的證明留給讀者自己思考。
反向傳播算法
BP算法為我們提供了一個計算損失函數梯度的方法。寫成一個算法的形式:
-
輸入 x:為輸入層設置相應的激活
。
-
前向:對於每個l=2,3,…,L計算
以及
。
-
輸出殘差
:計算向量
。
-
反向傳播殘差:對於每個l=L-1,L-2,…,2計算
。
-
輸出:損失函數的梯度為
和
。
我們從最后一層開始向后計算殘差向量,這可能看起來我們正在向后穿過網絡是奇怪的。但是,如果你思考反向傳播的證明,反向移動是由於損失是網絡的輸出的一個函數的事實所導致的。為了理解損失怎樣隨着早先的權重和偏置變化的,我們需要重復應用鏈式法則,層層向后計算來獲得可用表達式信息。反向傳播算法計算的是單個訓練樣本的梯度,即
。實踐中,通常把反向傳播和一個像隨機梯度這樣的學習算法組合,在隨機梯度算法中我們計算許多訓練樣本的梯度。特別地,給定一個含有m個訓練樣本的mini-batch,下面的算法應用了一個基於mini-batch的梯度下降學習算法:
-
輸入一個訓練樣本的集合
-
對於每個訓練樣本x:設置相應的輸入激活
,然后執行下面的步驟:
-
前向:對於每個l=2,3,…,L計算
以及
。
-
輸出殘差
:計算向量
。
-
反向傳播殘差:對於每個l=L-1,L-2,…,2計算
-
-
梯度下降:對於每個l=L,L-1,…,2依據規則
更新權重,依據規則
更近偏置。
當然,實踐中為了實現隨機梯度下降,你也需要一個外層循環來產生訓練樣本的mini-batches,以及一個外層循環單步執行訓練的多個epochs。
反向傳播代碼實現:
關於代碼的分析,請看我的下一篇文章《神經網絡代碼分析》。
轉載 http://www.gumpcs.com/index.php/archives/962