神經網路中常見的啟用函式
深度學習中已經成為了人工智慧領域的必備工具,源於人工神經網路的研究,含多個隱藏層的多層感知器就是一種深度學習結構。尋找隱藏層的權重引數和偏置的過程,就是常說的“學習”過程,其遵循的基本原則就是使得網路最終的輸出誤差最小化。在神經⽹絡中,啟用函式是必須選擇的眾多引數之⼀,從而使神經⽹絡獲得最優的結果和效能。
經常用到的啟用函式有哪些呢?如何進行選擇呢?
關於啟用函式
啟用函式(Activation Function),就是在人工神經網路的神經元上執行的函式,負責將神經元的輸入對映到輸出端,啟用函式將神經網路中將輸入訊號的總和轉換為輸出訊號。啟用函式大多是非線性函式,才能將多層感知機的輸出轉換為非線性,使得神經網路可以任意逼近任何非線性函式,進而可以應用到眾多的非線性模型中。
也就是說,非線性啟用函式可以建立輸入與輸出鍵的複雜對映關係,神經網路也能通過“學習”來更新引數。並且,因為非線性函式的導數與輸入有關,從而可以通過向後傳播演算法計算梯度,也可以構建多層神經網路,以處理複雜問題。
常見的啟用函式有用於淺層網路的sigmoid 系列,用於深層網路的ReLU系列,用於遞迴網路的tanh系列以及Softmax 系列等等。
sigmoid 系列
sigmoid函式也叫Logistic函式,用於隱層神經元輸出,能將( − ∞ , + ∞ )的數值對映到(0,1)的區間,當以概率形式表示預測值時,一般使用這個函式。sigmod啟用函式的Python 程式碼如下:
import numpy as np def sigmoid(x): s = 1 / (1 + np.exp(-x)) return s
函式的影象如下所示:
Sigmoid函式的優點在於它可導,並且值域在0到1之間,使得神經元的輸出標準化,是神經網路最早採用的啟用函式。它的不足也很明顯,在增加或減少到一定程度時,函式值變化很小,這就是所謂的“梯度消失”,致使網路的收斂速度變慢,進而耗費計算資源。另外,輸出值不是以0為中心,而是0.5。
一般的Sigmoid 函式應用於淺層網路。
HardSigmoid
在Sigmoid的基礎上,又有HardSigmoid,因為當輸入值趨向無窮大的時候,輸出值趨向於1;當輸入值趨向無窮小的時候,輸出值趨向於0。所以,顧名思義,HardSigmoid是在Sigmoid的基礎上,當輸入值超過某個範圍強行置1和0。HardSigmoid 的python 程式碼如下:
def Hard_sigmoid(x): y = [] for i in x: if i < -2.5: y_i = 0 elif i >= -2.5 and i <= 2.5: y_i = 0.2 * i + 0.5 else: y_i = 1 y.append(y_i) return y
HardSigmoid 啟用函式的函式影象如下:
Swish
swish的表示式為:f ( x ) = x ⋅ s i g m o i d ( b x ),python程式碼如下:
def Swish(x): return x / (1 + np.exp(-b*x))
其中b是可學引數, Swish 具備無上界有下界、平滑、非單調的特性。
Swish 在深層模型上的效果優於 ReLU。例如,僅僅使用 Swish 單元替換 ReLU 就能把 Mobile NASNetA 在 ImageNet 上的分類準確率提高 0.9%。
maxout
Maxout可以看做是在深度學習網路中加入一層啟用函式層,包含一個引數k。這一層相比ReLU,sigmoid等,其特殊之處在於增加了k個神經元,然後輸出啟用值最大的值。
maxout是一個函式逼近器,對於一個標準的MLP網路來說,如果隱藏層的神經元足夠多,那麼理論上是可以逼近任意的函式的。Maxout的擬合能力非常強,可以擬合任意的凸函式,具有ReLU的所有優點,線性、不飽和性,同時沒有ReLU的一些缺點,如神經元的死亡。
Relu系列
Relu (Rectified Linear Unit)稱為“線性整流函式”或者“修正線性單元”,通常就直接稱為 ReLU 函式,是解決梯度消失問題的方法。將 ReLU 函式引入神經網路時,也引入了很大的稀疏性。然而,由於稀疏性,時間和空間複雜度更低,不涉及成本更高的指數運算,允許網路快速收斂。
儘管Relu看起來像線性函式,但它具有導數函式並允許反向傳播,python 程式碼如下:
import numpy as np def relu(x): s = np.where(x < 0, 0, x) return s
ReLU引入了神經元死亡問題,當輸入接近零或為負時,函式的梯度變為零,網路將無法執行反向傳播,也無法學習,也就是說,網路的大部分分量都永遠不會更新,另外,它不能避免梯度爆炸問題。
ReLU是現在DNN模型中比較常用的啟用函式。
ELU
指數線性單元啟用函式ELU解決了 ReLU 的一些問題,同時也保留了一些好的方面。這種啟用函式要選取一個 α 值;常見的取值是在 0.1 到 0.3 之間。但 α =0.3時的函式影象如下:
ELU能避免神經元死亡問題,能得到負值輸出,這能幫助網路向正確的方向推動權重和偏置變化,在計算梯度時能得到啟用,而不是讓它們等於 0。ELU 的python 程式碼如下:
import numpy as np
def elu(x):
s = np.where(x >= 0, x, α(np.exp(x)-1)
return s
但是,由於包含了指數運算,計算時間更長,同樣無法避免梯度爆炸問題,另外,神經網路不學習 α 值。
Leaky ReLU
滲漏型整流線性單元啟用函式也有一個 α 值,通常取值在 0.1 到 0.3 之間。Leaky ReLU 啟用函式很常用,相比於 ELU 也有一些缺陷,但比 ReLU 具有一些優勢。
LeakyReLU的負值斜率很小,而不是平坦的斜率。斜率係數需要在訓練前確定,即在訓練過程中不學習。這種型別的啟用函式在可能遇到稀疏梯度的任務中很流行,例如訓練生成式對抗網路。
import numpy as np
def lrelu(x):
s = np.where(x >= 0, x, αx)
return s
類似 ELU,Leaky ReLU 也能避免死亡 ReLU 問題,因為其在計算導數時允許較小的梯度,由於不包含指數運算,所以計算速度比 ELU 快。
擴充套件型指數線性單元啟用函式(SELU)
SELU 啟用能夠對神經網路進行自歸一化,歸一化就是首先減去均值,然後除以標準差。因此,經過歸一化之後,網路的元件(權重、偏置和啟用)的均值為 0,標準差為 1,而這正是 SELU 啟用函式的輸出值。通過歸一化,網路引數會被初始化一個正態分佈。
通過歸一化,網路引數會被初始化一個正態分佈。
def SeLU(x,alpha=1.6732632423543772848170429916717,scale=1.0507009873554804934193349852946): y = [] for i in x: if i >= 0: y_i = scale * i else: y_i = scale * alpha * (np.exp(i) - 1) y.append(y_i) return y
SELU內部歸一化的速度比外部歸一化快,這意味著網路能更快收斂,而且避免了出現梯度消失或爆炸問題,在CNN或RNN 網路架構中有所應用。
高斯誤差線性單元啟用函式GELU
GELU是某些函式(比如雙曲正切函式 tanh)與近似數值的組合,
當 x 大於 0 時,輸出為 x;但 x=0 到 x=1 的區間除外,這時曲線更偏向於 y 軸。
import numpy as np
def tanh(x):
s1 = np.exp(x) - np.exp(-x)
s2 = np.exp(x) + np.exp(-x)
s = s1 / s2
return s
gelu = lambda x:0.5 * x * (1 + tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * np.power(x, 3))))
GELU 在NLP 領域有 較好 表現,尤其在 Transformer 模型中表現最好,能避免梯度消失問題。
tanh系列
tanh
Tanh函式,即雙曲正切函式,比sigmoid函式更受歡迎,能為多層神經網路提供更好的效能。
它的輸出更多地以零為中心,這有助於加速收斂,尤其是在訓練初期。 雙曲線正切函式的python程式碼如下:
import numpy as np
def tanh(x):
s1 = np.exp(x) - np.exp(-x)
s2 = np.exp(x) + np.exp(-x)
s = s1 / s2
return s
Tanh函式的最大優點是輸出值以 0為中心,即關於座標原點對稱,分屬為正數和負數兩大類別,函式及其導數都是單調的,收斂速度比sigmoid快,從而可以減少迭代次數。這使得它具有了Sigmoid函式的優勢,又克服了某些不足。但是,“梯度消失”的問題都還存在,進而導致收斂速度變慢。
Tanh 一般用於遞迴神經網路。
HardTanh
Hardtanh啟用函式是Tanh的線性分段近似。相較而言,它更易計算,這使得學習計算的速度更快,儘管首次派生值為零可能導致靜默神經元/過慢的學習速率。
TanhShrink
基於Tanh之上,計算輸入輸出的差值,即為TanhShrink, 函式影象如下。
在當輸入在0附近時,梯度近乎為0,而在輸入極大或極小時,梯度反而為正常梯度。
softmax 系列
Softmax函式比較適合作為多分類模型的啟用函式,一般會與交叉熵損失函式相配。
通常,Softmax函式只應用於輸出層,把一堆實數的值對映到0-1區間,並且使他們的和為1,可以理解為對應每個類別對應的預測概率。python程式碼如下:
def softmax(x): x_exp = np.exp(x) x_sum = np.sum(x_exp, axis=1, keepdims=True) s = x_exp / x_sum return s
如果某一個zj大過其他z,那這個對映的分量就逼近於1,其他就逼近於0。
Softmax函式用於將輸入進行歸一化到(0,1),並且其和為1,普遍應用於分類模型(互斥)的預測概率值。事實上,但凡涉及到概率的地方基本都會用到softmax,典型的就比如attention layer當中,都會使用softmax來計算attention值。
LogSoftMax
LogSoftmax是基於Softmax函式之上,計算其對應的對數值,範圍在(-∞,0)用來計算交叉熵損失函式(根據groundtruth的標籤取出對應的值即可)。 LogSoftMax 加快了運算速度,提高資料穩 定 性。
Softmin
Softmin是在Softmax的基礎上,做相反變換。 Softmin是在Softmax的基礎上,做相反變換。 跟softmax類似,輸入n維t資料,對它們進行重新縮放使得n維輸出的每個元素都在[0, 1]區間內,且和為1。不同的是,softmax是單調遞增而softmin是單調遞減,意味著softmax操作會使得最大的值在啟用操作後依然保持最大,而softmin會使得最小的數在經過了softmin後變成最大值。
啟用函式的選擇
以終為始,啟用函式的選擇也是為最終的任務目標服務的。不存在普遍適用各種神經網路的萬能的啟用函式,在選擇啟用函式的時候,要考慮不同的條件限制,例如,如果函式可導,求導數的計算難度如何? 函式光滑程度如何? 輸出是否保持標準化? 網路的收斂速度如何?等等。
一般地,在用於分類器時,Sigmoid函式及其組合通常效果更好。為了避免梯度消失問題,又需要避免使用Sigmoid和TanH。 如果是迴歸模型,在輸出層上可以使用線性啟用函式。 如果是淺層神經網路 ,如不超過4層的,可選擇使用多種激勵函式,沒有太大的影響 。 如果網路中存在大量未啟用神經元,可以考慮leaky ReLU函式 。
ReLU函式是應用比較廣泛的啟用函式,可以作為預設選項。 深度學習往往需要大量時間來處理大量資料,模型的收斂速度是尤為重要的 所以 要儘量選擇輸出具有zero-centered特點的啟用函式以加快模型的收斂速度。
一個經驗上的建議是:SELU > ELU > Leaky ReLU > ReLU> tanh > sigmoid,但是,如果網路的體系結構阻止自歸一化,那麼 ELU 可能是比 SELU 更好的選擇。如果速度很重要,Leaky ReLU 將是比慢很多的 ELU 更好的選擇。
更重要的是,啟用函式仍在發展,需要跟蹤業界的最新進展,並勇於探索和創新。
一句話小結
啟用函式是神經網路中的重要引數,一般地,Sigmoid 系列用於二分類任務輸出層,softmax系列用於多分類任務輸出層,tanh系列用於模型隱藏層,Relu系列用於迴歸任務以及卷積神經網路隱藏層。 但事無絕對,而且,新研究的啟用函式仍在湧現。
附, reddit上有一張啟用函式的圖,挺有意思的!
【關聯閱讀】
-
http://dashee87.github.io/deep%20learning/visualising-activation-functions-in-neural-networks/
-
http://en.wikipedia.org/wiki/Activation_function