摘要: 本文講述了從在fast.ai庫中讀論文,到根據論文複製實驗並作出改進,並將改進後的開源代碼放入fast.ai庫中。react
去年我發現MOOC網上有大量的Keras和TensorKow教學視頻,以後我從零開始學習及參加一些Kaggle比賽,並在二月底得到了fast.ai國際獎學金。去年秋天,當我在全力學習PyTorch時,我在feed中發現了一條關於新論文的推文:「平均權重會產生更普遍的局部優化和更好的泛化。」具體來講,就是我看到一條如何將其添加到fast.ai庫的推文。如今我也參與到這項研究。算法
在一名軟件工程師的職業生涯中,我發現學習一門新技術最好的方法是將它應用到具體的項目。因此我認爲這不只能夠練習提升個人PyTorch能力,還能更好的熟悉fast.ai庫,也能提升我閱讀和理解深度學習論文的能力。網絡
做者發表了使用隨機加權平均(SWA)訓練VGG16和預激活的Resnet-110模型時得到的改進。對於VGG網絡結構,SWA將錯誤率從6.58%下降到6.28%,相對提升了4.5%,而Resnet模型則更明顯,將偏差從4.47%減小到3.85%,相對提升了13.9%。架構
背景併發
隨機加權平均(SWA)方法來自於集成。集成是用於提升機器學習模型性能的流行的技術。例如,ensemble算法得到了Nekix獎,由於Netkix過於複雜不適用於實際生產,而在像Kaggle這樣的競爭平臺上,集成最終性能表現結果能夠遠超單個模型。機器學習
最簡單的方式爲,集成能夠對不一樣初始化的模型的若干副本進行訓練,並將對副本的預測平均以獲得總體的預測。可是這種方法的缺點是必須承擔n個不一樣副本的成本。研究人員提出快照集成(Snapshot Ensembles)方法。改方法是對一個模型進行訓練,並將模型收斂到幾個局部最優勢,保存每一個最優勢的權重。這樣一個單一的訓練就能夠產生n個不一樣的模型,將這些預測平均就能預測出總體。函數
在發表SWA論文以前,做者曾發表過快速幾何集成(FGE)方法的論文,改方法改進了快照集成的結果,FGE方法爲「局部最優能經過近乎恆定損耗的簡單曲線鏈接起來」也就是說,經過FGE做者可以發現損耗曲面中的曲線具備理想的特性,以及經過這些曲線集成模型。性能
在SWA論文中,做者提供了SWA接近FGE的證據。然而,SWA比FGE的好處是推理成本較低 。FGE須要產生n個模型的預測結果,而對於SWA而言,最終只須要一個模型,所以推斷能夠更快。單元測試
SWA算法的工做原理相對簡單。首先製做你正在訓練的模型的副本,以便用於跟蹤平均權重。在完成epoch訓練後,經過如下公式更新副本的權重:學習
其中n_models是已經包含在平均值中的模型數量,w_swa表示副本的權重,w表示正在訓練的模型的權重。這至關於在每一個epoch訓練時期結束時存儲模型的運行平均值。這就是該算法的精髓,但論文還介紹了一些細節,首頁做者制定了具體的學習率計劃,以確保SGD在開始平均模型時就可以找到出最優勢。其次,對網絡進行預訓練以達到開始時就有必定數量的epochs,而不是一開始就追蹤平均值。另外,若是使用週期性學習率,那麼須要在每一個週期結束時存儲平均值,而不是在每一個epoch後。
尋找更普遍的最優勢
SWA的算法的工做方式,做者提供了證據,證實與SGD相比,它能使模型達到更普遍的局部最優,從而可以提升模型的泛化能力,由於訓練損失和測試數據可能不徹底一致。所以,對訓練數據進行更普遍的優化使得模型對測試數據進行優化。
圖三的一部分
由圖可得,訓練損失(左)和測試錯誤(右)類似但不徹底相同。例如,最右邊的X處於訓練損失表面的最佳點,但距離最優測試偏差有必定距離。正是這些差別能更容易的尋找更普遍的最優勢,這更可能成爲訓練和測試損失的最佳點。
做者提出觀點:SWA能夠找到更普遍的最優勢。並在論文Optima Width章節中經過實驗給出了證據,將損失做爲給定方向上的Optima距離的函數,來比較SGD和SWA可以發現的最優勢寬度。做者對10個不一樣的方向進行了採樣,並測量了用SGD和SWA對CIFAR-10進行訓練的Preactivation Resnet的損失,結果以下:
圖4:「測試偏差...做爲隨機射線上的點函數,起始於CIFAR-100上預激活ResNet-110的SWA(藍色)和SGD(綠色)解決方案。」
圖中數據提供了證據,代表SWA發現的optima比SGD所發現的更普遍,由於它與SWA最優的距離比增長一樣數量的測試錯誤的距離更大。例如,要達到50%的測試偏差,你必須從距離SGD的最佳距離爲30,而SGD爲50。
做者進行了大量的實驗來驗證SWA方法在不一樣的數據集和模型架構上的有效性。首先,我將詳細描述爲了實現該算法作的實驗設置,而後講解一些關鍵結果。
使用VGG16和預激活的Resnet-110體系結構在CIFAR-10上進行了複製實驗。每一個體繫結構都有必定的預算,以表示僅使用SGD +動量來訓練模型收斂所需的時間數。VGG預算爲200,而Resnet則爲150。而後,爲了測試SWA,模型用SGD +動力培訓約75%的預算,而後用SWA進行額外的epochs訓練,達到原始預算的一、1.25和1.5倍。對每一個測試訓練了三個模型,並報告平均值和標準誤差。
除了對CIFAR-10的實驗外,做者還對CIFAR-100進行了相似的實驗。他們還在ImageNet上測試了預訓練模型,使用SWA運行了10個epochs,併發如今預訓練的ResNet-50、ResNet152和DenseNet-161的精度提升了。最後,做者經過使用固定學習速率的SWA,成功地從scratch中訓練了一個寬的ResNet-28-10。
閱讀並理解該論文後,我嘗試在fast.ai庫中找出哪一個位置添加代碼可以使SWA正常工做。該位置已經找到了,由於fast.ai庫提供了添加自定義回調的功能。若是我用每一個epoch結束時調用的hook來寫回調,那麼就能在適當的時間更新權重的運行平均值。這是結束的代碼:
82df6b30728983878ba9f2eedc2dd25b1c9bef81
回調採用三個參數:model、swa_model和swa_start。前兩個是咱們正在訓練的模型,以及咱們將用來存儲加權平均的模型副本。swa_start參數是平均開始的時間,由於在論文中,模型老是在開始跟蹤平均權重以前,用SGD+動量對必定數量的epochs進行訓練。
從這裏你能夠看到SWA回調如何將算法從文件轉換成PyTorch代碼。在SWA開始的epoch中,咱們將更新參數的運行平均值,並增長平均值中包含的模型數量。
在SWA模型進行推斷前,咱們還須要用包含代碼修復batchnorm的運算平均值。batchnorm層一般在訓練期間計算這些運行統計數據,但因爲模型的權重是做爲其餘模型的平均值計算的,因此這些運行統計數據對於SWA模型是錯誤的,所以須要再次單次傳遞數據讓batchnorm層計算正確的運行統計數據。修復代碼以下:
標題文字
測試很是重要,可是在機器學習代碼中應用單元測試是很困難的,由於有一些不肯定的因素或者測試的狀態須要較長時間。爲了確保所作工做其實是有效的,我作了兩個測試,一個是「功能」測試,它們是較小的代碼塊,一般運行在比較簡單的模型上,旨在回答:「這個功能是否按照個人想法實現了?」例如,一項功能測試代表,在通過幾個階段的訓練後,SWA模型實際上等於全部SGD模型參數的平均值:
這些測試一般在30秒內就能運行完成,因此在編寫實現代碼遇到問題時能快速提醒我。因爲fast.ai庫的開發速度很是快,這些測試還能在試圖解決master分支合併問題時快速識別問題。
第二個測試爲「實驗」測試。它的目的是回答:「若是我用本身的實現和fast.ai庫從新進行論文中的實驗,我是否能觀察到與論文相同的結果?」每次我實現一個功能就會運行這個測試,以肯定SWA是否對庫作出有用的貢獻。實驗測試要比功能測試花費的時間長,但能確保一切都按預期運行。
最後我能夠複述論文的結果-隨機權重平均確實在CIFAR-10上產生了比通常SGD更高的準確性,而且隨着訓練時期的增長,這種改善一般會增長。正以下表所示,我全部的結果都比原始論文結果更準確。其中一個因素多是數據加強的方式——對於CIFAR-10,經過將每一個圖像填充4個像素並隨機裁剪進行加強,而且我發現fast.ai默認使用不一樣類型的填充(rekection填充)。然而,能夠清楚地看到SWA改善超過SGD +momentum的模式。
原始論文的結果
個人結果
獲取測試代碼請點擊代碼。
我對這個項目的最終結果很是滿意,由於我從最前沿的研究論文中複製了一個實驗,併爲機器學習開源代碼作出了本身的第一個貢獻。我想鼓勵你們下載fast.ai庫,並嘗試一下SWA吧!
數十款阿里雲產品限時折扣中,趕忙點擊領劵開始雲上實踐吧!
本文由阿里云云棲社區組織翻譯。
文章原標題《Adding a cutting-edge deep learning training technique to the fast.ai library》
做者:William Horton
譯者:奧特曼,審校:袁虎。
本文爲雲棲社區原創內容,未經容許不得轉載。