近几天处理了几天卷积LSTM,操作的数据格式太复杂,蓦然回首,突然发现自己不明白LSTM中的输入格式是什么了,于是写一篇文章帮助自己回忆一下,也希望能帮助到一起正在机器学习的伙伴。补充一下,在LSTM之后,GRU和LSTM几乎已经取代了传统的RNN,因此在称呼RNN的时候,大多数情况也是在称呼LSTM,下文中可能会提到RNN,也是在说LSTM
按照Pytorch 给的文档里格式写一个LSTM
# author: https://www.cnblogs.com/danielkung/
lstm = torch.nn.LSTM(input_size, # INT,输入的维度
hidden_size, # INT,隐藏层的维度
num_layers, # INT,LSTM的层数
bias, # BOOL,是否需要wx+b中的b
batch_first, # BOOL,输入的数据第一维度为batch,与输出无关
dropout, # BOOL,是否需要dropout
bidirectional) # BOOL,是否双向RNN,是的话hidden,output都双倍
intput = torch.randn(seq_len, batch, input_size) # 三个参数需要定义
output, hidden = lstm(input)
Q:在处理了无数次以后,我终于有一次懵圈了,啥是seq_len来着?
A:seq_len就是输入的sequence_length(序列长度),既然LSTM是处理序列数据的,那么序列就需要一个长度。虽然LSTM处理的序列长度通常是不固定的,但是Pytorch和TensorFlow的集成实现还是固定了input的序列长度,在处理不固定长度的数据(如机器翻译),通常加入开始和结束符号
来看几个实际的例子:
1. 输入长度不固定,输出长度固定
我想做一个语句的情感分析(positve,negtive),或者给一串数字,预测这串数字的下一个数字是什么(例如某串长度为N,预测第N+1数字是什么)。
在第一个问题中,假设我们拿到了N条数据,每条包含的字数不定,但是可以知道最长的字数为MAX_LEN。首先我们需要进行word embedding,即把每个词转变为长度固定的矩阵。假如每个word被转化为 [1*128] 的矩阵,那我们得到的数据格式就为:
[N, MAX_LEN+2, 128]
此时你也许会问,那长度不够MAX_LEN的呢?不够的就被填充到MAX_LEN,并且多的2是开头和结尾的'sos''eos'。
然后在LSTM中,我们每次取N条中的batch_size条进行训练,并且input的seq_len就是MAX_LEN+2。代码:
# author: https://www.cnblogs.com/danielkung/
import torch
input_size = 128 # 输入的维度,就是我们word_embedding的长度
hidden_size = 64 # 这里我自己定义的,定义的是lstm的hidden也是输出的维度
num_layers = 1 # 先定义一层的LSTM
lstm = torch.nn.LSTM(input_size, hidden_size, num_layers)
input = getFromDataSet() # 函数没定义,就是从data中取batch条数据,input的shape:[seq_len, batch_size, input_size]=[MAX_LEN+2, batch, 128]
output, hidden = lstm(input, hidden=None) # Pytorch的LSTM会自己初始化hidden,因此hidden不写一样
output1 = output[-1] # 取最后一层的输出作为最终输出,因为只有一层LSTM,output[-1]==output[0]
print(output.shape)
# RETURN: [seq_len, batch_size, hidden_size]
这里发现如果是做postive或者negtive分析的话,我们只需要一个数值,甚至只需要一个BOOL,因此还需要把输出的output结果取最后一份output[-1],然后通过MLP即可,具体分析如图。
代码接上面继续:
fc = nn.Linear(hidden_size, 1)
last_cell = outpu1t[-1] # shape: [batch_size, hidden_size]
# 由图可见, 此时的last_cell就是LSTM的最后一次的输出结果。
res = fc(last_cell) # shape: [batch_size, 1]
# 由此就得出了所有所有batch的预测结果。
Q:可能有人要问,输出了那么多的output,只取最后一个用,这样准确吗?不浪费吗?
A:不准,浪费。但是可以这么处理。在早期的sequence_to_sequence模型中,就是把encoder RNN的最后一个cell的输出作为context传给decoder,当然后来还有更好的办法,如attention mechanism。在这里只展示最简单的。
2. 输入长度不固定,输出长度不固定
如果输出长度不固定,我们只需要把<1>中输出中加入'sos''eos',并且去掉最后的全连接层就好了。
3. 特殊情况,seq_len的长度特别大
这类问题通常出现在文本翻译或者文本处理,以及音频、视频处理中。我们需要把seq_len设置为一个适当的值,并且通过迭代,传递lstm的hidden_state的方式进行训练。这对模型的设计,网络的深度都有一定的要求,博客中就不在展示。
在相关领域已经有很多优秀的论文发表。
author:danielKKK