1.生物學解釋
神經網絡中的神經元(neurons):從輸入(如圖像)得到的一個輸出最小單元稱之爲一個神經元。具體一點說,對於一個雙層網絡(1輸入、1中間層、1輸出),如果輸入爲一個樣本,則隱藏層的維數H+最終輸出維度數C,就是神經元的個數。一個神經元包括所需要的所有參數;包括一組
樹突:
軸突:
The idea is that the synaptic strengths (the weights ww) are learnable and control the strength of influence (and its direction: excitory (positive weight) or inhibitory (negative weight)) of one neuron on another.當累加到一定程度後,輸出激活(由激活函數控制),將輸出傳到下一個神經元的突觸(
由於算出結果只是一個標量,所以一個神經元的輸出可以處理成概率(如softmax等),可以進行對一幅圖進行二分類。
SVM可以看做是單層神經網絡(沒有中間層,只有輸入輸出層,由於不必考慮輸入,所以是單層)。
2.圖像數據預處理
零中心值化的作用:
由於對W求導數是
如圖,我們需要不同方向的x(紅色),來使得最終的下降方向接近最優方向(藍色)圖:
具體做法是(灰度圖)減去所有值的平均值,或(彩色圖)RGB等channel分別減去各自channel的平均值。也可以從train數據中選一批圖像來做訓練。
PCA and Whitenning
如圖,對於輸入圖像xi和xj,他們的協方差矩陣爲:
所以PCA預處理過程爲
# Assume input data matrix X of size [N x D]
X -= np.mean(X, axis = 0) # zero-center the data (important)
cov = np.dot(X.T, X) / X.shape[0] # get the data covariance matrix
由於cov是半正定的,對其進行svd分解,可以得到特徵向量U,U各個維度相互正交。然後可以對數據進行去耦合,所謂去耦合,直觀上是將數據進行一定旋轉,具體方法是將各個數據維度投影到/乘上新的座標軸U(得到結果如中間的圖,x軸與y軸整體上已經沒有相關性):
U,S,V = np.linalg.svd(cov)
Xrot = np.dot(X, U) # decorrelate the data
同時由於U已經按照對應特徵值的權重進行了排序,因此我們可以選擇前n個權重較大的軸/維度,捨棄剩下部分,以達到降維目的。
Xrot_reduced = np.dot(X, U[:,:100]) # Xrot_reduced becomes [N x 100]
將這些數據歸一化(除以各自座標軸的權重),同時爲了避免權重爲0,可以加上一個白噪聲處理。【在降低維度階段就消除這些爲0或過小的維度?】
Xwhite = Xrot / np.sqrt(S + 1e-5)
整個過程相當於消除了低頻信號(圖像中梯度比較小的部分),增強高頻信號(特徵點、線)。
Batch Normalization
如果在每一層輸入的時候,先加個預處理操作,比如網絡第三層輸入數據X3(X3表示網絡第三層的輸入數據)把它歸一化至:均值0、方差爲1,然後再輸入第三層計算,這樣我們就可以解決前面所提到的“Internal Covariate Shift”的問題了。一般講BN放在全連接層和非線性函數之間
如圖:
如果認爲每個輸入都需要在相同的scale區間(比如[-1,1]),如不同圖片的光照條件差別很大,則可以對圖像進行normalization.
normalization的好處:
提高梯度平滑度;
減少強相關;
可以使用更高的學習率;
再說兩句
一般預處理是隻對train數據進行零均值化,得到的均值用來處理validation和test數據。
3.初始化
由於反向傳播時對x的梯度就是w,所以w需要進行一些初始化,一般認爲w應該整體上以0對稱分佈,同時不能太大,也不能太小。如果認爲輸入和結果都滿足標準高斯分佈的話,那麼w的方差即是1/n,則標準差/平均值爲1/sqrt(n)
所以對於類似tanh的激活函數,一般初始化成:
而對於Relu函數,由於分佈不同,一般初始化爲:
w = np.random.randn(n) * sqrt(2.0/n)
此外還有隨機遊走、數據關聯等方法來初始化。
而對b來說,一般初始化爲0.
4.正則化
正則化的
L1和L2正則化的使用區別
L1會導致一個比較稀疏的結果,也就是最終的w使得該系統更青睞於那些更重要高的輸入;相比之下L2更容易導致一個比較均勻的w。如果無法明確知道輸入有明顯的feature特性,就用L2吧。
Max norm constraints
即對w元素的最大值進行上界限制。
Dropout
在訓練時用一個概率p來丟棄某些參數,比如
H1*(np.random.rand(*H1.SHAPE)
5.調參
對於一個給定的模型框架,需要調試的參數包括:最初的學習率,學習率下降框架,正則項權重,droput項參數;對於一個給定的工作,需要的調參還包括初始值,訓練次數,神經網絡總層數包括每層的神經元個數
在設計程序時,需要設計一個worker部分來不斷地嘗試不同參數並記錄並輸出最終結果(時間、精確度等)到文件,同時一些worker在validation上驗證最終結果;並同時設計一個master來開啓或殺掉集羣中的這些workers.
先不加正則項來測試loss和grad;單獨調正則項確定它的權重,
確定grad沒問題時,現在一個小集合上訓練:
loss not going down:
- learning rate too low
loss exploding:
- learning rate too high
同時,需要調:
不同的初始化
coarse to fine:先挑一小部分數據跑,再在所有數據上跑;如故loss>3*original_cost
Prefer random search to grid search
梯度檢查:
對2層網絡來說:
relative error > 1e-2 usually means the gradient is probably wrong
but usually means the gradient is probably wrong
relative error < 1e-4 OK
but if ther are activation function, then relative error <1e-7 may be ok.
對多層網絡來說:
深度越深,可容納的誤差越大,比如10層網絡,1e-2可能就差不多了。
調學習率
x += -learning_rate * dx;#一般情況
Momentum update(動量下降):
直觀上我們能感受到整個下降過程的斜率變化越來越小,所以可以近似看做是一個減速運動模型
v = mu * v -learning_rate * dx
x += v
mu即是動量momentum,是一個待調試的hyperparameter(常常在0.9左右,所以常常在交叉驗證時設置爲[0.5,0,9,0.95,0.99])
動量下降可以極大加快下降速度
Nesterov Momentum
x_ahead = x + mu * v
# evaluate dx_ahead (the gradient at x_ahead instead of at x)
v = mu * v - learning_rate * dx_ahead
x += v
mu越大,表示越相信之前的迭代速度,也就是慣性越大
x_ahead = x + mu * v
dx = ....#calculate the gradient based ahead x.
v_prev = v # back this up
v = mu * v - learning_rate * dx # velocity update stays the same
x += mv*(v- v_prev) + v # position update changes form
AdaGrad (不常用)
相當於對之前的”速度”,也就是梯度,求平均值,那麼隨着梯度降低,最後的梯度也會越來越小沒速度也越來越小。假如有很多局部最優解呢,AdaGrad隨着時間,速度快速下降的特性會侷限在局部最優解中。下面是對它的改進
RMSProp
將上一次梯度下降速度融入到當前速度中,這樣會減緩速度的下降。
Adam(最常用)
相當於對(某個變量)下降速度和下降梯度平方之間進行一個權衡,使得變量迭代得更加平滑。此處的first_moment相當於下降速度,第二個相當於下降速度的速度。初值設置時需要注意:不能將moment2的初值設爲0,而要設一個很小的正數。
否則第一次迭代後分母過大會導致x的步長太大。
此外還有變種:Adamax,Nadam
還有一種全的方法
Adam比較常用
annealing/decay the learning rate(降低學習率)
有單步降低:a_{i+1} = a_0 - t * decay_a#t 是迭代次數
指數降低: a = a_0* e^{-kt}
常用的是單步降低,先跑一遍,得到一個比較合適的a,再降低decay_a來進一步得到合適的a。
可以先不用學習率的decay,看看下降情況,再使用上述各種decay方法。
L-BFGS(目前比較popular的limited memory的擬牛頓方法)
在相比小數據集,它在大數據集上表現比較好,也就是需要在很大的batch上甚至全局上進行計更新算;在非凸問題上表現不佳
根據結果繼續調參
過擬合
如果train精度與test精度的gap過大,則可能存在過擬合:
更深層的網絡容易出現過擬合現象,數據稀少也會造成過擬合。
- 使用淺層的網絡
- 增加訓練數據嗎,或者增加訓練/測試數據的比值
- 增加正則項權重
- 更多的dropout來阻止過擬合
- batch normalization
- data augmentation(即生成更多樣性的數據,比如一個貓的鏡像、平移、旋轉等等)
- max pooling
- 殘差網絡
一般先使用batch normalization,如果還不足夠,則加上其他功能。
如果模板比較模糊,可能是
最後模型集成(model ensembles)
模型集成有助於利用不同的參數
可以通過不同的方式訓練形成10個不同的model,然後將這些model加起來取平均值得到的效果可能好於一個model.
不同的模板的方法有
- 單一模型但不同的初始化;
- 通過交叉驗證在不同數據集上生成的模型;
- 每個模型之後設置不同的checkponits
transfer trainning
如果數據量很小,可以先看做類似目標(如分類)的已經訓練好的模型在數據也很相似的很大的數據上的參數。由於自己處理的任務可能只是它的任務的子集(比如它分成1000類,我只分成10類)以及自己數據量也比較小,自己可以只調這個模型的部分層的參數(如頭幾層):圖: