LSTM和GRU都是由torch.nn
提供
通过观察文档,可知LSMT的参数,
torch.nn.LSTM(input_size,hidden_size,num_layers,batch_first,dropout,bidirectional)
input_size
:输入数据的形状,即embedding_dimhidden_size
:隐藏层神经元的数量,即每一层有多少个LSTM单元num_layer
:即RNN的中LSTM单元的层数batch_first
:默认值为False,输入的数据需要[seq_len,batch,feature]
,如果为True,则为[batch,seq_len,feature]
dropout
:dropout的比例,默认值为0。dropout是一种训练过程中让部分参数随机失活的一种方式,能够提高训练速度,同时能够解决过拟合的问题。这里是在LSTM的最后一层,对每个输出进行dropoutbidirectional
:是否使用双向LSTM,默认是False实例化LSTM对象之后,不仅需要传入数据,还需要前一次的h_0(前一次的隐藏状态)和c_0(前一次memory)
即:lstm(input,(h_0,c_0))
实例化LSTM(input_size=embedding_dim,hidden_size=lstm单元的个数,num_layer=层数(默认就是1层), batch_first=输入中batch_size是否在第一个维度)
LSTM的默认输出为output, (h_n, c_n)
output
:(seq_len, batch, num_directions * hidden_size)
—>batch_first=Falseh_n
:(num_layers * num_directions, batch, hidden_size)
c_n
: (num_layers * num_directions, batch, hidden_size)
seq_len
就是时间步
output
就是把每个时间步上的结果在seq_len
这一个维度上进行拼接
h_n
就是把不同层的隐藏状态在num_layers * num_directions维度上进行拼接
import torch
import torch.nn as nn
batch_size = 10
seq_len = 20 # 句子长度 即时间步
vocab_size = 100 # 词典的数量
embedding_dim = 30 # embedding维度
hidden_size = 18
num_layers = 2
input = torch.randint(low=0, high=100, size=[batch_size, seq_len])
embedding = nn.Embedding(vocab_size, embedding_dim)
embeded_input = embedding(input)# [10, 20, 30]
# 实例化LSTM
lstm = nn.LSTM(input_size=embedding_dim, hidden_size=hidden_size, num_layers=num_layers, batch_first=True)
# 获得LSTM的输出
output, (h_n, c_n) = lstm(embeded_input)
# print(output.size()) #[10, 20, 18]
# print("*" * 100)
# print(h_n.size()) #[1*2, 10, 18]
# print("*" * 100)
# print(c_n.size()) #[1*2, 10, 18]
# print("*" * 100)
# 获取最后一个时间步上的输出,该输出和最后一个隐层输出是一致的
last_output = output[:, -1, :]
last_hidden_state = h_n[-1, :, :]
#print(last_output == last_hidden_state)
# GRU使用示例
gru = nn.GRU(input_size=embedding_dim, hidden_size=hidden_size, num_layers=num_layers)
output, h_n = gru(embeded_input)
# print(output.size())# [10, 20, 18]
# print("*" * 100)
# print(h_n.size())# [2, 20, 18]
# print("*" * 100)
#双向LSTM
#转化数据为batch_first=False
embeded_input = embeded_input.permute(1, 0, 2)# [20, 10, 30]
# 双向LSTM则第0个维度需要设置为num_layer * 2
h_0 = torch.rand(num_layers * 2, batch_size, hidden_size)
c_0 = torch.rand(num_layers * 2, batch_size, hidden_size)
lstm = torch.nn.LSTM(embedding_dim,hidden_size,num_layers,bidirectional=True)
output, (h_1, c_1) = lstm(embeded_input, (h_0, c_0))
# print(output.size()) #[20, 10, 36]
# print("*" * 100)
# print(h_1.size()) #[2*2, 10, 18]
# print("*" * 100)
# print(c_1.size()) #[2*2, 10, 18]
# print("*" * 100)
在单向LSTM中,最后一个time step的输出的前hidden_size个和最后一层隐藏状态h_1的输出相同,那么双向LSTM呢?
双向LSTM中:
output:按照正反计算的结果顺序在第2个维度进行拼接,正向第一个拼接反向的最后一个输出
hidden state:按照得到的结果在第0个维度进行拼接,正向第一个之后接着是反向第一个
前向的LSTM中,最后一个time step的输出的前hidden_size个和最后一层向前传播h_1的输出相同
示例:
#-1是前向LSTM的最后一个,前18是前hidden_size个
In [188]: a = output[-1,:,:18] #前项LSTM中最后一个time step的output
In [189]: b = h_1[-2,:,:] #倒数第二个为前向
In [190]: a.size()
Out[190]: torch.Size([10, 18])
In [191]: b.size()
Out[191]: torch.Size([10, 18])
In [192]: a == b
Out[192]:
tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
dtype=torch.uint8)
后向LSTM中,最后一个time step的输出的后hidden_size个和最后一层后向传播的h_1的输出相同
示例
#0 是反向LSTM的最后一个,后18是后hidden_size个
In [196]: c = output[0,:,18:] #后向LSTM中的最后一个输出
In [197]: d = h_1[-1,:,:] #后向LSTM中的最后一个隐藏层状态
In [198]: c == d
Out[198]:
tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
dtype=torch.uint8)
[batch, num_directions*hidden_size]
。
output[-1] or output[-1,:,:]
可以获取最后一维output[:,-1,:]
可以获取最后一维(seq_len, batch_size, num_directions * hidden_size)
,需要把它转化为(batch_size,seq_len, num_directions * hidden_size)
的形状,不能够不是view等变形的方法,需要使用output.permute(1,0,2)
,即交换0和1轴,实现上述效果torch.cat([h_1[-2,:,:],h_1[-1,:,:]],dim=-1)
[batch_size,hidden_size*2]