Keras中的stateful LSTM可以说是所有学习者的梦魇,令人混淆的机制,说明不到位的文档,中文资料的匮乏。
通过此文,旨在帮助有困惑的人理解statefulness这一状态。
警告: 永远不要在不熟悉stateful LSTM的情况下使用它
参考目录:
- 官方文档
- Stateful LSTM in Keras (必读圣经)
- 案例灵感来自此GitHub
- Stateful and Stateless LSTM for Time Series Forecasting with Python (这篇可以看完本文再看)
官方文档简介
stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
使 RNN 具有状态意味着每批样品的状态将被重新用作下一批样品的初始状态。
注意,此处的状态表示的是原论文公式里的c,h,即LSTM特有的一些记忆参数,并非w权重。
当使用有状态 RNN 时,假定:
- 所有的批次都有相同数量的样本
- 如果
x1
和x2
是连续批次的样本,则x2[i]
是x1[i]
的后续序列,对于每个i
。
要在 RNN 中使用状态,你需要:
- 通过将
batch_size
参数传递给模型的第一层来显式指定你正在使用的批大小。例如,对于 10 个时间步长的 32 样本的batch
,每个时间步长具有 16 个特征,batch_size = 32
。 - 在 RNN 层中设置
stateful = True
。 - 在调用
fit()
时指定shuffle = False
。
重置累积状态:
- 使用
model.reset_states()
来重置模型中所有层的状态 - 使用
layer.reset_states()
来重置指定有状态 RNN 层的状态
疑问解答:
将一个很长的序列(例如时间序列)分成小序列来构建我的输入矩阵。那LSTM网络会发现我这些小序列之间的关联依赖吗?
不会,除非你使用 stateful LSTM 。大多数问题使用stateless LSTM即可解决,所以如果你想使用stateful LSTM,请确保自己是真的需要它。在stateless时,长期记忆网络并不意味着你的LSTM将记住之前batch
的内容。在Keras中stateless LSTM中的stateless指的是?
注意,此文所说的stateful是指的在Keras中特有的,是batch之间的记忆cell状态传递。而非说的是LSTM论文模型中表示那些记忆门,遗忘门,c,h
等等在同一sequence
中不同timesteps
时间步之间的状态传递。
假定我们的输入X
是一个三维矩阵,shape = (nb_samples, timesteps, input_dim)
,每一个row
代表一个sample
,每个sample
都是一个sequence
小序列。X[i]
表示输入矩阵中第i
个sample
。步长啥的我们先不用管。
当我们在默认状态stateless
下,Keras会在训练每个sequence小序列(=sample)开始时,将LSTM网络中的记忆状态参数reset初始化(指的是c,h
而并非权重w
),即调用model.reset_states()
。为啥stateless LSTM每次训练都要初始化记忆参数?
因为Keras在训练时会默认地shuffle samples
,所以导致sequence
之间的依赖性消失,sample
和sample
之间就没有时序关系,顺序被打乱,这时记忆参数在batch
、小序列之间进行传递就没意义了,所以Keras要把记忆参数初始化。那stateful LSTM到底怎么传递记忆参数?
首先要明确一点,LSTM作为有记忆的网络,它的有记忆指的是在一个sequence中,记忆在不同的timesteps中传播。举个例子,就是你有一篇文章X,分解,然后把每个句子作为一个sample训练对象(sequence),X[i]就代表一句话,而一句话里的每个word各自代表一个timestep时间步,LSTM的有记忆即指的是在一句话里,X[i][0]
第一个单词(时间步)的信息可以被记忆,传递到第5个单词(时间步)X[i][5]
中。
而我们突然觉得,这还远远不够,因为句子和句子之间没有任何的记忆啊,假设文章一共1000句话,我们想预测出第1001句是什么,不想丢弃前1000句里的一些时序性特征(stateless时这1000句训练时会被打乱,时序性特征丢失)。那么,stateful LSTM就可以做到。
在stateful = True
时,我们要在fit中手动使得shuffle = False
。随后,在X[i]
(表示输入矩阵中第i
个sample
)这个小序列训练完之后,Keras会将将训练完的记忆参数传递给X[i+bs]
(表示第i+bs个sample),作为其初始的记忆参数。bs = batch_size
。这样一来,我们的记忆参数就能顺利地在sample
和sample
之间传递,X[i+n*bs]
也能知道X[i]
的信息。
用图片可以更好地展示,如下图,蓝色箭头就代表了记忆参数的传递,如果
stateful = False
,则没有这些蓝色箭头。
stateful LSTM中为何一定要提供batch_size参数?
我们可以发现,记忆参数(state)是在每个batch
对应的位置跳跃着传播的,所以batch_size
参数至关重要,在stateful lstm层中必须提供。那stateful时,对权重参数w有影响吗?
我们上面所说的一切记忆参数都是LSTM模型的特有记忆c,h
参数,和权重参数w没有任何关系。无论是stateful还是stateless,都是在模型接受一个batch
后,计算每个sequence的输出,然后平均它们的梯度,反向传播更新所有的各种参数。
总结
如果你还是不理解,没关系,简单的说:
- stateful LSTM:能让模型学习到你输入的samples之间的时序特征,适合一些长序列的预测,哪个sample在前,那个sample在后对模型是有影响的。
- stateless LSTM:输入samples后,默认就会shuffle,可以说是每个sample独立,之间无前后关系,适合输入一些没有关系的样本。
如果你还是不理解,没关系……举个例子:
stateful LSTM:我想根据一篇1000句的文章预测第1001句,每一句是一个sample。我会选用stateful,因为这文章里的1000句是有前后关联的,是有时序的特征的,我不想丢弃这个特征。利用这个时序性能让第一句的特征传递到我们预测的第1001句。(
batch_size = 10
时)stateless LSTM:我想训练LSTM自动写诗句,我想训练1000首诗,每一首是一个sample,我会选用stateless LSTM,因为这1000首诗是独立的,不存在关联,哪怕打乱它们的顺序,对于模型训练来说也没区别。
实战
如果感兴趣,可以看看官方的example——lstm_stateful.py,个人不推荐,用例繁琐,还没画图,讲的不清楚。
本实战代码地址:GitHub
具体代码里面可以自己看,我就不多说细节了,这里主要来展示下结果。
目标:
很简单,就是用LSTM去预测一个cos曲线。-
训练集:
训练集如下图:
生产训练集数据:
类似滑动窗口,假设我们有1000组数据,若滑动窗口大小为20,则第i
组数据trainX =Y[i:i+20]
, trainY =Y[i+20]
,一共980组训练数据。-
普通多层神经网络预测结果:
-
stateless LSTM预测结果:
-
单层Stateful LSTM预测结果:
-
双层stacked Stateful LSTM预测结果:
- 注意:训练存在不稳定性,若预测结果偏差过大,请重新训练。另外,不要迷信GPU,LSTM用CPU训练效率可能更高。