1. 程式人生 > >簡易理解RNN與LSTM

簡易理解RNN與LSTM

總說

這篇主要是如何一步步說明RNN和LSTM的形式的構造,方便對模型有一個更直觀的理解。寫的比較隨意。

RNN

我們知道,卷積是一個輸入,得到一個輸出。但有時候我們想輸出一串,然後得到一串輸出呢?並且是這一串都是相互有關聯的,比如句子翻譯。我們就需要一種能針對歷史資訊進行融合的單元,比如RNN。其實想想,只要以某種形式,將歷史資訊與當前輸入進行有效融合的方式,應該都可以處理類似的問題。

和CNN的區別是,RNN有一個隱層狀態ht,這個狀態必須將歷史的輸入x1,x2,...,xt1和當前的輸入xt進行融合。 由於我們RNN是一個迭代的過程,對於第t次,輸入只有xt,那歷史的輸入怎麼辦呢?這就要用到“歷史資訊”,也就是t

1時刻的隱層狀態ht1。這個歷史資訊只要和歷史輸入掛鉤就行。

比如第一次,我們先設定一個h0,那麼h1應該是x1h0的融合。嗯,沒錯。這樣一來,h2應該是x2h1的融合。此時h2的得到不僅融合了歷史輸入x1還結合了當前輸入x2

我們通過增加了一個隱層狀態,從而使得RNN能夠將當前輸入與歷史輸入進行有效的融合。隱層狀態是歷史資訊的載體。

對於每次新的輸入xt必須要和已有的隱層狀態ht1(就是下左圖的中間一行的第一個結點的狀態)進行融合的。融合方式很簡單,我們只需要對ht1xt分別進行一個變換,好讓其輸入的維度等於ht的維度就行。所以就有W1W2,分別表示對當前的輸入xt以及歷史輸入的一個“取捨程度”。

RNN還要有輸出,既然是迭代的,顯然對於第t次迭代,就會有y^t輸出。我們不能直接把ht輸出吧,為了增加複雜性,乘以一個權重W3吧,用於表示對當前隱層狀態ht的一個“取捨”。
所以自然就有下面:

ht=tanh(W1ht1+W2xt)
y¯=W3ht
這裡寫圖片描述

值得注意的是,這幅圖左邊是展開形式。那麼要定義給一個RNN,我們當然要定義這個t最大是多少。比如我們希望t最多迭代3次。那麼我們就有h1, h2h3, 就相當於有3個隱層神經元。因此RNN最多迭代次數就是我們所說的time step的最大值,也是recurrent layer的數目。

看看pytorch的對應函式,emmm,沒啥問題。預設的隱層啟用函式是tanh, 也可以選擇 relu.
這裡寫圖片描述

num_layers是什麼?
是RNN有多少層,前面看到的都是一層的RNN。比如很經典的預測下一個字母:
輸入是one-hot形式的4*1向量,紅色層是輸入層。隱層淺綠色,狀態是3*1。因此Wxh應該是3*4的矩陣。輸出是淺藍色部分,大小是4*1的。所以Why是4*3的矩陣。隱層time step的迭代顯然是3*3的方陣Whh

這裡寫圖片描述

前面的例子都是,輸入經過經過一次線性變換,成為隱層狀態,再經過一次線性變換,直接變成輸出了。為了增加複雜性,可以讓隱層狀態經過多次線性變換,再到輸出。這就是多層RNN
下面是3層的(綠色代表深度為3的隱層,紅色是輸入層,藍色是輸出層)
這裡寫圖片描述

BPTT

反向傳播的梯度推導如下,看看就行。

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

顯然容易出現梯度爆炸或者梯度消失的現象。對於梯度爆炸,直接梯度裁剪就行。但是梯度消失,就不好弄了,你不可能直接乘以一個數吧~~。

如何解決RNN的梯度消失問題

看看原來咋弄的:

ht=tanh(W1ht1+W2xt)
原來的當前隱層狀態的得到,是直接將當前輸入和上一次迭代的隱層狀態,進行簡單融合。那麼求導時,自然就會有連乘形式,那就容易爆炸或是消失啊!要不轉換成“連加”吧

ut=tanh(W1ht1+W2xt)
ht=ht1+ut

現在是,上一次迭代的隱層狀態和當前的輸入,融合後的