cs224n學習筆記L4: Backpropagation and computation graphs

課堂安排

  • 簡單網絡的梯度計算以及一些小提示
  • 計算圖和反向傳播
  • 需要掌握的知識
    a. 防止過擬合的規則 b. 向量化 c. 非線性 d. 初始化 e. 優化器 f.學習率

一、反向傳播·續

1.1 sW\frac{\partial s}{\partial W}的計算推導

上一節課我們得到:
sW=δzW \frac { \partial s } { \partial \boldsymbol { W } } = \boldsymbol { \delta }\frac{\partial z}{\partial W}
假設zz長度爲n, xx長度爲m,那麼我們現在來看看zW\frac{\partial z}{\partial W}, 由於W是一個n × m的矩陣, 我們單獨看一個元素WijW_{ij}。由於WijW_ij只對ziz_i有影響,因此:
ziWij=Wijk=1mWikxk=xj(j=k)\frac{\partial z_i}{\partial W_{ij}} = \frac{\partial }{\partial W_{ij}} \sum_{k = 1}^{m}W_{ik}x_k = x_j (即j=k時的係數)
所以有:
ziW=xT\frac{\partial z_i}{\partial W} = x^T
那麼zW\frac{\partial z}{\partial W} 就應該是一個n × m的矩陣, 而sWij=δixj\frac{\partial s}{\partial W_{ij}} = \delta_ix_j , 所以有:
sW=δxT[n×m][n×1][1×m] \begin{aligned} & \frac { \partial s } { \partial \boldsymbol { W } } = &\boldsymbol { \delta }&\boldsymbol { x } ^ { T } \\ &[ n \times m ] &[ n \times 1 ]& [ 1 \times m ] \end{aligned}

1.2 梯度推導溫馨提示

  1. 嚴肅認真的定義變量,並且始終記得維護他們的維度一致性
  2. 運用鏈式法則
  3. 對於頂層的softmax推導,要先考慮c=yc=y,即正確類別,然後考慮cyc \ne y, 即錯誤類別。
  4. 如果對矩陣推導感覺迷惑了,就進行元素級別的計算
  5. 運用維度傳播規律,任意一層的誤差信號δ\delta的長度與該層的大小相同。

1.3 輸入x的偏導

對於x的偏導,輸入階段我們將窗口內的單詞拼接成了一個向量,對於反向傳播的誤差,也可以直接拆分到各個單詞向量進行更新。
xJ=WTδ\nabla_xJ = W^T\delta
如果一個單詞在同一個窗口中出現了兩次,那麼我們就對這個單詞進行兩次更新。

1.4 下游任務更新詞向量存在的風險

假如預訓練詞向量中有電視、電影、節目三個詞義相近,詞向量相似的詞語,但訓練集只有電視、電影兩個詞出現,而測試集中出現了節目這個詞。那麼如果我們在訓練階段更新了詞向量,就會導致三個詞向量之間相似度降低。
解決方案: 如果下游任務數據集較小,就不要更新詞向量。如果下游任務數據集很大,那麼可以在訓練階段更新詞向量(相當於fine-tune)

二、計算圖及其反向傳播

這之前我們要了解圖計算(graph computing) 和 **計算圖(computation graph)**是兩個不同的概念。本節課的計算圖是用圖的方式來表示計算流程的神經網絡計算框架,而圖計算是利用圖論方法研究任意數據的內在聯繫的一類算法統稱。

2.1 計算圖的概念

前向傳播(黑色箭頭方向):
起始節點x爲輸入
每個中間節點爲運算操作
箭頭爲運算操作的輸出信號
反向傳播(藍色箭頭方向)
每條邊代表Loss函數對該層輸入信號的偏導(通過鏈式法則)。
在這裏插入圖片描述
對於單個節點的視圖如下:
在這裏插入圖片描述

2.2 一個簡單地計算實例

注意這裏的max函數,需要跟情況討論輸入參數的梯度,並根據運行反向傳播的時刻的輸入值來決定使用哪一個梯度(相當於激活的神經元或抑制的神經元)。下圖中藍色部分爲反向傳播的梯度值,在更新時需要與學習率α\alpha相乘。
在這裏插入圖片描述

2.3 分支網絡的處理

如果一個節點輸出被下一層的多個節點使用,那麼反向更新時這個節點就會接受到兩個誤差信號(如圖),我們只需要將這兩個輸入信號相加(事實上就是多元複合函數求偏導的公式呀)。 ![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200223122953606.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dlZWtfaGNo,size_16,color_FFFFFF,t_70) ## 2.4 反向傳播運算規律 觀察2.2節中的計算過程,可以得出以下規律: + +運算將上游梯度分發複製到下游每個分支 + max運算將上游梯度路由到下游中最大值的那一個分支 + *運算將下游的值交換後作爲梯度發送給下游分支。但這只是針對上游分支只有兩個的情況。如果有多個呢?(當然就是一個分支的梯度等於其他分支的前向傳播值的乘積)

2.5 高效計算:每個局部誤差信號僅計算一遍

對於如下計算圖,如果我們直接計算sb\frac{\partial s}{\partial \boldsymbol{b}},這是極其低效的,因爲這樣的話我們計算sW\frac{\partial s}{\partial \boldsymbol{W}}時又會重複計算上游的梯度。
高效的計算方式是Top-Down,從loss反向一層層的傳播,每一次計算都通過鏈式法則,利用上一層的梯度信息
在這裏插入圖片描述

2.6 更復雜的計算圖

對於以下計算圖,有了前面的知識,我們可以輕易地進行Fprop和Bprop,如果方法正確,Fprop和Bprop的計算複雜度應該相同。根據2.3節:
zx=i=1nzyiyix\frac{\partial z}{\partial \boldsymbol x}=\sum_{i=1}^{n} \frac{\partial z}{\partial y_{i}} \frac{\partial y_{i}}{\partial x}
在這裏插入圖片描述
對於一些規範的圖(大多數神經網絡),我們都可以利用矩陣和雅克比來簡化計算

三、神經網絡代碼實現及相關框架

3.1 自動求導

對於每個節點,如果滿足下面的條件,那麼由這些節點構成的網絡就能夠自動求導,反向傳播。
+ 定義節點的輸入與輸出
+ 定義該節點輸出對每個輸入的偏導
現代神經網絡框架正式利用這個原理,通過程序員定義每一層/節點的手寫梯度計算,來實現整個深度神經網絡的自動求導。求偏導公式是一個符號計算過程,tf, torch等框架只提供數值計算,所以需要程序員給出所有可能的計算公式(前向、反向)

3.2 計算圖的代碼(僞代碼)

這是pytorch框架計算圖的定義,可以很清晰地看到前向傳播、反向傳播的邏輯:
在這裏插入圖片描述
對於單個單元,這裏以簡單的乘法運算爲例,實現代碼如下,這裏要注意forward和backword的接口參數在這裏插入圖片描述

3.3 梯度檢查:數值梯度

(注意區分梯度的數值計算符號計算)
根據偏導的定義,我們可以通過以下公式計算梯度的近似值,但由於計算中h(1e-4)不是無窮小的數,所以並不是真實的梯度值。
f(x)f(x+h)f(xh)2h f ^ { \prime } ( x ) \approx \frac { f ( x + h ) - f ( x - h ) } { 2 h }
理論上我們可以用這個方法實現完全自動的求導,但我們可以看到這個方法要求每次計算梯度時都要重新計算f(x+h)、f(x-h),並且每次更新對每個參數都要計算一次,性能較低。通常使用這個方法來檢查我們的代碼實現。

3.4 瞭解梯度的計算過程的意義

  • 有助於我們思考如何提升模型性能
  • 可能存在的bug: 梯度消失和爆炸

四、其他細節

4.1 參數正則化

當網絡參數量很大的時候,爲了防止過擬合,我們需要在一般的loss後面添加一個L2正則項來限制參數。(通過懲罰偏離0較遠的參數值,限制模型的擬合能力)
J(θ)=1Ni=1Nlog(efyic=1Cefc)+λkθk2 J ( \theta ) = \frac { 1 } { N } \sum _ { i = 1 } ^ { N } - \log \left( \frac { e ^ { f _ { y _ { i } } } } { \sum _ { c = 1 } ^ { C } e ^ { f _ { c } } } \right) + \lambda \sum _ { k } \theta _ { k } ^ { 2 }

4.2 向量化運算

向量化是指,儘可能的將循環計算轉換爲更高維的向量計算,因爲計算框架對向量運算有優化,比一般的循環快很多。比如下面兩行,計算輸入和輸出一樣,但時間卻相差了40多倍,如果使用GPU, 差距會遠大得多。
在這裏插入圖片描述

4.3 非線性激活函數

早起使用的非線性激活函數如下,其中tanh(z) = 2*sigmod(z) - 1, sigmod 和 tanh現在仍然會在某些特殊情況下被用到,但不再是默認的激活函數:

  • sigmod
  • tanh
  • hard-tanh(出現的原因是爲了加速運算,雖然在每一段上都是線性的,但其分段打破了線性,因此是有效的激活函數)
    在這裏插入圖片描述
    這之後,激活函數不斷被改進,出現了更加簡化且高效的版本ReLU及其改進版本,ReLU的功能就是簡單地賦予神經元(抑制、有效)兩種狀態,求導非常容易,是在構建網絡時推薦的默認激活函數。leaky ReLU只在部分論文中被稱有效
    在這裏插入圖片描述

4.4 參數初始化

通常需要將權重初始化爲較小的值

  • biases初始化爲0,
  • 其他權重初始化爲uniform(-r, r)(r爲一個較小的數)

4.5 優化器

一般來說,簡單地SGD就會很有效。但一些複雜的網絡可能需要適應性更強的優化器,這些優化器可能通過給每個變量設置不同的學習率並記錄,來提高其優化效率(Adagrad、RMSprp、Adam(推薦作爲默認使用)、sparseAdam)

4.6 學習率

一般默認起始學習率0.001, 可以以10倍減小,太大會導致不收斂,太小則優化過程很慢。
最好允許學習率在學習過程中逐漸減小,比如每k個epoch減半或使用如下公式:
lr=lr0ekt(tepoch)lr = lr_0e^{-kt}(t爲epoch)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章