全面理解RNN(包括GRU、LSTM)以及對應pytorch實現

之前在學習RNN的時候,總是零零散散的搜一些東西。這次想要將關於RNN的知識總結起來,包括各種RNN網絡的結構、輸入輸出以及pytorch代碼實現。

單向RNN網絡簡介

我們首先介紹單向RNN網絡的結構,如下圖所示。時間步 ii 的輸入爲:xix_isi1s_{i-1},輸出是yiy_isis_i。這裏我們統一使用 ss 代表隱藏層狀態表示,yy 則表示模型輸出值。那麼,單個神經元的運算爲:(yt,st)=ft(xt,st1)(y_t, s_t) = f_t(x_t, s_{t-1})。其中,ftf_t 表示的該層的第 tt 個神經元中的運算。
在這裏插入圖片描述
在上面介紹的基礎上,接下來,會介紹三種RNN網絡,分別是Vanilla RNN(即簡單RNN),GRU,LSTM。對於這三種網絡,我會從單個神經元、單層以及多層的方面展開介紹。因爲Vanilla RNN和GRU的結構上是一樣的,只是內部計算不同,所以這裏將這兩個放在一起介紹

Vanilla RNN / GRU 的結構

首先給出簡單RNN/ GRU的單層和多層的網絡結構,這裏從單個神經元進行分析。網絡結構圖如下:
在這裏插入圖片描述
簡介中我們用sts_t表示隱層狀態,yty_t表示 tt 時刻輸出。那麼,單層Vanilla RNN / GRU的隱層狀態和輸出就是:st=hts_t = h_tyt=hty_t = h_t。可以看出,Vanilla RNN / GRU的隱層狀態和該時刻的輸出是一樣的。

對於多層Vanilla RNN / GRU來說,隱層狀態和輸出分別爲:st=(ht1(1),ht1(2),,ht1(l))s_t = (h_{t-1}^{(1)}, h_{t-1}^{(2)}, \cdots, h_{t-1}^{(l)})yt=ht(l)y_t = h_t^{(l)}。中間層的輸出ht(i)h_{t}^{(i)}直接用於下一層的輸入,不會被直接輸出出來。

LSTM 的結構

首先給出單層和多層LSTM的結構圖,可以看出,相比Vanilla RNN和GRU,LSTM多了一個ct1c_{t-1}的輸入,這個表示cell的狀態。
在這裏插入圖片描述
在單層LSTM中,隱層狀態和輸出分別對應於:st=(ht,ct)s_t = (h_t, c_t)yt=hty_t = h_t

在多層LSTM中,隱層狀態和輸出分別對應於:st=((ht(1),ct(1)),(ht(2),ct(2)),,(ht(l),ct(l)))s_t = ((h_t^{(1)}, c_t^{(1)}), (h_t^{(2)}, c_t^{(2)}), \cdots, (h_t^{(l)}, c_t^{(l)}))yt=ht(l)y_t = h_t^{(l)}

雙向RNN網絡簡介

雙向RNN就相當於在上面所講單向RNN基礎之上,再增加一層方向的相同結構網絡。圖示如下:
在這裏插入圖片描述
雙向RNN就會出現兩個輸出,分別爲yt\overrightarrow{y_t}yt\overleftarrow{y_t},通常這兩個輸出會concat在一起,作爲整體輸出。

知道了單向和雙向RNN的結構之後,我們就來看看pytorch裏怎樣實現這樣的網絡,這裏以LSTM爲例,GRU類似,只是輸入和輸出的不同。

單向和雙向LSTM的pytorch代碼實現

單向LSTM

rnn = nn.LSTM(input_size=10, hidden_size=20, num_layers=2)#(input_size,hidden_size,num_layers)
input = torch.randn(5, 3, 10)#(seq_len, batch, input_size)
h0 = torch.randn(2, 3, 20) #(num_layers,batch,output_size)
c0 = torch.randn(2, 3, 20) #(num_layers,batch,output_size)
output, (hn, cn) = rnn(input, (h0, c0))

那麼,output和hn,cn的維度是多少呢?

output.shape #(seq_len, batch, output_size)
torch.Size([5, 3, 20])
hn.shape #(num_layers, batch, output_size)
torch.Size([2, 3, 20])
cn.shape #(num_layers, batch, output_size)
torch.Size([2, 3, 20])

雙向LSTM

rnn = nn.LSTM(input_size=10, hidden_size=20, num_layers=2,bidirectional=True)#(input_size,hidden_size,num_layers)
input = torch.randn(5, 3, 10)#(seq_len, batch, input_size)
h0 = torch.randn(4, 3, 20) #(num_layers,batch,output_size)
c0 = torch.randn(4, 3, 20) #(num_layers,batch,output_size)
output, (hn, cn) = rnn(input, (h0, c0))

output和hn,cn的維度是多少呢?

output.shape #(seq_len, batch, output_size*2)
torch.Size([5, 3, 40])
hn.shape #(num_layers*2, batch, output_size)
torch.Size([4, 3, 20])
cn.shape #(num_layers*2, batch, output_size)
torch.Size([4, 3, 20])

Reference

學會區分RNN的output和state
lstm理解與使用(pytorch爲例)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章