本章內容
7.1 符號與網路架構
7.2 激勵函數
7.3 交叉熵損失
7.4 反向傳播
7.5 梯度下降的直覺
7.6 權重初始化
7.7 參考資料
神經網路由許多「線性組合加上非線性轉換」的層堆疊而成。每一層本身都很簡單,但層層疊加之後,就能表達非常複雜的函數。訓練神經網路的流程也只有三個步驟反覆進行:前向傳播(forward propagation)計算預測與損失,反向傳播(backpropagation)計算每個參數的梯度,再用梯度下降更新參數。
這一章整理這個流程中最基礎的元件:符號約定、激勵函數、交叉熵損失、反向傳播的推導,以及常被忽略卻非常關鍵的權重初始化。更進階的最佳化演算法與訓練技巧,分別留到第 8 章 與第 9 章 。
7.1 符號與網路架構Notation & Architecture
符號約定
本書以 a j [ l ] ( i ) a_j^{[l](i)} a j [ l ] ( i ) 表示第 i i i 筆樣本在第 l l l 層第 j j j 個神經元的激勵值(activation):
符號
意義
範圍
[ l ] [l] [ l ]
第 l l l 層
l = 1 , … , L l = 1, \dots, L l = 1 , … , L
( i ) (i) ( i )
第 i i i 筆樣本
i = 1 , … , N i = 1, \dots, N i = 1 , … , N
j j j
該層的第 j j j 個神經元
j = 1 , … , n [ l ] j = 1, \dots, n^{[l]} j = 1 , … , n [ l ]
n [ l ] n^{[l]} n [ l ] 是第 l l l 層的神經元數。輸入層記為第 0 層,a [ 0 ] = x \mathbf{a}^{[0]} = \mathbf{x} a [ 0 ] = x ,不計入層數 :一個有一層隱藏層加上輸出層的網路,稱為 2 層網路,L = 2 L = 2 L = 2 。
前向傳播
每一層先做線性組合,得到預激勵值(pre-activation)z [ l ] \mathbf{z}^{[l]} z [ l ] ,再經過激勵函數 g [ l ] g^{[l]} g [ l ] 得到激勵值 a [ l ] \mathbf{a}^{[l]} a [ l ] ,作為下一層的輸入:
z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] a [ l ] = g [ l ] ( z [ l ] )
\begin{aligned}
\mathbf{z}^{[l]} &= W^{[l]}\mathbf{a}^{[l-1]} + \mathbf{b}^{[l]} \\
\mathbf{a}^{[l]} &= g^{[l]}\big(\mathbf{z}^{[l]}\big)
\end{aligned}
z [ l ] a [ l ] = W [ l ] a [ l − 1 ] + b [ l ] = g [ l ] ( z [ l ] ) 其中權重矩陣 W [ l ] W^{[l]} W [ l ] 的形狀是 n [ l ] × n [ l − 1 ] n^{[l]} \times n^{[l-1]} n [ l ] × n [ l − 1 ] ,偏權值 b [ l ] \mathbf{b}^{[l]} b [ l ] 是長度 n [ l ] n^{[l]} n [ l ] 的向量。寫成單一神經元就是 z j [ l ] = ∑ k w j k [ l ] a k [ l − 1 ] + b j [ l ] z_j^{[l]} = \sum_k w_{jk}^{[l]} a_k^{[l-1]} + b_j^{[l]} z j [ l ] = ∑ k w jk [ l ] a k [ l − 1 ] + b j [ l ] 。從第 1 層一路算到第 L L L 層,最後的 a [ L ] = y ^ \mathbf{a}^{[L]} = \hat{\mathbf{y}} a [ L ] = y ^ 就是網路的預測,再與標籤比較得到損失。
實作時會把 N N N 筆樣本排成矩陣的欄,一次算完整批資料,偏權值則以廣播(broadcasting)加到每一欄:
import numpy as np
def forward(X, params, L):
"""X 的形狀為 (n0, N),每一欄是一筆樣本。"""
A = X
for l in range(1, L + 1):
Z = params[f"W{l}"] @ A + params[f"b{l}"] # (n_l, N)
A = np.maximum(0, Z) if l < L else 1 / (1 + np.exp(-Z))
return A # 隱藏層用 ReLU,輸出層用 sigmoid
7.2 激勵函數Activation Functions
為什麼需要非線性
激勵函數的目的是提供非線性轉換。如果拿掉激勵函數(或使用線性函數),兩層網路會化簡成
W [ 2 ] ( W [ 1 ] x + b [ 1 ] ) + b [ 2 ] = ( W [ 2 ] W [ 1 ] ) x + ( W [ 2 ] b [ 1 ] + b [ 2 ] )
W^{[2]}\big(W^{[1]}\mathbf{x} + \mathbf{b}^{[1]}\big) + \mathbf{b}^{[2]} = \big(W^{[2]}W^{[1]}\big)\mathbf{x} + \big(W^{[2]}\mathbf{b}^{[1]} + \mathbf{b}^{[2]}\big)
W [ 2 ] ( W [ 1 ] x + b [ 1 ] ) + b [ 2 ] = ( W [ 2 ] W [ 1 ] ) x + ( W [ 2 ] b [ 1 ] + b [ 2 ] ) 仍然只是一個線性函數。無論疊多少層,結果都和單層線性模型一樣,深度完全沒有意義。加入非線性激勵函數,網路才能逼近複雜的非線性關係。
常見的激勵函數
函數
定義
值域
導數 g ′ ( z ) g'(z) g ′ ( z )
sigmoid
σ ( z ) = 1 1 + e − z \sigma(z) = \tfrac{1}{1 + e^{-z}} σ ( z ) = 1 + e − z 1
( 0 , 1 ) (0, 1) ( 0 , 1 )
σ ( z ) ( 1 − σ ( z ) ) \sigma(z)\big(1 - \sigma(z)\big) σ ( z ) ( 1 − σ ( z ) )
tanh
tanh ( z ) = e z − e − z e z + e − z \tanh(z) = \tfrac{e^{z} - e^{-z}}{e^{z} + e^{-z}} tanh ( z ) = e z + e − z e z − e − z
( − 1 , 1 ) (-1, 1) ( − 1 , 1 )
1 − tanh 2 ( z ) 1 - \tanh^2(z) 1 − tanh 2 ( z )
ReLU
max ( 0 , z ) \max(0, z) max ( 0 , z )
[ 0 , ∞ ) [0, \infty) [ 0 , ∞ )
z > 0 z > 0 z > 0 時為 1,z < 0 z < 0 z < 0 時為 0
Leaky ReLU
max ( α z , z ) \max(\alpha z, z) max ( α z , z )
( − ∞ , ∞ ) (-\infty, \infty) ( − ∞ , ∞ )
z > 0 z > 0 z > 0 時為 1,z < 0 z < 0 z < 0 時為 α \alpha α
ReLU 在 z = 0 z = 0 z = 0 不可微,實作上通常直接取導數為 0。Leaky ReLU 的 α \alpha α 是一個小的正數(例如 0.01),必須小於 1,max ( α z , z ) \max(\alpha z, z) max ( α z , z ) 的寫法才成立。
飽和與梯度消失
sigmoid 與 tanh 都是 S 形曲線,兩端趨於平坦。sigmoid 的導數最大只有 0.25(在 z = 0 z = 0 z = 0 ),tanh 的導數最大為 1(同樣在 z = 0 z = 0 z = 0 ),但只要 ∣ z ∣ \lvert z \rvert ∣ z ∣ 稍大,導數就迅速趨近 0:例如 tanh ′ ( 3 ) = 1 − tanh 2 ( 3 ) ≈ 0.0099 \tanh'(3) = 1 - \tanh^2(3) \approx 0.0099 tanh ′ ( 3 ) = 1 − tanh 2 ( 3 ) ≈ 0.0099 ,σ ′ ( 5 ) ≈ 0.0066 \sigma'(5) \approx 0.0066 σ ′ ( 5 ) ≈ 0.0066 。這種現象稱為飽和 (saturation)。落在飽和區的神經元幾乎得不到梯度,參數更新得極慢;反向傳播時又要把各層的導數連乘,多層之後梯度會越乘越小,形成梯度消失(vanishing gradient)。
常見誤區Common pitfall
tanh 的導數在 z = 0 z = 0 z = 0 附近最大,∣ z ∣ \lvert z \rvert ∣ z ∣ 越大越接近 0,而不是相反。也就是說,輸入落在兩端的飽和區時,梯度幾乎消失;這正是深層網路的隱藏層不建議使用 sigmoid 或 tanh 的原因。
在兩者之間,tanh 的輸出以 0 為中心(事實上 tanh ( z ) = 2 σ ( 2 z ) − 1 \tanh(z) = 2\sigma(2z) - 1 tanh ( z ) = 2 σ ( 2 z ) − 1 ),下一層的輸入比較平衡,作為隱藏層通常比 sigmoid 好;但它一樣會飽和。
ReLU 與其變體
ReLU 在 z > 0 z > 0 z > 0 時導數恆為 1,正半邊不會飽和,計算又非常便宜,因此是隱藏層的預設選擇 。它的缺點是 z < 0 z < 0 z < 0 時梯度為 0:若某個神經元的輸入長期為負(例如一次過大的參數更新之後),它就再也不會更新,稱為「死亡 ReLU」(dying ReLU)。Leaky ReLU 在負半邊保留一個小斜率 α \alpha α ,讓梯度仍能流動;ELU、GELU(Transformer 中常用)等變體也出於類似的考量。
輸出層的選擇
輸出層的激勵函數由任務決定,而且要與損失函數搭配:
任務
輸出層激勵函數
搭配的損失
二元分類
sigmoid
二元交叉熵
多類別分類(單一標籤)
softmax
多類別交叉熵
多標籤分類
每個輸出各自用 sigmoid
二元交叉熵
迴歸
線性(恆等函數)
平方誤差
非負的迴歸目標
ReLU 或 softplus
依任務而定
7.3 交叉熵損失Cross-Entropy Loss
二元交叉熵
二元分類時,令 t i ∈ { 0 , 1 } t_i \in \{0, 1\} t i ∈ { 0 , 1 } 為目標(target),代表第 i i i 筆是否為正例;y i ∈ ( 0 , 1 ) y_i \in (0, 1) y i ∈ ( 0 , 1 ) 為模型預測 t i = 1 t_i = 1 t i = 1 的機率(sigmoid 的輸出)。損失為
J = − ∑ i = 1 N [ t i log y i + ( 1 − t i ) log ( 1 − y i ) ]
J = -\sum_{i=1}^{N}\Big[\,t_i \log y_i + (1 - t_i)\log(1 - y_i)\Big]
J = − i = 1 ∑ N [ t i log y i + ( 1 − t i ) log ( 1 − y i ) ] 每一項中只有一半會作用:t i = 1 t_i = 1 t i = 1 時損失是 − log y i -\log y_i − log y i ,t i = 0 t_i = 0 t i = 0 時是 − log ( 1 − y i ) -\log(1 - y_i) − log ( 1 − y i ) 。模型越有把握地答錯(例如 t i = 1 t_i = 1 t i = 1 卻預測 y i ≈ 0 y_i \approx 0 y i ≈ 0 ),損失就越趨近無限大。
這個形式不是憑空設計的。若把每筆標籤視為伯努利分布,概似是 ∏ i y i t i ( 1 − y i ) 1 − t i \prod_i y_i^{t_i}(1 - y_i)^{1 - t_i} ∏ i y i t i ( 1 − y i ) 1 − t i ,取負對數正好得到 J J J 。因此最小化交叉熵就是最大概似估計 ,也等於最小化真實分布與預測分布之間的 KL 散度(見第 6 章 )。
多類別交叉熵
K K K 個類別時,輸出層以 softmax 把 logit a k a_k a k 轉成機率,目標 t i \mathbf{t}^{i} t i 以 one-hot 向量表示:
y k = e a k ∑ l = 1 K e a l , J = − ∑ i = 1 N ∑ k = 1 K t k i log y k i
y_k = \frac{e^{a_k}}{\sum_{l=1}^{K} e^{a_l}}, \qquad J = -\sum_{i=1}^{N}\sum_{k=1}^{K} t_k^{i}\log y_k^{i}
y k = ∑ l = 1 K e a l e a k , J = − i = 1 ∑ N k = 1 ∑ K t k i log y k i 因為 t i \mathbf{t}^{i} t i 只有正確類別 c i c_i c i 那一格是 1,損失其實就是 − ∑ i log y c i i -\sum_i \log y_{c_i}^{i} − ∑ i log y c i i :只看模型給正確答案多少機率。二元交叉熵是 K = 2 K = 2 K = 2 的特例。實務上常除以 N N N 取平均,不改變最小值的位置,但讓學習率不受批次大小影響。
為什麼不用平方誤差
分類問題若改用 sigmoid 加平方誤差,對 logit 的梯度會多出一個 σ ′ ( a ) \sigma'(a) σ ′ ( a ) 因子。當模型錯得很離譜、輸出落在飽和區時,σ ′ ( a ) ≈ 0 \sigma'(a) \approx 0 σ ′ ( a ) ≈ 0 ,梯度反而消失,學不動。下一節會看到,交叉熵對 logit 的梯度正好是 y − t y - t y − t ,誤差越大梯度越大,沒有這個問題。
實作時,不要先算 softmax 再取對數,而是直接由 logit 計算,並先減去最大值避免 e a e^{a} e a 溢位(log-sum-exp 技巧)。主流框架的交叉熵函數(例如 PyTorch 的 nn.CrossEntropyLoss)也都直接接收 logit:
def softmax_cross_entropy(logits, t):
"""logits、t 的形狀皆為 (N, K),t 為 one-hot。回傳平均損失。"""
a = logits - logits.max(axis=1, keepdims=True) # 避免 exp 溢位
log_y = a - np.log(np.exp(a).sum(axis=1, keepdims=True))
return -(t * log_y).sum(axis=1).mean()
7.4 反向傳播Backpropagation
反向傳播就是有系統地套用連鎖律(chain rule):從輸出層開始,一層一層往回計算損失對每個中間量的偏導數,並重複利用已經算好的結果。這讓計算所有參數梯度的成本,與一次前向傳播大致同一個數量級。
設定
以一個單隱藏層、softmax 輸出的分類網路為例:
輸入層
權重
隱藏層
權重
輸出層
D D D 個特徵 x 1 , … , x D x_1, \dots, x_D x 1 , … , x D
w d m w_{dm} w d m
M M M 個單元 z 1 , … , z M z_1, \dots, z_M z 1 , … , z M
v m k v_{mk} v mk
K K K 個類別 y 1 , … , y K y_1, \dots, y_K y 1 , … , y K
s m = ∑ d = 1 D w d m x d , z m = g ( s m ) a k = ∑ m = 1 M v m k z m , y k = e a k ∑ l = 1 K e a l
\begin{aligned}
s_m &= \sum_{d=1}^{D} w_{dm}\,x_d, \qquad z_m = g(s_m) \\
a_k &= \sum_{m=1}^{M} v_{mk}\,z_m, \qquad y_k = \frac{e^{a_k}}{\sum_{l=1}^{K} e^{a_l}}
\end{aligned}
s m a k = d = 1 ∑ D w d m x d , z m = g ( s m ) = m = 1 ∑ M v mk z m , y k = ∑ l = 1 K e a l e a k 為了簡潔,偏權值省略不寫(可以視為一個恆等於 1 的額外輸入 x 0 = z 0 = 1 x_0 = z_0 = 1 x 0 = z 0 = 1 )。
補充Note
這一節沿用 Bishop 的寫法(ESL 同樣以 Z m Z_m Z m 表示隱藏層輸出):z m z_m z m 是隱藏層「經過激勵之後」的輸出,a k a_k a k 是輸出層「進入 softmax 之前」的 logit,正好與前面 [ l ] [l] [ l ] 符號中 z z z 、a a a 的角色相反。對照起來,這裡的 z m z_m z m 就是 a m [ 1 ] a_m^{[1]} a m [ 1 ] ,a k a_k a k 就是 z k [ 2 ] z_k^{[2]} z k [ 2 ] 。
步驟一:softmax 的導數
對 y j = e a j / ∑ l e a l y_j = e^{a_j} / \sum_l e^{a_l} y j = e a j / ∑ l e a l 用商的微分法則,分 j = k j = k j = k 與 j ≠ k j \ne k j = k 兩種情況:
∂ y j ∂ a k = { y k ( 1 − y k ) , j = k − y j y k , j ≠ k = y j ( δ j k − y k )
\frac{\partial y_j}{\partial a_k} =
\begin{cases}
y_k(1 - y_k), & j = k \\
-\,y_j\,y_k, & j \ne k
\end{cases}
\;=\; y_j\,(\delta_{jk} - y_k)
∂ a k ∂ y j = { y k ( 1 − y k ) , − y j y k , j = k j = k = y j ( δ jk − y k ) 其中 δ j k \delta_{jk} δ jk 是 Kronecker delta:j = k j = k j = k 時為 1,否則為 0。
步驟二:損失對 logit 的導數
先看單一樣本(省略上標 i i i ),J = − ∑ j t j log y j J = -\sum_j t_j \log y_j J = − ∑ j t j log y j 。改變 a k a_k a k 會影響所有的 y j y_j y j ,所以要對 j j j 加總:
∂ J ∂ a k = − ∑ j = 1 K t j 1 y j ∂ y j ∂ a k = − ∑ j = 1 K t j ( δ j k − y k ) = − ( t k − y k ∑ j = 1 K t j ) = y k − t k
\begin{aligned}
\frac{\partial J}{\partial a_k}
&= -\sum_{j=1}^{K} t_j\,\frac{1}{y_j}\,\frac{\partial y_j}{\partial a_k} \\
&= -\sum_{j=1}^{K} t_j\,(\delta_{jk} - y_k) \\
&= -\Big(t_k - y_k\sum_{j=1}^{K} t_j\Big) \\
&= y_k - t_k
\end{aligned}
∂ a k ∂ J = − j = 1 ∑ K t j y j 1 ∂ a k ∂ y j = − j = 1 ∑ K t j ( δ jk − y k ) = − ( t k − y k j = 1 ∑ K t j ) = y k − t k 第二行中,1 y j \tfrac{1}{y_j} y j 1 與 softmax 導數裡的 y j y_j y j 互相抵銷;第三行中,∑ j t j δ j k = t k \sum_j t_j \delta_{jk} = t_k ∑ j t j δ jk = t k ;最後一行用到 ∑ j t j = 1 \sum_j t_j = 1 ∑ j t j = 1 ,因為目標本身是一個機率分布(one-hot 向量只有一格為 1)。
步驟三:損失對輸出層權重的導數
v m k v_{mk} v mk 只透過 a k a_k a k 影響損失,且 ∂ a k / ∂ v m k = z m \partial a_k / \partial v_{mk} = z_m ∂ a k / ∂ v mk = z m 。把所有樣本的貢獻加總:
∂ J ∂ v m k = ∑ i = 1 N ∂ J ∂ a k i ∂ a k i ∂ v m k = ∑ i = 1 N ( y k i − t k i ) z m i
\frac{\partial J}{\partial v_{mk}} = \sum_{i=1}^{N}\frac{\partial J}{\partial a_k^{i}}\,\frac{\partial a_k^{i}}{\partial v_{mk}} = \sum_{i=1}^{N}\big(y_k^{i} - t_k^{i}\big)\,z_m^{i}
∂ v mk ∂ J = i = 1 ∑ N ∂ a k i ∂ J ∂ v mk ∂ a k i = i = 1 ∑ N ( y k i − t k i ) z m i 讀法很直觀:權重的梯度 = 輸出端的誤差訊號 × 輸入端的激勵值 。寫成矩陣,若 Z Z Z 是 N × M N \times M N × M 的隱藏層輸出、Y Y Y 與 T T T 是 N × K N \times K N × K 的預測與目標,則梯度為 Z ⊤ ( Y − T ) Z^\top (Y - T) Z ⊤ ( Y − T ) 。
重點Key point
softmax 搭配多類別交叉熵(以及 sigmoid 搭配二元交叉熵)時,損失對 logit 的梯度就是「預測減目標」y − t y - t y − t 。沒有激勵函數導數的因子,也就不會因為飽和而學不動,這是輸出層總是這樣搭配的原因。
步驟四:傳回隱藏層
令輸出層的誤差訊號 e k i = y k i − t k i e_k^{i} = y_k^{i} - t_k^{i} e k i = y k i − t k i 。隱藏單元 z m z_m z m 透過所有的 a k a_k a k 影響損失,因此要把各輸出的誤差沿權重 v m k v_{mk} v mk 加權傳回,再乘上自己的激勵函數導數:
e m i ≡ ∂ J ∂ s m i = g ′ ( s m i ) ∑ k = 1 K v m k e k i ∂ J ∂ w d m = ∑ i = 1 N e m i x d i
\begin{aligned}
e_m^{i} \equiv \frac{\partial J}{\partial s_m^{i}} &= g'(s_m^{i})\sum_{k=1}^{K} v_{mk}\,e_k^{i} \\
\frac{\partial J}{\partial w_{dm}} &= \sum_{i=1}^{N} e_m^{i}\,x_d^{i}
\end{aligned}
e m i ≡ ∂ s m i ∂ J ∂ w d m ∂ J = g ′ ( s m i ) k = 1 ∑ K v mk e k i = i = 1 ∑ N e m i x d i 同樣的模式可以一路往回套用到任意深度。以 [ l ] [l] [ l ] 符號、單一樣本表示,記 d z [ l ] = ∂ J / ∂ z [ l ] d\mathbf{z}^{[l]} = \partial J / \partial \mathbf{z}^{[l]} d z [ l ] = ∂ J / ∂ z [ l ] :
d z [ L ] = a [ L ] − t d z [ l ] = ( W [ l + 1 ] ) ⊤ d z [ l + 1 ] ⊙ g ′ [ l ] ( z [ l ] ) ∂ J ∂ W [ l ] = d z [ l ] ( a [ l − 1 ] ) ⊤ , ∂ J ∂ b [ l ] = d z [ l ]
\begin{aligned}
d\mathbf{z}^{[L]} &= \mathbf{a}^{[L]} - \mathbf{t} \\
d\mathbf{z}^{[l]} &= \big(W^{[l+1]}\big)^\top d\mathbf{z}^{[l+1]} \odot g'^{[l]}\big(\mathbf{z}^{[l]}\big) \\
\frac{\partial J}{\partial W^{[l]}} &= d\mathbf{z}^{[l]}\,\big(\mathbf{a}^{[l-1]}\big)^\top, \qquad \frac{\partial J}{\partial \mathbf{b}^{[l]}} = d\mathbf{z}^{[l]}
\end{aligned}
d z [ L ] d z [ l ] ∂ W [ l ] ∂ J = a [ L ] − t = ( W [ l + 1 ] ) ⊤ d z [ l + 1 ] ⊙ g ′ [ l ] ( z [ l ] ) = d z [ l ] ( a [ l − 1 ] ) ⊤ , ∂ b [ l ] ∂ J = d z [ l ] 其中 ⊙ \odot ⊙ 是逐元素相乘。第二行也說明了梯度消失與爆炸的來源:每往回一層,就要乘上一次權重矩陣與激勵函數導數。
7.5 梯度下降的直覺Gradient Descent Intuition
梯度指向函數值上升最快的方向。要讓損失變小,就沿著梯度的反方向走一小步:
θ ← θ − η ∇ θ J ( θ )
\theta \leftarrow \theta - \eta\,\nabla_\theta J(\theta)
θ ← θ − η ∇ θ J ( θ ) 其中 η \eta η 是學習率(learning rate)。可以把凸的成本函數想像成一個碗,全域最小值在碗底;不論從哪裡出發,一路往下坡走,最後都會到達碗底,這就是梯度下降(gradient descent)。反過來,若目標是最大化某個函數(例如對數概似),就沿梯度方向往上走,稱為梯度上升(gradient ascent):θ ← θ + η ∇ θ ℓ ( θ ) \theta \leftarrow \theta + \eta\,\nabla_\theta \ell(\theta) θ ← θ + η ∇ θ ℓ ( θ ) ,這與對 − ℓ -\ell − ℓ 做梯度下降完全相同。
神經網路的損失函數並不是凸的,存在許多局部最小值、鞍點與平坦區,梯度下降不保證找到全域最小值;但在高維的參數空間中,實務上通常仍能找到表現很好的解。學習率太大會來回震盪甚至發散,太小則收斂緩慢。小批次梯度下降、動量、Adam 等改良方法見第 8 章 。
7.6 權重初始化Weight Initialization
為什麼不能全部設為 0
如果同一層的權重全部相同(例如全為 0),該層每個神經元的輸出都一樣,反向傳播得到的梯度也一樣,更新之後依然相同。無論訓練多久,整層都只相當於一個神經元。因此權重必須隨機初始化,以打破對稱性(symmetry breaking);偏權值則可以設為 0。
梯度爆炸與消失
隨機初始化的尺度也很重要。暫時忽略激勵函數與偏權值,深層網路的輸出近似於 W [ L ] ⋯ W [ 2 ] W [ 1 ] x W^{[L]} \cdots W^{[2]} W^{[1]}\mathbf{x} W [ L ] ⋯ W [ 2 ] W [ 1 ] x 。若每一層的權重都讓訊號放大 1.5 倍,50 層之後就放大了 1.5 50 ≈ 6.4 × 10 8 1.5^{50} \approx 6.4 \times 10^{8} 1. 5 50 ≈ 6.4 × 1 0 8 倍;若每層縮小為 0.5 倍,則變成 0.5 50 ≈ 8.9 × 10 − 16 0.5^{50} \approx 8.9 \times 10^{-16} 0. 5 50 ≈ 8.9 × 1 0 − 16 。反向傳播的梯度同樣是權重的連乘,所以權重只要略大於或略小於 1,影響就會隨深度呈指數成長 ,造成梯度爆炸(exploding gradient)或梯度消失。
讓變異數維持穩定
好的初始化讓每一層輸出的變異數大致維持不變。考慮 z = ∑ k = 1 n w k a k z = \sum_{k=1}^{n} w_k a_k z = ∑ k = 1 n w k a k ,其中 n = n [ l − 1 ] n = n^{[l-1]} n = n [ l − 1 ] 。假設權重與輸入互相獨立、權重平均為 0,則
Var ( z [ l ] ) = n [ l − 1 ] Var ( w ) E [ ( a [ l − 1 ] ) 2 ]
\operatorname{Var}\big(z^{[l]}\big) = n^{[l-1]}\operatorname{Var}(w)\,\mathbb{E}\Big[\big(a^{[l-1]}\big)^2\Big]
Var ( z [ l ] ) = n [ l − 1 ] Var ( w ) E [ ( a [ l − 1 ] ) 2 ]
對 tanh 這類以 0 為中心、在原點附近近似線性的激勵函數,E [ a 2 ] ≈ Var ( z [ l − 1 ] ) \mathbb{E}[a^2] \approx \operatorname{Var}(z^{[l-1]}) E [ a 2 ] ≈ Var ( z [ l − 1 ] ) ,要讓變異數不變,就需要 Var ( w ) = 1 / n [ l − 1 ] \operatorname{Var}(w) = 1/n^{[l-1]} Var ( w ) = 1/ n [ l − 1 ] 。
ReLU 把一半的輸入歸零,E [ a 2 ] = 1 2 Var ( z [ l − 1 ] ) \mathbb{E}[a^2] = \tfrac{1}{2}\operatorname{Var}(z^{[l-1]}) E [ a 2 ] = 2 1 Var ( z [ l − 1 ] ) ,因此需要兩倍的變異數 Var ( w ) = 2 / n [ l − 1 ] \operatorname{Var}(w) = 2/n^{[l-1]} Var ( w ) = 2/ n [ l − 1 ] ,這就是 He 初始化。
Glorot 與 Bengio 進一步考慮反向傳播時梯度的變異數(需要 Var ( w ) = 1 / n [ l ] \operatorname{Var}(w) = 1/n^{[l]} Var ( w ) = 1/ n [ l ] ),取兩者折衷得到 2 / ( n [ l − 1 ] + n [ l ] ) 2/(n^{[l-1]} + n^{[l]}) 2/ ( n [ l − 1 ] + n [ l ] ) 。
方法
搭配的激勵函數
Var ( w ) \operatorname{Var}(w) Var ( w )
標準常態樣本乘上
He 初始化
ReLU 及其變體
2 / n [ l − 1 ] 2/n^{[l-1]} 2/ n [ l − 1 ]
2 / n [ l − 1 ] \sqrt{2/n^{[l-1]}} 2/ n [ l − 1 ]
LeCun(Xavier 只考慮前向的版本)
tanh
1 / n [ l − 1 ] 1/n^{[l-1]} 1/ n [ l − 1 ]
1 / n [ l − 1 ] \sqrt{1/n^{[l-1]}} 1/ n [ l − 1 ]
Xavier/Glorot
tanh、sigmoid
2 / ( n [ l − 1 ] + n [ l ] ) 2/(n^{[l-1]} + n^{[l]}) 2/ ( n [ l − 1 ] + n [ l ] )
2 / ( n [ l − 1 ] + n [ l ] ) \sqrt{2/(n^{[l-1]} + n^{[l]})} 2/ ( n [ l − 1 ] + n [ l ] )
只考慮前向的 1 / n [ l − 1 ] 1/n^{[l-1]} 1/ n [ l − 1 ] 版本也常稱為 LeCun 初始化。實作上就是從標準常態分布抽樣,再乘上縮放係數:
# 第 l 層的權重,形狀為 (n_l, n_prev)
W = np.random.randn(n_l, n_prev) * np.sqrt(2.0 / n_prev) # He,搭配 ReLU
W = np.random.randn(n_l, n_prev) * np.sqrt(1.0 / n_prev) # LeCun(常稱 Xavier),搭配 tanh
b = np.zeros((n_l, 1))
常見誤區Common pitfall
表中的 tanh、ReLU 指的是「這種初始化適合搭配哪一種激勵函數」,不是把權重代入 tanh 或乘上 tanh。做法一律是 w = randn × ⋯ w = \text{randn} \times \sqrt{\cdots} w = randn × ⋯ ,讓權重的變異數等於表中的值。Glorot 的論文也提供均勻分布版本 U ( − 6 / ( n [ l − 1 ] + n [ l ] ) , 6 / ( n [ l − 1 ] + n [ l ] ) ) U\big(-\sqrt{6/(n^{[l-1]} + n^{[l]})},\ \sqrt{6/(n^{[l-1]} + n^{[l]})}\big) U ( − 6/ ( n [ l − 1 ] + n [ l ] ) , 6/ ( n [ l − 1 ] + n [ l ] ) ) ,變異數相同。
適當的初始化能緩解梯度消失與爆炸,但無法完全消除。其他手段還包括批次正規化(batch normalization,見第 8 章 )、殘差連接(residual connection,見第 10 章 )與梯度裁剪(gradient clipping,見第 11 章 )。
7.7 參考資料References
Goodfellow, Bengio & Courville, Deep Learning , MIT Press, 2016,第 6 章 Deep Feedforward Networks、第 8 章 Optimization for Training Deep Models。
Bishop, C. M., Pattern Recognition and Machine Learning , Springer, 2006,第 5 章 Neural Networks。
Rumelhart, D. E., Hinton, G. E. & Williams, R. J., "Learning representations by back-propagating errors", Nature , 1986。
Glorot, X. & Bengio, Y., "Understanding the difficulty of training deep feedforward neural networks", AISTATS , 2010。
He, K., Zhang, X., Ren, S. & Sun, J., "Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification", ICCV , 2015。
Nair, V. & Hinton, G. E., "Rectified linear units improve restricted Boltzmann machines", ICML , 2010。
Stanford CS231n, Convolutional Neural Networks for Visual Recognition 課程筆記。
deeplearning.ai, Neural Networks and Deep Learning 與 Improving Deep Neural Networks (Coursera 深度學習專項課程第一、二門課)。