過擬合,快走開!

image
在機器學習的過程中,當引數數量比較多的時候,很可能就會出現過擬合的現象,使得模型在訓練集中擬合效果很好,但在測試集上擬合效果就讓人不那麼愉快了。
發生這種情況,就意味著訓練出來的模型泛化性比較差,無法適應複雜的現實情況。那我們肯定就需要想辦法防止或者減弱過擬合的發生。本篇 CoorChice 將會介紹幾種防止過擬合的方法。
正則化
在進行模型訓練的的時候,最重要的一步就是通過不斷減小損失函式的損失值來逼近全域性最優解,簡單的說就是讓我們的特徵權值能夠正確的描述出真實情況。
可是往往訓練出來的權值可能會有很多的噪聲,即有很多無用的特徵權值,在沒有類似噪聲的資料中很可能就會誤判。也可能某些特徵的權值特別大,導致只要出現一部分大的特徵,模型就會忽略掉其大特徵權值較小的有用權值,那這樣的模型也是很容易造成誤判。
如何解決這種困境呢?答案可以是正則化,或者說規則化。正則化是代數幾何中的一個概念。在機器學習中,加入正則化項表示加入了一個先驗規則項。大白話來說就是,我們對結果是有一定預期的,不能完全隨意的想咋搞咋搞。

image
通常會使用 範數 來作為損失函式的規則化項。

image
這就是範數公式,依據 p 的取值,可以產生 0範數 、 1範數 和 2範數 等,即 p 取 0、1、2。不同的範數所應對場景也有所不同。
0範數、1範數
0範數
上述範數公式,當 p 取 0 時,就稱為 0 範數,Lp 公式就變為如下形式:

image
可以看到,0 範數中,涉及到求解一個數的 0 次方根,這是很怪異的一個公式,很難說清它的意義是什麼,以及應該如何求解。
所以在0範數有一個優化的形式,使其具有一個明確的意義:

image
該公式的意義是,求解 w 向量空間中的非 0 元素個數。
它為什麼能夠防止過擬合呢?把它加入到損失函式中有如下式子:

image
此處插播一條說明,上面的 Loss 函式式由兩個部分組成,c0部分就是傳統的損失函式,稱為 “經驗風險”;後面的正則項稱為 “結構風險”,它有點從結構上約束前半部分 “經驗風險” 的意思。
可以看看當 p 趨近於 0 時範數影象:

image
不難看出這樣的趨勢,當 p 與接近於 0 時,它的結果就越貼近於各個座標軸。那麼可以想象出,當 p 為 0 的時候,結果就都落在座標軸上了。當損失部分的函式與其相切時,自然之可能切到座標軸上,即只有一個座標有值,其它全為 0。
這就意味這,在進行梯度下降不斷減小 Loss 的過程中,需要考慮將更多權值 w 置為 0 ,這樣才能使 0 範數項不斷的減小。那麼它的意義就浮現出來了,就是儘可能的將不重要的權值直接置 0,減少引數數量,儘量只保留有用的特徵。即它使權重集具有了稀疏性(包含 0),起到了篩選特徵的作用。

image
看起來很棒吧,能自動的篩選特徵!可是在對於特徵權值 w 數量龐大的機器學習中,要動態的去學習到如何將那些 w 設定為 0 既能保證 Loss 不斷的減小,又能保證 0 範數項也在不斷的減小,到底應該讓那些權值變小,而那些權值直接為 0 呢,可能性就太多了,多到幾乎不可能搜尋出一條最優的解路徑來。這樣的有解,但幾乎很難求解出來的問題被稱為 NP-hard 問題,意思就是雖然可以檢查每次計算結果的正確性,但計算結果眾多,以至於無法進行一一檢查,而是這個問題相當於無法解的問題。
1範數
在數學上,一般無法直接求解的問題就會使用近似的演算法去不斷的逼近真實的答案,得出一個近似的解,也是可以接受的。
那 1範數 就是具有 0範數 優勢,而又易於求解的一個近似演算法。
同理,1範數就是當 p 等於 1 時的範數式:

image
1範數的意思就很明瞭了,就是所有權值 w 的絕對值的和。加入1範數的 Loss 函式式如下:

image
從 Loss 可以知道,為了使整個式子的值最小,需要 1範數 項的值也最小,那看看 1範數額影象:

image
上圖是三維空間中1範數的影象,是一個八面體,存在與座標軸相交的頂點。推知,在更高維度的空間中,必然也存在很多這樣與座標軸相交的頂點。就是說,在梯度下降的求解過程中,也是能找到損失函式與這些個頂點相切的解的,那麼 1範數 也有機會和 0範數 一樣,能夠篩選出有用的特徵,而剔除噪聲,從而提高模型的泛化能力。
在計算過程中,從上面的影象可以看出,1範數存在不可導的點,也就是它的頂點們,這在計算上是不那麼方便的。
2範數
避免過擬合
既然1範數計算也不方便,那我們是不是可以再升級升級,看看更高的範數是不是可以計算方便一些呢?
看看 p 取 2 的範數式:

image
再看看影象是什麼樣的:

image
三維影象是個球!這意味著2範數在空間中是連續的且處處可導的函式。當然,它和座標軸也是由交點的,這意味著和損失函式的切點也是有可能落在座標軸上的,只不過從影象也能看出來,這樣的概率比1範數更小罷了。
加入2範數的 Loss 函式是這樣的:

image
也就是求 w 的平方和。這裡把開根去掉了,其實沒什麼影響的,效果差不多但計算量卻小了很多。
2範數與損失函式的切點既然很難落到座標軸上,那就是說它很難對特徵進行篩選,很難削減無用的噪聲特徵,那它憑什麼也能避免模型過擬合呢?
CoorChice 會慢慢道來。
我們考慮這樣一個例子:用3個特徵來識別小狗:dog:,簡單來說,就有3個特徵權值,即 [w1,w2,w3]。
w1 = 1,w2 = 1,w3 = 1 -> w1+w2+w3 = 3 w1 = 3,w2 = 0,w3 = 0 -> w1+w2+w3 = 3
以上是 w 取值的兩種情況。雖然 w 的和都是 3,但在識別的過程中,第二種情況中的 w2、w3 就完全的被巨大的 w1=3
給蓋過了。假設 w1 表示 4 條腿的特徵,那麼這個模型但凡遇到 4 條腿的東西就認為它是小狗了,顯然是不科學的。這就是說,模型在訓練集中準確率很高,但在複雜的實際情況中很容易誤判。
如果採用2範數,第一種情況的平方和是 3,而第二種情況的平方和就是 9 了!那麼要讓 Loss 不斷減小,就需要不斷的削弱 w1 這種強特徵的權重,使得一些有用的弱特徵也能過累加起來顛覆強特徵,讓模型不至於一遇到一個極強的特徵,就忽略了眾多較弱的特徵,而造成誤判。
2範數對權重的削弱平均特性,可以使得模型不依賴於某一部分強特徵,而是更加全面的去考慮綜合的特徵。這樣模型的泛化能力自然就提高了,也就不容易出現過擬合的情況了。
避免梯度爆炸:boom:
在 ofollow,noindex">《【Get】用深度學習識別手寫數字》 一文中,CoorChice 就提到了一開始訓練時遇到的瓶頸,因為梯度發生了 bong! bong! bong! 的爆炸。直接就導致了訓練完全沒辦法進行下去。但是在 CoorChice 加入正則化項之後,就成功了越過了梯度爆炸的雷區,順利完成了訓練。
原因就在於,訓練過程中,某些極強權值的大小太過誇張,導致連乘過程中數值巨大無比,就爆炸:boom:了了。2範數正則項剛好作用就是削弱這種極強的權值,所以在一定程度上,它能夠有效的減少梯度爆炸發生的可能性。
如何在 TensorFlow 中加入正則化項?
1.將所有權重 w 記錄下來
tf.add_to_collection(tf.GraphKeys.WEIGHTS, w)
每建立一個權值就呼叫這個函式把權值加入到池中。
2.構建正則化項,加入到 Loss 中
# 構建 l2 正則化項,設定其(縮放度)重要程度為 5.0 / 50000 regularization = tf.contrib.layers.l2_regularizer(scale=(5.0 / 50000)) # 讓正則化生效 reg_term = tf.contrib.layers.apply_regularization(regularization) # 在損失函式中加入正則化項 loss = (-tf.reduce_sum(y_data * tf.log(y_conv)) + reg_term)
Dropout
Dropout 是一種被經常用到深度學習中,用於減弱過擬合的一種技術。它的核心原理就是,在訓練過程中,讓一層中的神經元按照指定的比率一部分失效,一部分仍然有效,具體是哪些個神經元會被失效或者有效,都是隨機的。
失效的神經元在一次迭代中就不會被更新。而在下一輪的訓練中,又會有另外一部分神經元會被失效,不會被更新。
這樣做就相當於每次訓練都減少了神經元的數量,同時由於每次可能抽取到的神經元不一樣,就使得學習路徑變的具有隨機性。不同於沒有 Dropout 的網路那樣,每次只能全量的更新所有神經元,加入 Dropout 的神經網路中,神經元之間的共適應性會被削弱,在不斷減小的梯度的要求下,就能夠迫使網路學習出更加具有魯棒性的特徵。這樣模型的適應性會更強,而不是隻能適應一個套路。

image
解釋了一大堆,可能還是很抽象,這時不如來一張圖吧!

image
是不是感覺清晰了很多。左邊是沒有 Dropout 的網路,神經元之間都是全量連結的。右邊是有 Dropout 的網路,可以看到在一次訓練中,有一部分神經元是斷開連結的,即失效了。每次斷開連結的神經元都是隨機了,這就給網路增加了很多可能,就像是具有了變異的能力。
通常,Dropout 需要設定一個超引數,指定每次需要有多少神經元失效。這個值一般回取 0.5 ,因為這樣能夠組合出多種類的情況來。
在著名的 VGG-16 網路模型中,最後3層的全連結層中,都加入 Dropout。
當然,使用 Dropout 的弊端也是因為隨機性帶來,隨機很大概率上會導致訓練次數的增加,使得訓練時間變長。

image
如何在 TensorFlow 中加入 Dropout?
tf.nn.dropout(input, keep_prob)
很簡單,就是傳入前面的輸出,比如一個全連結層的輸出,然後在第二個引數指定需要保留的神經元的比率。
需要注意的是,Dropout 在目前版本的 TensorFlow Lite 中還沒有被支援,所以考慮在 TensorFlow Lite 上跑模型的同學就不能使用了哦!:flushed:
總結
本篇 CoorChice 介紹了 2 種減少過擬合發生的可能性的方法, 正則化 和 Dropout 。
-
L0 和 L1 正則化能夠具有稀疏能力,減少引數數量,提取出主要特徵。但 L0 在複雜引數集中難以求解,所以如果有需求時,通常選擇 L1 正則化代替。
-
L2 正則化能夠削弱強特徵,使能夠考慮更加全面的特徵。同時,L2 正則化還能一定程度上防止梯度爆炸:boom:的發生。
- Dropout 是一種比較具有通用性的防止過擬合的手段,但會增加訓練時間,而且目前 TensorFlow Lite 對該操作還不支援。
- 嘿,隨手點個贊吧 :heart:! Lok'Tar
image
- CoorChice 會不定期的分享乾貨,快進入 CoorChice的【個人主頁】 加關注吧。