训练神经网络时如何确定batch的大小?
?
當我們要訓練一個已經寫好的神經網絡時,我們就要直面諸多的超參數啦。這些超參數一旦選不好,那么很有可能讓神經網絡跑的還不如感知機。因此在面對神經網絡這種容量很大的model前,是很有必要深刻的理解一下各個超參數的意義及其對model的影響的。
?
貼心的小夕還是先帶領大家簡單回顧一下神經網絡的一次迭代過程:
?
?
即,首先選擇n個樣本組成一個batch,然后將batch丟進神經網絡,得到輸出結果。再將輸出結果與樣本label丟給loss函數算出本輪的loss,而后就可以愉快的跑BP算法了(從后往前逐層計算參數之于loss的導數)。最后將每個參數的導數配合步長參數來進行參數更新。這就是訓練過程的一次迭代。
?
由此,最直觀的超參數就是batch的大小——我們可以一次性將整個數據集喂給神經網絡,讓神經網絡利用全部樣本來計算迭代時的梯度(即傳統的梯度下降法),也可以一次只喂一個樣本(即嚴格意義上的隨機梯度下降法,也稱在線梯度下降法,簡稱SGD),也可以取個折中的方案,即每次喂一部分樣本讓其完成本輪迭代(即batch梯度下降法)。
?
數學基礎不太好的初學者可能在這里犯迷糊——一次性喂500個樣本并迭代一次,跟一次喂1個樣本迭代500次相比,有區別嗎?
?
其實這兩個做法就相當于:
第一種:
total = 舊參下計算更新值1+舊參下計算更新值2+...+舊參下計算更新值500 ;
新參數 = 舊參數 + total;
?
第二種:
新參數1 = 舊參數 + 舊參數下計算更新值1;
新參數2 = 新參數1 + 新參數1下計算更新值1;
新參數3 = 新參數2 + 新參數2下計算更新值1;
...
新參數500 =新參數500 + 新參數500下計算更新值1;
?
也就是說,第一種是將參數一次性更新500個樣本的量,第二種是迭代的更新500次參數。當然是不一樣的啦。
?
那么問題來了,哪個更好呢??
?
我們首先分析最簡單的影響,哪種做法收斂更快呢?
?
我們假設每個樣本相對于大自然真實分布的標準差為σ,那么根據概率統計的知識,很容易推出n個樣本的標準差為(有疑問的同學快翻開概率統計的課本看一下推導過程)。
從這里可以看出,我們使用樣本來估計梯度的時候,1個樣本帶來σ的標準差,但是使用n個樣本區估計梯度并不能讓標準差線性降低(也就是并不能讓誤差降低為原來的1/n,即無法達到σ/n),而n個樣本的計算量卻是線性的(每個樣本都要平等的跑一遍前向算法)。
?
由此看出,顯然在同等的計算量之下(一定的時間內),使用整個樣本集的收斂速度要遠慢于使用少量樣本的情況。換句話說,要想收斂到同一個最優點,使用整個樣本集時,雖然迭代次數少,但是每次迭代的時間長,耗費的總時間是大于使用少量樣本多次迭代的情況的。
?
那么是不是樣本越少,收斂越快呢?
理論上確實是這樣的,使用單個單核cpu的情況下也確實是這樣的。但是我們要與工程實際相結合呀~實際上,工程上在使用GPU訓練時,跑一個樣本花的時間與跑幾十個樣本甚至幾百個樣本的時間是一樣的!當然得益于GPU里面超多的核,超強的并行計算能力啦。
因此,在工程實際中,從收斂速度的角度來說,小批量的樣本集是最優的,也就是我們所說的mini-batch。這時的batch size往往從幾十到幾百不等,但一般不會超過幾千(你有土豪顯卡的話,當我沒說)。
?
那么,如果我真有一個怪獸級顯卡,使得一次計算10000個樣本跟計算1個樣本的時間相同的話,是不是設置10000就一定是最好的呢?雖然從收斂速度上來說是的,但!是!
我們知道,神經網絡是個復雜的model,它的損失函數也不是省油的燈,在實際問題中,神經網絡的loss曲面(以model參數為自變量,以loss值為因變量畫出來的曲面)往往是非凸的,這意味著很可能有多個局部最優點,而且很可能有鞍點!
?
插播一下,鞍點就是loss曲面中像馬鞍一樣形狀的地方的中心點,如下圖:
?
(圖片來自《Deep Learning》)
想象一下,在鞍點處,橫著看的話,鞍點就是個極小值點,但是豎著看的話,鞍點就是極大值點(線性代數和最優化算法過關的同學應該能反應過來,鞍點處的Hessian矩陣的特征值有正有負。不理解也沒關系,小夕過幾天就開始寫最優化的文章啦~),因此鞍點容易給優化算法一個“我已經收斂了”的假象,殊不知其旁邊有一個可以跳下去的萬丈深淵。。。(可怕)
?
回到主線上來,小夕在《機器學習入門指導(4)》中提到過,傳統的最優化算法是無法自動的避開局部最優點的,對于鞍點也是理論上很頭疼的東西。但是實際上,工程中卻不怎么容易陷入很差勁的局部最優點或者鞍點,這是為什么呢??
?
暫且不說一些很高深的理論如“神經網絡的loss曲面中的局部最優點與全局最優點差不太多”,我們就從最簡單的角度想~
?
想一想,樣本量少的時候會帶來很大的方差,而這個大方差恰好會導致我們在梯度下降到很差的局部最優點(只是微微凸下去的最優點)和鞍點的時候不穩定,一不小心就因為一個大噪聲的到來導致炸出了局部最優點,或者炸下了馬(此處請保持純潔的心態!),從而有機會去尋找更優的最優點。
?
因此,與之相反的,當樣本量很多時,方差很小(咦?最開始的時候好像在說標準差來著,反正方差與標準差就差個根號,沒影響的哈~),對梯度的估計要準確和穩定的多,因此反而在差勁的局部最優點和鞍點時反而容易自信的呆著不走了,從而導致神經網絡收斂到很差的點上,跟出了bug一樣的差勁。
?
小總結一下,batch的size設置的不能太大也不能太小,因此實際工程中最常用的就是mini-batch,一般size設置為幾十或者幾百。但是!?
好像這篇文章的轉折有點多了誒( ̄? ̄)
細心的讀者可能注意到了,這之前我們的討論是基于梯度下降的,而且默認是一階的(即沒有利用二階導數信息,僅僅使用一階導數去優化)。因此對于SGD(隨機梯度下降)及其改良的一階優化算法如Adagrad、Adam等是沒問題的,但是對于強大的二階優化算法如共軛梯度法、L-BFGS來說,如果估計不好一階導數,那么對二階導數的估計會有更大的誤差,這對于這些靠二階導數吃飯的算法來說是致命的。
?
因此,對于二階優化算法,減小batch換來的收斂速度提升遠不如引入大量噪聲導致的性能下降,因此在使用二階優化算法時,往往要采用大batch哦。此時往往batch設置成幾千甚至一兩萬才能發揮出最佳性能(比如小夕曾經試驗過,做信息抽取中的關系分類分類時,batch設置的2048配合L-BFGS取得了比SGD好得多的效果,無論是收斂速度還是最終的準確率)。
?
另外,聽說GPU對2的冪次的batch可以發揮更佳的性能,因此設置成16、32、64、128...時往往要比設置為整10、整100的倍數時表現更優(不過小夕沒有驗證過,有興趣的同學可以試驗一下~
總結
以上是生活随笔為你收集整理的训练神经网络时如何确定batch的大小?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ICLR2021 Oral |9行代码提
- 下一篇: 清华提出LogME,无需微调就能衡量预训