48

手把手教你搭建一个LSTM时间序列模型

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUxNDMzMjgxNQ%3D%3D&%3Bmid=2247490426&%3Bidx=1&%3Bsn=62e5e098621c3071b983968a7386e91a
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文转载自 运筹OR帷幄  (ID: ORAI_China) 作者: 书生

编者按: 当我们需要进行预测但是却没有太多特征可以利用时,就只能从过去的历史数据中获得特征,并对未来的结果进行预测。 对于神经网络和LSTM一窍不通的小白,请跟着本文开启你的第一个神经网络预测项目。

如果说Tensorflow 或者 Theano 神经网络方面的巨人。那么Keras 就是站在巨人肩膀上的人。

作为一个兼容 Theano 和 Tensorflow 的神经网络高级包, Keras来组建一个神经网络更加快速, 几条语句就搞定了,灰常简便。

而且广泛的兼容性能使 Keras 在 Windows 和 MacOS 或者 Linux 上运行无阻碍。

1.安装Keras

(1)在安装 Keras 之前, 需要确认自己已经安装好了 Numpy 和 Scipy.

(2)因为 Keras 是基于 Tensorflow 或者 Theano 的. 所以可以先自己安装 Tensorflow或者Theano.

(3)安装 Keras.在你的命令提示窗口直接输入 pip install Keras即可安装 。

安装好后,我们打开python导入Keras,可以查看其底层运用的框架是Tensorflow还是Theano,如下图。可以看到我的Keras的底层是基于TensorFlow的。

YfmqUrr.png!web

2.常规LSTM时间序列分析

LSTM(Long Short-Term Memory),长短期记忆模型的核心是细胞的状态及其中的门结构[1]。

LSTM的细胞状态由两种激活函数构成(sigmoid和tanh),分别组成遗忘门、输入门和输出门。其中sigmoid将输入的参数输出为0到1之间的数值,它主要用于判定某特征对于模型的影响程度,为1时影响程度最大。如下图[1]

3a6J7bV.png!web

tanh将输入的参数输出为-1到1之间的数值,用于将结果进行归一标准化,避免因为特征维度差异造成不必要的权重影响,如下图[1]

IRJf22a.png!web

最后,我们可以得到一个神经网络单元的结构如下,不熟悉的话可以自己手画一下,强化记忆。其中 代表单元的长期记忆, 代表单元的短期记忆, 为每次外部输入的数据。

Jra6Rb6.jpg!web

可见,长期记忆 在经过每个单元时,要删减掉一些不重要的信息,随后增加一些重要信息。而短期记忆 作为最终的预测结果,是 fYbmyij.png!web共同作用的结果。

3.一个具体的实例--仓库发货量预测

接下来,我们以某仓库过去一段时间的发货量来预测未来发货量,说明一下Keras中LSTM时间序列问题的一般建模流程。

首先导入必要的数据分析、可视化模块。

import time

import warnings

import numpy as np

import time

import matplotlib.pyplot as plt

from numpy import newaxis

import pandas as pd

读取数据,要说明的一点是python在read_csv的时候默认使用C engine作为parser engine。这样子当文件名中含有中文或者其他一些特殊字符的时候,用C engine就会出错,而使用python作为engine的时候兼容性更好且功能更全,当然C engine的好处就是运行更快。

df = pd.read_csv(r'E://LSTM//data.csv',engine='python')

数据共计631条,查看下数据的量级。

df.head(10)

fiqeamJ.png!web

基于数据绘制图像如下

aIFBBfQ.png!web

从图像来看发货量结果并不是很平滑,如果要用Arima算法的话,一般需要多次平滑获得稳定的时间序列分布后才能获得较好的预测结果。因此,这里我们首先尝试用LSTM模型。

3.1 处理数据

这里首先我们要依据给定的数据进行9:1的比例划分训练集(522条)和测试集(58条),并预留51条数据用作验证集。

另外,通过对数据的观察我们发现当前数据的量级过大,为了获得更好的结果,我们构建函数对数据进行归一化处理。(处理的详情见代码)

X_train, y_train, X_test, y_test, window =load_data('E://LSTM//data.csv', 50, True)

构建数据集后,进一步我们确认下数据集的size

print('X_train shape:',X_train.shape)

print('y_train shape:',y_train.shape)

print('X_test shape:',X_test.shape)

print('y_test shape:',y_test.shape)

RN7Z73Q.png!web

此时的数据已经归一化处理,并转换成np.array的形式。

3.2 构建模型

在获得处理好数据集后,构建LSTM神经网络模型进行结果预测。

from keras.models import Sequential

from keras.layers import Bidirectional,LSTM

from keras.layers.core import Dense, Activation, Dropout

其中,Sequential用于构建序贯模型,它可以由多个网络层进行线性堆叠。Bidirectional是双向神经网络结构,Dense就是我们所说的一层全连接神经网络,activation是激活函数,dropout是选择层后连接的神经元数,以避免过拟合 [2]。

3.3 版本问题说明

这里我偷个懒,仅展示单向神经网络的构建方式(双层可见代码)。

低版本的keras中模型构建的方式采用参数input_dim和output_dim,在高版本中采用此法会出现红色的warning。

因为,在高版本中已经采用input_shape和units,代替原来的input_dim和output_dim,以避免红色的warning信息[3]。

两种参数构建模型的效果是一样的,在此说明。

另外,对于小白来说,在开发过程中遇到keras本地环境和线上环境不同,导致函数方法不同而lost的情况也时有发生,这时候可以通过help方法查看某个函数的用法,例如你可以尝试输入help(LSTM)查看LSTM的常用方法和输入参数。

3.4 模型构建

接下来,构建一个LSTM神经网络模型。

通过add来增加一层神经网络,首先输入训练数据。

其中input_shape = (None,1)中的None代表模型输入集的数据量不限制(即可以是过去任意天的工作量),1在这里代表只有工作量一个维度。

units = 50 代表将输入的维度映射成50个维度输出。return_sequences为True意味着返回多个单元短期的输出结果,为False则只返回一个单元的输出结果 [4]。

随后加入一层输出为1维的神经网络,并设置激活层函数为线性(选择线性的原因,是因为我这里试用了多种激活函数,发现线性激活函数效果最好)

最终对模型进行编译,预测结果显然是一个回归问题,我们选择损失函数为mse,优化器选择rmsprop。

至此模型构建完成。

<span><br /></span>

<span>model = Sequential() #layers [1,50,50,50,50,1]</span>

<span>model.add(LSTM(input_shape=(None,1),units=50,return_sequences=True))</span>

<span>model.add(Dropout(0.2))</span>

<span>model.add(LSTM(input_shape=(None,50),units=50,return_sequences=True))</span>

<span>model.add(Dropout(0.2))</span>

<span>model.add(LSTM(input_shape=(None,50),units=50,return_sequences=True))</span>

<span>model.add(Dropout(0.2))</span>

<span>model.add(LSTM(50,return_sequences=False))</span>

<span>model.add(Dropout(0.2))</span>

<span>model.add(Dense(units=1))</span>

<span>model.add(Activation(&quot;linear&quot;))</span>

<span># model.add(Activation(&quot;sigmoid&quot;))</span>

<span>start = time.time()</span>

<span>model.compile(loss=&quot;mse&quot;, optimizer=&quot;rmsprop&quot;)</span>

<span>print(&quot;Compilation Time : &quot;, time.time() - start)</span>

进一步,通过len命令可以查看模型的层数为10层

len(model.layers)

随后,对结果进行拟合 。

其中batch_size是每次梯度更新的样本数,未写明则为32。

值得说明一下的是batch_size这个参数的坑有点深,我看了好久才理解,它主要的作用其实是用较少的样本获得合适的优化模型的梯度方向,避免全样本迭代时过高的内存占用;

epochs是指训练模型迭代次数,可以理解为我们遍历了一次所有的模型,则为1次epoch;(在keras1.*版本中的时候用的是nb_epoch,意义一样)

validation_split代表将数据集中多少数据用作验证集的训练数据的比例,这里选择5%的结果进行验证[2]。

model.fit(X_train,y_train,batch_size=10,nb_epoch=100,validation_split=0.05)

查看模型的预测误差值,这样看准确率大概在88%,运用到生产上效果还是可以接受的。

score2 = model.evaluate(X_test,y_test)

print(score2)

0.12872567772865295

随后,对所有的测试结果进行预测,并重塑预测结果的输出size。

显然这里的预测结果是我们在上面流程中已经标准化后的结果,因此这里我们需要将预测结果进一步反归一化后得到最终的预测结果。

进一步,我们将结果通过散点图和折线图的形式展示,如下:

JRfyEvn.jpg!web

可见预测与真实结果的趋势比较接近,但也存在较为明显的问题,峰值点的出现的时间较之真实情况略有滞后,并且预测峰值点的值明显小于真实点的峰值情况。

考虑到本次预测是单纯的一维时间序列预测问题,因此后期会考虑加入其它特征优化。

4.思考

本文仅展示了LSTM的基本原理和预测一个时间序列的简单流程,一般我们理解的LSTM不同于传统的监督学习方式,是一种自回归模型。然而通过改变LSTM网络的结构,例如加入autoencoding层,可以扩展特征维度。另外,LSTM在预测方面还可以加入除了时间外的其他特征以优化预测结果。

基于LSTM网络的结构,我们可以进行调整加入多个特征,这一定程度上将问题转化成了一个监督学习问题。还可以预测多个特征,例如预测未来一周每天的发货量。

有时间再写一下。

参考文献

[1]  难以置信!LSTM和GRU的解析从未如此清晰 https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/82922386

[2] Keras中文文档 https://keras-cn.readthedocs.io/en/latest/getting_started/sequential_model/

[3] Keras神经网络参数说明 https://blog.csdn.net/weixin_44731100/article/details/99976214

[4] Difference Between Return Sequences and Return States for LSTMs in Keras  https://machinelearningmastery.com/return-sequences-and-return-states-for-lstms-in-keras/

可以在 【运筹OR帷幄】公众号后台 回复关键词:“LSTM” 获得本文的示例代码与文件

文章声明

文章作者: 书生

审核编辑: 阿春

微信编辑: 葡萄

文章由『运筹OR帷幄』原创发布,经授权转载

6JVj63n.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK