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