ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

MATLAB LSTM时间序列预测实战:从数据准备到滚动验证

MATLAB LSTM时间序列预测实战:从数据准备到滚动验证 简介这是面向MATLAB用户的LSTM时间序列预测示例资源适合需要借助深度学习工具箱完成历史序列建模与趋势预测的开发者也适用于机器学习初学者理解循环神经网络的实际用法。脚本lstm_yuce.m演示了从数据预处理归一化、LSTM层创建、训练参数设置、模型训练到预测输出与反归一化的完整流程其中还体现了门机制对长期依赖信息的处理思路并对预测精度评估如RMSE、MAE预留了接口。资源包共1个m文件压缩后仅2KB轻量易读便于对照代码逐行掌握核心步骤可替换自己的数据快速验证。该资源已有1570人浏览学习适合作为LSTM序列预测入门或基线模型搭建的参考。1. MATLAB 里的 LSTM 预测先看清它在解决哪一类问题LSTM 预测在 MATLAB 里不是拖个 App、点一下开始预测就能交付的事。它解决的是这样一类问题给定一段按时间排列的观测值预测未来若干步的取值序列里既有趋势和周期又有无法用固定公式描写的非线性成分典型如水文径流、电力负荷数据。MATLAB 的深度学习工具箱提供了 lstmLayer、trainNetwork、predictAndUpdateState 一整套接口让熟悉 MATLAB 但不熟悉 Python 深度学习框架的工程师能在不换语言的前提下把数据规范化、滑窗造样本、训练、滚动预测串成完整链路。真正的难点在输入格式、窗口长度、训练选项与验证方式的配合下面按这四个方面依次展开。2. LSTM 预测的数据准备从原始序列到可训练样本对LSTM 不能直接吃原始时间序列。trainNetwork 要求输入是若干条固定长度的输入输出样本对数据必须先完成归一化、滑窗切片、cell 格式转换这三步任何一步出错训练曲线都会表现出难以归因的怪象。这一章把每一步的格式约定和容易在边界上出错的地方讲清楚。2.1 归一化为什么先做 z-scoremu 和 sigma 只准用训练集算LSTM 的门控由 sigmoid 与 tanh 组成对输入量级很敏感。原始数据跨度大时比如温度在 20 到 80 之间、压力在 0.1 到 5 之间波动未经归一化的输入会让遗忘门、输入门长期处于饱和区梯度被少数大数值样本主导训练半天损失曲线纹丝不动。常见做法是 z-score 归一化即 (x - mu) / sigma预测完成后再反变换回原始量纲RMSE 与 MAPE 的计算不受影响。% 生成合成序列周期 趋势 高斯噪声保证演示可复现 rng(1); t (0:0.1:200); y sin(0.3*t) 0.2*sin(2*t) 0.05*randn(size(t)); % z-score 归一化 mu mean(y); sigma std(y); yn (y - mu) / sigma;逻辑说明rng(1)固定随机数种子同一段代码在不同机器上会产生一致的数据与训练过程换成真实数据时删掉这行即可。mu与sigma只应在训练集范围内计算如果先在全序列上算好再切分验证集与测试集的统计量就泄漏进了训练过程测试误差会系统性偏低这个坑在短序列上尤其明显。注意yn仍是列向量后续滑窗时会按行切片。2.2 滑窗构造样本对numSteps 与单步预测的监督化格式LSTM 预测的标准做法是把回归任务改造成监督学习用过去 numSteps 个连续值预测第 numSteps1 个值。每个样本是一个 1 x numSteps 的行向量MATLAB 约定用 cell 数组存放一个 cell 对应一个样本。很多人第一次接触会把整条序列的列向量直接喂给 trainNetwork报错还是小事更隐蔽的是把时间维与 batch 维搞混训练能跑预测结果却整体偏移。numSteps 30; % 窗口长度过去 30 个值预测下 1 个 X cell(length(yn) - numSteps, 1); Y cell(length(yn) - numSteps, 1); for i 1:length(yn) - numSteps X{i} yn(i : i numSteps - 1); % 1 x numSteps行向量是格式关键 Y{i} yn(i numSteps); % 单步预测的目标值 end % 按原始时间顺序切分训练数据不打乱 trainEnd floor(0.8 * numel(X)); XTrain X(1:trainEnd); YTrain Y(1:trainEnd); XTest X(trainEnd1:end); YTest Y(trainEnd1:end);参数说明X{i}必须是行向量即特征数 x 时间步的矩阵单变量特征数为 1所以是 1 x numStepsY{i}是标量响应。如果某个 MATLAB 版本提示响应格式错误把 Y 换成数值列向量cell2mat(YTrain)再传入即可两种写法在单响应回归里都常见。trainEnd取前 80% 样本作训练集这里按样本下标切分有一个已知缺陷相邻滑窗共享 numSteps-1 个历史点切分边界附近有信息重叠更严格的做法是先按原始时间下标切段再在每段内部重建窗口代价是边界损失一部分样本。对短序列预测先按 8:2 切分跑通流程比一开始就追求严格隔离更能帮助你定位问题。滑窗相关参数汇总如下。参数取值示例作用常见误用numSteps10 / 20 / 30 / 50决定模型能看到多长的历史超过主周期一半窗口冗余过大X{i} 格式1 x numSteps 行向量满足序列输入层特征 x 时间约定误写成 numSteps x 1 列向量mu / sigma 计算范围仅训练集防止测试信息泄漏全序列统一计算2.3 网络四层结构与单步预测的 OutputMode 选择网络结构在单变量 LSTM 预测里通常是四层序列输入层、LSTM 层、全连接回归头、回归损失层。LSTM 层内部由遗忘门、输入门、输出门三组门控构成门控状态沿时间逐步滚动这是它区别于普通 RNN 在长序列上梯度更可控的原因。对过去 30 步预测下 1 步的任务OutputMode必须设为last表示只取最后一个时间步的隐状态输出若设成sequence网络会把每一步的输出都送回全连接层训练目标与任务定义就对不上了。layers [ sequenceInputLayer(1) lstmLayer(64, OutputMode, last) dropoutLayer(0.2) fullyConnectedLayer(1) regressionLayer];结构说明sequenceInputLayer(1)声明每个时间步只有 1 个特征lstmLayer(64)的 64 是隐单元数这里用的是信息只沿时间正向传递的单向 LSTM参数量约为 4 x输入维 隐单元数x 隐单元数单层 64 单元约 1.7 万参数样本量小时必须配合 dropout 与验证集控制过拟合。dropoutLayer(0.2)在OutputMode为last时作用于最后一步输出若之后还要再接一层 LSTM应把前一层设为sequence让 dropout 在每个时间步上生效这是层叠结构与单层结构的一个关键区别。fullyConnectedLayer(1)输出连续值regressionLayer在训练时计算均方误差损失。3. 在 MATLAB 中跑通 LSTM 预测的最小代码3.1 trainNetwork 与 trainingOptions 的最小参数组数据与结构就绪后训练只涉及两个函数trainingOptions 与 trainNetwork。对刚上手的团队我一般建议先把参数组固定成下面这组可复现的值跑通后再逐个调整。一次只动一个参数否则损失曲线异常时无法判断是谁引起的。options trainingOptions(adam, ... MaxEpochs, 120, ... MiniBatchSize, 32, ... InitialLearnRate, 0.005, ... GradientThreshold, 1, ... Shuffle, never, ... Plots, training-progress); net trainNetwork(XTrain, YTrain, layers, options);参数说明求解器选adam它自适应调整每个参数的学习率是 LSTM 序列任务上的默认选择不必一上来就尝试带动量的 SGD 变体。InitialLearnRate取 0.005落在 0.001 到 0.01 的常见区间如果训练损失在前几轮就变成 NaN第一步是把学习率降到 0.001而不是去调网络宽度。GradientThreshold设为 1 是 LSTM 训练里最容易被漏掉的一项默认值是 Inf长序列下一旦梯度范数爆炸损失曲线会瞬间跳成 NaN。Shuffle用never是因为滑窗样本彼此高度相似打乱 batch 带来的泛化收益有限却让边界样本反复横跳数据量大时可试once但训练与测试的切分边界不能被触碰。训练曲线通过Plots实时显示看到损失稳步下行且验证损失不反弹再进入预测环节。给 options 加上ValidationData, {XVal, YVal}后训练过程会打印验证损失便于判断是否提前停止。训练曲线形态与对应调整手段如下。曲线形态常见原因调整方向训练与验证损失都不降学习率过低或窗口太短学习率提到 0.01或先加大 numSteps训练降、验证升过拟合减隐单元数dropout 提到 0.4损失中途跳 NaN梯度爆炸GradientThreshold 调到 0.5学习率减半3.2 预测阶段resetState、预热与单步测试训练完成后网络内部还残留着最后一次迭代推进留下的状态直接预测不可靠。必须先 resetState 清空再用训练数据把状态推进到序列末尾这个动作称为预热。预热之后用测试集里每个真实窗口做单步预测评估模型在给定真实历史条件下的误差这是 LSTM 预测最贴近实际使用的评估口径之一。net resetState(net); net predictAndUpdateState(net, XTrain); % 预热状态推进到训练集末端 YTestPred zeros(numel(XTest), 1); for i 1:numel(XTest) [net, yp] predictAndUpdateState(net, XTest{i}); YTestPred(i) yp; end rmse1 sqrt(mean((YTestPred - cell2mat(YTest)).^2));逻辑说明predictAndUpdateState在一次调用里同时完成预测与状态更新第一个返回值是更新后的网络第二个是预测值。循环里每个XTest{i}都是来自真实历史的重叠窗口因此这里算的是单步预测误差衡量模型对短程动态的拟合能力。YTestPred与cell2mat(YTest)都是列向量减法和 mean 直接可用。注意rmse1只是单步口径不能代表多步预测水平两者差距往往很大。3.3 多步预测自回归滚动与误差累积的起点多步预测的常见做法是从训练集末端出发把上一轮的预测值接回输入窗口让网络自回归地往下滚。从第二步起输入里已经混入网络自己的输出这是误差累积的根源也是多步预测曲线逐渐偏离真实序列、趋于一个均值或缓慢漂移的原因。下面的代码直接对应这个机制。net resetState(net); net predictAndUpdateState(net, XTrain); % 再次从训练集末端起步 Xwind XTrain{end}; % 最后一个包含真实值的窗口 numPred 50; ypred zeros(numPred, 1); for k 1:numPred [net, yk] predictAndUpdateState(net, Xwind); ypred(k) yk; Xwind [Xwind(2:end), yk]; % 窗口右移一格用预测值补位 end predFinal ypred * sigma mu; % 反归一化回原始量纲参数说明Xwind每次更新等价于丢弃最老的真实值、追加最新的预测值网络始终只看 30 个输入。numPred 50决定预测时长建议从 10、20、30 这样的小步长开始先观察第三步以后曲线是否明显发散一旦发散优先检查模型记忆长度与样本量而不是把GradientThreshold或学习率来回微调。单步与多步的 RMSE 要分别记录能说清楚单步 0.3、30 步 1.1这种差异比贴一张漂亮的拟合图更有说服力。提示多步预测的误差永远大于单步预测这是自回归滚动的固有代价不是模型坏了。评估时把两种口径都写出来决策者才能知道模型承诺到多长是可信的。4. 从现象反推参数LSTM 预测的三个典型坑4.1 预测漂移网络把自己的输出当成了事实多步预测一旦超过十几个步长预测曲线往往先快速逼近历史均值然后贴在某个水平线上不动这叫预测漂移。机理上自回归滚动让误差逐级累积网络每一轮都面对一个偏离训练分布的输入窗口分布偏移又放大下一步误差形成正反馈。这不是代码 bug也不说明模型没训练好。常见的处理手段有三类第一类是限制预测步长只承诺模型可信的区间第二类是改用直接多步策略把输出层从 1 个神经元改成 h 个一次性输出未来 h 步训练时用步长加权的损失第三类是在训练阶段引入 teacher forcing把真实值按一定概率喂回输入窗口让网络在训练时见过干净与被污染两种输入分布。对多数工程场景先做第一类、把预测区间切成若干段滚动刷新成本最低。4.2 样本量小与过拟合先看隐单元数再看 dropout单层 LSTM 隐单元数为 64 时单变量输入下参数量约 1.7 万而一段工业传感器序列经过滑窗后通常只有几百到几千个样本参数远多于样本过拟合几乎是必然。表现是训练损失持续下降而验证损失在 20 轮左右开始反弹。此时不要急着加数据以外的技巧先把lstmLayer的隐单元数降到 16 或 32观察验证损失是否回落同时把dropoutLayer的丢弃率从 0.2 提到 0.4它影响的是 LSTM 输出到全连接层之间的连接。注意 MATLAB 的 lstmLayer 本身没有内置 dropout 参数必须用独立的 dropoutLayer并确认它与OutputMode的配合符合预期单层网络用last层叠结构需要中间层保持sequence。样本量在几百量级时把MaxEpochs从 120 下调到 60并借助验证集损失判断早停比把希望押在正则化上更直接。现象最可能原因首个调整动作训练损失不降学习率过小或窗口无信息学习率提至 0.01先查 numSteps训练降、验证升隐单元过多隐单元降到 16 或 32dropout 提到 0.4损失中途变 NaN梯度爆炸GradientThreshold 降到 0.5学习率减半多步预测贴均值线窗口记忆不足增大 numSteps先看自相关滞后表里的每一条都对应可直接执行的修改路径。调参时一次只改一行记录改动前后的单步与多步 RMSE比同时动三个参数更可能定位到真正的瓶颈。4.3 numSteps 到底取多少先用自相关定位记忆长度numSteps 是滑窗长度等于模型能看到的过去。取太小网络学不到周期或趋势取太大窗口之间重叠度过高样本冗余训练效率下降模型还要为遥远过去的无关信息分配容量。常见做法是先画自相关图观察自相关系数衰减到零附近的滞后阶数再取该阶数附近的若干候选值放进训练段做网格比较。figure; autocorr(yn, 60);说明autocorr来自 Econometrics Toolbox60 表示画到滞后 60 步纵轴落在置信带之外说明该滞后仍有统计相关的记忆。以本章合成数据为例主周期约为 2*pi/0.3 约等于 21 个点自相关会在滞后 10 到 20 之间明显衰减此时 numSteps 取 20 到 30 是合理区间若序列存在明显的季节性周期让 numSteps 覆盖一个完整周期并留少量余量通常是稳妥的起点。网格比较时只利用训练段内部的效果做初筛最终判定以第 5 章的滚动验证结果为准避免在测试段上反复试探造成选择偏差。5. 用滚动验证与残差自相关校准 LSTM 预测模型5.1 滚动原点验证用多个起点代替单一留出集单一训练测试切分受切点位置影响很大换一个起点可能让 RMSE 变化 30% 以上。更可靠的是滚动原点验证在训练段内取多个起点每个起点只利用它之前的数据训练预测之后固定长度的区间再汇总各次预测误差。下面的骨架可以直接套用。origins [300, 450, 600, 750]; rmseRoll zeros(numel(origins), 1); for k 1:numel(origins) % 1) 用 yn(1:origins(k)) 重建滑窗并训练网络复用第 3 章代码 % 2) 从第 origins(k) 个点起滚动预测 30 步 % 3) 与 yn(origins(k)1:origins(k)30) 比较写入 rmseRoll(k) end meanRmse mean(rmseRoll);说明每个起点都重新训练一次网络训练时间会成倍增加但对短序列预测是值得的。origins按时间递增越晚的起点可利用数据越多rmseRoll 从前往后通常会缓慢改善若最后一个起点误差反而跳升多半是序列在该区间发生了结构性变化这比盲目调参更值得深挖。5.2 残差自相关与朴素基线判断 LSTM 是否真的在学结构校准模型的最后一步是看残差。把多步预测的残差做一次自相关滞后 1 阶自相关系数若大于 0.6说明残差里仍有大量一阶记忆模型很可能只是学会了把上一时刻的值抄出来这种模型在趋势型序列上表现不错遇到转折点误差会急剧放大。此时优先调整 numSteps而不是继续调学习率。另一个低成本参照是朴素基线用当前值直接作为未来所有步的预测值。以 30 步预测为例若 LSTM 的多步 RMSE 没有低于朴素基线的 80%说明序列里真正可外推的结构有限此时换成 BiLSTM 或加深网络都不会有本质改善先把数据长度和特征质量补起来更实际。滚动验证、残差自相关与朴素基线三者结合能在一张图里同时回答模型是否可用、能预测多长、瓶颈在数据还是结构这三个问题。先把残差滞后一阶自相关打出来再决定下一步动哪里。本文还有配套的精品资源点击获取
返回列表