線性模型的侷限性:只通過線性變換,任意層的全連接神經網絡和單層神經網絡的表達能力並沒有任何區別,線性模型能解決的問題是有限的。
激活函數的目的是去線性化,如果將每一個神經元的輸出通過一個非線性函數,那麼整個神經網絡的模型也就不再是線性的了,這個非線性函數就是激活函數。
評價某個激活函數是否有用時,需要考慮的因素有:
1)該函數應是單調的, 這樣輸出便會隨着輸入的增長而增長,從而使利用梯度下降法尋找局部極值點成爲可能.
2)該函數應是可微分的,以保證該函數定義域內的任意一點上導數都存在,從而使得梯度下降法能夠正常使用來自這類激活函數的輸出.
ReLU函數
ReLU函數是個非常常用的激活函數,其公式爲:
f(x) = max(0, x)
即,大於0的爲其本身,否則爲0.
tensorflow中,該激活函數爲,
tf.nn.relu(
features,
name=None
)
計算修改線性:max(features, 0).
優點:1)使網絡可以自行引入稀疏性,提高了訓練速度;2)計算複雜度低,不需要指數運算,適合後向傳播。
缺點:1)輸出不是零均值,不會對數據做幅度壓縮;2)容易造成神經元壞死現象,某些神經元可能永遠不會被激活,導致相應參數永遠不會更新。
卷積層後面通常用ReLU
tf.nn.relu6(features, name=None)
以6爲閾值的整流函數:min(max(features, 0), 6)
Sigmoid函數
其公式爲:
y = 1 / (1 + exp(-x))
其中,x的範圍爲正無窮大到負無窮大,y的範圍爲0到1.
它的曲線呈現S形,將變量映射到(0,1)這個值域範圍上。它的導數 f’(x)=f(x)[1-f(x)]。
優點:1)輸出範圍有限,數據不會發散;2)求導簡單。
缺點:1)激活函數計算量大,涉及指數和除法;2)反向傳播時,很容易就會出現梯度消失的情況,從而無法完成深層網絡的訓練。
邏輯迴歸一般用sigmoid。
Sigmoid原函數及導數圖形如下,由圖可知,導數從0開始很快就又趨近於0了,易造成「梯度消失」現象。
如上圖所示,經過Sigmoid函數輸出的函數都會在0~1區間裏,但,可以看出,當x=10和x=1000其實輸出的y差距並不大,所以可以看出,Sigmoid函數極限在x爲-6到6之間,其中x在-3到3之間效果比較好。
tensorflow中,該激活函數爲
tf.nn.sigmoid()
tf.sigmoid(
x,
name=None
)
Tanh函數
tf.nn.tanh(
x,
name=None
)
其公式爲:
y =(exp(x)-exp(-x))/(exp(x)+exp(-x)) = (1 - exp(-2x)) / (1 + exp(-2x))
導數:df(x)/dx=1-f(x)^2
其中,x的範圍爲正無窮大到負無窮大,y的範圍爲-1到1.
這個函數的作用是計算 x 的 tanh 函數。
tanh和tf.sigmoid非常接近,且與後者具有類似的優缺點,tf.sigmoid和tf.tanh的主要區別在於後者的值爲[-1.0,1.0]
優點:輸出範圍[-1,1],解決了sigmoid非零均值的問題,在一些特定的網絡架構中,能夠輸出負值的能力十分有用。
缺點:仍然存在梯度消失和冪運算的問題。
如果給Tanh的輸入值很大,那在反向求梯度的時候就很小,不利於網絡收斂。
下圖是Sigmoid和Tanh的對比:
(注意這裏tanh和tan是不一樣的,後者是正切函數,前者是雙曲正切函數。)
Swish函數
Swish激活函數的效果優於ReLU函數,公式如下:
y = x * sigmoid(βx)
其中,β爲x的縮放參數,一般取1即可。
Tensorflow好像還沒有定義該函數,但是我們可以用sigmoid函數自己定義,
def swish(x, b = 1):
return x * tf.nn.sigmoid(b * x)
Softmax函數
Softmax函數主要用來處理分類問題,該函數將前向傳播結果轉爲概率問題,所有概率之和爲1。例如對(a, b, c)用softmax函數後爲,
softmax=(exp(a)/(exp(a)+exp(b)+exp( c)), exp(b)/(exp(a)+exp(b)+exp( c)), exp( c)/(exp(a)+exp(b)+exp( c))).
softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)
在實際使用中,softmax函數的分類,一般都將分類標籤轉成one-hot編碼,需要分成幾類,就在這層放幾個節點。例如前面說的MNIST數據集和CIFAR10數據集,最後一層的輸出都是10個節點,因爲這兩個數據集都是十分類問題。
Tensorflow中,softmax函數爲
tf.nn.softmax(
logits,
axis=None,
name=None,
dim=None
)
tf.nn.dropout
tf.nn.dropout(
x,
keep_prob=None,
noise_shape=None,
seed=None,
name=None,
rate=None
)
解釋:這個函數的作用是計算神經網絡層的dropout。一個神經元將以概率keep_prob決定是否放電,如果不放電,那麼該神經元的輸出將是0,如果該神經元放電,那麼該神經元的輸出值將被放大到原來的1/keep_prob倍。這裏的放大操作是爲了保持神經元輸出總個數不變。比如,神經元的值爲[1, 2],keep_prob的值是0.5,並且是第一個神經元是放電的,第二個神經元不放電,那麼神經元輸出的結果是[2, 0],也就是相當於,第一個神經元被當做了1/keep_prob個輸出,即2個。這樣保證了總和2個神經元保持不變。
默認情況下,每個神經元是否放電是相互獨立的。但是,如果noise_shape被修改了,那麼他對於變量x就是一個廣播形式,而且當且僅當 noise_shape[i] == shape(x)[i] ,x中的元素是相互獨立的。比如,如果 shape(x) = [k, l, m, n], noise_shape = [k, 1, 1, n] ,那麼每個批和通道(channel component)都是相互獨立的,但是每行和每列的數據都是關聯的,即要不都爲0,要不都還是原來的值。
import tensorflow as tf
a = tf.constant([[-1.0, 2.0, 3.0, 4.0],[-3.0, 4.0, 5.0, 6.0]])
print(a)
with tf.Session() as sess:
b = tf.nn.dropout(a, 0.5) # 第0維相互獨立,第1維相互獨立,0維是列,1維是行
print(sess.run(b))
b = tf.nn.dropout(a, 0.5, noise_shape=[2, 4]) # 第0維相互獨立,第1維相互獨立的
print(sess.run(b))
b = tf.nn.dropout(a, 0.5, noise_shape=[2, 1]) # 第0維相互獨立,第1維不相互獨立的
print(sess.run(b))
b = tf.nn.dropout(a, 0.5, noise_shape=[1, 4]) # 第0維不相互獨立,第1維相互獨立的
print(sess.run(b))
b = tf.nn.dropout(a, 0.5, noise_shape=[1, 1]) # 第0維不相互獨立,第1維不相互獨立的
print(sess.run(b))
輸出爲: Tensor(「Const_48:0」, shape=(2, 4), dtype=float32) [[-0. 4. 0. 8.] [-0. 0. 10. 12.]] // 第一個默認都是相互獨立的 [[-2. 4. 0. 8.] [-6. 0. 10. 0.]] // 第二個 noise_shape=[2, 4]=shape=(2, 4),所以也是都相互獨立的 [[-0. 0. 0. 0.] [-6. 8. 10. 12.]] //第三個 noise_shape=[2, 1],所以1維不相互獨立,1維是行,所以要麼整行全部都0,要不全部都乘以2 [[-0. 0. 6. 8.] [-0. 0. 10. 12.]] // 第四個 noise_shape=[1, 4],第0維不相互獨立,0維是列,所以6和10,8和12, 0和0這些是不獨立的。 [[-0. 0. 0. 0.] [-0. 0. 0. 0.]] // 第五個 noise_shape=[1, 1],第0維和1維都不獨立,所以它要麼全0,要麼全部乘以2,只有兩種可能。