目錄
最近在做NLP相關任務的時候,訓練神經網絡模型的過程中,遇到過模型過擬合的情況,到底怎麼解決過擬合,來提高模型的性能,不是特別的清晰。以前學習機器學習的時候,也講到了模型的過擬合,對裏面怎麼來解決過擬合的方法也有一些模糊的印象,例如正則化、增加數據和集成學習等,對於原理和具體的步驟等細節也記不清楚了。因此很有必要對這一專題做一個總結,加深印象和記憶。當然網上也是有一大堆的相關博客,我寫這篇博客的目的不求做出創新,只求做到全面,對自己以後跳槽有利。
一、過擬合的表現以及判定
1、模型過擬合的表現
過擬合(over-fitting),機器學習模型或者是深度學習模型在訓練樣本中表現得過於優越,導致在驗證數據集以及測試數據集中表現不佳。也就是泛化誤差比較大,泛化能力差。從方差和偏差的角度來說,過擬合也就是訓練集上高方差,低偏差。爲了更加生動形象的表示,我們看一些經典的圖:
對比這幾個圖,發現圖一的擬合並沒有把大體的規律給擬合出來,這個就是欠擬合。圖三則是擬合的太細緻了,用的擬合函數太複雜了,在這些數據集上的效果很好,但是換到另外的一個數據集效果肯定可預見的不好。只有圖二是最好的,把數據的規律擬合出來了,同時在更換數據集後,效果也不會很差。
仔細想想圖片三中的模型,擬合函數肯定是一個高次函數,其參數個數肯定肯定比圖二的要多,可以說圖三的擬合函數比圖二的要大,模型更加複雜。這也是過擬合的一個判斷經驗,模型是否太複雜。另外,針對圖三,我們把一些高次變量對應的參數值變小,也就相當於把模型變簡單了。這個角度上看,可以減小參數值,也就是一般模型過擬合,參數值整體比較大。從模型複雜性來講,可以是:
1、模型的參數個數;2、模型的參數值的大小。個數越多,參數值越大,模型就越複雜。
2、模型過擬合的判定
針對模型過擬合這個問題,有沒有什麼方法來判定模型是否過擬合呢?其實一般都是依靠模型在訓練集和驗證集上的表現有一個大體的判斷就行了。如果要有一個具體的方法,可以參考機器學中,學習曲線來判斷模型是否過擬合。如下圖:
也就是看訓練集合驗證集隨着樣本數量的增加,他們之間的差值變化。如果訓練集和測試集的準確率都很低,那麼說明模型欠擬合;如果訓練集的準確率接近於1而驗證集還相差甚遠,說明模型典型的過擬合。當然具體的差多少這個沒有明確的定義,個人看法是,如果訓練集95%+,而驗證集才60-80直接感覺都是有點過擬合的。
二、過擬合的原因
1、數據量太小
這個是很容易產生過擬合的一個原因。設想,我們有一組數據很好的吻合3次函數的規律,現在我們局部的拿出了很小一部分數據,用機器學習或者深度學習擬合出來的模型很大的可能性就是一個線性函數,在把這個線性函數用在測試集上,效果可想而知肯定很差了。
2、訓練集和驗證集分佈不一致
訓練集訓練出一個適合訓練集那樣分佈的數據集,當你把模型運用到一個不一樣分佈的數據集上,效果肯定大打折扣。這個是顯而易見的。
3、模型複雜度太大
在選擇模型算法的時候,首先就選定了一個複雜度很高的模型,然後數據的規律是很簡單的,複雜的模型反而就不適用了。
4、數據質量很差
數據還有很多噪聲,模型在學習的時候,肯定也會把噪聲規律學習到,從而減小了具有一般性的規律。這個時候模型用來預測肯定效果也不好。
5、過度訓練
這個是同第4個是相聯繫的,只要訓練時間足夠長,那麼模型肯定就會吧一些噪聲隱含的規律學習到,這個時候降低模型的性能是顯而易見的。
三、過擬合的解決方案
針對過擬合的原因我們可以有針對性的來使用一些方法和技巧來減少過擬合。
1、模型層面
這裏主要是減小模型的複雜度,主要是從模型包含的參數個數和參數值。
a、正則化
這裏包含L1和L2範數,具體的區別去看相關的理論去了解,這裏一般使用L1範數,使得模型擬合的參數大部分都爲0,這樣就可以說從參數值和參數個數的角度減少了模型的複雜度,從而降低了過擬合。
b、權值共享
這個方法常用於深度學習中,一般在網絡中,某些層可能會使用同樣的參數,那麼這樣就在參數個數上減小了——模型複雜度也隨之降低
c、dropout
這個方法也很常見,在神經網絡中以一定的概率使得神經元不工作。這種方法的本質上是沒一個step中,使用的模型都是不一樣的,並且模型參數在一定程度上也是減少了。
torch.nn.Dropout(0.5)
在pytorch中,這裏的0.5的意思就是神經元不保留的概率,這個與tf框架不同。
d、Batch Normalization
這個批歸一化處理層,是一個作用非常大的。我自己在寫網絡中也嘗試在使用這個BN層,其作用是:使得每一層的數據分佈不變,做歸一化處理,加快了模型的收斂速度,避免梯度消失、提高準確率。反正就是優點很多!
e、權值衰減
權值衰減——weight_decay,簡單的理解就是乘在正則項的前面的係數,目的是爲了使得權值衰減到很小的值,接近如0。一般在深度學習好中,pytorch的提供的優化器都可以設置的:
optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9,weight_decay=1e-5)
2、數據層面
a、保證數據集分佈一致性
在切分數據集的時候要保證分佈一致性。可以使用sklearn包中,model_selection相關train_text_split來實現數據集切割後分布的一致性。
b、增加數據集的規模
最好的是人工標註高質量的數據,但是成本非常高;可以採用一定的數據增強策略,來實現數據集的擴充。注意的是這裏可能會引入一定的噪聲,噪聲也會影響模型的性能的,要注意利弊的取捨。另外CV和NLP的數據增強是不一樣的,NLP數據增強更難。
3、訓練層面
這個訓練就要看經驗了,模型需要到達什麼樣的一個基線標準。然後參考這個標準對模型實施early-stopping。神經網絡的訓練過程中我們會初始化一組較小的權值參數,隨着模型的訓練,這些權值也變得越來越大了。爲了減小過擬合的影響,就有可能需要早停止了。我本人沒有使用過early-stopping,一般都是設置10個epoch然後看效果來考慮時候增加epochs的次數。
4、其他
集成學習——也就是一個均值的思想,通過集成的思想來減弱過擬合的影響。
參考文章: