深度學習基本部件-啟用函式詳解

嵌入式視覺發表於2023-01-10

文章首發於我的 github 倉庫-cv演算法工程師成長之路,歡迎關注我的公眾號-嵌入式視覺。

本文分析了啟用函式對於神經網路的必要性,同時講解了幾種常見的啟用函式的原理,並給出相關公式、程式碼和示例圖。

啟用函式概述

前言

人工神經元(Artificial Neuron),簡稱神經元(Neuron),是構成神經網路的基本單元,其主要是模擬生物神經元的結構和特性,接收一組輸入訊號併產生輸出。生物神經元與人工神經元的對比圖如下所示。

neuron

從機器學習的角度來看,神經網路其實就是一個非線性模型,其基本組成單元為具有非線性啟用函式的神經元,透過大量神經元之間的連線,使得多層神經網路成為一種高度非線性的模型。神經元之間的連線權重就是需要學習的引數,其可以在機器學習的框架下透過梯度下降方法來進行學習。

啟用函式定義

啟用函式(也稱“非線性對映函式”),是深度卷積神經網路模型中必不可少的網路層。

假設一個神經元接收 \(D\) 個輸入 \(x_1, x_2,⋯, x_D\),令向量 \(x = [x_1;x_2;⋯;x_?]\) 來表示這組輸入,並用淨輸入(Net Input) \(z \in \mathbb{R}\) 表示一個神經元所獲得的輸入訊號 \(x\) 的加權和:

\[z = \sum_{d=1}^{D} w_{d}x_{d} + b = w^\top x + b \]

其中 \(w = [w_1;w_2;⋯;w_?]\in \mathbb{R}^D\)\(D\) 維的權重矩陣,\(b \in \mathbb{R}\) 是偏置向量。

以上公式其實就是帶有偏置項的線性變換(類似於放射變換),本質上還是屬於線形模型。為了轉換成非線性模型,我們在淨輸入 \(z\) 後新增一個非線性函式 \(f\)(即啟用函式)。

\[a = f(z) \]

由此,典型的神經元結構如下所示:
典型的神經元架構

啟用函式性質

為了增強網路的表示能力和學習能力,啟用函式需要具備以下幾點性質:

  1. 連續並可導(允許少數點上不可導)的非線性函式。可導的啟用函式 可以直接利用數值最佳化的方法來學習網路引數。
  2. 啟用函式及其導函式要儘可能的簡單,有利於提高網路計算效率。
  3. 啟用函式的導函式的值域要在一個合適的區間內,不能太大也不能太小,否則會影響訓練的效率和穩定性.

Sigmoid 型函式

Sigmoid 型函式是指一類 S 型曲線函式,為兩端飽和函式。常用的 Sigmoid 型函式有 Logistic 函式和 Tanh 函式。

相關數學知識: 對於函式 \(f(x)\),若 \(x \to −\infty\) 時,其導數 \({f}'\to 0\),則稱其為左飽和。若 \(x \to +\infty\) 時,其導數 \({f}'\to 0\),則稱其為右飽和。當同時滿足左、右飽和時,就稱為兩端飽和。

Sigmoid 函式

對於一個定義域在 \(\mathbb{R}\) 中的輸入,sigmoid 函式將輸入變換為區間 (0, 1) 上的輸出(sigmoid 函式常記作 \(\sigma(x)\)):

\[\sigma(x) = \frac{1}{1 + exp(-x)} \]

sigmoid 函式的導數公式如下所示:

\[\frac{\mathrm{d} }{\mathrm{d} x}\text{sigmoid}(x) = \frac{exp(-x)}{(1+exp(-x))^2} = \text{sigmoid}(x)(1 - \text{sigmoid}(x)) \]

sigmoid 函式及其導數影像如下所示:

sigmoid 函式及其導數影像

注意,當輸入為 0 時,sigmoid 函式的導數達到最大值 0.25; 而輸入在任一方向上越遠離 0 點時,導數越接近 0

sigmoid 函式在隱藏層中已經較少使用,其被更簡單、更容易訓練的 ReLU 啟用函式所替代。

當我們想要輸出二分類或多分類、多標籤問題的機率時,sigmoid 可用作模型最後一層的啟用函式。下表總結了常見問題型別的最後一層啟用和損失函式。

問題型別 最後一層啟用 損失函式
二分類問題(binary) sigmoid sigmoid + nn.BCELoss(): 模型最後一層需要經過 torch.sigmoid 函式
多分類、單標籤問題(Multiclass) softmax nn.CrossEntropyLoss(): 無需手動做 softmax
多分類、多標籤問題(Multilabel) sigmoid sigmoid + nn.BCELoss(): 模型最後一層需要經過 sigmoid 函式

nn.BCEWithLogitsLoss() 函式等效於 sigmoid + nn.BCELoss

Tanh 函式

Tanh(雙曲正切)函式也是一種 Sigmoid 型函式,可以看作放大並平移 Sigmoid 函式,其能將其輸入壓縮轉換到區間 (-1, 1) 上。公式如下所示:

\[\text{tanh}(x) = 2\sigma(2x) - 1 \]

Sigmoid 函式和 Tanh 函式曲線如下圖所示:

Logistic函式和Tanh函式

兩種啟用函式實現和視覺化程式碼如下所示:

# example plot for the sigmoid activation function
from math import exp
from matplotlib import pyplot
import matplotlib.pyplot as plt

# sigmoid activation function
def sigmoid(x):
    """1.0 / (1.0 + exp(-x))
    """
    return 1.0 / (1.0 + exp(-x))

def tanh(x):
    """2 * sigmoid(2*x) - 1
    (e^x – e^-x) / (e^x + e^-x)
    """
    # return (exp(x) - exp(-x)) / (exp(x) + exp(-x))
    return 2 * sigmoid(2*x) - 1

def relu(x):
    return max(0, x)

def gradient_relu(x):
    if x < 0:
        return 0
    else:
        return 1

def gradient_sigmoid(x):
    """sigmoid(x)(1−sigmoid(x))
    """
    a = sigmoid(x)
    b = 1 - a
    return a*b

# 1, define input data
inputs = [x for x in range(-10, 11)]

# 2, calculate outputs
outputs = [sigmoid(x) for x in inputs]
outputs2 = [tanh(x) for x in inputs]

# 3, plot sigmoid and tanh function curve
plt.figure(dpi=90) # dpi 設定
plt.style.use('ggplot') # 主題設定

plt.subplot(1, 2, 1) # 繪製子圖
plt.plot(inputs, outputs, label='sigmoid')
plt.plot(inputs, outputs2, label='tanh')


plt.xlabel("x") # 設定 x 軸標籤
plt.ylabel("y")
plt.title('sigmoid and tanh') # 折線圖示題
plt.legend()
plt.show()

另外一種 Logistic 函式和 Tanh 函式的形狀對比圖:

Logistic 函式和 Tanh 函式的形狀

來源: 《神經網路與深度學習》圖4.2。

Logistic 函式和 Tanh 函式都是 Sigmoid 型函式,具有飽和性,但是計算開銷較大。因為這兩個函式都是在中間(0 附近)近似線性,兩端飽和。因此,這兩個函式可以透過分段函式來近似。

ReLU 函式及其變體

ReLU 函式

ReLU(Rectified Linear Unit,修正線性單元),是目前深度神經網路中最經常使用的啟用函式。公式如下所示:

\[ReLU(x) = max\{0,x\} = \left\{\begin{matrix} x & x\geqslant 0 \\ 0 & x< 0 \end{matrix}\right.\]

以上公式通俗理解就是,ReLU 函式僅保留正元素並丟棄所有負元素。

1,優點:

  • ReLU 啟用函式計算簡單
  • 具有很好的稀疏性,大約 50% 的神經元會處於啟用狀態。
  • 函式在 \(x > 0\) 時導數為 1 的性質(左飽和函式),在一定程度上緩解了神經網路的梯度消失問題,加速梯度下降的收斂速度。

相關生物知識: 人腦中在同一時刻大概只有 1% ∼ 4% 的神經元處於活躍 狀態。

2,缺點:

  • ReLU 函式的輸出是非零中心化的,給後一層的神經網路引入偏置偏移,會影響梯度下降的效率
  • ReLU 神經元在訓練時比較容易“死亡”。如果神經元引數值在一次不恰當的更新後,其值小於 0,那麼這個神經元自身引數的梯度永遠都會是 0,在以後的訓練過程中永遠不能被啟用,這種現象被稱作“死區”。

ReLU 啟用函式的程式碼定義如下:

# pytorch 框架對應函式: nn.ReLU(inplace=True)
def relu(x):
    return max(0, x)

ReLU 啟用函式及其函式梯度圖如下所示:

relu_and_gradient_curve

Leaky ReLU/PReLU/ELU/Softplus 函式

1,Leaky ReLU 函式: 為了緩解“死區”現象,研究者將 ReLU 函式中 \(x < 0\) 的部分調整為 \(\gamma \cdot x\), 其中 \(\gamma\) 常設定為 0.01 或 0.001 數量級的較小正數。這種新型的啟用函式被稱作帶洩露的 ReLU(Leaky ReLU)。

\[\text{Leaky ReLU}(x) = max(0, ?) + \gamma\ min(0, x) = \left\{\begin{matrix} x & x\geqslant 0 \\ \gamma \cdot x & x< 0 \end{matrix}\right. \]

2,PReLU 函式: 為了解決 Leaky ReLU 中超引數 \(\gamma\) 不易設定的問題,有研究者提出了引數化 ReLU(Parametric ReLU,PReLU)。引數化 ReLU 直接將 \(\gamma\) 也作為一個網路中可學習的變數融入模型的整體訓練過程。對於第 \(i\) 個神經元,PReLU 的 定義為:

\[\text{Leaky ReLU}(x) = max(0, ?) + \gamma_{i}\ min(0, x) = \left\{\begin{matrix} x & x\geqslant 0 \\ \gamma_{i} \cdot x & x< 0 \end{matrix}\right. \]

3,ELU 函式: 2016 年,Clevert 等人提出了 ELU(Exponential Linear Unit,指數線性單元),它是一個近似的零中心化的非線性函式。ELU 具備 ReLU 函式的優點,同時也解決了 ReLU 函式的“死區”問題,但是,其指數操作也增加了計算量。 \(\gamma ≥ 0\) 是一個超引數,決定 \(x ≤ 0\) 時的飽和曲線,並調整輸出均值在 0 附近。ELU 定義為:

\[\text{Leaky ReLU}(x) = max(0, ?) + min(0, \gamma(exp(x) - 1) = \left\{\begin{matrix} x & x\geqslant 0 \\ \gamma(exp(x) - 1) & x< 0 \end{matrix}\right. \]

4,Softplus 函式: Softplus 函式其導數剛好是 Logistic 函式.Softplus 函式雖然也具有單側抑制、寬 興奮邊界的特性,卻沒有稀疏啟用性。Softplus 定義為:

\[\text{Softplus}(x) = log(1 + exp(x)) \]

注意: ReLU 函式變體有很多,但是實際模型當中使用最多的還是 ReLU 函式本身

ReLU、Leaky ReLU、ELU 以及 Softplus 函式示意圖如下圖所示:

relu_more

Swish 函式

Swish 函式[Ramachandran et al., 2017] 是一種自門控(Self-Gated)啟用 函式,定義為

\[\text{swish}(x) = x\sigma(\beta x) \]

其中 \(\sigma(\cdot)\) 為 Logistic 函式,\(\beta\) 為可學習的引數或一個固定超引數。\(\sigma(\cdot) \in (0, 1)\) 可以看作一種軟性的門控機制。當 \(\sigma(\beta x)\) 接近於 1 時,門處於“開”狀態,啟用函式的輸出近似於 \(x\) 本身;當 \(\sigma(\beta x)\) 接近於 0 時,門的狀態為“關”,啟用函式的輸出近似於 0

Swish 函式程式碼定義如下,結合前面的畫曲線程式碼,可得 Swish 函式的示例圖。

def swish(x, beta = 0):
    """beta 是需要手動設定的引數"""
    return x * sigmoid(beta*x)

Swish 函式

Swish 函式可以看作線性函式和 ReLU 函式之間的非線性插值函式,其程度由引數 \(\beta\) 控制

啟用函式總結

常用的啟用函式包括 ReLU 函式、sigmoid 函式和 tanh 函式。下表彙總比較了幾個啟用函式的屬性:

activation_function

參考資料

  1. Pytorch分類問題中的交叉熵損失函式使用
  2. 《解析卷積神經網路-第8章》
  3. 《神經網路與深度學習-第4章》
  4. How to Choose an Activation Function for Deep Learning

相關文章