简介:本资源面向需要掌握时序预测的 Matlab 用户与算法学习者,提供一套可直接运行的 LSTM 长短期记忆神经网络预测方案,解决从数据读取、模型搭建到结果评估的完整流程问题。压缩包共 7 个文件,约 363KB,包含 1 个 main.m 主程序、1 个 xlsx 示例数据集以及 5 张 png 结果图,主程序中文注释清晰,按示例数据格式替换数据集即可运行。内容覆盖训练集与测试集的预测值对比真实值曲线、训练过程图及预测结果对比图,并给出评价指标计算,便于直观判断模型拟合效果。已有 620 人学习下载,适合具备基础 Matlab 操作能力、希望快速复现 LSTM 时序预测实验的读者参考,也可作为课程设计或论文实验的起步模板。
1. 从一份能直接跑的 Matlab LSTM 时序预测包说起
手里拿到一份时序数据,领导要下周看到预测曲线和误差指标,这种场景下最耗时间的往往不是建模思路,而是把数据读进来、把网络搭起来、把图画出图、把 RMSE 和 MAPE 算出来这一整套流程。这份 Matlab LSTM 长短期记忆神经网络时序预测算法资源,就是冲着这个痛点来的:一个 main.m 主脚本、一份 Excel 数据集、若干训练与测试对比图,外加训练过程曲线和评价指标输出。它解决的是「单变量时序预测从数据到结论」的完整闭环,适合做电力负荷、销量、传感器读数这类按时间排列的数值预测,也适合刚接触 LSTM 想先跑通一遍再改结构的人。中文注释写得比较清楚,替换数据集、改几行参数就能复现,不需要从零搭网络。
2. LSTM 时序预测的骨架:数据怎么进、网络怎么搭
2.1 为什么时序预测绕不开 LSTM 的门控结构
普通全连接网络处理时序数据时,把每个时间点当成独立特征,前一刻的信息传不到下一刻,预测出来的曲线要么滞后要么平滑得没有细节。LSTM 靠输入门、遗忘门、输出门三个门控单元,决定哪些历史信息保留、哪些丢弃,这让它在捕捉长间隔依赖上比传统 RNN 稳得多。时序预测里常见的滞后效应——比如今天的气温受前三天影响——正好是 LSTM 的强项。
这份资源用的是 Matlab 深度学习工具箱里的 lstmLayer,配合 sequenceInputLayer 和 regressionLayer 组成回归网络。选它而不是自己手写前向传播,是因为工具箱已经把反向传播、梯度裁剪、mini-batch 调度都封装好了,main.m 里只需要声明层结构、训练选项和数据划分。对一线工程来说,能少写一百行容易出错的梯度代码,就多一分按时交付的把握。
需要留意的是,LSTM 不是万能的。数据如果几乎没有时间相关性,比如随机噪声,LSTM 学出来的东西和均值预测差不多。判断方法很简单:先画自相关图,如果滞后几阶的自相关系数都在零附近,那这份数据用 LSTM 就是杀鸡用牛刀,换成移动平均可能更省事。
2.2 数据准备:Excel 读入、归一化与滑窗构造
时序预测的第一步永远是把原始序列变成网络能吃的样本对。这份资源的数据集是 Excel 格式,main.m 里用 readmatrix 或 xlsread 读入,然后做归一化和滑窗。滑窗的逻辑是:用前 N 个时刻的值预测第 N+1 个时刻的值,窗口向前滑动就得到一批训练样本。
% 读取 Excel 数据集,假设第一列是时间,第二列是待预测数值 data = readmatrix('数据集.xlsx'); series = data(:, 2); % 取出数值列 series = series(~isnan(series)); % 去掉缺失值 % 归一化到 [0,1],避免量纲差异导致训练震荡 seriesNorm = (series - min(series)) / (max(series) - min(series)); % 滑窗构造样本,lookback 为回看步数 lookback = 10; X = []; Y = []; for i = 1 : length(seriesNorm) - lookback X = [X; seriesNorm(i : i + lookback - 1)']; Y = [Y; seriesNorm(i + lookback)]; end这段代码里 lookback 是最关键的参数,它决定网络能看到多长的历史。设太小,模型记不住周期性;设太大,样本数骤减且训练变慢。常见做法是先按数据周期定,比如日周期数据取 7 或 14,再根据验证集误差微调。归一化用 min-max 而不是 z-score,是因为这份资源的输出层没有额外反归一化封装,min-max 的反变换只需一行乘加,不容易出错。
注意:如果原始数据里有明显的异常尖峰,归一化前最好先做一次中值滤波或 3σ 剔除,否则 min 和 max 会被单个异常值拉偏,整条序列压缩到很窄的区间,网络学不到东西。
2.3 网络层结构与训练参数设置
层结构决定了模型容量,训练参数决定了能不能收敛。这份资源的 main.m 里,网络大致是 sequenceInputLayer 接 lstmLayer 再接 fullyConnectedLayer 和 regressionLayer。lstmLayer 的 NumHiddenUnits 是核心超参,它控制隐藏状态维度,太小欠拟合,太大过拟合且显存吃紧。
numFeatures = 1; % 输入特征维度,单变量为 1 numHiddenUnits = 128; % 隐藏单元数,常用 64/128/256 numResponses = 1; % 回归输出维度 layers = [ ... sequenceInputLayer(numFeatures) lstmLayer(numHiddenUnits, 'OutputMode', 'last') fullyConnectedLayer(numResponses) regressionLayer]; options = trainingOptions('adam', ... 'MaxEpochs', 200, ... 'MiniBatchSize', 32, ... 'InitialLearnRate', 0.005, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropPeriod', 50, ... 'LearnRateDropFactor', 0.5, ... 'GradientThreshold', 1, ... 'ValidationData', {XVal, YVal}, ... 'ValidationFrequency', 10, ... 'Plots', 'training-progress', ... 'Verbose', false);OutputMode 设为 last 表示只取最后一个时间步的输出做回归,这是单步预测的标准写法;如果要做多步预测,得改成 sequence 并调整输出维度。InitialLearnRate 取 0.005 配合分段衰减,是时序回归里比较稳的组合,学习率太大损失会来回跳,太小则 200 轮都收敛不到位。GradientThreshold 设 1 是防梯度爆炸的保险,LSTM 虽然比普通 RNN 稳,但序列一长照样会炸。
训练时如果验证损失连续多轮不降,先别急着加层,优先检查学习率和 batch size。我一般会把 MiniBatchSize 从 32 调到 16 试一轮,小批量带来的噪声有时反而帮模型跳出局部极小。
3. 跑通 main.m:从训练到预测输出的完整链路
3.1 训练集与测试集划分的两种做法
时序数据的划分和普通回归不一样,不能随机打乱,否则未来信息会泄漏到训练集里,测试指标好看但上线就崩。这份资源默认按时间顺序切分,前 80% 做训练,后 20% 做测试,这是最稳妥的做法。
trainRatio = 0.8; n = size(X, 1); idxTrain = 1 : floor(n * trainRatio); idxTest = floor(n * trainRatio) + 1 : n; XTrain = X(idxTrain, :); YTrain = Y(idxTrain); XTest = X(idxTest, :); YTest = Y(idxTest);按顺序切分的好处是测试集完全在训练集时间之后,模拟真实预测场景。代价是测试集只有一段,指标波动可能较大。如果数据量足够,可以用滚动预测的方式:每次用历史数据训练,预测下一步,然后窗口前移,这样能得到多条预测曲线做统计。资源里给的是单次划分,够用但不算最严谨,做论文或正式报告时可以自己补一个滚动验证。
3.2 训练过程监控与损失曲线解读
main.m 里开了 training-progress 图,训练时能实时看到损失下降。这份资源附带的训练图.png 就是这条曲线的截图。看损失曲线有几个经验点:训练损失和验证损失同步下降且贴近,说明拟合正常;验证损失先降后升,说明过拟合,该早停或减隐藏单元;两条曲线都平在高位,说明欠拟合,加层或加单元。
% 训练网络 net = trainNetwork(XTrain, YTrain, layers, options); % 用训练好的网络做预测 YPredTrain = predict(net, XTrain, 'MiniBatchSize', 32); YPredTest = predict(net, XTest, 'MiniBatchSize', 32); % 反归一化回原始量纲 YPredTrain = YPredTrain * (max(series) - min(series)) + min(series); YPredTest = YPredTest * (max(series) - min(series)) + min(series); YTestReal = YTest * (max(series) - min(series)) + min(series);predict 和 trainNetwork 分开调用,是为了拿到预测值后统一做反归一化和指标计算。MiniBatchSize 在预测阶段可以设大一点,不影响结果只影响速度。反归一化必须用训练集算出的 min 和 max,不能用测试集的,否则量纲基准不一致,指标会失真。
3.3 预测对比图与评价指标的计算
资源里给了训练集预测值 VS 训练集真实值.png 和测试集预测值 VS 测试集真实值.png,这两张图是判断模型好坏最直观的依据。图画出来之后,还要有量化指标兜底。时序预测常用的三个指标是 RMSE、MAE 和 MAPE。
% 计算评价指标 rmse = sqrt(mean((YPredTest - YTestReal).^2)); mae = mean(abs(YPredTest - YTestReal)); mape = mean(abs((YPredTest - YTestReal) ./ YTestReal)) * 100; fprintf('测试集 RMSE: %.4f\n', rmse); fprintf('测试集 MAE : %.4f\n', mae); fprintf('测试集 MAPE: %.2f%%\n', mape); % 绘制对比图 figure; plot(YTestReal, 'b-', 'LineWidth', 1.2); hold on; plot(YPredTest, 'r--', 'LineWidth', 1.2); legend('真实值', '预测值'); xlabel('时间步'); ylabel('数值'); title('测试集预测结果对比'); grid on;RMSE 对大误差敏感,适合关注极端偏差的场景;MAE 更稳健,反映平均偏差;MAPE 是百分比,方便跨量纲比较,但真实值接近零时会爆炸,这时候要换 SMAPE。三个指标一起看,比只看一个靠谱。如果 RMSE 很小但 MAPE 很大,说明大部分点预测准,少数接近零的点误差被放大了,得回去看那些点的数据质量。
提示:画对比图时如果两条曲线几乎重合,别急着高兴,先检查是不是数据泄漏了——比如归一化用了全量数据的 min/max,或者滑窗时测试样本混进了训练集。
4. 避坑与排查:LSTM 时序预测里最容易翻车的几处
4.1 现象:损失不下降,一直卡在初始值附近
原因通常有三个:学习率过大导致震荡、数据没归一化导致梯度尺度失衡、或者序列长度和 batch 不匹配。先看训练窗口的损失值,如果它在同一个数量级来回跳,把 InitialLearnRate 降到 0.001 再试。如果损失几乎不动,检查归一化那一步是不是漏了,原始数据量纲在几千以上时,不归一化基本训不动。还有一种隐蔽情况是 lookback 设得比序列还长,构造出的样本为空,trainNetwork 直接报错或返回随机权重。
4.2 现象:测试集指标远差于训练集
这是过拟合的典型信号。先看隐藏单元数,128 对几百条样本来说偏大,降到 32 或 64 往往立刻改善。其次看 MaxEpochs,200 轮对小型数据集太多,配合 ValidationData 做早停更合理。如果数据本身噪声大,可以加 dropout 层,但 LSTM 后面加 dropout 要注意位置,一般放在 lstmLayer 和 fullyConnectedLayer 之间,概率取 0.2 到 0.5。
4.3 现象:预测曲线整体平移,形状对但数值偏
这种「形状对、幅值偏」的问题,九成出在归一化和反归一化的基准不一致。检查反归一化时用的 min 和 max 是不是训练集算出来的那一组。如果中途重新读了数据或者改了划分比例,很容易把测试集的极值混进去。另一个可能是输出层没有偏置,fullyConnectedLayer 默认带偏置,但如果手动改了结构,确认一下没把偏置去掉。
4.4 现象:MAPE 出现 Inf 或 NaN
真实值里有零或接近零的点,除法直接爆掉。解决办法是改用 SMAPE,或者给分母加一个极小常数。更根本的做法是检查数据里为什么会有零,是缺失值填零还是真实业务里的零,前者要补插值,后者要考虑这份数据适不适合用百分比误差。
4.5 现象:每次运行结果都不一样
Matlab 默认每次启动的随机种子不同,网络初始化权重和 batch 打乱顺序都会变。要做可复现的实验,在脚本开头固定随机种子。注意 rng 只影响 Matlab 层面的随机数,GPU 上的某些操作仍有非确定性,追求完全一致需要设成单线程 CPU 训练,但那样速度会慢很多,一般固定种子就够了。
rng(42); % 固定随机种子,保证结果可复现5. 把这份资源用出边界:多步预测与参数扫描的实操技巧
单步预测跑通之后,真正的工作场景往往要求多步预测,比如用过去 30 天预测未来 7 天。这份资源的骨架可以直接改:把 OutputMode 从 last 改成 sequence,输出维度改成预测步长,标签 Y 从单值变成向量。改完之后网络输出是一个序列,反归一化和指标计算要按维度展开,别再用 mean 一把梭。
% 多步预测:用过去 lookback 步预测未来 horizon 步 horizon = 7; X = []; Y = []; for i = 1 : length(seriesNorm) - lookback - horizon + 1 X = [X; seriesNorm(i : i + lookback - 1)']; Y = [Y; seriesNorm(i + lookback : i + lookback + horizon - 1)']; end % 网络输出层改为 sequence 模式 layers = [ ... sequenceInputLayer(1) lstmLayer(128, 'OutputMode', 'sequence') fullyConnectedLayer(horizon) regressionLayer];多步预测的误差会随步长累积,第 7 步的精度通常明显低于第 1 步。评估时要分步长报告指标,而不是只给一个平均值,否则会掩盖远端预测的崩坏。我一般会画一张「误差随预测步长变化」的曲线,如果第 3 步之后 RMSE 就翻倍,说明模型的有效预测窗口只有 2 到 3 步,业务上就不能拿它做太长远的决策。
参数扫描是另一个值得花时间的地方。NumHiddenUnits、lookback、InitialLearnRate 这三个参数对结果影响最大,可以用嵌套循环做网格搜索,每个组合训练一次记录验证集 RMSE。样本少的时候别扫太细,粗粒度先定位区间,再在小区间里细扫。扫描过程记得把每次的配置和指标写进表格,不然跑完十几组就记混了。
| 参数 | 常用范围 | 影响方向 | 调整建议 |
|---|---|---|---|
| NumHiddenUnits | 32 / 64 / 128 / 256 | 容量与过拟合 | 样本少选小值 |
| lookback | 5 / 10 / 20 / 30 | 历史依赖长度 | 按数据周期定 |
| InitialLearnRate | 0.001 / 0.005 / 0.01 | 收敛速度与稳定性 | 不降损失就减半 |
| MiniBatchSize | 16 / 32 / 64 | 梯度噪声 | 小数据选小值 |
最后说一个验证习惯:每次改完参数,别只看测试集指标,把训练集和测试集的预测对比图都画出来并排看。训练集拟合好、测试集也跟得上,才是真的稳;训练集完美、测试集发散,那就是过拟合在敲门。从那以后我每次跑时序预测,都强制先固定随机种子、再确认归一化基准、最后分步长报告误差,这三步走完才敢把结果发出去。希望帮到你。
本文还有配套的精品资源,点击获取