什么是過擬合
所謂過擬合(over-fitting)其實就是所建的機器學習模型或者是深度學習模型在訓練樣本中表現得過於優越,導致在驗證數據集以及測試數據集中表現不佳。
舉個例子:
現在我訓練一個模型來識別狗狗,訓練的數據恰好全是二哈的圖片,結果多次迭代后把二哈的全部特點都識別成狗狗特有的了(比如二哈的顏色、和愛拆家的特點等)。這樣如果我去識別一只金毛的時候則無法識別。這就是過擬合。 簡單的一句話就是機器模型學到了太多不該學到的特點。
過擬合的原因
- 使用的模型比較復雜
- 有噪聲存在
- 數據量有限
過擬合的危害
- 過擬合的模型可以看成是一種完全記憶式的模型,這種模型是無用的,因為它不能被一般化。
- 過擬合也可以看成一個過度復雜的模型,這種模型很容易去利用那些看似正確實則無用的(spurious)關系,這往往會誤導最終的判斷。
keras過擬合相關解決辦法
1.縮小神經網絡的規模
防止過擬合最簡單的方法是縮小模型的規模:模型中的可學習的參數數量(由層數和每層節點數決定)。 在深度學習中,模型中參數的數量通常被稱為模型的能力。 直觀地說,擁有更多參數的模型具有更強的記憶能力,甚至可以可以輕松地學習訓練樣本與其目標之間的類似字典的完美對應關系 –一種沒有任何泛化能力的對應。但是這樣的模型對於分類新的數字樣本卻沒用,新的樣本無法在這個“字典”找到它對應的類別。 一定要記住這一點:深度學習模型傾向於適應訓練數據,但真正的挑戰是泛化,而不是只對訓練集樣本適用就OK。
另一方面,如果網絡的記憶資源有限(即參數較少),就不能輕易學習這種映射;因此,為了最小化損失,它必須要壓縮信息 – 保留最有用的信息。因此,請記住,模型應該有足夠的參數。不幸的是,沒有一個公式可以用來確定神經網絡正確的層數和層數所含的正確的節點數。我們必須評估一系列不同的網絡架構(當然,在我們的驗證集上,而不是我們的測試集上),以便為我們的數據找到合適的模型。找到合適的模型大小的一般過程是從相對較少的隱藏層和節點開始,逐漸增加隱藏層的節點數或添加新的層,直到看到驗證集損失下降。
讓我們在電影評論分類網絡上試試這個。原來的網絡是下面顯示的:
from keras import models
from keras import layers
original_model = models.Sequential()
original_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
original_model.add(layers.Dense(16, activation='relu'))
original_model.add(layers.Dense(1, activation='sigmoid'))
original_model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['acc'])
讓我們嘗試用這個更小的網絡:
model = models.Sequential()
model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
圖1.1顯示了原始網絡和較小網絡的驗證損失的比較。點是較小網絡的驗證損失值,十字是原來較大的網絡(記住,驗證集損失越小表示模型越好)。
圖1.1模型大小對驗證集損失的影響:嘗試一個更小的模型
正如你所看到的,較小的網絡在六個epoch而不是三個epoch之后才出現了過擬合。並且從過擬合開始,其性能變差得也更慢些。
現在,為了對比,讓我們使用一個規模更大的網絡 – 遠遠超過了問題的需求:
bigger_model = models.Sequential()
bigger_model.add(layers.Dense(512, activation='relu', input_shape=(10000,)))
bigger_model.add(layers.Dense(512, activation='relu'))
bigger_model.add(layers.Dense(1, activation='sigmoid'))
bigger_model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['acc'])
圖1.2模型大小對驗證集損失的影響:嘗試一個更大的模型
圖1.2顯示了與原始網絡相比更大的網絡模型在驗證集的表現。點是較大網絡的驗證集損失值,十字是原始網絡。僅僅一個epoch后,更大的網絡立即開始過擬合,其驗證集損失值也是雜亂的。
同時,圖1.3顯示了兩個網絡的訓練集損失值隨epoch的變化情況。正如你所看到的,更大的網絡很快就會把訓練集損失訓練到接近零。 網絡越大,訓練數據學習的速度就越快(使訓練損失很快降低),但是也更容易過擬合(導致訓練和驗證損失之間的巨大差異)。
圖1.3模型大小對訓練集損失的影響:嘗試一個更大的模型
2.權重正則化技術
你可能熟悉奧卡姆剃刀原則:給出兩個解釋,最可能正確的解釋是更簡單的一個 – 假設較少的解釋。 這個原則也適用於神經網絡的模型: 簡單的模型比復雜的泛化能力好。
在這種情況下,一個簡單的模型指的是模型:參數值的分布具有較小的熵(或者參數較少)。 因此,減少過擬合的一種常見方法是通過使權重只取小值來限制網絡的復雜性,這使得權重值的分布更加規整。 這就是所謂的權重正則化,這是改變網絡的損失函數來實現的,在原來的損失函數基礎上增加限制權重的成本。這個成本有兩種:
- L1正則化 – 所增加的成本與權重系數的絕對值成正比(權重的L1范數),權重稀疏化。
- L2正則化 – 所增加的成本與權重系數(權重的L2范數)的平方成正比。L2正則化在神經網絡中也稱為權重衰減。 不要讓不同的名字混淆你:權重衰減在數學上與L2正則化相同。
在Keras中,通過將選擇的權重正則化作為關鍵字參數傳遞給網絡層來增加正則成本。 讓我們在電影評論分類網絡中添加L2權重正則化。
from keras import regularizers
model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
l2(0.001)意味着該層的權重矩陣中的每個系數將增加0.001 * weight_coefficient_value到網絡的總損失。 請注意,由於這種懲罰只是在訓練時間增加的,這個網絡的損失在訓練時比在測試時間要高得多。圖2.1顯示了L2正則化懲罰的影響。正如你所看到的那樣,即使兩個模型具有相同數量的參數,具有L2正則化的模型(點)也比參考模型(十字)更能減少過擬合。
圖2.1 L2權重正則化對驗證集損失的影響
除了L2正則化,你還可以使用以下Keras權重正則方法。
from keras import regularizers
regularizers.l1(0.001) # L1正則化
regularizers.l1_l2(l1=0.001, l2=0.001) # 同時進行L1和L2正則化
3.Dropout
Dropout是最有效和最常用的神經網絡正則化技術之一。Dropout在網絡層訓練期間隨機失活(設置為零)該層的許多輸出特征(節點)。 假設輸入樣本經過一個隱藏層后輸出一個向量[0.2, 0.5, 1.3, 0.8, 1.1]。 在該層應用了Dropout之后,這個向量將出現幾個為0的特征值:例如[0, 0.5, 1.3, 0, 1.1]。 Dropout的值表示節點被隨機失活的概率,通常設置在0.2到0.5之間。在測試時間,則不再用dropout了,也就是說測試時所有的節點都要保留。這樣就造成了測試與訓練輸出比例不匹配,測試時隱藏層活躍節點更多。因此,網絡層的輸出特征(節點)要乘上與Dropout率相等的因子來縮小,達到了類似L2正則化權重衰減的目的。因此Dropout在過程上與L1正則化相似,在最終結果上則與L2正則化相似。
假設一個網絡層的輸出layer_output的shape為(layer_size,features)。 在訓練的時候,我們隨機地將矩陣中的一小部分值置零:
# 在訓練時,隨機失活50%的節點
layer_output *= np.random.randint(0, high=2, size=layer_output.shape)
在測試時,我們乘以隨機失活率縮小輸出比例。在這里,我們縮小了0.5(因為我們之前隨機失活了一半的節點單元):
# 測試時
layer_output * = 0.5
注意,這個過程可以在訓練時通過兩個操作實現,並且在測試時保持輸出不變,這在實踐中通常是這樣實現的(見圖4.8):
# 訓練時
layer_output *= np.random.randint(0, high=2, size=layer_output.shape)
layer_output /= 0.5 # 注意,在這種情況下,我們擴大了輸出,而不是縮小
圖3.1 Dropout在訓練時應用於激活矩陣.。在測試時,激活矩陣不變。
這種技術可能看起來很奇怪和也很隨意。為什么這會減少過擬合? Hinton說,他是受到銀行所使用的防欺詐機制的啟發。他說:“我去了我的銀行。 出納員不斷變化,我問他們其中一個為什么要這樣呢。 他說他不知道,他們就是這樣來回換。我想這一定是因為欺詐機制需要員工之間的合作。 這使我意識到,在每個網絡層中隨機刪除一個不同的神經元將防止“欺詐”,從而減少過度擬合。核心思想是,在一個圖層的輸出值中引入噪聲可以打破特定模式 Hinton所稱的欺詐),如果沒有噪聲存在,網絡將開始記憶特定模式。
在Keras中,我們可以通過在激活層輸出之后添加一個Dropout層實現Dropout:
model.add(layers.Dropout(0.5))
在IMDB例子中添加兩個Dropout層,看看它們在減少過擬合方面的表現:
dpt_model = models.Sequential()
dpt_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(16, activation='relu'))
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(1, activation='sigmoid'))
dpt_model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['acc'])
由圖3.2顯然可以得到:Dropout在4個epoch才出現過擬合,而原來的網絡在三個epoch就出現過擬合。並且在出現過擬合后,驗證集損失的增長速度明顯比原來網絡緩慢。
圖3.2 Dropout對網絡過擬合的影響
總結一下,神經網絡中防止過擬合的常用方法:
- 獲得更多的訓練數據
- 縮小網絡規模
- 權重正則化
- Dropout
其中首選是增加數據,然后是Dropout、權重正則化、最后選擇縮小網絡規模
參考博客:https://www.deeplearn.me/2351.html
關注"Python做些事",祝大家在代碼界一帆風順,各位大佬,干杯