---
# System prepended metadata

title: '循環神經網絡（Recurrent Neural Network, RNN）'
tags: [架構設計, 深度學習, 陳縕儂]

---

## Language model 的演進
### 1. N-Gram language modeling
語言模型，可以透過考慮前面 i - 1 個字並輸出第 i 個字，但在 N-Gram language modele 中僅考慮輸出第 i 個字之前的 n 個字，其餘更前面的文字皆忽略不看，並且從訓練資料(training data)中預測下一個字的機率。

但是存在一個問題，如果在訓練資料中沒有對應的資料，那機率永遠是零，例如訓練資料有兩筆資料是狗在跑、貓在叫，請問出現狗在叫的機率是多少呢？沒錯，就是零。為了避免這種狀況，通常會給予一個小的機率值 = 0.0001，這個動作叫做 smoothing，但這樣的機率往往是不準確的。

![image](https://hackmd.io/_uploads/r1cFKCzSC.png)

### 2. Neural Language modeling
在 Neural network 中，先準備好大量訓練資料，一開始先丟入輸入 "START" 的 vector，代表正式開始訓練並且期望輸出 "wreck"，再將輸出當成輸入丟到 NN 中，期望產生新的輸出 "a"，以此類推。

這些丟入的輸入向量，如果說在 Word representation 中的關係是接近的，即使訓練資料中只有狗在跑、貓在叫，因為貓跟狗的關係是接近的，所以出現狗在叫的機率也不會是零，等於是自動完成 smoothing 的效果。

但也是要考慮到有可能第一個字與第十個字有關，或者與第一百個字有關，而目前的 Neural Language modeling 僅能考慮固定的 Window 裡的字，例如 window = 1 僅考慮前一個字輸出下一個字，而無法考慮到更多的字。

![image](https://hackmd.io/_uploads/Sk8D20fSC.png)

### 3. Recurrent Neural Network Language Model, RNNLM
利用 RNNLM 就能夠解決固定 window 的問題，最主要的差異在於能將過往的資訊傳遞給下一層的隱藏層，便能在後面輸出第十或一百個字時，也能考慮到之前的文字，進而預測出較佳的輸出結果，這便是 RNNLM 的優點。

![image](https://hackmd.io/_uploads/HknpJJXBC.png)

## 介紹 RNNLM
RNNLM 具體運作流程如下圖，考慮前一個隱藏層的向量（hₜ₋₁）以及輸入向量（xₜ），並且乘上對應的矩陣 W、U，得到 sₜ₋₁ 再乘上 V 矩陣得到輸出 oₜ₋₁，以此類推。

![image](https://hackmd.io/_uploads/B1AqtOrBR.png)

### 不同的 RNN 架構
![image](https://hackmd.io/_uploads/rkSW-buo1e.png)
![image](https://hackmd.io/_uploads/HyLlbW_j1g.png)


:::info
Bidirectional RNN，同時考慮左側以及右側的資訊。
![image](https://hackmd.io/_uploads/S1y9HYBHR.png)
Deep Bidirectional RNN
![image](https://hackmd.io/_uploads/SJql8KHHC.png)
:::

## Backpropagation Through Time
為什麼要加上 through time 呢？這是因為 RNNLM 的特色是有時序性，必須要等到上一個輸出結果結束後作為輸入，才能再輸出下一個，存在時間先後順序的差異，因此被稱為 Backpropagation Through Time。

以下圖片出自於「[Gadient descent & Backpropagation](https://hackmd.io/@lcaMuWOwR1Ox5o5yeTEupA/SJCapzVSR)」的文章，根據後一層(δˡ⁺¹)的結果推算出前一層(δˡ)的結果，但這樣的最佳化方式，可能存有兩個潛藏的問題，分別是 Vanishing gradient 以及 Exploding gradient，因為會一直乘上相同的矩陣 w，可以想像成一直乘上比 1 大(例如 2)的數字結果會越來越大，反之一直乘上比 1 小(例如 0.5)的數字結果會越來越小。

![image](https://hackmd.io/_uploads/HJXwaQVrA.png)

### 什麼是 Vanishing gradient 以及 Exploding gradient？
從下方兩張圖可以看到，在更新參數 50 次後，會變得相當極端，只出現在非常接近於零(非常平緩)的地方，代表 Vanishing gradient，也會出現在非常大的數值(非常陡峭)，代表 Exploding gradient。

![image](https://hackmd.io/_uploads/S15nCOSSR.png =40%x) ![image](https://hackmd.io/_uploads/SyQRR_HH0.png =50%x)

### 解決 Exploding gradient 的方式 - 梯度剪裁
需要先設定閥值(threshold)，然後在梯度大於該閥值時縮小梯度。
#### 1. 按值裁減，定義梯度的最小和最大閾值
ex: 更新參數後的梯度計算為 [0.9, -1.4, 5.2]，將裁切閾值設為 -1 和 1 時，調整後的梯度將變為 [0.9, -1, 1]。
#### 2. 按比例裁減，梯度按比例縮小以與該閾值對齊
ex: 更新參數後的梯度計算為 [1.6, 0.6, 1.8]，將裁切閾值設為 1 且縮放因子為 0.5 時，調整後的梯度將變為 [0.8, 0.6, 0.9]。

### 解決 vanishing gradient 的方式 - Gating
#### 1. Long Short-Term Memory (LSTM)
與 Vanilla RNN 最大差別在於，具有一個上方通道只做 Linear transform(加、乘之運算)，不做任何數值壓縮導致消失，能夠確保資訊一直被保留下來，並且 LSTM 擁有三個 gate，分別是 forget gate、input gate 以及 output gate。

a. forget gate：決定要遺忘(或丟棄)哪些過去資訊，若 fₜ = 1 則完全保留，fₜ = 0 則完全遺忘。
b. input gate：決定哪些新的輸入資訊可以更新在 cell state 中。
c. output gate：決定哪些資訊可以作為輸出。
    
:::info
Cell state update，同時考慮 forget gate 以及 input gate，決定遺忘哪些資訊並且新增哪些資訊，藉由 fₜ 與 iₜ 控制每一次的遺忘與更新，讓 Cₜ 可以保有我們所需要的資訊。
::: 

![image](https://hackmd.io/_uploads/SkeN2hIBR.png)
#### 2. Gated Recurrent Unit (GRU)
相較於 LSTM，GRU 只有兩個 gate，分別是 update gate 以及 reset gate。

a. update gate：結合 forget gate 和 input gate
b. reset gate
    
特別注意的地方在於 rₜ * hₜ₋₁，當 rₜ = 0 代表完全忽略先前的資訊，只儲存新資訊。

![image](https://hackmd.io/_uploads/SkYE33LSA.png)

:::info
LSTM v.s. GRU
由於 GRU 少了一個 gate，因此參數量是較少的，在更新參數上會比 LSTM 快，但如果有非常大量的資料，還是建議使用 LSTM 較能夠幫助模型表現得更好。
:::

## 總結 RNN
在文章中，我們提到了 Language Model 的演進，說明 RNN 能夠考慮先前的資料，因此在預測下一個字的輸出結果較良好，但也由於資訊不斷地往下傳遞，存在了最佳化（Optimization）的問題，就是 Vanishing gradient 以及 Exploding gradient，並且針對這兩種情境介紹了對應的解決方法。

---
:::info 
以上就是這篇文章「循環神經網絡（Recurrent Neural Network, RNN）」的所有內容，第一次看的人會花比較多時間消化吸收，這是很正常的事情，若有任何問題，歡迎在下方與我聯繫、討論，接下來也會繼續分享相關文章，敬請期待。
