一、概要:
批訓練(mini-batch)的訓練方法幾乎每一個深度學習的任務都在用,但是關於批訓練的一些問題卻仍然保留,本文透過對MNIST資料集的演示,詳細討論了batch_size對訓練的影響,結果均透過colab(https://colab.research.google.com/drive/1ygbjyKZH2DPhMbAU7r2CUm3f59UHq7Iv?usp=sharing)跑出,開始時對資料進行了歸一化處理,其他的與經典CNN程式碼無差,(單GPU:Telsa T4),對結果懷疑的可以去復現一下。
二、實驗結果:
首先我選取了 Batch Size=64,Epochs=20,進行了18次實驗,第一張圖橫座標是訓練次數,縱座標是每一次單獨所花時間,由圖易得趨勢是很不穩定的,這跟批訓練的本質有關,這在第三節中有詳細探討。由此可以得出一個結論:
”任何時候幾乎每一次的訓練得到的結果都是互異的,當且僅當超引數一致和不同批之間的資料分佈幾乎無差情況下不滿足。”
因而多數情況下,批訓練出的結果不一定具有很強的代表性,之所以會比較它們的原因主要是為了比對不同配置(如超引數不一樣)帶來的相對變化,若以一次批訓練的結果就開始信口開河就不免滑稽了。
下面兩張圖是不同的兩次訓練所呈現的精確度與Epochs的關係,不難發現,兩者的平穩程度有很大差異,也符合前面的結論。
因為訓練時較不穩定,因此在以下的對照實驗中每一組均至少進行5次實驗,選取較為接近的資料( ±3% )取平均,當然,可以發現 Batch Size=64 時的情況與上面又有一定差異。下表中的資料基於 Epochs=20 , Time 指的是跑完所有的Epochs所需的時間。
- 最慢的為 Batch Size=1 的情況,如果一開始資料經過了shuffle處理,這種情況可以近似為SGD。
-
不存在無條件batch越大,時間越短的情況,只是在一定範圍內( [1, 1024] )該結論成立,雖然1024時時間慢於512,考慮到不穩定的情況,這裡擴大了範圍,當然,結論在 [1,512] 範圍內應滿足。
-
當 Batch Size>=1024 之後,儘管速度比64和128來得快,但是卻較難收斂,所以較大batch和較小batch之間幾乎沒有可比性。
接下來我將後面不能完全收斂的組在 Epochs=80 的設定下繼續進行實驗,可以發現會有輕微提升但還是不能收斂,關於如何實現大batch加速在會在第四節討論。
三、批訓練的本質:
如果把訓練類比成從山頂到山腳的過程,批訓練就是每一次你選定一個方向(一個batch的資料)往下走,batch的大小可以類比成你打算每一次走多少步,當然,深度學習是實驗型科學,這裡的例子只是嘗試解釋一下intuition,例子有不妥之處,樂一樂也無妨。
- 若 Batch Size=1 ,小碎步往下走,謹小慎微,自然花的時間比較多
-
當 Batch Size 慢慢增大時,你思考的時間相對來講會變少,但你每一次的遇到的路況不算多,因而你學習能力強,應對出現過的路況能較好應對,訓練會一定程度提高
-
當 Batch Size 很大時,你一開始一個大跨步就直接來到了一個很平坦的地方,你誤以為這邊就是山腳,因而卡在了區域性最優處,當然如果你運氣好,每次都是有坡度的情況,你很快就到了山腳。或者可以這樣想,你一下子走太多步,有些路況你給忘了,導致下一次走的時候做了錯誤的選擇,導致走不出來,這也是大batch泛化能力差的原因吧。
-
訓練時需要保證batch裡面的資料與整個資料的差異不太大,如果當差異很大的時候,我們一開始遇到的路況跟後面的完全不一樣,導致你直接懵逼,訓練效果差。
四、保持準確率的大batch加速:
詳見:Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour
https://arxiv.org/abs/1706.02677
雖然是2017的論文,但是是篇有意思的論文,透過分散式訓練可以在 Batch Size=8k 的時候保持準確率,時間為1hour,資料集為ImageNet,有多個GPU的可以去深挖一下,加速自己的訓練,因我連GPU都是白嫖colab的,分散式更不可能了,這裡只是簡單敘述而已。
Linear Scaling Rule:當mini-batch的大小乘以k,則學習率也乘以k。
x 是從總的分佈 X 中取樣出來,w 代表一個網路的權重引數, l(x,w) 意味著損失,將它們加起來再除以總資料分佈的大小便是總損失了。
mini-batch的SGD更新一次如下, B 是一個從 X 中取樣出來的mini-batch, n=|B| 是mini-batch的大小。
在時間步 t ,權重引數為 wt ,經過 k 次迭代更新後如下,這是一次一次疊加起來的
warm-up:一開始的學習率不那麼高
臉書討論了兩種熱身方式:恆定常數和循序漸進法進行熱身。前者說的是在前5個Epochs保持學習率為 η ,之後再調為 kη ,在fine-tune目標識別和分割的任務中的模型大有裨益,可是當 k 很大後,錯誤急劇上升。循序漸進說的是一開始為 η,然後不斷加上常數,要求是前5個訓練結束後能達到 kη 。後者證明在訓練ImageNet更有效。
技巧還有每一個分散式GPU訓練的損失除以 kn 和對修改後的學習率進行momentum修正。還有一些分散式的細節這裡不再詳述。
五、討論:
看了臉書的那篇論文,我也突發奇想,能不能設計一個自定義的學習率來試試呢?實驗中 Batch Size=1024,Epochs=20 ,選取的自定義為每當經過了step size的optimizer.step()就給學習率乘上 γ ,當 Batch Size=1024 時,一共有59個batch,因而step的總次數為59 * 20 = 1180,同時考慮到模型在第6個Epoch卡在區域性最優點,將step size設為100,當然也設定過200,400等,結果一樣收斂不了。