使用LSTM模型做股票預測【基於Tensorflow】
LSTM模型簡介
LSTM是迴圈神經網路的一種,它具有長短時記憶的能力,克服了傳統RNN在輸入序列較長時產生的遺忘問題(即梯度消失)。LSTM通過三個分別稱為遺忘門、輸入門和輸出門的結構控制資訊的輸入輸出。LSTM有兩個狀態h(隱藏狀態)和c(細胞狀態),h控制短期記憶,c控制長期記憶。
其結構示意圖為:
其各個門的數學表達為:
其中小圓圈表示哈達瑪乘積。
最後,再總結一下各個門的客觀意義:
遺忘門:控制上個細胞狀態有多少資訊被保留
輸入門:控制當前的輸入資訊有多少被保留
輸出門:控制當前輸出有多少資訊值得保留
資料集
股票資料總共有九個維度,分別是
由於本人對經濟學沒有太多研究,所以這些各個維度所代表的資訊我也不是很清楚,但在我眼裡,它們就是一堆時序資料,而長短時記憶時序模型LSTM處理時序資料具有很強的優勢。
專案資料(儲存格式是excel):https://pan.baidu.com/s/1qcqCDAATaHapMOs2I_qr6A
提取碼:1346
然後我們來簡單觀察一下資料集的分佈。使用pandas庫讀取excel檔案後,將其轉換為numpy陣列,簡單剔除掉代號、日期之類的無用資料後,利用繪相簿matplotlib將各個維度的資料分佈繪製出來,程式如下:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
#check train data and test data
train_data = pd.read_excel('train_data.xlsx',index_col=0)
train_arrs = np.array(train_data.iloc[:,:])
trains = train_arrs[:,-9:].astype('float32')
test_data = pd.read_excel('test_data.xlsx',index_col=0)
test_arrs = np.array(test_data.iloc[:,:])
tests = test_arrs[:,-9:].astype('float32')
dim_names = ['open','high','low','close','pre_close','change','pct_chg','vol','amount']
#normalize
for dim in range(trains.shape[1]):
trains[:,dim] = (trains[:,dim] - trains[:,dim].min()) / (trains[:,dim].max() - trains[:,dim].min())
for dim in range(tests.shape[1]):
tests[:,dim] = (tests[:,dim] - tests[:,dim].min()) / (tests[:,dim].max() - tests[:,dim].min())
#visualization of train data
for dim in range(trains.shape[1]):
plt.subplot(3,3,dim+1)
plt.plot(trains[:,dim])
plt.title('%s'%(dim_names[dim]))
plt.show()
#visualization of test data
for dim in range(tests.shape[1]):
plt.subplot(3,3,dim+1)
plt.plot(tests[:,dim])
plt.title('%s'%(dim_names[dim]))
plt.show()
效果如下:
對於訓練集:
對於測試集:
可以簡單看出,各個維度並不是相互獨立的,有些分佈具有很強的相似性。
接著,我們來建立train_batches和test_batches以訓練模型。這裡用到的技巧其實不多,有一點提一下,對於資料集使用歸一化能加快模型的收斂以及抑制梯度爆炸。然後要注意這是預測模型,不是迴歸模型,模型的輸入是前n個time step的由各個維度構成的向量組,輸出的是下個time step的包含各個維度的向量,說起來有點繞,我作了一個簡單的示意圖,希望能理清你們的思路:
從shape的角度理解的話,那麼輸入資料的shape為[BATCH_SIZE,TIME_STEP,INPUT_DIM]。輸出資料的shape為[BATCH_SIZE,INPUT_DIM]
說明一下,該專案的預測只是對於開盤價,也就是’open’這個維度,所以實際的輸出資料的shape為[BATCH_SIZE,1]
建立train/test batches的程式碼如下:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
#讀取訓練資料
train_data = pd.read_excel('train_data.xlsx',index_col=0)
train_arrs = np.array(train_data.iloc[:,:])
train_xs = train_arrs[:,-8:].astype('float32')
train_ys = (np.array(train_data['open'],dtype='float32')).reshape(-1,1)
#讀取測試資料
test_data = pd.read_excel('test_data.xlsx',index_col=0)
test_arrs = np.array(test_data.iloc[:,:])
test_xs = test_arrs[:,-8:].astype('float32')
test_ys = (np.array(test_data['open'],dtype='float32')).reshape(-1,1)
#歸一化
train_ys = (train_ys-train_ys.min()) / (train_ys.max() - train_ys.min())
test_ys = (test_ys-test_ys.min()) / (test_ys.max() - test_ys.min())
for dim in range(train_xs.shape[1]):
train_xs[:,dim] = (train_xs[:,dim] - train_xs[:,dim].min()) / (train_xs[:,dim].max() - train_xs[:,dim].min())
for dim in range(test_xs.shape[1]):
test_xs[:,dim] = (test_xs[:,dim] - test_xs[:,dim].min()) / (test_xs[:,dim].max() - test_xs[:,dim].min())
#由於是預測任務,那麼資料的第一個維度會少掉一個time_step-1
time_step = 8
input_dim = 8
aranged_train_xs = np.zeros(shape=(train_xs.shape[0]-time_step+1,time_step,input_dim))
for idx in range(aranged_train_xs.shape[0]):
aranged_train_xs[idx] = train_xs[idx:idx+8]
aranged_test_xs = np.zeros(shape=(test_xs.shape[0]-time_step+1,time_step,input_dim))
for idx in range(aranged_test_xs.shape[0]):
aranged_test_xs[idx] = test_xs[idx:idx+8]
aranged_train_ys = train_ys[time_step-1:]
aranged_test_ys = test_ys[time_step-1:]
#儲存資料
np.save(r'train_x_batch.npy',aranged_train_xs)
np.save(r'train_y_batch.npy',aranged_train_ys)
np.save(r'test_x_batch.npy',aranged_test_xs)
np.save(r'test_y_batch.npy',aranged_test_ys)
搭建/訓練模型
在整理得到資料集後,我們就可以開始建模了。
建模流程(建議大家都多花時間提升下建模能力):
①定義超引數(batch_size、學習率、epochs、神經元數量等)
②定義待訓練引數(從什麼分佈取樣,需要做什麼正則化)
③ 定義一個load_data函式,從之前建立的資料集中讀取資料
④定義LSTM單元,注意預設的啟用函式是tanh,同時可以利用 tf.contrib.rnn.DropoutWrapper增加dropout層。
⑤定義LSTM網路,LSTM接受的是時序資料,所以需要將輸入變成一個列表,列表的長度及時間步數。然後使用列表推導技巧(官方的辦法)定義多層LSTM網路,建議都使用這個技巧,據瞭解別的方式BUG很多。最後使用tf.contrib.rnn.static_rnn得到網路輸出,注意static和dynamic的區別,前者的時間步數是固定的,而後者是可變的,對於我們創造的資料集,每個Batch的時間步數都相同,所以我們使用static(靜態)方式。
⑥訓練模型,對於Tensorflow框架,其訓練模型的方式大家都應該爛熟於心了。定義placeholder,定義預測函式、損失函式、優化函式等等。然後啟動Session(互動式或非互動式),最後迭代進行訓練。
整個過程的程式碼如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
plt.rcParams['font.sans-serif']=['SimHei']#顯示中文
plt.rcParams['axes.unicode_minus']=False#顯示負號
#Hyperparams
batch_size = 128
lr = 1e-6
epochs = 600
num_neurons = [32,32,64,64,128,128]
kp = 1.0
#定義輸出層的weight和bias
w = tf.Variable(tf.random_normal([num_neurons[-1],1]))
b = tf.Variable(tf.random_normal([1]))
def load_data():
train_x_batch = np.load(r'train_x_batch.npy',allow_pickle=True)
train_y_batch = np.load(r'train_y_batch.npy',allow_pickle=True)
return (train_x_batch,train_y_batch)
#定義lstm單元
def lstm_cell(units,keep_prob):
cell = tf.contrib.rnn.BasicLSTMCell(num_units=units,forget_bias=0.9)#activation預設為tanh
return tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=keep_prob)
#定義lstm網路
def lstm_net(x,w,b,num_neurons,keep_prob):
#將輸入變成一個列表,列表的長度及時間步數
inputs = tf.unstack(x,8,1)
cells = [lstm_cell(units=n,keep_prob = keep_prob) for n in num_neurons]
stacked_lstm_cells = tf.contrib.rnn.MultiRNNCell(cells)
outputs,_ = tf.contrib.rnn.static_rnn(stacked_lstm_cells,inputs,dtype=tf.float32)
return tf.matmul(outputs[-1],w) + b
if __name__ == '__main__':
#載入資料
(train_x,train_y) = load_data()
#定義placeholder
x = tf.placeholder(shape=(None,8,8),dtype=tf.float32)
y = tf.placeholder(shape=(None,1),dtype=tf.float32)
keep_prob = tf.placeholder(tf.float32,[])
#定義預測函式、損失函式、優化函式、初始函式、儲存函式
pred = lstm_net(x,w,b,num_neurons,keep_prob)
cost = tf.reduce_mean(tf.reshape(tf.pow((pred-y),2),[-1]))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=lr).minimize(cost)
init = tf.global_variables_initializer()
saver = tf.train.Saver(tf.global_variables())
#啟動互動式Session
sess = tf.InteractiveSession()
#訓練模型
sess.run(init)
losses = []#記錄每個epoch結束時的損失值
for epoch in range(epochs):
for step in range(train_x.shape[0]//batch_size+1):
batch_x = train_x[step*batch_size:(step+1)*batch_size]
batch_y = train_y[step*batch_size:(step+1)*batch_size]
sess.run(optimizer,feed_dict={x:batch_x,y:batch_y,keep_prob:kp})
loss = sess.run(cost,feed_dict={x:batch_x,y:batch_y,keep_prob:1.0})
losses.append(loss)
print('Epoch[{}/{}],Loss = {:.4f}\n'.format(epoch+1,epochs,loss))
#視覺化訓練過程
plt.plot(losses)
plt.ylim(0,1.2*max(losses))
plt.title('損失值隨迭代週期的改變')
plt.xlabel('Epoch')
plt.ylabel('損失值')
plt.show()
#儲存模型
#saver.save(sess,r'model_data\my_model.ckpt')
#關閉會話
sess.close()
訓練過程的損失曲線為:
使用模型進行預測
重頭戲來了,所謂是騾子還是馬,拉出來遛一遛就知道了,你的建模能力再強,資料處理能力再好,如果模型最終效果不行,都白搭。
要做預測,就要寫個predictor指令碼,方式其實更建模差不多,區別就是不用訓練引數,而是載入已經訓練好的引數,程式碼如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
plt.rcParams['font.sans-serif']=['SimHei']#顯示中文
plt.rcParams['axes.unicode_minus']=False#顯示負號
def load_data():
test_x_batch = np.load(r'test_x_batch.npy',allow_pickle=True)
test_y_batch = np.load(r'test_y_batch.npy',allow_pickle=True)
return (test_x_batch,test_y_batch)
#定義lstm單元
def lstm_cell(units):
cell = tf.contrib.rnn.BasicLSTMCell(num_units=units,forget_bias=0.0)#activation預設為tanh
return cell
#定義lstm網路
def lstm_net(x,w,b,num_neurons):
#將輸入變成一個列表,列表的長度及時間步數
inputs = tf.unstack(x,8,1)
cells = [lstm_cell(units=n) for n in num_neurons]
stacked_lstm_cells = tf.contrib.rnn.MultiRNNCell(cells)
outputs,_ = tf.contrib.rnn.static_rnn(stacked_lstm_cells,inputs,dtype=tf.float32)
return tf.matmul(outputs[-1],w) + b
#超引數
num_neurons = [32,32,64,64,128,128]
#定義輸出層的weight和bias
w = tf.Variable(tf.random_normal([num_neurons[-1],1]))
b = tf.Variable(tf.random_normal([1]))
#定義placeholder
x = tf.placeholder(shape=(None,8,8),dtype=tf.float32)
#定義pred和saver
pred = lstm_net(x,w,b,num_neurons)
saver = tf.train.Saver(tf.global_variables())
if __name__ == '__main__':
#開啟互動式Session
sess = tf.InteractiveSession()
saver.restore(sess,r'D:\股票預測\model_data\my_model.ckpt')
#載入資料
test_x,test_y = load_data()
#預測
predicts = sess.run(pred,feed_dict={x:test_x})
predicts = ((predicts.max() - predicts) / (predicts.max() - predicts.min()))#數學校準
#視覺化
plt.plot(predicts,'r',label='預測曲線')
plt.plot(test_y,'g',label='真實曲線')
plt.xlabel('第幾天/days')
plt.ylabel('開盤價(歸一化)')
plt.title('股票開盤價曲線預測(測試集)')
plt.legend()
plt.show()
#關閉會話
sess.close()
最終效果如圖所示:
後話
在訓練過程中,本人遇到過兩個問題,我將它們命名為顛倒性和超前/滯後性。前者是指,最終的預測曲線的趨勢與真實曲線完完全全相反,比如真實曲線上升達到極大值,預測曲線就下降達到極小值,然而,在將預測曲線上下顛倒後,其與真實曲線又能很好吻合!在經過仔細地研究和排查後,發現這種現象貌似不是來源於程式,而是具有隨機性,或者用哲學的話來說,感覺這是時序模型的一個種屬(就像性慾之於人類)。後者是所有時序模型的通病,就是說你的預測模型會永遠多多少少比真實模型超前或者滯後。怎麼說呢,這兩點的存在,使得預測和現實總是有個無法逾越的鴻溝。希望未來能看到能夠完美預測的時序模型。
相關文章
- 使用Tensorflow實現的基於LSTM的預測例項
- 基於LSTM模型的智慧選股策略模型
- 如何基於TensorFlow使用LSTM和CNN實現時序分類任務CNN
- 獲取和生成基於TensorFlow的MobilNet預訓練模型模型
- 基於Tensorflow影像分類模型的微服務模型微服務
- 模型預測不在行?別慌,收下這篇TensorFlow指南模型
- 數分專案-基於Cox風險比例模型的流失會員使用者預測模型
- 網路流量預測入門(三)之LSTM預測網路流量
- 基於XGBoost模型的幸福度預測——阿里天池學習賽模型阿里
- 基於WOA最佳化的CNN-LSTM的時間序列迴歸預測matlab模擬CNNMatlab
- 基於Python和TensorFlow實現BERT模型應用Python模型
- 基於WOA最佳化的CNN-LSTM-Attention的時間序列迴歸預測matlab模擬CNNMatlab
- 基於TensorFlow Serving的深度學習線上預估深度學習
- 基於大資料的使用者行為預測大資料
- 人口預測模型模型
- SiMBA:基於Mamba的跨影像和多元時間序列的預測模型模型
- 基於PSO粒子群最佳化的CNN-LSTM的時間序列迴歸預測matlab模擬CNNMatlab
- 發電機過速診斷研究 - 基於LSTM進行狀態監測
- 用TensorFlow實現ML模型並調優:每秒可做3億次預測模型
- 基於docker安裝tensorflowDocker
- 基於機器學習預測Airbnb的城市旅行成本機器學習AI
- Tensorflow-基礎使用
- 大模型+電力預測?大模型
- 基於 AI 大模型的精準測試分享AI大模型
- 如何用LSTMs做預測?(附程式碼)| 博士帶你學LSTM
- [譯] TensorFlow 教程預告 & #01 - 簡單線性模型模型
- 基於社會媒體的預測技術
- 使用pmml跨平臺部署機器學習模型Demo——房價預測機器學習模型
- 開發Bidirectional LSTM模型的簡單教程 | 博士帶你學LSTM模型
- Tensorflow實現RNN(LSTM)手寫數字識別RNN
- 基於滴滴雲虛擬機器的TensorFlow搭建與使用虛擬機
- 迴圈神經網路LSTM RNN迴歸:sin曲線預測神經網路RNN
- 基於BP神經網路的苦瓜生長含水量預測模型matlab模擬神經網路模型Matlab
- TensorFlow 呼叫預訓練好的模型—— Python 實現模型Python
- 7.6 模型擬合及預測模型
- Tensorflow神經網路預測股票均價神經網路
- 《深度學習——基於Tensorflow的實戰》公開課語音直播預告深度學習
- TensorFlow2.0教程-使用keras訓練模型Keras模型