# 李宏毅_ML_Lecture_21-1
###### tags: `Hung-yi Lee` `NTU` `Machine Learning`
[課程撥放清單](https://www.youtube.com/channel/UC2ggjtuuWvxrHHHiaDH1dlQ/playlists)
## ML Lecture 21-1: Recurrent Neural Network (Part I)
[課程連結](https://www.youtube.com/watch?v=xCGidAeyS4M&list=PLJV_el3uVTsPy9oCRY30oBPNLCo89yu49&index=30)
### Example Application
![](https://i.imgur.com/chPElpL.png)
RNN應用範例,i.e. Slot Filling,使用者說了一句話,系統必需從語句中取得目的地<sub>(Destination)</sub>以及到達時間<sub>(time of arrival)</sub>
### Example Application
![](https://i.imgur.com/CwEAMqz.png)
對於Slot Filling的問題,也可以利用feedforward network來解,輸入則是一個詞彙,i.e Taipei,但在此之前需要將詞彙先以向量來表示<sub>(見下方兩小節說明)</sub>,輸出為詞彙屬Slots的機率,如Taipei屬Destination或time of arrival的機率。
### 1-of-N encoding
![](https://i.imgur.com/lwFnLvF.png)
最簡單將詞彙以向量來表示的就是1-of-N encoding的方式,
### Beyond 1-of-N encoding
![](https://i.imgur.com/a0GZLMl.png)
利用1-of-N encoding會遇到的問題在於某一個詞彙可能從來沒有見過,這時候我們會在向量內加入一個『other』來表示沒見過的詞彙,又或者可以利用詞彙字母來表示向量,這樣就可以避免遇到沒見過的詞彙,i.e. Word hashing,apple對應到的三個字母為1,其餘為0。
### Example Application
![](https://i.imgur.com/2M5uHZZ.png)
單純的利用feedforward network判斷詞彙是否為Slot可能不是那麼適用,因為不同的語句之間有不同的意函,但feedforward network無法判斷,以上圖例,一個為arrive,一個為leave,但feedforward network只會判斷Taipei與November 2nd,卻不會判斷arrive與leave的差異。
這時候我們希望NN可以擁有記憶力來記錄語句的上下文,根據不同的上下文來產生不同的輸出。
### Recurrent Neural Network(RNN)
![](https://i.imgur.com/fLHBAmE.png)
RNN中,每一層Hidden Layer的輸出都會被存到memory中,後續的過程中就不會僅是考慮輸出,還會考慮memory中的值。
### Example
![](https://i.imgur.com/pbg4VDy.png)
![](https://i.imgur.com/WoMWMsx.png)
![](https://i.imgur.com/fg5SXoI.png)
![](https://i.imgur.com/HmCHZIK.png)
舉例來說,權重皆為1,沒有偏差單元(bias),activation function為線性,memory初始為0,輸入為Sequence(1,1,1,1,2,2)。
1. 第一次輸入
1. (1, 1)
2. memory(0, 0)
3. output(4, 4)
4. update memory(2, 2)
2. 第二次輸入
1. (1, 1)
2. memory(2, )
3. output(12, 12)
4. update memory(6, 6)
2. 第三次輸入
1. (2, 2)
2. memory(6, 6)
3. output(32, 32)
4. update memory(16, 16)
輸入的序列有其順序性,從上面簡單的範例可以發現到,調換了順序會造成產生的結果不同。
### RNN
![](https://i.imgur.com/2Zx6mAJ.png)
以『arrive Taipei on November 2nd』為例,模型首先輸入『arrive』,並計算『arrive』屬於每一個slot的機率$y^1$,接著輸入『Taipei』,這時候『Taipei』除了考慮自己之後也同時考慮了$a^1$<sub>『arrive』</sub>再輸出機率$y^2$,一直到所有的詞彙計算完畢。
注意到上圖中有三個輸入、輸出並不代表它是三個神經網路組成,它是一個神經網路在三個時間點上被使用了三次,並且相同的顏色代表著相同的權重
### RNN
![](https://i.imgur.com/UwRWPnC.png)
加入了記憶單元之後,雖然第二個單字一樣是『Taipei』,但因為第一個單字的不同會造成記憶單元的不同,最後所得的輸出就不會相同。
### Of course it can be deep
![](https://i.imgur.com/9d3H6Ck.png)
RNN也可以很深,每一個Hidden Layer都保存它的memory,在下一個時步計算的時候再提出一起計算。
### Elman Network & Jordan Network
![](https://i.imgur.com/0RLRiUK.png)
* Elman Network:
* 如前幾個單元所述即為Elman Network
* Jordan Network:
* 所記憶的並非每一個Hidden Layer的輸出,而是最後的輸出$y^t$,在下一個時步再讀入計算。
傳說,Jordan可以擁有較好的效能,這是因為Hidden Layer是沒有目標的輸出,較難控制學習到的資訊,而最後的output是有的。
### Bidirectional RNN
![](https://i.imgur.com/UBAOntm.png)
RNN不僅單向依時步向前執行,也可以逆向執行,兩個RNN共同將輸出給予Output layer來得到結果。
這可以讓RNN所讀的資訊較廣,一個句子讀完了來回完整的句子之後再決定詞彙的slot。
### Long Short-term Memory(LSTM)
![](https://i.imgur.com/F1Q528G.png)
相較於稍早所提的RNN,LSTM的memory更為複雜,存在著3個gate,4個input,1個output。
* 3個Gate
1. Input Gate: 某個neruon的output想寫入Memory Cell之前,要先經過input gate,超過閥值才有辦法把值寫入Memory Cell
2. Output Gate: 決定是否允許其它neuron讀取Memory Cell的值
3. Forget Gate: 決定什麼時候Memory Cell清空
* 4個Input
1. 想寫入Memory Cell的input
2. 操控Input Gate的訊號
3. 操控Output Gate的訊號
4. 操控Forget Gate的訊號
其中3個Gate的寫入、讀取、忘記與否皆由神經網路自行學習。
### Long Short-term Memory(LSTM)
![](https://i.imgur.com/rIhBCY7.png)
仔細觀察數學式如上圖:
* 符號約定:
1. Input: $z$
2. 操作Input Gate: $z_i$
2. 操作Forget Gate: $z_f$
2. 操作Output Gate: $z_o$
3. Output: $a$
4. Memory Cell: $C$
* 流程說明:
1. $Z$通過sigmoid function得到$g(z)$
2. $Z_i$通過sigmoid function得到$g(z_i)$
3. 1、2所得相乘得到$g(z)f(z_i)$
4. $Z_f$通過sigmoid function得到$g(z_f)$
5. Memory Cell乘上Forget Gat的值,得到$cf(z_f)$
* 當forget gate的輸入為0,那代表之前存在memory cell的值會變0
* 當forget gate的輸入為1,那代表之前存在memory cell的值會保留
7. 將5、3相加得到$c'$
* $c'=g(z)f(z_i)+cf(z_f)$
* 當input gate的輸入為0,那就相當於沒有更新
* 當input gate的輸入為1,那就相當於直接把$g(z)$當做輸入
8. Memory Cell $c$變為$c'$
9. $c'$通過h function得到$h(c')$
10. $z_o$通過sigmoid function得到$f(z_o)$
* 當output gate的輸入為1,代表可以通過
* 當output gate的輸入為0,則$f(z_o)$為0,代表無法通過
11. 9、10相乘得到$a=h(c')f(z_o)$
* activation function:
* 通常選擇使用Sigmoid Function,因為輸出是介於0、1之間的值,用以代表gate被打開的程度
### LSTM - Example
![](https://i.imgur.com/XTMBVVX.png)
範例說明:
* input為三維的vector
* output為一維的vector
* 神經網路中只有一個LSTM的cell
* $x_2$為1的時候,$x_1$的值就會被寫入memory
* $x_2$為-1的時候,$x_1$的值就會被重置
* $x_3$為1的時候,output gate才會開啟,才看的到output
* 初始memory為0
上排的值是代表每一個時步結果,在timestep為3的時候因為timestep2的$x_2$為1,因此記憶,以此類推。
### LSTM - Example
![](https://i.imgur.com/6l0dHom.png)
上圖是實際執行一個過程,依之前所提,一個memory cell會有四個input,三個gate,一個output,權重與偏差單元都是學習過程中學習到的,範例中假設我們已經得到相關學習參數並且初始memory cell為0。
* input:
* 僅第1個權重有值
* input_gate:
* 僅第2個權重有值,並且偏差單元為-10,這代表$x_2$為0則輸出為-10,經過sigmoid之後是接近0,因此關閉
* forget_gate:
* 僅第2個權重有值,並且偏差單元為10,這代表平常是開啟狀態<sub>(開啟代表記憶)</sub>,在$x_2$輸入是很大的負值時才會啟動重置。
* output_gate:
* 僅第3個權重有值,並且偏差單元為-10,代表必需$x_3$有值並大於偏差單元情況下才會輸出。
* memory_cell: init 0
計算:
1. input: (3,1,0)
* input: 3
* input_gate: open
* forget_gate: open
* memory_cell: 3
* output_gate: close
* output: 0
1. input: (4,1,0)
* input: 4
* input_gate: open
* forget_gate: open
* memory_cell: 7
* output_gate: close
* output: 0
1. input: (2,0,0)
* input: 2
* input_gate: close
* forget_gate: open
* memory_cell: 7
* output_gate: close
* output: 0
1. input: (1,0,1)
* input: 1
* input_gate: close
* forget_gate: open
* memory_cell: 7
* output_gate: open
* output: 7
1. input: (3,-1,0)
* input: 3
* input_gate: close
* forget_gate: close
* memory_cell: 0
* output_gate: close
* output: 0
### Original - Network
![](https://i.imgur.com/UUHmGm7.png)
![](https://i.imgur.com/eRRTy8e.png)
原始神經網路中存在著很多神經單元,將input乘上不同的weight之後做為不同神經單元的輸入,而每一個神經單元都是一個function,輸入一個scalar,輸出另一個scalar。
而LSTM在於,只要將神經單元想成是Memory Cell就可以了,並且一個輸入會影響Memory Cell中的三個gate,就是四個input,原始神經網路中很單純的就是一個input對應一個output,在LSTM是四個input對應一個output,也因此LSTM的參數量會是一般神經網路的四倍。
### LSTM
![](https://i.imgur.com/Iq3VtqH.png)
假設目前有一排的LSTM的Memory Cell,每一個Cell都存著一組Scalar,將所有的Scalar接起來成為一個Vector,即$c^{t-1}$
在時間點$t$輸入一個Vector,$x^t$,經過transform之後變為$z$,$z$中的每一個dimension代表操控一個相對應的Cell<sub>(即$z$的dimension會相等於Memory Cell)</sub>
接著$x^t$再乘上另一個transform得到$z^i$,它的dimension依然相等於Memory Cell,操控相對應的input gate。一樣的,會有$z^f, z^o$來操控forget gate與output gate。
這四個Vector就是操控Memory Cell的關鍵。
### LSTM
![](https://i.imgur.com/qWFeRF9.png)
上圖是LSTM計算流程的說明:
1. 時步$t$輸入了$x^t$
2. transform之後得到$z$,與input gate的$z^i$相乘<sub>(元素相乘)</sub>
3. $z^f$與上一個時步的Memory Cell,$c^{t-1}$相乘
4. output gate $z^o$與2、3相加結果相乘得到最後結果$y^t$
### LSTM
![](https://i.imgur.com/DESfd1r.png)
上一小節中的步驟2、3相加得到的結果就是新的Memory Cell的值$c^t$,相同的計算方式進入下一個時步$t+1$,不斷循環。
注意到,真正的LSTM中的輸入會考慮上一個時步的output gate的值,如上圖中$x \rightarrow h^t$,也會考慮上一個時步的Memory Cell。
因此,操作LSTM的四個gate的同時你考慮這個時步的輸入、上一個時步的Memory Cell以及上一個時步的Hidden Layer的Output。
### Multiple-layer LSTM
![](https://i.imgur.com/96ms9co.png)
Keras中有LSTM的Module可以直接使用,不用過於擔心。(LSTM, GRU, SimpleRNN)
GRU少了一個Gate,但少了1/3的參數,效能與LSTM差不了多少。