如何用TensorFlow進行股票價格預測的簡單深度學習模型

如何用TensorFlow進行股票價格預測的簡單深度學習模型

4 人贊了文章

對於我們最近在STATWORX上做過的黑客馬拉松 ,我們的一些團隊成員從谷歌財經API中略微收集了標準普爾500指數的數據。 該數據包括標準普爾500指數成份股的指數和股票價格。 掌握了這些數據後,我立即想出了一個基於500分成分價格來預測標準普爾500指數的深度學習模型的想法。

使用TensorFlow來處理數據和構建深度學習模型很有趣,因此我決定編寫我的第一個Medium.com故事:一個關於預測標準普爾500股票價格的TensorFlow小教程。 您將閱讀的內容不是深入的教程,而是對TensorFlow模型的重要構建塊和概念的高級介紹。 我創建的Python代碼沒有針對效率進行優化,而是可理解性。 我用過的數據集可以從這裡下載(40MB)。

請注意,這個故事是關於TensorFlow的動手教程。 實際的股票價格預測是一項非常具有挑戰性和複雜性的任務,需要付出巨大努力,特別是在較高頻率下,例如此處使用的分鐘數。

導入和準備數據

我們的團隊將刮取的數據作為csv文件從我們的抓取伺服器中導出。 該數據集包含n = 41266分鐘的數據,範圍從2017年4月到8月,500隻股票以及標準普爾500指數的總價格。 指數和股票以寬幅格式排列。

# Import data

data = pd.read_csv(『data_stocks.csv』)

#刪除日期變數

data = data.drop([『DATE』],1)

# Dimensions of dataset

n = data.shape[0]

p = data.shape[1]

#使數據成為一個numpy數組

data = data.values

數據已經清理和準備,意味著缺少庫存和指數價格是LOCF(最後一次觀察結轉),因此該文件不包含任何缺失值。

使用pyplot.plot(data[『SP500』])快速查看標準普爾時間序列:

標準普爾500指數的時間序列圖。

注意:這實際上是標準普爾500指數的領先者,這意味著它的價值在未來1分鐘內轉移(這已經在數據集中完成)。 此操作是必要的,因為我們想要預測索引的下一分鐘而不是當前分鐘。 從技術上講,數據集中的每一行都包含標準普爾500指數在t + 1的價格和成分股在T = t時的價格。

準備培訓和測試數據

數據集分為訓練和測試數據。 訓練數據包含總數據集的80%。 數據沒有改組,而是按順序切片。 培訓數據範圍從4月到大約。 2017年7月底,測試數據將於2017年8月底結束。

# Training and test data

train_start = 0

train_end = int(np.floor(0.8*n))

test_start = train_end

test_end = n

data_train = data[np.arange(train_start, train_end), :]

data_test = data[np.arange(test_start, test_end), :]

時間序列交叉驗證有很多不同的方法,例如有或沒有改裝的滾動預測或更複雜的概念,如時間序列引導程序重新採樣。 後者涉及來自時間序列的季節性分解的剩餘部分的重複樣本,以便模擬遵循與原始時間序列相同的季節性模式但不是其值的精確副本的樣本。

數據擴展

大多數神經網路架構都受益於擴展輸入(有時也是輸出)。 為什麼? 因為網路神經元的最常見激活函數,例如tanh或sigmoid,分別在[-1, 1]或[0, 1]間隔上定義。 如今,經整流的線性單元(ReLU)激活是常用的激活,其在可能的激活值的軸上是無界的。 但是,我們無論如何都會擴展輸入和目標。 使用sklearn的MinMaxScaler可以在Python中輕鬆完成縮放。

# Scale data

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()

scaler.fit(data_train)

data_train = scaler.transform(data_train)

data_test = scaler.transform(data_test)

# Build X and y

X_train = data_train[:, 1:]

y_train = data_train[:, 0]

X_test = data_test[:, 1:]

y_test = data_test[:, 0]

備註:必須注意縮放數據的哪個部分以及何時縮放。 常見的錯誤是在應用訓練和測試分割之前縮放整個數據集。 為什麼這是一個錯誤? 因為縮放調用統計的計算,例如變數的最小值/最大值。 在現實生活中進行時間序列預測時,您沒有預測時未來觀測的信息。 因此,必須對訓練數據進行縮放統計的計算,然後必須將其應用於測試數據。 否則,您在預測時使用未來信息,這通常會使預測指標偏向正向。

TensorFlow簡介

TensorFlow是一個偉大的軟體,目前是領先的深度學習和神經網路計算框架。 它基於C++低級後端,但通常通過Python控制( R還有一個簡潔的TensorFlow庫 ,由RStudio維護)。 TensorFlow對基礎計算任務的圖形表示進行操作。 該方法允許用戶將數學運算指定為數據,變數和運算符的圖形中的元素。 由於神經網路實際上是數據和數學運算的圖形,因此TensorFlow非常適合神經網路和深度學習。 看看這個簡單的例子(從我們博客的深度學習介紹中偷來的):

一個非常簡單的圖表,將兩個數字相加。

在上圖中,應該添加兩個數字。 這些數字存儲在兩個變數a和b 。 這兩個值流過圖形併到達方形節點,在那裡添加它們。 添加的結果存儲在另一個變數c 。 實際上, a , b和c可以被視為佔位符。 任何輸入a和b數字都會被添加並存儲到c 。 這正是TensorFlow的工作原理。 用戶通過佔位符和變數定義模型(神經網路)的抽象表示。 之後,佔位符將「填充「實際數據並進行實際計算。 以下代碼在TensorFlow中實現了上面的玩具示例:

# Import TensorFlow

import tensorflow as tf

# Define a and b as placeholders

a = tf.placeholder(dtype=tf.int8)

b = tf.placeholder(dtype=tf.int8)

# Define the addition

c = tf.add(a, b)

# Initialize the graph

graph = tf.Session()

# Run the graph

graph.run(c, feed_dict={a: 5, b: 4})

導入TensorFlow庫後,使用tf.placeholder()定義了兩個佔位符。 它們對應於上圖中左側的兩個藍色圓圈。 然後,通過tf.add()定義數學加法。 計算結果是c = 9 。 設置佔位符後,可以使用a和b任何整數值執行圖形。 當然,前一個問題只是一個玩具的例子。 神經網路中所需的圖形和計算要複雜得多。

佔位符

如前所述,這一切都始於佔位符。 為了適應我們的模型,我們需要兩個佔位符: X包含網路的輸入(在時間T = t時所有標準普爾500指數成份股的股票價格)和Y網路的輸出(在時間T = t + 1時標準普爾500指數的指數值) T = t + 1 )。

佔位符的形狀對應於[None, n_stocks] , [None]表示輸入是2維矩陣,輸出是1維向量。 了解神經網路需要哪些輸入和輸出維度以便正確設計它至關重要。

# Placeholder

X = tf.placeholder(dtype=tf.float32, shape=[None, n_stocks])

Y = tf.placeholder(dtype=tf.float32, shape=[None])

None參數表明,此時我們還不知道每批中流經神經網路圖的觀測數量,因此我們保持靈活性。 稍後我們將定義變數batch_size ,它控制每個訓練批次的觀察次數。

變數

除了佔位符,變數是TensorFlow Universe的另一個基石。 雖然佔位符用於在圖形中存儲輸入和目標數據,但變數用作圖形中允許在圖形執行期間更改的靈活容器。 權重和偏差表示為變數,以便在訓練期間進行調整。 在模型訓練之前,需要初始化變數。 我們稍後會更詳細地討論這個問題。

該模型由四個隱藏層組成。 第一層包含1024個神經元,略大於輸入大小的兩倍。 隨後的隱藏層總是前一層的一半大小,這意味著512,256和最後128個神經元。 每個後續層的神經元數量的減少壓縮了網路在先前層中識別的信息。 當然,其他網路架構和神經元配置也是可能的,但這些引入級別的文章不在其中。

#模型架構參數

n_stocks = 500

n_neurons_1 = 1024

n_neurons_2 = 512

n_neurons_3 = 256

n_neurons_4 = 128

n_target = 1

# Layer 1: Variables for hidden weights and biases

W_hidden_1 = tf.Variable(weight_initializer([n_stocks, n_neurons_1]))

bias_hidden_1 = tf.Variable(bias_initializer([n_neurons_1]))

# Layer 2: Variables for hidden weights and biases

W_hidden_2 = tf.Variable(weight_initializer([n_neurons_1, n_neurons_2]))

bias_hidden_2 = tf.Variable(bias_initializer([n_neurons_2]))

# Layer 3: Variables for hidden weights and biases

W_hidden_3 = tf.Variable(weight_initializer([n_neurons_2, n_neurons_3]))

bias_hidden_3 = tf.Variable(bias_initializer([n_neurons_3]))

# Layer 4: Variables for hidden weights and biases

W_hidden_4 = tf.Variable(weight_initializer([n_neurons_3, n_neurons_4]))

bias_hidden_4 = tf.Variable(bias_initializer([n_neurons_4]))

# Output layer: Variables for output weights and biases

W_out = tf.Variable(weight_initializer([n_neurons_4, n_target]))

bias_out = tf.Variable(bias_initializer([n_target]))

了解輸入,隱藏和輸出層之間所需的變數維度非常重要。 作為多層感知器(MLP,此處使用的網路類型)的經驗法則,前一層的第二維是當前層中權重矩陣的第一維。 這可能聽起來很複雜,但基本上只是每個層將其輸出作為輸入傳遞給下一層。 偏差維度等於當前圖層權重矩陣的第二維,它對應於該圖層中的神經元數量。

設計網路架構

在定義了所需的權重和偏差變數之後,需要指定網路拓撲,網路的體系結構。 因此,需要將佔位符(數據)和變數(權重和偏差)組合成順序矩陣乘法系統。

此外,網路的隱藏層由激活功能轉換。 激活函數是網路體系結構的重要元素,因為它們會給系統帶來非線性。 有許多可能的激活功能,其中最常見的是整流線性單元(ReLU),它也將用於該模型。

# Hidden layer

hidden_1 = tf.nn.relu(tf.add(tf.matmul(X, W_hidden_1), bias_hidden_1))

hidden_2 = tf.nn.relu(tf.add(tf.matmul(hidden_1, W_hidden_2), bias_hidden_2))

hidden_3 = tf.nn.relu(tf.add(tf.matmul(hidden_2, W_hidden_3), bias_hidden_3))

hidden_4 = tf.nn.relu(tf.add(tf.matmul(hidden_3, W_hidden_4), bias_hidden_4))

# Output layer (must be transposed)

out = tf.transpose(tf.add(tf.matmul(hidden_4, W_out), bias_out))

下圖說明了網路架構。 該模型由三個主要構建塊組成。 輸入圖層,隱藏圖層和輸出圖層。 該體系結構稱為前饋網路。 前饋表示該批數據僅從左向右流動。 其他網路架構,例如遞歸神經網路,也允許數據在網路中「向後「流動。

我們的前饋網路架構的酷技術插圖。

成本函數

網路的成本函數用於生成網路預測與實際觀察到的訓練目標之間的偏差度量。 對於回歸問題,通常使用均方誤差(MSE)函數。 MSE計算預測和目標之間的平均平方偏差。 基本上,可以實現任何可微函數以便計算預測和目標之間的偏差度量。

# Cost function

mse = tf.reduce_mean(tf.squared_difference(out, Y))

然而,MSE表現出某些有利於解決一般優化問題的特性。

優化

優化器負責必要的計算,這些計算用於在訓練期間調整網路的權重和偏差變數。 這些計算調用所謂的梯度的計算,其指示在訓練期間必須改變權重和偏差的方向,以便最小化網路的成本函數。 穩定和快速優化的發展是神經網路的一個主要領域,是一項深度學習研究。

# Optimizer

opt = tf.train.AdamOptimizer().minimize(mse)

這裡使用了Adam Optimizer,它是深度學習開發中當前的默認優化器之一。 Adam代表」 Ada ptive M oment Estimation」,可以被視為兩個其他流行優化器AdaGrad和RMSProp之間的組合。

初始化器

初始化器用於在訓練之前初始化網路變數。 由於神經網路是使用數值優化技術訓練的,因此優化問題的出發點是找到潛在問題的良好解決方案的關鍵因素之一。 TensorFlow中有不同的初始化程序,每個初始化程序都有不同的初始化方法。 在這裡,我使用tf.variance_scaling_initializer() ,這是默認的初始化策略之一。

# Initializers

sigma = 1

weight_initializer = tf.variance_scaling_initializer(mode=」fan_avg」, distribution=」uniform」, scale=sigma)

bias_initializer = tf.zeros_initializer()

注意,使用TensorFlow可以為圖中的不同變數定義多個初始化函數。 但是,在大多數情況下,統一初始化就足夠了。

適合神經網路

在定義了網路的佔位符,變數,初始化器,成本函數和優化器之後,需要對模型進行訓練。 通常,這是通過minibatch培訓完成的。 在小批量訓練期間,從訓練數據中抽取n = batch_size隨機數據樣本並將其饋送到網路中。訓練數據集分為n / batch_size批次,這些批次順序地輸入網路。 此時佔位符X和Y開始起作用。 它們存儲輸入和目標數據,並將它們作為輸入和目標呈現給網路。

X採樣數據批次流經網路,直到到達輸出層。 在那裡,TensorFlow將模型預測與當前批次中實際觀察到的目標Y進行比較。 之後,TensorFlow進行優化步驟並更新與所選學習方案相對應的網路參數。 更新了權重和偏差後,對下一批進行採樣,並重複該過程。 該過程將繼續,直到所有批次都已呈現給網路。 所有批次的全掃描被稱為時代。

一旦達到最大曆元數或者用戶定義的另一個停止標準適用,網路的訓練就停止。

#製作會話

net = tf.Session()

# Run initializer

net.run(tf.global_variables_initializer())

# Setup interactive plot

plt.ion()

fig = plt.figure()

ax1 = fig.add_subplot(111)

line1, = ax1.plot(y_test)

line2, = ax1.plot(y_test*0.5)

plt.show()

# Number of epochs and batch size

epochs = 10

batch_size = 256

對於範圍內的e(時期):

#隨機播放訓練數據

shuffle_indices = np.random.permutation(np.arange(len(y_train)))

X_train = X_train [shuffle_indices]

y_train = y_train [shuffle_indices]

#Minibatch培訓

對於範圍內的i(0,len(y_train)// batch_size):

start = i * batch_size

batch_x = X_train [start:start + batch_size]

batch_y = y_train [start:start + batch_size]

#使用批處理運行優化程序

net.run(opt,feed_dict = {X:batch_x,Y:batch_y})

#顯示進度

如果np.mod(i,5)== 0:

#預測

pred = net.run(out,feed_dict = {X:X_test})

line2.set_ydata(預計值)

plt.title(『Epoch』+ str(e)+』,Batch』+ str(i))

file_name =』img / epoch_』+ str(e)+』_ batch_』+ str(i)+』.jpg』

plt.savefig(FILE_NAME)

plt.pause(0.01)

#訓練後列印最終MSE

mse_final = net.run(mse,feed_dict = {X:X_test,Y:y_test})

列印(mse_final)

在培訓期間,我們評估測試集上的網路預測 – 每個第5批中未學習但預留的數據 – 並將其可視化。 此外,圖像將導出到磁碟,然後組合成培訓過程的視頻動畫(見下文)。 該模型快速了解測試數據中時間序列的形狀和位置,並能夠在一些時期之後產生準確的預測。 太好了!

在訓練期間網路測試數據預測(橙色)的視頻動畫。

可以看出,網路迅速適應時間序列的基本形狀,並繼續學習更精細的數據模式。 這也對應於亞當學習方案,該方案在模型訓練期間降低學習速率以便不超過優化最小值。 在10個時代之後,我們非常接近測試數據! 最終測試MSE等於0.00078(它非常低,因為目標是縮放的)。 測試集上預測的平均絕對百分比誤差等於5.31%,這是相當不錯的。 請注意,這僅適用於測試數據,實際場景中沒有實際的樣本指標。

預測和實際標準普爾價格之間的分散圖(按比例)。

請注意,有很多方法可以進一步改善這一結果:層和神經元的設計,選擇不同的初始化和激活方案,引入神經元的丟失層,提前停止等等。 此外,不同類型的深度學習模型,例如遞歸神經網路,可以在此任務上獲得更好的性能。 但是,這不是這篇介紹性文章的範圍。

結論和展望

TensorFlow的發布是深度學習研究中的一個里程碑事件。 它的靈活性和性能使研究人員能夠開發各種複雜的神經網路架構以及其他ML演算法。 然而,與更高級別的API(如KerasMxNet)相比,靈活性需要更長的模型周期時間。 儘管如此,我確信TensorFlow將在神經網路和研究和實際應用中的深度學習開發方面達到事實上的標準。 我們的許多客戶已經在使用TensorFlow或開始開發採用TensorFlow模型的項目。 我們STATWORX的數據科學顧問也大量使用TensorFlow進行深度學習和神經網路研究與開發。 讓我們來看看谷歌為TensorFlow的未來做了多少計劃。 至少在我看來,缺少的一件事是用TensorFlow後端設計和開發神經網路架構的簡潔圖形用戶界面。 也許,這是谷歌已經在努力的事情;)

如果您對我的第一篇中篇故事有任何意見或問題,請隨時在下面發表評論!我會儘力回答他們。 此外,您可以隨意使用我的代碼或在您選擇的社交平台上與同行分享此故事。

更新:我已將Python腳本和(壓縮)數據集添加到Github存儲庫 。 隨意克隆和分叉。


推薦閱讀:

??tf.concat
谷歌TPU家族新品,可申請提前試用丨Edge TPU晶元
如何利用TensorFlow.js部署簡單AI版「你畫我猜」
【深度學習之美12】感知機是如何工作的?
Inside TF-Slim(9) evaluation

TAG:AI技術 | TensorFlow | 股票期權 |