# Recurrent Neural Networks

## Sequence Models

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtghhsCIFXPwhkGCFHj%2F-Ltghj8qZ5D-M_5evin5%2Fsequence_model_examples.png?generation=1573781961541684\&alt=media)

* Sequence data 指的是一連串的 data
  * 例如訓練 input 一連串聲音 output 成文字 (speech recognition)
* 我們要利用例如 Recurrent Neural Network (RNN) 來建立出 sequence model
  * model 將幫助我們把 non-sequence/sequence data 轉換成 non-sequence/sequence data

## Notation

* 假設有一個 name entity recognition 案例
  * 要標示出所有的人名

$$
\begin{aligned}
x =  \text{Harry Potter and Hermione Granger invented a new spell.}\\
y =  \text{{\color{red}Harry Potter} and {\color{red}Hermione Granger} invented a new spell.}
\end{aligned}
$$

* 句子中每個字依照順序會標註成

$$
\begin{aligned}
\text{Harry} &: x^{<1>} \\
\text{Potter} &: x^{<2>} \\&...
\end{aligned}
$$

* 因為 y 跟 x 的字一模一樣，所以用 1 標示是要找的人名

$$
\begin{aligned}
\text{Harry}: y^{<1>} &= 1\\
\text{Potter}: y^{<2>} &= 1\\
\text{and}: y^{<3>} &= 0\\&...
\end{aligned}
$$

* 另外 $$T\_x = 9$$ 表示句子的字數，同樣方式表達 y 的字數 $$T\_y = 9$$
* 因為可能有多筆 training set，若要表示第 i 筆 data 的第 t 個 word

$$
X^{(i)<t>}, y^{(i)<t>}
$$

* 表達字數的方式也差不多

$$
T\_x^{(i)} = 9, T\_y^{(i)} = 9
$$

### Vocabulary (Dictionary)

* 通常會用一整個列表記錄所有單字，一個列表可能會有 30 \~ 100000 個單字

$$
\begin{bmatrix}
\text{a} \ \text{aaron} \\\vdots \\\text{and}\\\vdots\\\text{Harry}\\\vdots\\\text{Potter}\\\vdots\\\text{zoo}
\end{bmatrix}
$$

* 上面的案例是一個 10000 個單字的 dictionary
  * `and` 的 index 在 367
  * `Harry` 在 4075
  * `Potter` 在 6830
* 接著用 one-hot 方式來呈現單字
  * 例如 Harry 就會是一個全為 0 但 index=4075 為 1 的 10000 長度向量

$$
x^{<1>} = \begin{bmatrix}
0\0\\\vdots\1 (4075^{th})\\\vdots\0\\\vdots\0
\end{bmatrix}
$$

* 該 model 的目標就是給定一堆 $$x^{<t>}$$ 找出各別對應的 $$y^{<t>}$$

## Recurrent Neural Network Model

### Why not standard network ?

* 以 Harry 例子來說，Input 9 個單字要產生 9 個 output，每個 input/output 又都是 10000 長的 one-hot vector
* 第一個問題
  * 每個 training set 的 input 跟 output 會不斷改變
* 第二個問題
  * Input features 之間並沒有 share 的關係
    * 在 $$x^{<1>}$$ 發現 Harry 是人名，$$x^{<87>}$$ 又是 Harry，那 1 能告訴 87 嗎?
* 第三個問題
  * 參數太多，計算量太大
* Recurrent Neural Network 沒有這些問題

### RNNs

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtghhsCIFXPwhkGCFHj%2F-Ltghj8vnezKe27kVsbu%2Frnns.png?generation=1573781961514463\&alt=media)

* 我們會先讀第一個單字 $$x^{<1>}$$
  * 將他丟入 neural network 產生 $$\hat{y}^{<1>}$$
  * 同時會產生 $$a^{<1>}$$ 給下一個單字 $$x^{<2>}$$ 使用
    * 通常 $$a^{<0>}$$ 是一個 0 vector
* 所以 $$x^{<1>}$$ 可以共享資訊給 $$x^{<3>}$$ 來產生 $$\hat{y}\_^{<3>}$$&#x20;
  * 這個模型無法由 3 供應資訊給 1
  * 之後會談到雙向的 RNNs (Bidirectional RNNs)
* 所有的 neural networks 會共享三大參數
  * $$W\_{ax}, W\_{aa}, W\_{ya}$$
  * 命名的規則 (已 ax 為例) : 跟 x 作用並產生 a
* 以一般化 $$x^{t}$$ 來解釋每個單字在網路中的 forward propogation

$$
\begin{aligned}
a^{<0>} &= 0 \\
a^{<t>} &= \text{tanh}(W\_{aa} a^{<t-1>} + W\_{ax}x^{<t>} + b\_a) \\
\hat{y}^{<t>} &= \text{softmax}(W\_{ya}a^{<t>} + b\_y)
\end{aligned}
$$

* 第一個 activation function 可選擇 tanh 或 ReLU
* 第二個 activation function 可選擇 sigmoid 或 softmax

### Simplify Forward Propogation

* 為了講解之後較複雜的 RNNs，我們可以將 forward propogation 進一步簡化
* 將 Waa 和 Wax 合併為 Wa
  * 若 Waa 是一個 100\*100 矩陣
  * 且 Wax 是一個 100\*10000 矩陣
  * 那麼 Wa 就是 100\*10100 的寬矩陣

$$
W\_a = \begin{bmatrix}
W\_{aa} \mid W\_{ax}
\end{bmatrix}
$$

* 將 $$a^{<t-1>}$$ 和 $$x^{<t>}$$ 也合併起來
  * 若 a 是一個 100\*1 向量
  * 且 x 是一個 10000\*1 向量
  * 那麼合併後就是一個長為 10100\*1 的向量

$$
\begin{bmatrix}
a^{<t-1>}\ x^{<t>}
\end{bmatrix}
$$

* 新的 forward propogation 公式

$$
\begin{aligned}
a^{<t>} &= \text{tanh}(W\_a \[a^{<t-1>};x^{<t>}] + b\_a) \\
\hat{y}^{<t>} &= \text{softmax}(W\_{y}a^{<t>}+ b\_y)
\end{aligned}
$$

### Backpropogation through time

* RNNs 的 backpropogation 又稱作 backpropogation through time
  * 因為由右至左推回來，像是時間逆流的感覺
* 要計算 backpropogation 之前，要先知道每個單字的 loss function
* 這邊使用 Cross-entropy loss 作為每個單字 (或說時間點) 的 loss function
* 也就是在 $$x^{<t>}$$ 時的 loss 表示為

$$
\mathcal{L}^{<t>}(\hat{y}^{<t>}, y^{<t>}) = -y^{<t>}\log\hat{y}^{<t>} - (1-y^{<t>})\log(1-\hat{y}^{<t>})
$$

* 而整體的 loss function 可以定義為

$$
\mathcal{L}(\hat{y}, y) = \sum\_{t=1}^{T\_x}\mathcal{L}^{<t>}(\hat{y}^{<t>}, y^{<t>})
$$

* 如此一來，就可以回推並更新 $$W\_y, b\_y, W\_a, b\_a$$

## Different types of RNNs

* 剛剛的網路建立在 $$T\_x = T\_y$$ 的狀況下
* 如果要達成各式不同的 input/output 勢必需要不同的網路形式

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtghhsCIFXPwhkGCFHj%2F-Ltghj9-FqY1QJyN6grb%2Frnn_architectures.png?generation=1573781961468223\&alt=media)

* One-to-One
  * 很無聊，就是個普通的神經網路
* One-to-Many
  * 用於 sequence generation&#x20;
  * e.g. music generation
    * 給定音樂種類，生產出一系列的音符
  * 要注意的是該種類會把 $$\hat{y}$$ 當作下一層的 input
* Many-to-One
  * 用於 sentiment classification
  * e.g. 電影評價打分數
    * 讀入一連串的評價，產出 1\~5 的分數
* Many-to-many with same length
  * e.g. name entity recognition
    * 給定一串文字，標示出文字為名稱的部分
* Many-to-many with different length
  * e.g. machine translation
    * 給定一串英文，翻譯成長度不同的中文
  * 首先先讀取 x 的部分，最後再處理 y 的部分

## Language model and sequence generation

### Language Modelling

* 假設 speech recognition 時聽到了一句話
  * “The apple and pear salad.”
* 那到底是聽到上面的句子還是 “The apple and pair salad.” ?
* 為了判斷是哪一句話，所以給兩句話機率的方法就是 **language modelling**

$$
P(\text{The apple and pear salad.}) = 5.7\times 10^{-10}\\
P(\text{The apple and pair salad.}) = 3.2\times 10^{-13}
$$

* 可以看到在這個 language model 中
  * The apple and pear salad 的機率比較高

### Build Language model with RNNs

* training set 會是 large **corpus** of english text
  * corpus 是一個 NLP 名詞，代表大量句子所組成的文本
* 首先要 tokenize corpus 中的所有單字，也就是建立字典
  * 標點符號可以 tokenize 可以不要

$$
\begin{aligned}
&\text{The } &\text{ Egyptian } &\text{ Mau } &\text{ is } &\text{ a } &\text{ bread } &\text{ of } &\text{ cat }. &\text{ <EOS> }\\
\&y^{<1>}\&y^{<2>}\&y^{<3>}\&y^{<4>}\&y^{<5>}\&y^{<6>}\&y^{<7>}\&y^{<8>}\&y^{<9>}
\end{aligned}
$$

* tokenize 前有時會增加一個 `<EOS>` 代表句子結束
* tokenize 會將每一個單字轉換為 one hot vector
  * 假設有一個 10000 單字的字典，那就會在該單字的 index 設 1 其他設 0
  * 今天遇到一個不在字典的單字，例如 `Mau`
    * 那就會將他設定在 `<UNK>` 的位置，表示 unknown
* Tokenize 後就可以將他們 input 到 RNN 訓練

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtiOJRgTJgCN_TEalGf%2F-LtiOKf2zBez2eTgw7zq%2Frnn_language_model.png?generation=1573810168414584\&alt=media)

* 首先 $$x^{<1>}$$ 和 $$a^{<0>}$$ 都設為 0
* 第一個 timestep 算出的 $$\hat{y}^{<1>}$$ 代表字典中所有單字是句子中第一個字的機率
  * 有 10002 個字，包括 `EOS` 和 `UNK`

    $$P(\text{a})P(\text{aaron})\cdots P(\text{cat})\cdots P(\text{UNK})P(\text{EOS})$$
* 第二個 timestep 的 $$x^{<2>}$$ 就是原本句子得到的 $$y^{<1>}$$
  * 加上上一個 timestep 算出的 $$a^{<1>}$$
  * 所以算出來的 $$\hat{y}^{<2>}$$ 代表出現 cats 後字典裡每一個單字是下一個字的機率
  * 所以 average 應該要是最高才對

    $$
    P(\text{average}\mid \text{cats}) \text{ should be the highest}
    $$
* 以此類推，$$\hat{y}^{<3>}$$ 表示 cats average 出現後，字典中每個單字的出現機率

  $$
  P(\text{15} \mid \text{cats average})\text{ should be the highest}
  $$
* 為了要訓練這個 RNN 我們定義 cost function
  * 在 predict 第 t 個單字時的 softmax loss function 為

    $$
    \mathcal{L}(\hat{y}^{<t>}, y^{<t>})=-\sum\_i y\_i^{<t>}\log\hat{y}\_i^{<t>}
    $$
  * Overall 的 Cost function 為

    $$
    \mathcal{L} = \sum\_t \mathcal{L}^{<t>}(\hat{y}^{<t>}, y^{<t>})
    $$
* 總結一下，要預測一個句子 $$P(y^{<1>},y^{<2>},y^{<3>})$$的機率
  * 等於要計算 $$P(y^{<1>})$$
  * 以及知道 $$P(y^{<1>})$$ 下的 $$P(y^{<2>})$$ 為何
  * 再來是 $$P(y^{<1>}, y^{<2>})$$ 下 $$P(y^{<3>})$$ 為何

$$
P(y^{<1>},y^{<2>},y^{<3>}) = P(y^{<1>})P(y^{<2>}\mid y^{<1>})P(y^{<3>}\mid y^{<1>},y^{<2>})
$$

### Sampling novel sequences

* 訓練好的 language model 可以用 sampling 方式來呈現他所學的結果
* Sampling 方式就像 one-to-many model
  * 給定 $$a^{<0>} = x^{<1>} = \vec{0}$$
  * 算出 $$\hat{y}^{<1>}$$ 之後，用 `np.random.choice` 方式從中選取任意一個 sample
  * 這個 sample 作為 $$x^{<2>}$$ 繼續算出 $$\hat{y}^{<2>}$$ 再選一個 sample
  * 以此類推直到 sampling 到 EOS 或是自訂回合數就停止

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJaK6qHgM4m8qNQ%2Frnn_sampling.png?generation=1574091759108764\&alt=media)

* 以上的方法每個 $$x^{<t>}$$ 都是一個單字，稱作 word level model
  * $$\text{Vocabulary} = \[\text{a}, \text{aaron},\cdots, \text{zoo}, \text{<UNK>}]$$
* 我們可以使用 character 作為每個 inputs
  * 可以有大小寫字母、數字、符號
  * $$\text{Vocabulary} = \[\text{a, b, c, ..., z, ., ;, 0, ..., 9, A, ...,Z}]$$
  * 優點是不會有 `<UNK>`
  * 缺點是資料量變大，計算變大、訓練成本過高
    * 不過隨著硬體發展，有一些專案使用 character level model
* Sampling example
  * 下圖左是一個從 news 訓練出的 model 所產生的 sampling novel sequences
  * 下圖右則是讀完沙士比亞文章所產生的 sequences

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJczRSc7jfs9IhJ%2Fsequence_generation_sampling.jpg?generation=1574091758928123\&alt=media)

## Vanishing gradients with RNNs

* 觀察以下兩句句子

$$
\text{The cat},\text{ which already ate } \cdots, \text{ was full.} \\
\text{The cats},\text{ which already ate } \cdots, \text{ were full.} \\
$$

* 人類可以記住非常前面的詞 (cat/cats) 來去判斷很後面的詞 (was/were)
* 但目前的 basic RNN models 很難去找出這種 **Long-term Dependencies**
* 原因跟 deep neural networks 已提過的 **vanishing gradients** 有著很大關係
  * 回憶一下 vanishing gradients 是因為 backprop 的導數小於 1
  * 造成越往回走梯度越小，最終使得梯度消失

### Vanishing gradients in RNNs

* RNN 中也有類似 vanishing gradient 的情況，在 RNN 中會出現 local influences
* 舉例來說 $$\hat{y}^{<3>}$$ 只會跟 $$x^{<1>}, x^{<2>}, x^{<3>}$$ 有較大關係
* 假設 was 在 $$\hat{y}^{<100>}$$ 那他就無法跟最前面的 cat/cats 互相影響了
* 這造成 basic RNN model 有著無法處理 long-term dependencies 的弱點

> 補充 : RNN 也有可能出現 Exploding gradient 但情況較少
>
> 而且梯度爆炸比較好偵錯，只要參數有問題或是出現 numerial overflow (出現 NaN) 就會知道
>
> 並且可以用 **gradient clipping** 方法解決 (設定 threshold 避免梯度繼續增高)

* 為了處理 RNN 中的 vanishing gradient，要使用 GRU 及 LSTM 的技術

## Gated Recurrent Unit (GRU)

* 先回顧 basic RNN 的架構，在計算 $$a^{<t>}$$ 時是這樣計算

  $$a^{<t>} = g(W\_a\[a^{<t-1>}, x^{<t>}]+b\_a)$$

  * 可以將 basic RNN 畫成下圖表示

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJeX-rFqcs4_1XV%2Fbasic_single_rnn.png?generation=1574091758936188\&alt=media)

* GRU 在 basic RNN 中加入一個 **memory cell** $$(c)$$ 的概念
* 回到原本的句子，目標是讓網路可以記憶 `cat` 並在之後知道要使用 `was`
  * $$\text{The cat, which already ate ... was full.}$$
* 定義每一個 $$c^{<t>}$$ 會和 $$a^{<t>}$$ 相等 $$c^{<t>} = a^{<t>}$$
* 然後定義 $$\tilde{c}^{<t>}$$ 是可能取代掉 $$c^{<t>}$$ 的候補
  * $$\tilde{c}^{<t>} = \text{tanh}(W\_c\[c^{<t-1>}, x^{<t>}]+b\_c)$$
* 接著定義一個 **Update Gate** $$(\Gamma\_u)$$ 用來決定是否要用 $$\tilde{c}^{<t>}$$ 取代掉 $$c^{<t>}$$
  * Update Gate 最好要能 output 0/1 值，1 決定取代、0 放棄取代，所以使用 sigmoid function
  * $$\Gamma\_u = \sigma(W\_u \[c^{<t-1>},x^{<t>}]+b\_u)$$
* 最後用以下公式決定每個 time step 要不要更新 $$c^{<t>}$$

  * $$c^{<t>} = \Gamma\_u \times \tilde{c}^{<t>} + (1-\Gamma\_u) \times c^{<t-1>}$$
    * 當 $$\Gamma\_u = 1$$ 時，後面被消掉，所以 $$c^{<t>} = \tilde{c}^{<t>}$$
    * 當 $$\Gamma\_u = 0$$ 時，前面被消掉，所以 $$c^{<t>} = c^{<t-1>}$$

  **Example**

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJg01hMRNRSh5WI%2Frnn_gru_example.jpg?generation=1574091759020593\&alt=media)

* 回到 cat 的句子問題
  * 在 cat 時把 $$\tilde{c}^{<t>} = 1, \Gamma\_u = 1$$
    * 此時的 $$c^{<t>}$$ 就會被設定為 1 (假設 1 代表單數、0 代表多數)
  * 接著句子持續下去，每一個的 $$\Gamma\_u$$ 都設定為 0，避免 cat 的資訊被刷掉
  * 直到 was 的 time step 出現，我們就可以用 $$c^{<t>}$$ 告訴他是 cat 要用 was
  * 等到 was 結束，不會再用到這個資訊，在之後的某個地方就會設定 $$\Gamma\_u = 1$$ 更新
* 因為使用 sigmoid 作為 $$\Gamma\_u$$ 的計算方式
  * 使得 $$\Gamma\_u$$ 長期都會非常接近 0 或是 1
  * 當 $$\Gamma\_u = 1$$ 時，$$c^{<t>}$$ 就會被更新
  * 當 $$\Gamma\_u = 0$$ 時，$$c^{<t>}$$ 就會保持 $$c^{<t-1>}$$
  * 由於 c 經過很長時間依然不變，且 c 就是 a，所以也解決了 vanishing gradients

### Simplified GRU

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJixdgJAkmD0nVD%2Fgru_single_rnn.png?generation=1574091759116661\&alt=media)

* 在 GRU 的 network 中
  * 先用 $$c^{<t-1>}$$ 和 $$x^{<t>}$$ 進行 `tanh` 得到 $$\tilde{c}^{<t>}$$&#x20;
  * 再用 $$c^{<t-1>}$$ 和 $$x^{<t>}$$ 進行 `sigmoid` 得到 $$\Gamma\_u$$
  * 然後透過紫色區塊 (就是決定是否更新) 來更新新的 $$c^{<t>} = a^{<t>}$$
  * 最後跟一般一樣，產出 $$\hat{y}^{<t>}$$
* 要注意的是，$$c^{<t>}$$ 可以是一個 vector
  * 若是 $$c^{<t>}$$ 是一個 100 dimensional 的向量
  * 那麼 $$\tilde{c}^{<t>}, \Gamma\_u$$ 也會是 100 dimensional
  * 而更新 $$c^{<t>}$$ 的乘法就會是 element-wise 的乘法

    $$c^{<t>} = \Gamma\_u \ast \tilde{c}^{<t>} + (1-\Gamma\_u) \ast c^{<t-1>}$$

### Full GRU

* 以上的 GRU 是簡化過的 GRU
* 在完整的 GRU 中，會再添加一個 **Relevance Gate** $$\Gamma\_r$$
* Relevance gate 用來表示 $$c^{<t>}$$ 和 $$\tilde{c}^{<t>}$$ 的關聯性
* 我們在原本的 $$\tilde{c}^{<t>}$$
  * $$\tilde{c}^{<t>} = \text{tanh}(W\_c\[c^{<t-1>}, x^{<t>}]+b\_c)$$
* 加入 Relevance gate
  * $$\tilde{c}^{<t>} = \text{tanh}(W\_c\[\Gamma\_r \times c^{<t-1>}, x^{<t>}]+b\_c)$$
* 而 Relevance gate 的算法也很簡單
  * $$\Gamma\_r = \sigma(W\_r\[c^{<t-1>}, x^{<t>}] + b\_r)$$
* Full GRU 的算式如下

$$
\begin{aligned}
\tilde{c}^{<t>} &= \text{tanh}(W\_c\[\Gamma\_r \times c^{<t-1>}, x^{<t>}]+b\_c)\\
\Gamma\_u &= \sigma(W\_u \[c^{<t-1>},x^{<t>}]+b\_u)\\
\Gamma\_r &= \sigma(W\_r\[c^{<t-1>}, x^{<t>}] + b\_r)\\
c^{<t>} &= \Gamma\_u \times \tilde{c}^{<t>} + (1-\Gamma\_u) \times c^{<t-1>}
\end{aligned}
$$

> 補充 : GRU 最重要的兩篇論文 :
>
> * [Cho et al., 2014. On the properties of neural machine translation: Encoder-decoder approaches](https://arxiv.org/pdf/1409.1259.pdf)
> * [Chung et al., 2014. Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling](https://arxiv.org/pdf/1412.3555.pdf)

## Long Short Term Memory (LSTM)

* LSTM 跟 GRU 長的很像，但其實 LSTM 是較早出現的架構
* LSTM 捨棄了 **relevance gate**，保留 **update gate**，並新增了 **forget gate** 和 **output gate**
  * 所以 LSTM 共有三個 gates
* LSTM 不再讓 $$c^{<t>} = a^{<t>}$$，並將兩者分開來計算

$$
\begin{aligned}
\tilde{c}^{<t>} &= \text{tanh}(W\_c\[a^{<t-1>}, x^{<t>}]+b\_c)\\
\Gamma\_u &= \sigma(W\_u \[a^{<t-1>},x^{<t>}] + b\_u)\\
\Gamma\_f &= \sigma(W\_f\[a^{<t-1>}, x^{<t>}] + b\_f)\\
\Gamma\_o &= \sigma(W\_o\[a^{<t-1>}, x^{<t>}] + b\_o)\\
c^{<t>} &= \Gamma\_u \ast \tilde{c}^{<t>} + \Gamma\_f \ast c^{<t-1>} \\
a^{<t>} &= \Gamma\_o \ast \text{tanh}(c^{<t>})
\end{aligned}
$$

* 首先 $$\tilde{t}^{<t>}$$ 不再使用 $$c^{<t-1>}$$ 而是使用 $$a^{<t-1>}$$ 來跟著 $$x^{<t>}$$ 一起計算
* 然後依次算出 $$\Gamma\_u, \Gamma\_f, \Gamma\_o$$
* 更新 $$c^{<t>}$$ 時，不再是兩者取一，而是將 $$c^{<t-1>}$$ 乘上 forget gate 後，**加進** update 的 $$\tilde{t}^{<t>}$$
* 最終用 output gate 乘上 $$\text{tanh}(c^{<t>})$$ 來更新 $$a^{<t>}$$

### LSTM nets

* 單個 LSTM 模型可以表示如下

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJlEYtE42X9jOiJ%2Frnn_lstm_graph.jpg?generation=1574091758940796\&alt=media)

* 接收上一層的 $$c^{<t-1>}, a^{<t-1>}$$
* 結合 $$x^{<t>}$$ 算出三個 gate 和 $$\tilde{c}^{<t>}$$
* 計算出這一層的 $$c^{<t>}, a^{<t>}$$ 給下一層使用
* 算出預測值 $$\hat{y}^{<t>}$$
* 將多個 LSTM 相連在一起就是 LSTM network

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJnRfzVqurlQjNB%2Frnn_lstm_nets.png?generation=1574091759258603\&alt=media)

### Peephole Connection

* 上面的 LSTM 的三個 gate 值只有使用 $$x^{<t>}, a^{<t-1>}$$ 計算出來
* 但在實作上有一種方法將 $$c^{<t-1>}$$ 也帶入計算 gate 值
* 這種方法稱為 **Peephole connection**
* 注意點是，若 gate 是個 100 dimensional 的 vector
  * 那麼 c 的第 i 個值，只會影響到 gate vector 中的第 i 個值
  * 也就是 c 和 gate 的關係是 1 對 1 的
  * 跟 GRU 在更新 gate 是不一樣的

$$
\begin{aligned}
\Gamma\_u &= \sigma(W\_u\[a^{<t-1>}, x^{<t>}, c^{<t-1>}] + b\_u)\\
\Gamma\_f &= \sigma(W\_f\[a^{<t-1>}, x^{<t>}, c^{<t-1>}] + b\_f)\\
\Gamma\_o &= \sigma(W\_o\[a^{<t-1>}, x^{<t>}, c^{<t-1>}] + b\_o)
\end{aligned}
$$

## Bidirectional RNN (BRNN)

* 前面也說過，單方向的 RNN 會無法處理一些問題
* 例如單字必須透過後方單字才能辨別是否是人名

$$
\begin{aligned}
&\text{He said, "Teddy bears are on sales!"}\\
&\text{He said, "Teddy Roosevelt was a great President!"}
\end{aligned}
$$

* 上面兩個句子，只讀前三個字，可能會判斷兩個 Teddy 都是人名
* 但事實上只有第二句的 Teddy 指的是人名
* 為了解決此問題，出現了能夠雙向處理的 RNN － **Bidirectional RNN (BRNN)**

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJplgewZnKgxNws%2Fbidirectional_rnn_intuition.jpg?generation=1574091758920418\&alt=media)

* 為了簡化問題，假設現在只讀了前四個字 `He said Teddy Roosevelt`
* 首先一如往常將句子由左至右產出 $$a^{<1>}, a^{<2>}, a^{<3>}, a^{<4>}$$ (以 $$\rightarrow$$ 表示)
* 接著再將句子由右至左產出 $$a^{<4>}, a^{<3>}, a^{<2>}, a^{<1>}$$ (以 $$\leftarrow$$ 表示)
  * 要注意的是，兩個都是 forward propogation，並非 backpropogation !
* 所以現在要計算句子中任意一個 $$\hat{y}^{<t>}$$ 都可以配合左右兩邊的資訊來計算
  * $$\hat{y}^{<t>} = g(W\_y\begin{bmatrix}\overrightarrow{a}^{<t>}, \overleftarrow{a}^{<t>}\end{bmatrix}+b\_y)$$
* 例如要計算 $$\hat{y}^{<3>}$$ 的 Teddy 為人名的機率
  * $$\hat{y}^{<3>} = g(W\_y\begin{bmatrix}\overrightarrow{a}^{<3>}, \overleftarrow{a}^{<3>}\end{bmatrix}+b\_y)$$
  * 他考慮的 $$\overrightarrow{a}^{<3>}$$ 考慮了 a1, a2 的 `He said`
  * 他考慮的 $$\overleftarrow{a}^{<3>}$$ 考慮了 a4 的 `Roosevelt`
* BRNN 的缺點是需要完整的句子序列，才可以訓練並預測句子中的任意單字
* 若用在 speech recognition，不可能等所有話講完，再慢慢處理所有文字
* 所以在 speech recognition 的實際應用上，不會使用 standard BRNN
* 但是在能夠一次取得完整句子的 NLP 應用中， standard BRNN 是很有效率的

## Deep RNNs (DRNN)

![](https://2991100231-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LhyC30yNfTP1YdCIj83%2F-LtzATlPcMpBTbaR0naR%2F-LtzAVJrNOH7RSGBJkiZ%2Fdrnn_intuition.png?generation=1574091759085270\&alt=media)

* 到目前為止見到的只是 one hidden layer 的 RNN model
* 事實上 RNN 也可以有多個 hidden layer，只是不會像 CNN 那麼多
* 上圖有幾個 notation 需要解釋
  * $$\[l]$$ 用來代表第 l 層
  * $$<t>$$ 用來代表第 t 個 time step
  * 所以 $$a^{\[2]<3>}$$ 代表是第 2 個 hidden layer 在第 3 個 timestep 的狀況
* 另外在 parameters 也有不同
  * $$W\_a^{\[l]}$$ 代表在第 l 層的 $$W\_a$$
  * $$b\_a^{\[l]}$$ 代表在第 l 層的 $$b\_a$$
  * 所以 $$a^{\[2]<3>}$$ 的算法為

    $$a^{\[2]<3>} = W\_a^{\[2]}\begin{bmatrix}a^{\[2]<2>}, a^{\[1]<3>}\end{bmatrix} + b\_a^{\[2]}$$
* DRNN 中的每一個 blocks 可以是一般的、GRU、LSTM blocks
* DRNN 在計算 $$\hat{y}^{<t>}$$ 前，也可以先接上一連串的 fully-connected networks
* 因為 RNN 的計算量已經相當龐大，所以 DRNN 的 hidden layers 數目並不會太多
