天天看點

卷積神經網絡的激活函數

        目前所有神經網絡和支撐向量機的基礎都是1957年提出來的感覺機。感覺機(perceptron) 是二類分類的線性分類模型, 其輸入為執行個體的特征向量, 輸出為執行個體的類别, 取+1和–1二值。 感覺機對應于輸入空間(特征空間) 中将執行個體劃分為正負兩類的分離超平面, 屬于判别模型。但是感覺機卻不能分來異或這種簡單的布爾運算。後來是加入了激活函數才将感覺機給拯救了回來,也才有了現在的各種神經網絡。

        激活函數(activation function)運作時激活神經網絡中某一部分神經元,将激活資訊向後傳入下一層的神經網絡。神經網絡之是以能解決非線性問題,本質上就是激活函數加入了非線性因素,彌補了線性模型的表達力,把“激活的神經元的特征”通過函數保留并映射到下一層。

        因為神經網絡的數學基礎是處處可微的,是以選取的激活函數要能保證資料輸入與輸出也是可微的。那麼激活函數在 TensorFlow 中是如何表達的呢?激活函數不會更改輸入資料的次元,也就是輸入和輸出的次元是相同的。 TensorFlow 中包括平滑非線性的激活函數,如 sigmoid、 tanh、 elu、 softplus 和 softsign,也包括連續但不是處處可微的函數 relu、 relu6、 crelu 和 relu_x,以及随機正則化函數 dropout。

        上述激活函數的輸入均為要計算的 x(一個張量),輸出均為與 x 資料類型相同的張量。常見的激活函數有 sigmoid、 tanh、 relu 和 softplus 這 4 種。下面我們就來逐一講解。

(1) sigmoid 函數

        這是傳統神經網絡中最常用的激活函數之一(另一個是 tanh),對應的公式和圖像如下圖所示。

卷積神經網絡的激活函數

        使用方法如下:

import tensorflow as tf

a = tf.constant([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]])
sess = tf.Session()
print(sess.run(tf.sigmoid(a)))
           

        結果如下:

[[0.7310586 0.880797 ]
 [0.7310586 0.880797 ]
 [0.7310586 0.880797 ]]
           

        sigmoid 函數的優點在于,它的輸出映射在(0,1)内,單調連續,非常适合用作輸出層,并且求導比較容易。但是,它也有缺點,因為軟飽和性,一旦輸入落入飽和區, f'(x)就會變得接近于 0,很容易産生梯度消失。

軟飽和是指激活函數 h(x)在取值趨于無窮大時,它的一階導數趨于 0。硬飽和是指當|x| > c 時,其中 c 為常數,f '(x)=0。relu 就是一類左側硬飽和激活函數。

    梯度消失是指在更新模型參數時采用鍊式求導法則反向求導,越往前梯度越小。最終的結果是到達一定深度後梯度對模型的更新就沒有任何貢獻了。
           

(2) tanh 函數

        對應的公式和圖像如下圖所示。

卷積神經網絡的激活函數

        tanh 函數也具有軟飽和性。因為它的輸出以 0 為中心,收斂速度比 sigmoid 要快。但是仍無法解決梯度消失的問題。

 (3) relu 函數是目前最受歡迎的激活函數

        ReLU函數雖然不是Alex首次提出來的,但是當AlexNet在2012屆圖像識别大賽取得冠軍才使其被大衆所熟知。softplus可以看作是 ReLU的平滑版本。 relu定義為 f(x)=max(x,0)。softplus 定義為 f(x)=log(1+exp(x))。

卷積神經網絡的激活函數

        由上圖可見, relu 在 x<0 時硬飽和。由于 x>0 時導數為 1,是以, relu 能夠在 x>0 時保持梯度不衰減,進而緩解梯度消失問題,還能夠更很地收斂,并提供了神經網絡的稀疏表達能力。但是,随着訓練的進行,部分輸入會落到硬飽和區,導緻對應的權重無法更新,稱為“神經元死亡”。

a = tf.constant([-1.0, 2.0])
with tf.Session() as sess:
    b = tf.nn.relu(a)
    print(sess.run(b))
           

        結果:

[0. 2.]
           

(4) dropout 函數。

        一個神經元将以機率 keep_prob 決定是否被抑制。如果被抑制,該神經元的輸出就為 0;如果不被抑制,那麼該神經元的輸出值将被放大到原來的 1/keep_prob 倍。

        在預設情況下,每個神經元是否被抑制是互相獨立的。但是否被抑制也可以通過 noise_shape 來調節。當 noise_shape[i] == shape(x)[i]時, x 中的元素是互相獨立的。如果 shape(x) = [k, l, m, n],x 中的次元的順序分别為批、行、列和通道,如果 noise_shape = [k, 1, 1, n],那麼每個批和通道都是互相獨立的,但是每行和每列的資料都是關聯的,也就是說,要不都為 0,要不都還是原來的值。使用示例如下:

a = tf.constant([[-1.0, 2.0, 3.0, 4.0]])
print(a)
with tf.Session() as sess:
    b1 = tf.nn.dropout(a, 0.5, noise_shape = [1,4])
    print(sess.run(b1))
    b1 = tf.nn.dropout(a, 0.5, noise_shape = [1,4])
    print(sess.run(b1))
    
    b2 = tf.nn.dropout(a, 0.5, noise_shape = [1,1])
    print(sess.run(b2))
    b2 = tf.nn.dropout(a, 0.5, noise_shape = [1,1])
    print(sess.run(b2))
           

        結果:

Tensor("Const_26:0", shape=(1, 4), dtype=float32)
[[-0.  0.  0.  0.]]
[[-2.  0.  0.  0.]]
[[-2.  4.  6.  8.]]
[[-0.  0.  0.  0.]]
           

激活函數的選擇:

        當輸入資料特征相差明顯時,用 tanh 的效果會很好,且在循環過程中會不斷擴大特征效果并顯示出來。當特征相差不明顯時, sigmoid 效果比較好。同時,用 sigmoid 和 tanh 作為激活函數時,需要對輸入進行規範化,否則激活後的值全部都進入平坦區,隐層的輸出會全部趨同,喪失原有的特征表達。而 relu 會好很多,有時可以不需要輸入規範化來避免上述情況。是以,現在大部分的卷積神經網絡都采用 relu 作為激活函數。

PS:全部摘自李嘉璇的<<TensorFlow 技術解析與實戰>>第四章4.7.1節

繼續閱讀