1. 程式人生 > >關於訓練神經網路的諸多技巧Tricks(完全總結版)

關於訓練神經網路的諸多技巧Tricks(完全總結版)

歡迎訪問Oldpan部落格,分享人工智慧有趣訊息,持續醞釀深度學習質量文。

前言

很多人都說訓練神經網路和鍊金術師煉藥的過程相像,難以破解其中的黑盒子。其實不然,在訓練的時候我們依然可以通過大量的技巧去最大化我們的訓練效果,從而幫助我們的任務取得不錯的精度,這些技巧是訓練神經網路不可缺少的一環。

本文儘可能說明訓練過程中所需要的各種小技巧,會有不完善的地方,限於篇幅每個點不會說很細,但是這些觀念是我們都需要掌握的,牢記這幾點,在訓練神經網路的過程中就可以得心應手,讓煉丹不再沒有頭緒~

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

避免overfitting

overfitting即過擬合,典型的表現為訓練集損失遠遠小於驗證集損失。而欠擬合則表現為訓練集損失大於驗
證集損失。

我們要清楚遠遠大於的概念,如果訓練集損失只比驗證集損失多一點點的話,同等數量級(例如0.8與0.9)這種情況下並不是過擬合的表現。我們一般遇到的過擬合應該是0.8(訓練集損失)與2.0(驗證集損失)這種不在一個量級的損失比。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

dropout與overfitting的關係

Dropout類似於bagging ensemble減少variance。也就是投通過投票來減少可變性。通常我們在全連線層部分使用dropout,在卷積層則不使用。但要宣告,dropout並不適合所有的情況,請大家不要無腦上Dropout

Dropout一般適合於全連線層部分,而卷積層由於其引數並不是很多,所以不需要dropout,加上的話對模型的泛化能力並沒有太大的影響。如下圖:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

我們一般在網路的最開始和結束的時候使用全連線層,而hidden layers則是網路中的卷積層。所以一般情況,在全連線層部分,採用較大概率的dropout而在卷積層採用低概率或者不採用dropout。

進一步請看相關討論

資料集是否損壞?

資料集的好壞是演算法泛化好壞的一個非常重要的前提條件,我們通常在構建深度學習的任務中,所得到的資料集一般不會是非常完美的(不論是自己搭建還是利用他人的資料,在資料集量過大的時候,資料集中難免會有影象損壞或者錯誤的個例)。

如果有損壞的影象,如果我們不知情,一般來說,在我們使用程式碼讀取的時候就會報錯,舉個例子:
raise IOError("image file is truncated) "

在Kaggle的一個比賽中就存在這樣的情況,訓練的資料中有10w+的影象資料,但是存在10餘張的影象內容缺失(影象大小明顯小於其他正常影象)或者直接被損壞無法讀取。這個時候就需要我們自己去手動編寫程式碼將那些錯誤且無法參與訓練的影象挑選出來。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

那麼如果正確過濾這些影象呢?

  • 找到損壞影象的特點,例如無法讀取,編寫程式去除無法讀取的影象
  • 找到內容缺失的影象,這樣的影象大小往往比普通影象小一些,通過過濾檔案大小小於某一閾值去除

當然,資料集損壞的形式還有很多,需要我們自己去發掘。在一開始得到資料集的時候最好不要直接開始訓練,應該去仔細檢查自己的資料集是否有問題,這樣可以避免很多之後訓練時需要的處理的麻煩。

難例挖掘 hard-negative-mining

在任何一個深度學習任務中,我們都會遇到一些比較“棘手”的資料,這些資料相比較於其他的普通資料更難識別,這種特比容易識別錯誤的例子就稱為hard-negative

舉個栗子。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

比如Kaggle比賽中的一個識別遙感影象中船隻的任務,使用的影象集是從一張大的遙感圖中裁剪出來的,每張圖的大小為768*768,在簡單地對影象進行分類時(僅僅分類影象中有無船隻),在validation中發現最容易識別出錯的圖如下:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

在觀察到這些最難辦的影象的特徵後,我們可以針對這些難辦的影象採取一些方法來解決這些問題。我們先用初始的正負樣本(一般是正樣本+與正樣本同規模的負樣本的一個子集)訓練分類器, 然後再用訓練出的分類器對樣本進行分類, 把其中負樣本中錯誤分類的那些樣本(hard negative)放入負樣本集合, 再繼續訓練分類器, 如此反覆, 直到達到停止條件(比如分類器效能不再提升)。也就是不停滴將困難樣本拿去訓練,讓分類器更好地學習到難以學習的特徵,簡單來說就是熟能生巧嘛。

而在fast-rcnn中,這個方法也被使用了:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

在 Fast-RCNN 中將與 groud-truth 的 IoU 在 [0.1, 0.5) 之間的影象標記為負例,[0, 0.1)的example 用於hard negative mining.在訓練時一般輸入為N=2張圖片, 選擇128個RoI,即每張圖片64個RoI。對於每張圖片, 按照1:3的比例來抽取RoI, 抽取正負樣本的比例為1:3,要在負例中抽取48個。

相關的兩篇文章可以看一下

[17] P. Felzenszwalb, R. Girshick, D. McAllester, and D. Ramanan. Object detection with discriminatively trained part based models. TPAMI, 2010.
[37] K. Sung and T. Poggio. Example-based learning for viewbased human face detection. Technical Report A.I. Memo No. 1521, Massachussets Institute of Technology, 1994.
複製程式碼

關於學習率

尋找合適的學習率(learning rate)

學習率是一個非常非常重要的超引數,這個引數呢,面對不同規模、不同batch-size、不同優化方式、不同資料集,其最合適的值都是不確定的,我們無法光憑經驗來準確地確定lr的值,我們唯一可以做的,就是在訓練中不斷尋找最合適當前狀態的學習率。

比如下圖利用fastai中的lr_find()函式尋找合適的學習率,根據下方的學習率-損失曲線得到此時合適的學習率為1e-2

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

如果想要了解更多,這裡推薦一篇fastai首席設計師Sylvain Gugger的一篇部落格:How Do You Find A Good Learning Rate
以及相關的論文Cyclical Learning Rates for Training Neural Networks

learning-rate與batch-size的關係

一般來說,越大的batch-size使用越大的學習率。

原理很簡單,越大的batch-size意味著我們學習的時候,收斂方向的confidence越大,我們前進的方向更加堅定,而小的batch-size則顯得比較雜亂,毫無規律性,因為相比批次大的時候,批次小的情況下無法照顧到更多的情況,所以需要小的學習率來保證不至於出錯。

可以看下圖損失Loss學習率Lr的關係:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》
《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

上圖來源於這篇文章:Visualizing Learning rate vs Batch size

當然我們也可以從上圖中看出,當batchsize變大後,得到好的測試結果所能允許的lr範圍在變小,也就是說,當batchsize很小時,比較容易找打一個合適的lr達到不錯的結果,當batchsize變大後,可能需要精細地找一個合適的lr才能達到較好的結果,這也給實際的large batch分散式訓練帶來了困難。

所以說,在視訊記憶體足夠的條件下,最好採用較大的batch-size進行訓練,找到合適的學習率後,可以加快收斂速度。另外,較大的batch-size可以避免batch normalization出現的一些小問題:github.com/pytorch/pyt…

更多類似的問題可以在知乎找到相關答案:www.zhihu.com/question/64…

差分學習率與遷移學習

首先說下遷移學習,遷移學習是一種很常見的深度學習技巧,我們利用很多預訓練的經典模型直接去訓練我們自己的任務。雖然說領域不同,但是在學習權重的廣度方面,兩個任務之間還是有聯絡的。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

由上圖,我們拿來model A訓練好的模型權重去訓練我們自己的模型權重(Model B),其中,modelA可能是ImageNet的預訓練權重,而ModelB則是我們自己想要用來識別貓和狗的預訓練權重。

那麼差分學習率和遷移學習有什麼關係呢?我們直接拿來其他任務的訓練權重,在進行optimize的時候,如何選擇適當的學習率是一個很重要的問題。

一般地,我們設計的神經網路(如下圖)一般分為三個部分,輸入層,隱含層和輸出層,隨著層數的增加,神經網路學習到的特徵越抽象。因此,下圖中的卷積層和全連線層的學習率也應該設定的不一樣,一般來說,卷積層設定的學習率應該更低一些,而全連線層的學習率可以適當提高。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

這就是差分學習率的意思,在不同的層設定不同的學習率,可以提高神經網路的訓練效果,具體的介紹可以檢視下方的連線。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

上面的示例圖來自:towardsdatascience.com/transfer-le…

餘弦退火(cosine annealing)和熱重啟的隨機梯度下降

餘弦就是類似於餘弦函式的曲線,退火就是下降,餘弦退火就是學習率類似餘弦函式慢慢下降。

熱重啟就是在學習的過程中,學習率慢慢下降然後突然再回彈(重啟)然後繼續慢慢下降。

兩個結合起來就是下方的學習率變化圖:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

更多詳細的介紹可以檢視知乎機器學習演算法如何調參?這裡有一份神經網路學習速率設定指南
以及相關論文SGDR: Stochastic Gradient Descent with Warm Restarts

權重初始化

權重初始化相比於其他的trick來說在平常使用並不是很頻繁。

為什麼呢?

原因很簡單,因為大部分人使用的模型都是預訓練模型,使用的權重都是在大型資料集上訓練好的模型,當然不需要自己去初始化權重了。只有沒有預訓練模型的領域會自己初始化權重,或者在模型中去初始化神經網路最後那幾個全連線層的權重。

那麼大家喜歡用什麼初始化權重演算法?

當然是kaiming_normal或者xavier_normal

相關論文:
Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification
Understanding the difficulty of training deep feedforward neural networks

多尺度訓練

多尺度訓練是一種直接有效的方法,通過輸入不同尺度的影象資料集,因為神經網路卷積池化的特殊性,這樣可以讓神經網路充分地學習不同解析度下影象的特徵,可以提高機器學習的效能。

也可以用來處理過擬合效應,在影象資料集不是特別充足的情況下,可以先訓練小尺寸影象,然後增大尺寸並再次訓練相同模型,這樣的思想在Yolo-v2的論文中也提到過:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

需要注意的是:多尺度訓練並不是適合所有的深度學習應用,多尺度訓練可以算是特殊的資料增強方法,在影象大小這一塊做了調整。如果有可能最好利用視覺化程式碼將多尺度後的影象近距離觀察一下,看看多尺度會對影象的整體資訊有沒有影響,如果對影象資訊有影響的話,這樣直接訓練的話會誤導演算法導致得不到應有的結果。

關於優化演算法

按理說不同的優化演算法適合於不同的任務,不過我們大多數採用的優化演算法還是是adamSGD+monmentum

這兩個為什麼好用?

經驗唄~

嘗試過擬合一個小資料集。

這是一個經典的小trick了,但是很多人並不這樣做,可以嘗試一下。

關閉正則化/隨機失活/資料擴充,使用訓練集的一小部分,讓神經網路訓練幾個週期。確保可以實現零損失,如果沒有,那麼很可能什麼地方出錯了。

Cross Validation 交叉驗證

在李航的統計學方法中說到,交叉驗證往往是對實際應用中資料不充足而採用的,基本目的就是重複使用資料。在平常中我們將所有的資料分為訓練集和驗證集就已經是簡單的交叉驗證了,可以稱為1折交叉驗證。注意,交叉驗證和測試集沒關係,測試集是用來衡量我們的演算法標準的,不參與到交叉驗證中來。

交叉驗證只針對訓練集和驗證集。

交叉驗證是Kaggle比賽中特別推崇的一種技巧,我們經常使用的是5-折(5-fold)交叉驗證,將訓練集分成5份,隨機挑一份做驗證集其餘為訓練集,迴圈5次,這種比較常見計算量也不是很大。還有一種叫做leave-one-out cross validation留一交叉驗證,這種交叉驗證就是n-折交叉,n表示資料集的容量,這種方法只適合資料量比較小的情況,計算量非常大的情況很少用到這種方法。

吳恩達有一節課The nuts and bolts of building applications using deep learning中也提到了。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

關於資料集

如果資料集極其不平衡,假如我們有個檢測船隻的任務,在100000圖中只有30000張圖中含有船隻,其餘影象都是不含船隻的影象,這時候如果對此直接進行訓練效果應該會很差。為此,首先可以挑選出只有船隻的影象集合進行初步訓練。其次,使用訓練好的模型去檢測沒有訓練的部分(不含船隻),挑選出檢測失敗的false positive(也就是在沒有船的影象集中檢測出船隻了)加入之前的訓練集再次進行訓練。

資料增強

資料集增強是一個老生常談的話題了,我們為什麼需要那麼多資料?為什麼需要資料增強技術?
可以看這篇文章來了解一下:深度學習為什麼需要那麼多的資料?

這裡只簡單說下我們常用的資料增強的Transform
大部分我們使用的影象增強技術一般是隨機旋轉,水平翻轉,高斯模糊和尺度變化還有什麼拉伸等blabla的操作。這些影象變化對大部分的任務是比較適合的,但針對特定的任務,存在某一簇特殊的影象增強技術可以達到比普通影象增強技術更好的效果。

例如夜檢視或者光照:

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

但也需要提個醒,並不是所有的影象增強都可以提升模型的泛化能力

而且有些影象增強技術會對原始影象造成損失從而導致神經網路學習到錯誤的資訊,這點是我們比較容易忽視的問題,同樣重要,相關內容可以檢視fastai中的影象增強技術為什麼相對比較好

TTA(Test Time Augmentation)

最初這個概念是在fastai課程中看到的,這個過程在訓練階段不會參與,是通過在驗證和測試階段進行的。具體過程是,對所要處理的影象進行幾種隨機的影象增強變化,然後對每種影象增強後的影象進行預測,對預測結果取平均值。

原理類似於模型平均,犧牲推斷速度來實現推斷精度的提升。

《關於訓練神經網路的諸多技巧Tricks(完全總結版)》

當然,這個技術也有好有壞,在我自己跑的衛星圖資料集中採用TTA的精確度比不採用低了0.03個百分點。

結語

大概先說這麼多,訓練神經網路真的很像煉丹,而我們所有使用的技巧tricks,也只是增加一些煉丹的成功率,而究竟煉丹能不能成功,最終還是要取決於我們設計的演算法合不合理。

參考文章:

www.cnblogs.com/nowgood/p/H…
towardsdatascience.com/kaggle-plan…

文章來源於OLDPAN部落格,歡迎來訪:Oldpan部落格

歡迎關注Oldpan部落格公眾號,持續醞釀深度學習質量文: