深入理解Keras LSTM的stateful

Python07

深入理解Keras LSTM的stateful,第1张

一、参考目录:

官方文档

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

有点绕,我给翻译翻译

假设Timestep=5,batch_size=2

X1和X2就是连续的两个批次,X2[i]是X1[i]的后续序列,也就是说,床前明月光后面是疑是地上霜

光的状态会传递到疑作为初始状态,也就是用光输出的(h, c)来初始化疑的(h, c)

那就不难理解为什么“所有的批次都有相同数量的样本”,如果不同批次的样本数不同,那上一批次传过来的(h, c)将没人接手

进而,Keras文档说用stateful需要指定batch_size也没毛病,不指定的话,Keras默认容忍最后一个批次样本数不同。例如,samples=9,batch_szie=2,那么默认分成5批,最后一批只有1个样本

下一个问题,shuffle

shuffle = True会在每个epoch开始之前打乱 训练集 数据顺序,使用stateful LSTM肯定要设置shuffle = False,不然光可能传给汗不就乱套了

三、疑问解答:

将一个很长的序列(例如时间序列)分成小序列来构建我的输入矩阵。那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首诗是独立的,不存在关联,哪怕打乱它们的顺序,对于模型训练来说也没区别。

RNN模型的基础结构是单元,其中比较常见的有LSTM单元,GRU单元等,它们充当了RNN模型中的基础结构部分。使用单元搭建出来的RNN模型会有更好的拟合效果。

LSTM单元与GRU单元是RNN模型中最常见的单元,其内容由输入门、忘记门、和输出门三种结构组合而成。

LSTM单元与GRU单元的作用几乎相同,唯一不同的是:

相比之下,使用GRU单元会更加简单。

QRNN(Quasi-Recurrent Neural Networks) 单元是一种RNN模型的基础单元,它比LSTM单元速度更快。

QRNN单元发表于2016年。它使用卷积操作替代传统的循环结构,其网络结构介于RNN与CNN之间。

QRNN内部的卷积结构可以将序列数据以矩阵方式同时运算,不再像循环结构那样必须按照序列顺序依次计算。其以并行的运算方式取代了串行,提升了运算速度。在训练时,卷积结构也要比循环结构的效果更加稳定。

在实际应用中,QRNN 单元可以与RNN模型中的现有单元随意替换。

了解更多,可以参考论文:

Quasi-Recurrent Neural Networks

SRU单元是RNN模型的基础单元,它的作用与QRNN单元类似,也是对LSTM单元在速度方面进行了提升。

LSTM单元必须要将样本按照序列顺序一个个地进行运算,才能够输出结果。这种运算方式使得单元无法在多台机器并行计算的环境中发挥最大的作用。

SRU单元被发表于2017年。它保留LSTM单元的循环结构,通过调整运算先后顺序的方式(把矩阵乘法放在串行循环外,把相乘的再相加的运算放在串行循环内)提升了运算速度。

若需要研究SRU单元更深层次理论,可以参考如下论文:

Simple Recurrent Units for Highly Parallelizable Recurrence

关于函数tf.contrib.rnn.SRUCell 的更多使用方法,可以参照官方帮助文档。

https://www.tensorflow.org/api_docs/python/tf/contrib/rnn/SRUCell

注:需要科学上网

github可以参考:

https://github.com/tensorflow/tensorflow/blob/r1.15/tensorflow/contrib/rnn/python/ops/rnn_cell.py#L2738-L2816

顾名思义,时间序列数据是一种随时间变化的数据类型。例如,24小时内的温度,一个月内各种产品的价格,一年中特定公司的股票价格。诸如长期短期记忆网络(LSTM)之类的高级深度学习模型能够捕获时间序列数据中的模式,因此可用于对数据的未来趋势进行预测。在本文中,您将看到如何使用LSTM算法使用时间序列数据进行将来的预测。