ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

时间序列预测参数调优:自回归阶数与隐层节点数实战指南

时间序列预测参数调优:自回归阶数与隐层节点数实战指南 1. 先把思路捋顺自回归阶数和隐层节点数到底卡在哪动手写代码之前我先说个结论时间序列预测这活儿90%的坑不在模型选型而在你根本没想明白两个数字怎么来。标题里提到的自回归阶数就是 AR 模型的滞后阶数 p它决定了你用过去多少个点的数据去预测下一个点。隐层节点数则是神经网络里那一层神经元的数量它直接决定了网络能记住多少种非线性特征。这两个参数一个偏统计建模一个偏深度学习看起来八竿子打不着但实际遇到的时候你会发现自己卡在同一步改阶数、改节点数试了一遍又一遍结果不是过拟合就是欠拟合训练曲线画出来跟心电图似的根本没法用。我最近在一个压力传感器的连续采集项目里做多步预测样本量大概几千个点频率是每分钟一条。数据本身不算复杂但当我第一次用 MATLAB 跑神经网络的时候隐层节点数随便设了个 10结果验证集误差大得离谱后来改成 50训练倒是收敛了可预测曲线明显在“背答案”泛化能力一塌糊涂。同样的AR 模型那边p 取 2 的时候残差里还有明显的相关性取 20 的时候模型参数多到样本量都撑不住。当时我就在想这种问题绝对是所有做时序预测的人都躲不过去的所以干脆把完整过程整理成一篇老铁们照着操作就行。这篇文章我不聊理论推导只讲三件事自回归阶数怎么用数据说话隐层节点数怎么用验证集试出来以及 MATLAB 里一套能直接跑的完整流程。适合刚开始接触时序预测、或者已经在跑模型但被参数调优折磨的朋友看。如果你用的工具是 Python 也没关系思路完全一致MATLAB 代码里每一步的逻辑你都能迁移过去。1.1 先分清你手里的是哪种预测问题很多人在第一步就走偏了。时间序列预测分单步预测和多步预测单步预测是拿过去 N 个点预测未来 1 个点多步预测是预测未来 H 个点。这两个问题对参数的要求完全不同。单步预测时AR 模型只需要看前 p 个点p 通常不会太大神经网络也只需要输出一个值隐层节点数稍微多一点问题不大。多步预测就不一样了一步错步步错误差会累积这时候模型复杂度、隐层节点数、训练策略全都要重新考虑。我建议大家在动手之前先把自己的预测步长写死比如我就做 6 步预测那模型评估、数据划分、滞后窗口全部围绕这个来。别一会儿预测 1 步一会儿预测 50 步参数选型根本没有可比性。1.2 建模路线怎么选AR 打底神经网络做对比我的做法是双轨并行。先用 AR 模型作为基线把自回归阶数通过统计方法定下来得到一个稳定可解释的预测结果。然后在这个基线上再用神经网络去做增强对比这时候隐层节点数就是主要调参对象。为什么要这样因为 AR 模型给你的是“可控的底线”如果神经网络连 AR 模型都打不过那说明你的数据本身可能就不适合深度学习或者隐层节点数、训练策略出了问题。这个思路帮我省了无数时间老铁们可以试试。2. 自回归阶数用 PACF 定候选用 AIC/BIC 做裁决自回归阶数 p 的本质是当前值 y(t) 与过去 y(t-1), y(t-2), ..., y(t-p) 之间的线性关系。你要是拍脑袋定 p那就等着被数据打脸吧。正确做法分两步先用 PACF偏自相关函数看截尾位置得到一个候选范围再用信息准则从候选范围里挑一个最优值。2.1 平稳性检查是前提千万别跳过AR 模型的数学基础要求序列平稳也就是均值和方差不能随时间变化。大部分原始数据都不平稳比如传感器值有漂移负荷数据有周期性。直接做 PACF 和 AIC出来的阶数基本都是虚高因为非平稳性会被当成自回归结构。MATLAB 里做平稳性检验我用的是 ADF 检验adftest。零假设是序列存在单位根也就是非平稳。如果返回的 p 值小于 0.05说明拒绝原假设序列平稳否则就要差分。我的代码开场通常是y data; % 原始时序数据 [h, pval] adftest(y); if ~h y_diff diff(y); disp(原始序列非平稳先做一阶差分); else y_diff y; disp(原始序列平稳直接建模); end这里有个很多人不知道的细节差分后模型预测的是差分值预测结果要还原成原始量级。这一步漏掉后面预测曲线永远跟真实值差一个平移量。2.2 PACF 图怎么读截尾位置就是 AR 阶数的候选点PACF 图横轴是滞后阶数纵轴是偏自相关系数。偏自相关的意思是在剔除了中间滞后项影响之后y(t) 与 y(t-k) 之间的直接相关性。AR(p) 模型的 PACF 应该在 p 阶之后突然“截尾”也就是系数落入置信区间内不再显著。MATLAB 里直接用parcorr画图maxLag 30; figure; parcorr(y_diff, NumLags, maxLag);注意parcorr需要计量经济学工具箱或者系统辨识工具箱不同版本函数位置可能不一样后面我会专门说版本坑。拿到图以后我的读取规则是这样的找第一个超出蓝色置信边界的滞后阶数同时看它后面的系数是否快速回落。如果 2 阶显著、3 阶骤降到置信带内那 p2 就是强候选如果一直到 10 阶都断断续续显著那说明可能存在移动平均成分或者数据预处理不到位先别急着定阶。2.3 AIC/BIC 定阶代码循环所有候选阶数PACF 给出的只是候选范围比如 2 到 8。真正做裁决的是信息准则。AIC 和 BIC 都是“残差越小越好、参数越多越罚”它们的区别在于惩罚力度BIC 对参数数量罚得更狠所以 BIC 选出来的阶数一般比 AIC 小。我的习惯是 AIC 结果当上限BIC 结果当下限最后在两者之间选一个贴合业务解释的。MATLAB 里我用的方法是arima建模 aicbic计算maxP 10; aicVals zeros(maxP, 1); bicVals zeros(maxP, 1); for p 1:maxP mdl arima(p, 0, 0); % AR(p) 模型 [~, ~, logL] estimate(mdl, y_diff, Display, off); numParams p 1; % AR系数 常数项/方差项按实际模型调整 [aicVals(p), bicVals(p)] aicbic(logL, numParams, length(y_diff)); end [minAIC, pAIC] min(aicVals); [minBIC, pBIC] min(bicVals); fprintf(AIC最优阶数: %d, BIC最优阶数: %d\n, pAIC, pBIC);我实测下来AIC 经常会选 7 或 8BIC 选 3 或 4。这时候不要直接取某一个而是看 PACF 图。如果 PACF 在 4 阶截尾BIC 也选 4那就用 p4不需要追求 AIC 的最小值。模型又不是数学竞赛非要拿最小那个过拟合的风险远大于那一点点残差下降。2.4 定完阶数怎么验证看残差相关性阶数定完以后一定要做残差白噪声检验。如果残差还有自相关说明你没把信息提取干净阶数偏低。MATLAB 里可以用infer提取残差再画parcorr看残差的相关性estMdl estimate(arima(pAIC, 0, 0), y_diff, Display, off); res infer(estMdl, y_diff); figure; parcorr(res, NumLags, 20);如果残差 PACF 还有显著点说明 p 太小。如果怎么增加 p 都压不下去那基本可以放弃纯 AR 模型改用 ARMA 或者神经网络这时候就到了第三部分的隐层节点数问题。3. 隐层节点数经验法则当起点验证集试错定终值隐层节点数没有统计学公式可以直接算出结果这是一等一的实践问题。网络节点太少表达能力不够欠拟合节点太多会把训练数据里的噪声一并背下来过拟合。我见过太多人一上来就是hidden100然后指责模型不行其实是你自己把参数顶到天上去了。3.1 经验法则只能给你一个搜索起点网上流传的经验法则有一堆什么隐层节点数要小于训练样本数大于输入维度还有什么hidden (输入维数 输出维数) / 2 sqrt(样本数)之类的。说实话这些公式的适用场景非常窄大部分来源于上世纪九十年代的神经网络研究当时的数据规模和训练方式跟现在完全不同。我不否认它们的参考价值但我更建议把它们当成搜索范围的上下界而不是最终取值。我自己在单变量时序预测里输入窗口一般是 10 到 30 个历史点输出是 1 个未来点所以输入维度很小。这时候隐层节点数的合理搜索范围大概是 4 到 64。低于 4网络退化得跟线性模型差不多高于 64几千个样本的小数据集几乎必然过拟合。范围定好剩下就是做控制变量实验。3.2 MATLAB 里做隐层节点数网格搜索如果你用的是 LSTM隐藏单元数就是lstmLayer里的第一个参数。我的搜索代码长这样numSteps 12; % 用过去12个点 hiddenCandidates [4, 8, 16, 32, 64]; valRMSE zeros(length(hiddenCandidates), 1); for i 1:length(hiddenCandidates) h hiddenCandidates(i); rng(42); % 保证每次实验可复现 % 构建训练数据XTrain是 [features x timeSteps x observations] % YTrain是 [observations x 1] layers [ sequenceInputLayer(1) lstmLayer(h, OutputMode, last) fullyConnectedLayer(1) regressionLayer]; options trainingOptions(adam, ... MaxEpochs, 150, ... MiniBatchSize, 32, ... InitialLearnRate, 0.01, ... ValidationData, {XVal, YVal}, ... ValidationFrequency, 10, ... Verbose, 0); net trainNetwork(XTrain, YTrain, layers, options); YPred predict(net, XVal); valRMSE(i) sqrt(mean((YVal - YPred).^2)); end [bestRMSE, idx] min(valRMSE); bestHidden hiddenCandidates(idx);这里几个关键点第一rng(42)必须在每次训练前都设置否则网络初始化权重每次都不一样搜索结果里混杂了随机性。第二MiniBatchSize要根据样本量调整样本量五百以下建议用 16 或 32样本量五千以上再考虑 64。第三ValidationData不要跟训练数据重叠最好从时间序列的中间段截一段出来当验证集。这一点在时序预测里跟普通分类任务完全不同不能用随机打乱的方式抽验证集否则未来信息泄露验证误差会严重失真。3.3 实验结果怎么读不只盯最后的误差网格搜索结束以后你拿到的不应该只是一张表格还有每条训练曲线。我的经验是看三样东西最终 RMSE、训练集和验证集误差的差距、训练曲线有没有震荡。如果验证 RMSE 随着隐层节点数增大先是下降然后掉头上升那恭喜你你找到了过拟合拐点。拐点对应的节点数就是最优值。如果验证 RMSE 一直下降到 64 都没停那说明你的搜索范围上限不够或者训练策略有问题可能学习率太低导致大网络没充分训练。如果训练误差和验证误差差距永远都很大那除了隐藏节点数你还得检查数据标准化、序列长度、学习率这些环节问题不一定出在节点数上。我自己跑出来的一组典型结果是hidden4 时验证 RMSE 是 1.23hidden8 是 0.87hidden16 是 0.85hidden32 是 0.96。看起来 16 最优但注意 hidden8 和 16 只差了 0.02这时候我会果断选 8因为参数更少、训练更快、稳定性更好。别为了 0.02 的误差去加倍模型复杂度这在实际项目里不值得。4. 一条龙示例从原始数据到预测曲线下面这部分我给你跑一个完整流程数据就用 MATLAB 自带或者模拟的传感器数据重点展示每一步怎么衔接。你直接新建脚本把下面代码按顺序粘进去就能跑通。4.1 数据准备差分、归一化、构造滑动窗口clear; clc; rng(42); % 模拟一段非平稳的传感器压力数据 t 0:0.1:100; y 50 0.3*t 5*sin(t/3) randn(size(t)) * 0.5; y y(:); figure; plot(t, y); title(原始压力数据);先把序列画出来我习惯人眼扫一遍看趋势、周期和异常点。然后做一阶差分去掉趋势yDiff diff(y); yDiff yDiff(:);神经网络对量纲非常敏感LSTM 内部用的是 Sigmoid 和双曲正切这类激活函数输入数据太大很容易把梯度顶到饱和区。我一般用normalize做 z-score 标准化mu mean(yDiff); sigma std(yDiff); yNorm (yDiff - mu) / sigma;构造滑动窗口的时候要注意重叠。比如用过去 12 个点预测未来第 13 个点窗口滑一格就构造一条样本这样样本量大约是序列长度减窗口长度。代码numSteps 12; XTrain zeros(numSteps, length(yNorm) - numSteps - 1); YTrain zeros(length(yNorm) - numSteps - 1, 1); for i 1:length(yNorm) - numSteps - 1 XTrain(:, i) yNorm(i : i numSteps - 1); YTrain(i) yNorm(i numSteps); end注意这里的维度XTrain我做成[timeSteps, observations]因为后面喂给 LSTM 时sequenceInputLayer的顺序是这样的。如果你用的 MATLAB 版本比较新也可以写成[features, timeSteps, observations]的形状比如XTrain reshape(XTrain, 1, numSteps, [])两种都行只要层里sequenceInputLayer(1)的特征维度对得上。4.2 AR 模型训练与预测先拿到一个可信基线差分后的数据用 AR 模型定阶和预测。按照第二部分的方法先跑 PACF 和 AIC假设选出来的阶数是 p4p 4; mdl arima(p, 0, 0); estMdl estimate(mdl, yNorm, Display, off);预测 6 步h 6; yForecast forecast(estMdl, h, Y0, yNorm(end - p 1 : end)); yForecast yForecast * sigma mu;这样得到的预测值还是差分域的我已经还原成了原始差分值范围但要注意如果原始序列做了差分你预测的是差分值最终还原到原始压力值时需要做累加。这个细节很多人栽过我后面单独列一条。4.3 LSTM 模型训练与预测同样的数据不同的味道LSTM 的训练数据直接用前面构造的XTrain/YTrain但标准化参数必须用训练集的统计量。我在 4.1 里偷懒用了全序列的mu和sigma实际项目里这样会泄漏未来信息正确的做法是先划分训练集和测试集再分别算mu和sigma。小规模演示问题不大但你心里要有数。LSTM 训练layers [ sequenceInputLayer(1) lstmLayer(16, OutputMode, last) fullyConnectedLayer(1) regressionLayer]; options trainingOptions(adam, ... MaxEpochs, 200, ... MiniBatchSize, 32, ... InitialLearnRate, 0.01, ... Verbose, 0, ... Plots, training-progress); net trainNetwork(XTrain, YTrain, layers, options);这里我的XTrain是[numSteps, obs]在 MATLAB 较新版本里trainNetwork会自动把numSteps维度当成序列长度obs当成观察数所以能跑通。如果你遇到维度报错就改成reshape(XTrain, 1, numSteps, [])。预测YTestPred predict(net, XTest); YTestPred YTestPred * sigma mu;4.4 结果对比要看整体预测曲线不要只盯着指标最后一步把 AR 和 LSTM 的预测曲线放在同一张图里。这是我强烈建议的做法因为 RMSE 只告诉你数字大小曲线能告诉你误差发生在哪里。比如 AR 模型在拐点附近误差大LSTM 在平坦期误差大两者的应用场景完全不同。figure; plot(t, y, DisplayName, 真实值); hold on; plot(tFuture, yArPred, DisplayName, AR预测); plot(tFuture, yLstmPred, DisplayName, LSTM预测); legend;如果 LSTM 在测试集上的 RMSE 比 AR 高不少不要急着加隐层节点数。先看是不是数据本身线性成分强、非线性成分弱。对这种数据LSTM 的优势本来就不明显你把它当黑盒硬调还不如老老实实把 AR 模型调好。时序预测这行没有谁一定比谁强只有合不合适。5. 常见问题与排查我替你踩过这些坑这章节我给老铁们列一份速查表全是实际跑代码时遇到过的问题。别等报错了再翻文档直接对照着检查。5.1 常见问题速查表现象可能原因解决方案AIC 选出来的阶数特别大模型不稳定序列非平稳PACF 图虚高先做差分adftest通过后再定阶PACF 图看不出来截尾点缓慢衰减可能存在 MA 成分纯 AR 不合适改用 ARMA 或直接换神经网络LSTM 训练曲线震荡严重学习率过高 / MiniBatchSize 太小把学习率降到 0.001批次加到 64训练损失下降验证损失持续上升过拟合隐层节点数太多减小隐藏单元数或加 DropoutLayer验证损失一直不降数据标准化没做好 / 网络结构错误检查输入数据范围和维度改用 z-score预测曲线整体比真实值平移一段差分还原时忘记累加对差分预测值做cumsum再加回原值换了数据后最优隐层节点数总是变正常现象数据特性不同不要盲目沿用旧参数重新跑网格搜索5.2 工具箱版本坑同一个函数名工具箱不一样MATLAB 最大的问题是版本碎片化。parcorr在较早版本里是计量经济学工具箱的函数在系统辨识工具箱里也有类似功能。arima在老版本叫arima在更早的包里叫armax。trainNetwork则是深度学习工具箱的没装 Deep Learning Toolbox 的话直接报 undefined。我建议动手前先在命令行敲ver看看自己装了哪些工具箱。如果没装计量经济学工具箱PACF 可以自己手写公式不复杂用最小二乘回归一步一步算偏相关系数就行。如果没装深度学习工具箱那 LSTM 肯定跑不了老老实实用 AR 或者前馈神经网络feedforwardnet。5.3 我反复踩的三个大坑第一个坑是数据划分。做分类任务的人习惯了cvpartition随机划分时间序列也用随机划分结果把未来的数据混进了训练集验证误差好看得不得了一上真实数据就崩。时序预测只能用顺序划分训练集在前验证集在后中间可以留一段缓冲区分隔防止延迟效应污染训练。第二个坑是预测的未来点越多效果越虚。很多人测试 LSTM 多步预测时把每个预测值当成新输入喂回去每喂一次误差翻一倍。如果你做 6 步预测合理的方式是在测试集上做 Teacher Forcing也就是每一步都用真实观测值作为下一步的输入。做滚动预测时要清楚标注这是“迭代预测”不然你自己都会被结果骗到。第三个坑是过早开始调参。我见过太多同学一上来就把隐藏节点数、学习率、批次大小全部拿来调调了两宿没结果。正确的顺序是先把数据流程走通确保损失函数能稳定下降再做参数搜索。数据流程跑通的前提下网格搜索才有意义。否则你调出来的“最优参数”很可能只是给错误数据流程擦屁股。5.4 一个小技巧用早停机制保住性价比如果隐层节点数搜索结果差别不大我建议引入早停。trainingOptions里有一个ValidationPatience参数验证损失连续 N 轮不下降就停止训练。这样做的好处是你不用为了追求那 0.01 的提升硬跑 200 轮大网络也不会因为训练太久而过拟合。我实际跑下来ValidationPatience, 20配合隐层节点数 8 到 16比 64 个节点猛跑 200 轮更稳训练时间还少一半。写到最后说点实在话这些东西说起来都是老生常谈但真到自己动手的时候还是会忍不住犯懒。有人图省事直接抄网上的隐层节点数经验值结果模型不收敛有人花一个礼拜去调批次大小最后发现数据标准化根本没做对。我在 MATLAB 上反复折腾下来的最大体会是自回归阶数这问题统计工具给你答案但统计工具也只会给你数学上的最优业务上的解释和稳健性永远要自己把关。隐层节点数这个就更直白没有捷径只有控制变量、反复验证老老实实把搜索做完整才能拿到一个换了数据集也不会太慌的结论。老铁们如果自己跑的时候遇到 MATLAB 报错多看看错误信息里的函数名再对比一下自己工具箱版本八成能自查出来。这套流程你跑通一次以后后面换什么数据都不会害怕了。
返回列表