最優化方法一直是機器學習中非常重要的部分,也是學習過程的核心算法。而 Adam 自 14 年提出以來就受到廣泛關注,目前該論文的引用量已經達到了 10047。不過自去年以來,很多研究者發現 Adam 優化算法的收斂性得不到保證,ICLR 2017 的最佳論文也重點關注它的收斂性。在本文中,作者發現大多數深度學習庫的 Adam 實現都有一些問題,並在 fastai 庫中實現了一種新型 AdamW 算法。根據一些實驗,作者表示該算法是目前訓練神經網絡最快的方式。
Adam 過山車
Adam 優化器之旅可以說是過山車(roller-coaster)式的。該優化器於 2014 年推出,本質上是一個出於直覺的簡單想法:既然我們明確地知道某些參數需要移動得更快、更遠,那麼爲什麼每個參數還要遵循相同的學習率?因爲最近梯度的平方告訴我們每一個權重可以得到多少信號,所以我們可以除以這個,以確保即使是最遲鈍的權重也有機會發光。Adam 接受了這個想法,在過程中加入了標準方法,就這樣產生了 Adam 優化器(稍加調整以避免早期批次出現偏差)!
首次發表之時,深度學習社區都爲來自原論文的一些圖表(如下圖)興奮不已:
Adam 和其他優化器的對比
訓練速度提高 200%!「總體來看,我們發現 Adam 非常魯棒,而且廣泛適用於機器學習領域的各種非凸優化問題」論文結尾這樣寫道。那是三年前,深度學習的黃金時期。然而,事情並沒有按照我們期望的方向發展。使用 Adam 訓練模型的研究文章少之又少,新的研究開始明顯地抑制了它的應用,並在幾個實驗中表明,SGD+momentum 可能比複雜的 Adam 表現更好。2018 fast.ai 課程開課之際,可憐的 Adam 被從早期課程中刪除。
但是到了 2017 年末,Adam 似乎又重獲新生。Ilya Loshchilov 和 Frank Hutter 在他們的論文《Fixing Weight Decay Regularization in Adam》中指出,每個庫在 Adam 上實施的權重衰減似乎都是錯誤的,並提出了一種簡單的方法(他們稱之爲 AdamW)來修復它。儘管結果略有不同,但他們確實給出了一些類似下圖的令人鼓舞的圖表:
Adam 和 AdamW 對比
我們希望人們恢復對 Adam 的熱情,因爲該優化器的一些早期結果似乎可以復現。但事與願違。實際上,應用它的唯一一個深度學習框架就是使用 Sylvain 編碼的 fastai。由於缺乏可用的廣泛框架,日常實踐者就只能固守又舊又不好用的 Adam。
但這不是唯一的問題。前面還有很多阻礙。兩篇論文指出了 Adam 在收斂性證明方面的明顯問題,儘管其中一篇提出了名爲 AMSGrad 的修正(並在享有盛譽的 ICLR 大會上贏得了「最佳論文」獎)。但是,如果說我們從這種最戲劇化的生活(至少按照優化器的標準來說是戲劇化的)簡史中學到了什麼,那就是,沒有什麼是它表面看起來的樣子。的確,博士生 Jeremy Bernstein 指出,所謂的收斂問題其實只是選擇不當的超參數的跡象,也許 AMSGrad 也解決不了問題。另一名博士生 Filip Korzeniowski 展示了一些早期成果,似乎支持了 AMSGrad 這種令人沮喪的觀點。
啓動過山車
那麼我們這些只希望快速訓練精確模型的人該做些什麼呢?我們選擇用數百年來解決科學辯論的方式——科學實驗——來解決這一爭議!稍後將呈現所有細節,但首先讓我們來看一下大致結果:
適當調參之後,Adam 真的可以用!我們在以下幾個任務中得到了訓練時間方面的最新結果:
在含有測試時間增加的僅僅 18 個 epoch 或 30 個 epoch 上訓練 CIFAR10,直到其準確率超過 94%,如 DAWNBench 競賽;
對 Resnet50 進行調參,直至其在斯坦福汽車數據集上的準確率達到 90%,只需訓練 60 個 epoch(之前達到相同的準確率需要 600 個 epoch);
從零開始訓練一個 AWD LSTM or QRNN,歷經 90 個 epoch(或在一個 GPU 上訓練 1 個半小時),其困惑度在 Wikitext-2 上達到當前最優水平(之前的 LSTM 需要 750 個 epoch,QRNN 需要 500 個 epoch)。
這意味着我們已經看到使用 Adam 的超收斂!超收斂是訓練學習率高的神經網絡時出現的一種現象,它表示節省了一半訓練過程。在 AdamW 之前,訓練 CIFAR10 至 94 % 的準確率需要大約 100 個 epoch。
與之前的工作相比,我們發現只要調整得當,Adam 在我們嘗試過的每一個 CNN 圖像問題上都可以獲得與 SGD+Momentum 一樣好的準確率,而且幾乎總是快一點。
關於 AMSGrad 是一個糟糕的「解決方案」的建議是正確的。我們一直髮現,AMSGrad 在準確率(或其他相關指標)上沒有獲得比普通 Adam / AdamW 更高的增益。
當你聽到人們說 Adam 的泛化性能不如 SGD+Momentum 時,你基本上總會發現他們爲自己的模型所選擇的超參數不咋地。通常 Adam 需要的正則化比 SGD 多,因此在從 SGD 轉向 Adam 時,確保調整正則化超參數。
文章結構:
1. AdamW
理解 AdamW
實現 AdamW
AdamW 實驗和 AdamW-ish
2. AMSGrad
理解 AMSGrad
實現 AMSGrad
AMSGrad 實驗的結果
3. 完整結果圖表
AdamW
理解 AdanW:權重衰減與 L2 正則化
L2 正則化是減少過擬合的經典方法,它會向損失函數添加由模型所有權重的平方和組成的懲罰項,並乘上特定的超參數以控制懲罰力度。以下本文所有的方程式都是用 Python、NumPy 和 PyTorch 風格的表達方式:
final_loss = loss + wd * all_weights.pow(2).sum() / 2
其中 wd 爲我們設置的超參數,用以控制懲罰力度。這也可以稱爲權重衰減,因爲每一次運用原版 SGD 時,它都等價於使用如下方程式更新權重:
w = w - lr * w.grad - lr * wd * w
其中 lr 表示學習率、w.grad 表示損失函數對 w 的導數,而後面的 wd * w 則表示懲罰項對 w 的求導結果。在這個等式中,我們會看到每一次更新都會減去一小部分權重,這也就是「衰減」的來源。
fast.ai 查看過的所有庫都使用第一種形式。在實踐中,幾乎都是通過向梯度 wd*w 而實現算法,而不是真正地改變損失函數。因爲我們並不希望增加額外的計算量來修正損失,尤其是還有其它簡單方法的時候。
既然它們是同一種表達,那麼我們爲什麼需要區分這兩種概念呢?原因在於它們只對於原版 SGD 是等價的,而當我們添加動量或使用如 Adam 那樣複雜的最優化方法,L2 正則化(第一個方程)和權重衰減(第二個方程)就會存在很大的不同。在本文其餘的部分中,我們討論權重衰減指的都是第二個方程式,而討論 L2 正則化都是討論第一個經典方式。
如下在帶動量的 SGD 中,L2 正則化與權重衰減是不等價的。L2 正則化會將 wd*w 添加到梯度中,但現在權重並不是直接減去梯度。首先我們需要計算移動均值:
moving_avg = alpha * moving_avg + (1-alpha) * (w.grad + wd*w)
然後權重才能通過減去乘上了學習率的移動均值而得到更新。所以 w 更新中涉及到的正則化爲 lr* (1-alpha)*wd * w 加上已經在 moving_avg 中前面權重的組合。
因此,權重衰減的更新方式可以表示爲:
moving_avg = alpha * moving_avg + (1-alpha) * w.grad w = w - lr * moving_avg - lr * wd * w
我們可以觀察到,從 w 中減去有關正則化的部分在兩種方法中是不同的。當我們使用 Adam 優化器時,權重衰減的部分可能相差更大。因爲 Adam 中的 L2 正則化需要添加 wd*w 到梯度中,並分別計算梯度及其平方的移動均值,然後再能更新權重。然而權重衰減方法只是簡單地更新權重,並每次從權重中減去一點。
顯然這是兩種不同的方法,在進行了實驗後,Ilya Loshchilov 和 Frank Hutter 建議我們應該在 Adam 算法中使用權重衰減方法,而不是像經典深度學習庫中實現的 L2 正則化。
實現 AdamW
那麼我們要如何才能實現 AdamW 算法呢?如果你們在使用 fastai 的庫,那麼在使用 fit 函數時添加參數 use_wd_sched=True 就能簡單地實現:
learn.fit(lr, 1, wds=1e-4, use_wd_sched=True)
如果你更喜歡新的訓練 API,你就能在每一個訓練階段中使用參數 wd_loss=False:
phases = [TrainingPhase(1, optim.Adam, lr, wds=1-e4, wd_loss=False)]learn.fit_opt_sched(phases)
以下簡要地概述了 fastai 是如何實現 AdamW 的。在優化器中的階梯函數,我們只需要使用梯度修正參數,根本不使用參數本身的值(除了權重衰減,我們將在外部處理它)。然後我們可以在最優化器之前通簡單的實現權重衰減,但這仍需要在計算梯度後才能完成,否則它就會影響梯度的值。所以在訓練循環中,我們必須確定計算權重衰減的位置。
loss.backward()#Do the weight decay here!optimizer.step()
當然,最優化器應該設定 wd=0,否則它還會做一些 L2 正則化,這也是我們不希望看到的。現在在權重衰減的位置中,我們可以在所有參數上寫一個循環語句,並依次採用權重衰減的更新。而我們的參數應該存儲在優化器的字典 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()
AdamW 實驗的結果:它真的能行嗎?
我們首先在計算機視覺問題上進行測試,效果非常好。具體來說,Adam 和 L2 正則化在 30 個 epoch 中獲得的平均準確率爲 93.96%,在兩次中有一次超過 94%。我們選擇 30 個 epoch 是因爲通過 1cycle 策略和 SGD 可以獲得 94% 準確率。當我們使用 Adam 與權重衰減方法,我們持續獲得 94% 到 94.25% 的準確率。爲此,我們發現使用 1cycle 策略時的最優 beta2 值爲 0.99。我們將 beta1 參數視爲 SGD 中的動量,這也就意味着它學習率的增長由 0.95 降低到 0.85,然後隨學習率的降低而又增加到 0.95。
L2 正則化或權重衰減準確率
更令人印象深刻的是,使用測試時間增加(即在測試集的一個圖像和它四個增加數據的版本上取預測的平均值),我們可以在僅僅 18 個 epoch 內達到 94 % 的準確率(平均 93.98 %)!通過簡單的 Adam 和 L2 正則化,每嘗試 20 次就會出現一次超過 94 % 的情況。
在這些比較中需要考慮的一點是,改變正則化方式會改變權重衰減或學習率的最佳值。在我們進行的測試中,L2 正則化的最佳學習率爲 1e-6(最大學習率爲 1e-3),而權重衰減的最佳值爲 0.3(學習率爲 3e-3)。在我們的所有測試中,數量級的差異都是非常一致的,主要是因爲 L2 正則化被梯度的平均範數(相當低)有效地劃分,並且 Adam 的學習率相當小(所以權重衰減的更新需要更強的係數)。
那麼,權重衰減總是比 Adam 的 L2 正則化更好?我們還沒有發現明顯更糟的情況,但無論是遷移學習問題(例如斯坦福汽車數據集上 Resnet50 的微調)還是 RNNs,它都沒有給出更好的結果。
AMSGrad
理解 AMSGrad
AMSGrad 是由 Sashank J. Reddi、Satyen Kale 和 Sanjiv Kumar 在近期的一篇文章中介紹的。通過分析 Adam 優化器收斂的證明,他們在更新規則中發現了一個錯誤,該錯誤可能導致算法收斂到次優點。他們設計了理論實驗,展示 Adam 失敗的情形,並提出了一個簡單的解決方案。機器之心也曾從適應性學習率算法出發分析過這一篇最佳論文:Beyond Adam。
爲了更好地理解錯誤和解決方案,讓我們來看一下 Adam 的更新規則:
avg_grads = beta1 * avg_grads + (1-beta1) * w.gradavg_squared = beta2 * (avg_squared) + (1-beta2) * (w.grad ** 2)w = w - lr * avg_grads / sqrt(avg_squared)
我們剛剛跳過了偏差校正(對訓練的開始很有用),把重心放在了主要點上。作者發現 Adam 收斂證明中的錯誤之處在於:
lr / sqrt(avg_squared)
這是我們朝着平均梯度方向邁出的一步,在訓練中逐漸減少。由於學習率常常是恆定或遞減的,作者提出的解決方案是通過添加另一個變量來跟蹤它們的最大值,從而迫使 avg _ square 量增加。
實現 AMSGrad
相關文章在 ICLR 2018 中獲得了一項大獎並廣受歡迎,而且它已經在兩個主要的深度學習庫——PyTorch 和 Keras 中實現。所以,我們只需傳入參數 amsgrad = True 即可。
avg_grads = beta1 * avg_grads + (1-beta1) * w.gradavg_squared = beta2 * (avg_squared) + (1-beta2) * (w.grad ** 2)max_squared = max(avg_squared, max_squared)w = w - lr * avg_grads / sqrt(max_squared)
AMSGrad 實驗結果:大量噪音都是沒用的
AMSGrad 的結果令人非常失望。在所有實驗中,我們都發現它沒有絲毫幫助。即使 AMSGrad 發現的最小值有時比 Adam 達到的最小值稍低(在損失方面),其度量(準確率、f_1 分數…)最終總是更糟(詳見引言中的表格)。
Adam 優化器在深度學習中收斂的證明(因爲它針對凸問題)和他們在其中發現的錯誤對於與現實問題無關的合成實驗很重要。實際測試表明,當這些 avg _ square 梯度想要減小時,這麼做能得到最好的結果。
這表明,即使把重點放在理論上有助於獲得一些新想法,也沒有什麼可以取代實驗(而且很多實驗!)以確保這些想法實際上有助於從業人員訓練更好的模型。
附錄:所有結果
從零開始訓練 CIFAR10(模型是 Wide-ResNet-22,以下爲五個模型的平均結果):
使用 fastai 庫引入的標準頭對斯坦福汽車數據集上的 Resnet 50 進行微調(解凍前對頭訓練 20 個 epoch,並用不同的學習率訓練 40 個 epoch):
使用來自 GitHub(https://github.com/salesforce/awd-lstm-lm)的超參數訓練 AWD LSTM(結果顯示在有或沒有緩存指針(cache pointer)情況下驗證/測試集的困惑度):
使用來自 GitHub repo 的超參數訓練 QRNN(結果顯示在有或沒有緩存指針情況下驗證/測試集的困惑度):
針對這一具體任務,我們採用了 1cycle 策略的修改版本,加快了學習速度,之後長時間保持較高的恆定學習速度,然後再往下降。
Adam 和其它優化器之間的對比
所有相關超參數的值以及用於產生這些結果的代碼地址如下:https://github.com/sgugger/Adam-experiments
原文鏈接:http://www.fast.ai/2018/07/02/adam-weight-decay/