L2正則是一種減少過拟合的一種經典方法,它在損失函數中加入對模型所有權重的平方和,乘以給定的超參數(本文中的所有方程都使用python,numpy,和pytorch表示):
final_loss = loss + wd * all_weights.pow(2).sum() / 2
...其中wd是要設定的l2正則的超參數。這也稱為weight decay,因為在應用普通的SGD時,它相當于采用如下所示來更新權重:
w = w - lr * w.grad - lr * wd * w
(注意,w 2相對于w的導數是2w。)在這個等式中,我們看到我們如何在每一步中減去一小部分權重,是以成為衰減。
我們檢視過的所有深度學習庫,都使用了第一種形式。(實際上,它幾乎總是通過向gradients中添加wd * w來實作,而不是去改變損失函數:我們不希望在有更簡單的方法時,通過修改損失來增加更多計算量。)
那麼為什麼要區分這兩個概念,它們是否起到了相同的作用呢?答案是,它們對于vanilla SGD來說是一樣的東西,但隻要我們在公式中增加動量項,或者使用像Adam這樣更複雜的一階或二階的optimizer,L2正則化(第一個等式)和權重衰減(第二個等式)就會變得不同。在本文的其餘部分,當我們談論weight decay時,我們将始終參考第二個公式(梯度更新時,稍微減輕權重)并談談L2正則化,如果我們想提一下經典的方法。
以SGD + momentum為例。使用L2正則化,并添加wd * w衰減項到公式中(如前所述),但不直接從權重中減去梯度。首先我們計算移動平均值(moving average):
moving_avg = alpha * moving_avg + (1-alpha) * (w.grad + wd*w)
...這個移動平均值将乘以學習率并從w中減去。是以,與将從w取得的正則化相關聯的部分是lr *(1-alpha)* wd * w加上前一步的moving_avg值。
另一方面,weight decay的梯度更新如下式:
moving_avg = alpha * moving_avg + (1-alpha) * w.grad w = w - lr * moving_avg - lr * wd * w
我們可以看到,從與正則化相關聯的w中減去的部分在兩種方法中是不同的。當使用Adam optimizer時,它會變得更加不同:在L2正則化的情況下,我們将這個wd * w添加到gradients,然後計算gradients及其平方值的移動平均值,然後再使用它們進行梯度更新。而weight decay的方法隻是在進行更新,然後減去每個權重。
顯然,這是兩種不同的方法。在嘗試了這個之後,Ilya Loshchilov和Frank Hutter在他們的文章中建議我們應該使用Adam的權重衰減,而不是經典深度學習庫實作的L2正則化方法。
1.2 實作AdamW
我們應該怎麼做?基于fastai庫為例,具體來說,如果使用fit函數,隻需添加參數 use_wd_sched = True:
learn.fit(lr, 1, wds=1e-4, use_wd_sched=
True)
如果您更喜歡新的API,則可以在每個訓練階段使用參數wd_loss = False(計算損失函數時,不使用weight decay):
phases = [TrainingPhase(1, optim.Adam, lr, wds=1-e4, wd_loss=False)]
learn.fit_opt_sched(phases)
以下給出基于fast庫的一個簡單實作。在optimizer的step函數的内部,隻使用gradients來更新參數,根本不使用參數本身的值(除了weight decay,但我們将在外圍處理)。然後我們可以在optimizer處理之前,簡單地執行權重衰減。在計算梯度之後仍然必須進行相同操作(否則會影響gradients值),是以在訓練循環中,你必須找到這個位置。
loss.backward()
#Do the weight decay here!
optimizer.step()
當然,optimizer應該設定為wd = 0,否則它會進行L2正則化,這正是我們現在不想要的。現在,在那個位置,我們必須循環所有參數,并做weight decay更新。你的參數應該都在optimizer的字典param_groups中,是以循環看起來像這樣:
loss.backward()
for group in optimizer.param_groups():
for param in group['params']:
param.data = param.data.add(-wd * group['lr'], param.data)
optimizer.step()
1.3 AdamW實驗的結果:它有效嗎?
我們在計算機視覺問題上第一次進行測試得到的結果非常令人驚訝。具體來說,我們采用Adam+L2正規化在30個epochs内獲得的準确率(這是SGD通過去1 cycle policy達到94%準确度所需要的必要時間)的平均為93.96%,其中一半超過了94%。使用Adam + weight decay則達到94%和94.25%之間。為此,我們發現使用1 cycle policy時,beta2的最佳值為0.99。我們将beta1參數視為SGD的動量(意味着它随着學習率的增長從0.95變為0.85,然後當學習率變低時再回到0.95)。

L2正則化或權重衰減的準确性
更令人印象深刻的是,使用Test Time Augmentation(即對測試集上的一個圖像,取四個和他相同data-augmented版本的預測的平均值作為最終預測結果),我們可以在18個epochs内達到94%的準确率(平均預測值為93.98%) )!通過簡單的Adam和L2正規,超過20個epochs時,達到94%。
在這些比較中要考慮的一件事是,改變我們正則的方式會改變weight decay或學習率的最佳值。在我們進行的測試中,L2正則化的最佳學習率是1e-6(最大學習率為1e-3),而0.3是weight decay的最佳值(學習率為3e-3)。在我們的所有測試中,數量級的差異非常一緻,主要原因是,L2正則于梯度的平均範數(相當小)相除後,變得非常有效,且Adam使用的學習速率非常小(是以,weight decay的更新需要更強的系數)。
那麼,使用Adam時,權重衰減總是比L2正規化更好嗎?我們還沒有發現一個明顯更糟的情況,但對于遷移學習問題或RNN而言(例如在Stanford cars資料集上對Resnet50進行微調),它沒有獲得更好的結果。