摘要:神經(jīng)網(wǎng)絡(luò)是機(jī)器學(xué)習(xí)中的熱門話題河哑。但是網(wǎng)絡(luò)上有關(guān)LSTM在時(shí)間序列上的應(yīng)用卻很少洞就,我們不妨透過本文來開拓LSTM的應(yīng)用視野夕膀。
作者介紹:
Jakob Aungiers 現(xiàn)就職于匯豐銀行倫敦總部功蜓,擔(dān)任全球資產(chǎn)管理的開發(fā)副總裁逝撬。擅長機(jī)器學(xué)習(xí)冷溃,神經(jīng)網(wǎng)絡(luò)等領(lǐng)域钱磅。
(以下為譯文)
談及機(jī)器學(xué)習(xí),神經(jīng)網(wǎng)絡(luò)無疑是當(dāng)前的熱門話題似枕。因此盖淡,在網(wǎng)絡(luò)上圍繞神經(jīng)網(wǎng)絡(luò)的教程和社區(qū)多不勝數(shù)。現(xiàn)在雖然有大量的公共研究論文和文章涉及LSTM凿歼,但我發(fā)現(xiàn)褪迟,這些理論和例子并沒有顯示出LSTM在時(shí)間序列預(yù)測(cè)上的真正實(shí)力。有鑒于此答憔,我決定以本文作拋磚引玉之用味赃,使用LSTM來預(yù)測(cè)一些時(shí)間序列—例如股市(使用Keras包,對(duì)應(yīng)Python版本為2.7)虐拓。
此項(xiàng)目的完整代碼可以在GitHub頁面上找到(鏈接)心俗。
簡單的正弦波
讓我們從最基本的事情開始----標(biāo)準(zhǔn)正弦波函數(shù)。首先創(chuàng)建數(shù)據(jù)侯嘀,然后模擬這個(gè)函數(shù)的多個(gè)振蕩另凌,以便進(jìn)行LSTM網(wǎng)絡(luò)訓(xùn)練谱轨。我做了一個(gè)excel電子表格,這是一個(gè)幅度和頻率為1(給出角頻率為6.28)的正弦波吠谢,我使用該函數(shù)獲得超過5001個(gè)數(shù)據(jù)點(diǎn)的時(shí)間段土童,時(shí)間增量為0.01。其結(jié)果看起來是這樣的:
(用作訓(xùn)練/測(cè)試文件的鏈接在這里)
這些數(shù)據(jù)有什么用呢工坊?LSTM將從這一組窗口大小數(shù)據(jù)值來學(xué)習(xí)正弦波献汗,然后LSTM會(huì)據(jù)此來進(jìn)行時(shí)序預(yù)測(cè)以畫出n步后的波形圖。
我們首先從CSV文件中轉(zhuǎn)換和載入數(shù)據(jù)到numpy數(shù)組中王污,然后喂食LSTM罢吃。Keras LSTM層的工作方式是通過接收3維(N,W昭齐,F(xiàn))的數(shù)字陣列尿招,其中N是訓(xùn)練序列的數(shù)目,W是序列長度阱驾,F(xiàn)是每個(gè)序列的特征數(shù)目就谜。我選擇的一個(gè)序列長度(讀取窗口大小)為50里覆,這可讓網(wǎng)絡(luò)在每個(gè)序列中知道正弦波的形狀丧荐,從而教會(huì)自身基于先前窗口信息的前提下建立序列的模式。序列本身是滑動(dòng)的窗口喧枷,因此每次移動(dòng)1長度后虹统,會(huì)保持與先前窗口的恒定重疊。
長度為50的序列的示例
下面是將訓(xùn)練數(shù)據(jù)CSV加載到正確形狀numpy數(shù)組中的代碼:
def load_data(filename):? ? f =open('sinwave.csv','rb').read()? ? data = f.split('\r\n')? ? sequence_length =50result= []forindexinrange(len(data) - sequence_length):result.append(data[index: index + sequence_length])result= np.array(result)? ? row =round(0.9*result.shape[0])? ? train =result[:row, :]? ? np.random.shuffle(train)? ? x_train = train[:, :-1]? ? y_train = train[:,-1]? ? x_test =result[row:, :-1]? ? y_test =result[row:,-1]? ? x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1],1))? ? x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1],1))return[x_train, y_train, x_test, y_test]
接下來隧甚,我們需要實(shí)際構(gòu)建網(wǎng)絡(luò)本身车荔。我使用了[1,50,100,1]的網(wǎng)絡(luò)結(jié)構(gòu),其中我們有1個(gè)輸入層(由大小為50的序列組成)呻逆,該輸入層喂食50個(gè)神經(jīng)元給LSTM層夸赫,接著該LSTM層喂食100個(gè)神經(jīng)元給另一個(gè)LSTM層,然后使用一個(gè)線性激活函數(shù)來喂食一個(gè)完全連接的正常層以用于下一個(gè)時(shí)間步的預(yù)測(cè)咖城。
模型構(gòu)建函數(shù)代碼如下:
def build_model(layers):? ? model = Sequential()? ? model.add(LSTM(? ? ? ? input_dim=layers[0],? ? ? ? output_dim=layers[1],? ? ? ? return_sequences=True))? ? model.add(Dropout(0.2))? ? model.add(LSTM(? ? ? ? layers[2],? ? ? ? return_sequences=False))? ? model.add(Dropout(0.2))? ? model.add(Dense(? ? ? ? output_dim=layers[3]))? ? model.add(Activation("linear"))start=time.time()? ? model.compile(loss="mse", optimizer="rmsprop")? ? print"Compilation Time : ",time.time() -startreturnmodel
最后是訓(xùn)練網(wǎng)絡(luò)上的數(shù)據(jù)茬腿,看看我們得到了什么。在該LSTM我只使用了1個(gè)訓(xùn)練時(shí)期宜雀,這有別于需要大量訓(xùn)練數(shù)據(jù)的傳統(tǒng)網(wǎng)絡(luò)切平。因?yàn)槲覀兪褂玫氖呛喌木呖深A(yù)測(cè)模式的正弦波,1訓(xùn)練時(shí)期將足夠獲得非常近似的全sin函數(shù)辐董。
放入run.py模塊后的代碼:
epochs? =1seq_len =50print'Loading data... 'X_train, y_train, X_test, y_test = lstm.load_data('sinwave.csv')print'\nData Loaded. Compiling...\n'model= lstm.build_model([1,50,100,1])model.fit(? ? X_train,? ? y_train,? ? batch_size=512,? ? nb_epoch=epochs,? ? validation_split=0.05)predicted = lstm.predict_point_by_point(model, X_test)
如果你注意到你會(huì)注意到我們?cè)谏厦娴膌oad_data()函數(shù)中悴品,我們將數(shù)據(jù)分為訓(xùn)練/測(cè)試集,這是機(jī)器學(xué)習(xí)問題的標(biāo)準(zhǔn)做法。然而苔严,我們需要注意的是定枷,我們實(shí)際上想要在時(shí)間序列實(shí)現(xiàn)預(yù)測(cè)。
如果我們使用測(cè)試集届氢,我們將運(yùn)行每個(gè)窗口的真實(shí)數(shù)據(jù)來預(yù)測(cè)下一個(gè)時(shí)間步欠窒。下圖是使用該方法后的結(jié)果:
epochs = 1, window size = 50
然而,如果我們想要預(yù)測(cè)許更多的時(shí)間步退子,我們需使用來自測(cè)試數(shù)據(jù)的第一個(gè)窗口作為啟動(dòng)窗口岖妄。 在每個(gè)時(shí)間步,彈出窗口后面的最先條目寂祥,并將下一個(gè)時(shí)間步預(yù)測(cè)附加到窗口的前面荐虐,實(shí)質(zhì)上是移動(dòng)窗口,所以它是慢慢地用預(yù)測(cè)建立自己丸凭,直到窗口都是預(yù)測(cè)值(在我們的例子中福扬,因?yàn)槲覀兊拇翱诖笮?0,這將發(fā)生在50個(gè)時(shí)間步之后)惜犀。 然后忧换,我們無限期地保持這一點(diǎn),預(yù)測(cè)下一步對(duì)未來時(shí)間步驟的預(yù)測(cè)向拆,從而實(shí)現(xiàn)看到趨勢(shì)預(yù)測(cè)。
下圖顯示了僅從真實(shí)測(cè)試數(shù)據(jù)的初始開始窗口預(yù)測(cè)的正弦波時(shí)間序列酪耳,然后預(yù)測(cè)約500步:
epochs = 1, window size = 50
除了簡單的正弦波預(yù)測(cè)浓恳,LSTM還能做更復(fù)雜的預(yù)測(cè)嗎?答案是肯定的碗暗,例如以下的有關(guān)股票市場(chǎng)的時(shí)間序列預(yù)測(cè)颈将。什么?言疗!股票預(yù)測(cè)G缁!是的噪奄。這是LSTM另一個(gè)技能--潛在隱藏趨勢(shì)預(yù)判死姚。
首先我準(zhǔn)備了一個(gè)CSV文件(鏈接),其保存的是標(biāo)準(zhǔn)普爾500股權(quán)指數(shù)從2000年1月到2016年8月的收盤數(shù)據(jù)勤篮。我使它與我們的正弦波數(shù)據(jù)具完全相同的格式都毒,然后運(yùn)行相同的模型。
這之前我們需要對(duì)我們的數(shù)據(jù)做一個(gè)微小的改變碰缔,因?yàn)檎也ㄒ呀?jīng)是一個(gè)很規(guī)范的重復(fù)模式账劲,但股票數(shù)據(jù)是不規(guī)范的。因此為了應(yīng)對(duì)這種情況,我們需要使訓(xùn)練/測(cè)試數(shù)據(jù)的每個(gè)n大小的窗口進(jìn)行標(biāo)準(zhǔn)化瀑焦,以反映從該窗口開始的百分比變化(因此點(diǎn)i = 0處的數(shù)據(jù)將始終為0)腌且。我們將使用以下方程式進(jìn)行歸一化,然后在預(yù)測(cè)過程結(jié)束時(shí)進(jìn)行反標(biāo)準(zhǔn)化榛瓮,以得到預(yù)測(cè)中的真實(shí)世界數(shù):
n =價(jià)格變化的標(biāo)準(zhǔn)化列表[窗口]
p =原始列表[窗口]調(diào)整的每日回報(bào)價(jià)格
標(biāo)準(zhǔn)化公式:
反標(biāo)準(zhǔn)化公式:
在代碼中添加一個(gè)normalise_windows(window_data)函數(shù)铺董,并更新load_data(filename)函數(shù)以包含一個(gè)條件調(diào)用,以及獲取序列長度和規(guī)范化標(biāo)志load_data(filename榆芦,seq_len柄粹,normalise_window):
代碼如下:
def load_data(filename, seq_len, normalise_window):? ? f =open(filename,'rb').read()? ? data = f.split('\r\n')? ? sequence_length = seq_len +1result= []forindexinrange(len(data) - sequence_length):result.append(data[index: index + sequence_length])ifnormalise_window:result= normalise_windows(result)result= np.array(result)? ? row =round(0.9*result.shape[0])? ? train =result[:row, :]? ? np.random.shuffle(train)? ? x_train = train[:, :-1]? ? y_train = train[:,-1]? ? x_test =result[row:, :-1]? ? y_test =result[row:,-1]? ? x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1],1))? ? x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1],1))return[x_train, y_train, x_test, y_test]def normalise_windows(window_data):? ? normalised_data = []forwindowinwindow_data:? ? ? ? normalised_window = [((float(p) / float(window[0])) -1)forpinwindow]? ? ? ? normalised_data.append(normalised_window)returnnormalised_data
歸一化了如上所述的窗口后,我們現(xiàn)在可以通過LSTM網(wǎng)絡(luò)運(yùn)行我們的股票數(shù)據(jù)匆绣。 讓我們看看它的運(yùn)行情況:
在如上所述的單個(gè)逐點(diǎn)預(yù)測(cè)上運(yùn)行數(shù)據(jù)給出了與實(shí)際相當(dāng)接近的圖形驻右。但這是欺騙性的!為什么崎淳?如果你更仔細(xì)地看堪夭,預(yù)測(cè)線由單一的預(yù)測(cè)點(diǎn)組成,它們?cè)谒鼈冎缶哂姓麄€(gè)先前的真實(shí)歷史窗口拣凹。因此森爽,網(wǎng)絡(luò)并不依賴時(shí)間序列本身,除了每下一個(gè)點(diǎn)可能不會(huì)離最后一點(diǎn)太遠(yuǎn)嚣镜。因此爬迟,即使它得到錯(cuò)誤預(yù)測(cè)的點(diǎn),下一個(gè)預(yù)測(cè)可在考慮真實(shí)歷史后忽略不正確的預(yù)測(cè)菊匿,并允許再次出現(xiàn)錯(cuò)誤付呕。
那么,我們來看看是否真的有一些潛在的模式在價(jià)格中變動(dòng)切可辨別跌捆?接下來讓我們做對(duì)正弦波問題做的同樣事情徽职,讓網(wǎng)絡(luò)預(yù)測(cè)點(diǎn)序列而不是下一個(gè)點(diǎn)。
這樣佩厚,我們現(xiàn)在可以看到姆钉,與作為正弦波序列的正弦波不同,它與真實(shí)數(shù)據(jù)幾乎相同抄瓦,我們的股票數(shù)據(jù)預(yù)測(cè)很快地收斂到某種平衡潮瓶。
epochs = 50, window size = 50
epochs = 1, window size = 50
讓我們進(jìn)一步研究回歸收斂,將我們的預(yù)測(cè)序列限制到50個(gè)未來時(shí)間步長钙姊,然后每次將啟動(dòng)窗口移動(dòng)50單位:
epochs = 1, window size = 50, sequence shift = 50
而當(dāng)epochs增加到400時(shí)(這應(yīng)該使模型模式更準(zhǔn)確)筋讨,我們看到,實(shí)際上它現(xiàn)在只是試圖預(yù)測(cè)幾乎每個(gè)時(shí)間段的向上動(dòng)量摸恍。
epochs = 400, window size = 50, sequence shift = 50
小結(jié):
LSTM的應(yīng)用日益廣泛悉罕,例如文本預(yù)測(cè)赤屋,AI智能聊天,自駕車等許多前沿領(lǐng)域壁袄。 希望本文能有助你開拓LSTM在時(shí)間序列中應(yīng)用的視野类早。
本文由北郵@愛可可-愛生活老師推薦,阿里云云棲社區(qū)組織翻譯嗜逻。
文章原標(biāo)題《LSTM NEURAL NETWORK FOR TIME SERIES PREDICTION》涩僻,作者:Jakob Aungiers ,譯者:伍昆
文章為簡譯栈顷,更為詳細(xì)的內(nèi)容逆日,請(qǐng)查看**原文**
注:本文轉(zhuǎn)自網(wǎng)絡(luò),僅供交流學(xué)習(xí)使用萄凤,權(quán)利歸原作者所有室抽,如有侵權(quán),請(qǐng)聯(lián)系刪除靡努。