python在Keras中使用LSTM解决序列问题

时间序列预测是指我们必须根据时间相关的输入来预测结果的问题类型。时间序列数据的典型示例是股市数据,其中股价随时间变化。 

由Kaizong Ye,Coin Ge撰写

时间序列预测是指我们必须根据时间相关的输入来预测结果的问题类型。时间序列数据的典型示例是股市数据,其中股价随时间变化。 

递归神经网络(RNN)已被证明可以有效解决序列问题。特别地,作为RNN的变体的长期短期记忆网络(LSTM)当前正在各种领域中用于解决序列问题。

序列问题的类型

序列问题可以大致分为以下几类:

  1. 一对一:其中有一个输入和一个输出。一对一序列问题的典型示例是您拥有一幅图像并且想要为该图像预测单个标签的情况。
  2. 多对一:在多对一序列问题中,我们将数据序列作为输入,并且必须预测单个输出。文本分类是多对一序列问题的主要示例,其中我们有一个单词输入序列,并且我们希望预测一个输出标签。
  3. 一对多:在一对多序列问题中,我们只有一个输入和一个输出序列。典型示例是图像及其相应的说明。
  4. 多对多:多对多序列问题涉及序列输入和序列输出。例如,将7天的股票价格作为输入,并将接下来7天的股票价格作为输出。聊天机器人还是多对多序列问题的一个示例,其中文本序列是输入,而另一个文本序列是输出。

×

神经网络通过强大的非线性拟合能力,成为最为流行的人工智能模型之一,在分类和预测任务中都有优异的表现。它通过模拟神经单元的构造和功能来设计相关的网络模型,再通过不同的连接方式搭建不同的神经网络 。

1986年Rumelhart等人提出的反向传播(BP)的前馈神经网络是最早提出的神经网络,其通过引入隐藏层来实现非线性计算;循环神经网络(RNN)则在序列相关的数据上做了改进,通过在神经网络层之间引入有向循环连接,使其具备时序数据的记忆功能 。但RNN在长期依赖的问题上,随着需要提取的依赖项的长度增加时,梯度将不会再更新,甚至出现梯度消失等现象,因此需要对RNN进行改进,以解决信息的长期依赖。

长短期记忆网络(LSTM)是RNN的一种改进网络结构,相较普通的神经网络,LSTM加入了可控门单元。LSTM结构包括输入门it、输出门ot、遗忘门ft等门结构,这些特殊的设计能够实现细胞状态Ct的更新,式(1)、(2)、(3)是3个门的更新公式。其中,σ表示激活函数,W和b分别表示权重矩阵和偏置,下标f、i、o代表遗忘门、输入门和输出门。ht − 1表示t − 1时LSTM细胞的输出,xt代表t时刻的输入。

σ  ⋅  −  ) (1)

σ  ⋅  −  ) (2)

σ  ⋅  −  ) (3)

在计算时,首先从当前时刻的输入和上一时刻隐藏层状态的信息中选择出要遗弃的部分,该部分是由遗忘门来实现的。然后由输入门决定神经单元要更新的值,通过Tanh函数更新神经单元状态。最终神经单元输出的状态由输出门决定,其先用Sigmoid层决定要输出的神经单元状态,然后将这些状态用Tanh函数压缩在−1到1之间。



 在本文中,我们将了解如何使用LSTM及其不同的变体来解决一对一和多对一的序列问题。 

阅读本文后,您将能够基于历史数据解决诸如股价预测,天气预报等问题。由于文本也是单词序列,因此本文中获得的知识也可以用于解决自然语言处理任务,例如文本分类,语言生成等。

一对一序列问题

正如我之前所说,在一对一序列问题中,只有一个输入和一个输出。在本节中,我们将看到两种类型的序列问题。首先,我们将了解如何使用单个特征解决一对一的序列问题,然后我们将了解如何使用多个特征解决一对一的序列问题。

单一特征的一对一序列问题

在本节中,我们将看到如何解决每个时间步都有一个特征的一对一序列问题。

首先,我们导入将在本文中使用的必需库:

创建数据集

在下一步中,我们将准备本节要使用的数据集。

在上面的脚本中,我们创建20个输入和20个输出。每个输入都包含一个时间步,而该时间步又包含一个特征。每个输出值是相应输入值的15倍。如果运行上面的脚本,应该看到如下所示的输入和输出值:

LSTM层的输入应为3D形状,即(样本,时间步长,特征)。样本是输入数据中样本的数量。输入中有20个样本。时间步长是每个样本的时间步长数。我们有1个时间步。最后,特征对应于每个时间步的特征数量。每个时间步都有一个特征。

通过简单LSTM解决方案

现在,我们可以创建具有一个LSTM层的简单LSTM模型。

在上面的脚本中,我们创建了一个LSTM模型,该模型具有一层包含50个神经元和relu激活函数的LSTM层。您可以看到输入形状为(1,1),因为我们的数据具有一个特征的时间步长。 

现在让我们训练模型:

我们为2000个时期训练模型,批大小为5。您可以选择任何数字。训练模型后,我们可以对新实例进行预测。

假设我们要预测输入为30的输出。实际输出应为30 x 15 =450。 首先,我们需要按照LSTM的要求将测试数据转换为正确的形状,即3D形状。以下 预测数字30的输出:

我得到的输出值437.86略小于450。

 通过堆叠LSTM解决方案

现在让我们创建一个堆叠的LSTM,看看是否可以获得更好的结果。数据集将保持不变,模型将被更改。看下面的脚本:

在上面的模型中,我们有两个LSTM层。注意,第一个LSTM层的参数return_sequences设置为True。当返回序列设置True为时,每个神经元隐藏状态的输出将用作下一个LSTM层的输入。以上模型的摘要如下:

接下来,我们需要训练我们的模型,如以下脚本所示:


python用于NLP的seq2seq模型实例:用Keras实现神经网络机器翻译

阅读文章


我得到的输出为459.85,好于我们通过单个LSTM层获得的数字437。

具有多个特征的一对一序列问题

在最后一节中,每个输入样本都有一个时间步,其中每个时间步都有一个特征。在本节中,我们将看到如何解决输入时间步长具有多个特征的一对一序列问题。

创建数据集

首先创建数据集。看下面的脚本:

在上面的脚本中,我们创建三个列表:X1X2,和Y。每个列表包含25个元素,这意味着总样本大小为25。最后,Y包含输出。X1X2以及Y列表已输出在下面:

输出列表中的每个元素基本上都是X1和 X2列表中相应元素的乘积。例如,输出列表中的第二个元素是24,这是列表中的第二个元素(X1即4)和列表中的第二个元素(X2即6 )的乘积。

输入将由X1X2列表的组合组成,其中每个列表将表示为一列。以下脚本创建最终输入:

这是输出:

可以看到它包含两列,即每个输入两个特征。如前所述,我们需要将输入转换为3维形状。我们的输入有25个样本,其中每个样本包含1个时间步,每个时间步包含2个特征。以下脚本可重塑输入。

通过简单LSTM解决方案

我们现在准备训练我们的LSTM模型。让我们首先像上一节中那样开发一个LSTM模型:

我们现在准备训练我们的LSTM模型。让我们首先像上一节中那样开发一个LSTM模型:

在这里,我们的LSTM层包含80个神经元。我们有两个神经层,其中第一层包含10个神经元,第二个密集层(也作为输出层)包含1个神经元。该模型的摘要如下:

以下脚本训练模型:

让我们在一个新的数据点上测试我们训练有素的模型。我们的数据点将具有两个特征,即(55,80)实际输出应为55 x 80 =4400。让我们看看我们的算法预测了什么。执行以下脚本:

我的输出为3263.44,与实际输出相差甚远。

通过堆叠LSTM解决方案

现在,让我们创建一个具有多个LSTM和密集层的更复杂的LSTM,看看是否可以改善我们的模型:

模型摘要如下:

下一步是训练我们的模型,并在测试数据点(即(55,80))上对其进行测试。

为了提高准确性,我们将减小批量大小,并且由于我们的模型更加复杂,现在我们还可以减少时期数。以下脚本训练LSTM模型并在测试数据点上进行预测。

在输出中,我得到的值3705.33仍小于4400,但比以前使用单个LSTM层获得的3263.44的值好得多。您可以将LSTM层,密集层,批处理大小和时期数进行不同的组合,以查看是否获得更好的结果。

多对一序列问题

在前面的部分中,我们看到了如何使用LSTM解决一对一的序列问题。在一对一序列问题中,每个样本都包含一个或多个特征的单个时间步。具有单个时间步长的数据实际上不能视为序列数据。事实证明,密集连接的神经网络在单个时间步长数据下表现更好。

实际序列数据包含多个时间步长,例如过去7天的股票市场价格,包含多个单词的句子等等。

在本节中,我们将看到如何解决多对一序列问题。在多对一序列问题中,每个输入样本具有多个时间步长,但是输出由单个元素组成。输入中的每个时间步都可以具有一个或多个特征。我们将从具有一个特征的多对一序列问题开始,然后我们将了解如何解决输入时间步长具有多个特征的多对一问题。

具有单个特征的多对一序列问题

首先创建数据集。我们的数据集将包含15个样本。每个样本将具有3个时间步长,其中每个时间步长将包含一个单一特征,即一个数字。每个样本的输出将是三个时间步长中每个步长的数字之和。例如,如果我们的样本包含序列4,5,6,则输出将为4 + 5 + 6 = 10。

创建数据集

首先创建一个从1到45的整数列表。由于我们要在数据集中获得15个样本,因此我们将对包含前45个整数的整数列表进行整形。

在输出中,您应该看到前45个整数:

我们可以使用以下函数将其重塑为样本数,时间步长和特征:

上面的脚本将列表X转换为带有15个样本,3个时间步长和1个特征的3维形状。上面的脚本还输出了调整后的数据。

我们已经将输入数据转换为正确的格式,现在让我们创建输出向量。正如我之前所说,输出中的每个元素将等于相应输入样本中时间步长中的值之和。以下脚本创建输出向量:

输出数组Y如下所示:

通过简单LSTM解决方案

现在让我们用一个LSTM层创建模型。

以下脚本训练了我们的模型:

训练完模型后,我们就可以使用它对测试数据点进行预测。让我们预测数字序列50、51、52的输出。实际输出应为50 + 51 + 52 =153。以下脚本将我们的测试点转换为3维形状,然后预测输出:

我的输出为145.96,比实际输出值153少7点。

通过堆叠LSTM解决方案

现在,让我们创建一个具有多层的复杂LSTM模型,看看是否可以获得更好的结果。执行以下脚本来创建和训练具有多个LSTM和密集层的复杂模型:

现在让我们在测试序列(即50、51、52)上测试模型:

我在这里得到的答案是155.37,比我们之前得到的145.96更好。在这种情况下,我们与153的实际差值只有2分。

通过双向LSTM解决方案

双向LSTM是一种LSTM,可以从正向和反向两个方向的输入序列中学习。最终的序列解释是向前和向后学习遍历的串联。让我们看看使用双向LSTM是否可以获得更好的结果。

以下脚本创建了一个双向LSTM模型,该模型具有一个双向层和一个作为模型输出的密集层。

以下脚本训练模型并根据测试序列50、51和52进行预测。

我得到的结果是152.26,仅比实际结果少一小部分。因此,我们可以得出结论,对于我们的数据集,具有单层的双向LSTM的性能优于单层和堆叠的单向LSTM。

具有多个特征的多对一序列问题

在多对一序列问题中,我们有一个输入,其中每个时间步均包含多个特征。输出可以是一个值或多个值,在输入时间步长中每个特征一个。我们将在本节中介绍这两种情况。

创建数据集

我们的数据集将包含15个样本。每个样本将包含3个时间步。每个时间步都有两个特征。

让我们创建两个列表。一个将包含3的倍数,直到135,即总共45个元素。第二个列表将包含5的倍数,从1到225。第二个列表也将总共包含45个元素。以下脚本创建这两个列表:

您可以在以下输出中看到列表的内容:

上面的每个列表代表时间样本中的一个特征。可以通过合并两个列表来创建聚合数据集,如下所示:

输出显示汇总的数据集:

我们需要将数据重塑为三个维度,以便LSTM可以使用它。我们的数据集中共有45行,两列。我们将数据集重塑为15个样本,3个时间步长和两个特征。

您可以在以下输出中看到15个样本:

输出还将具有对应于15个输入样本的15个值。输出中的每个值将是每个输入样本的第三时间步中两个特征值的总和。例如,第一个样本的第三时间步长具有特征9和15,因此输出将为24。类似地,第二个样本的第三时间步长中的两个特征值分别为18和30;第二个时间步长中的两个特征值分别为18和30。相应的输出将是48,依此类推。

以下脚本创建并显示输出向量:

现在让我们通过简单的,堆叠的和双向的LSTM解决多对一序列问题。

通过简单LSTM解决方案

模型经过训练。我们将创建一个测试数据点,然后将使用我们的模型对测试点进行预测。

输入的第三时间步长的两个特征的总和为14 + 61 =75。我们的带有一个LSTM层的模型预测为73.41,这非常接近。

通过堆叠LSTM解决方案

以下脚本训练堆叠的LSTM并在测试点上进行预测:

我收到的输出为71.56,比简单的LSTM差。似乎我们堆叠的LSTM过度拟合。

通过双向LSTM解决方案


随时关注您喜欢的主题


这是简单双向LSTM的训练脚本,以及用于对测试数据点进行预测的代码:

输出为76.82,非常接近75。同样,双向LSTM似乎胜过其余算法。

到目前为止,我们已经基于来自不同时间步长的多个要素值预测了单个值。在多对一序列的另一种情况下,您希望在时间步长中为每个特征预测一个值。例如,我们在本节中使用的数据集具有三个时间步,每个时间步具有两个特征。我们可能希望预测每个特征系列的单独价值。下面的示例很清楚,假设我们有以下输入:

在输出中,我们需要一个具有两个特征的时间步,如下所示:

您可以看到输出中的第一个值是第一个系列的延续,第二个值是第二个系列的延续。我们可以通过简单地将输出密集层中神经元的数量更改为我们想要的输出中特征值的数量来解决此类问题。但是,首先我们需要更新输出向量Y。输入向量将保持不变:

上面的脚本创建一个更新的输出向量并将其输出在控制台上,输出如下所示:

现在,让我们在数据集上训练我们的简单,堆叠和双向LSTM网络。以下脚本训练了一个简单的LSTM:

下一步是在测试数据点上测试我们的模型。以下脚本创建一个测试数据点:

实际输出为[29,45]。我们的模型预测[29.089157,48.469097],这非常接近。

现在让我们训练一个堆叠的LSTM并预测测试数据点的输出:

输出为[29.170143,48.688267],再次非常接近实际输出。

最后,我们可以训练双向LSTM并在测试点上进行预测:

输出为[29.2071,48.737988]。

您可以再次看到双向LSTM做出最准确的预测。

结论

简单的神经网络不适用于解决序列问题,因为在序列问题中,除了当前输入之外,我们还需要跟踪先前的输入。具有某种记忆的神经网络更适合解决序列问题。LSTM就是这样一种网络。


可下载资源

关于作者

Kaizong Ye拓端研究室(TRL)的研究员。

本文借鉴了作者最近为《R语言数据分析挖掘必知必会 》课堂做的准备。

​非常感谢您阅读本文,如需帮助请联系我们!

 
QQ在线咨询
售前咨询热线
15121130882
售后咨询热线
0571-63341498