• 全部文章 专栏目录
  • 互动问答
  • 栈栈作者
    2019-08-26 17:13:33
    案例剖析:利用LSTM深层神经网络进行时间序列预测

    本文将重点介绍如何使用LSTM神经网络架构,使用Keras和Tensorflow提供时间序列预测,特别是在股票市场数据集上,以提供股票价格的动量指标。

    这个框架的代码可以在下面的GitHub repo中找到(它假设python版本3.5.x和requirements.txt文件中的需求版本。偏离这些版本可能会导致错误):https://github.com/jaungiers/LSTM-Neural-Network-for-Time-Series-Prediction

    什么是LSTM神经元?

    长期困扰传统神经网络架构的基本问题之一是,如何能够解释依赖于信息和上下文的输入序列。该信息可以是句子中的前一个单词,以方便通过上下文来预测下一个单词可能是什么,或者它也可以是序列的时序信息。

    简而言之,传统的神经网络每次都会采用独立的数据向量,并且没有内存概念来帮助他们处理需要内存的任务。

    早期尝试解决这个问题的方法是对网络中的神经元使用简单的反馈类型方法,其中输出被反馈到输入中,以提供后看到的输入的上下文。这些被称为递归神经网络(RNN)。虽然这些RNN在一定程度上起作用,但它们有一个相当大的缺点,因此它们的一些重要用途都会导致产生消失梯度的问题。我们不会进一步扩展讨论它,而是说由于这个问题导致RNN不适合大多数现实问题,因此,我们需要找到别的解决办法。

    这就是长期短期记忆(LSTM)神经网络起作用的地方。与RNN神经元一样,LSTM神经元在其管道中可以保持记忆,以允许解决顺序和时间问题,而不会出现影响其性能的消失梯度问题。

    许多关于它的研究论文和文章都可以在网上找到,它们在数学细节上讨论了LSTM细胞的工作原理。然而,在本文中,我们不会讨论LSTM的复杂工作原理,因为我们更关心它们的使用。

    对于上下文,下面是LSTM神经元的典型内部工作图。它由若干层和逐点操作组成,这些操作充当数据输入、输出的门,为LSTM单元状态提供信息。这种单元状态是通过网络和输入保持长期记忆和上下文。

    一个简单的正弦波示例

    为了演示LSTM神经网络在预测时间序列中的使用,让我们从基本的事情开始,我们可以想到这是一个时间序列:可靠的正弦波。让我们创建我们需要的数据,以便为LSTM网络训练此函数的许多“振荡模型”。

    代码数据文件夹中提供的数据包含我们创建的sinewave.csv文件,该文件包含5001个正弦波时间段,幅度和频率为1(角频率为6.28),时间差值为0.01。绘制时的结果如下所示:

    数据集为正弦波

    现在我们有了数据,我们实际上想要实现什么?简单的说,我们只是希望LSTM从我们将提供的数据的设定窗口大小中学习正弦波,并且希望我们可以要求LSTM预测该系列中的第N步骤,并且它将继续输出正弦波。

    我们将首先把CSV文件中的数据转换加载到pandas数据帧,然后将其用于输出,它将为LSTM提供数据的numpy数组。 Keras LSTM层的工作方式是采用3维(N,W,F)的numpy数组,其中N是训练序列的数量,W是序列长度,F是每个序列的特征数。我们选择使用50的序列长度(读取窗口大小)来允许网络,因此可以在每个序列中看到正弦波的形状,有希望自己建立基于序列的序列模式。

    序列本身是滑动窗口,因此每次移动1,导致与先前窗口不断重叠。当绘制时,序列长度为50的典型训练窗口如下所示:

    Sinewave数据集训练窗口

    为了加载这些数据,我们在代码中创建了一个DataLoader类,为数据加载层提供抽象。您会注意到,在初始化DataLoader对象时,会传入文件名, 并确定用于训练与测试的数据百分比的拆分变量,且允许选择一列或多列数据的列变量用于单维或多维分析。

    在我们有一个允许我们加载数据的数据对象之后,需要构建深度神经网络模型。同样,对于抽象,我们的代码框架使用的是模型类和config.json文件,在给定存储在配置文件中的所需体系结构和超参数的情况下,轻松构建模型的实例。构建我们网络的主要功能是build_model()函数,它接收经过解析的配置文件。

    此功能代码如下所示,可以轻松扩展,以便将来在更复杂的体系架构上使用。

    加载数据并建立模型后,我们现在可以继续使用我们的训练数据训练模型。为此,我们创建了一个单独的运行模块,它将利用我们的模型和模块抽象将它们组合起来进行训练、输出和可视化。

    下面是训练我们模型的一般运行线程代码:

    对于输出,我们将运行两种类型的预测:种将以逐点方式进行预测,即我们每次仅预测单个点,将此点绘制为预测,然后沿着下一个窗口进行预测使用完整的测试数据并再次预测下一个点。

    我们要做的第二个预测是预测一个完整的序列,我们只用训练数据的部分初始化一次训练窗口。然后模型预测下一个点,我们就移动窗口,就像逐点方法一样。不同之处在于我们使用我们在先前预测中预测的数据来进行下一步预测。在第二步中,这意味着只有一个数据点(后一个点)来自先前的预测。在第三个预测中,后两个数据点将来自先前的预测,依此类推。经过50次预测后,我们的模型将随后根据自己的先前预测进行预测。这使我们可以使用该模型预测未来的许多时间步骤,但由于它是在预测的基础上进行预测,这反过来可以反过来又可以预测,将增加预测的错误率,我们会预测的更远。

    下面我们可以看到逐点预测和完整序列预测的代码和相应的输出。

    逐点正弦波预测

    正弦波全序列预测

    作为参考,可以在下面的配置文件中看到用于正弦波示例的网络架构和超参数。

    在真实数据的叠加下我们可以看到,只需1个时期和相当小的训练数据集,LSTM深度神经网络就可以很好地预测正弦函数。

    您可以看到,随着我们对未来越来越多的预测,误差幅度会随着先前预测中的误差在用于未来预测时被越来越多地放大并且增加。因此,我们看到在完整序列示例中,预测越远,我们预测预测的频率和幅度与真实数据相比就越不准确。然而,由于sin函数是一个非常简单的零噪声振荡函数,它仍然可以在没有过度拟合的情况下很好地预测它。这很重要,因为我们可以通过增加时期和取出dropout 层来轻松地过度拟合模型。这个训练数据几乎完全准确,与测试数据具有相同的模式,但对于其他现实世界的例子,将模型过度拟合到训练数据上会导致测试精度直线下降,因为模型不会一概而论。

    在下一步中,我们将尝试在此类真实数据上使用该模型来查看效果。

    不那么简单的股票市场

    我们在的逐点基础上预测了几百个正弦波的步长。因此,我们现在可以在股市时间序列中做同样的事情并立即获利,对吗?不幸的是,在现实世界中,这并不是那么简单。

    与正弦波不同,股票市场时间序列不是可以映射的任何特定静态函数。描述股票市场时间序列运动的佳属性是随机游走。作为随机过程,真正的随机游走没有可预测的模式,因此尝试对其进行建模将毫无意义。幸运的是,许多方面都在持续争论说股票市场不是一个纯粹的随机过程,这使我们可以理解时间序列可能有某种隐藏模式。正是这些隐藏的模式,LSTM深度网络成为预测的主要候选者。

    此示例将使用的数据是数据文件夹中的sp500.csv文件。此文件包含2000年1月至2018年9月的标准普尔500股票指数的开盘价、高价、低价、收盘价以及每日交易量。

    在个例子中,我们将仅使用收盘价创建单维模型。调整config.json文件以反映新数据,我们将保持大部分参数相同。然而,需要做出的一个改变是,与只有-1到+1之间的数值范围的正弦波不同,收盘价是股票市场不断变化的价格。这意味着如果我们试图在不对其进行标准化的情况下训练模型,它就永远不会收敛。

    为了解决这个问题,我们将采用每个n大小的训练/测试数据窗口,并对每个窗口进行标准化以反映从该窗口开始的百分比变化(因此点i = 0处的数据将始终为0)。我们将使用以下等式进行归一化,然后在预测过程结束时进行去标准化,以获得现实世界数量的预测:

    n =价格变化的标准化列表[窗口]

    p =调整后的每日回报价格的原始清单[窗口]

    正常化: 

    反规范化:

    我们已将normalise_windows()函数添加到DataLoader类以执行此转换,并且配置文件中包含布尔规范化标志,表示这些窗口的规范化。

    随着窗口的标准化,我们现在可以运行模型,就像我们针对正弦波数据运行模型一样。但是,我们在运行这些数据时做了一个重要的改变,而不是使用我们框架的model.train()方法,只是使用我们创建的model.train_generator()方法。我们这样做是因为我们发现在尝试训练大型数据集时很容易耗尽内存,因为model.train()函数将完整数据集加载到内存中,然后将规范化应用于内存中的每个窗口,容易导致内存溢出。因此,我们使用了Keras的fit_generator()函数,允许使用python生成器动态训练数据集来绘制数据,这意味着内存利用率将大大降低。下面的代码详细说明了用于运行三种类型预测的新运行线程(逐点,完整序列和多序列)。

    如上所述,在单个逐点预测上运行数据可以非常接近匹配返回的内容。但这有点欺骗性。经过仔细检查,会发现预测线由奇异的预测点组成,这些预测点在它们后面具有整个先前的真实历史窗口。因此,网络不需要了解时间序列本身,除了下一个点很可能不会离后一点太远。因此,即使它得到错误点的预测,下一个预测也将考虑真实的历史并忽略不正确的预测,然后再次允许产生错误。

    虽然这对于下一个价格点的预测而言初听起来并不乐观,但它确实有一些重要的用途。虽然它不知道确切的下一个价格是多少,但它确实能够准确地表示下一个价格的范围。

    此信息可用于诸如波动率预测等应用(能够预测市场中高或低波动的时段对特定交易策略非常有利),或远离交易这也可用作良好指标用于异常检测。可以通过预测下一个点,然后将其与真实数据进行比较来实现异常检测,并且如果真实数据值与预测点显著不同,则可以针对该数据点标出异常标记。

    标准普尔500指数逐点预测

    继续进行完整的序列预测,似乎这被证明是对这种类型的时间序列不有用的预测(至少使用这些超参数训练这个模型)。我们可以看到预测开始时的轻微碰撞,其中模型遵循某种类型的动量,但是很快我们可以看到模型确定佳模式是收敛到时间序列的某个均衡。在这个阶段,这可能看起来并没有提供太多价值,但是均值回归交易者可能会在那里宣称,该模型只是找到价格序列在波动率被消除时将恢复的平均值。

    标准普尔500指数全序列预测

    后,我们对该模型进行了第三种预测,我将其称为多序列预测。这是完整序列预测的混合,因为它仍然使用测试数据初始化测试窗口,预测下一个点,然后使用下一个点创建一个新窗口。但是,一旦它到达输入窗口完全由过去预测组成的点,它就会停止,向前移动一个完整的窗口长度,用真实的测试数据重置窗口,然后再次启动该过程。实质上,这为测试数据提供了多个趋势线预测,以便能够分析模型获得未来动量趋势的程度。

    标准普尔500指数多序列预测

    我们可以从多序列预测中看出,网络似乎正确地预测了绝大多数时间序列的趋势(和趋势幅度)。虽然不完美,但它确实表明了LSTM深度神经网络在顺序和时间序列问题中的有用性。通过仔细的超参数调整,肯定可以实现更高的准确性。

    结论

    虽然本文的目的是在实践中给出LSTM深度神经网络的一个工作实例,但它只是触及了它们在顺序和时间问题中的潜力和应用的表面。

    在撰写本文时,LSTM已成功应用于众多现实问题中,从此处所述的经典时间序列问题到文本自动纠正、异常检测和欺诈检测,以及开发自动驾驶汽车技术的核心。

    目前使用上述LSTM存在一些局限性,特别是在使用金融时间序列时,该系列本身具有很难建模的非平稳特性(尽管在使用贝叶斯深度神经网络方法方面取得了进展)解决时间序列的非平稳性问题。同样对于一些应用,还发现基于注意力的神经网络机制的新进展已经超过LSTM(并且LSTM与这些基于注意力的机制相结合也优于其自身)。

    然而,截至目前,LSTM在更经典的统计时间序列方法上提供了显著的进步,能够非线性地建模关系,并且能够以非线性方式处理具有多个维度的数据。

    我们开发的框架的完整源代码可以在以下GitHub页面上的MIT许可证下找到:https: //github.com/jaungiers/LSTM-Neural-Network-for-Time-Series-Prediction

    1
    0
    AI中国
    创建时间:2019-08-22 17:24:09
    我将分享我关注的人工智能资讯、采访报道、技术干货文章等
    展开
    订阅须知

    • 所有用户可根据关注领域订阅专区或所有专区

    • 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

    • 专区发布评论属默认订阅所评论专区(除付费小栈外)

    作者

    • 栈栈
      作者
    戳我,来吐槽~