回歸時間序列區(qū)間預(yù)測)
簡介這份MATLAB資源面向需要開展時間序列區(qū)間預(yù)測的研究人員與工程師尤其適用于風(fēng)速、負(fù)荷、功率等單變量數(shù)據(jù)的預(yù)測場景?;贚STM神經(jīng)網(wǎng)絡(luò)與分位數(shù)回歸方法程序可輸出不同置信水平下的預(yù)測區(qū)間而不僅是單點預(yù)測能較好捕捉非線性時間序列的長期依賴與不確定性。壓縮包體積僅20KB共包含5個文件其中4個為.m腳本涵蓋主程序、分位數(shù)回歸層定義及區(qū)間覆蓋率指標(biāo)計算等功能模塊另有1個Excel數(shù)據(jù)文件便于直接替換數(shù)據(jù)驗證模型。已有496人學(xué)習(xí)下載。資源運行環(huán)境為MATLAB 2018及以上版本輸入輸出均為單個變量結(jié)構(gòu)緊湊、注釋清晰適合剛接觸區(qū)間預(yù)測的讀者快速上手也方便在此基礎(chǔ)上擴(kuò)展多變量或不同數(shù)據(jù)集應(yīng)用是一份兼具教學(xué)與實用價值的小型示例程序包。1. 為什么用QRLSTM分位數(shù)回歸給LSTM補上不確定性的短板時間序列區(qū)間預(yù)測最怕的不是預(yù)測不準(zhǔn)而是模型只會給一個點估計卻答不上“這個預(yù)測有多大的可能落在哪個范圍里”。QRLSTM就是來解決這個問題的把分位數(shù)回歸與長短期記憶神經(jīng)網(wǎng)絡(luò)結(jié)合起來用LSTM提取時序依賴用分位數(shù)損失訓(xùn)練多個輸出頭一次性給出低、中、高分位數(shù)對應(yīng)的預(yù)測區(qū)間。MATLAB里實現(xiàn)這套QRLSTM不需要復(fù)雜環(huán)境Deep Learning Toolbox自帶LSTM和自定義回歸層配合完整程序和數(shù)據(jù)能直接復(fù)現(xiàn)并接到自己的業(yè)務(wù)數(shù)據(jù)上。適合做風(fēng)速、負(fù)荷、銷量、水位這類單變量或多變量時間序列區(qū)間預(yù)測的工程師和學(xué)生。要跑通它關(guān)鍵在于分位數(shù)損失函數(shù)、序列滑窗構(gòu)造以及輸出層的分位數(shù)個數(shù)設(shè)計。2. 區(qū)間預(yù)測的數(shù)學(xué)基礎(chǔ)分位數(shù)損失、LSTM結(jié)構(gòu)與預(yù)測區(qū)間構(gòu)建2.1 分位數(shù)回歸與pinball lossLSTM的損失函數(shù)怎么改普通回歸網(wǎng)絡(luò)用均方誤差學(xué)的是給定輸入下的條件均值。但區(qū)間預(yù)測需要多個條件分位數(shù)比如5%分位數(shù)和95%分位數(shù)。分位數(shù)回歸做的事情不是換個網(wǎng)絡(luò)結(jié)構(gòu)而是把損失函數(shù)換成pinball loss也叫分位數(shù)損失。對于第τ個分位數(shù)定義誤差e y - y_hat損失函數(shù)為當(dāng)y ≥ y_hat即預(yù)測偏低損失為 τ * |e|當(dāng)y y_hat即預(yù)測偏高損失為 (1-τ) * |e|。寫成MATLAB風(fēng)格就是max(τ*e, (τ-1)*e)。這個表達(dá)式把兩種情況統(tǒng)一了因為當(dāng)τ0.5時退化為絕對誤差的一半所以中位數(shù)分位數(shù)對應(yīng)的就是最小絕對偏差回歸。τ越接近0模型對低于預(yù)測值的誤差懲罰越重于是預(yù)測值會偏向低分位τ越接近1則偏向高分位。QRLSTM的核心就是把LSTM最后一個時間步的隱藏狀態(tài)接到一個全連接層上輸出一組分?jǐn)?shù)每個分?jǐn)?shù)對應(yīng)一個τ然后對每個輸出分別計算pinball loss并求和取平均。這樣LSTM學(xué)到的隱藏特征被共享給所有分位數(shù)而不是為每個分位數(shù)單獨訓(xùn)練一個模型。為什么不能用MSE再加個殘差方差因為MSE假設(shè)殘差是正態(tài)分布且方差恒定而時間序列的波動經(jīng)常是異方差的預(yù)測殘差在不同時段寬度完全不同。直接用分位數(shù)回歸不需要假設(shè)分布形態(tài)只要損失函數(shù)是凸的理論上就能逼近條件分位數(shù)。這是QRLSTM的吸引力所在也是后續(xù)所有實現(xiàn)步驟的根據(jù)。2.2 LSTM為什么適合分位數(shù)回歸共享特征與序列依賴LSTM長短期記憶神經(jīng)網(wǎng)絡(luò)通過輸入門、遺忘門和輸出門控制信息流動能記住幾百步之前的相關(guān)信息這對風(fēng)速、負(fù)荷、水流這類有明顯時序依賴的數(shù)據(jù)很關(guān)鍵。在MATLAB的Deep Learning Toolbox里調(diào)用lstmLayer就能拿到一個可訓(xùn)練的網(wǎng)絡(luò)層。QRLSTM的結(jié)構(gòu)不復(fù)雜sequenceInputLayer輸入過去一段時間的觀測值lstmLayer輸出最后一個時間步的狀態(tài)再經(jīng)過全連接層輸出多個分位數(shù)。這里有個很有用的特性分位數(shù)輸出共享同一個LSTM隱狀態(tài)。這意味著網(wǎng)絡(luò)只用一次前向計算就能同時得到所有分位數(shù)預(yù)測訓(xùn)練速度比分別訓(xùn)練五個模型快得多。而且不同分位數(shù)之間通過共享特征相互約束一個分位數(shù)學(xué)習(xí)到的趨勢信息會影響另一個分位數(shù)整體上比獨立模型更平滑。實踐中常見做法是把分位數(shù)個數(shù)控制在5到9個太少畫不出區(qū)間形狀太多會讓輸出層參數(shù)量變大在中小樣本上反而容易過擬合。還有一種做法是把分位數(shù)作為額外輸入讓網(wǎng)絡(luò)自己學(xué)習(xí)分位數(shù)條件但在MATLAB里直接多輸出的方式更直觀。fullyConnectedLayer(numQuantiles)的輸出維度就是分位數(shù)個數(shù)不需要額外條件輸入。要注意的是輸出層不要接Softmax或Sigmoid分位數(shù)回歸輸出在實數(shù)域上激活函數(shù)會讓邊界分位數(shù)失真。2.3 從多個分位數(shù)到預(yù)測區(qū)間覆蓋率和區(qū)間寬度的權(quán)衡有了τ0.05、0.25、0.5、0.75、0.95這組輸出后預(yù)測區(qū)間怎么拼出來最直觀的做法是取一對對稱分位數(shù)比如0.05和0.95對應(yīng)90%區(qū)間0.25和0.75對應(yīng)50%區(qū)間。區(qū)間上界和下界直接就是對應(yīng)分位數(shù)的預(yù)測值。中位數(shù)0.5分位數(shù)可以作為確定性的點預(yù)測比直接用MSE模型多點一個信息點預(yù)測和邊界同時給出來。但區(qū)間不是越窄越好。一個始終預(yù)測整個訓(xùn)練數(shù)據(jù)范圍的區(qū)間覆蓋率高但沒有信息量一個只覆蓋一個點的區(qū)間信息量高但覆蓋率低。實際評估常用兩個指標(biāo)預(yù)測區(qū)間覆蓋率PICP統(tǒng)計測試集里真實值落入上下界的比例區(qū)間平均寬度在滿足覆蓋率的前提下越窄越好。QRLSTM訓(xùn)練時通過不同τ的損失權(quán)重自然平衡這兩個目標(biāo)但訓(xùn)練數(shù)據(jù)不均勻時容易出現(xiàn)某個分位數(shù)偏移需要在驗證集上做校準(zhǔn)這個第6章再展開。3. MATLAB完整實現(xiàn)QRLSTM數(shù)據(jù)構(gòu)造、自定義損失層、訓(xùn)練與預(yù)測3.1 數(shù)據(jù)準(zhǔn)備與滑窗建序列我平時跑通一個方案第一步是先驗證流程再用真實數(shù)據(jù)。下面的程序生成一段帶趨勢、季節(jié)項和噪聲的模擬時間序列長度1000點方便復(fù)現(xiàn)和檢查代碼邏輯。如果手里有真實數(shù)據(jù)把data替換成自己的列向量就可以但要保證它是等間隔采樣的。% 生成模擬時間序列趨勢 季節(jié) 噪聲 rng(42); T 1000; t (1:T); data 10 * sin(t / 50) 2 * sin(t / 10) 0.02 * t 0.6 * randn(T, 1);這段數(shù)據(jù)有基礎(chǔ)的周期性和逐漸上升的趨勢加上高斯噪聲能看出區(qū)間預(yù)測在中波動時段的表現(xiàn)。參數(shù)0.6控制噪聲幅度可以根據(jù)需要調(diào)大調(diào)小。然后是滑窗構(gòu)造特征和響應(yīng)核心是保證每個樣本都用過去inputSteps個點預(yù)測下一個點。inputSteps 24; % 用過去24個時刻預(yù)測下一個時刻 numSamples T - inputSteps; X cell(numSamples, 1); Y zeros(numSamples, 1); for i 1:numSamples X{i} data(i:iinputSteps-1, :); % 24x1 序列 Y(i) data(iinputSteps); % 真實未來值 end這里X是cell數(shù)組每個元素是一個24×1的序列MATLAB的trainNetwork自帶的序列分塊機制能直接處理這種格式。Y是標(biāo)量響應(yīng)但后面會被復(fù)制成多個分位數(shù)對應(yīng)的矩陣。參數(shù)inputSteps是最敏感的旋鈕之一對于小時級負(fù)荷數(shù)據(jù)24步可能代表一天對于分鐘級數(shù)據(jù)24步可能不夠周期信息要加大到48或72?;爸丿B意味著相鄰訓(xùn)練樣本有19個點是重復(fù)的這不會造成信息泄漏因為預(yù)測目標(biāo)始終在當(dāng)前窗口之后的那個點。3.2 自定義分位數(shù)回歸層繼承RegressionLayer實現(xiàn)pinball lossMATLAB訓(xùn)練網(wǎng)絡(luò)有兩種路徑一種是用trainNetwork搭配自定義層代碼簡潔另一種是用dlnetwork寫訓(xùn)練循環(huán)靈活但繁瑣。QRLSTM的分位數(shù)損失不是內(nèi)置層所以需要自定義一個回歸層。下面是完整的層定義保存為quantileRegressionLayer.m。classdef quantileRegressionLayer nnet.layer.RegressionLayer properties Quantiles end methods function layer quantileRegressionLayer(quantiles, name) layer.Quantiles quantiles(:); layer.Name name; end function loss forwardLoss(layer, Y, T) q layer.Quantiles; % numQuantiles x 1 diff T - Y; % numQuantiles x N loss mean(mean(max(q .* diff, (q - 1) .* diff), 1), 2); end end end這個層的作用是計算整個mini-batch的平均pinball loss。Y是網(wǎng)絡(luò)輸出形狀是numQuantiles x NT是目標(biāo)值在訓(xùn)練前需要把真實值復(fù)制成同樣形狀。max(q.*diff, (q-1).*diff)同時處理了正負(fù)誤差兩種情況。mean(mean(...))先對分位數(shù)維度平均再對樣本維度平均得到標(biāo)量損失。這個向量化寫法比for循環(huán)快不少親測在GPU訓(xùn)練時差距很大。注意T必須預(yù)先復(fù)制否則forwardLoss里的尺寸對不上報錯。如果你在MATLAB R2018a之前版本上跑nnet.layer.RegressionLayer的接口略有不同建議至少用R2021a之后的版本Deep Learning Toolbox對自定義層的支持更穩(wěn)定。3.3 網(wǎng)絡(luò)定義與訓(xùn)練選項設(shè)置網(wǎng)絡(luò)層定義不復(fù)雜關(guān)鍵是確定隱藏單元數(shù)和分位數(shù)個數(shù)。下面的代碼把五個分位數(shù)作為輸出用兩層結(jié)構(gòu)提取特征。quantiles [0.05, 0.25, 0.5, 0.75, 0.95]; numQuantiles numel(quantiles); layers [ sequenceInputLayer(1, Normalization, zscore) lstmLayer(64, OutputMode, last) fullyConnectedLayer(32) reluLayer() fullyConnectedLayer(numQuantiles) quantileRegressionLayer(quantiles, qrloss) ];序列輸入層的Normalization選項自動做標(biāo)準(zhǔn)化但注意它用的是整個訓(xùn)練集的均值和方差。這里是先滑窗后訓(xùn)練標(biāo)準(zhǔn)化只會對輸入特征做不會影響目標(biāo)。lstmLayer(64)輸出模式必須設(shè)為last因為我們要的是最后一個時間步的隱藏狀態(tài)不是所有時間步。reluLayer之后接全連接輸出分位數(shù)這里不加激活讓輸出在實數(shù)域自由取值。接下來構(gòu)造訓(xùn)練目標(biāo)矩陣。trainNetwork要求響應(yīng)矩陣與網(wǎng)絡(luò)輸出層輸出的大小一致即numQuantiles x numSamples所以每一列都是同一真實值復(fù)制了numQuantiles份。% 訓(xùn)練集/測試集按時間順序切分 trainRatio 0.8; numTrain floor(numSamples * trainRatio); XTrain X(1:numTrain); XTest X(numTrain1:end); YTrain repmat(Y(1:numTrain), numQuantiles, 1); YTest Y(numTrain1:end);這里numTrain是前80%樣本測試集嚴(yán)格排在訓(xùn)練集之后不做隨機切分。如果隨機打亂測試樣本可能早于部分訓(xùn)練樣本相當(dāng)于用未來預(yù)測過去區(qū)間評估全失真。YTrain用repmat擴(kuò)展成5×numTrain矩陣每一行對應(yīng)一個分位數(shù)的目標(biāo)數(shù)值相同。因為分位數(shù)損失本身不要求目標(biāo)分位數(shù)有區(qū)別區(qū)別只在于損失權(quán)重所以復(fù)制是沒問題的。訓(xùn)練選項我習(xí)慣這么設(shè)options trainingOptions(adam, ... MaxEpochs, 80, ... MiniBatchSize, 32, ... InitialLearnRate, 0.005, ... Shuffle, every-epoch, ... GradientThreshold, 2, ... Plots, training-progress, ... Verbose, 1); net trainNetwork(XTrain, YTrain, layers, options);InitialLearnRate設(shè)為0.005是常見起點LSTM對學(xué)習(xí)率比全連接網(wǎng)絡(luò)更敏感太大容易NaN太小收斂慢。GradientThreshold設(shè)為2是為了防止LSTM梯度爆炸這類分位數(shù)回歸的損失曲線不如MSE平滑梯度裁剪幾乎是必備的。MiniBatchSize32在小數(shù)據(jù)集上比較平衡如果顯存緊張可以降到16。3.4 預(yù)測與可視化區(qū)間怎么畫出來訓(xùn)練完成后用predict對測試集做前向計算得到的是5×N的矩陣每一行是一個分位數(shù)的預(yù)測序列。畫區(qū)間時取0.05和0.95作為90%預(yù)測區(qū)間邊界0.5作為點預(yù)測中線。YPred predict(net, XTest, MiniBatchSize, 32); YLo YPred(1, :); % 0.05分位數(shù) YMid YPred(3, :); % 0.5分位數(shù) YHi YPred(5, :); % 0.95分位數(shù) % 畫測試集的區(qū)間 idx 1:numel(YTest); figure; fill([idx, fliplr(idx)], [YHi, fliplr(YLo)], ... [0.8 0.9 0.95], FaceAlpha, 0.4, EdgeColor, none); hold on; plot(idx, YMid, b-, LineWidth, 1.2); plot(idx, YTest, r-, LineWidth, 1); legend(90%區(qū)間, 中位數(shù)預(yù)測, 真實值, Location, best);YPred每一行的順序和創(chuàng)建層時傳入的quantiles順序一致所以第一行是0.05第三行是0.5第五行是0.95。fill函數(shù)先畫上界從左到右再畫下界從右到左形成閉合區(qū)域。FaceAlpha控制透明度方便觀察真實值曲線與區(qū)間的重合程度。這里我習(xí)慣把區(qū)間畫成淺藍(lán)色真實值畫成紅色疊加起來一眼能看出預(yù)測是否在波動大的時段明顯發(fā)散。4. 參數(shù)與超參數(shù)調(diào)試QRLSTM最值得花時間的三個旋鈕4.1 分位數(shù)的數(shù)量與位置怎么選才合理分位數(shù)集合決定了輸出層維度和區(qū)間形狀。常用做法是選對稱分位數(shù)對比如[0.05,0.5,0.95]對應(yīng)90%區(qū)間[0.1,0.5,0.9]對應(yīng)80%區(qū)間。如果想同時看多個覆蓋級別可以設(shè)[0.05,0.25,0.5,0.75,0.95]這樣既能畫50%區(qū)間又能畫90%區(qū)間。分位數(shù)個數(shù)增加會直接增加全連接輸出層的參數(shù)但影響不大真正的影響是損失函數(shù)里各分位數(shù)之間的平衡。如果數(shù)據(jù)噪聲是對稱的對稱選擇沒問題如果數(shù)據(jù)有右偏比如銷售數(shù)據(jù)偶爾有爆發(fā)性高值低分位數(shù)和高分位數(shù)之間的不對稱性更強可以適當(dāng)把高分位數(shù)往0.99推低分位數(shù)放到0.01。我一般不會一開始就用19個分位數(shù)那是為了畫精細(xì)分布才做的。絕大多數(shù)業(yè)務(wù)場景5個分位數(shù)足夠太多會讓某些極端分位數(shù)在訓(xùn)練集里得不到足夠樣本約束反而出現(xiàn)交叉或擺動。訓(xùn)練完先看中位數(shù)序列是否合理再看0.05和0.95之間是否始終保持下界低于上界如果交叉嚴(yán)重先減少分位數(shù)。4.2 序列長度、隱藏單元和學(xué)習(xí)率的聯(lián)動關(guān)系inputSteps決定模型看到多長的歷史。序列太短周期信息學(xué)不到太長樣本數(shù)減少訓(xùn)練時間增加而且LSTM要學(xué)習(xí)長期依賴的難度變大。我的經(jīng)驗是先用數(shù)據(jù)自相關(guān)圖判斷周期。比如小時負(fù)荷數(shù)據(jù)有24小時周期inputSteps至少要看48小時覆蓋兩個周期如果計算資源緊張24也可以但需要調(diào)高隱藏單元。隱藏單元lstmLayer的維度通常從32到128之間試。64對于幾百到幾千樣本的時間序列是安全的起點。注意隱藏單元增加會顯著增加訓(xùn)練時間因為LSTM四個門控矩陣的參數(shù)量和隱藏單元平方成正比。這三個參數(shù)是聯(lián)動的序列長、隱藏單元多時模型容量大學(xué)習(xí)率要降低否則容易震蕩。我自己調(diào)試時會把學(xué)習(xí)率從0.01開始如果損失曲線前期下降過快但后期震蕩就降到0.003如果前20個epoch幾乎不下降先檢查數(shù)據(jù)標(biāo)準(zhǔn)化和損失層有沒有寫錯再考慮調(diào)大學(xué)習(xí)率。Adam優(yōu)化器對初始學(xué)習(xí)率沒那么敏感但LSTM還是建議加上梯度裁剪這能避免很多翻車現(xiàn)場。4.3 區(qū)間評估PICP、區(qū)間平均寬度與Winkler得分模型好不好不能只看損失曲線區(qū)間預(yù)測的評價指標(biāo)要單獨算。PICP是測試集真實值落在預(yù)測區(qū)間內(nèi)的比例比如90%區(qū)間理論上PICP應(yīng)接近0.9。區(qū)間平均寬度則是上下界差的均值。只看PICP會騙人把小界擴(kuò)到無窮寬PICP直接100%。只看寬度也會騙人區(qū)間窄但漏掉很多點。更綜合的是Winkler得分它同時懲罰窄區(qū)間和超出區(qū)間的點。在MATLAB里可以手寫一段picp mean((YTest YLo) (YTest YHi)); avgWidth mean(YHi - YLo); fprintf(PICP %.3f, avgWidth %.3f\n, picp, avgWidth);如果PICP低于名義覆蓋水平比如90%區(qū)間實際只有70%說明網(wǎng)絡(luò)對數(shù)據(jù)波動估計不足需要放大邊界分位數(shù)或做后校準(zhǔn)。如果PICP接近但區(qū)間寬度偏大說明邊界分位數(shù)被過度外推可以考慮在損失函數(shù)里對邊界分位數(shù)加一個寬度懲罰項。QRLSTM本身沒有顯式的寬度控制靠pinball loss在訓(xùn)練數(shù)據(jù)上的分布自動平衡所以業(yè)務(wù)上對覆蓋率要求更嚴(yán)格時后處理校準(zhǔn)幾乎不可避免。5. 常見問題與避坑MATLAB實現(xiàn)QRLSTM的五個翻車場景5.1 訓(xùn)練損失變成NaN或發(fā)散現(xiàn)象訓(xùn)練迭代到幾十步后損失變成NaN或者從初始值開始就一路飆升。原因?qū)W習(xí)率過大導(dǎo)致梯度爆炸輸入數(shù)據(jù)含有NaN或極端值LSTM的梯度在長序列上累積爆炸。解決先檢查數(shù)據(jù)里有沒有NaN用any(isnan(data))確認(rèn)。然后把InitialLearnRate降到0.001以下同時設(shè)置GradientThreshold為1或2。如果仍然NaN檢查自定義層的forwardLoss返回值是不是標(biāo)量MATLAB在某些版本下如果返回0×0數(shù)組也會觸發(fā)奇怪行為。我在實際中遇到過數(shù)據(jù)標(biāo)準(zhǔn)化沒做某個極端值把LSTM門控飽和損失直接跳到NaN做了zscore之后問題消失。5.2 預(yù)測區(qū)間上下界交叉現(xiàn)象測試集某些時刻0.95分位數(shù)預(yù)測值小于0.05分位數(shù)區(qū)間反了。原因多個分位數(shù)輸出在訓(xùn)練時是相互獨立的網(wǎng)絡(luò)沒有在結(jié)構(gòu)上保證單調(diào)性。如果訓(xùn)練樣本少或數(shù)據(jù)波動大某些時刻的極端分位數(shù)可能相互擠壓。解決最簡單的方法是在畫圖前排序YPred sort(YPred, 1)讓每一時刻的分位數(shù)按從小到大排列。這個方法聽起來有點粗糙但實踐中很常用因為真正評估覆蓋率時只需要排序后的上下界。如果想從訓(xùn)練層面緩解可以把分位數(shù)個數(shù)減少到3個或者讓低分位數(shù)和高分位數(shù)共享更多特征比如全連接層先減少維度再分出多列。也可以在后處理時做保序回歸但MATLAB里沒有現(xiàn)成函數(shù)重寫太費勁排序法足夠應(yīng)對大多數(shù)情況。5.3 訓(xùn)練速度慢到無法忍受現(xiàn)象一個5000樣本、序列長度50的簡單任務(wù)用CPU訓(xùn)練LSTM要跑幾小時。原因LSTM是循環(huán)計算無法像卷積那樣大規(guī)模并行且序列越長計算量越大。自定義層的for循環(huán)還會放大問題。解決先把自定義損失層改成向量化寫法就是3.2節(jié)那個版本性能提升非常明顯。其次檢查MiniBatchSize太小會讓每次GPU利用率低太大顯存不夠32到128之間調(diào)。再有就是確認(rèn)trainNetwork是否真的檢測到GPU運行g(shù)puDevice查看如果返回空則說明還沒配置。如果數(shù)據(jù)規(guī)模實在大可以把inputSteps縮短到關(guān)鍵周期長度或者用sequenceInputLayer加Normalization減少訓(xùn)練負(fù)擔(dān)。最后還有一個血淚經(jīng)驗不要用MATLAB Live Script跑訓(xùn)練圖形渲染會拖慢迭代編輯窗口直接運行會更快。5.4 數(shù)據(jù)集劃分順序錯誤導(dǎo)致未來信息泄漏現(xiàn)象訓(xùn)練損失很低測試集表現(xiàn)卻差得離譜但區(qū)間覆蓋率反而高整體看起來很怪。原因隨機切分測試集或標(biāo)準(zhǔn)化時用了全量數(shù)據(jù)統(tǒng)計量導(dǎo)致測試集信息混進(jìn)訓(xùn)練過程。解決嚴(yán)格按時間順序切分。我習(xí)慣在滑窗之前就留出最后20%作為測試集先切分再做滑窗而且標(biāo)準(zhǔn)化參數(shù)只用訓(xùn)練集計算。如果你用sequenceInputLayer的Normalization選項它會在訓(xùn)練時自動用訓(xùn)練集統(tǒng)計量歸一化這個沒問題。但如果自己手動做(data-mean(data))/std(data)請一定只對訓(xùn)練集算mean和std再對測試集應(yīng)用。只要未來信息進(jìn)入訓(xùn)練集分位數(shù)區(qū)間就會顯得過于自信部署時直接翻車。5.5 目標(biāo)矩陣復(fù)制維度不匹配現(xiàn)象運行trainNetwork時報錯提示輸出層大小與響應(yīng)大小不一致。原因fullyConnectedLayer(numQuantiles)的輸出是numQuantiles x N而如果YTrain還是1×N的普通向量trainNetwork無法對齊。解決用repmat把目標(biāo)復(fù)制成numQuantiles x numTrain每一行都是真實值的重復(fù)。檢查方式size(YTrain)應(yīng)為[numQuantiles, numTrain]size(YPred)預(yù)測后也應(yīng)為[numQuantiles, N_test]。如果改了分位數(shù)個數(shù)記住目標(biāo)矩陣也要同步重新復(fù)制。這個坑很常見因為常規(guī)回歸網(wǎng)絡(luò)輸出一個標(biāo)量很多人會忘記多輸出時響應(yīng)矩陣要擴(kuò)維。6. 進(jìn)階用分位數(shù)校準(zhǔn)讓區(qū)間更可靠QRLSTM訓(xùn)練完直接輸出的90%區(qū)間可能只有82%的實際覆蓋率這在中位數(shù)附近表現(xiàn)尚可邊界分位數(shù)經(jīng)常由于訓(xùn)練數(shù)據(jù)有限而偏離名義水平。我習(xí)慣在測試集之外再留一個小的驗證集專門做分位數(shù)校準(zhǔn)。校準(zhǔn)思路很簡單對于每個分位數(shù)τ統(tǒng)計真實值低于該分位數(shù)預(yù)測的比例記為τ_hat。如果τ_hat小于τ說明該分位數(shù)預(yù)測偏低需要往高調(diào)反之則往低調(diào)。具體做法是給每個分位數(shù)預(yù)測值加一個偏移量偏移量由驗證集上的偏差決定。對0.05分位數(shù)如果驗證集里實際只有2%的點低于預(yù)測說明預(yù)測太高了把預(yù)測整體減去一點對0.95分位則相反。更平滑的做法是做一個線性變換y_calibrated a * y_raw b在驗證集上用分位數(shù)回歸或單純線性插值擬合a和b。這相當(dāng)于把QRLSTM的輸出當(dāng)做事后校準(zhǔn)的特征而不是最終結(jié)果。我自己的習(xí)慣是訓(xùn)練時用5個分位數(shù)預(yù)測后在驗證集上計算每個分位數(shù)的經(jīng)驗偏差然后把偏移量加到測試集預(yù)測上。如果偏移后覆蓋率仍然不足我會把邊界分位數(shù)從0.05/0.95挪到0.02/0.98重新訓(xùn)練一次。這比修改損失函數(shù)更可控因為模型主體不動后處理邏輯很容易解釋給業(yè)務(wù)方。另一個提升穩(wěn)定性的技巧是多輪訓(xùn)練取平均。LSTM初始化和隨機梯度下降會導(dǎo)致不同訓(xùn)練輪次的分位數(shù)曲線有微小差異單獨一次的結(jié)果可能在某幾段區(qū)間上偏窄??梢园淹粋€QRLSTM訓(xùn)練三次每個分位數(shù)取三次預(yù)測的平均值區(qū)間寬度和覆蓋率都會更平滑。代價是訓(xùn)練時間三倍但成果是區(qū)間更穩(wěn)定值得嘗試。QRLSTM不是黑匣子它的數(shù)學(xué)原理和落地方案都很清晰。真正決定使用體驗的是數(shù)據(jù)切分、分位數(shù)選擇和后校準(zhǔn)這幾個環(huán)節(jié)。你只要把第3章的完整程序跑通再加上第5章的避坑經(jīng)驗就能在自己的時間序列數(shù)據(jù)上得到可解釋、可評估的預(yù)測區(qū)間。希望幫到你。本文還有配套的精品資源點擊獲取