文章目錄
- 1 RNN存在的問題
- 1.1梯度消失問題
- 1.2梯度爆炸問題
- 1.3梯度爆炸的對策
- 2梯度消失的對策——LSTM
- 2.1輸出門
- 2.2遺忘門
- 2.3輸入門
- 2.4總結
- 2.5 LSTM梯度的流動
1 RNN存在的問題
RNN存在梯度消失和梯度爆炸的問題。
-
書上以下圖的這句話為例,進行說明;為了正確預測出問號處的單詞:
- 一方面需要利用RNN將前面的所有信息編碼并保存在RNN層的隱藏狀態中;
-
另一方面,可以通過反向傳播,將待預測單詞位置處的梯度在水平方向上傳遞到過去(如下圖所示),這種有意義的梯度,最終更新模型的權重,使得模型能夠學習時間方向上的依賴關系,最終正確做出預測;
-
但是如果梯度在反向傳播的過程中,梯度越向過去傳播,越小,則則靠前的模型權重就得不到更新,從而無法讓模型編碼有用的信息,無法讓模型學習并利用水平方向上長期的依賴關系來進行預測;
-
此外,如果梯度越來越大,會出現梯度爆炸,這會使得模型的學習變得不穩定,也是一個問題;
-
而這兩種問題在RNN中都存在;
-
下面僅僅從時間方向上看梯度的傳播(如下圖所示);縱向來的梯度會和水平方向上傳遞來的梯度相加;因此僅僅分析水平方向上梯度的變化的結論在考慮縱向時也是適用的;
1.1梯度消失問題
-
y = t a n h ( x ) y=tanh(x) y=tanh(x)函數的導數為: y ′ = 1 ? y 2 y'=1-y^2 y′=1?y2;下圖是原函數與導數的圖像:
-
由圖像可知,導數值小于 1.0,并且隨著 x 遠離 0,它的值在變小;因此導數永遠小于1,即局部梯度是小數,那么輸出側的梯度乘上局部梯度就會變小;并且如果 x 遠離 0,局部梯度會非常小;那么經過這么一個tanh節點,梯度就會變小一次;而水平方向上有好多個tanh節點,那么傳播到非常過去的節點,梯度甚至有可能會消失。
-
RNN 層的激活函數一般使用 tanh 函數,但是如果改為 ReLU 函數, 則有希望抑制梯度消失的問題(當 ReLU 的輸入為 x 時,它的輸出是 max(0, x))。這是因為,在 ReLU 的情況下,當 x 大于 0 時,反向傳播將上游的梯度原樣傳遞到下游,梯度不會“退化”。而且可以在ReLU之前將輸入全部變到正數,這樣就完全是x了;
1.2梯度爆炸問題
簡單起見, 這里我們忽略反向傳播圖中的 tanh 節點;
加法節點梯度不變,因此就沒畫出來了;
-
那么簡單來看,圖中只剩矩陣乘法的節點,如下圖所示:
-
前面說過矩陣相乘的梯度傳播公式;這里每經過一個矩陣乘法節點,都要乘上一個局部梯度 W h \boldsymbol{W}_h Wh??;
- 由于RNN是使用一組權重參數的,因此這里每次乘的權重是一樣的;
-
接下來書上初始化了一個梯度為1的矩陣,然后執行了多次局部梯度,并計算了每次反向傳播之后梯度的L2范數;代碼如下圖所示:
- L2 范數定義為每個元素的平方和的平方根,因此當向量中某個元素很大時,整個范數值就會被拉大;
- 這就使得 L2 范數對離群值和噪聲更加敏感,因為這些值在平方運算中會被放大
- 所以本書中就計算了這個范數,這樣可以直觀的去看一下梯度是不是有爆炸的趨勢
-
下圖是實驗結果;可見確實有爆炸的趨勢;梯度爆炸會導致數值過大,甚至溢出,影響神經網絡的學習;
-
但是有一個問題,如果權重是一個標量,那么如果權重大于1,則肯定梯度會越來越大的;權重是一個矩陣的時候,就又涉及到矩陣的奇異值這個概念了(還需要深入了解);
- 簡單而言,矩陣的奇異值表示數據的離散程度;
- 根據這個奇異值(更準確地說是多個奇異值中的最大值)是否大于 1,可以預測梯度大小的變化
- 如果奇異值的最大值大于 1,則可以預測梯度很有可能會呈指數級增加;而如果奇異值的最大值小于 1,則可以判斷梯度會呈指數級減小;詳見論文;
1.3梯度爆炸的對策
-
梯度爆炸的對策為**梯度裁剪**;
-
裁剪按照下式進行:
- 將神經網絡所有的參數整合到一起,合成一個”向量“ g ^ \hat{\boldsymbol{g}} g^??;
- t h r e s h o l d threshold threshold為梯度閾值;
- ∥ g ^ ∥ \|\hat{\boldsymbol{g}}\| ∥g^?∥為L2范數;
i f ∥ g ^ ∥ ? t h r e s h o l d : g ^ = t h r e s h o l d ∥ g ^ ∥ g ^ (1) \begin{aligned} if\; \|\hat{\boldsymbol{g}}\|&\geqslant threshold:\\ \hat{\boldsymbol{g}}&=\frac{threshold}{\|\hat{\boldsymbol{g}}\|}\hat{\boldsymbol{g}} \end{aligned} \tag{1} if∥g^?∥g^???threshold:=∥g^?∥threshold?g^??(1)
-
下面的代碼是書上的一個小例子:
def clip_grads(grads, max_norm):total_norm = 0for grad in grads:total_norm += np.sum(grad**2) # 對梯度矩陣的所有元素求和;因為公式中就是把所有的梯度組合在一起,然后求的范數;total_norm = np.sqrt(total_norm) # 二范數rate = max_norm / (total_norm + 1e-6) # 公式的變形if rate < 1:for grad in grads:grad *= rateif __name__ == '__main__':dW1 = np.random.rand(3, 3) * 10dW2 = np.random.rand(3, 3) * 10grads = [dW1, dW2] # 對應梯度裁剪公式里面的gmax_norm = 5.0 # 范數閾值clip_grads(grads, max_norm)pass
2梯度消失的對策——LSTM
通過改變RNN的網絡結構,改變了存放”記憶“的載體;引入了門結構;即Gated RNN;
這里先看看LSTM;后面再看一下書上的GRU;
-
LSTM這里的改進涉及:增加了一個記憶單元、輸入門、輸出門、遺忘門;
-
下圖為RNN和LSTM結構的簡略對比:
- LSTM多了記憶單元 c \boldsymbol{c} c?;
- 這個記憶單元僅在 LSTM 層內部接收和傳遞數據,不像 h \boldsymbol{h} h?那樣還要傳遞給上面的層;
- 結合前面說的TRNN層,雖然我們說水平方向上有多個RNN層,但本質上就是一組參數,這些RNN層其實就是一個;后面的TLSTM也是這樣;因此,書上說,記憶單元在 LSTM 層內部結束工作,不向其他層輸出,對外部不可見。
2.1輸出門
概括: t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct?)編碼了目前時刻為止所需要的信息,用輸出門來控制信息中各個元素的重要程度;
-
LSTM的記憶單元 c t \boldsymbol{c}_t ct?保存了從過去到時刻 t t t的所有必要信息,基于這個充滿必要信息的記憶,向外部的層(和下一時刻的 LSTM)輸出隱藏狀態 h t \boldsymbol{h}_t ht??;如下圖所示:
- LSTM輸出經過tanh變換后的記憶單元
- c t \boldsymbol{c}_t ct?基于 c t ? 1 \boldsymbol{c}_{t-1} ct?1?、 h t ? 1 \boldsymbol{h}_{t-1} ht?1?、 x t \boldsymbol{x}_t xt??經過”某種計算“得到;
- 隱藏狀態 h t = t a n h ( c t ) \boldsymbol{h}_{t}=tanh(\boldsymbol{c}_t) ht?=tanh(ct?);即對 c t \boldsymbol{c}_t ct?各個元素應用tanh函數;
-
門的概念:
- 從字面意義上看,門可以用于控制開合;
- 但LSTM中的門,還可以控制將門打開多少來控制數據的流動;
- 門的開合程度由 0.0 ~1.0 的實數表示(1.0 為全開);重點是,門的開合程度也是(自動) 從數據中學習到的;
-
接下來用到的函數的區別:
- tanh函數:輸出是 ?1.0 ~ 1.0 的實數;表示某種被編碼的“信息”的強弱(程度);
- sigmoid函數:輸出是 0.0~1.0 的實數;表示數據流出的比例;如同前面二分類時用它來轉化為概率一樣;
- 因此,在大多數情況下,門使用 sigmoid 函數作為激活函數,而包含實質信息的數據則使用 tanh 函數作為激活函數;
-
綜合2和3,我們可以說:
- 有專門的權重參數用于控制門的開合程度,這些權重參數通過學習被更新
- sigmoid函數用于求門的開合程度,即將權重參數計算之后的結果輸出到0-1之間;
-
輸出門:對 t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct?)施加門,針對 t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct?)中的每個元素,調整它們作為下一時刻的隱藏狀態的重要程度;
-
由于這個門管理當前時刻的輸出,即隱藏狀態 h t \boldsymbol{h}_t ht?,所以稱為輸出門
-
輸出門的公式如下:
o = σ ( x t W x ( o ) + h t ? 1 W h ( o ) + b ( o ) ) (2) \boldsymbol{o}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{o})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{o})}+\boldsymbol{b}^{(\mathrm{o})}\right) \tag{2} o=σ(xt?Wx(o)?+ht?1?Wh(o)?+b(o))(2)-
和單純的RNN的公式如出一轍;輸入 x t \boldsymbol{x}_t xt?有權重 W x ( o ) \boldsymbol{W}_x^{(\mathrm{o})} Wx(o)?,上一時刻的隱藏狀態 h t ? 1 \boldsymbol{h}_{t-1} ht?1?有權重 W h ( o ) \boldsymbol{W}_h^{(\mathrm{o})} Wh(o)?; σ ( ) \sigma() σ()表示sigmoid函數;結果 o \boldsymbol{o} o應該是一個行向量;
-
然后將 o \boldsymbol{o} o和 t a n h ( c t ) tanh(\boldsymbol{c}_t) tanh(ct?)的對應元素相乘,作為輸出 h t \boldsymbol{h}_t ht?,如下式所示;對應元素相乘即哈達瑪積(Hadamard product),用 ⊙ \odot ⊙來表示;
h t = o ⊙ tanh ? ( c t ) (3) \boldsymbol{h}_t=\boldsymbol{o} \odot \tanh \left(\boldsymbol{c}_t\right) \tag{3} ht?=o⊙tanh(ct?)(3)
-
-
下圖是加入輸出門之后的LSTM結構圖:
-
2.2遺忘門
- 前面說了: c t \boldsymbol{c}_t ct?基于 c t ? 1 \boldsymbol{c}_{t-1} ct?1?、 h t ? 1 \boldsymbol{h}_{t-1} ht?1?、 x t \boldsymbol{x}_t xt?經過”某種計算“得到;
- 遺忘門的作用:對上一個LSTM單元傳遞來的記憶信息進行取舍,告訴模型需要忘記什么;因此設置一個遺忘門作用在 c t ? 1 \boldsymbol{c}_{t-1} ct?1?上,將需要忘記的賦予更低的重要性;
-
與輸出門類似,遺忘門也是一組權重參數,加上一個sigmoid函數;如下式所示:
f = σ ( x t W x ( f ) + h t ? 1 W h ( f ) + b ( f ) ) (4) \boldsymbol{f}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{f})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{f})}+\boldsymbol{b}^{(\mathrm{f})}\right) \tag{4} f=σ(xt?Wx(f)?+ht?1?Wh(f)?+b(f))(4)
其中 W x ( f ) \boldsymbol{W}_x^{(\mathrm{f})} Wx(f)?、 W h ( f ) \boldsymbol{W}_h^{(\mathrm{f})} Wh(f)?、 b ( f ) \boldsymbol{b}^{(\mathrm{f})} b(f)為遺忘門的權重和偏置參數; σ ( ) \sigma() σ()依舊表示sigmoid函數;然后將遺忘門 f \boldsymbol{f} f與 c t ? 1 \boldsymbol{c}_{t-1} ct?1?對應元素相乘,得到當前時刻的記憶單元 c t \boldsymbol{c}_{t} ct??;如下式所示:
c t = f ⊙ c t ? 1 (5) \boldsymbol{c}_t=\boldsymbol{f} \odot \boldsymbol{c}_{t-1} \tag{5} ct?=f⊙ct?1?(5) -
加入遺忘門之后LSTM的結構如下圖所示:
2.3輸入門
- 除了遺忘一部分信息,還需要讓模型記住一些新的信息;
- 新的信息也有重要程度之分,因此引入輸入門,判斷新增信息的各個元素的價值有多大;
-
將新的信息加入到記憶單元中,因此使用tanh函數,而不用sigmoid函數;計算公式如下:
g = tanh ? ( x t W x ( g ) + h t ? 1 W h ( g ) + b ( g ) ) (6) \boldsymbol{g}=\tanh \left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{g})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{g})}+\boldsymbol{b}^{(\mathrm{g})}\right) \tag{6} g=tanh(xt?Wx(g)?+ht?1?Wh(g)?+b(g))(6)
相關參數類似前面的輸出門和遺忘門的參數;這是計算的新的信息;將此信息加入到上一時刻的記憶單元 c t ? 1 \boldsymbol{c}_{t-1} ct?1??中,形成新的記憶;
-
為了區分新的信息中元素的價值,構建輸入門,用輸入門對新的信息加權;輸入門公式如下:
i = σ ( x t W x ( i ) + h t ? 1 W h ( i ) + b ( i ) ) (7) \boldsymbol{i}=\sigma\left(\boldsymbol{x}_t \boldsymbol{W}_x^{(\mathrm{i})}+\boldsymbol{h}_{t-1} \boldsymbol{W}_h^{(\mathrm{i})}+\boldsymbol{b}^{(\mathrm{i})}\right) \tag{7} i=σ(xt?Wx(i)?+ht?1?Wh(i)?+b(i))(7)
用這個權值 i \boldsymbol{i} i與新增加的信息 g \boldsymbol{g} g相乘,對應元素相乘,然后再添加到被篩選過的保留下來的上一時刻的記憶單元 c t ? 1 \boldsymbol{c}_{t-1} ct?1?中。 -
加入新增信息和輸入門之后LSTM的結構如下:
2.4總結
-
上一時刻傳來的記憶單元有些信息需要被遺忘,因此增加了遺忘門;
-
當前時刻有新的信息需要添加,且增加的信息也有重要程度之分,因此加了輸入門;
-
1和2形成了當前時刻的記憶單元;
-
當前時刻輸出的隱藏狀態原本就是要包含目前為止所有的信息的,因此基于當前時刻的記憶單元,計算當前時刻的隱藏狀態;而輸出門就是用來調整當前時刻記憶單元作為下一時刻隱藏狀態的重要程度的。
-
另外,從公式上看,不管是哪個門,以及新增的記憶單元,都是基于 h t ? 1 \boldsymbol{h}_{t-1} ht?1?、 x t \boldsymbol{x}_t xt?;每個門的權重參數具體數值不同,但形式相同。
2.5 LSTM梯度的流動
LSTM中最關鍵的就是記憶單元 c \boldsymbol{c} c,隱藏狀態 h \boldsymbol{h} h就是基于 c \boldsymbol{c} c計算得到的;因此LSTM的記憶信息主要來自于 c \boldsymbol{c} c;所以梯度的流動我們主要關注一下記憶單元 c \boldsymbol{c} c部分。
-
涉及記憶單元的梯度流動如下圖所示:
- 涉及兩種計算:加法和乘法
- 加法節點,梯度直接傳遞,沒有任何變化;因此主要看一下乘法節點
-
不會梯度消失或者爆炸的原因:
- RNN里面的乘法節點是矩陣乘法,而且每次都是相同的權重矩陣,因此出現了梯度消失或者梯度爆炸的情況;
- 而這里的LSTM的乘法是對應元素相乘,因此不會像矩陣乘法的梯度那樣,每經過一個節點,都要再乘上一個矩陣;
- 而且這里每次的梯度都是不同的門值(因為每次輸入 x \boldsymbol{x} x?不一樣,雖然依然是一套權重參數)
-
另外,這里的乘法節點是遺忘門處的:
- 遺忘門作為權重乘到了上一時刻的記憶單元上,需要被忘記的會被分配較低的權重;
- 那么反向傳播時,需要被忘記的對應的梯度就小,需要保持記住的對應的梯度就大;
- 梯度大,意味著能夠被學習;且在水平方向上需要保持記住的,它們的梯度就會保持住,不會退化,能夠傳播到非常開始的時刻;那么這就讓模型能夠保持長期的記憶、保持長期的依賴關系
-
LSTM是Long Short-Term Memory(長短期記憶)的縮寫,意思是可以長(Long)時間維持短期記憶(Short-Term Memory):
- 每經過一個時刻都可以形成新的記憶,這是短期的;
- 但是由于該記住的,對應的梯度不會退化,因此可以長期記住;