一、pytorch中LSTM实现原理:
对于输入序列中的每个元素,每层计算以下函数:
i
t
=
σ
(
W
i
i
x
t
+
b
i
i
+
W
h
i
h
t
−
1
+
b
h
i
)
i_t = \sigma(W_{ii}x_t + b_{ii} + W_{hi}h_{t-1}+b_{hi})
it=σ(Wiixt+bii+Whiht−1+bhi)
f
t
=
σ
(
W
i
f
x
t
+
b
i
f
+
W
h
f
h
t
−
1
+
b
h
f
)
f_t = \sigma(W_{if}x_t + b_{if} + W_{hf}h_{t-1}+b_{hf})
ft=σ(Wifxt+bif+Whfht−1+bhf)
o
t
=
σ
(
W
i
o
x
t
+
b
i
o
+
W
h
o
h
t
−
1
+
b
h
o
)
o_t = \sigma(W_{io}x_t + b_{io} + W_{ho}h_{t-1}+b_{ho})
ot=σ(Wioxt+bio+Whoht−1+bho)
g
t
=
t
a
n
h
(
W
i
g
x
t
+
b
i
g
+
W
h
g
h
t
−
1
+
b
h
g
)
g_t=tanh(W_{ig}x_t + b_{ig} + W_{hg}h_{t-1} + b_{hg})
gt=tanh(Wigxt+big+Whght−1+bhg)
c
t
=
f
t
⊙
c
t
−
1
+
i
t
⊙
g
t
c_t=f_t \odot c_{t-1} + i_t \odot g_t
ct=ft⊙ct−1+it⊙gt
h
t
=
o
t
⊙
t
a
n
h
(
c
t
)
h_t = o_t \odot tanh(c_t)
ht=ot⊙tanh(ct)
其中各个变量的含义如下:
- h t h_t ht:表示在t时间步的hidden state
- c t c_t ct:表示在t时间步的cell state
- x t x_t xt:表示在t时间步的输入
- h t − 1 h_{t-1} ht−1:表示在上个时间步的hidden state 或者在初始时间步的hidden state
- i t i_t it, f t f_t ft, o t o_t ot表示输入门,遗忘门,输出门
- σ \sigma σ:表示sigmoid函数
-
⊙
\odot
⊙:表示点积
在多层LSTM中, 第 l l l层的输入 x t ( l ) x_t^{(l)} xt(l)( l l l>=2)来自于前一层对应时间步的hidden state做dorpout的结果。
二、参数
1. 初始化参数
- input_size:输入x的 维度
- hidden_size:hidden state 的维度
- num_layers:LSTM堆叠层数,设置num_layers=2 的话,表示堆叠两层LSTM到一起,第二个 LSTM 接收第一个 LSTM 的输出并计算最终结果;默认为1
- bias:如果是False,将不再加入 b_h和b_hh,默认为True
- batch_first:如果为True,则输入和输出的tensors的维度为(batch,seq,feature)而不是(seq,batch,feature)。注意:此标识只对output有效,对hidden state 和 cell state无效,默认为False
- dorpout:如果为非0,在每个 LSTM 层(最后一层除外)的输出上引入一个dropout层,dropout概率等于此参数值。默认值:0,只对多层LSTM有效。
- bidirectional:如果为True,则是双向LSTM,默认为False
- proj_size:如果>0,将使用具有相应大小的投影的 LSTM。
2. forward入参
- Input:单个样本(unbatched)输入,则形状为 ( L , H i n ) (L, H_{in}) (L,Hin);batch_first=False,则形状为 ( L , N , H i n ) (L,N,H_{in}) (L,N,Hin);batch_first=True,则形状为 ( N , L , H i n ) (N,L,H_{in}) (N,L,Hin)。输入也可以是打包的可变长度序列。参考packedtorch.nn.utils.rnn.pack_padded_sequence() h或者torch.nn.utils.rnn.pack_sequence() 方法。
- h_0:单个样本(unbatched)输入,形状为 ( D ∗ n u m l a y e r s , H o u t ) (D*num_layers, H_out) (D∗numlayers,Hout);batch样本输入,则形状为 ( D ∗ n u m l a y e r s , N , H o u t ) (D*num_layers, N, H_out) (D∗numlayers,N,Hout)也就是初始化的hidden state, 默认为0(h_0, c_0)。
- c_0:单个样本(unbatched)输入,形状为
(
D
∗
n
u
m
l
a
y
e
r
s
,
H
c
e
l
l
)
(D*num_layers, H_cell)
(D∗numlayers,Hcell);batch样本输入,则形状为
(
D
∗
n
u
m
l
a
y
e
r
s
,
N
,
H
c
e
l
l
)
(D*num_layers, N, H_cell)
(D∗numlayers,N,Hcell)也就是初始化的hidden state, 默认为0(h_0, c_0)。
其中: - N=batch size
- L=sequence length
- D=2 if bidirectional=True otherwise 1
- H i n H_{in} Hin=input_size
- H c e l l H_{cell} Hcell=hidden_size
- H o u t H_{out} Hout=hidden_size
3. 输出
- output:单个样本(unbatched)输入,则形状为 ( L , D ∗ H o u t ) (L, D*H_{out}) (L,D∗Hout);batch_first=False,则形状为 ( L , N , D ∗ H o u t ) (L,N,D*H_{out}) (L,N,D∗Hout);batch_first=True,则形状为 ( N , L , D ∗ H o u t ) (N,L,D*H_{out}) (N,L,D∗Hout)。输入也可以是打包的可变长度序列。参考packedtorch.nn.utils.rnn.pack_padded_sequence() h或者torch.nn.utils.rnn.pack_sequence() 方法。
- h_0:单个样本(unbatched)输入,形状为 ( D ∗ n u m l a y e r s , H o u t ) (D*num_layers, H_out) (D∗numlayers,Hout);batch样本输入,则形状为 ( D ∗ n u m l a y e r s , N , H o u t ) (D*num_layers, N, H_out) (D∗numlayers,N,Hout),包含序列中每个元素的最终隐藏状态。当双向 = True 时,h_n将分别包含最终正向和反向隐藏状态的串联。
- c_0:单个样本(unbatched)输入,形状为 ( D ∗ n u m l a y e r s , H c e l l ) (D*num_layers, H_cell) (D∗numlayers,Hcell);batch样本输入,则形状为 ( D ∗ n u m l a y e r s , N , H c e l l ) (D*num_layers, N, H_cell) (D∗numlayers,N,Hcell),包含序列中每个元素的最终cell状态。
三、实例
1)
import torch.nn as nn
import torch
rnn = nn.LSTM(10, 20, 2)# embedding_size, hidden_size, num_layer
input = torch.randn(5, 3, 10)# sequence length, batch size, embedding_size
h0 = torch.randn(2, 3, 20)# num_layer*dirc, batch size, hidden_size
c0 = torch.randn(2, 3, 20)# num_layer*dirc, batch size, hidden_size
output, (hn, cn) = rnn(input, (h0, c0))
output.shape
Out[8]: torch.Size([5, 3, 20])# # sequence length, batch size, hidden_size
hn.shape
Out[9]: torch.Size([2, 3, 20])# num_layer*dirc, batch size, hidden_size
c0.shape
Out[10]: torch.Size([2, 3, 20])# num_layer*dirc, batch size, hidden_size
2)
rnn = nn.LSTM(input_size=1, hidden_size=20, num_layers=2)
input = torch.tensor([[1,2,0], [3,0,0], [4,5,6]], dtype=torch.float)
lens = [2, 1, 3]
# 构建输入数据,维度为:torch.Size([3, 3, 1]), 即 bactch_size=3, sequence length=3, embedding size=1
input = input.unsqueeze(2)
input
Out[68]:
tensor([[[1.],
[2.],
[0.]],
[[3.],
[0.],
[0.]],
[[4.],
[5.],
[6.]]])
# 第一维是 batch,则batch_first=True,
padded_seq = pack_padded_sequence(input, lens, batch_first=True, enforce_sorted=False)
# 将 padded_seq输入,并且不对hidden和cell进行初始化
output, (hn, cn) = rnn(padded_seq)
# 进行逆操作拆箱
output = pad_packed_sequence(output, batch_first=True)
# output[0] LSTM输出,output[1]为batch中样本长度
output[0].shape
Out[72]: torch.Size([3, 3, 20])
output[1]
Out[73]: tensor([2, 1, 3])
hn.shape
Out[76]: torch.Size([2, 3, 20])
cn.shape
Out[77]: torch.Size([2, 3, 20])
未完待续。。。