Tensorflow學習筆記(六)幾種常見的啟用函式介紹及用matplotlib畫圖
歷史上,sigmoid函式曾非常常用,然而現在它已經不太受歡迎,實際很少使用了,因為它主要有兩個缺點:
1. 函式飽和使梯度消失:sigmoid 神經元在值為 0 或 1的時候接近飽和,這些區域,梯度幾乎為 0。因此在反向傳播時,這個區域性梯度會與整個代價函式關於該單元輸出的梯度相乘,結果也會接近為 0 。
這樣,幾乎就沒有訊號通過神經元傳到權重再到資料了,因此這時梯度就對模型的更新沒有任何貢獻。除此之外,為了防止飽和,必須對於權重矩陣的初始化特別留意。比如,如果初始化權重過大,那麼大多數神經元將會飽和,導致網路就幾乎不學習。
2. sigmoid 函式不是關於原點中心對稱的
這個特性會導致後面網路層的輸入也不是零中心的,進而影響梯度下降的運作。
因為如果輸入都是正數的話(如 f=wTx+bf=wTx+b 中每個元素都x>0 ),那麼關於 w的梯度在反向傳播過程中,要麼全是正數,要麼全是負數(具體依據整個表示式 f而定),這將會導致梯度下降權重更新時出現 z 字型的下降。
當然,如果是按batch 去訓練,那麼每個 batch 可能得到不同的訊號,整個批量的梯度加起來後可以緩解這個問題。因此,該問題相對於上面的神經元飽和問題來說只是個小麻煩,沒有那麼嚴重。
(2)Relu
ReLU. 近年來,ReLU 變的越來越受歡迎。它的數學表示式是: f(x)=max(0,x)。很顯然,從上圖左可以看出,輸入訊號
<0時,輸出為0,>0時,輸出等於輸入。ReLU的優缺點如下:
對比sigmoid類函式主要變化是:
1)單側抑制
2)相對寬闊的興奮邊界
3)稀疏啟用性。
Leaky ReLUs 就是用來解決ReLU壞死的問題的。和ReLU不同,當x<0時,它的值不再是0,而是一個較小斜率(如0.01等)的函式。也就是說f(x)=1(x<0)(ax)+1(x>=0)(x),其中a是一個很小的常數。這樣,既修正了資料分佈,又保留了一些負軸的值,使得負軸資訊不會全部丟失。關於Leaky ReLU 的效果,眾說紛紜,沒有清晰的定論。有些人做了實驗發現 LeakyReLU 表現的很好;有些實驗則證明並不是這樣。
- PReLU. 對於 Leaky ReLU 中的a,通常都是通過先驗知識人工賦值的。然而可以觀察到,損失函式對a的導數我們是可以求得的,可不可以將它作為一個引數進行訓練呢? Kaiming He 2015的論文《Delving Deep into Rectifiers: Surpassing Human-Level Performance
onImageNet Classification》指出,不僅可以訓練,而且效果更好。原文說使用了Parametric ReLU後,最終效果比不用提高了1.03%.
-Randomized Leaky ReLU. Randomized Leaky ReLU 是leaky ReLU 的random 版本, 其核心思想就是,在訓練過程中,a是從一個高斯分佈中隨機出來的,然後再在測試過程中進行修正。
(3)tanh
tanh 函式同樣存在飽和問題,但它的輸出是零中心的,因此實際中 tanh 比 sigmoid 更受歡迎。
優點:
1.比Sigmoid函式收斂速度更快。
2.相比Sigmoid函式,其輸出以0為中心。
缺點:
還是沒有改變Sigmoid函式的最大問題——由於飽和性產生的梯度消失。
(4)ELU
ELU被定義為 f(x)={a(ex−1)xif(x<0)if(0≤x) 其中a>0優點:
1.ELU減少了正常梯度與單位自然梯度之間的差距,從而加快了學習。
2.在負的限制條件下能夠更有魯棒性。
另附畫圖程式,將其他一些啟用函式也畫了出來
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-10,10, 60)
def elu(x,a):
y=[]
for i in x:
if i>=0:
y.append(i)
else:
y.append(a*np.exp(i)-1)
return y
relu=np.maximum(x,[0]*60)
relu6=np.minimum(np.maximum(x,[0]*60),[6]*60)
softplus=np.log(np.exp(x)+1)
elu=elu(x,1)
softsign=x/(np.abs(x)+1)
sigmoid=1/(1+np.exp(-x))
tanh=np.tanh(x)
lrelu=np.maximum(0.1*x,x)
plt.figure()#matplotlib 的 figure 就是一個 單獨的 figure 小視窗
plt.plot(x, relu6,label='relu6',linewidth=3.0)
plt.plot(x, relu,label='relu',color='black',linestyle='--',linewidth=2.0)
plt.plot(x, elu,label='elu',linewidth=2.0)
plt.plot(x, lrelu,label='lrelu',linewidth=1.0)
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.legend(loc='best')
plt.figure()
plt.ylim((-1.2, 1.2))
plt.plot(x, softsign,label='softsign',linewidth=2.0)
plt.plot(x, sigmoid,label='sigmoid',linewidth=2.0)
plt.plot(x, tanh,label='tanh',linewidth=2.0)
plt.plot(x, softplus,label='softplus',linewidth=2.0)
# plt.plot(x, hyperbolic_tangent,label='hyperbolic_tangent',linewidth=2.0)
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.legend(loc='best')
plt.show()