一文詳解?RNN?及股票預測實戰(zhàn)(Python)!
時間:2021-12-07 11:15:13
手機看文章
掃描二維碼
隨時隨地手機看文章
[導讀]作者|泳魚來源|算法進階循環(huán)神經網絡(RNN)是基于序列數據(如語言、語音、時間序列)的遞歸性質而設計的,是一種反饋類型的神經網絡,其結構包含環(huán)和自重復,因此被稱為“循環(huán)”。它專門用于處理序列數據,如逐字生成文本或預測時間序列數據(例如股票價格)。一、RNN網絡類型RNN以輸入數...
一、 RNN 網絡類型
RNN以輸入數m對應輸出數n的不同,可以劃分為5種基礎結構類型:
二、RNN原理
關于RNN模型,我們還是從數據、模型、學習目標、優(yōu)化算法這幾個要素展開解析,使用過程需要重點關注的是其輸入和輸出的差異(本節(jié)以經典的m==n的RNN結構為例)。2.1 數據層面
不像傳統的機器學習模型假設輸入是獨立的,RNN的輸入數據元素有順序及相互依賴的,并按時間步逐一的串行輸入模型的。上一步的輸入對下一步的預測是有影響的(如文字預測的任務,以“貓吃魚”這段序列文字,上一步的輸入“貓”--x(0)會影響下一步的預測“吃”--x(1)的概率,也會繼續(xù)影響下下步的預測“魚”--x(2)的概率),我們通過RNN結構就可以將歷史的(上下文)的信息反饋到下一步。2.2 模型層面及前向傳播
上圖展開了兩個時間步t-1及t的計算過程;t取值為0~m(序列的長度);x(t)是t時間步的 輸入向量;U是 輸入層到隱藏層的權重矩陣; h(t)是t時間步 隱藏層的輸出狀態(tài)向量,能表征歷史輸入(上下文)的反饋信息;V是 隱藏層到輸出層的權重矩陣;b是 偏置項;o(t)是t時間步 輸出層的輸出向量;
2.2.1 t 時間步的輸入過程
假設各時間步的狀態(tài)h的維度為2,h初始值為[0,0],輸入x和輸出o維度為1。將上一時刻的狀態(tài)h(t-1),與當前時刻的輸入x(t)拼接成一維向量作為全連接的隱藏層的輸入,對應隱藏層的的輸入維度為3 (如下圖的輸入部分)。
2.2.2 t時間步輸出h(t) 并反饋到下一步的過程
對應到計算流程圖上,t-1時刻輸出的狀態(tài)h(t-1)為[0.537, 0.462],t時刻的輸入為[2.0],拼接之后為[0.537, 0.462, 2.0]輸入全連接的隱藏層,隱藏層的權重矩陣為[[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]],偏置項b1為[0.1, -0.1],經過隱藏層的矩陣運算為:h(t-1)拼接x(t) * 權重參數W 拼接 權重矩陣U 偏置項(b1)再由tanh轉換后輸出為狀態(tài)h(t)。接著h(t)與x(t 1)繼續(xù)輸入到下一步(t 1)的隱藏層。# 隱藏層的矩陣運算的對應代碼np.tanh(np.dot(np.array([[0.537, 0.462, 2.0]]),np.array([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])) np.array([0.1, -0.1]))
# 輸出h(t)為:array([[0.85972772, 0.88365397]])
2.2.3 t時間步h(t) 到輸出o(t)的過程
隱藏層輸出狀態(tài)h(t)為[0.86, 0.884],輸出層權重矩陣為[[1.0], [2.0]],偏置項b1為[0.1], h(t)經由輸出層的矩陣運算為:h(t) * V 偏置項(b2)后,輸出o(t)# 輸出層的矩陣運算的對應代碼np.dot(np.array([[0.85972772, 0.88365397]]),np.array([[1.0], [2.0]])) np.array([0.1])
# o(t) 輸出: array([[2.72703566]])
上述過程從初始輸入(t=0)遍歷到序列結束(t=m),就是一個完整的前向傳播過程,我們可以看出權重矩陣、、和偏置項在不同時刻都是同一組,這也說明RNN在不同時刻中是共享參數的。可以將這RNN計算過程簡要概述為兩個公式:
狀態(tài)h(t) = f( U * x(t) W * h(t-1) b1), f為激活函數,上圖隱藏層用的是tanh。隱藏層激活函數常用tanh、relu
輸出o(t) = g( V * h(t) b2),g為激活函數,上圖輸出層做回歸預測,沒有用非線性激活函數。當用于分類任務,輸出層一般用softmax激活函數
2.3 學習目標
RNN模型將輸入 x(t)序列映射到輸出值 o(t)后, 同全連接神經網絡一樣,可以衡量每個 o(t) 與相應的訓練目標 y 的誤差(如交叉熵、均方誤差)作為損失函數,以最小化損失函數L(U,W,V)作為學習目標(也可以稱為優(yōu)化策略)。
2.4 優(yōu)化算法
RNN的優(yōu)化過程與全連接神經網絡沒有本質區(qū)別,通過誤差反向傳播,多次迭代梯度下降優(yōu)化參數,得到合適的RNN模型參數 (此處忽略偏置項) 。區(qū)別在于RNN是基于時間反向傳播,所以RNN的反向傳播有時也叫做BPTT(back-propagation through time),BPTT會對不同時間步的梯度求和,由于所有的參數在序列的各個位置是共享的,反向傳播時我們更新的是相同的參數組。如下BPTT示意圖及U,W,V求導(梯度)的過程。
- RNN優(yōu)化的難點
2.5 RNN的局限性
- 上述展示的都是單向的 RNN,單向 RNN 有個缺點是在 t 時刻,無法使用 t 1 及之后時刻的序列信息,所以就有了雙向循環(huán)神經網絡(bidirectional RNN)。
- 理論上RNN能夠利用任意長序列的信息,但是實際中它能記憶的長度是有限的,經過一定的時間后將導致梯度爆炸或者梯度消失(如上節(jié)),即長期依賴(long-term dependencies)問題。一般的,使用傳統RNN常需要對序列限定個最大長度、設定梯度截斷以及引導信息流的正則化,或者使用門控RNN 如GRU、LSTM 以改善長期依賴問題。
三、 RNN預測股票
本項目通過創(chuàng)建單層隱藏層的RNN模型,輸入前60個交易日(時間步)股票開盤價的時間序列數據,預測下一個(60 1)交易日的股票開盤價。
import matplotlib.pyplot as plt
import pandas as pd
#(本公眾號閱讀原文訪問數據集及源碼)
dataset_train = pd.read_csv('./data/NSE-TATAGLOBAL.csv')
dataset_train = dataset_train.sort_values(by='Date').reset_index(drop=True)
training_set = dataset_train.iloc[:, 1:2].values
print(dataset_train.shape)
dataset_train.head()
對訓練數據進行歸一化,加速網絡訓練收斂。
from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler(feature_range = (0, 1))
training_set_scaled = sc.fit_transform(training_set)
將數據整理為樣本及標簽:60 timesteps and 1 output# 每條樣本含60個時間步,對應下一時間步的標簽值
X_train = []
y_train = []
for i in range(60, 2035):
X_train.append(training_set_scaled[i-60:i, 0])
y_train.append(training_set_scaled[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)
print(X_train.shape)
print(y_train.shape)
# Reshaping
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
print(X_train.shape)
利用kera創(chuàng)建單隱藏層的RNN模型,并設定模型優(yōu)化算法adam, 目標函數均方根MSE
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import SimpleRNN,LSTM
from keras.layers import Dropout
# 初始化順序模型
regressor = Sequential()
# 定義輸入層及帶5個神經元的隱藏層
regressor.add(SimpleRNN(units = 5, input_shape = (X_train.shape[1], 1)))
# 定義線性的輸出層
regressor.add(Dense(units = 1))
# 模型編譯:定義優(yōu)化算法adam, 目標函數均方根MSE
regressor.compile(optimizer = 'adam', loss = 'mean_squared_error')
# 模型訓練
history = regressor.fit(X_train, y_train, epochs = 100, batch_size = 100, validation_split=0.1)
regressor.summary()
展示模型擬合的情況:訓練集、驗證集均有較低的loss
plt.plot(history.history['loss'],c='blue') # 藍色線訓練集損失
plt.plot(history.history['val_loss'],c='red') # 紅色線驗證集損失
plt.show()
評估模型:以新的時間段的股票交易系列數據作為測試集,評估模型測試集的表現。# 測試數據
dataset_test = pd.read_csv('./data/tatatest.csv')
dataset_test = dataset_test.sort_values(by='Date').reset_index(drop=True)
real_stock_price = dataset_test.iloc[:, 1:2].values
dataset_total = pd.concat((dataset_train['Open'], dataset_test['Open']), axis = 0)
inputs = dataset_total[len(dataset_total) - len(dataset_test) - 60:].values
inputs = inputs.reshape(-1,1)
inputs = sc.transform(inputs)
# 提取測試集
X_test = []
for i in range(60, 76):
X_test.append(inputs[i-60:i, 0])
X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
# 模型預測
predicted_stock_price = regressor.predict(X_test)
# 逆歸一化
predicted_stock_price = sc.inverse_transform(predicted_stock_price)
# 模型評估
print('預測與實際差異MSE',sum(pow((predicted_stock_price - real_stock_price),2))/predicted_stock_price.shape[0])
print('預測與實際差異MAE',sum(abs(predicted_stock_price - real_stock_price))/predicted_stock_price.shape[0])
通過測試集評估,預測與實際差異MSE:53.03141531,預測與實際差異MAE :5.82196445??梢暬A測值與實際值的差異情況,整體比較一致(注:本文僅從數據規(guī)律維度預測股價,僅供參考不構成任何投資建議,虧光了別找我)。
plt.plot(real_stock_price, color = 'red', label = 'Real TATA Stock Price')
plt.plot(predicted_stock_price, color = 'blue', label = 'Predicted TAT Stock Price')
plt.title('TATA Stock Price Prediction')
plt.xlabel('samples')
plt.ylabel('TATA Stock Price')
plt.legend()
plt.show()