之前在学习RNN的时候,总是零零散散的搜一些东西。这次想要将关于RNN的知识总结起来,包括各种RNN网络的结构、输入输出以及pytorch代码实现。
我们首先介绍单向RNN网络的结构,如下图所示。时间步 i i i 的输入为: x i x_i xi和 s i − 1 s_{i-1} si−1,输出是 y i y_i yi和 s i s_i si。这里我们统一使用 s s s 代表隐藏层状态表示, y y y 则表示模型输出值。那么,单个神经元的运算为: ( y t , s t ) = f t ( x t , s t − 1 ) (y_t, s_t) = f_t(x_t, s_{t-1}) (yt,st)=ft(xt,st−1)。其中, f t f_t ft 表示的该层的第 t t t 个神经元中的运算。
在上面介绍的基础上,接下来,会介绍三种RNN网络,分别是Vanilla RNN(即简单RNN),GRU,LSTM。对于这三种网络,我会从单个神经元、单层以及多层的方面展开介绍。因为Vanilla RNN和GRU的结构上是一样的,只是内部计算不同,所以这里将这两个放在一起介绍
首先给出简单RNN/ GRU的单层和多层的网络结构,这里从单个神经元进行分析。网络结构图如下:
简介中我们用 s t s_t st表示隐层状态, y t y_t yt表示 t t t 时刻输出。那么,单层Vanilla RNN / GRU的隐层状态和输出就是: s t = h t s_t = h_t st=ht, y t = h t y_t = h_t yt=ht。可以看出,Vanilla RNN / GRU的隐层状态和该时刻的输出是一样的。
对于多层Vanilla RNN / GRU来说,隐层状态和输出分别为: s t = ( h t − 1 ( 1 ) , h t − 1 ( 2 ) , ⋯ , h t − 1 ( l ) ) s_t = (h_{t-1}^{(1)}, h_{t-1}^{(2)}, \cdots, h_{t-1}^{(l)}) st=(ht−1(1),ht−1(2),⋯,ht−1(l)), y t = h t ( l ) y_t = h_t^{(l)} yt=ht(l)。中间层的输出 h t ( i ) h_{t}^{(i)} ht(i)直接用于下一层的输入,不会被直接输出出来。
首先给出单层和多层LSTM的结构图,可以看出,相比Vanilla RNN和GRU,LSTM多了一个 c t − 1 c_{t-1} ct−1的输入,这个表示cell的状态。
在单层LSTM中,隐层状态和输出分别对应于: s t = ( h t , c t ) s_t = (h_t, c_t) st=(ht,ct), y t = h t y_t = h_t yt=ht。
在多层LSTM中,隐层状态和输出分别对应于: s t = ( ( h t ( 1 ) , c t ( 1 ) ) , ( h t ( 2 ) , c t ( 2 ) ) , ⋯ , ( h t ( l ) , c t ( l ) ) ) s_t = ((h_t^{(1)}, c_t^{(1)}), (h_t^{(2)}, c_t^{(2)}), \cdots, (h_t^{(l)}, c_t^{(l)})) st=((ht(1),ct(1)),(ht(2),ct(2)),⋯,(ht(l),ct(l))), y t = h t ( l ) y_t = h_t^{(l)} yt=ht(l)。
双向RNN就相当于在上面所讲单向RNN基础之上,再增加一层方向的相同结构网络。图示如下:
双向RNN就会出现两个输出,分别为 y t → \overrightarrow{y_t} yt和 y t ← \overleftarrow{y_t} yt,通常这两个输出会concat在一起,作为整体输出。
知道了单向和双向RNN的结构之后,我们就来看看pytorch里怎样实现这样的网络,这里以LSTM为例,GRU类似,只是输入和输出的不同。
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])
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])
学会区分RNN的output和state
lstm理解与使用(pytorch为例)