1. 程式人生 > >基於時間的反向傳播演算法和梯度消失 -part3

基於時間的反向傳播演算法和梯度消失 -part3

本文翻譯自
前文從零開始實現了RNN,但是沒有詳細介紹Backpropagation Through Time (BPTT) 演算法如何實現梯度計算。這篇文章將詳細介紹BPTT。之後會分析梯度消失問題,它導致了LSTM和GRU的發展,這是兩個在NLP領域最為流行和有效的模型。
梯度消失問題在1991年被發現,但在近來受到關注,因為深度框架的廣泛應用;
為了充分理解這個教程,我建議要熟悉部分分化和基本反向傳播演算法的工作機制相關教程part1part2part3

BACKPROPAGATION THROUGH TIME (BPTT)
快速重述RNN中的基本公式
這裡寫圖片描述
yt是在step t正確的單詞輸出,yt^指預測值。
我們還是傳統的認為一個完整的序列(句子)是一個訓練樣本,所以總的誤差為每一步的誤差之和;
這裡寫圖片描述


我們的目標是計算有關U,V,W的損失函式的梯度,使用隨機梯度下降演算法學習得到更好的引數值。就像我們誤差相加,我們也把每一個樣本的每一步中的梯度值相加
這裡寫圖片描述
為了計算梯度,我們使用了分化鏈規則。
這裡寫圖片描述
上述,這裡寫圖片描述
這裡寫圖片描述是兩個向量的外積;
這個公式想要說明的問題是,這裡寫圖片描述僅僅依賴於當前步的值這裡寫圖片描述。如果知道了這些,計算V的梯度就是一個簡單的矩陣相乘。
但是這裡寫圖片描述(U的情況也是如此)的情況不同,為了分析原因,下面寫出鏈式規則:
這裡寫圖片描述
注意:這裡寫圖片描述依賴於S2,而S2依賴於W和S1。如果我們求與W相關的導數,不能認為S2為常數。需要進一步運用鏈式規則。
這裡寫圖片描述
我們把每一步對梯度的貢獻相加。換句話說,W在每一步中都被使用,最終得到輸出。我們需要從t=3通過網路反向傳播梯度到t=0;
這裡寫圖片描述

注意,這和在前饋神經網路中使用的標準的反向傳播演算法一樣。關鍵的不同在於我們把每一步驟中W的梯度相加。在傳統的NN,沒有在層間共享引數,所以不用相加。BPTT像是一個有趣的標準反向傳播演算法運用在展開的RNN上面;
一個BPTT的程式碼實現如下:

def bptt(self, x, y):
    T = len(y)
    # Perform forward propagation
    o, s = self.forward_propagation(x)
    # We accumulate the gradients in these variables
    dLdU = np.zeros
(self.U.shape) dLdV = np.zeros(self.V.shape) dLdW = np.zeros(self.W.shape) delta_o = o delta_o[np.arange(len(y)), y] -= 1. # For each output backwards... for t in np.arange(T)[::-1]: dLdV += np.outer(delta_o[t], s[t].T) # Initial delta calculation: dL/dz delta_t = self.V.T.dot(delta_o[t]) * (1 - (s[t] ** 2)) # Backpropagation through time (for at most self.bptt_truncate steps) for bptt_step in np.arange(max(0, t-self.bptt_truncate), t+1)[::-1]: # print "Backpropagation step t=%d bptt step=%d " % (t, bptt_step) # Add to gradients at each previous step dLdW += np.outer(delta_t, s[bptt_step-1]) dLdU[:,x[bptt_step]] += delta_t # Update delta for next step dL/dz at t-1 delta_t = self.W.T.dot(delta_t) * (1 - s[bptt_step-1] ** 2) return [dLdU, dLdV, dLdW]

這就說明了標準的RNNs難以訓練的原因,句子序列可能相當的長,可能多於20個單詞,因此需要反向傳播通過很多層,在實際中許多人限制反向傳播在某幾步;
梯度消失問題(THE VANISHING GRADIENT PROBLEM)
在之前的教程中,提到RNNs在學習長期的依賴時遇到困難。單詞之間的相互作用僅僅在幾步之間。這是有問題的,因為英語語句的語義是由相距較遠單詞共同組成的。“The man who wore a wig on his head went inside”這句話的真實語義是一個人出去,而不是假髮,但是普通的RNN不能捕獲到這樣的資訊。為了理解為什麼讓我們仔細看一下上面計算的梯度:
這裡寫圖片描述
注意到,這裡寫圖片描述就是鏈式規則本身;例如,這裡寫圖片描述,同樣注意我們要求與一個向量相關的向量函式的導數,結果是一個矩陣(稱作雅可比矩陣),它的每個元素是逐點導數;重寫上面的梯度
這裡寫圖片描述
這證明了雅可比矩陣的2-norm(可以視為絕對值)具有上界為1,
直觀的理解是因為tanh(or sigmoid)啟用函式把所有值對映到-1到1之間。 它的單數同樣有界,為1
這裡寫圖片描述
你能看出tanh和sigmoid函式在端點處的導數為0.它們接近平滑的線。
當這種情況發生時,我們認為相關的神經元飽和了。它們擁有0梯度
,使之前層的梯度趨向於0 。因此,在矩陣中的小數值和倍數矩陣乘法,梯度值快速的收縮指數。最終在幾步之後完全消失。從某一不開始梯度貢獻為0,這就導致這些步的狀態不能對學習有所貢獻。最後就變成不能學習遠範圍的依賴關係。消失梯度不僅僅在RNNs中出現。它還出現在深度前饋神經網路。由於RNNs趨向於很深,使得問題更加
常見;
容易想象,根據我們的啟用函式和神經引數,如果雅可比矩陣的值很大的話,即使不梯度消失,也會爆炸。稱之為爆炸梯度問題。消失梯度相比爆炸梯度獲得了更多的關注的原因是雙重的。1爆炸梯度是明顯的,你的梯度會變為NaN,程式會崩潰。第二,用預處理的閾值裁剪梯度是一個簡單有效的方法處理爆炸梯度問題。消失梯度出現的不明顯而且沒有明顯的方法處理它;
幸運的是:有很多方法來克服消失梯度問題。W矩陣的合適的初始化能夠減少 消失梯度的影響。所以可以正則化。一個更好的方法是使用ReLU代替tanh或sigmoid啟用函式。ReLU導數是0或1常數,所以不受消失梯度的影響。一個更加流行的解決方案是使用 Long Short-Term Memory (LSTM) or Gated Recurrent Unit (GRU) 框架。
LSTMs在1997年被第一次提出,可能是現在最常用的自然語言處理模型。GRUs在2014年被提出,是LSTMs的簡單變體。這些RNN架構被明確的設計用來解決消失梯度的問題,能夠有效的處理長距離依賴,