# CS231N (2017) Lec 04 課程筆記
###### tags: `CV`
🔷 計算圖(Computational Graph)
📌 Recall
Lec 03 提到了兩種分析梯度的方法
(1) 實務上不可行,可做為 debugging tool,慢且不準確的「數值型梯度」(numerical gradient)
(2) 實務上可行,快且準確的「分析型梯度」(analytic gradient)
📌 Today topic
issue: 如何針對任意複雜的函數: 計算其「分析型梯度」
tool: 計算圖(Computational Graph)
📌 計算圖(Computational Graph)
利用多個節點以解釋損失函數的計算過程,每個節點代表一個計算步驟
📌 反向梯度傳播(Backward Propagation)
計算梯度的主要工具,遞迴地: 使用鏈鎖率(chain rule)計算梯度(即: 偏導數)
-------------------------
從終點(箭頭的終點,位於最右側)起算,
逐漸向左移動(逆向或反向傳播)到起點(箭頭的起點,位於最左側)
-------------------------
🔘 計算範例 -1: fig. 6-8
每條線之上的是旁邊節點的函數值,
每條線之上的是旁邊節點的梯度值=偏導數值
🔘 計算範例 -2: fig. 9-11
(1) 對於一張「計算圖」(computational graph),
可先定義所有「計算節點」(computational nodes)
(2) 直接指向(向前傳播到)每個 計算節點 的梯度
可分解為:
「上游梯度」(upstream gradient)
和「局部梯度」(local gradient)
🔘 計算範例 -3: fig. 12-16
f (w, x) = 1 / (1 + e ^ [ - ( w_0 * x_0 + w_1 * x_1 + w_2 ) ] )
這是個比較複雜(計算節點較多)的計算圖
但對應到(指向,向前傳播到)每個節點的 2 個輸出
都可拆解為: 加法 及 乘法 的簡單形式
---
透過 (a) 計算導數 和 (b) 梯度 = 上游梯度 x 局部梯度
便可從最右側的終點
逐個向後(箭頭的反方向,即左側)計算梯度
---
> 詳見 "fig. 12 - 梯度計算過程"
🔘 計算範例 -4: fig. 17
"計算範例 -3" 中的 1 / (1 + e ^ -x) 等效於 Sigmoid 函數: σ(x)
經過以下推導,
我們知道 Sigmoid 函數對 x 的導數可簡化為: [ 1 - σ(x) ] * σ(x)
因此「計算 1 / (1 + e ^ -x) 的梯度」原本需要 4 次運算
可替換為計算這個簡化後的算式: [ 1 - σ(x) ] * σ(x),只需 1 次運算
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
σ(x) = 1 / (1+e^-x)
d [ σ(x) ] / dx = d [ (1+e^-x)^(-1) ] / dx
= (-1) * (1+e^-x)^(-2) * [0+(-e^-x)]
= e^-x / (1+e^-x)^2
= (1+e^-x-1) * 1 / (1+e^-x)^2
= [ (1+e^-x-1) / (1+e^-x) ] * [ 1 / (1+e^-x) ]
= [ 1 - σ(x) ] * σ(x)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 詳見 "fig. 12 - 梯度計算過程"
🔘 梯度計算的表示
∂ f / ∂ x = Σ_i (∂ f / ∂ q_i) * (∂ q_i / ∂ x)
📌 向量編碼後的梯度(Gradient for vectorized code)
假設 f 函數有兩輸入: x 和 y,並有一輸出 z
則: 損失函數 L 在 x 方向上的梯度為
∂ L / ∂ x = (∂ L / ∂ z) * (∂ z / ∂ x) ,
其中: (1) ∂ L / ∂ z 為 上游梯度, ∂ z / ∂ x 為 局部梯度
// 與 non-vectorized 無異
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(2) x, y, z 皆為「向量」而非數值
// 與 non-vectorized 不同
(3) 局部梯度: ∂ z / ∂ x 為「Jacobian 矩陣」
// 與 non-vectorized 不同
// 代表 "z 向量所有元素" 對 "各自對應的 x 向量元素" 的若干個偏導數所構成的矩陣
📌 向量化運算(Vectorized operations)
輸入: 4096 維, 向量
輸出: 4096 維, 向量
函數: f (x) = max (0, x),
對應於: 逐個元素(element-wise, i.e., x)
(1) Jacobian 矩陣的大小
4096 x 4096 ➡️ 對單一訓練樣本
409600 x 409600 ➡️ 對(實際上常見的)多個訓練樣本
此例假設有 100 個樣本/每個 mini-batch
➡️ 41 萬 x 41 萬
= 1677 億個元素(需運算次數)---❌: 實務上不可行
➡️ 考慮「哪個輸入維度」各自會主要影響對應的「哪個輸出維度」
可推知: row 1 → col 1, row 2 → col 2, row 3 → col 3, etc.
輸出會被輸入影響的主要維度,皆位於對角線上
因此,實務上在建立 Jacobian 矩陣時:
(1) 會先計算「對角線元素」
(2) 再填充其它非對角線元素
42:48
(2) 範例
🔘 輸入和節點
f (x, W) = | dot_product( W, X ) | ^2
= Σ_i to n [ (dot_product( W, X )_i) ^2 ]
W: 「權重」輸入值,
函數值為一個 2x2 矩陣,
其值為 [ [ 0.1 0.5 ] [ -0.3 0.8 ] ]
x : 「資料(特徵)」輸入值,
函數值為一個 2x1 向量,
其值為 [ [ 0.2 ] [ 0.4 ] ]
q : 「*」節點的函數,
函數值為一個 2x1 向量,
其中 q = dot_product( W, x ),
其函數值(輸出)為 [ [ 0.22 ] [ 0.26 ] ]
f (q) : 「L2」節點的函數,
函數值為一個常數,
其中 f (q) = | q | ^2 = q_1 ^2 + ... + q_n ^2,
其函數值為 0.116
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔘 梯度計算
(a) ∂ f / ∂ q_i
= ∂ ( || q || ^2 ) / ∂ q_i
= 2 * q_i
➡️ ▽_q f = dot (2 , q) (反向傳播的「梯度」和順向傳播「原始數值」的關係式)
➡️ 利用上述的關係式,可計算
對應到 q 函數值(輸出)的梯度:
▽_q f = 2 * [ [ 0.22 ] [ 0.26 ] ]
= [ [ 0.44 ] [ 0.52 ] ]
(b) ∂ f / ∂ W_( i, j )
-------------------------
∂ q_( i ) / ∂ W_( i, j )
= x_( j )
∂ f / ∂ W_( i, j )
= [ ∂ ( || q_( i ) || ^2 ) / ∂ q_( i ) ] * [ ∂ q_( i ) / ∂ W_( i, j ) ]
= 2 * q_( i ) * x_( j )
➡️ ▽_w f = dot ( 2 * q, transpose( x ) )
(反向傳播的「梯度」和順向傳播「原始數值」的關係式)
➡️ 利用上述的關係式,可計算
對應到 w 函數值(輸出)的梯度:
▽_w f = 2 * [ [ 0.22 ] [ 0.26 ] ] * [ 0.2 0.4 ]
= [ [ 0.44 ] [ 0.52 ] ] * [ 0.2 0.4 ] // (2x1) x (1x2) => (2x2)
= [ [ 0.44*0.2 0.44*0.4 ]
[ 0.52*0.2 0.52*0.4 ] ]
= [ [ 0.088 0.176 ]
[ 0.104 0.208 ] ]
// 永遠記得檢查:「變數的梯度」與「變數本身」兩者應「尺寸相同」
// i.e., shape (▽_w f ) = shape(w) = (2, 2) // 2 row x 2 col
(c) ∂ f / ∂ x_( j )
-------------------------
∂ q_( i ) / ∂ x_( j )
= W_( i, j )
∂ f / ∂ x_( j )
= [ ∂ ( || q_( i ) || ^2 ) / ∂ q_( i ) ] * [ ∂ q_( i ) / ∂ x_( j ) ]
= 2 * q_( i ) * W_( i, j )
➡️ ▽_x f = dot ( transpose( w ), 2 * q )
(反向傳播的「梯度」和順向傳播「原始數值」的關係式)
➡️ 利用上述的關係式,可計算
對應到 x 函數值(輸出)的梯度:
▽_x f = transpose(w) * 2 * [ [ 0.22 ] [ 0.26 ] ]
= [ [ 0.1 -0.3 ] [ 0.5 0.8 ] ] * [ [ 0.44 ] [ 0.52 ] ]
= [ [ -0.112 ] [ 0.636 ] ]
// 永遠記得檢查:「變數的梯度」與「變數本身」兩者的「尺寸」應相同
// i.e., shape (▽_x f ) = shape(x) = (2, 1) // 2 row x 1 col
📌 模組化實現: forward/backward API
(略)
Caffe: 快速特嵌入的卷積結構
🔷 神經網路(Neural Network): 借鏡大腦神經網路的「功能」作為架構,但不包含其「內容」
(1) Before: Linear score function 線性分數函數
f = W x
(2) Now: 2-layer Neural Network 雙層神經網路
f = W_2 * max ( 0, W_1 * x )
or 3-layer Neural Network 三層神經網路
f = W_3 * max ( 0, W_2 * max ( 0, W_1 * x ) )
神經網路 = 階層式堆疊(Hierarchically stack)多個線性層,其中帶有幾個非線性函數(層)
----------------------------------------------------------------
Analog:
「權重矩陣 W」
就像是用來表達輸入數值(express input values)的「模板」(template)
----------------------------------------------------------------
Explanation:
W_1: 與輸入 X 直接相連,因此較依賴於「輸入特徵」
無法有效的廣義化(泛化, generalize)
假設訓練集的「車子類別」只包含紅色車,則黃色車與 W_1 模板的匹配程度較低
W_2: 為一個「加權和」(weighted sum)
相較 W_1,較能有效的廣義化(泛化, generalize)
假設訓練集的「車子類別」只包含紅色車,則黃色車與 W_2 模板的匹配程度較高
// 若能得到類似上述這樣的結果,實務上很有用,
// 代表模型接近輸出層的權重矩陣 W_n 有學習出:
// 「車子」除了「顏色特徵」以外的「其它特徵」
// 且足夠廣義化的模型,在 測試集 或 未知資料 上的穩健性較佳
h: 「分數向量」,代表: 對應到 每個類別模板 的分數
其計算方法在此為線性整流函數 ReLU,即: max ( 0, W_1 * X )
// 註: 「線性整流函數 ReLU」是一個「非線性」函數
(3) Neuron 神經元
🔘 nerve impulse(神經脈衝): 又稱 spike,來自外部的刺激,可以推動細胞本體前進
➡️ 即: 數值/訊號
🔘 dendrite(樹突): 「接收」外部神經脈衝,流向細胞本體
➡️ 即: 輸入層
🔘 cell body(細胞本體): 「整合」外部神經脈衝
➡️ 即: 淨輸入/分數向量
🔘 axon(軸突): 「傳遞」經整合的刺激訊號到下游的神經元
➡️ 即: 中間層
🔘 presynaptic terminal(突觸前神經元): 位於下游的神經元
➡️ 即: 輸出層
(4) Activation function 激勵函數
🔘 Sigmoid
➡️ σ ( x ) = 1 / ( 1 + e ^ -x )
🔘 tanh
➡️ tanh ( x )
🔘 ReLU
➡️ max ( 0, x )
🔘 Leaky ReLU
➡️ max ( 0.1 * x, x )
🔘 ELU
➡️ x if x >= 0
α ( e ^ x + 1 ) otherwise
🔘 Maxout
➡️ max ( w_1 * x + b_1, w_2 * x + b_2 )