如何优雅地用TensorFlow预测时间序列:TFTS库详细教程-阿里云开发者社区

开发者社区> 行者武松> 正文

如何优雅地用TensorFlow预测时间序列:TFTS库详细教程

简介:
+关注继续查看
本文来自AI新媒体量子位(QbitAI)

这篇文章中,作者详细介绍了TensorFlow Time Series(TFTS)库的使用方法。主要包含数据读入、AR模型的训练、LSTM模型的训练三部分内容。内容翔实有趣,量子位转载分享给大家。

前言

如何用TensorFlow结合LSTM来做时间序列预测其实是一个很老的话题,然而却一直没有得到比较好的解决。如果在Github上搜索“tensorflow time series”,会发现star数最高的tgjeon/TensorFlow-Tutorials-for-Time-Series已经和TF 1.0版本不兼容了,并且其他的项目使用的方法也各有不同,比较混乱。

tgjeon/TensorFlow-Tutorials-for-Time-Series地址:

https://github.com/tgjeon/TensorFlow-Tutorials-for-Time-Series**

在刚刚发布的TensorFlow 1.3版本中,引入了一个TensorFlow Time Series模块(以下简称为TFTS)。TFTS专门设计了一套针对时间序列预测问题的API,目前提供AR、Anomaly Mixture AR、LSTM三种预测模型

TFTS模块源码地址:

https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/timeseries

由于是刚刚发布的库,文档还是比较缺乏的,我通过研究源码,大体搞清楚了这个库的设计逻辑和使用方法,这篇文章是一篇教程帖,会详细的介绍TFTS库的以下几个功能:

  • 读入时间序列数据(分为从numpy数组和csv文件两种方式)
  • 用AR模型对时间序列进行预测
  • 用LSTM模型对时间序列进行预测(包含单变量和多变量)

先上效果图,使用AR模型预测的效果如下图所示,蓝色线是训练数据,绿色为模型拟合数据,红色线为预测值:

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1
使用LSTM进行单变量时间序列预测:
640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1
使用LSTM进行多变量时间序列预测(每一条线代表一个变量):
640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1
文中涉及的所有代码已经保存在Github上了,以下提到的所有代码和文件都是相对于这个项目的根目录来说的

Github地址:

https://github.com/hzy46/TensorFlow-Time-Series-Examples

时间序列问题的一般形式

一般地,时间序列数据可以看做由两部分组成:观察的时间点和观察到的值。以商品价格为例,某年一月的价格为120元,二月的价格为130元,三月的价格为135元,四月的价格为132元。

那么观察的时间点可以看做是1,2,3,4,而在各时间点上观察到的数据的值为120,130,135,132。

从Numpy数组中读入时间序列数据

如何将这样的时间序列数据读入进来?TFTS库中提供了两个方便的读取器NumpyReader和CSVReader。前者用于从Numpy数组中读入数据,后者则可以从CSV文件中读取数据。

我们利用np.sin,生成一个实验用的时间序列数据,这个时间序列数据实际上就是在正弦曲线上加上了上升的趋势和一些随机的噪声:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

我们利用np.sin,生成一个实验用的时间序列数据,这个时间序列数据实际上就是在正弦曲线上加上了上升的趋势和一些随机的噪声:

如图:

640?wx_fmt=png&wxfrom=5&wx_lazy=1
横坐标对应变量“x”,纵坐标对应变量“y”,它们就是我们之前提到过的“观察的时间点”以及“观察到的值”。TFTS读入x和y的方式非常简单,请看下面的代码:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

我们首先把x和y变成python中的词典(变量data)。变量data中的键值tf.contrib.timeseries.TrainEvalFeatures.TIMES实际就是一个字符串“times”,而tf.contrib.timeseries.TrainEvalFeatures.VALUES就是字符串”values”。

所以上面的定义直接写成“data = {‘times’:x, ‘values’:y}”也是可以的。写成比较复杂的形式是为了和源码中的写法保持一致。

得到的reader有一个read_full()方法,它的返回值就是时间序列对应的Tensor,我们可以用下面的代码试验一下:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

不能直接使用sess.run(reader.read_full())来从reader中取出所有数据。原因在于read_full()方法会产生读取队列,而队列的线程此时还没启动,我们需要使用tf.train.start_queue_runners启动队列,才能使用sess.run()来获取值。

我们在训练时,通常不会使用整个数据集进行训练,而是采用batch的形式。从reader出发,建立batch数据的方法也很简单:

640?wx_fmt=png&wxfrom=5&wx_lazy=1
tf.contrib.timeseries.RandomWindowInputFn会在reader的所有数据中,随机选取窗口长度为window_size的序列,并包装成batch_size大小的batch数据。换句话说,一个batch内共有batch_size个序列,每个序列的长度为window_size

以batch_size=2, window_size=10为例,我们可以打出一个batch内的数据:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

这部分读入代码的地址:
https://github.com/hzy46/TensorFlow-Time-Series-Examples/blob/master/test_input_array.py

从CSV文件中读入时间序列数据

有的时候,时间序列数据是存在CSV文件中的。我们当然可以将其先读入为Numpy数组,再使用之前的方法处理。更方便的做法是使用tf.contrib.timeseries.CSVReader读入。

项目中提供了一个test_input_csv.py代码,示例如何将文件./data/period_trend.csv中的时间序列读入进来。

代码地址:

https://github.com/hzy46/TensorFlow-Time-Series-Examples/blob/master/test_input_csv.py

假设CSV文件的时间序列数据形式为:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

CSV文件的第一列为时间点,第二列为该时间点上观察到的值。将其读入的方法为:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

从reader建立batch数据形成train_input_fn的方法和之前完全一样。下面我们就利用这个train_input_fn来训练模型。

使用AR模型预测时间序列

自回归模型(Autoregressive model,可以简称为AR模型)是统计学上处理时间序列模型的基本方法之一。在TFTS中,已经实现了一个自回归模型。使用AR模型训练、验证并进行时间序列预测的示例程序为train_array.py。

train_array.py地址:

https://github.com/hzy46/TensorFlow-Time-Series-Examples/blob/master/train_array.py

先建立一个train_input_fn:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

针对这个序列,对应的AR模型的定义就是:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

这里的几个参数比较重要,分别给出解释。

第一个参数periodicities表示序列的规律性周期。我们在定义数据时使用的语句是:“y = np.sin(np.pi * x / 100) + x / 200. + noise”,因此周期为200。

input_window_size表示模型每次输入的值,output_window_size表示模型每次输出的值。input_window_size和output_window_size加起来必须等于train_input_fn中总的window_size

在这里,我们总的window_size为40,input_window_size为30,output_window_size为10,也就是说,一个batch内每个序列的长度为40,其中前30个数被当作模型的输入值,后面10个数为这些输入对应的目标输出值。

最后一个参数loss指定采取哪一种损失,一共有两种损失可以选择,分别是NORMAL_LIKELIHOOD_LOSS和SQUARED_LOSS。

num_features参数表示在一个时间点上观察到的数的维度。我们这里每一步都是一个单独的值,所以num_features=1

除了程序中出现的几个参数外,还有一个比较重要的参数是model_dir。它表示模型训练好后保存的地址,如果不指定的话,就会随机分配一个临时地址。

使用变量ar的train方法可以直接进行训练:

640?wx_fmt=png&wxfrom=5&wx_lazy=1
TFTS中验证(evaluation)的含义是:使用训练好的模型在原先的训练集上进行计算,由此我们可以观察到模型的拟合效果,对应的程序段是:

640?wx_fmt=png&wxfrom=5&wx_lazy=1
如果要理解这里的逻辑,首先要理解之前定义的AR模型:它每次都接收一个长度为30的输入观测序列,并输出长度为10的预测序列。

整个训练集是一个长度为1000的序列,前30个数首先被当作“初始观测序列”输入到模型中,由此就可以计算出下面10步的预测值。接着又会取30个数进行预测,这30个数中有10个数就是前一步的预测值,新得到的预测值又会变成下一步的输入,以此类推。

最终我们得到970个预测值(970=1000-30,因为前30个数是没办法进行预测的)。这970个预测值就被记录在evaluation[‘mean’]中。evaluation还有其他几个键值,如evaluation[‘loss’]表示总的损失,evaluation[‘times’]表示evaluation[‘mean’]对应的时间点等等。

evaluation[‘start_tuple’]会被用于之后的预测中,它相当于最后30步的输出值和对应的时间点。以此为起点,我们可以对1000步以后的值进行预测,对应的代码为:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

这里的代码在1000步之后又像后预测了250个时间点。对应的值就保存在predictions[‘mean’]中。我们可以把观测到的值、模型拟合的值、预测值用下面的代码画出来:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

画好的图片会被保存为“predict_result.jpg”

640?wx_fmt=png&wxfrom=5&wx_lazy=1

使用LSTM预测单变量时间序列

注意:以下LSTM模型的例子必须使用TensorFlow最新的开发版的源码。具体来说,要保证“from tensorflow.contrib.timeseries.python.timeseries.estimators import TimeSeriesRegressor”可以成功执行。

给出两个用LSTM预测时间序列模型的例子,分别是train_lstm.py和train_lstm_multivariate.py。前者是在LSTM中进行单变量的时间序列预测,后者是使用LSTM进行多变量时间序列预测。

为了使用LSTM模型,我们需要先使用TFTS库对其进行定义,定义模型的代码来源于TFTS的示例源码,在train_lstm.py和train_lstm_multivariate.py中分别拷贝了一份。

TFTS的示例源码地址:

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/timeseries/examples/lstm.py

我们同样用函数加噪声的方法生成一个模拟的时间序列数据:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

此处y对x的函数关系比之前复杂,因此更适合用LSTM这样的模型找出其中的规律。得到y和x后,使用NumpyReader读入为Tensor形式,接着用tf.contrib.timeseries.RandomWindowInputFn将其变为batch训练数据。

一个batch中有4个随机选取的序列,每个序列的长度为100。

接下来我们定义一个LSTM模型:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

num_features = 1表示单变量时间序列,即每个时间点上观察到的量只是一个单独的数值。num_units=128表示使用隐层为128大小的LSTM模型。

训练、验证和预测的方法都和之前类似。在训练时,我们在已有的1000步的观察量的基础上向后预测200步:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

将验证、预测的结果取出并画成示意图,画出的图像会保存成“predict_result.jpg”文件:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

使用LSTM预测多变量时间序列

所谓多变量时间序列,就是指在每个时间点上的观测量有多个值。在data/multivariate_periods.csv文件中,保存了一个多变量时间序列的数据:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

这个CSV文件的第一列是观察时间点,除此之外,每一行还有5个数,表示在这个时间点上的观察到的数据。换句话说,时间序列上每一步都是一个5维的向量

使用TFTS读入该CSV文件的方法为:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

与之前的读入相比,唯一的区别就是column_names参数。它告诉TFTS在CSV文件中,哪些列表示时间,哪些列表示观测量。

接下来定义LSTM模型:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

区别在于使用num_features=5而不是1,原因在于我们在每个时间点上的观测量是一个5维向量。

训练、验证、预测以及画图的代码与之前比较类似,可以参考代码train_lstm_multivariate.py,此处直接给出最后的运行结果:

640?wx_fmt=png&wxfrom=5&wx_lazy=1
参考代码地址:

https://github.com/hzy46/TensorFlow-Time-Series-Examples/blob/master/train_lstm_multivariate.py

图中前100步是训练数据,一条线就代表观测量在一个维度上的取值。100步之后为预测值。

总结

这篇文章详细介绍了TensorFlow Time Series(TFTS)库的使用方法。主要包含三个部分:数据读入、AR模型的训练、LSTM模型的训练。

文章里使用的所有代码都保存在Github上了,地址是:https://github.com/hzy46/TensorFlow-Time-Series-Examples。如果觉得有帮助,欢迎点赞或star~~~


点击左下角“阅读原文”处可查看完整代码~

还可参与讨论(≧ω≦)

本文作者:何之源
原文发布时间:2017-09-01

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Jenkins 教程(二)实现本地资源ssh上传
在教程一中我们只实现了在jenkins容器中的打包和结果通知,这节教程将用一个ssh工具将我们package完的项目上传到我们的服务器中。 1. 安装插件 Publish over SSH 完了点击直接安装 2. 插件的系统配置 配置完成后测试一下: 3. 插件的工程配置 最后一个框是在服务器运行什么脚本。
863 0
Directx11教程38 纹理映射(8)
上篇日志中,我们用纹理和光照颜色调制的方式得到最终颜色,本章我们尝试用纹理采样的颜色,直接做为材质的漫反射系数Kd,并用它来做光照计算,最后再做个gamma校正,如果不做的话,效果会偏亮。      lighttex.
700 0
PyTorch快餐教程2019 (2) - Multi-Head Attention
# PyTorch快餐教程2019 (2) - Multi-Head Attention 上一节我们为了让一个完整的语言模型跑起来,可能给大家带来的学习负担过重了。没关系,我们这一节开始来还上节没讲清楚的债。 还记得我们上节提到的两个Attention吗? ![两种Attention机制](https://upload-images.jianshu.io/upload_images/
1480 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4479 0
PySide教程:第一个PySide应用
  PySide安装:请参考 http://www.meegoq.com/thread-1161-1-1.html   使用你已经安装了PySide,那么现在你应该已经拥有完整的PySide拷贝,并且可以使用Qt+Python的方式开发GUI应用程序。
1125 0
Directx11教程(43) 纹理映射(13)-动态纹理映射
本篇教程中,我们将在前面基于光照的地形与水面程序里面加上纹理映射,而且我们会基于时间动态改变水面的纹理坐标,实现水面纹理波动的效果。       地形(山谷)以及水面都是基于网格的平面。
756 0
Directx11教程40 纹理映射(10)
本章尝试使用纹理行列式,或者说纹理数组,在ps中,使用2个纹理,最终的像素颜色,是光照颜色*纹理1采样颜色*纹理2采样颜色,主要是想达到如下的效果:    把这两个图像以及光照产生的颜色融合生成以下图像:   为此我们新建一个lighttex2.
817 0
+关注
行者武松
杀人者,打虎武松也。
14545
文章
2569
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载