CS231n課程筆記翻譯:神經網路筆記3(上)

譯者註:本文智能單元首發,譯自斯坦福CS231n課程筆記Neural Nets notes 3,課程教師Andrej Karpathy授權翻譯。本篇教程由杜客翻譯完成,堃堃和鞏子嘉進行校對修改。譯文含公式和代碼,建議PC端閱讀。

原文如下

內容列表:

  • 梯度檢查
  • 合理性(Sanity)檢查
  • 檢查學習過程
    • 損失函數
    • 訓練集與驗證集準確率
    • 權重:更新比例
    • 每層的激活數據與梯度分布
    • 可視化 譯者註:上篇翻譯截止處
  • 參數更新
    • 一階(隨機梯度下降)方法,動量方法,Nesterov動量方法
    • 學習率退火
    • 二階方法
    • 逐參數適應學習率方法(Adagrad,RMSProp)
  • 超參數調優
  • 評價
    • 模型集成
  • 總結
  • 拓展引用

學習過程

在前面章節中,我們討論了神經網路的靜態部分:如何創建網路的連接、數據和損失函數。本節將致力於講解神經網路的動態部分,即神經網路學習參數和搜索最優超參數的過程。

梯度檢查

理論上將進行梯度檢查很簡單,就是簡單地把解析梯度和數值計算梯度進行比較。然而從實際操作層面上來說,這個過程更加複雜且容易出錯。下面是一些提示、技巧和需要仔細注意的事情:

使用中心化公式。在使用有限差值近似來計算數值梯度的時候,常見的公式是:

displaystyle frac{df(x)}{dx}=frac{f(x+h)-f(x)}{h}(bad, do not use)

其中h是一個很小的數字,在實踐中近似為1e-5。在實踐中證明,使用中心化公式效果更好:

displaystyle frac{df(x)}{dx}=frac{f(x+h)-f(x-h)}{2h}(use instead)

該公式在檢查梯度的每個維度的時候,會要求計算兩次損失函數(所以計算資源的耗費也是兩倍),但是梯度的近似值會準確很多。要理解這一點,對f(x+h)f(x-h)使用泰勒展開,可以看到第一個公式的誤差近似O(h),第二個公式的誤差近似O(h^2)(是個二階近似)。(譯者註:泰勒展開相關內容可閱讀《高等數學》第十二章第四節:函數展開成冪級數。)

使用相對誤差來比較。比較數值梯度f和解析梯度f的細節有哪些?如何得知此兩者不匹配?你可能會傾向於監測它們的差的絕對值|f或者差的平方值,然後定義該值如果超過某個規定閾值,就判斷梯度實現失敗。然而該思路是有問題的。想想,假設這個差值是1e-4,如果兩個梯度值在1.0左右,這個差值看起來就很合適,可以認為兩個梯度是匹配的。然而如果梯度值是1e-5或者更低,那麼1e-4就是非常大的差距,梯度實現肯定就是失敗的了。因此,使用相對誤差總是更合適一些:

displaystyle frac{|f

上式考慮了差值佔兩個梯度絕對值的比例。注意通常相對誤差公式只包含兩個式子中的一個(任意一個均可),但是我更傾向取兩個式子的最大值或者取兩個式子的和。這樣做是為了防止在其中一個式子為0時,公式分母為0(這種情況,在ReLU中是經常發生的)。然而,還必須注意兩個式子都為零且通過梯度檢查的情況。在實踐中:

  • 相對誤差>1e-2:通常就意味著梯度可能出錯。

  • 1e-2>相對誤差>1e-4:要對這個值感到不舒服才行。

  • 1e-4>相對誤差:這個值的相對誤差對於有不可導點的目標函數是OK的。但如果目標函數中沒有kink(使用tanh和softmax),那麼相對誤差值還是太高。

  • 1e-7或者更小:好結果,可以高興一把了。

要知道的是網路的深度越深,相對誤差就越高。所以如果你是在對一個10層網路的輸入數據做梯度檢查,那麼1e-2的相對誤差值可能就OK了,因為誤差一直在累積。相反,如果一個可微函數的相對誤差值是1e-2,那麼通常說明梯度實現不正確。

使用雙精度。一個常見的錯誤是使用單精度浮點數來進行梯度檢查。這樣會導致即使梯度實現正確,相對誤差值也會很高(比如1e-2)。在我的經驗而言,出現過使用單精度浮點數時相對誤差為1e-2,換成雙精度浮點數時就降低為1e-8的情況。

保持在浮點數的有效範圍。建議通讀《What Every Computer Scientist Should Konw About Floating-Point Artthmetic》一文,該文將闡明你可能犯的錯誤,促使你寫下更加細心的代碼。例如,在神經網路中,在一個批量的數據上對損失函數進行歸一化是很常見的。但是,如果每個數據點的梯度很小,然後又用數據點的數量去除,就使得數值更小,這反過來會導致更多的數值問題。這就是我為什麼總是會把原始的解析梯度和數值梯度數據列印出來,確保用來比較的數字的值不是過小(通常絕對值小於1e-10就絕對讓人擔心)。如果確實過小,可以使用一個常數暫時將損失函數的數值範圍擴展到一個更「好」的範圍,在這個範圍中浮點數變得更加緻密。比較理想的是1.0的數量級上,即當浮點數指數為0時。

目標函數的不可導點(kinks)。在進行梯度檢查時,一個導致不準確的原因是不可導點問題。不可導點是指目標函數不可導的部分,由ReLU(max(0,x))等函數,或SVM損失,Maxout神經元等引入。考慮當x=-1e6的時,對ReLU函數進行梯度檢查。因為x<0,所以解析梯度在該點的梯度為0。然而,在這裡數值梯度會突然計算出一個非零的梯度值,因為f(x+h)可能越過了不可導點(例如:如果h>1e-6),導致了一個非零的結果。你可能會認為這是一個極端的案例,但實際上這種情況很常見。例如,一個用CIFAR-10訓練的SVM中,因為有50,000個樣本,且根據目標函數每個樣本產生9個式子,所以包含有450,000個max(0,x)式子。而一個用SVM進行分類的神經網路因為採用了ReLU,還會有更多的不可導點。

注意,在計算損失的過程中是可以知道不可導點有沒有被越過的。在具有max(x,y)形式的函數中持續跟蹤所有「贏家」的身份,就可以實現這一點。其實就是看在前向傳播時,到底x和y誰更大。如果在計算f(x+h)f(x-h)的時候,至少有一個「贏家」的身份變了,那就說明不可導點被越過了,數值梯度會不準確。

使用少量數據點。解決上面的不可導點問題的一個辦法是使用更少的數據點。因為含有不可導點的損失函數(例如:因為使用了ReLU或者邊緣損失等函數)的數據點越少,不可導點就越少,所以在計算有限差值近似時越過不可導點的幾率就越小。還有,如果你的梯度檢查對2-3個數據點都有效,那麼基本上對整個批量數據進行梯度檢查也是沒問題的。所以使用很少量的數據點,能讓梯度檢查更迅速高效。

謹慎設置步長h。在實踐中h並不是越小越好,因為當h特別小的時候,就可能就會遇到數值精度問題。有時候如果梯度檢查無法進行,可以試試將h調到1e-4或者1e-6,然後突然梯度檢查可能就恢復正常。這篇維基百科文章中有一個圖表,其x軸為h值,y軸為數值梯度誤差。

在操作的特性模式中梯度檢查。有一點必須要認識到:梯度檢查是在參數空間中的一個特定(往往還是隨機的)的單獨點進行的。即使是在該點上梯度檢查成功了,也不能馬上確保全局上梯度的實現都是正確的。還有,一個隨機的初始化可能不是參數空間最優代表性的點,這可能導致進入某種病態的情況,即梯度看起來是正確實現了,實際上並沒有。例如,SVM使用小數值權重初始化,就會把一些接近於0的得分分配給所有的數據點,而梯度將會在所有的數據點上展現出某種模式。一個不正確實現的梯度也許依然能夠產生出這種模式,但是不能泛化到更具代表性的操作模式,比如在一些的得分比另一些得分更大的情況下就不行。因此為了安全起見,最好讓網路學習(「預熱」)一小段時間,等到損失函數開始下降的之後再進行梯度檢查。在第一次迭代就進行梯度檢查的危險就在於,此時可能正處在不正常的邊界情況,從而掩蓋了梯度沒有正確實現的事實。

不要讓正則化吞沒數據。通常損失函數是數據損失和正則化損失的和(例如L2對權重的懲罰)。需要注意的危險是正則化損失可能吞沒掉數據損失,在這種情況下梯度主要來源於正則化部分(正則化部分的梯度表達式通常簡單很多)。這樣就會掩蓋掉數據損失梯度的不正確實現。因此,推薦先關掉正則化對數據損失做單獨檢查,然後對正則化做單獨檢查。對於正則化的單獨檢查可以是修改代碼,去掉其中數據損失的部分,也可以提高正則化強度,確認其效果在梯度檢查中是無法忽略的,這樣不正確的實現就會被觀察到了。

記得關閉隨機失活(dropout)和數據擴張(augmentation)。在進行梯度檢查時,記得關閉網路中任何不確定的效果的操作,比如隨機失活,隨機數據擴展等。不然它們會在計算數值梯度的時候導致巨大誤差。關閉這些操作不好的一點是無法對它們進行梯度檢查(例如隨機失活的反向傳播實現可能有錯誤)。因此,一個更好的解決方案就是在計算f(x+h)f(x-h)前強制增加一個特定的隨機種子,在計算解析梯度時也同樣如此。

檢查少量的維度。在實際中,梯度可以有上百萬的參數,在這種情況下只能檢查其中一些維度然後假設其他維度是正確的。注意確認在所有不同的參數中都抽取一部分來梯度檢查。在某些應用中,為了方便,人們將所有的參數放到一個巨大的參數向量中。在這種情況下,例如偏置就可能只佔用整個向量中的很小一部分,所以不要隨機地從向量中取維度,一定要把這種情況考慮到,確保所有參數都收到了正確的梯度。

學習之前:合理性檢查的提示與技巧

在進行費時費力的最優化之前,最好進行一些合理性檢查:

  • 尋找特定情況的正確損失值。在使用小參數進行初始化時,確保得到的損失值與期望一致。最好先單獨檢查數據損失(讓正則化強度為0)。例如,對於一個跑CIFAR-10的Softmax分類器,一般期望它的初始損失值是2.302,這是因為初始時預計每個類別的概率是0.1(因為有10個類別),然後Softmax損失值正確分類的負對數概率:-ln(0.1)=2.302。對於Weston Watkins SVM,假設所有的邊界都被越過(因為所有的分值都近似為零),所以損失值是9(因為對於每個錯誤分類,邊界值是1)。如果沒看到這些損失值,那麼初始化中就可能有問題。

  • 第二個合理性檢查:提高正則化強度時導致損失值變大。

  • 對小數據子集過擬合。最後也是最重要的一步,在整個數據集進行訓練之前,嘗試在一個很小的數據集上進行訓練(比如20個數據),然後確保能到達0的損失值。進行這個實驗的時候,最好讓正則化強度為0,不然它會阻止得到0的損失。除非能通過這一個正常性檢查,不然進行整個數據集訓練是沒有意義的。但是注意,能對小數據集進行過擬合併不代表萬事大吉,依然有可能存在不正確的實現。比如,因為某些錯誤,數據點的特徵是隨機的,這樣演算法也可能對小數據進行過擬合,但是在整個數據集上跑演算法的時候,就沒有任何泛化能力。

檢查整個學習過程

在訓練神經網路的時候,應該跟蹤多個重要數值。這些數值輸出的圖表是觀察訓練進程的一扇窗口,是直觀理解不同的超參數設置效果的工具,從而知道如何修改超參數以獲得更高效的學習過程。

在下面的圖表中,x軸通常都是表示周期(epochs)單位,該單位衡量了在訓練中每個樣本數據都被觀察過次數的期望(一個周期意味著每個樣本數據都被觀察過了一次)。相較於迭代次數(iterations),一般更傾向跟蹤周期,這是因為迭代次數與數據的批尺寸(batchsize)有關,而批尺寸的設置又可以是任意的。

損失函數

訓練期間第一個要跟蹤的數值就是損失值,它在前向傳播時對每個獨立的批數據進行計算。下圖展示的是隨著損失值隨時間的變化,尤其是曲線形狀會給出關於學習率設置的情況:

————————————————————————————————————————

左圖展示了不同的學習率的效果。過低的學習率導致演算法的改善是線性的。高一些的學習率會看起來呈幾何指數下降,更高的學習率會讓損失值很快下降,但是接著就停在一個不好的損失值上(綠線)。這是因為最優化的「能量」太大,參數在混沌中隨機震蕩,不能最優化到一個很好的點上。右圖顯示了一個典型的隨時間變化的損失函數值,在CIFAR-10數據集上面訓練了一個小的網路,這個損失函數值曲線看起來比較合理(雖然可能學習率有點小,但是很難說),而且指出了批數據的數量可能有點太小(因為損失值的噪音很大)。

————————————————————————————————————————

損失值的震蕩程度和批尺寸(batch size)有關,當批尺寸為1,震蕩會相對較大。當批尺寸就是整個數據集時震蕩就會最小,因為每個梯度更新都是單調地優化損失函數(除非學習率設置得過高)。

有的研究者喜歡用對數域對損失函數值作圖。因為學習過程一般都是採用指數型的形狀,圖表就會看起來更像是能夠直觀理解的直線,而不是呈曲棍球一樣的曲線狀。還有,如果多個交叉驗證模型在一個圖上同時輸出圖像,它們之間的差異就會比較明顯。

有時候損失函數看起來很有意思:lossfunctions.tumblr.com。

訓練集和驗證集準確率

在訓練分類器的時候,需要跟蹤的第二重要的數值是驗證集和訓練集的準確率。這個圖表能夠展現知道模型過擬合的程度:

————————————————————————————————————————

在訓練集準確率和驗證集準確率中間的空隙指明了模型過擬合的程度。在圖中,藍色的驗證集曲線顯示相較於訓練集,驗證集的準確率低了很多,這就說明模型有很強的過擬合。遇到這種情況,就應該增大正則化強度(更強的L2權重懲罰,更多的隨機失活等)或收集更多的數據。另一種可能就是驗證集曲線和訓練集曲線如影隨形,這種情況說明你的模型容量還不夠大:應該通過增加參數數量讓模型容量更大些。

————————————————————————————————————————

權重更新比例

最後一個應該跟蹤的量是權重中更新值的數量和全部值的數量之間的比例。注意:是更新的,而不是原始梯度(比如,在普通sgd中就是梯度乘以學習率)。需要對每個參數集的更新比例進行單獨的計算和跟蹤。一個經驗性的結論是這個比例應該在1e-3左右。如果更低,說明學習率可能太小,如果更高,說明學習率可能太高。下面是具體例子:

# 假設參數向量為W,其梯度向量為dWparam_scale = np.linalg.norm(W.ravel())update = -learning_rate*dW # 簡單SGD更新update_scale = np.linalg.norm(update.ravel())W += update # 實際更新print update_scale / param_scale # 要得到1e-3左右

相較於跟蹤最大和最小值,有研究者更喜歡計算和跟蹤梯度的範式及其更新。這些矩陣通常是相關的,也能得到近似的結果。

每層的激活數據及梯度分布

一個不正確的初始化可能讓學習過程變慢,甚至徹底停止。還好,這個問題可以比較簡單地診斷出來。其中一個方法是輸出網路中所有層的激活數據和梯度分布的柱狀圖。直觀地說,就是如果看到任何奇怪的分布情況,那都不是好兆頭。比如,對於使用tanh的神經元,我們應該看到激活數據的值在整個[-1,1]區間中都有分布。如果看到神經元的輸出全部是0,或者全都飽和了往-1和1上跑,那肯定就是有問題了。

第一層可視化

最後,如果數據是圖像像素數據,那麼把第一層特徵可視化會有幫助:

————————————————————————————————————————

將神經網路第一層的權重可視化的例子。左圖中的特徵充滿了噪音,這暗示了網路可能出現了問題:網路沒有收斂,學習率設置不恰當,正則化懲罰的權重過低。右圖的特徵不錯,平滑,乾淨而且種類繁多,說明訓練過程進行良好。

————————————————————————————————————————

神經網路筆記3 (上)結束。

譯者反饋

  1. 轉載須全文轉載且註明原文鏈接,否則保留維權權利;
  2. 請知友們通過評論和私信等方式批評指正,貢獻者均會補充提及;
  3. CS231n的翻譯即將進入尾聲,歡迎知友們建議後續的翻譯方向;
  4. 知友@豬皮建議下一步的翻譯方向是領域內的一些經典論文;
  5. 知友@一蓑煙灰在評論中詳細解釋了自己學習CS231n及本科畢設相關情況,建議下一步的翻譯方向是課程作業解析。

推薦閱讀:

人工智慧取代法官是否更能維護公正?
AlphaGo對戰柯潔:關鍵不是人工智慧勝過人
Google黑科技系列 3 —將圖片變成視頻的技術Deep Stereo

TAG:机器学习 | 深度学习DeepLearning | 人工智能 |