經常會被問到你用深度學習訓練模型時怎麼樣改善你的結果呢?然後每次都懵逼了,一是自己懂的不多,二是實驗的不多,三是記性不行忘記了。所以寫這篇部落格,記錄下別人以及自己的一些經驗。
ilya sutskever(hinton的學生)講述了有關深度學習的見解及實用建議:
獲取資料:確保要有高質量的輸入/輸出資料集,這個資料集要足夠大、具有代表性以及擁有相對清楚的標籤。缺乏資料集是很難成功的。
預處理:將資料進行集中是非常重要的,也就是要使資料均值為0,從而使每個維度的每次變動為1。有時,當輸入的維度隨量級排序變化時,最好使用那個維度的log(1+x)。基本上,重要的是要找到乙個0值的可信編碼以及自然分界的維度。這樣做可使學習工作得更好。情況就是這樣的,因為權值是通過公式來更新的:wij中的變化 \propto xidl/dyj(w表示從層x到層y的權值,l是損失函式)。如果x的均值很大(例如100),那麼權值的更新將會非常大,並且是相互關聯的,這使得學習變得低劣而緩慢。保持0均值和較小的方差是成功的關鍵因素。
批處理:在如今的計算機上每次只執行乙個訓練樣本是很低效的。反之如果進行的是128個例子的批處理,效率將大幅提高,因為其輸出量是非常可觀的。事實上使用數量級為1的批處理效果不錯,這不僅可獲得效能的提公升同時可降低過度擬合;不過這有可能會被大型批處理超越。但不要使用過大的批處理,因為有可能導致低效和過多過度擬合。所以我的建議是:根據硬體配置選取適合的批處理規模,量力而為會更加高效。
梯度歸一化:根據批處理的大小來拆分梯度。這是乙個好主意,因為如果對批處理進行倍增(或倍減),無需改變學習率(無論如何,不要太多)。
學習率計畫:從乙個正常大小的學習率(lr)開始,朝著終點不斷縮小。
1lr的典型取值是0.1,令人驚訝的是,對於大量的神經網路問題來說,0.1是學習率的乙個很好的值。通常學習率傾向於更小而非更大。但最重要的是要關注學習率。一些研究人員(比如alex krizhevsky)使用的方法是,監視更新範數和權值範數之間的比率。比率取值大約為10¯³。如果取值過小,那麼學習會變得非常慢;如果取值過大,那麼學習將會非常不穩定甚至失敗。使用乙個驗證集——乙個不進行訓練的訓練集子集,來決定何時降低學習率以及何時停止訓練(例如當驗證集的錯誤開始增多的時候)。
學習率計畫的實踐建議:若發現驗證集遭遇瓶頸,不妨將lr除以2(或5),然後繼續。最終,lr將會變得非常小,這也到了停止訓練的時候了。這樣做可以確保在驗證效能受到損害的時候,你不會擬合(或過度擬合)訓練資料。降低lr是很重要的,通過驗證集來控制lr是個正確的做法。
權值初始化。關注權值在學習開始時的隨機初始化。
如果想偷懶,不妨試試0.02*randn(num_params)。這個範圍的值在許多不同的問題上工作得很好。當然,更小(或更大)的值也值得一試。所以關注初始化是很有必要的。嘗試多種不同的初始化,努力就會得到回報。如果網路完全不工作(即沒法實施),繼續改進隨機初始化是正確的選擇。如果它工作得不好(例如是乙個非常規的和/或非常深的神經網路架構),那麼需要使用init_scale/sqrt(layer_width)*randn來初始化每個權值矩陣。在這種情況下,init_scale應該設定為0.1或者1,或者類似的值。
對於深度且迴圈的網路,隨機初始化是極其重要的。如果沒有處理好,那麼它看起來就像沒有學習到任何東西。我們知道,一旦條件都設定好了,神經網路就會學習。
乙個有趣的故事:多年來,研究人員相信sgd不能訓練來自隨機初始化的深度神經網路。每次嘗試都以失敗告終。令人尷尬的是,他們沒有成功是因為使用「小的隨機權值」來進行初始化,雖然小數值的做法在淺度網路上工作得非常好,但在深度網路上的表現一點也不好。當網路很深時,許多權值矩陣之間會進行乘積,所以不好的結果會被放大。
但如果是淺度網路,sgd可以幫助我們解決該問題。
如果正在訓練rnn或者lstm,要對梯度(記得梯度已除以批量大小)範數使用乙個硬約束。像15或者5這樣的約束在我個人的實驗中工作得很好。請將梯度除以批處理大小,再檢查一下它的範數是否超過15(或5)。如果超過了,將它縮小到15(或5)。這個小竅門在rnn和lstm的訓練中發揮著巨大作用,不這樣做的話,**性的梯度將會導致學習失敗,最後不得不使用像1e-6這樣微小而無用的學習率。
數值梯度檢查:如果沒有使用過theano或者torch,梯度實現只能親力親為了。在實現梯度的時候很容易出錯,所以使用數值梯度檢查是至關重要的。這樣做會讓你對自己的**充滿信心。調整超級引數(比如學習率和初始化)是非常有價值的,因此好刀要用在刀刃上。
如果正在使用lstm同時想在具有大範圍依賴的問題上訓練它們,那麼應該將lstm遺忘關口的偏差初始化為較大的值。預設狀態下,遺忘關口是s型的全部輸入,當權值很小時,遺忘關口會被設定為0.5,這只能對部分問題有效。這是對lstm初始化的乙個警示。
資料增加(data augmentation):使用演算法來增加訓練例項數量是個有創意的做法。如果是影象,那麼應該轉換和旋轉它們;如果是音訊,應該將清晰的部分和所有型別的雜音進行混合處理。資料新增是一門藝術(除非是在處理影象),這需要一定的常識。
dropout:dropout提供了乙個簡單的方法來提公升效能。記得要調整退出率,而在測試時不要忘記關閉dropout,然後對權值求乘積(也就是1-dropout率)。當然,要確保將網路訓練得更久一點。不同於普通訓練,在進入深入訓練之後,驗證錯誤通常會有所增加。dropout網路會隨著時間推移而工作得越來越好,所以耐心是關鍵。
綜合(ensembling)。訓練10個神經網路,然後對其**資料進行平均。該做法雖然簡單,但能獲得更直接、更可觀的效能提公升。有人可能會困惑,為什麼平均會這麼有效?不妨用乙個例子來說明:假如兩個分類器的錯誤率為70%,如果其中乙個的正確率保持較高,那麼平均後的**會更接近正確結果。這對於可信網路的效果會更加明顯,當網路可信時結果是對的,不可信時結果是錯的。
(下面幾點是上面的簡化版)
1:準備資料:務必保證有大量、高質量並且帶有乾淨標籤的資料,沒有如此的資料,學習是不可能的
2:預處理:這個不多說,就是0均值和1方差化
3:minibatch:建議值128,1最好,但是效率不高,但是千萬不要用過大的數值,否則很容易過擬合
4:梯度歸一化:其實就是計算出來梯度之後,要除以minibatch的數量。這個不多解釋
5:下面主要集中說下學習率
5.1:總的來說是用乙個一般的學習率開始,然後逐漸的減小它
5.2:乙個建議值是0.1,適用於很多nn的問題,一般傾向於小一點。
5.3:乙個對於排程學習率的建議:如果在驗證集上效能不再增加就讓學習率除以2或者5,然後繼續,學習率會一直變得很小,到最後就可以停止訓練了。
5.4:很多人用的乙個設計學習率的原則就是監測乙個比率(每次更新梯度的norm除以當前weight的norm),如果這個比率在10-3附近,如果小於這個值,學習會很慢,如果大於這個值,那麼學習很不穩定,由此會帶來失敗。
6:使用驗證集,可以知道什麼時候開始降低學習率,和什麼時候停止訓練。
7:關於對weight初始化的選擇的一些建議:
7.1:如果你很懶,直接用0.02*randn(num_params)來初始化,當然別的值你也可以去嘗試
7.2:如果上面那個不太好使,那麼久依次初始化每乙個weight矩陣用init_scale / sqrt(layer_width) * randn,init_scale可以被設定為0.1或者1
7.3:初始化引數對結果的影響至關重要,要引起重視。
7.4:在深度網路中,隨機初始化權重,使用sgd的話一般處理的都不好,這是因為初始化的權重太小了。這種情況下對於淺層網路有效,但是當足夠深的時候就不行了,因為weight更新的時候,是靠很多weight相乘的,越乘越小,有點類似梯度消失的意思(這句話是我加的)
8:如果訓練rnn或者lstm,務必保證gradient的norm被約束在15或者5(前提還是要先歸一化gradient),這一點在rnn和lstm中很重要。
9:檢查下梯度,如果是你自己計算的梯度。
10:如果使用lstm來解決長時依賴的問題,記得初始化bias的時候要大一點
12:盡可能想辦法多的擴增訓練資料,如果使用的是影象資料,不妨對影象做一點扭轉啊之類的,來擴充資料訓練集合。
13:使用dropout
14:評價最終結果的時候,多做幾次,然後平均一下他們的結果。
深度學習調參技巧
模型引數的一般設定 epoch迭代幾十到幾百次。mini batch size從幾十到幾百,為了更好的利用硬體加速,通常取8的倍數,例如128,256。learning rate取0.1 資料集越大,模型越複雜,應取值越小 weight decay取0.005,momentum取0.9。dropou...
深度學習調參技巧
1 準備資料 務必保證有大量 高質量並且帶有乾淨標籤的資料,沒有如此的資料,學習是不可能的 2 預處理 這個不多說,就是0均值和1方差化 3 minibatch 建議值128,1最好,但是效率不高,但是千萬不要用過大的數值,否則很容易過擬合 4 梯度歸一化 其實就是計算出來梯度之後,要除以minib...
深度學習調參策略(二)
超引數 hyper parameter 是困擾神經網路訓練的問題之一,因為這些引數不可通過常規方法學習獲得。神經網路經典五大超引數 學習率 leraning rate 權值初始化 weight initialization 網路層數 layers 單層神經元數 units 正則懲罰項 regular...