1. 激活函數
1.1. 為什么需要激活函數(激勵函數)
在神經網絡中,對於圖像,我們主要采用了卷積的方式來處理,也就是對每個像素點賦予一個權值,這個操作顯然就是線性的。但是對於我們的樣本來說,不一定是線性可分的,為了解決這個問題,我們可以進行線性變化,或者我們引入非線性因素,解決線性模型所不能解決的問題。
這就是為什么要有激活函數:激活函數是用來加入非線性因素的,因為線性模型的表達力不夠。
所以激活函數,並不是去激活什么,而是指如何把“激活的神經元的特征”通過函數把特征保留並映射出來(保留特征,去除一些數據中是的冗余),這是神經網絡能解決非線性問題關鍵。
1.1.1. ReLU
簡稱為“抹零” 😃
優點:
- 相較於sigmoid和tanh函數,relu對於SGD(梯度下降優化算法) 的收斂有巨大的加速作用(Alex Krizhevsky指出有6倍之多)。有人認為這是由它的線性、非飽和的公式導致的。
- 相比於sigmoid和tanh,relu只需要一個閾值就可以得到激活值,而不用去算一大堆復雜的(指數)運算。
- relu在x<0時是硬飽和。當x>0時一階導數為1,所以relu函數在x>0時可以保持梯度不衰減,從而有效緩解了梯度消失的問題。
- 在沒有無監督預訓練的時候也能有較好的表現。
- 提供了神經網絡的稀疏表達能力。
缺點:隨着訓練的進行,部分輸入會落到硬飽和區,導致對應的權重無法更新。我們稱之為“神經元死亡”。
實際中,如果學習率設置得太高,可能會發現網絡中 40% 的神經元都會死掉(在整個訓練集中這些神經元都不會被激活)。合理設置學習率,會降低這種情況的發生概率。
除了relu本身外,TensorFlow后續又有相關ReLU衍生的激活函數,比如:ReLU6、SReLU、Leaky ReLU 、PReLU、RReLU、CReLU。
LReLU、PReLU與RReLU是relu激活函數的改進版本,圖像如下:
1.1.2. sigmod
優點:它輸出映射在(0,1)內,單調連續,非常適合用作輸出層;並且求導比較容易。
缺點:具有軟飽和性,一旦輸入落入飽和區,一階導數就變得接近於0,很容易產生梯度消失;指數運算相對耗時;sigmoid 函數關於原點中心不對稱;並且對於權重矩陣的初始化必須特別留意。比如,如果初始化權重過大,那么大多數神經元將會飽和,導致網絡就幾乎不學習。
飽和性:當|x|>c時,其中c為某常數,此時一階導數等於0,通俗的說一階導數就是上圖中的斜率,函數越來越水平。
1.1.3. tanh
tach也是傳統神經網絡中最常用的激活函數,與sigmoid一樣也存在飽和問題,但它的輸出是0中心的,因此實際應用中tanh比sigmoid 更受歡迎。tanh函數實際上是一個放大的sigmoid函數。
1.2. Pytorch常見激活函數
作用:把卷積層輸出結果做非線性映射。
常用到的激活函數包括:
- sigmoid:
torch.nn.functional.sigmoid(input)
(已經不推薦使用了) - tanh:
torch.nn.functional.tanh(input)
- Relu:
torch.nn.functional.relu(input, inplace = False)
- Leaky Relu:
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False)
- EReLU
- Maxout
2. 損失函數
2.1. Keras內置的損失函數
2.1.1. Keras core Loss
model.compile(loss='目標函數 ', optimizer='adam', metrics=['accuracy'])
損失函數,或稱目標函數,是網絡中的性能函數,也是編譯一個模型必須的兩個參數之一。由於損失函數種類眾多,下面以keras官網手冊的為例。
在官方keras.io里面,有如下資料:
-
mean_squared_error或mse
-
mean_absolute_error或mae
-
mean_absolute_percentage_error或mape
-
mean_squared_logarithmic_error或msle
-
squared_hinge
-
hinge
-
binary_crossentropy(亦稱作對數損失,logloss)
-
categorical_crossentropy(亦稱作多類的對數損失)
注意使用該目標函數時,需要將標簽轉化為形如(nb_samples, nb_classes)的二值序列
-
sparse_categorical_crossentrop:
如上,但接受稀疏標簽。注意,使用該函數時仍然需要你的標簽與輸出值的維度相同,你可能需要在標簽數據上增加一個維度:np.expand_dims(y,-1)
-
kullback_leibler_divergence
從預測值概率分布Q到真值概率分布P的信息增益,用以度量兩個分布的差異.
-
cosine_proximity
即預測值與真實標簽的余弦距離平均值的相反數
2.1.2. mean_squared_error
顧名思義,意為均方誤差,也稱標准差,縮寫為MSE,可以反映一個數據集的離散程度。
標准誤差定義為各測量值誤差的平方和的平均值的平方根,故又稱為均方誤差。
公式:
可以理解為一個從n維空間的一個點到一條直線的距離的函數。(此為在圖形上的理解,關鍵看個人怎么理解了)
2.1.3. mean_absolute_error
譯為平均絕對誤差,縮寫MAE。
平均絕對誤差是所有單個觀測值與算術平均值的偏差的絕對值的平均。
公式:
2.1.4. binary_crossentropy
即對數損失函數,log loss,與sigmoid相對應的損失函數。
公式:L(Y,P(Y|X)) = -logP(Y|X)
該函數主要用來做極大似然估計的,這樣做會方便計算。因為極大似然估計用來求導會非常的麻煩,一般是求對數然后求導再求極值點。
損失函數一般是每條數據的損失之和,恰好取了對數,就可以把每個損失相加起來。負號的意思是極大似然估計對應最小損失。
2.1.5. categorical_crossentropy
多分類的對數損失函數,與softmax分類器相對應的損失函數,理同上。
tip:此損失函數與上一類同屬對數損失函數,sigmoid和softmax的區別主要是,sigmoid用於二分類,softmax用於多分類。
注意: 當使用 categorical_crossentropy 損失時,你的目標值應該是分類格式 (即,如果你有 10 個類,每個樣本的目標值應該是一個 10 維的向量,這個向量除了表示類別的那個索引為 1,其他均為 0)。 為了將 整數目標值 轉換為 分類目標值,你可以使用 Keras 實用函數 to_categorical:
from keras.utils.np_utils import to_categorical
categorical_labels = to_categorical(int_labels, num_classes=None)
2.2. Pytorch內置的損失函數
2.2.1. 交叉熵:用於分類
-
熵(Entropy)
-
交叉熵(Cross Entropy)
- OneHot編碼
- 二分類: Binary Classification
-
Softmax函數
在Pytorch里,nn.Cross_Entropy()損失函數已經將
softmax() -> log2() -> nll_loss()
綁在一起。因此,使用了Cross_Entropy()函數,函數里的paramets必須是logits。全連接層后面不需要再添加softmax層,此處也是與TensorFlow不同之處。
2.2.2. 均方誤差(MSE): 用於回歸
回歸問題解決的是對具體的數值進行預測。例如,房價預測、銷量預測都是回歸問題。這些問題需要預測的不是一個事先定義好的類別,而是一個任意實數,解決回歸問題的神經網絡一般只有一個輸出節點,這個節點的輸出值就是預測值。對於回歸問題常用的損失函數為均方誤差(MSE,mean squared error): nn.MSELoss()
。
3. 反向傳播
反向傳播算法就是一個有效的求解梯度的算法,本質上其實就是一個鏈式求導法則的應用。
3.1. 鏈式法則
鏈式法則是微積分中的求導法則,用於求一個復合函數的導數,是在微積分的求導運算中一種常用的方法。
例如:f(x,y,z) = (x+y)*z
本來可以直接求出函數的關於x、y、z的導數,但是此次采用鏈式求導法則:
令 q = x+y
則 f = qz
對於這兩個式子分別求出它們的微分 ∂f / ∂q = z, ∂f / ∂z = q
,其中,∂q / ∂y = 1, ∂q / ∂x = 1
。
因需要求出 ∂f / ∂y
, ∂f / ∂x
, ∂f / ∂z
,那么f(x,y,z)的連續求導為:
∂f / ∂x = (∂f / ∂q) * ( ∂q / ∂x) = z
∂f / ∂y = (∂f / ∂q) * ( ∂q / ∂y) = z
∂f / ∂z = q = x + y
以上便是鏈式求導法則的核心,通過連續求導,便得出了 ∂f / ∂y
, ∂f / ∂x
, ∂f / ∂z
。
3.2. 神經網絡優化算法
Pytorch 提供了 torch.optim
模塊。參數的梯度可以通過求偏導的方式計算,對於參數Θ,其梯度為 ∂J(Θ)/∂Θ
,有了梯度,還需要定義一個學習率來定義每次參數更新的幅度,則得到參數更新的公式為:
3.2.1. SGD
隨機梯度下降法(Stochastic Gradient Descent):每次使用一批(batch)數據進行梯度的計算。而不是計算全部數據的梯度,因為現在的深度學習的數據量都特別大,所以每次都計算所有數據的梯度是不現實的,這樣會導致運算的時間特別的長,並且每次都計算全部的梯度還失去了一些隨機性,容易陷入局部誤差,所以,SGD能減小收斂所需要的迭代次數,使用隨機梯度下降法可能每次都不是朝着真正最小的方向,但是這樣反而容易跳出局部極小點。
3.2.2. Momentum
Momentum就是在隨機梯度下降的同時,增加動量,可以把它理解為增加慣性,可解釋為利用慣性跳出局部極小值點。
3.2.3. Adagrad
Adagrad優化器,是基於SGD的一種算法,它的核心思想是對比較常見的數據給與它比較小的學習率去調整參數,對於比較罕見的數據給予它比較大的學習率去調整參數,適合用於數據稀疏的數據集。Adagrad主要的優勢在於不需要人為的調節學習率,它可以自動調節。它的缺點在於,隨着迭代次數的增多,學習率也會越來越低,最終會趨向於0.
3.2.4. RMSprop
RMSprop不會再將前面有所的梯度求和,而是通過一個衰減率將其變小,使用了一種平滑平均的方式,越靠前面的梯度對自適應的學習率影響越小,這樣就能更加有效地避免Adagrad學習率一直遞減太多的問題,能夠更快的收斂。
3.2.5. Adam
Adam是一階基於梯度下降的算法,基於自適應低階矩估計優化器,效果比RMSprop好。其還有一種Adamax優化算法是基於無窮大范數的Adam算法的一個變種。
Adam像Adadelta和RMSprop一樣會存儲之前衰減的平方梯度,同時它也會保存之前衰減的梯度。經過一些處理之后再使用類似Adadelta和RMSprop的方式更新參數。
4. Dropout函數
Dropout函數是Hintion在2012年提出的,為了防止模型過擬合,在每個訓練批次中,通過忽略一般的神經元即讓一部分的隱層節點值為0,可明顯地減少過擬合現象。
torch.nn.functional.dropout(input, p = 0.5,training = False,inplace = False)
torch.nn.functional.alpha_dropout(input, p = 0.5,training = False)
torch.nn.functional.dropout2d(input, p = 0.5,training = False,inplace = False)
torch.nn.functional.dropout3d(input, p = 0.5,training = False,inplace = False)
注:pytorch中的 p = 0.5
,表示的是dropout_prob;而TensorFlow中的 p = 0.5
,表示keep_prob。