CS231n課程筆記翻譯:神經網絡筆記1(上)
一、常用激活函數
每個激活函數(或非線性函數)的輸入都是一個數字,然后對其進行某種固定的數學操作。下面是在實踐中可能遇到的幾種激活函數:
————————————————————————————————————————
左邊是Sigmoid非線性函數,將實數壓縮到[0,1]之間。右邊是tanh函數,將實數壓縮到[-1,1]。
————————————————————————————————————————
1.Sigmoid
sigmoid非線性函數的數學公式是,函數圖像如上圖的左邊所示。在前一節中已經提到過,它輸入實數值並將其“擠壓”到0到1范圍內。更具體地說,很大的負數變成0,很大的正數變成1。在歷史上,sigmoid函數非常常用,這是因為它對於神經元的激活頻率有良好的解釋:從完全不激活(0)到在求和后的最大頻率處的完全飽和(saturated)的激活(1)。然而現在sigmoid函數已經不太受歡迎,實際很少使用了,這是因為它有兩個主要缺點:
- 1. Sigmoid函數飽和使梯度消失。sigmoid神經元有一個不好的特性,就是當神經元的激活在接近0或1處時會飽和:在這些區域,梯度幾乎為0。回憶一下,在反向傳播的時候,這個(局部)梯度將會與整個損失函數關於該門單元輸出的梯度相乘。因此,如果局部梯度非常小,那么相乘的結果也會接近零,這會有效地“殺死”梯度,幾乎就有沒有信號通過神經元傳到權重再到數據了。還有,為了防止飽和,必須對於權重矩陣初始化特別留意。比如,如果初始化權重過大,那么大多數神經元將會飽和,導致網絡就幾乎不學習了。
- 2.Sigmoid函數的輸出不是零中心的。這個性質並不是我們想要的,因為在神經網絡后面層中的神經元得到的數據將不是零中心的。這一情況將影響梯度下降的運作,因為如果輸入神經元的數據總是正數(比如在
中每個元素都
),那么關於
的梯度在反向傳播的過程中,將會要么全部是正數,要么全部是負數(具體依整個表達式
而定)。這將會導致梯度下降權重更新時出現z字型的下降。然而,可以看到整個批量的數據的梯度被加起來后,對於權重的最終更新將會有不同的正負,這樣就從一定程度上減輕了這個問題。因此,該問題相對於上面的神經元飽和問題來說只是個小麻煩,沒有那么嚴重。
2.Tanh
tanh非線性函數圖像如上圖右邊所示。它將實數值壓縮到[-1,1]之間。和sigmoid神經元一樣,它也存在飽和問題,但是和sigmoid神經元不同的是,它的輸出是零中心的。因此,在實際操作中,tanh非線性函數比sigmoid非線性函數更受歡迎。注意tanh神經元是一個簡單放大的sigmoid神經元,具體說來就是:。
————————————————————————————————————————

左邊是ReLU(校正線性單元:Rectified Linear Unit)激活函數,當
時函數值為0。當
函數的斜率為1。右邊是從 Krizhevsky等的論文中截取的圖表,指明使用ReLU比使用tanh的收斂快6倍
——————————————————————————————————————
3.ReLU
在近些年ReLU變得非常流行。它的函數公式是。換句話說,這個激活函數就是一個關於0的閾值(如上圖左側)。
使用ReLU有以下一些優缺點:
- 優點:相較於sigmoid和tanh函數,ReLU對於隨機梯度下降的收斂有巨大的加速作用( Krizhevsky 等的論文指出有6倍之多)。據稱這是由它的線性,非飽和的公式導致的。
- 優點:sigmoid和tanh神經元含有指數運算等耗費計算資源的操作,而ReLU可以簡單地通過對一個矩陣進行閾值計算得到。
- 缺點:在訓練的時候,ReLU單元比較脆弱並且可能“死掉”。舉例來說,當一個很大的梯度流過ReLU的神經元的時候,可能會導致梯度更新到一種特別的狀態,在這種狀態下神經元將無法被其他任何數據點再次激活。如果這種情況發生,那么從此所以流過這個神經元的梯度將都變成0。也就是說,這個ReLU單元在訓練中將不可逆轉的死亡,因為這導致了數據多樣化的丟失。例如,如果學習率設置得太高,可能會發現網絡中40%的神經元都會死掉(在整個訓練集中這些神經元都不會被激活)。通過合理設置學習率,這種情況的發生概率會降低。
sigmoid偏移性導致梯度Z字形下降:簡而言之就是收斂速度會很慢,
ReLU死亡:這個神經元的輸入永遠都小於0,所以就不會被激活,也不會產生梯度更新。
4.Leaky ReLU。
Leaky ReLU是為解決“ReLU死亡”問題的嘗試。ReLU中當x<0時,函數值為0。而Leaky ReLU則是給出一個很小的負數梯度值,比如0.01。所以其函數公式為其中
是一個小的常量。有些研究者的論文指出這個激活函數表現很不錯,但是其效果並不是很穩定。Kaiming He等人在2015年發布的論文Delving Deep into Rectifiers中介紹了一種新方法PReLU,把負區間上的斜率當做每個神經元中的一個參數。然而該激活函數在在不同任務中均有益處的一致性並沒有特別清晰。
5.Maxout。
一些其他類型的單元被提了出來,它們對於權重和數據的內積結果不再使用函數形式。一個相關的流行選擇是Maxout(最近由Goodfellow等發布)神經元。Maxout是對ReLU和leaky ReLU的一般化歸納,它的函數是:
。ReLU和Leaky ReLU都是這個公式的特殊情況(比如ReLU就是當
的時候)。這樣Maxout神經元就擁有ReLU單元的所有優點(線性操作和不飽和),而沒有它的缺點(死亡的ReLU單元)。然而和ReLU對比,它每個神經元的參數數量增加了一倍,這就導致整體參數的數量激增。
以上就是一些常用的神經元及其激活函數。最后需要注意一點:在同一個網絡中混合使用不同類型的神經元是非常少見的,雖然沒有什么根本性問題來禁止這樣做。
一句話:“那么該用那種呢?”用ReLU非線性函數。注意設置好學習率,或許可以監控你的網絡中死亡的神經元占的比例。如果單元死亡問題困擾你,就試試Leaky ReLU或者Maxout,不要再用sigmoid了。也可以試試tanh,但是其效果應該不如ReLU或者Maxout。
激活函數比較:
不同激活函數形狀不同,a的取值范圍也有差異。
首先我們來比較sigmoid函數和tanh函數。
對於隱藏層的激活函數,一般來說,tanh函數要比sigmoid函數表現更好一些。因為tanh函數的取值范圍在[-1,+1]之間,隱藏層的輸出被限定在[-1,+1]之間,可以看成是在0值附近分布,均值為0。這樣從隱藏層到輸出層,數據起到了歸一化(均值為0)的效果。因此,隱藏層的激活函數,tanh比sigmoid更好一些。
而對於輸出層的激活函數,因為二分類問題的輸出取值為{0,+1},所以一般會選擇sigmoid作為激活函數。
觀察sigmoid函數和tanh函數,我們發現有這樣一個問題,就是當|z|很大的時候,激活函數的斜率(梯度)很小。因此,在這個區域內,梯度下降算法會運行得比較慢。在實際應用中,應盡量避免使z落在這個區域,使|z|盡可能限定在零值附近,從而提高梯度下降算法運算速度。
為了彌補sigmoid函數和tanh函數的這個缺陷,就出現了ReLU激活函數。ReLU激活函數在z大於零時梯度始終為1;在z小於零時梯度始終為0;z等於零時的梯度可以當成1也可以當成0,實際應用中並不影響。對於隱藏層,選擇ReLU作為激活函數能夠保證z大於零時梯度始終為1,從而提高神經網絡梯度下降算法運算速度。但當z小於零時,存在梯度為0的缺點,實際應用中,這個缺點影響不是很大。為了彌補這個缺點,出現了Leaky ReLU激活函數,能夠保證z小於零是梯度不為0。
最后總結一下,如果是分類問題,輸出層的激活函數一般會選擇sigmoid函數。但是隱藏層的激活函數通常不會選擇sigmoid函數,tanh函數的表現會比sigmoid函數好一些。實際應用中,通常會會選擇使用ReLU或者Leaky ReLU函數,保證梯度下降速度不會太小。其實,具體選擇哪個函數作為激活函數沒有一個固定的准確的答案,應該要根據具體實際問題進行驗證(validation)。
是否可以使用線性激活函數呢?
不可以
假設所有的激活函數都是線性的,經過推導使用神經網絡與直接使用線性模型的效果並沒有什么兩樣。即便是包含多層隱藏層的神經網絡,如果使用線性函數作為激活函數,最終的輸出仍然是輸入x的線性模型。這樣的話神經網絡就沒有任何作用了。因此,隱藏層的激活函數必須要是非線性的。加入線性函數,那么最后還是線性函數無法解決非線性問題,所以需要加入非線性函數~
另外,如果所有的隱藏層全部使用線性激活函數,只有輸出層使用非線性激活函數,那么整個神經網絡的結構就類似於一個簡單的邏輯回歸模型,而失去了神經網絡模型本身的優勢和價值。
值得一提的是,如果是預測問題而不是分類問題,輸出y是連續的情況下,輸出層的激活函數可以使用線性函數。如果輸出y恆為正值,則也可以使用ReLU激活函數,具體情況,具體分析。
神經網絡模型中的參數權重W是不能全部初始化為零的,
參數b可以全部初始化為零,並不會影響神經網絡訓練效果。
-->解決方法也很簡單,就是將W進行隨機初始化(b可初始化為零)。
W_1 = np.random.randn((2,2))*0.01 b_1 = np.zero((2,1)) W_2 = np.random.randn((1,2))*0.01 b_2 = 0
這里我們將W1和W2矩陣乘以0.01的目的是盡量使得權重W初始化比較小的值。之所以讓W比較小,是因為如果使用sigmoid函數或者tanh函數作為激活函數的話,W比較小,得到的|z|也比較小(靠近零點),而零點區域的梯度比較大,這樣能大大提高梯度下降算法的更新速度,盡快找到全局最優解。如果W較大,得到的|z|也比較大,附近曲線平緩,梯度較小,訓練過程會慢很多。
當然,如果激活函數是ReLU或者Leaky ReLU函數,則不需要考慮這個問題。但是,如果輸出層是sigmoid函數,則對應的權重W最好初始化到比較小的值。
斯坦福CS231n項目實戰(四):淺層神經網絡
二、神經網絡意義 擁有至少一個隱層的神經網絡是一個通用的近似器
在研究(例如1989年的論文Approximation by Superpositions of Sigmoidal Function,或者Michael Nielsen的這個直觀解釋。)中已經證明,給出任意連續函數和任意
,均存在一個至少含1個隱層的神經網絡
(並且網絡中有合理選擇的非線性激活函數,比如sigmoid),對於
,使得
。換句話說,神經網絡可以近似任何連續函數。
既然一個隱層就能近似任何函數,那為什么還要構建更多層來將網絡做得更深?答案是:雖然一個2層網絡在數學理論上能完美地近似所有連續函數,但在實際操作中效果相對較差。在一個維度上,雖然以為參數向量“指示塊之和”函數
也是通用的近似器,但是誰也不會建議在機器學習中使用這個函數公式。神經網絡在實踐中非常好用,是因為它們表達出的函數不僅平滑,而且對於數據的統計特性有很好的擬合。同時,網絡通過最優化算法(例如梯度下降)能比較容易地學習到這個函數。類似的,雖然在理論上深層網絡(使用了多個隱層)和單層網絡的表達能力是一樣的,但是就實踐經驗而言,深度網絡效果比單層網絡好。
另外,在實踐中3層的神經網絡會比2層的表現好,然而繼續加深(做到4,5,6層)很少有太大幫助。卷積神經網絡的情況卻不同,在卷積神經網絡中,對於一個良好的識別系統來說,深度是一個極端重要的因素(比如數十(以10為量級)個可學習的層)。對於該現象的一種解釋觀點是:因為圖像擁有層次化結構(比如臉是由眼睛等組成,眼睛又是由邊緣組成),所以多層處理對於這種數據就有直觀意義。
三、過擬合(Overfitting)vs 泛化(generalization)
如果數據不是足夠復雜,則似乎小一點的網絡更好,因為可以防止過擬合。然而並非如此,防止神經網絡的過擬合有很多方法(L2正則化,dropout和輸入噪音等)。在實踐中,使用這些方法來控制過擬合比減少網絡神經元數目要好得多。
不要減少網絡神經元數目的主要原因在於小網絡更難使用梯度下降等局部方法來進行訓練:雖然小型網絡的損失函數的局部極小值更少,也比較容易收斂到這些局部極小值,但是這些最小值一般都很差,損失值很高。相反,大網絡擁有更多的局部極小值,但就實際損失值來看,這些局部極小值表現更好,損失更小。因為神經網絡是非凸的,就很難從數學上研究這些特性。
更大網絡總是更好。然而更大容量的模型一定要和更強的正則化(比如更高的權重衰減)配合,否則它們就會過擬合。(dropout是正則化)
CS231n課程筆記翻譯:神經網絡筆記 2
四、神經網絡訓練過程
1.數據預處理
均值減法
歸一化 第一種是先對數據做零中心化(zero-centered)處理,然后每個維度都除以其標准差,實現代碼為X /= np.std(X, axis=0)。第二種方法是對每個維度都做歸一化,使得每個維度的最大和最小值是1和-1。
PCA和白化
在這種處理中,先對數據進行零中心化處理,然后計算協方差矩陣,它展示了數據中的相關性結構。
# 假設輸入數據矩陣X的尺寸為[N x D] X -= np.mean(X, axis = 0) # 對數據進行零中心化(重要) cov = np.dot(X.T, X) / X.shape[0] # 得到數據的協方差矩陣
數據協方差矩陣的第(i, j)個元素是數據第i個和第j個維度的協方差。具體來說,該矩陣的對角線上的元素是方差。還有,協方差矩陣是對稱和半正定的。我們可以對數據協方差矩陣進行SVD(奇異值分解)運算。
U,S,V = np.linalg.svd(cov)
U的列是特征向量,S是裝有奇異值的1維數組(因為cov是對稱且半正定的,所以S中元素是特征值的平方)。為了去除數據相關性,將已經零中心化處理過的原始數據投影到特征基准上:
Xrot = np.dot(X,U) # 對數據去相關性
注意U的列是標准正交向量的集合(范式為1,列之間標准正交),所以可以把它們看做標准正交基向量。因此,投影對應x中的數據的一個旋轉,旋轉產生的結果就是新的特征向量。
np.linalg.svd的一個良好性質是在它的返回值U中,特征向量是按照特征值的大小排列的。我們可以利用這個性質來對數據降維,只要使用前面的小部分特征向量,丟棄掉那些包含的數據沒有方差的維度。 這個操作也被稱為主成分分析( Principal Component Analysis 簡稱PCA)降維:
Xrot_reduced = np.dot(X, U[:,:100]) # Xrot_reduced 變成 [N x 100]
經過上面的操作,將原始的數據集的大小由[N x D]降到了[N x 100],留下了數據中包含最大方差的100個維度。
白化(whitening)。白化操作的輸入是特征基准上的數據,然后對每個維度除以其特征值來對數值范圍進行歸一化。該變換的幾何解釋是:如果數據服從多變量的高斯分布,那么經過白化后,數據的分布將會是一個均值為零,且協方差相等的矩陣。該操作的代碼如下:
# 對數據進行白化操作: # 除以特征值 Xwhite = Xrot / np.sqrt(S + 1e-5)
注意分母中添加了1e-5(或一個更小的常量)來防止分母為0。
該變換的一個缺陷是在變換的過程中可能會誇大數據中的噪聲,這是因為它將所有維度都拉伸到相同的數值范圍,這些維度中也包含了那些只有極少差異性(方差小)而大多是噪聲的維度。
實踐操作。在這個筆記中提到PCA和白化主要是為了介紹的完整性,實際上在卷積神經網絡中並不會采用這些變換。然而對數據進行零中心化操作還是非常重要的,對每個像素進行歸一化也很常見。
常見錯誤。進行預處理很重要的一點是:任何預處理策略(比如數據均值)都只能在訓練集數據上進行計算,算法訓練完畢后再應用到驗證集或者測試集上。例如,如果先計算整個數據集圖像的平均值然后每張圖片都減去平均值,最后將整個數據集分成訓練/驗證/測試集,那么這個做法是錯誤的。應該怎么做呢?應該先分成訓練/驗證/測試集,只是從訓練集中求圖片平均值,然后各個集(訓練/驗證/測試集)中的圖像再減去這個平均值。
2.權重初始化
錯誤:全零初始化。
因為如果網絡中的每個神經元都計算出同樣的輸出,然后它們就會在反向傳播中計算出同樣的梯度,從而進行同樣的參數更新。換句話說,如果權重被初始化為同樣的值,神經元之間就失去了不對稱性的源頭。
小隨機數初始化。
因此,權重初始值要非常接近0又不能等於0。解決方法就是將權重初始化為很小的數值,以此來打破對稱性。
其思路是:如果神經元剛開始的時候是隨機且不相等的,那么它們將計算出不同的更新,並將自身變成整個網絡的不同部分。小隨機數權重初始化的實現方法是:W = 0.01 * np.random.randn(D,H)。其中randn函數是基於零均值和標准差的一個高斯分布來生成隨機數的。
也可以使用均勻分布生成的隨機數,但是從實踐結果來看,對於算法的結果影響極小。
警告。並不是小數值一定會得到好的結果。例如,一個神經網絡的層中的權重值很小,那么在反向傳播的時候就會計算出非常小的梯度(因為梯度與權重值是成比例的)。這就會很大程度上減小反向傳播中的“梯度信號”,在深度網絡中,就會出現問題。
使用1/sqrt(n)校准方差。上面做法存在一個問題,隨着輸入數據量的增長,隨機初始化的神經元的輸出數據的分布中的方差也在增大。我們可以除以輸入數據量的平方根來調整其數值范圍,這樣神經元輸出的方差就歸一化到1了。也就是說,建議將神經元的權重向量初始化為:w = np.random.randn(n) / sqrt(n)。其中n是輸入數據的數量。這樣就保證了網絡中所有神經元起始時有近似同樣的輸出分布。實踐經驗證明,這樣做可以提高收斂的速度。
偏置(biases)的初始化。通常將偏置b初始化為0
批量歸一化(Batch Normalization)。批量歸一化是loffe和Szegedy最近才提出的方法,該方法減輕了如何合理初始化神經網絡這個棘手問題帶來的頭痛:),其做法是讓激活數據在訓練開始前通過一個網絡,網絡處理數據使其服從標准高斯分布。因為歸一化是一個簡單可求導的操作,所以上述思路是可行的。
在實現層面,應用這個技巧通常意味着全連接層(或者是卷積層,后續會講)與激活函數之間添加一個BatchNorm層。
3.正則化
L1L2
最大范式約束(Max norm constraints)。另一種形式的正則化是給每個神經元中權重向量的量級設定上限,並使用投影梯度下降來確保這一約束。在實踐中,與之對應的是參數更新方式不變,然后要求神經元中的權重向量必須滿足
這一條件,一般
值為3或者4。有研究者發文稱在使用這種正則化方法時效果更好。這種正則化還有一個良好的性質,即使在學習率設置過高的時候,網絡中也不會出現數值“爆炸”,這是因為它的參數更新始終是被限制着的。
隨機失活(Dropout)是一個簡單又極其有效的正則化方法。該方法由Srivastava在論文Dropout: A Simple Way to Prevent Neural Networks from Overfitting中提出的,與L1正則化,L2正則化和最大范式約束等方法互為補充。在訓練的時候,隨機失活的實現方法是讓神經元以超參數的概率被激活或者被設置為0。
注意:在預測時不進行隨機失活,因此對於兩個隱層的輸出都要乘以,調整其數值范圍。這一點非常重要,因為在測試時所有的神經元都能看見它們的輸入,因此我們想要神經元的輸出與訓練時的預期輸出是一致的。
""" 普通版隨機失活: 不推薦實現 (看下面筆記) """ p = 0.5 # 激活神經元的概率. p值更高 = 隨機失活更弱 def train_step(X): """ X中是輸入數據 """ # 3層neural network的前向傳播 H1 = np.maximum(0, np.dot(W1, X) + b1) U1 = np.random.rand(*H1.shape) < p # 第一個隨機失活遮罩 H1 *= U1 # drop! H2 = np.maximum(0, np.dot(W2, H1) + b2) U2 = np.random.rand(*H2.shape) < p # 第二個隨機失活遮罩 H2 *= U2 # drop! out = np.dot(W3, H2) + b3 # 反向傳播:計算梯度... (略) # 進行參數更新... (略) def predict(X): # 前向傳播時模型集成 H1 = np.maximum(0, np.dot(W1, X) + b1) * p # 注意:激活數據要乘以p H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # 注意:激活數據要乘以p out = np.dot(W3, H2) + b3
反向隨機失活(inverted dropout),它是在訓練時就進行數值范圍調整 除以p,從而讓前向傳播在測試時保持不變。這樣做還有一個好處,無論你決定是否使用隨機失活,預測方法的代碼可以保持不變。
""" 反向隨機失活: 推薦實現方式. 在訓練的時候drop和調整數值范圍,測試時不做任何事. """ p = 0.5 # 激活神經元的概率. p值更高 = 隨機失活更弱 def train_step(X): # 3層neural network的前向傳播 H1 = np.maximum(0, np.dot(W1, X) + b1) U1 = (np.random.rand(*H1.shape) < p) / p # 第一個隨機失活遮罩. 注意/p! H1 *= U1 # drop! H2 = np.maximum(0, np.dot(W2, H1) + b2) U2 = (np.random.rand(*H2.shape) < p) / p # 第二個隨機失活遮罩. 注意/p! H2 *= U2 # drop! out = np.dot(W3, H2) + b3 # 反向傳播:計算梯度... (略) # 進行參數更新... (略) def predict(X): # 前向傳播時模型集成 H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用數值范圍調整了 H2 = np.maximum(0, np.dot(W2, H1) + b2) out = np.dot(W3, H2) + b3
CS231n課程筆記翻譯:神經網絡筆記3(上)
4.梯度檢查(Gradient Checking)
概念:
理論上將進行梯度檢查很簡單,就是簡單地把解析梯度和數值計算梯度進行比較。然而從實際操作層面上來說,這個過程更加復雜且容易出錯。
1.f'使用中心化公式。在使用有限差值近似來計算數值梯度的時候,常見的公式是:
其中是一個很小的數字,在實踐中近似為1e-5。在實踐中證明,使用中心化公式效果更好:
該公式在檢查梯度的每個維度的時候,會要求計算兩次損失函數(所以計算資源的耗費也是兩倍),但是梯度的近似值會准確很多。要理解這一點,對和
使用泰勒展開,可以看到第一個公式的誤差近似
,第二個公式的誤差近似
(是個二階近似)。
2.使用相對誤差來比較。比較數值梯度和解析梯度
的細節有哪些?如何得知此兩者不匹配?你可能會傾向於監測它們的差的絕對值
或者差的平方值,然后定義該值如果超過某個規定閾值,就判斷梯度實現失敗。然而該思路是有問題的。想想,假設這個差值是1e-4,如果兩個梯度值在1.0左右,這個差值看起來就很合適,可以認為兩個梯度是匹配的。然而如果梯度值是1e-5或者更低,那么1e-4就是非常大的差距,梯度實現肯定就是失敗的了。因此,使用相對誤差總是更合適一些:
3.使用雙精度
4.保持在浮點數的有效范圍
5.謹慎設置步長h。在實踐中h並不是越小越好,因為當特別小的時候,就可能就會遇到數值精度問題。
有時候如果梯度檢查無法進行,可以試試將調到1e-4或者1e-6
6.目標函數存在不可導點(kinks)。
使用少量數據點:解決上面的不可導點問題的一個辦法是使用更少的數據點。因為含有不可導點的損失函數(例如:因為使用了ReLU或者邊緣損失等函數)的數據點越少,不可導點就越少,所以在計算有限差值近似時越過不可導點的幾率就越小。還有,如果你的梯度檢查對2-3個數據點都有效,那么基本上對整個批量數據進行梯度檢查也是沒問題的。所以使用很少量的數據點,能讓梯度檢查更迅速高效。
7.不要讓正則化吞沒數據。通常損失函數是數據損失和正則化損失的和(例如L2對權重的懲罰)。需要注意的危險是正則化損失可能吞沒掉數據損失,在這種情況下梯度主要來源於正則化部分(正則化部分的梯度表達式通常簡單很多)。這樣就會掩蓋掉數據損失梯度的不正確實現。因此,推薦先關掉正則化對數據損失做單獨檢查,然后對正則化做單獨檢查。對於正則化的單獨檢查可以是修改代碼,去掉其中數據損失的部分,也可以提高正則化強度,確認其效果在梯度檢查中是無法忽略的,這樣不正確的實現就會被觀察到了。
8.記得關閉隨機失活(dropout)和數據擴張(augmentation)。在進行梯度檢查時,記得關閉網絡中任何不確定的效果的操作,比如隨機失活,隨機數據擴展等。不然它們會在計算數值梯度的時候導致巨大誤差。關閉這些操作不好的一點是無法對它們進行梯度檢查(例如隨機失活的反向傳播實現可能有錯誤)。因此,一個更好的解決方案就是在計算和
前強制增加一個特定的隨機種子,在計算解析梯度時也同樣如此。
9.只檢查部分維度。在實際中,梯度可以有上百萬的參數,在這種情況下只能檢查其中一些維度然后假設其他維度是正確的。
注意:確認在所有不同的參數中都抽取一部分來梯度檢查。在某些應用中,為了方便,人們將所有的參數放到一個巨大的參數向量中。在這種情況下,例如偏置就可能只占用整個向量中的很小一部分,所以不要隨機地從向量中取維度,一定要把這種情況考慮到,確保所有參數都收到了正確的梯度。
在之后的圖表中,x軸通常都是表示周期(epochs)單位,該單位衡量了在訓練中每個樣本數據都被觀察過次數的期望(一個周期意味着每個樣本數據都被觀察過了一次)。相較於迭代次數(iterations),一般更傾向跟蹤周期,這是因為迭代次數與數據的批尺寸(batchsize)有關,而批尺寸的設置又可以是任意的。
5.合理性檢查的提示與技巧
在進行費時費力的最優化之前,最好進行一些合理性檢查:
-
尋找特定情況的正確損失值。在使用小參數進行初始化時,確保得到的損失值與期望一致。最好先單獨檢查數據損失(讓正則化強度為0)。例如,對於一個跑CIFAR-10的Softmax分類器,一般期望它的初始損失值是2.302,這是因為初始時預計每個類別的概率是0.1(因為有10個類別),然后Softmax損失值正確分類的負對數概率:-ln(0.1)=2.302。對於Weston Watkins SVM,假設所有的邊界都被越過(因為所有的分值都近似為零),所以損失值是9(因為對於每個錯誤分類,邊界值是1)。如果沒看到這些損失值,那么初始化中就可能有問題。
-
第二個合理性檢查:提高正則化強度時導致損失值變大。
-
對小數據子集過擬合。最后也是最重要的一步,在整個數據集進行訓練之前,嘗試在一個很小的數據集上進行訓練(比如20個數據),然后確保能到達0的損失值。進行這個實驗的時候,最好讓正則化強度為0,不然它會阻止得到0的損失。除非能通過這一個正常性檢查,不然進行整個數據集訓練是沒有意義的。但是注意,能對小數據集進行過擬合並不代表萬事大吉,依然有可能存在不正確的實現。比如,因為某些錯誤,數據點的特征是隨機的,這樣算法也可能對小數據進行過擬合,但是在整個數據集上跑算法的時候,就沒有任何泛化能力。
6.檢查整個學習過程
1.損失函數
訓練期間第一個要跟蹤的數值就是損失值,它在前向傳播時對每個獨立的批數據進行計算。下圖展示的是隨着損失值隨時間的變化,尤其是曲線形狀會給出關於學習率設置的情況:
左圖展示了不同的學習率的效果。過低的學習率導致算法的改善是線性的。高一些的學習率會看起來呈幾何指數下降,更高的學習率會讓損失值很快下降,但是接着就停在一個不好的損失值上(綠線)。這是因為最優化的“能量”太大,參數在混沌中隨機震盪,不能最優化到一個很好的點上。
右圖顯示了一個典型的隨時間變化的損失函數值,在CIFAR-10數據集上面訓練了一個小的網絡,這個損失函數值曲線看起來比較合理(雖然可能學習率有點小,但是很難說),而且指出了批數據的數量可能有點太小(因為損失值的噪音很大)。
損失值的震盪程度和批尺寸(batch size)有關,當批尺寸為1,震盪會相對較大。當批尺寸就是整個數據集時震盪就會最小,因為每個梯度更新都是單調地優化損失函數(除非學習率設置得過高)。
有的研究者喜歡用對數域對損失函數值作圖。因為學習過程一般都是采用指數型的形狀,圖表就會看起來更像是能夠直觀理解的直線,而不是呈曲棍球一樣的曲線狀。還有,如果多個交叉驗證模型在一個圖上同時輸出圖像,它們之間的差異就會比較明顯。
2.訓練集和驗證集准確率
在訓練分類器的時候,需要跟蹤的第二重要的數值是驗證集和訓練集的准確率。這個圖表能夠展現知道模型過擬合的程度:
————————————————————————————————————————
在訓練集准確率和驗證集准確率中間的空隙指明了模型過擬合的程度。
在圖中,藍色的驗證集曲線顯示相較於訓練集,驗證集的准確率低了很多,這就說明模型有很強的過擬合。遇到這種情況,就應該增大正則化強度(更強的L2權重懲罰,更多的隨機失活等)或收集更多的數據。另一種可能就是驗證集曲線和訓練集曲線如影隨形,這種情況說明你的模型容量還不夠大:應該通過增加參數數量(增加模型復雜度)讓模型容量更大些。
3.權重更新比例
最后一個應該跟蹤的量是權重中更新值的數量和全部值的數量之間的比例。注意:是更新的,而不是原始梯度(比如,在普通sgd中就是梯度乘以學習率)。需要對每個參數集的更新比例進行單獨的計算和跟蹤。一個經驗性的結論是這個比例應該在1e-3左右。如果更低,說明學習率可能太小,如果更高,說明學習率可能太高。下面是具體例子:
# 假設參數向量為W,其梯度向量為dW param_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左右
4.每層的激活數據及梯度分布
一個不正確的初始化可能讓學習過程變慢,甚至徹底停止。還好,這個問題可以比較簡單地診斷出來。其中一個方法是輸出網絡中所有層的激活數據和梯度分布的柱狀圖。直觀地說,就是如果看到任何奇怪的分布情況,那都不是好兆頭。比如,對於使用tanh的神經元,我們應該看到激活數據的值在整個[-1,1]區間中都有分布。如果看到神經元的輸出全部是0,或者全都飽和了往-1和1上跑,那肯定就是有問題了。
7.損失函數
我們已經討論過損失函數的正則化損失部分,它可以看做是對模型復雜程度的某種懲罰。損失函數的第二個部分是數據損失,它是一個有監督學習問題,用於衡量分類算法的預測結果(即分類評分)和真實標簽結果之間的一致性。數據損失是對所有樣本的數據損失求平均。也就是說,中,
是訓練集數據的樣本數。讓我們把神經網絡中輸出層的激活函數簡寫為
,在實際中你可能需要解決以下幾類問題:
1.分類問題
在該問題中,假設有一個裝滿樣本的數據集,每個樣本都有一個唯一的正確標簽(是固定分類標簽之一)。
在這類問題中,一個最常見的損失函數就是SVM(是Weston Watkins 公式):
之前簡要提起過,有些學者的論文中指出平方折葉損失(即使用)算法的結果會更好。
第二個常用的損失函數是Softmax分類器,它使用交叉熵損失:
問題:類別數目巨大。
當標簽集非常龐大(例如字典中的所有英語單詞,或者ImageNet中的22000種分類),就需要使用分層Softmax(Hierarchical Softmax)了(參考文獻)。分層softmax將標簽分解成一個樹。每個標簽都表示成這個樹上的一個路徑,這個樹的每個節點處都訓練一個Softmax分類器來在左和右分枝之間做決策。樹的結構對於算法的最終結果影響很大,而且一般需要具體問題具體分析。
屬性(Attribute)分類
上面兩個損失公式的前提,都是假設每個樣本只有一個正確的標簽。但是如果
是一個二值向量,每個樣本可能有,也可能沒有某個屬性,而且屬性之間並不相互排斥呢?比如在Instagram上的圖片,就可以看成是被一個巨大的標簽集合中的某個子集打上標簽,一張圖片上可能有多個標簽。在這種情況下,一個明智的方法是為每個屬性創建一個獨立的二分類的分類器。例如,針對每個分類的二分類器會采用下面的公式:
上式中,求和是對所有分類,
的值為1或者-1,具體根據第i個樣本是否被第j個屬性打標簽而定,當該類別被正確預測並展示的時候,分值向量
為正,其余情況為負。可以發現,當一個正樣本的得分小於+1,或者一個負樣本得分大於-1的時候,算法就會累計損失值。
另一種方法是對每種屬性訓練一個獨立的邏輯回歸分類器。二分類的邏輯回歸分類器只有兩個分類(0,1),其中對於分類1的概率計算為:
因為類別0和類別1的概率和為1,所以類別0的概率為:。這樣,如果
或者
,那么樣本就要被分類成為正樣本(y=1)。然后損失函數最大化這個對數似然函數,問題可以簡化為:
上式中,假設標簽非0即1,
就是sigmoid函數。上面的公式看起來嚇人,但是
的梯度實際上非常簡單:
(你可以自己求導來驗證)。
2.回歸問題是預測實數的值的問題,比如預測房價,預測圖片中某個東西的長度等。
對於這種問題,通常是計算預測值和真實值之間的損失。然后用L2平方范式或L1范式度量差異。對於某個樣本,L2范式計算如下:
之所以在目標函數中要進行平方,是因為梯度算起來更加簡單。因為平方是一個單調運算,所以不用改變最優參數。L1范式則是要將每個維度上的絕對值加起來:
在上式中,如果有多個數量被預測了,就要對預測的所有維度的預測求和,即。觀察第i個樣本的第j維,用
表示預測值與真實值之間的差異。關於該維度的梯度(也就是
)能夠輕松地通過被求導為L2范式的
或
。這就是說,評分值的梯度要么與誤差中的差值直接成比例,要么是固定的並從差值中繼承sign。
注意:L2損失比起較為穩定的Softmax損失來,其最優化過程要困難很多。直觀而言,它需要網絡具備一個特別的性質,即對於每個輸入(和增量)都要輸出一個確切的正確值。而在Softmax中就不是這樣,每個評分的准確值並不是那么重要:只有當它們量級適當的時候,才有意義。還有,L2損失魯棒性不好,因為異常值可以導致很大的梯度。所以在面對一個回歸問題時,先考慮將輸出變成二值化是否真的不夠用。例如,如果對一個產品的星級進行預測,使用5個獨立的分類器來對1-5星進行打分的效果一般比使用一個回歸損失要好很多。分類還有一個額外優點,就是能給出關於回歸的輸出的分布,而不是一個簡單的毫無把握的輸出值。如果確信分類不適用,那么使用L2損失吧,但是一定要謹慎:L2非常脆弱,在網絡中使用隨機失活(尤其是在L2損失層的上一層)不是好主意。
當面對一個回歸任務,首先考慮是不是必須這樣。一般而言,盡量把你的輸出變成二分類,然后對它們進行分類,從而變成一個分類問題。
3.結構化預測(structured prediction)
結構化損失是指標簽可以是任意的結構,例如圖表、樹或者其他復雜物體的情況。通常這種情況還會假設結構空間非常巨大,不容易進行遍歷。結構化SVM背后的基本思想就是在正確的結構和得分最高的非正確結構之間畫出一個邊界。解決這類問題,並不是像解決一個簡單無限制的最優化問題那樣使用梯度下降就可以了,而是需要設計一些特殊的解決方案,這樣可以有效利用對於結構空間的特殊簡化假設。我們簡要地提一下這個問題,但是詳細內容就超出本課程范圍。