基于Matlab的LSTM神经网络时序预测(完整代码+范例数据文件)
本文部分理論引用了:4 Strategies for Multi-Step Time Series Forecasting
Multivariate Time Series Forecasting with LSTMs in Keras (machinelearningmastery.com)
(更新于2022年10月,最近需要做相關的大型實驗,對這個LSTM神經網絡預測有了更深的認識,也發現以往有些概念是錯誤的,在這里記錄一下。有問題或者有其他預測需求可以直接私聊我一起交流,我有空的時候會看的。)
(1.首先題目的“時序多步預測”改為了“時序預測”,其實這個代碼算是一個多次的單步預測,而且并不需要一次性去預測兩步(如果需要改的話,需要改神經網絡預測中的交替時間步,可以用一個XTrain對應兩個YTrain中的兩個數,那就可以多步預測了。原理和結果詳情可見置頂的第二篇文章,里面基于Python提到了一次性預測兩步的問題),因為LSTM不斷在更新網絡,所以這樣反而精度下降了。但是那個在前文提到,交替一個時間步的預測效果是最好的,因為很顯然,只預測一步當然比預測兩步的效果好。)
(2.在文章中區分出lag和多步預測(預測步數為a)的概念。這個概念在之前有些混淆。lag指的是利用當前數據去預測下一個數據時中間隔了多少秒。預測步數a指的是利用當前數據去預測下一幾個時間步的數據。)
(網上資料繁雜眾多,而且到底如何預測也沒有一個準確答案,基本都是教如何訓練神經網絡以及驗證神經網絡的準確度的,但是都沒有一個神經網絡的實戰,本文將好好記錄一下我這些年的所思所感以及LSTM神經網絡在實驗中的應用,所用源代碼+數據(非實驗所用,經過簡化處理)將會以文件的方式供大家下載,有需要的自己去下載使用。希望能給大家啟發。)
LSTM時序預測神經網絡與NAR、NARx等時序預測神經網絡結構有著本質上的不同,像其他幾篇博客所述,通過觀察工作區發現,NAR和NARx的輸入實際上是“延遲向量”。LSTM神經網絡因為“門”這種特殊的概念引入,使其有著更長、更好的時間預測效果。?本文將根據LSTM有兩種預測方式,一種是根據預測值去更新網絡狀態,另外一種是根據觀測值去更新網絡狀態。
目錄
一、根據預測值去更新網絡狀態(單序列數據用)
Step1:加載數據,并進行數據預處理
Step2:交替一個時間步
Step3:定義LSTM網絡架構并訓練
Step4:初始化網絡狀態
Step5:利用LSTM網絡進行單步預測
Step6:將預測結果與實際數據對比
Step7:重置網絡狀態
二、根據觀測值去更新網絡狀態(實驗用)
Step1:加載數據,并進行數據預處理
Step2:構造交替5秒時間間隔的時間序列作為神經網絡的輸入和輸出。
Step3:神經網絡訓練
Step4:神經網絡預測+精度反映
Step5:神經網絡實際應用
一、根據預測值去更新網絡狀態(單序列數據用)
數據集、源碼地址:(直接運行就能用)
放在評論區了,放在文字里面沒法通過審核。
實現的是:已知前面幾年的數據,往后預測2023年的100天的數據。
Step1:加載數據,并進行數據預處理
clc clear load dataset.mat %加載數據(double型,剔除了2023年的的第一個數據,總共為2191個。時序預測沒有實際時間,只有事情發生的順序) data=data(:,2)'; %不轉置的話,無法訓練lstm網絡,顯示維度不對。 %% 序列的前2000個用于訓練,后191個用于驗證神經網絡,然后往后預測200個數據。 dataTrain = data(1:2000); %定義訓練集 dataTest = data(2001:2191); %該數據是用來在最后與預測值進行對比的 %% 數據預處理 mu = mean(dataTrain); %求均值 sig = std(dataTrain); %求均差 dataTrainStandardized = (dataTrain - mu) / sig;?LSTM對于數據標準化要求很高。且這里只對訓練集進行標準化的原因是經過神經網絡中的值只有訓練集,因此無須對測試集進行標準化。
Step2:交替一個時間步
%% 輸入的每個時間步,LSTM網絡學習預測下一個時間步,這里交錯一個時間步效果最好。 XTrain = dataTrainStandardized(1:end-1); YTrain = dataTrainStandardized(2:end);大多數LSTM相關的資料還是使用默認的a=1來將時間序列拆分為具有輸入和輸出分量的樣本。我在自己的其他試驗中使用不同的a來觀察(a=1,2,5,10)。這個a的意思是規定了一次性往后預測多少步。設置不同的預測步數a的目的是觀察是否能夠改善預測模型性能。但據某些驗證表明,增加滯后并不能改善預測模型的性能。其實也很好理解,單次預測精度肯定是比預測兩步的精度要高的。
a=1即輸入[[1],[2],[3],...,[10]]對應著輸出[[2],[3],[4],...[11]],a為2的時候即[[1],[2],[3],...,[10]]對應著[[2,3],[3,4],[4,5],...,[10,11]。
這里的交替時間步的作用是什么呢?
Step3:定義LSTM網絡架構并訓練
%% 一維特征lstm網絡訓練 numFeatures = 1; %特征為一維 numResponses = 1; %輸出也是一維 numHiddenUnits = 200; %創建LSTM回歸網絡,指定LSTM層的隱含單元個數200。可調layers = [ ...sequenceInputLayer(numFeatures) %輸入層lstmLayer(numHiddenUnits) % lstm層,如果是構建多層的LSTM模型,可以修改。fullyConnectedLayer(numResponses) %為全連接層,是輸出的維數。regressionLayer]; %其計算回歸問題的半均方誤差模塊 。即說明這不是在進行分類問題。%指定訓練選項,求解器設置為adam, 1000輪訓練。 %梯度閾值設置為 1。指定初始學習率 0.01,在 125 輪訓練后通過乘以因子 0.2 來降低學習率。 options = trainingOptions('adam', ...'MaxEpochs',1000, ...'GradientThreshold',1, ...'InitialLearnRate',0.01, ... 'LearnRateSchedule','piecewise', ...%每當經過一定數量的時期時,學習率就會乘以一個系數。'LearnRateDropPeriod',400, ... %乘法之間的紀元數由“ LearnRateDropPeriod”控制。可調'LearnRateDropFactor',0.15, ... %乘法因子由參“ LearnRateDropFactor”控制,可調'Verbose',0, ... %如果將其設置為true,則有關訓練進度的信息將被打印到命令窗口中。默認值為true。'Plots','training-progress'); %構建曲線圖 將'training-progress'替換為none net = trainNetwork(XTrain,YTrain,layers,options);需要提醒的是:在MATLAB中,其已經將LSTM網絡進行封裝,類似工具箱的形式,因此不再涉及底層的“門”概念。如果利用Python去編程,將會涉及到。
這里有三個參數很重要,第一個是numHiddenUnits,第二是LearnRateDropPeriod,第三個是LearnRateDropFactor,這三個需要根據你的數據集去改。如果RMSE曲線下降太慢,那么就可能是以下原因:(在本代碼中,需要將LearnRateDropPeriod改大。)
Step4:初始化網絡狀態
net = predictAndUpdateState(net,XTrain); %將新的XTrain數據用在網絡上進行初始化網絡狀態 [net,YPred] = predictAndUpdateState(net,YTrain(end)); %用訓練的最后一步來進行預測第一個預測值,給定一個初始值。這是用預測值更新網絡狀態特有的。訓練的最后一個,即預測的第一個。
Step5:利用LSTM網絡進行單步預測
%% 進行用于驗證神經網絡的數據預測(用預測值更新網絡狀態) for i = 2:291 %從第二步開始,這里進行191次單步預測(191為用于驗證的預測值,100為往后預測的值。一共291個)[net,YPred(:,i)] = predictAndUpdateState(net,YPred(:,i-1),'ExecutionEnvironment','cpu'); %predictAndUpdateState函數是一次預測一個值并更新網絡狀態 end在其他博客提到的NAR和NARx中,遞歸預測會一直累積誤差,以至于使性能迅速下降,但LSTM對比其他網絡獨有的是其有這個特殊的函數predictAndUpdateState能夠在每次預測時更新網絡狀態,因此其能夠預測更長的序列。
Step6:將預測結果與實際數據對比
%% 驗證神經網絡 YPred = sig*YPred + mu; %使用先前計算的參數對預測去標準化。 rmse = sqrt(mean((YPred(1:191)-dataTest).^2)) ; %計算均方根誤差 (RMSE)。 subplot(2,1,1) plot(dataTrain(1:end)) %先畫出前面2000個數據,是訓練數據。 hold on idx = 2001:(2000+191); %為橫坐標 plot(idx,YPred(1:191),'.-') %顯示預測值 hold off xlabel("Time") ylabel("Case") title("Forecast") legend(["Observed" "Forecast"]) subplot(2,1,2) plot(data) xlabel("Time") ylabel("Case") title("Dataset") %% 繼續往后預測2023年的數據 figure(2) idx = 2001:(2000+291); %為橫坐標 plot(idx,YPred(1:291),'.-') %顯示預測值 hold offStep7:重置網絡狀態
net = resetState(net);如果需要進行其他的預測,如進行下一輪300個的預測。需要重置一下網絡狀態。
訓練結果:
?
左圖表示的是,從2191個開始,往后預測了100個。右圖表示的是利用2001:2191個數據來驗證神經網絡的訓練結果,這里還是比較好的。
但在預測的時候,不能單從訓練集和預測集的數量以及比例去評價這個數據集的好壞,從理論上來說,訓練集應包含多個周期的變化,不然肯定無法通過此去進行預測。而且100個數據去預測30個數據這并不意味著用1000個數據去預測后面300個是一樣的表現,兩者是不相同的。
使預測模型更加精確的方法有:增加預測輸入的維度,即加入不同的特征(如下文所提到的多個波高儀)。同時需要注意的是,該模型僅適用于單序列預測(即僅有波浪力這個數據,去預測后面的波浪力,因此其實它的預測精度也是不高的。)
二、根據觀測值去更新網絡狀態(實驗用、多序列)
在實驗中的需求是:利用5個波高儀的波高數據去預測去一段時間間隔(5秒)后的波浪力。因此神經網絡訓練所需要的是足夠數量的波高、波浪力數據樣本,每一步將5個波高儀的數據去跟5秒后的波浪力數據進行對應即可。由于實驗數據不能泄露,因此大家可參透代碼根據自己的實際情況進行使用。
Step1:加載數據,并進行數據預處理
%% 將所有測得的數據切分為7500個數據和對數據進行標準化,消除變量之間的量綱關系,使數據具有可比性。 load testdata.mat %其中第一列為時間,第二列至第六列為波高數據,第七列為波浪力數據。 dt=0.01 %這里的每一步的間隔為0.01秒,可根據實際實驗采樣頻率情況來定。 time_lag=500; %這里指的是根據波高力數據預測5秒后的波浪力,這個間距可以自己根據實際來調整。 N_total=7500; %這里指的是7500個時間步 t=testdata(:,1); %時間,共有7500個。 std_scale=std(testdata(:,2:7)); %對波高數據和波浪力數據求標準差 testdata_norm(:,2:7) =normalize(testdata(:,2:7)); %將數據歸一化 lag=500;Step2:構造交替5秒時間間隔的時間序列作為神經網絡的輸入和輸出。
%% 首先先將時間步分割好 t_input=t(1:end-lag); %7000=7500-500。1:7000個 t_output=t(lag+1:end); %501:7500個%% 分割波高數據和波浪力數據 height_input(1:5,:)=testdata_norm(1:end-lag,2:6)'; %因此這里height_input中的每一行是一個波高儀的數據,一共有5個波高儀,每個波高儀收集了1-7500個時間步的波高信息。然后這里波高作為輸入,是只截取第1-7000個時間步的數據作為輸入。 height_output(1,:)=testdata_norm(lag+1:end,7)'; %這里指的是第501~7500個時間步的波浪力作為輸出。%% 決定網絡的輸入、輸出、總數 net_input=height_input; %1:7000,指代的是波高信息 net_output=height_output; %501:7500,指代的是波浪力信息 sample_size=length(height_output); %樣本總數7000Step3:神經網絡訓練
%% 訓練神經網絡參數設定 numHiddenUnits =5; %指定LSTM層的隱含單元個數為5 train_ratio= 0.8; %劃分用于神經網絡訓練的數據比例為總數的80% LearnRateDropPeriod=50; %乘法之間的紀元數由“ LearnRateDropPeriod”控制 LearnRateDropFactor=0.5; %乘法因子由參“ LearnRateDropFactor”控制,%% 定義訓練時的時間步。 numTimeStepsTrain = floor(train_ratio*numel(net_input(1,:))); %一共為7000個*0.8=5600個%% 交替一個時間步,可以交替多個時間步,但這里交替一個時間步的效果其實是最好的,詳見那篇開頭第二篇建立在python之上的文章。(真正想要改變往后預測時間的長短為lag這個變量。) XTrain = net_input(:, 1: numTimeStepsTrain+1); %1~5601,XTrain---input,一共為5601個 YTrain = net_output(:, 2: numTimeStepsTrain+2); %2~5602,YTrain---expected output,為5601個%% 輸入有5個特征,輸出有1個特征。 numFeatures = numel(net_input(:,1)); %5 numResponses = numel(net_output(:,1)); %1 layers = [ ...sequenceInputLayer(numFeatures) %輸入層為5lstmLayer(numHiddenUnits) %lstm層,構建5層的LSTM模型,fullyConnectedLayer(numResponses) %為全連接層,是輸出的維數。regressionLayer]; %其計算回歸問題的半均方誤差模塊 。即說明這不是在進行分類問題。options = trainingOptions('adam', ... %指定訓練選項,求解器設置為adam, 1000輪訓練。'MaxEpochs',150, ... %最大訓練周期為150'GradientThreshold',1, ... %梯度閾值設置為 1'InitialLearnRate',0.01, ... %指定初始學習率 0.01'LearnRateSchedule','piecewise', ... %每當經過一定數量的時期時,學習率就會乘以一個系數。'LearnRateDropPeriod', LearnRateDropPeriod, ... 'LearnRateDropFactor',LearnRateDropFactor, ... %在50輪訓練后通過乘以因子 0.5 來降低學習率。'Verbose',0, ... %如果將其設置為true,則有關訓練進度的信息將被打印到命令窗口中,0即是不打印 。'Plots','training-progress'); %構建曲線圖 ,不想構造就將'training-progress'替換為nonenet = trainNetwork(XTrain,YTrain,layers,options); %訓練神經網絡 save('LSTM_net', 'net'); %將net保存為LSTM_netendStep4:神經網絡預測+精度反映
%% 定義Xtest和Ytest,其目的是仿照神經網絡訓練中XTrain和YTrain的樣式去構造一個測試集 %% input_Test指的是實驗中得到的波高數據。 %% output_Test指的就是參與跟預測值進行對比的測量值。即expected output numTimeStepsTrain2 = floor(0.1*sample_size); %一共為7000個*0.1=700個。可以自己再隨意取一個比例,去嘗試一下。當然也可以跟上面的numTimeStepsTrain保持一致。 input_Test = net_input(:, numTimeStepsTrain2+1: end-1); %7000個中取701個~6999,一共是6299個 output_Test = net_output(:, numTimeStepsTrain2+2: end); %7000個取702:7000,為6299個,因為 numTimeStepsTrain是700.%% 這里首先用input_Train來初始化神經網絡。經過測試,不是將整個input_Train放進去最好,放其中一點比例即可。 input_Train = net_input(:, floor(numTimeStepsTrain*0.9): numTimeStepsTrain); %630~700 net = predictAndUpdateState(net, input_Train); %% 預測量預定義 rec_step=numel(output_Test); %滾動預測6299個。跟后面的j循環有關。 YPred=zeros(rec_step,1); %6299個預測,1個特征。這個預測是和Test來比對,看是否正確的。%% 神經網絡預測(這個也是之后實際預測需要用到的)for j=1: rec_step[net,YPred0] = predictAndUpdateState(net, input_Test(:, j)); %用input_Test代入剛剛用input_Train來更新的網絡得到第一個輸出并得到對應的預測值。YPred(j, :) = YPred0; %記錄輸出的預測值。end%% 神經網絡精度反映。這里的Y都是波浪力 YTest = output_Test(:,1:rec_step)'; %這一步可以簡化。其實只是一個轉置。 NRMSE=sqrt(sum((YPred-YTest).^2)/rec_step/(max(YTest)-min(YTest)));這里需要重點說明的是用input_Train來初始化神經網絡的問題。 因為在LSTM中,state cell是實時在更新的,但對于整個網絡需要給它一個初始化的值,但不一定是利用整個input_Train的效果最好,因此在實際使用中input_Train可以考慮給予一個比例,來讓其初始化。
Step5:神經網絡實際應用
rec_step=2; %這里只預測兩步 input_Test=[1;2;3;4;5,6;4;8;9;7]; %假設第一個時間步波高數據分別為1,2,3,4,5,第二個時間步波高數據分別為6;4;8;9;7。%% 神經網絡預測for j=1: rec_step[net,YPred0] = predictAndUpdateState(net, input_Test(:, j)); %用input_Test代入剛剛用input_Train來更新的網絡得到第一個輸出并得到對應的預測值。YPred(j, :) = YPred0; %記錄輸出2個的預測值。end假設已經同時得到了5個波高儀數據,需要預測5秒(在之前的神經網絡訓練中已經預設好了)后的波浪力。每次得到的波高數據應該是放在for循環里面,去不斷的進行單步預測。
?左邊是數據集,右邊是預測,我在預測中的輸入是2秒前的波高,預測了2秒后的波浪力。這個相當于多次的單步預測,還是相當的準確的。
總結
以上是生活随笔為你收集整理的基于Matlab的LSTM神经网络时序预测(完整代码+范例数据文件)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: log4j自定义配置文件(SpringM
- 下一篇: linux php cgi.sock,n