常用的激活函數


激活函數的主要目的是制造非線性。如果不用激勵函數,每一層輸出都是上層輸入的線性函數,無論神經網絡有多少層,輸出都是輸入的線性組合。
如果使用的話,激活函數給神經元引入了非線性因素,使得神經網絡可以任意逼近任何非線性函數,這樣神經網絡就可以應用到眾多的非線性模型中。

理論上來說,神經網絡和多項式展開一樣,或者傅里葉變換,通過一種方法來表達(或逼近)任意的函數,因此只有線性肯定是不夠的,加上了非線性才能有表達非線性函數的能力。

softmax函數:定義Softmax函數,或稱歸一化指數函數,是邏輯函數的一種推廣。它能將一個含任意實數的K維向量  “壓縮”到另一個K維實向量  中,使得每一個元素的范圍都在  之間,並且所有元素的和為1。實際上就是對數歸一化,將實數映射到(0,1)之間,而且單調性不變,凸顯其中最大的值並抑制遠低於最大值的其他分量。

import math
z = [1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0]
z_exp = [math.exp(i) for i in z]  
print(z_exp)  # Result: [2.72, 7.39, 20.09, 54.6, 2.72, 7.39, 20.09]
sum_z_exp = sum(z_exp)
print(sum_z_exp)  # Result: 114.98 
softmax = [round(i / sum_z_exp, 3) for i in z_exp]
print(softmax)  # Result: [0.024, 0.064, 0.175, 0.475, 0.024, 0.064, 0.175]
scores = np.array([123, 456, 789])    # example with 3 classes and each having large scores
scores -= np.max(scores)    # scores becomes [-666, -333, 0]
p = np.exp(scores) / np.sum(np.exp(scores))

 使用 Softmax 需要注意數值溢出的問題。因為有指數運算,如果 V 數值很大,經過指數運算后的數值往往可能有溢出的可能。所以,需要對 V 進行一些數值處理:即 V 中的每個元素減去 V 中的最大值。

Sigmoid函數:Sigmoid就是極端情況(類別數為2)下的Softmax 。優點是可以解釋,比如將0-1之間的取值解釋成一個神經元的激活率(firing rate)

缺點:激活函數計算量大,反向傳播求誤差梯度時,求導涉及除法,反向傳播時,很容易就會出現梯度消失的情況,從而無法完成深層網絡的訓練。Sigmoids函數飽和且kill掉梯度。Sigmoids函數收斂緩慢。

 

對比 Softmax Sigmoid
公式
本質 離散概率分布 非線性映射
任務 多分類 二分類
定義域 某個一維向量 單個數值
值域 [0,1] (0,1)
結果之和 一定為1 為某個正數

提問:softmax VS k個二元分類器

如果開發一個音樂分類的應用,需要對k種類型的音樂進行識別,那么是選擇使用 softmax 分類器呢,還是使用 logistic 回歸算法建立 k 個獨立的二元分類器呢?
這一選擇取決於類別之間是否互斥,例如,如果有四個類別的音樂,分別為:古典音樂、鄉村音樂、搖滾樂和爵士樂,那么可以假設每個訓練樣本只會被打上一個標簽(即:一首歌只能屬於這四種音樂類型的其中一種),此時應該使用類別數 k = 4 的softmax回歸。(如果在數據集中,有的歌曲不屬於以上四類的其中任何一類,那么可以添加一個“其他類”,並將類別數 k 設為5。)
如果四個類別如下:人聲音樂、舞曲、影視原聲、流行歌曲,那么這些類別之間並不是互斥的。例如:一首歌曲可以來源於影視原聲,同時也包含人聲 。這種情況下,使用4個二分類的 logistic 回歸分類器更為合適。這樣,對於每個新的音樂作品 ,算法可以分別判斷它是否屬於各個類別。
一個計算視覺領域的例子,任務是將圖像分到三個不同類別中。(i) 假設這三個類別分別是:室內場景、戶外城區場景、戶外荒野場景。會使用sofmax回歸還是 3個logistic 回歸分類器呢?

(ii) 現在假設這三個類別分別是室內場景、黑白圖片、包含人物的圖片,會選擇 softmax 回歸還是多個 logistic 回歸分類器呢?
在第一個例子中,三個類別是互斥的,因此更適於選擇softmax回歸分類器 。而在第二個例子中,建立三個獨立的 logistic回歸分類器更加合適。

提問:softmax 反向梯度

其實就是對權重參數進行反向求導。softmax可以看做是一個線性分類器,求導過程的程序設計分為兩種方法:一種是使用嵌套 for 循環,另一種是直接使用矩陣運算。

使用嵌套 for 循環,對權重 W 求導函數定義如下:

def softmax_loss_naive(W, X, y, reg):
 """
 Softmax loss function, naive implementation (with loops)

 Inputs have dimension D, there are C classes, and we operate on minibatches
 of N examples.

 Inputs:
 - W: A numpy array of shape (D, C) containing weights.
 - X: A numpy array of shape (N, D) containing a minibatch of data.
 - y: A numpy array of shape (N,) containing training labels; y[i] = c means
   that X[i] has label c, where 0 <= c < C.
 - reg: (float) regularization strength

 Returns a tuple of:
 - loss as single float
 - gradient with respect to weights W; an array of same shape as W
 """
 # Initialize the loss and gradient to zero.
 loss = 0.0
 dW = np.zeros_like(W)

 num_train = X.shape[0]
 num_classes = W.shape[1]
 for i in xrange(num_train):
   scores = X[i,:].dot(W)
   scores_shift = scores - np.max(scores)
   right_class = y[i]
   loss += -scores_shift[right_class] + np.log(np.sum(np.exp(scores_shift)))
   for j in xrange(num_classes):
     softmax_output = np.exp(scores_shift[j]) / np.sum(np.exp(scores_shift))
     if j == y[i]:
       dW[:,j] += (-1 + softmax_output) * X[i,:]
     else:
       dW[:,j] += softmax_output * X[i,:]

 loss /= num_train
 loss += 0.5 * reg * np.sum(W * W)
 dW /= num_train
 dW += reg * W

 return loss, dW

  使用矩陣運算,對權重 W 求導函數定義如下:

def softmax_loss_vectorized(W, X, y, reg):
 """
 Softmax loss function, vectorized version.

 Inputs and outputs are the same as softmax_loss_naive.
 """
 # Initialize the loss and gradient to zero.
 loss = 0.0
 dW = np.zeros_like(W)

 num_train = X.shape[0]
 num_classes = W.shape[1]
 scores = X.dot(W)
 scores_shift = scores - np.max(scores, axis = 1).reshape(-1,1)
 softmax_output = np.exp(scores_shift) / np.sum(np.exp(scores_shift), axis=1).reshape(-1,1)
 loss = -np.sum(np.log(softmax_output[range(num_train), list(y)]))
 loss /= num_train
 loss += 0.5 * reg * np.sum(W * W)

 dS = softmax_output.copy()
 dS[range(num_train), list(y)] += -1
 dW = (X.T).dot(dS)
 dW = dW / num_train + reg * W  

 return loss, dW

  實際驗證表明,矩陣運算速度要比嵌套循環快很多,特別是在訓練樣本數量多的情況下。我們使用 CIFAR-10 數據集中約5000個樣本對兩種求導方式進行測試對比:

tic = time.time()
loss_naive, grad_naive = softmax_loss_naive(W, X_train, y_train, 0.000005)
toc = time.time()
print('naive loss: %e computed in %fs' % (loss_naive, toc - tic))

tic = time.time()
loss_vectorized, grad_vectorized = softmax_loss_vectorized(W, X_train, y_train, 0.000005)
toc = time.time()
print('vectorized loss: %e computed in %fs' % (loss_vectorized, toc - tic))

grad_difference = np.linalg.norm(grad_naive - grad_vectorized, ord='fro')
print('Loss difference: %f' % np.abs(loss_naive - loss_vectorized))
print('Gradient difference: %f' % grad_difference)

  結果顯示為:

naive loss: 2.362135e+00 computed in 14.680000s

vectorized loss: 2.362135e+00 computed in 0.242000s

Loss difference: 0.000000

Gradient difference: 0.000000

  顯然,此例中矩陣運算的速度要比嵌套循環快60倍。所以,當我們在編寫機器學習算法模型時,盡量使用矩陣運算,少用 嵌套循環,以提高運算速度。(求線性回歸的最小二乘解涉及矩陣求逆。在樣本量大/維度高的情況下計算量較大。這時可以使用梯度下降法近似來求最小二乘解。)

實際上,這又回歸到解方程,線性代數那部分知識去了,如果通常來說參數比樣本少,多元方程肯定有解,如果參數太多,多余樣本,也可以找到一個較小的loss值作為求參結束的標志。參考以下網址:http://cs231n.github.io/classification/

https://blog.csdn.net/red_stone1/article/details/80687921

ReLU函數:

 輸入信號 <0 時,輸出都是0,>0 的情況下,輸出等於輸入。Krizhevsky et al. 發現使用 ReLU 得到的 SGD 的收斂速度會比 sigmoid/tanh 快很多。

ReLU更容易學習優化。因為其分段線性性質,導致其前傳,后傳,求導都是分段線性。而傳統的sigmoid函數,由於兩端飽和,在傳播過程中容易丟棄信息。

ReLU激活函數在AlexNet[3]中大放異彩,使用ReLU作為激活函數的網絡比使用tanh作為激活函數的網絡收斂快6倍。這個時候大家突然發現激活函數的主要目的是制造非線性,有沒有生物學解釋其實不那么重要,函數光滑不光滑也沒那么重要。

缺點:訓練的時候很”脆弱”,很容易就”die”了,還是非zero-centered。非zero-centered會導致后一層的神經元將得到上一層輸出的非0均值的信號作為輸入。 產生的一個結果就是對w求局部梯度則都為正,

這樣在反向傳播的過程中w要么都往正方向更新,要么都往負方向更新,導致有一種捆綁的效果,使得收斂緩慢。詳細可以參考:https://www.jianshu.com/p/917f71b06499

例如,一個非常大的梯度流過一個 ReLU 神經元,更新過參數之后,這個神經元再也不會對任何數據有激活現象了,那么這個神經元的梯度就永遠都會是 0.
如果 learning rate 很大,那么很有可能網絡中的 40% 的神經元都”dead”了。

Tanh函數:

也稱為雙切正切函數,取值范圍為[-1,1]。
tanh在特征相差明顯時的效果會很好,在循環過程中會不斷擴大特征效果。
與 sigmoid 的區別是,tanh 是 0 均值的,因此實際應用中 tanh 會比 sigmoid 更好,但是雖然tanh是zero-centered,但是還是會飽和。

Maxout函數:

maxout是通過分段線性函數來擬合所有可能的凸函數來作為激活函數的,但是由於線性函數是可學習,所以實際上是可以學出來的激活函數。具體操作是對所有線性取最大,也就是把若干直線的交點作為分段的界,然后每一段取最大。

maxout可以看成是relu家族的一個推廣。

缺點在於增加了參數量。

 結尾: 應用中如何選擇合適的激活函數?

這個問題目前沒有確定的方法,憑一些經驗吧。
1)深度學習往往需要大量時間來處理大量數據,模型的收斂速度是尤為重要的。所以,總體上來講,訓練深度學習網絡盡量使用zero-centered數據 (可以經過數據預處理實現) 和zero-centered輸出。所以要盡量選擇輸出具有zero-centered特點的激活函數以加快模型的收斂速度。
2)如果使用 ReLU,那么一定要小心設置 learning rate,而且要注意不要讓網絡出現很多 “dead” 神經元,如果這個問題不好解決,那么可以試試 Leaky ReLU、PReLU 或者 Maxout.
3)最好不要用 sigmoid,你可以試試 tanh,不過可以預期它的效果會比不上 ReLU 和 Maxout.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM