常見的激活函數有sigmoid、tanh和relu三種非線性函數,其數學表達式分別為:
- sigmoid: y = 1/(1 + e-x)
- tanh: y = (ex - e-x)/(ex + e-x)
- relu: y = max(0, x)
其代碼實現如下:
import numpy as np import matplotlib.pyplot as plt def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x)) def relu(x): return np.maximum(0, x) x = np.arange(-5, 5, 0.1) p1 = plt.subplot(311) y = tanh(x) p1.plot(x, y) p1.set_title('tanh') p1.axhline(ls='--', color='r') p1.axvline(ls='--', color='r') p2 = plt.subplot(312) y = sigmoid(x) p2.plot(x, y) p2.set_title('sigmoid') p2.axhline(0.5, ls='--', color='r') p2.axvline(ls='--', color='r') p3 = plt.subplot(313) y = relu(x) p3.plot(x, y) p3.set_title('relu') p3.axvline(ls='--', color='r') plt.subplots_adjust(hspace=1) plt.show()
其圖形解釋如下:
相較而言,在隱藏層,tanh函數要優於sigmoid函數,可以認為是sigmoid的平移版本,優勢在於其取值范圍介於-1 ~ 1之間,數據的平均值為0,而不像sigmoid為0.5,有類似數據中心化的效果。
但在輸出層,sigmoid也許會優於tanh函數,原因在於你希望輸出結果的概率落在0 ~ 1 之間,比如二元分類,sigmoid可作為輸出層的激活函數。
但實際應用中,特別是深層網絡在訓練時,tanh和sigmoid會在端值趨於飽和,造成訓練速度減慢,故深層網絡的激活函數默認大多采用relu函數,淺層網絡可以采用sigmoid和tanh函數。
另外有必要了解激活函數的求導公式,在反向傳播中才知道是如何進行梯度下降。三個函數的求導結果及推理過程如下:
1. sigmoid求導函數:
其中,sigmoid函數定義為 y = 1/(1 + e-x) = (1 + e-x)-1
與此相關的基礎求導公式:(xn)' = n * xn-1 和 (ex)' = ex
應用鏈式法則,其求導過程為:dy/dx = -1 * (1 + e-x)-2 * e-x * (-1)
= e-x * (1 + e-x)-2
= (1 + e-x - 1) / (1 + e-x)2
= (1 + e-x)-1 - (1 + e-x)-2
= y - y2
= y(1 -y)
2. tanh求導函數:
其中,tanh函數定義為 y = (ex - e-x)/(ex + e-x)
與此相關的基礎求導公式:(u/v)' = (u' v - uv') / v2
同樣應用鏈式法則,其求導過程為:dy/dx = ( (ex - e-x)' * (ex + e-x) - (ex - e-x) * (ex + e-x)' ) / (ex + e-x)2
= ( (ex - (-1) * e-x) * (ex + e-x) - (ex - e-x) * (ex + (-1) * e-x) ) / (ex + e-x)2
= ( (ex + e-x)2 - (ex - e-x)2 ) / (ex + e-x)2
= 1 - ( (ex - e-x)/(ex + e-x) )2
= 1 - y2
3. relu求導函數:
其中,relu函數定義為 y = max(0, x)
可以簡單推理出 當x <0 時,dy/dx = 0; 當 x >= 0時,dy/dx = 1