今天的重頭戲會是 RNN 的變形 - LSTM (Long Short Term Memory) 與 GRU (Gated Recurrent Units) 這兩個模型。在介紹這兩者之前,先來聊聊 RNN 遇到的一個大問題 - 梯度消失。
梯度消失 (Vanishing gradient)
梯度消失指的是,當我們試圖利用 Gradient Descent 與 Backpropagation 演算法更新參數時,梯度會隨著傳遞的層數越多而遞減,使得模型的參數被更新的很慢,甚至難以繼續訓練。
而在 RNN 的情況,由於權重是重複被使用,梯度消失的問題變成權重只受到接近的詞影響,越遠的詞影響越小。換句話說,模型在做預測時,可能會遺失太遠之前的資訊。
以語言模型為例:
小明去找小花借書,路上遇到了另一個好朋友大雄,兩人開心的聊了一下天,(中略100字...)。道別後沒想到突然下起雨,小明只好回家一趟,決定隔天再跟小花拿 _
直觀上來想, _ 應該要填入書
,但由於梯度消失的問題,模型可能會遺失這麼多句子以前的資訊而預測錯誤。為了改善這個問題,發展出了後來具有額外記憶機制的模型,其中以 LSTM 與 GRU 最廣為人知。
在介紹這兩個模型之前,來深入看看梯度消失的數學原理吧。
==數學分隔線又來了==
在利用 Gradient Descent 更新參數時,我們常常會需要計算目標函數的微分,以最大化或最小化目標函數。而 Backpropagation 就是使得計算微分更有效率的一個演算法。
Backpropagation 裡面沒有什麼高深的數學,你唯一需要記得的就只有 chain rule - 李宏毅教授
Chain rule 是微積分的一個技巧,以下圖 case1 為例
y = g(x), z = h(y)
z = h(g(x))
dz/dx = dz/dy * dy/dx
當我們對以 x 對 z 微分時,兩者的關係包了兩層函數,需要透過 chain rule 分別計算這兩層的微分才能求得 dz/dx 。
圖片出處: 李宏毅教授 Backpropagation 課程
在深度學習的模型中,我們需要計算每一層參數對目標函式的篇微分,若從第一層往後計算,計算量將會很可觀。但 Backpropagation 的做法是由 output layer 往前計算,每推進一層,只要計算當層的偏微分,再乘以上一層得到的偏微分的值即為所求。
圖片出處: 李宏毅教授 Backpropagation 課程
回到 RNN ,我們在計算第一個詞的 hidden state h(1) 對目標函數 J(4) 的偏微分時,透過 chain rule 可以轉換成圖中的式子。這時候,如果 ∂h(2)/∂h(1), ∂h(3)/∂h(2), ∂h(4)/∂h(3) 這些值很小,相乘的結果就會得到很小的 ∂J(4)/∂h(1) ,更新的梯度也就消失了。
梯度消失的結果導致在這一步驟 (J(4)已經看過了第一到第四個詞)權重 W 更新時,第一個詞的影響力很小。也因為梯度消失,使得越遠的詞對模型權重的影響越小, 模型也就越可能忘記越之前的資訊。
長短期記憶 (LSTM)
看完了(或是直接跳過)上面的數學推導,相信大家可以深刻體會梯度消失的影響。接下來的長短期記憶模型,就是希望可以透過分開的記憶機制,來讓過去的資訊記得更久一點。
先來看看模型的圖:
圖片出處 Stanford NLP with DL 課程
LSTM 一樣是把相同的結構重複,也就是 RNN Recurrent 的概念, LSTM 與 RNN 相似,能處理不同長度的 input 並轉換成同樣長度的 hidden state ,這些 hidden state 就可以再進一步的做各種運算,像是語言模型預測下一個詞、或是句子的翻譯等等。
接著,讓我們放大來看看 LSTM 的核心 - Memory Cell
圖片出處:李宏毅教授 RNN 課程
在處理文字的每一個步驟(從第一個詞到最後一個詞),模型都有一個沿用基礎 RNN 的 hidden state 以及 LSTM 加入的 cell state ,memory cell 被用來儲存長期資訊。模型可以對這個 cell 進行三種操作:寫入、讀取以及遺忘,這三種操作分別由 input gate, output gate 與 forget gate 控制。
更詳細一點來說
- Input gate: 控制模型新讀入的資訊,有多少比例被寫入 memory cell 中。而新讀入的資訊是由這個步驟被讀入的值 x(t) 與上一個步驟的 hidden state h(t-1) 計算而得
- Output gate: 控制要從現在的 memory cell c(t) 讀取多少比例,來計算 hidden state h(t)
- Forget gate: 控制多少比例的資訊要保留到下一個步驟的 memory cell (沒保留的就是被忘掉的資訊拉)
值得一提的是,這些閘門並不是只有開跟關兩種狀態,而是可以介於開與關之間的狀態!也就是並非 0 或 1 兩種可能,可以是任意小數。這些閘門的數值,也是經由學習而來。
最後補上兩張圖,讓大家更了解 LSTM 的數學原理與細節。
下面這張圖,看似一堆數學很複雜,其實可以歸納出兩大部分:
上半部分說明這三個 gate 的數值,都和前一個 hidden state h(t-1) 與現在的 input x(t) 有關,分別以不同的矩陣做運算後再學習而得。
下半部分則是更詳細說明剛剛條列的三個 gate 的作用。首先,由 h(t-1) 與 x(t) 進行矩陣運算得到即將被寫入的新內容。這個新內容先由 input gate 把關,決定寫入多少比例,再加上 forget gate 從上一步 memory cell 保留下來的資訊,才是真正寫入 memory cell 的資訊。最後,再由 output gate 決定要從現在的 memory cell 讀取多少資訊放入 hidden state 。
下面這張圖則是更詳細地畫出上面的模型圖,每個相連的部分究竟做了什麼事囉。
GRU
至於 GRU ,我真的不知道他的中文叫什麼 XD 。他的概念其實和 LSTM 非常相像,都是使用了 gate 的想法,話不多說,先貼張數學嚇嚇大家。
他與 LSTM 的差別是, GRU 只用了兩個 gate ,分別是 update gate 與 reset gate 。 reset gate 控制該用多少比例的上一個 hidden state h(t-1) 來和新讀入的 input x(t) 計算下一個「準」 hidden state 。而 update gate 則是調配「準」 hidden state 與上一個 hidden state h(t-1) 的比例,來得到最終的 hidden state 。
關於 GRU 模型的架構與數學我這邊就簡單帶過,來談談他與 LSTM 的比較。 GRU 少了一個 gate ,使用的參數較少,因此計算上比 LSTM 快上許多,而且表現並沒有因此下降多少 (LSTM 還是比較強的 )。因此 stanford 課程中建議:
LSTM 是你預設的最佳選擇,不過當你的訓練資料數量龐大,或是希望縮短運算時間時,就可以考慮 GRU 了。
小結
導入 gate 機制的 RNN - LSTM 與 GRU ,能比基礎的 RNN 記得更久之前的資訊。後來更進一步發展出 Bi-directional RNNs 與 Multi-layer RNNs 等更強大的模型,礙於篇幅無法詳細介紹,有興趣朋友可以在網路上找到更多資料。
至此,自然語言處理又因為這些強大的 RNN 模型再創高峰,但是,利用閘門機制能記得的資訊仍然有限,如果我們用一些超長的文章或句子丟給模型,模型還是難以處理,我們後面會在介紹更多強力的機制使得模型更加進化。