TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)

  • 本节简介
  • TensorFlow更新
  • 注意
  • 下载最新源码编译源码更新
  • 首先卸载当前的tensorflow
  • 参考官方的从源码安装tensorflow
  • 直接使用pip工具更新
  • 更新后可能会遇到的异常
  • 自定义LSTM循环神经网络进行时间序列预测
  • 工程实现
  • 需要用到的模块
  • 生成训练数据与测试数据
  • 注解
  • 定义网络模型
  • 创建模型并训练
  • Estimator工具
  • 绘图
  • 利用TFTS进行时间序列预测
  • 载入数据部分
  • 从CSV文件中读入时间序列数据
  • 使用AR模型预测时间序列
  • 代码实现
  • 产生数据
  • 创建ar模型
  • 训练评估模型并预测
  • 使用LSTM预测单变量时间序列
  • 产生训练数据
  • 定义训练模型并预测
  • 绘制预测数据图
  • 使用LSTM预测多变量时间序列
  • 获取训练数据
  • 定义训练模型并预测
  • 绘制预测图
  • 总结

本节简介

本节关于TFTS模块的使用参考知乎-何之源-如何优雅地用TensorFlow预测时间序列:TFTS库详细教程。

如何在TensorFlow上使用LSTM来做时间序列预测是一个很老的话题,然而一直没有比较好的解决方案。在刚刚发布的TensorFlow1.3版本中,在tf.contrib包下引入了一个Time Series模块(TensorFlow Time Series,TFTS)。其源码地址在github timeseries。TFTS提供了一套基础的时间序列模型API。目前提供AR、Anomaly Mixture AR、LSTM三种预测模型。

这里因为是刚刚发布的库,文档匮乏,我们着重于介绍TFTS的以下几个功能:

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

先看效果图,

  1. 使用自定义LSTM循环网络对单变量进行时间序列预测(没使用TFTS,代码比较繁琐):

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


  1. 使用TFTS下的AR模型预测效果如下,蓝色为训练数据,绿色为模型拟合数据,红色为预测数据:

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


  1. 使用TFTS下的LSTM对单变量进行时间序列预测:

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


  1. 使用TFTS下的LSTM对多变量进行时间序列预测:

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


这里涉及到的代码保存在github-hzy46.网速不好的同学可以到或者在CSDN上下载。



TensorFlow更新

注意

后面使用的LSTM模型的例子须使用TensorFlow最新的开发版的源码。具体来说,要保证下面这句话可以成功执行。

from tensorflow.contrib.timeseries.python.timeseries.estimators import TimeSeriesRegressor

  • 1
  • 2

如果执行不成功,则需要下面的更新操作。

下载最新源码(编译源码更新)

1. 首先卸载当前的tensorflow

pip uninstall tensorflow #gpu版 就是tensorflow-gpu

  • 1
  • 2

2. 参考官方的从源码安装tensorflow

参考TensorFlow官方安装教程。我的开发环境是Ubuntu16.04+1080显卡,需要安装gpu版本。

  • 保证显卡驱动,CUDA8.0,cudnn6.0安装成功
  • 安装bazel bazel安装教程
  • 安装Python依赖包
  • sudo apt-get install python-numpy python-dev python-pip python-wheel # 对py2
  • sudo apt-get install python3-numpy python3-dev python3-pip python3-wheel #对py3
  • 1
  • 2
  • 从github上下载最新的源码
  • git clone https://github.com/tensorflow/tensorflow
  • 1
  • 配置tensorflow安装
  • cd tensorflow # cd to the top-level directory created
  • $ ./configure
  • '''
  • 除了CUDA项选择y,其他都是n或者默认项.
  • Configuration finished
  • '''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 编译成pip包

'''

编译

'''

bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package

'''

挺长的一段编译时间

生产pip包

'''

bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

'''

安装

'''

sudo pip install /tmp/tensorflow_pkg/tensorflow-1.3.0-py2-none-any.whl

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果出啥问题,建议直接看官方教程来整,有啥小问题,上stackoverflow上找找原因。(从源码编译tensorflow前前后后花费了我2天的时间,现在整出来了,踩了不少的坑,感觉下次会快很多了~)

现在9月初tensorflow的pip安装版本还不支持这个TimeSeriesRegressor类,等到后面版本稳定更新了,应该可以用下面pip工具更新。

直接使用pip工具更新

因为本次用到的库需要运行在TensorFlow1.3版本,而我的环境是Ubuntu下的1.0.1版本的TensorFlow。如果你不知道自己的TensorFlow是啥版本,有一个简单的方法:

激活python编程环境,键入以下代码运行即可。

import tensorflow as tf

print(tf.__version__) # 查看tensorflow版本

print(tf.__path__) # 查看tensorflow安装位置

'''

输出:

1.0.1

['/root/anaconda2/lib/python2.7/site-packages/tensorflow']

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

更新方法也很简单,如果你的TensorFlow是普通的安装,直接在命令行键入以下命令:

$: sudo pip install --upgrade tensorflow-gpu # 我安装的是gpu版

  • 1

等待更新完成即可。

import tensorflow as tf

print(tf.__version__) # 查看tensorflow版本

print(tf.__path__) # 查看tensorflow安装位置

'''

输出:

1.3.0

['/root/anaconda2/lib/python2.7/site-packages/tensorflow']

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

更新后可能会遇到的异常

  • 问题描述:
  • libcudnn.so.6:cannot open sharedobject file: No such file or directory
  • 1
  • 问题分析:
  • 我在开始安装1.0.1版本的tensorflow时,配置的是CUDA8.0+cudnn-v5.1。这里我把tensorflow升级到1.3版本,新的Tensorflow适配的是cudnn-v6.0。故需要升级cudnn。
  • 解决办法:
  • 升级cudnn的方法参考安装CUDNN。
  1. 下载适配CUDA版本和系统版本的cudnn-v6.0

  1. 解压下载好的cudnn
  2. $ : sudo tar -zxvf cudnn-8.0-linux-x64-v6.0.tgz
  3. 将解压文件拷贝并修改权限
  4. $ :sudo cp cuda/include/cudnn.h /usr/local/cuda/include/ # copy file
  5. $ :sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lin64/
  6. $ :sudo chmod a+r /usr/local/cuda/include/cudnn.h # 修改权限
  7. $ :sudo chmod a+r /usr/local/cuda/libcudnn*
  • 1
  • 2
  • 3
  • 4

到这里,算是大功告成了~



自定义LSTM循环神经网络进行时间序列预测

在使用TFTS库前,我们先利用自定义循环神经网络预测正弦函数。初步学习一下如何使用LSTM循环神经网络进行时间序列预测,这里我们会使用TensorFlow的一个高级封装工具-TFLearn(集成在tf.contrib.learn).

工程实现

1. 需要用到的模块

# coding:utf8

import numpy as np

import tensorflow as tf

from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat

import matplotlib.pyplot as plt

learn = tf.contrib.learn

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2. 生成训练数据与测试数据

因为是要预测正弦函数,这里我们使用np模块下的np.sin函数生成训练数据和测试数据。

TRAINING_EXAMPLES = 10000 # 训练数据大小

TESTING_EXAMPLES = 1000 # 测试数据大小

SAMPLE_GAP = 0.01 #采样间隔

TIMESTEPS = 10 # 循环神经网络截断长度

def generate_data(seq):

'''

定义生成正弦函数数据函数

:param seq:

:return: X为训练数据序列,y为预测数据

'''

X = []

y = []

for i in range(len(seq) - TIMESTEPS - 1):

X.append([seq[i: i + TIMESTEPS]]) # 截取以i下标开始的以TIMESTEPS为batch的数据

y.append([seq[i + TIMESTEPS]]) # 预测i+TIMESTEPS的数据

return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)

# 生成数据

# TRAINING_EXAMPLES训练数据个数 SAMPLE_GAP采样间隔

test_start = TRAINING_EXAMPLES * SAMPLE_GAP

# 训练数据和测试数据个数

test_end = (TRAINING_EXAMPLES + TESTING_EXAMPLES) * SAMPLE_GAP

# np.linspace生成等差数列 即采样横轴数据

# 从0到test_start,生成TRAINING_EXAMPLES个数据(即采样间隔为SAMPLE_GAP)

train_X, train_y = generate_data(np.sin(np.linspace(

0, test_start, TRAINING_EXAMPLES, dtype=np.float32)))

# np.linspace生成等差数列

#

test_X, test_y = generate_data(np.sin(np.linspace(

test_start, test_end, TESTING_EXAMPLES, dtype=np.float32)))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

注解:

训练数据TRAINING_EXAMPLES加上测试数据TESTING_EXAMPLES一共需要11000组。

这里我们设置是采样间隔SAMPLE_GAP是0.01。故我们整个采样距离是11000*0.01=110.也就是在sin函数上,x轴为[0,110]这段距离上均分为11000份。

训练数据是以网络的截断长度为分割间距。这里循环神经网络的截断长度TIMESTEPS为10。故我们的数据也是10个采样点和对应的sin值为一组,预测第11个点。(训练时候就是回归第11个点的值).

  • 先使用np.linspace函数取出等差间隔的采样点
  • 再使用np.sin函数获得对应的sin值。
  • 在生成数据generate_data时,以TIMESTEPS截断数据到X内,将TIMESTEPS+1个数据放到对应的标签y内。

下面是np.linspace和np.sin的用法示例:

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


3. 定义网络模型

我们使用BasicLSTMCell和MultiRNNCell构成一个hidden_size为30的2层的LSTM循环神经网络。需要注意的是不同版本下在创建LSTMCells的方法是不一样的。

HIDDEN_SIZE = 30 # 隐藏单元个数

NUM_LAYERS = 2 #LSTM层数

TRAINING_STEPS = 3000 # 训练数据轮数

BATCH_SIZE = 32 # batch大小

def lstm_model(X, y):

'''

定义LSTM模型

:param X: 训练数据

:param y: 预测标签

:return:

'''

# 1.2版本后,tensorflow对使用BasicLSTMCell等 RNNCells生成cells有不同的处理方法,这里多层的RNN建议采用这种创建cell方法

stacked_rnn = []

for iiLyr in range(NUM_LAYERS):

stacked_rnn.append(tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True))

cell = tf.nn.rnn_cell.MultiRNNCell(cells=stacked_rnn, state_is_tuple=True)

#lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True) #1.2版本前

#cell = tf.contrib.rnn.MultiRNNCell([lstm_cell] * NUM_LAYERS)

# 将多层LSTM结构连接成RNN网络并计算其前向传播结果

output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)

# 只关注网络的最后一个输出结果,即为下一时刻的预测输出

output = tf.reshape(output, [-1, HIDDEN_SIZE])

# 通过无激活函数的全联接层计算线性回归,并将数据压缩成一维数组的结构。

predictions = tf.contrib.layers.fully_connected(output, 1, None)

labels = tf.reshape(y, [-1])

predictions = tf.reshape(predictions, [-1])

# 定义平方差损失

loss = tf.losses.mean_squared_error(predictions, labels)

# 创建模型优化器并得到优化步骤

train_op = tf.contrib.layers.optimize_loss(

loss, tf.contrib.framework.get_global_step(),

optimizer="Adagrad", learning_rate=0.1)

return predictions, loss, train_op

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

4. 创建模型并训练

这里我们使用了tf.contrib.learn下的一个封装模型工具Estimator。使用Estimator封装好一个预测模型后((已训练),我们对测试数据进行了预测,再计算了下均方误差,大体上的评估了一下模型的预测性能。

# 封装之前定义的lstm

# 如果你的tensorflow1.2版本前已经训练好了这样的的一个模型,在tensorflow更新后,重新生成模型。

# 因为在新版本的Tensorflow里,LSTM单元的文件改变了,这里我们简单的把以前的model_dir修改了,保证创建了新的模型

regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir="Models/model_3"))

# 拟合数据

regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)

# 计算预测值

predicted = [[pred] for pred in regressor.predict(test_X)]

# 计算MSE

rmse = np.sqrt(((predicted - test_y) ** 2).mean(axis=0))

print ("Mean Square Error is: %f" % rmse[0])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Estimator工具

这里我们简单的介绍以下Estimator工具。

参考TensorFlow 0.12 Estimators Models Layers学习笔记。Estimators的作用是:

  • tf.estimator framework用于快速构建和训练机器学习模型,同时Estimator提供了一些常见的模型(常见的回归和分类模型,例如:线性分类,线性回归等)
  • tf.estimator为monitors,checkpointing提供了初始化配置,同时提供了构建和评估自定义模型的大部分逻辑。依照着tutorial可以很方便的创建一个estimator.TensorFlow关于Estimator介绍

总的来说,我们可以认为tf.estimator工具是用来提供一个自定义模型的框架,我们照着定义好的格式配置好输入即可。

  1. 创建一个Estimator
  • 先看构造器定义:
  • init(model_fn=None, model_dir=None, config=None, params=None, feature_engineering_fn=None)
  • '''
  • Args:
  • model_fn: 模型定义,定义了train, eval, predict的实现
  • model_dir: log文件和训练参数的保存目录
  • config: Configuration object
  • params: dict of hyper parameters that will be passed into model_fn. Keys are names of parameters, values are basic python types.
  • feature_engineering_fn: Feature engineering function. Takes features and labels which are the output of input_fn and returns features and labels which will be fed into model_fn. Please check model_fn for a definition of features and labels.
  • '''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • tf.estimator常接收2个参数:model_fn和model_dir.注意到我们使用的.
  • learn.Estimator(model_fn=lstm_model, model_dir="Models/model_3") # model_fn和model_dir参数
  • 1
  • 这里需要注意model_fn:
  1. model_fn(features, labels, mode, params)
  2. '''
  3. features: Tensor or dict of Tensor's. 即样本数据x.
  4. labels: Tensor or dict of Tensor's. 样本数据y.(支持无标签训练,调整对应的mode即可)
  5. mode: 指定model_fn功能.
  6. params: params is a dict of hyperparameters
  7. '''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 训练模型
  2. 将我们的训练数据塞给fit,训练完成后,就会按照前面指定的model_dir存放训练好的模型.
  3. fit(x=None, y=None, input_fn=None, steps=None, batch_size=None, monitors=None, max_steps=None)
  4. '''
  5. x: 训练数据x. 格式为[n_samples,n_features...],如果设置此参数,input_fn需为None.
  6. y: 训练数据y。x对应的标签。
  7. steps: 每次训练ops.
  8. batch_size: minibatch size.
  9. moitors: Used for callbacks inside the training loop.
  10. max_steps: Number of total steps for which to train model.
  11. input_fn: 说白了就是把x,y,batch_size包装一下。 用这个就不用设置x,y,batch_size了.
  12. '''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 预测
  2. 将需要预测的数据塞给predict,返回的就是预测值.
  3. predict(x=None, input_fn=None, batch_size=None, outputs=None, as_iterable=True)
  4. '''
  5. x : 为需要预测的数据。
  6. batch_size: minibatch size.
  7. input_fn: 对x和batch_size的包装
  8. outputs: list of str, name of the output to predict. If None, returns all
  9. as_iterable: If True, return an iterable which keeps yielding predictions for each example until inputs are exhausted. Note: The inputs must terminate if you want the iterable to terminate (e.g. be sure to pass num_epochs=1 if you are using something like read_batch_features).
  10. '''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. 注意
  2. 前面我说了如果在输入的时候设置x,y,batch_size就不要设置input_fn,需要注意的是:,如果使用x,y而不是input_fn来传参数的形式,需要用Estimator里一个叫SKCompat的类包装一下.
  3. estimator_instance = SKCompat(Estimator(model_fn=..., model_dir=...))
  • 1
  • 2
  1. 到这里,我们对TensorFlow内的Estimator工具介绍就算结束了~

5. 绘图

使用plt将预测数据和测试数据绘制出来,有一个直观上的认识。

fig = plt.figure()

plot_predicted, = plt.plot(predicted, label='predicted')

plot_test, = plt.plot(test_y[0:399], label='real_sin')

plt.legend([plot_predicted, plot_test],['predicted', 'real_sin'])

plt.show()

fig.savefig('pre_sin.png')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)



利用TFTS进行时间序列预测

到这里算是切入主题了,下面介绍如何使用TFTS模块进行时间序列预测。

载入数据部分

对于时间序列预测问题,我们可以把数据抽象成:{观察点:观察值}。例如某年一月的价格为120元,二月的价格为130元,三月的价格为135元,四月的价格为132元。那么观察的时间点可以看做是1,2,3,4,而在各时间点上观察到的数据的值为120,130,135,132。

TFTS库提供了两个数据读取器NumpyReader和CSVReader.

NumpyReader用于从Numpy数组中读入数据,下面举一个demo:

import numpy as np

import matplotlib.pyplot as plt

x = np.array(range(1000))

noise = np.random.uniform(-0.2, 0.2, 1000) # 随机生成-0.2~0.2之间的数据

y = np.sin(np.pi * x * 0.01) + x * 0.005 + noise # y=sin(0.01*pi*x) + 0.005*x + noise

p = plt.plot(x, y)

plt.show()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)

横轴即’采样点x’,纵轴为’采样值y’.

TFTS提供的读入x和y的接口非常简单,使用demo如下:

data = {

tf.contrib.timeseries.TrainEvalFeatures.TIMES: x,

tf.contrib.timeseries.TrainEvalFeatures.VALUES: y,

}

reader = NumpyReader(data)

  • 1
  • 2
  • 3
  • 4
  • 5

我们首先把x和y转为Python中的dict.我们来分析以下上面data的写法。tf.contrib.timeseries.TrainEvalFeatures.TIMES就是一个字符串’times’,而对应tf.contrib.timeseries.TrainEvalFeatures.VALUES也是一个字符串’values’.上面的data定义也可以写成:

data = {

'times' : x,

'values': y,

}

  • 1
  • 2
  • 3
  • 4

至于为什么写成上面的那个形式,也是为了配合规范化。

NumpyReader返回的对象有一个read_full()方法,该方法用于从Reader中读取所有的数据,但需要注意的是:read_full()会产生读取队列(这样的处理训练数据的方法和TensorFlow开源的AlexNet网络上对输入数据做增强操作使用的方法类似),这要求我们在使用该方法前,需要先调用tf.train.start_queue_runners启动队列,然后才能读取数据。使用的demo如下:

with tf.Session() as sess:

full_data = reader.read_full()

coord = tf.train.Coordinator() # 创建一个线程协调器

threads = tf.train.start_queue_runners(sess=sess, coord=coord) # 启动线程队列

print('times shape:', full_data['times'])

print('values shape:', full_data['values'])

print(sess.run(full_data)['times'][0:10])

print(sess.run(full_data)['values'][0:10])

coord.request_stop()

'''

输出:

times shape: Tensor("Squeeze_1:0", shape=(1000,), dtype=int64)

values shape: Tensor("Squeeze:0", shape=(1000, 1), dtype=float64)

[0 1 2 3 4 5 6 7 8 9]

[[-0.09581681]

[ 0.01284531]

[ 0.1107236 ]

[ 0.08856841]

[ 0.19104294]

[ 0.32795446]

[ 0.17780316]

[ 0.35017529]

[ 0.10477021]

[ 0.16101822]]

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

通常在训练模型时,我们采需要的是minibatch形式的训练数据,TFTS库提供了tf.contrib.timeseries.RandomWindowInputFn方法用于在reader中随机选取window_size大小的数据组成一组序列数据。demo如下:

train_input_fn = tf.contrib.timeseries.RandomWindowInputFn(

reader, batch_size=2, window_size=10)

with tf.Session() as sess:

batch_data = train_input_fn.create_batch()

coord = tf.train.Coordinator()

threads = tf.train.start_queue_runners(sess=sess, coord=coord)

one_batch = sess.run(batch_data[0])

coord.request_stop()

print('one_batch_data:', one_batch)

'''

即一个batch为2组序列数据,每组序列数据有10条数据。

输出:

one_batch_data: {

'values': array([[[ 1.21827106],

[ 1.37975747],

[ 1.15419451],

[ 1.07579377],

[ 1.19008057],

[ 1.32173953],

[ 1.2152622 ],

[ 1.31092923],

[ 1.26184174],

[ 1.25915473]],

[[ 0.08465949],

[-0.0859257 ],

[-0.02987006],

[ 0.17472125],

[ 0.23542243],

[ 0.2032668 ],

[ 0.07650485],

[ 0.20822309],

[ 0.30753332],

[ 0.16054565]]]),

'times': array([[61, 62, 63, 64, 65, 66, 67, 68, 69, 70],

[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])}

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

TFTS从Numpy中读取数据的流程大概操作就是这样了~


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

TFTS还提供了CSVReader用于读取CSV文件。

项目中提供了一个input_input_csv.py文件用于处理csv文件,这里处理的文件是’./data/period_trend.csv’.

这里CSV的文件形式如下(截取):

1,-0.6656603714

2,-0.1164380359

3,0.7398626488

4,0.7368633029

5,0.2289480898

6,2.257073255

7,3.023457405

8,2.481161007

9,3.773638612

10,5.059257738

11,3.553186083

12,4.554486452

13,3.655475698

14,3.419647598

15,4.303376245

16,4.830153934

17,7.253057441

18,5.064802335

19,5.448082106

20,6.251301517

...

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

CSV的第一列数据为时间点,第二列数据为对应的观察值。

CSVReader的操作步骤除了读取文件的部分不同,后面的操作和前面的NumpyReader是一样的。操作的demo如下:

from __future__ import print_function

import tensorflow as tf

csv_file_name = './data/period_trend.csv'

reader = tf.contrib.timeseries.CSVReader(csv_file_name)

with tf.Session() as sess:

data = reader.read_full()

coord = tf.train.Coordinator()

threads = tf.train.start_queue_runners(sess=sess, coord=coord)

print(sess.run(data))

coord.request_stop()

train_input_fn = tf.contrib.timeseries.RandomWindowInputFn(reader, batch_size=4, window_size=16)

with tf.Session() as sess:

data = train_input_fn.create_batch()

coord = tf.train.Coordinator()

threads = tf.train.start_queue_runners(sess=sess, coord=coord)

batch1 = sess.run(data[0])

batch2 = sess.run(data[0])

coord.request_stop()

print('batch1:', batch1)

print('batch2:', batch2)

'''

输出:

{'values': array([[ -0.66566038],

[ -0.11643804],

[ 0.73986262],

[ 0.73686332],

[ 0.22894809],

[ 2.25707316],

[ 3.02345729],

...

dtype=float32), 'times': array([ 1, 2, 3, 4, 5, 6, ...,500])}

batch1: {'values': array([[[ 9.75562382],

[ 9.1494894 ],

[ 8.94796562],

[ 9.1767683 ],dtype=float32), 'times': array([[ 98, 99,...,129]])}

batch2: {'values': array([[[ 4.97288084],

[ 5.21278238],...,dtype=float32), 'times': array([[ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,

95, 96, 97],...,226]])}

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

到这里为止,载入数据部分到这里就算结束了。


使用AR模型预测时间序列

AR模型是一种线性预测,即已知N个数据,可由模型推出第N点前面或后面的数据(设推出P点),所以其本质类似于插值,其目的都是为了增加有效数据,只是AR模型是由N点递推,而插值是由两点(或少数几点)去推导多点,所以AR模型要比插值方法效果更好。

代码实现

产生数据

产生数据的方法就是上面介绍的方法。

x = np.array(range(1000))

noise = np.random.uniform(-0.2, 0.2, 1000)

y = np.sin(np.pi * x / 100) + x / 200. + noise

plt.plot(x, y)

plt.savefig('timeseries_y.jpg')

data = {

tf.contrib.timeseries.TrainEvalFeatures.TIMES: x,

tf.contrib.timeseries.TrainEvalFeatures.VALUES: y,

}

reader = NumpyReader(data)

train_input_fn = tf.contrib.timeseries.RandomWindowInputFn(

reader, batch_size=16, window_size=40)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

创建ar模型

创建ar模型,我们需要使用tf.contrib.timeseries.ARRegressor类


先看下ARRegressor类

class ARRegressor(_TimeSeriesRegressor):

"""

ARRegressor是基于滑窗模型的。这要求输入窗口大小要固定为'input_window_size',输出窗口大小固定为'output_window_size'. 同时这两个参数的和必须等于window_size(满足训练或评估时使用的input_fn)。建议使用'RandomWindowInputFn'(就是上面讲的随机产生batch数据的函数)产生训练或者评估。

"""

def __init__(self,

periodicities, input_window_size,

output_window_size, num_features, num_time_buckets=10,

loss=ar_model.ARModel.NORMAL_LIKELIHOOD_LOSS,

hidden_layer_sizes=None, anomaly_prior_probability=None,

anomaly_distribution=None, optimizer=None,

model_dir=None, config=None):

"""

参数:

periodicities: value or a list of values. 输入信号的周期。

input_window_size: 回归时给定的输入数据时间步数.

output_window_size: 预测时间步数,建议设置>1.

num_features: 时间序列的维度.(数据的观察值)

loss: SQUARED_LOSS 或者 NORMAL_LIKELIHOOD_LOSS.

hidden_layer_sizes: 默认即可.

anomaly_distribution;anomaly_distribution: 默认即可,指定即构成混合模型

optimizer: defaults to Adagrad with step size 0.1.

model_dir:模型存储地址.(上面Estimator有讲)

config: See `Estimator`.

"""

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

总的来说,需要填的参数有periodicities,input_window_size,output_window_size,num_features,loss。其它的参数默认即可。


这里需要注意的有input_window_size + output_window_size = window_size.(RandomWindowInputFn生成数据里面的window_size).我们在上面的生成数据使用的window_size=40.下面使用的是input_window_size=30, output_window_size=10.就是输入序列30个,预测10个。

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

periodicities是信号的周期分量的周期,我们信号的表达式为:

y=sin(0.01∗π∗x)+0.005∗x+noise

y=sin(0.01∗π∗x)+0.005∗x+noise

y的周期分量的frequency为2∗π∗(1/f)

2∗π∗(1/f),故f=200,所以periodicities=200

f=200,所以periodicities=200。

loss的取值现在支持NORMAL_LIKELIHOOD_LOSS和SQUARED_LOSS。 ar = tf.contrib.timeseries.ARRegressor(

periodicities=200, input_window_size=30, output_window_size=10,

num_features=1,

loss=tf.contrib.timeseries.ARModel.NORMAL_LIKELIHOOD_LOSS)

'''

(input_window_size=30) + (output_window_size=10) = (window_size=40)

'''

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

训练评估模型并预测

使用train函数传入创建好的数据train_input_fn训练模型即可.

ar.train(input_fn=train_input_fn, steps=6000)

  • 1

接下来就是对模型进行评估,首先我们使用AR模型提供的evaluate函数,这里evaluation的处理是使用训练好的模型在原先的训练集上进行计算,由此我们可以观察到模型的拟合效果.

evaluation_input_fn = tf.contrib.timeseries.WholeDatasetInputFn(reader)

evaluation = ar.evaluate(input_fn=evaluation_input_fn, steps=1)

# keys of evaluation: ['covariance', 'loss', 'mean', 'observed', 'start_tuple', 'times', 'global_step']

# evaluation['covariance']代表协方差 evaluation['loss']代表损失 etc..

  • 1
  • 2
  • 3
  • 4

如果要理解这里evaluate函数的逻辑,这里AR模型:每次都接收长度为30的输入观测序列,并输出长度为10的预测序列。以此为规则,每次移动步长为1,以此类推,整个训练集长度为1000的序列,最终我们得到970个预测值。

这970个预测值记录在evaluation[‘mean’]中;evaluation还有其他几个键值:evaluation[‘loss’]表示总的损失,evaluation[‘times’]表示evaluation[‘mean’]对应的时间点等等.

评估完模型后,下面该是使用模型了,这里我们会用到predict函数来预测,传入参数为evaluation[‘start_tuple’]会被用于之后的预测中,它相当于最后30步的输出值和对应的时间点。以此为起点(也就是给定观察数据),我们可以对1000步以后的值进行预测,对应的代码为:

(predictions,) = tuple(ar.predict(

input_fn=tf.contrib.timeseries.predict_continuation_input_fn(

evaluation, steps=250)))

  • 1
  • 2
  • 3

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

plt.figure(figsize=(15, 5))

plt.plot(data['times'].reshape(-1), data['values'].reshape(-1), label='origin')

plt.plot(evaluation['times'].reshape(-1), evaluation['mean'].reshape(-1), label='evaluation')

plt.plot(predictions['times'].reshape(-1), predictions['mean'].reshape(-1), label='prediction')

plt.xlabel('time_step')

plt.ylabel('values')

plt.legend(loc=4)

plt.savefig('predict_result.jpg')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


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

注意:以下LSTM模型的例子必须使用TensorFlow最新的开发版的源码。具体来说,要保证

from tensorflow.contrib.timeseries.python.timeseries.estimators import TimeSeriesRegressor

  • 1

可以成功执行。(就是前面说的需要安装最新版的tensorflow)

给出两个用LSTM预测时间序列模型的例子,分别是train_lstm.py和train_lstm_multivariate.py。前者是在LSTM中进行单变量的时间序列预测,后者是使用LSTM进行多变量时间序列预测。为了使用LSTM模型,我们需要先使用TFTS库对其进行定义,定义模型的代码来源于TFTS的示例源码,在train_lstm.py和train_lstm_multivariate.py中分别拷贝了一份。

产生训练数据

这里我们产生的数据公式修改一下

y=sin(π∗0.02∗x)+cos(π∗0.02∗x)+sin(π∗0.04∗x)+noise

y=sin(π∗0.02∗x)+cos(π∗0.02∗x)+sin(π∗0.04∗x)+noise

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

x = np.array(range(1000))

noise = np.random.uniform(-0.2, 0.2, 1000)

y = np.sin(np.pi * x / 50 ) + np.cos(np.pi * x / 50) + np.sin(np.pi * x / 25) + noise

data = {

tf.contrib.timeseries.TrainEvalFeatures.TIMES: x,

tf.contrib.timeseries.TrainEvalFeatures.VALUES: y,

}

'''

plt.plot(x, y)

plt.savefig('train_data.jpg')

'''

reader = NumpyReader(data)

train_input_fn = tf.contrib.timeseries.RandomWindowInputFn(

reader, batch_size=4, window_size=100) # batch_size为4 序列长度为100

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

产生数据如下:

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)

定义训练模型并预测

这里使用TFTS包内提供的TimeSeriesRegressor模型。其中_LSTMModel来自TFTS包的官方例子。


  • _LSTMModel接受两个参数:num_units: 模型中使用的LSTM单元个数
  • num_features: 时间序列能观察到的维度.(即每个时间步能观察到的数据特征量)

这里我们使用的模型参数为num_features = 1表示单变量时间序列,即每个时间点上观察到的量只是一个单独的数值。num_units=128表示使用隐层为128大小的LSTM模型。后续的训练,评估,预测和前面讲的代码类似。在以后的1000组数据上,我们向后预测了200组数据。


代码如下:

estimator = ts_estimators.TimeSeriesRegressor(

model=_LSTMModel(num_features=1, num_units=128),

optimizer=tf.train.AdamOptimizer(0.001))

estimator.train(input_fn=train_input_fn, steps=2000)

evaluation_input_fn = tf.contrib.timeseries.WholeDatasetInputFn(reader)

evaluation = estimator.evaluate(input_fn=evaluation_input_fn, steps=1)

# Predict starting after the evaluation 预测后续的200组数据

(predictions,) = tuple(estimator.predict(

input_fn=tf.contrib.timeseries.predict_continuation_input_fn(

evaluation, steps=200)))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

绘制预测数据图

observed_times = evaluation["times"][0]

observed = evaluation["observed"][0, :, :]

evaluated_times = evaluation["times"][0]

evaluated = evaluation["mean"][0]

predicted_times = predictions['times']

predicted = predictions["mean"]

plt.figure(figsize=(15, 5))

plt.axvline(999, linestyle="dotted", linewidth=4, color='r')

observed_lines = plt.plot(observed_times, observed, label="observation", color="k")

evaluated_lines = plt.plot(evaluated_times, evaluated, label="evaluation", color="g")

predicted_lines = plt.plot(predicted_times, predicted, label="prediction", color="r")

plt.legend(handles=[observed_lines[0], evaluated_lines[0], predicted_lines[0]],

loc="upper left")

plt.savefig('predict_result.jpg')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)


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

与上面的使用LSTM预测单变量时间序列不同的地方在于数据的读取和模型的预测量。使用原理实质上是一致的。

获取训练数据

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

0,0.926906299771,1.99107237682,2.56546245685,3.07914768197,4.04839057867

1,0.108010001864,1.41645361423,2.1686839775,2.94963962176,4.1263503303

2,-0.800567600028,1.0172132907,1.96434754116,2.99885333086,4.04300485864

3,0.0607042871898,0.719540073421,1.9765012584,2.89265588817,4.0951014426

4,0.933712200629,0.28052120776,1.41018552514,2.69232603996,4.06481164223

5,-0.171730652974,0.260054421028,1.48770816369,2.62199129293,4.44572807842

6,-1.00180162933,0.333045158863,1.50006392277,2.88888309683,4.24755865606

7,0.0580061875336,0.688929398826,1.56543458772,2.99840358953,4.52726873347

8,0.764139447412,1.24704875327,1.77649279698,3.13578593851,4.63238922951

9,-0.230331874785,1.47903998963,2.03547545751,3.20624030377,4.77980005228

10,-1.03846045211,2.01133000781,2.31977503972,3.67951536251,5.09716775897

11,0.188643592253,2.23285349038,2.68338482249,3.49817168611,5.24928239634

12,0.91207302309,2.24244446841,2.71362604985,3.96332587625,5.37802271594

13,-0.296588665881,2.02594634141,3.07733910479,3.99698324956,5.56365901394

14,-0.959961476551,1.45078629833,3.18996420137,4.3763059609,5.65356015609

15,0.46313530679,1.01141441548,3.4980215948,4.20224896882,5.88842247449

16,0.929354125798,0.626635305936,3.70508262244,4.51791573544,5.73945973251

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

即每个时间步上能观察到多个数据变量(这里有5组数据)。举个简单的例子:如果现在我在跑步,每个时间步上,可以获取到我的心跳,血压,体温。这就是在每个时间步上能观察到3个数据变量。

下面依旧是使用CSVReader处理数据,区别在column_names参数,该参数告诉CSVReader那些变量是对应的时间步和变量。

csv_file_name = path.join("./data/multivariate_periods.csv")

reader = tf.contrib.timeseries.CSVReader(

csv_file_name,

column_names=((tf.contrib.timeseries.TrainEvalFeatures.TIMES,)

+ (tf.contrib.timeseries.TrainEvalFeatures.VALUES,) * 5))

train_input_fn = tf.contrib.timeseries.RandomWindowInputFn(

reader, batch_size=4, window_size=32)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

定义训练模型并预测

这里与上面的程序不同的地方在于_LSTMModel中参数num_features=5.即能观察的数据量维度为5.本次向后预测的数据为100组。(训练数据100组)

estimator = ts_estimators.TimeSeriesRegressor(

model=_LSTMModel(num_features=5, num_units=128),

optimizer=tf.train.AdamOptimizer(0.001))

estimator.train(input_fn=train_input_fn, steps=200)

evaluation_input_fn = tf.contrib.timeseries.WholeDatasetInputFn(reader)

evaluation = estimator.evaluate(input_fn=evaluation_input_fn, steps=1)

# Predict starting after the evaluation

(predictions,) = tuple(estimator.predict(

input_fn=tf.contrib.timeseries.predict_continuation_input_fn(

evaluation, steps=100)))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

绘制预测图

observed_times = evaluation["times"][0]

observed = evaluation["observed"][0, :, :]

evaluated_times = evaluation["times"][0]

evaluated = evaluation["mean"][0]

predicted_times = predictions['times']

predicted = predictions["mean"]

plt.figure(figsize=(15, 5))

plt.axvline(99, linestyle="dotted", linewidth=4, color='r')

observed_lines = plt.plot(observed_times, observed, label="observation", color="k")

evaluated_lines = plt.plot(evaluated_times, evaluated, label="evaluation", color="g")

predicted_lines = plt.plot(predicted_times, predicted, label="prediction", color="r")

plt.legend(handles=[observed_lines[0], evaluated_lines[0], predicted_lines[0]],

loc="upper left")

plt.savefig('predict_result.jpg')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

TensorFlow实战:Chapter-7下(TFTS库与时间序列预测)



总结

TFTS是Tensorflow官方提供的基于LSTM模型的时序预测工具,可以用于常见的时序模型上(替代HMM)。这里讲了如果使用TFTS模型读取数据并产生训练数据,同时讲了如果使用TFTS模块自带的AR和LSTM模型。

相关推荐