自己動手寫深度神經網路框架(五)
前幾篇的鏈接如下:
永遠在你身後:自己動手寫深度神經網路框架(一)
永遠在你身後:自己動手寫深度神經網路框架(二)
永遠在你身後:自己動手寫深度神經網路框架(三)
永遠在你身後:自己動手寫深度神經網路框架(四)
然後是:完整實現
在前面幾篇中已經介紹了一些Layer的正反向計算過程及其推導,並且用它們構建了一個網路
雖然推導的過程是建立在單個訓練樣本的基礎上的,但對於同時使用多個訓練樣本同樣有效,下面來簡單的證明一下:
首先回顧一下線性層的forward計算過程,輸入 是一個向量
所有神經元的權重是一個矩陣:
輸出 同樣是一個向量
計算過程為:
現在將其改成每次訓練多個樣本,先看訓練批量為1的情況;另外, 的符號要做下改動
然後,將輸入輸出都寫成矩陣形式
很容易可以得到下面的計算過程
現在,設每次訓練n個樣本,這些新增的訓練樣本表示為
……
所以輸入的矩陣就變成了:
輸出的計算過程就變成了:
可以看到,即使每次訓練多個樣本,它們之間的計算都是相互獨立的,並不會糾纏在一起
這個是線性層的證明,其他的Layer就不一一說明瞭,再看看backward計算過程,同樣,我們先看訓練樣本數為1的情況
backward中傳進來的參數是損失關於輸出的梯度
為了方便表示,這裡令
同時已知:
為了將損失繼續傳回上一層,所以需要計算 ,根據鏈式法則可得:
同樣令
上面是訓練樣本數為1時的情況,第(三)篇有詳細的推導,這裡只是簡單的回顧一下
現在來看訓練樣本數為n的情況,將損失關於輸出的梯度表示成矩陣形式有:
利用和上面相同的計算過程有:
所以,在反向傳播過程中,多個訓練樣本之間的梯度計算也是獨立的,不會相互影響
其實這個在證明forward以後結論已經很明顯了,不過backward的任務不僅僅是把損失傳給上一層,主要是計算參數的梯度,而且,這個與之前的計算還是有一些不同的,來看一下:
這是之前推導過的權重關於損失的梯度的公式,計算出來這個梯度矩陣的單個元素的值為:
現在看多個訓練樣本的情況:
雖然變成矩陣與矩陣相乘了,但是算一下維度就可以發現, 的各維度大小並沒有改變,依然是:
不過它其中的元素的值肯定是變了:
通過公式可以知道,其中每一個梯度的值都變成了多個訓練樣本梯度的總和,所以在更新參數時,應該將梯度除以訓練樣本的數量,如下:
以上是權重的一些變化,偏置也有一些變化,不過也差不過,就不細說了,下面把修改的代碼貼上:
def backward(self, eta):
if self.require_grad:
batch_size = eta.shape[0]
self.W.grad = np.dot(self.x.T, eta) / batch_size
if self.b is not None: self.b.grad = np.sum(eta, axis=0) / batch_size
return np.dot(eta, self.W.T)
可以看到,和之前(三)裡面的代碼對比,eta變成一個二維數組了,其中第一個維度大小就是訓練樣本的數量(batch_size),然後將W和b的梯度都除以batch_size,其他地方的代碼不需要改變
最後,即使你只需要使用一個樣本進行訓練,上述代碼也是兼容的
上面簡單的討論了一下多批量訓練的情況下的計算過程,接下來是時候進入正題了
在上一篇提到了優化器,使用的優化演算法是SGD(Stochastic gradient descent,隨機梯度下降)
梯度下降的概念之前已經說過了,也可百度一下,相關的文章有茫茫多
而隨機梯度下降就是指每次使用一個樣本進行訓練,因為只有一個樣本的計算量,所以每次訓練的速度非常快,但是同樣,也正是因為只有一個樣本,偶然性很大,並不一定很好的複合了訓練集的整體分佈,所以,針對某一個樣本進行訓練,下一輪訓練換一個樣本損失甚至有可能不減反增
所以,可以同時使用多個樣本訓練改良上述優化演算法,例如MNIST訓練集數量為60000,那麼每次訓練都使用這60000個樣本進行訓練,這種方法叫做BGD(Batch gradient descent,批量梯度下降)
雖然這樣訓練數據肯定是符合訓練集的整體分佈的,但是缺點也是顯而易見的,速度太慢了
所以,可以採取一種折中的辦法,叫做miniBGD(mini Batch gradient descent,小批量梯度下降)
前面的代碼也就是使用的這種方法,其實小批量梯度下降不過是在SGD和BGD之間調整了訓練樣本的數量而已,使用miniBGD演算法,但每次訓練的樣本數為1時,它就變成了SGD,同理,如果你每次都將整個訓練集丟進去,那麼它就化身為BGD了
一般,訓練樣本數(batch_size)可以取2的整數次方,如64,128等等
批量訓練說完了,下面來介紹一下動量優化演算法(Momentum)
在之前討論的miniBGD裏,每一輪訓練的梯度都是獨立的,沒有關聯的,比如第一輪使用64個樣本進行訓練,計算得到的是梯度a,在下一輪訓練中換一批樣本進行訓練,得到了梯度b,顯然梯度a和b之間並沒有什麼關聯,它們都是朝著各自的方向更新參數,所以有個很顯然的問題,舉個栗子