如何優雅地用TensorFlow預測時間序列:TFTS庫詳細教程
雷鋒網按:本文作者何之源,原文載於知乎專欄AI Insight,雷鋒網獲其授權發布。
前言
如何用TensorFlow結合LSTM來做時間序列預測其實是一個很老的話題,然而卻一直沒有得到比較好的解決。如果在Github上搜索「tensorflow time series」,會發現star數最高的tgjeon/TensorFlow-Tutorials-for-Time-Series已經和TF 1.0版本不兼容了,並且其他的項目使用的方法也各有不同,比較混亂。
在剛剛發布的TensorFlow 1.3版本中,引入了一個TensorFlow Time Series模塊(源碼地址為:tensorflow/tensorflow,以下簡稱為TFTS)。TFTS專門設計了一套針對時間序列預測問題的API,目前提供AR、Anomaly Mixture AR、LSTM三種預測模型。
由於是剛剛發布的庫,文檔還是比較缺乏的,我通過研究源碼,大體搞清楚了這個庫的設計邏輯和使用方法,這篇文章是一篇教程帖,會詳細的介紹TFTS庫的以下幾個功能:
讀入時間序列數據(分為從numpy數組和csv文件兩種方式)
用AR模型對時間序列進行預測
用LSTM模型對時間序列進行預測(包含單變數和多變數)
先上效果圖,使用AR模型預測的效果如下圖所示,藍色線是訓練數據,綠色為模型擬合數據,紅色線為預測值:
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/1e34436bf3593e66870f1854b964f256.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic1.zhimg.com/v2-f65d210a595774496115fcb1a9790b38_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/1e34436bf3593e66870f1854b964f256.jpg"/>
使用LSTM進行單變數時間序列預測:
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/0141f69e3937d1df2ba0f033230ebfc3.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic3.zhimg.com/v2-fa65657aff4d55c646429442291cb4ba_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/0141f69e3937d1df2ba0f033230ebfc3.jpg"/>
使用LSTM進行多變數時間序列預測(每一條線代表一個變數):
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/7ae46f187e37574a10afd6346055e3bf.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic2.zhimg.com/v2-e94b1088eb4b57d590c971c24972b745_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/7ae46f187e37574a10afd6346055e3bf.jpg"/>
文中涉及的所有代碼已經保存在Github上了,地址是: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,生成一個實驗用的時間序列數據,這個時間序列數據實際上就是在正弦曲線上加上了上升的趨勢和一些隨機的雜訊:
如圖:
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/c845810cccb9277dbf88d52d8dcd571c.png" data-rawwidth="494" data-rawheight="371" class="origin_image zh-lightbox-thumb" width="494" data-original="https://pic1.zhimg.com/v2-bc8b2321b16abb778a172728115a3aa4_r.png" _src="https://static.leiphone.com/uploads/new/article/pic/201708/c845810cccb9277dbf88d52d8dcd571c.png"/>
橫坐標對應變數「x」,縱坐標對應變數「y」,它們就是我們之前提到過的「觀察的時間點」以及「觀察到的值」。TFTS讀入x和y的方式非常簡單,請看下面的代碼:
data={
}
reader=NumpyReader(data)
得到的reader有一個read_full()方法,它的返回值就是時間序列對應的Tensor,我們可以用下面的代碼試驗一下:
with tf.Session() as sess:
full_data=reader.read_full()
# 調用read_full方法會生成讀取隊列
coord=tf.train.Coordinator()
print(sess.run(full_data))
coord.request_stop()
我們在訓練時,通常不會使用整個數據集進行訓練,而是採用batch的形式。從reader出發,建立batch數據的方法也很簡單:
reader,batch_size=2,window_size=10)
以batch_size=2, window_size=10為例,我們可以打出一個batch內的數據:
with tf.Session() as sess:
batch_data=train_input_fn.create_batch()
coord=tf.train.Coordinator()
one_batch=sess.run(batch_data[0])
coord.request_stop()
print('one_batch_data:',one_batch)
這部分讀入代碼的地址為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中的時間序列讀入進來。
假設CSV文件的時間序列數據形式為:
CSV文件的第一列為時間點,第二列為該時間點上觀察到的值。將其讀入的方法為:
# coding: utf-8
from__future__import print_function
import tensorflow as tf
csv_file_name='./data/period_trend.csv'
從reader建立batch數據形成train_input_fn的方法和之前完全一樣。下面我們就利用這個train_input_fn來訓練模型。
使用AR模型預測時間序列
自回歸模型(Autoregressive model,可以簡稱為AR模型)是統計學上處理時間序列模型的基本方法之一。在TFTS中,已經實現了一個自回歸模型。使用AR模型訓練、驗證並進行時間序列預測的示常式序為train_array.py。
先建立一個train_input_fn:
x=np.array(range(1000))
y=np.sin(np.pi*x/100)+x/200.+noise
plt.plot(x,y)
plt.savefig('timeseries_y.jpg')
data={
}
reader=NumpyReader(data)
reader,batch_size=16,window_size=40)
針對這個序列,對應的AR模型的定義就是:
periodicities=200,input_window_size=30,output_window_size=10,
num_features=1,
loss=tf.contrib.timeseries.ARModel.NORMAL_LIKELIHOOD_LOSS)
這裡的幾個參數比較重要,分別給出解釋。第一個參數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方法可以直接進行訓練:
ar.train(input_fn=train_input_fn, steps=6000)
TFTS中驗證(evaluation)的含義是:使用訓練好的模型在原先的訓練集上進行計算,由此我們可以觀察到模型的擬合效果,對應的程序段是:
evaluation=ar.evaluate(input_fn=evaluation_input_fn,steps=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步以後的值進行預測,對應的代碼為:
(predictions,)=tuple(ar.predict(
evaluation,steps=250)))
這裡的代碼在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')
畫好的圖片會被保存為「predict_result.jpg」
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/e288631a0a65abf0906543c855fc8ac1.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic2.zhimg.com/v2-f71bc465796845a1e74cd5df69fccb21_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/e288631a0a65abf0906543c855fc8ac1.jpg"/>
使用LSTM預測單變數時間序列
給出兩個用LSTM預測時間序列模型的例子,分別是train_lstm.py和train_lstm_multivariate.py。前者是在LSTM中進行單變數的時間序列預測,後者是使用LSTM進行多變數時間序列預測。為了使用LSTM模型,我們需要先使用TFTS庫對其進行定義,定義模型的代碼來源於TFTS的示例源碼,在train_lstm.py和train_lstm_multivariate.py中分別拷貝了一份。
我們同樣用函數加雜訊的方法生成一個模擬的時間序列數據:
x=np.array(range(1000))
y=np.sin(np.pi*x/50)+np.cos(np.pi*x/50)+np.sin(np.pi*x/25)+noise
data={
}
reader=NumpyReader(data)
reader,batch_size=4,window_size=100)
接下來我們定義一個LSTM模型:
estimator=ts_estimators.TimeSeriesRegressor(
model=_LSTMModel(num_features=1,num_units=128),
optimizer=tf.train.AdamOptimizer(0.001))
num_features = 1表示單變數時間序列,即每個時間點上觀察到的量只是一個單獨的數值。num_units=128表示使用隱層為128大小的LSTM模型。
訓練、驗證和預測的方法都和之前類似。在訓練時,我們在已有的1000步的觀察量的基礎上向後預測200步:
estimator.train(input_fn=train_input_fn,steps=2000)
evaluation=estimator.evaluate(input_fn=evaluation_input_fn,steps=1)
# Predict starting after the evaluation
(predictions,)=tuple(estimator.predict(
evaluation,steps=200)))
將驗證、預測的結果取出並畫成示意圖,畫出的圖像會保存成「predict_result.jpg」文件:
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/0141f69e3937d1df2ba0f033230ebfc3.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic3.zhimg.com/v2-fa65657aff4d55c646429442291cb4ba_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/0141f69e3937d1df2ba0f033230ebfc3.jpg"/>
使用LSTM預測多變數時間序列
所謂多變數時間序列,就是指在每個時間點上的觀測量有多個值。在data/multivariate_periods.csv文件中,保存了一個多變數時間序列的數據:
這個CSV文件的第一列是觀察時間點,除此之外,每一行還有5個數,表示在這個時間點上的觀察到的數據。換句話說,時間序列上每一步都是一個5維的向量。
使用TFTS讀入該CSV文件的方法為:
與之前的讀入相比,唯一的區別就是column_names參數。它告訴TFTS在CSV文件中,哪些列表示時間,哪些列表示觀測量。
接下來定義LSTM模型:
estimator=ts_estimators.TimeSeriesRegressor(
model=_LSTMModel(num_features=5,num_units=128),
optimizer=tf.train.AdamOptimizer(0.001))
區別在於使用num_features=5而不是1,原因在於我們在每個時間點上的觀測量是一個5維向量。
訓練、驗證、預測以及畫圖的代碼與之前比較類似,可以參考代碼train_lstm_multivariate.py,此處直接給出最後的運行結果:
<img src="https://static.leiphone.com/uploads/new/article/pic/201708/7ae46f187e37574a10afd6346055e3bf.jpg" data-rawwidth="1500" data-rawheight="500" class="origin_image zh-lightbox-thumb" width="1500" data-original="https://pic2.zhimg.com/v2-e94b1088eb4b57d590c971c24972b745_r.jpg" _src="https://static.leiphone.com/uploads/new/article/pic/201708/7ae46f187e37574a10afd6346055e3bf.jpg"/>
圖中前100步是訓練數據,一條線就代表觀測量在一個維度上的取值。100步之後為預測值。
總結
這篇文章詳細介紹了TensorFlow Time Series(TFTS)庫的使用方法。主要包含三個部分:數據讀入、AR模型的訓練、LSTM模型的訓練。文章里使用的所有代碼都保存在Github上了,地址是:hzy46/TensorFlow-Time-Series-Examples。如果覺得有幫助,歡迎點贊或star~~~
點擊展開全文
※亞馬遜Echo發家史(下):高維布局、戰略碾壓,Alexa的全場景較量
※英特爾推出Movidius Myriad X VPU,用神經計算引擎全面加速AI時代
※日銷100多萬,京東之家的「魔力」是如何煉成的?
TAG:雷鋒網 |
※Intel CPU 再現新漏洞:預測執行攻擊 L1 Terminal Fault
※Google AI在現場比賽期間預測NCAA Final Four的獲勝者
※AlphaGo之後,DeepMind重磅推出AlphaFold:基因序列預測蛋白質結構
※AI賦能DevOps:基於TensorFlow的端到端軟體缺陷預測
※DeepMind 團隊 CASP 奪冠:用 AlphaFold 預測蛋白質結構
※Facebook開源 時間序列預測框架 Prophet
※Google Flights:用人工智慧預測航班延誤
※Themis Chain聯手Lomostar 重新定義世界盃預測
※Sensor Tower預測:《PUBG Mobile》上月收入超《堡壘之夜》手游
※用Prophet快速進行時間序列預測(附Prophet和R代碼)
※Christopher Nolan 預測《Black Panther》將獲得下屆奧斯卡「最佳電影」提名!?
※Magic Leap UI界面曝光,微軟用AI預測Win 10更新時間
※Pixel Watch預測總結Google狙擊 pple Watch的秘密武器
※iPhone X plus新機預測
※手把手教你用Python庫Keras做預測
※Pytorch實現CNN時間序列預測
※Perceptive Automata加入Renovo的Aware生態系統 為自動駕駛車輛預測人類行為
※Sonkwo Plus:猜大餅,E3預測專題(上)
※npj Computational Materials:快速準確預測晶格熱導率的「小技巧」
※MathWorks 為 MATLAB 添加新的預測性維護產品