
上面出現的問題主要是機器不夠、内存不夠用。在深度學習訓練的時候,數據的batch size大小受到GPU内存限制,Batch size大小會影響模型最終的準确性和訓練過程的性能。在GPU内存不變的情況下,模型越來越大,那麼這就意味着數據的batch size智能縮小,這個時候,梯度累積(Gradient accumulation)可以作為一種簡單的解決方案來解決這個問題。
下面這個圖中橙色部分HERE就是梯度累積算法在AI系統中的大緻位置,一般在AI框架/AI系統的表達層,跟算法結合比較緊密。

訓練數據的Batch size大小對訓練過程的收斂性,以及訓練模型的最終準确性具有關鍵影響。通常,每個神經網絡和數據集的Batch size大小都有一個最佳值或值範圍。
不同的神經網絡和不同的數據集可能有不同的最佳Batch size大小。
選擇Batch size的時候主要考慮兩個問題:
泛化性:大的Batch size可能陷入局部最小值。陷入局部最小值則意味着神經網絡将在訓練集之外的樣本上表現得很好,這個過程稱為泛化。因此,泛化性一般表示過度拟合。
收斂速度:小的Batch size可能導緻算法學習收斂速度慢。網絡模型在每個Batch的更新将會确定下一次Batch的更新起點。每次Batch都會訓練數據集中,随機抽取訓練樣本,因此所得到的梯度是基于部分數據噪聲的估計。在單次Batch中使用的樣本越少,梯度估計準确度越低。換句話說,較小的Batch size可能會使學習過程波動性更大,從本質上延長算法收斂所需要的時間。
考慮到上面兩個主要的問題,所以在訓練之前需要選擇一個合适的Batch size。

雖然傳統計算機在CPU上面可以訪問大量RAM,還可以利用SSD進行二級緩存或者虛拟緩存機制。但是如GPU等AI加速芯片上的内存要少得多。這個時候訓練數據Batch size的大小對GPU的内存有很大影響。
為了進一步理解這一點,讓我們首先檢查訓練時候AI芯片内存中内存的内容:
因此,Batch size越大,意味着神經網絡訓練的時候所需要的樣本就越多,導緻需要存儲在AI芯片内存變量激增。在許多情況下,沒有足夠的AI加速芯片内存,Batch size設置得太大,就會出現OOM報錯(Out Off Memor)。
使用大Batch size的方法解決AI加速芯片内存限制,并運行大Batch size的一種方法是将數據Sample的Batch拆分為更小的Batch,叫做Mini-Batch。這些小Mini-Batch可以獨立運行,并且在網絡模型訓練的時候,對梯度進行平均或者求和。主要實現的有兩種方式。
1)數據并行:使用多個AI加速芯片并行訓練所有Mini-Batch,每份數據都在單個AI加速芯片上。累積所有Mini-Batch的梯度,結果用于在每個Epoch結束時求和更新網絡參數。
2)梯度累積:按順序執行Mini-Batch,同時對梯度進行累積,累積的結果在最後一個Mini-Batch計算後求平均更新模型變量。
雖然兩種技術都挺像的,解決的問題都是内存無法執行更大的Batch size,但梯度累積可以使用單個AI加速芯片就可以完成啦,而數據并行則需要多塊AI加速芯片,所以手頭上隻有一台12G二手卡的同學們趕緊把梯度累積用起來。
梯度累積原理梯度累積是一種訓練神經網絡的數據Sample樣本按Batch拆分為幾個小Batch的方式,然後按順序計算。
在進一步讨論梯度累積之前,我們來看看神經網絡的計算過程。
深度學習模型由許多相互連接的神經網絡單元所組成,在所有神經網絡層中,樣本數據會不斷向前傳播。在通過所有層後,網絡模型會輸出樣本的預測值,通過損失函數然後計算每個樣本的損失值(誤差)。神經網絡通過反向傳播,去計算損失值相對于模型參數的梯度。最後這些梯度信息用于對網絡模型中的參數進行更新。
優化器用于對網絡模型模型權重參數更新的數學公式。以一個簡單随機梯度下降(SGD)算法為例。
假設Loss Function函數公式為:

在構建模型時,優化器用于計算最小化損失的算法。這裡SGD算法利用Loss函數來更新權重參數公式為:

其中theta是網絡模型中的可訓練參數(權重或偏差),lr是學習率,grad是相對于網絡模型參數的損失。
梯度累積則是隻計算神經網絡模型,但是并不及時更新網絡模型的參數,同時在計算的時候累積計算時候得到的梯度信息,最後統一使用累積的梯度來對參數進行更新。

在不更新模型變量的時候,實際上是把原來的數據Batch分成幾個小的Mini-Batch,每個step中使用的樣本實際上是更小的數據集。
在N個step内不更新變量,使所有Mini-Batch使用相同的模型變量來計算梯度,以确保計算出來得到相同的梯度和權重信息,算法上等價于使用原來沒有切分的Batch size大小一樣。即:

最終在上面步驟中累積梯度會産生與使用全局Batch size大小相同的梯度總和。

當然在實際工程當中,關于調參和算法上有兩點需要注意的:
學習率 learning rate:一定條件下,Batch size越大訓練效果越好,梯度累積則模拟了batch size增大的效果,如果accumulation steps為4,則Batch size增大了4倍,根據ZOMI的經驗,使用梯度累積的時候需要把學習率适當放大。 歸一化 Batch Norm:accumulation steps為4時進行Batch size模拟放大效果,和真實Batch size相比,數據的分布其實并不完全相同,4倍Batch size的BN計算出來的均值和方差與實際數據均值和方差不太相同,因此有些實現中會使用Group Norm來代替Batch Norm。
梯度累積實現正常訓練一個batch的僞代碼:
for i, (images, labels) in enumerate(train_data):
# 1. forwared 前向計算
outputs = model(images)
loss = criterion(outputs, labels)
# 2. backward 反向傳播計算梯度
optimizer.zero_grad()
loss.backward()
optimizer.step()
即在網絡中輸入一個batch的數據,就計算一次梯度,更新一次網絡。
使用梯度累加後:
# 梯度累加參數
accumulation_steps = 4
for i, (images, labels) in enumerate(train_data):
# 1. forwared 前向計算
outputs = model(imgaes)
loss = criterion(outputs, labels)
# 2.1 loss regularization loss正則化
loss = loss / accumulation_steps
# 2.2 backward propagation 反向傳播計算梯度
loss.backward()
# 3. update parameters of net
if ((i 1) % accumulation)==0:
# optimizer the net
optimizer.step()
optimizer.zero_grad() # reset grdient
梯度累積就是,每次獲取1個batch的數據,計算1次梯度,此時梯度不清空,不斷累積,累積一定次數後,根據累積的梯度更新網絡參數,然後清空所有梯度信息,進行下一次循環。
參考文獻更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!