---
# System prepended metadata

title: RNN

---

# RNN(Recurrent neural network)
> ~~Recurrent，顧名思義，會重複遞移~~

## 概念

在一個簡單的神經網路之中，通常只有少數的隱藏層，而深度學習會具有數十個甚至上百個隱藏層，再根據不同的架構形成不同的類型，這裡就不再額外贅述，而今天要討論的是RNN。

RNN的基本架構如下：
![JywniHv](https://hackmd.io/_uploads/HkGGtSjA6.png)
<center>x：輸入&ensp; &ensp; O：輸出&ensp; &ensp;  V：表示一個時間點到另一個時間點的訊號&ensp; &ensp;  h：RNN的Block，包含了網路的權重和Activation functions</center> 

<br>
<br>

我們稍後再來討論它的數學原理，先來講講它的特性：

RNN跟一般的的神經網路的差異是，他會把前一層的資訊傳遞下來，由前一層的狀態來影響下一層的狀態，從而達到令資料有連續性的目的。
![Rnn01](https://hackmd.io/_uploads/HkjEXroA6.gif)

<center>第n層的hidden layer，會將上一層的state以及本層的input組合成新的state</center> 

<br>
<br>

![rnn02](https://hackmd.io/_uploads/r1EH7BoCa.gif)

<center>新的state轉移給下一層</center> 
<br>

因為這樣子的特性，所以很常被使用在自然語言處理(NLP)，語音辨識，聊天機器人等等……

RNN能夠處理不同長度的資料以及不同長度的輸出從而延伸不同應用，主要分為以下四種:

一對一(one to one)：固定長度的輸入(input)及輸出(output)，即一般的 Neural Network 模型。

一對多(one to many)：單一輸入、多個輸出，例如影像標題(Image Captioning)，輸入一個影像，希望偵測影像內多個物體，並一一給予標題，這稱之為『Sequence output』。

多對一(many to one)：多個輸入、單一輸出，例如情緒分析(Sentiment Analysis)，輸入一大段話，判斷這段話是正面或負面的情緒表達，這稱之為『Sequence input』。

多對多(many to many)：多個輸入、多個輸出，例如語言翻譯(Machine Translation)，輸入一段英文句子，翻譯成中文，這稱之為『Sequence input and sequence output 』。


接下來，我們來討論運作RNN的數學原理

## 數學原理

##### 擠壓函數(squashing function)
透過特定函數將值限制在特定的位置，RNN通常會使用**雙曲正切函數（Hyperbolic tangent,tanh）**
![IMG_3765](https://hackmd.io/_uploads/rkRQfcjR6.png)
<center>透過這個函數，我們可以將神經網路的權重限制在1和-1之間</center>

 <br>
    
    
##### recurrent 

跟一般的線性回歸函數(ex.y=Wx+b)相似，只是加入了遞迴的概念

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

加入了遞迴的概念，形成了下圖第一個公式，再加入Activation function，就形成了第二個公式


![image](https://hackmd.io/_uploads/SyHv1tiRa.png)
<center>其中h是預測值，W和U和V分別代表不同的權重</center>
<br>

我們把擠壓函數跟這個公式結合起來，就是RNN的遞迴公式了

![IMG_3767](https://hackmd.io/_uploads/HJO9Hcs0T.png)
<center>整理後的數學式</center>

<br>
<br>


RNN本身也因為它的特性而帶來一些隱藏的問題，我們接下來會討論它的缺點。

<br>



> **PS**:可以參考看看[這篇文章](<https://yuehhua.github.io/2018/07/21/why-rnn/>)，從馬可夫鍊的角度思考，可能對狀態轉移這個概念本身有更深的理解。


<br>

### RNN的問題：
容易**梯度消失（Gradient Vanishing）**，**梯度爆炸（Gradient Explored)）**

**梯度消失**：拿Sigmoid作為Activation functions來舉例
![image](https://hackmd.io/_uploads/rybLWLiA6.png)
將Sigmoid進行微分會得到以下結果：
![image](https://hackmd.io/_uploads/HyEaWLi0p.png)
可以看見導數最大值只有1/4，最小值是0，當梯度反向傳播的時候不斷連乘，越乘越小，最終導致梯度消失(靠近input層的淺層hidden layer權重變動會越來越小)

**權重爆炸**：就反過來，導數超過一的時候會梯度爆炸(淺層的權重變動越來越大)

<br>

可以透過**LSTM**(Long Short-Term Memory)或是**GRU**(Gated Recurrent Unit)來漸少梯度消失的這個問題

LSTM：在RNN的基礎上，加入了三個gate，Input gate(輸入門)，Forget gate(遺忘門)，和Output gate(輸出門)。
Input gate： 決定這一次的輸入需不需要被記憶，或者要記多少(可能只記個30%)
Forget gate： 決定要不要遺忘之前的hidden state，也可以按比例遺忘。
Output gate： 決定這一次所得到的輸出要放多少(也是比例)進去hidden state小房間。
透過三個門將不重要的資訊忽略掉

GRU：在RNN的基礎上，加入了兩個gate，Reset gate(重製門)和Update gate(更新門)。
Reset gate： 決定是否要遺忘之前留下來的hidden state。
Update gate： 決定這一次的hidden state所要留下來的比例。
類似於LSTM，把Input gate跟Forget gate合併成和Update Gate，可以加快速度跟減少記憶體使用，代價是Accuracy會下降。

> 礙於筆者撰寫時正在修習數位邏輯設計實驗，看到閘門的概念就頭痛，請恕我簡單帶過去就好XD

需要注意的是這兩者只能避免梯度消失，不能避免梯度爆炸，梯度爆炸可以透過梯度裁減(gradients clipping)，修正梯度來解決問題：
![image](https://hackmd.io/_uploads/SyqyMFjA6.png)



<br>

~~實作的部分等我回學校再放，我要去放假了~~

參考資料:
https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21
https://medium.com/deeplearningbrasilia/deep-learning-recurrent-neural-networks-f9482a24d010