资讯动态

基于MATLAB的LSTM、BILSTM、GRU、BIGRU与BP负荷预测对比

发布时间:2026/10/25 19:10:08 来源:尧图企业网站定制
简介电力负荷预测是电网调度与能源管理中的核心任务这份压缩包聚焦LSTM、BILSTM、GRU、BIGRU及BP五种模型的MATLAB实现适合电力系统研究人员、数据分析师以及深度学习初学者对照学习。包内共32个文件以9个可运行的m脚本为主覆盖数据归一化、模型训练、评估指标计算等环节另有7个mat数据集、2个xlsx电力负荷与价格数据、12张png结果图及2个asv备份文件压缩包整体约5.49MB小巧紧凑。目前已有489人学习下载。通过这些脚本读者可以直接运行各模型对应的主程序结合澳大利亚电力负荷与价格预测数据对比不同循环神经网络在负荷预测任务上的效果并借助MSE、RMSE、R²等指标评估模型性能适合用于课程设计、论文实验或工程预研。1. 把五个负荷预测模型打包进一套 MATLAB 代码LSTM、BILSTM、GRU、BIGRU 与 BP 神经网络对比实验的落地过程电力负荷预测这件事做过的人都知道降压站要按小时申报用电计划算少了要考核算多了白白买电。传统时序方法碰上工作日和节假日的突变预测误差能到百分之十几。这套资源给的不是单个模型而是把 LSTM、BILSTM、GRU、BIGRU、BP 神经网络五个模型分别写好 main 脚本、统一评估函数的 MATLAB 工程包直接就能跑对比实验。它能解决的核心问题只有一个让你在同一个数据集、同一套评估口径下搞清楚五种网络结构在你的负荷数据上到底谁更靠谱。适合正在做毕设、写小论文、或者刚接手负荷预测项目需要快速出基线结果的工程师不需要你从头搭代码改改数据路径和网络参数就能看到训练曲线、预测对比图和误差指标。2. 先摸清数据和代码文件结构哪个文件负责训练、哪个文件负责评估、怎么替换你自己的负荷数据2.1 按文件名拆解这套工程包的职责边界拿到压缩包之后第一件事不是双击打开某个 .m 脚本就开始跑而是先把文件按职责归类。这套包的命名习惯相当直白main开头的都是训练与预测主脚本MSE_RMSE_MBE_MAE.m和R_2.m是评估函数.mat文件是预处理好的训练数据xlsx是原始数据。从代码组织上来说这符合 MATLAB 项目的一般惯例——主脚本、函数文件、数据文件三层分离。五个主脚本对应五个模型这是核心入口mainlstm.m标准 LSTM 单层或多层网络训练与预测脚本mainbilstm.m双向 LSTM两个方向同时编码时序特征maingru.m门控循环单元比 LSTM 少一个门计算开销更低mainbigru.m双向 GRU原理对应 BILSTMmainbp.m三层或四层 BP 前馈网络作为非时序基线模型注意mainz.m和mainz.asv.asv是 MATLAB 的自动保存文件说明作者在调试过程中手动备份过这个文件可以直接不看。main0.m大概率是数据加载与预处理的辅助脚本打开看一眼就知道它是把 Excel 转成.mat流程。数据文件方面lstmdata.mat、bilstmdata.mat、grudata.mat、bigrudata.mat、maydata.mat都是已经归一化好的训练输入输出对。maynet.mat看名字像是保存好的训练结果网络可以做加载测试用。澳大利亚电力负荷与价格预测数据.xlsx是原始数据包含负荷和电价两列以上字段data.xlsx是精简版或经过初步清洗的数据。2.2 从 Excel 到 .mat数据预处理的三种常规做法main0.m这类预处理脚本的核心职责是把原始负荷序列转换成神经网络能吃的样本对。常见做法是滑窗构造输入输出用过去 24 个小时的负荷数据预测下一个小时。这涉及到两个关键参数——滑动窗口长度input_len和预测步长output_len。窗口设太短网络学不到日周期规律设太长训练数据量骤减而且引入过多噪声。我用 MATLAB 处理这个环节时一般会先固定随机种子避免每次运行切分训练集和测试集的结果不一样。之后做归一化把负荷数据映射到[0, 1]区间。这里有个容易翻车的细节归一化的最大值和最小值必须单独保存预测完成后要做反归一化还原否则预测曲线会被压缩在一个极小的范围内画出来的图用户根本看不懂。% 滑窗构造样本对间隔为1小时窗口24小时预测未来1小时 function [XTrain, YTrain, XTest, YTest] prepare_data(data, input_len, output_len, train_ratio) % 归一化到[0,1]注意用全量数据的min/max而不是训练集的 mu min(data); sigma max(data) - min(data); data_norm (data - mu) / sigma; % 构造输入输出矩阵 X []; Y []; for i 1 : length(data_norm) - input_len - output_len 1 X [X; data_norm(i : i input_len - 1)]; Y [Y; data_norm(i input_len : i input_len output_len - 1)]; end % 按比例切分训练集和测试集 num_train floor(size(X, 1) * train_ratio); XTrain X(1 : num_train, :); YTrain Y(1 : num_train, :); XTest X(num_train 1 : end, :); YTest Y(num_train 1 : end, :); end这段滑窗代码的逻辑不复杂但mu和sigma用全量数据计算是关键决策。如果只用训练集的 min/max 来归一化而测试集里有超出范围的数据归一化后的值会跑到[0, 1]区间外面激活函数的输出饱和预测误差直接被放大。第 2 行到第 4 行做的事情就是先求归一化参数中间循环构造滑窗样本最后按train_ratio切分。input_len24和output_len1是负荷预测最常见的默认参数对应日周期预测下一小时。2.3 原始数据长什么样时间戳、负荷、电价三维度打开澳大利亚电力负荷与价格预测数据.xlsx你大概率看到三列数据日期时间、电力负荷值、电价。负荷数据从几百到几千兆瓦量级波动电价则会出现尖峰这两个特征量纲完全不同。如果直接把两列拼在一起喂给模型负荷特征会被电价特征的数值范围淹没所以预处理必须分列归一化也就是对负荷和电价分别取 min/max。这套数据在实际实验中还有一个特性它包含明显的日周期性、周周期性和季节性。LSTM 家族模型能学到这些周期性但前提是滑窗长度不能太短。如果你是拿这套数据做论文对照实验建议把数据集切成连续的时间段来划分训练集和测试集而不要随机打乱再切分——时序数据一旦打乱就等于是用了未来信息去预测过去实验结论完全失真。3. 五个模型的核心差异和 MATLAB 实现骨架改哪里就能换模型3.1 LSTM 与 GRU 的结构取舍门控数量不是唯一差距LSTM 有三个门——输入门、遗忘门、输出门每个门都有一个 sigmoid 层和一个 tanh 层组合。GRU 只有两个门——更新门和重置门参数数量大约减少四分之一到三分之一。这个差异在训练速度上体现得最直观同样一个数据集GRU 收敛通常比 LSTM 快 10% 到 20%。但快并不代表更好。LSTM 的三个门机制允许网络更精细地控制记忆的写入、保留和读取在序列特别长、依赖关系跨越很长时间步的场景下稍微占优。负荷预测的数据往往是一个月甚至一年的小时级数据长期依赖真实存在比如上周同一天的负荷模式LSTM 理论上能刻画得更好。不过这种优势要在数据量足够大的时候才明显数据量只有几千条时GRU 反而因为参数少、不容易过拟合表现常常更好。在 MATLAB 里实现这两者的差异非常小核心就在网络层的替换。下面这段代码是mainlstm.m的核心段落% 定义 LSTM 网络结构序列输入 - LSTM层 - 全连接 - 回归输出 layers [ sequenceInputLayer(24) % 输入维度是24对应24小时滑窗 lstmLayer(128, OutputMode, last) % 128个隐藏单元只输出最后一步 fullyConnectedLayer(1) % 单步预测所以输出维度为1 regressionLayer]; % 回归任务损失函数用MSE % 训练参数Adam优化器初始学习率0.005120轮迭代 options trainingOptions(adam, ... MaxEpochs, 120, ... InitialLearnRate, 0.005, ... LearnRateSchedule, piecewise, ... LearnRateDropPeriod, 60, ... LearnRateDropFactor, 0.2, ... MiniBatchSize, 64, ... Verbose, 0, ... Plots, training-progress);把 LSTM 换成 GRU 只需把lstmLayer改成gruLayer其余结构完全不用动。第 2 行的sequenceInputLayer(24)必须和滑窗长度保持一致如果prepare_data里input_len改成 48这里的 24 也要跟着改否则 MATLAB 直接报维度不匹配错误。lstmLayer(128)的 128 是隐藏单元数量这个参数越大模型表达能力越强但训练时间成倍增加且更容易过拟合。小数据集从 64 开始试大数据集 128 或 256 都行。3.2 从单向到双向BILSTM 和 BIGRU 的上下文增强逻辑双向网络的核心思路是在时间维度上跑两个独立的循环网络一个从左往右读序列另一个从右往左读序列然后把两个方向输出的特征拼接或相加送入下一层。这样做的前提假设是未来的上下文信息有助于理解当前时刻的负荷状态。对负荷预测来说这通常成立——比如午后负荷的下降趋势网络如果能看到下午的上升曲线对当前尖峰时刻的估计就会不同。双向结构的代价是训练时间翻倍。因为每一层实际上跑了两个方向的网络参数量的增加和训练和推理时程翻倍是同步的。如果你用的是bilstmLayerMATLAB 内部会自动处理两个方向的序列拼接不需要额外调整数据格式。% 双向 LSTM两个方向的隐藏状态拼接输出 layers [ sequenceInputLayer(24) bilstmLayer(128, OutputMode, last) fullyConnectedLayer(1) regressionLayer];在实际对比实验里一个常见现象是双向网络在测试集上的误差略低于单向网络但容易在训练初期出现损失震荡。原因在于双向网络需要同时学习两个方向的特征梯度更新路径更长初始学习率设置稍微偏大就会出现不稳定。我的建议是双向网络把初始学习率下调一半比如从 0.005 改成 0.002再把LearnRateDropPeriod缩短让学习率更快衰减下来。3.3 BP 神经网络的定位不是陪跑而是基线参照BP 网络在这个工程包里的作用经常被低估。很多人把它当成最简单的对比模型实际上它是整个实验里不可缺失的判定基准。LSTM、GRU 这些模型在测试集上的预测误差如果连 BP 都没跑赢说明你的数据和预处理存在严重问题。BP 网络是纯前馈结构输入是 24 个负荷值展平成向量输出一个预测值中间层用 sigmoid 或 ReLU。它不感知时间顺序24 个输入位置调换了顺序预测结果不受影响。这既是它的短板也是它的特点用 BP 做对比看的是多出来的性能到底来自网络结构的时序建模能力还是仅仅是数据预处理的功劳。MATLAB 里实现 BP 有两种路径一种是用feedforwardnet函数快速构建另一种是手动定义网络层。前者适合快速出结果后者适合精确参数控制。建议用feedforwardnet因为它的内置训练算法trainlmLevenberg-Marquardt在小数据集上收敛速度远快于 Adam而且收敛稳定性好。这个特性是 BP 网络在这个项目里最大的工程价值——它是你调试数据预处理是否正确的最快工具。4. 评估指标函数拆解MSE、RMSE、MBE、MAE 和 R² 在 MATLAB 里的计算方法与判读逻辑4.1 四个误差指标分别暴露什么问题压缩包里的MSE_RMSE_MBE_MAE.m和R_2.m是评估模型预测效果的核心函数。MSE 是均方误差把所有预测误差平方后取平均它对大误差极其敏感——如果模型在某些时刻出现严重偏离MSE 会被这几个异常点拉高。RMSE 是 MSE 开方后的值量纲回归到负荷数值本身比如 30 MW 的 RMSE 就是可解释的。MBE 是平均偏差误差预测值减真实值取平均它的符号有明确含义正值说明模型系统性地高估负值则说明系统性低估。MAE 是平均绝对误差不区分预测误差是来自个别大偏差还是整体小偏差。这四个指标放一起看能暴露不同问题。MBE 接近 0 但 RMSE 很大的组合说明模型正负误差抵消严重整体趋势对但波动幅度没抓住MBE 明显偏正说明模型有系统偏差需要通过调整预测结果的偏置来修正。在实际实验中LSTM 容易出现 RMSE 大但 MAE 小的组合——意味着大部分时间都预测得很准但偶尔会有几个时刻完全偏离这通常发生在负荷曲线的陡升陡降段。% 统一评估函数输入真实值和预测值输出四个误差指标 function [mse, rmse, mbe, mae] MSE_RMSE_MBE_MAE(y_true, y_pred) % 去除NaN值预测结果中可能因边界效应产生无效值 valid ~isnan(y_true) ~isnan(y_pred); y_true y_true(valid); y_pred y_pred(valid); % 逐项计算误差 errors y_pred - y_true; mse mean(errors.^2); rmse sqrt(mse); mbe mean(errors); mae mean(abs(errors)); end第 2 行的valid逻辑索引是在做执行检测防止输入序列里混入 NaN。这个过滤操作非常必要因为训练完的网络在预测时初始时刻的隐藏状态是随机初始化的前几步预测往往偏离严重有些同学会保留这些异常值参与指标计算导致评估结果虚高。第 4 到第 8 行分别计算四个指标逻辑直接到不需要额外注释。4.2 R² 的判定边界95% 代表什么90% 代表什么R_2.m计算的是决定系数公式是 1 减去残差平方和与总平方和的比值。它在负荷预测中的含义可以通俗理解为模型捕捉到了时间序列中多大比例的方差变化。R² 达到 0.95 意味着模型解释了 95% 的负荷波动剩余 5% 的波动是模型抓不到的。但有个很容易被忽视的问题R² 很容易被数据的整体方差大小误导。如果测试集所在的时间段刚好包含一个极大的负荷突变总平方和会被拉大R² 在分子不变的情况下会自动变高。所以 R² 必须和 RMSE 一起看R² 很高但 RMSE 也不低的情况完全可能同时存在这时候 R² 的参考价值就很低了。利用 R² 还有一个作用判断多个模型的差异是否有意义。如果 LSTM 的 R² 是 0.973GRU 是 0.968这个 0.005 的差距通常不足以说明 LSTM 更优因为换一次随机种子这个差距可能就反过来了。工程上判断模型优劣更靠谱的标准是多次实验取平均值再用 t 检验或至少看波动范围这套代码跑出来的单次指标差异在 0.01 以内都算同一水平模型。5. 避坑与排查五个必踩的坑——从数据泄漏到归一化边界5.1 坑一训练损失下降正常但预测曲线是一条平线现象模型训练完成loss 曲线稳定下降但画出的预测结果几乎是一条水平直线贴近训练集的均值。原因最常见的诱因是滑窗构造样本时输入特征和输出标签之间没有有效的时间依赖。另一种情况是归一化时误用了在线归一化——测试集使用了训练集的均值和标准差如果测试集分布偏离太大模型学到的隐状态几乎不随输入变化。解决先检查prepare_data里X和Y的构造逻辑确认Y取的是未来时刻而非当前时刻。再看data_norm的归一化代码把全量的 min/max 打印出来和实际负荷数据的最大值核对一遍。如果平线出现在测试集的前几个时刻而后续正常这是隐藏状态初值问题直接把预测序列的前 5 个点舍弃再画图就好。5.2 坑二BILSTM 训练时间比 LSTM 多出不止一倍现象mainbilstm.m的训练时间远超mainlstm.m上图一看显著多出 200% 以上。原因双向网络虽然在参数量上是单向的约两倍但训练时间翻倍属于正常现象如果超出太多问题出在 GPU 资源没有吃满MATLAB 默认用 CPU 训练 LSTM 层而 CPU 训练下双向网络的计算复杂度会被成倍放大。解决检查trainingOptions里有没有设置ExecutionEnvironment, gpu。安装 Deep Learning Toolbox 之后用 GPU 训练这五个模型的速度差异会明显缩小。值得注意的是BP 网络在 CPU 上训练很快但 LSTM 家族在 CPU 上速度差异巨大如果手头没有 NVIDIA 显卡可以先跑通 GRU把 BILSTM 放到最后跑。5.3 坑三评估指标算出来 MBE 为正负 50 以上模型预测整体偏高现象MBE 指标异常大且符号一致预测曲线整体在真实曲线上方。原因反归一化环节出了问题。训练时用归一化数据计算误差预测完成后把结果反归一化时如果用的是训练集的最大值和最小值但这个最大值远小于测试集里出现的负荷尖峰反归一化后的预测值会被压得过低或整体偏移MBE 随之被污染。解决反归一化必须使用训练前保存的全量数据的mu和sigma而且必须把保存的参数从工作区导出为.mat或csv文件不要在预测脚本里重新计算。另一个排查方向是检查训练目标YTrain是不是单列向量如果YTrain是列向量而预测输出是行向量MATLAB 的隐式扩展可能导致逐元素运算错位。5.4 坑四训练到一半 loss 变 NaN现象训练过程显示 loss 突变成 NaN训练曲线断裂后面不再更新。原因学习率设置过高导致梯度爆炸特别是数据归一化不彻底时最常遇到。负荷数据如果有缺失值没有处理NaN 会通过滑窗传播到训练样本中反向传播时梯度计算直接崩掉。解决先把原始数据中的缺失值和异常尖峰处理掉常见做法是线性插值或前向填充。然后把InitialLearnRate从 0.005 下调到 0.001并把GradientThreshold设置成 1在trainingOptions里加一行GradientThreshold, 1这样即使出现大梯度也会被裁剪保住训练过程不中断。5.5 坑五运行mainlstm.m时报维度无法广播的错误现象MATLAB 直接红字报错提示两个矩阵的行数或列数不一致指向fullyConnectedLayer或trainNetwork的位置。原因sequenceInputLayer(24)定义的输入维度和实际滑窗数据不对应。比如prepare_data里input_len设置成了 24但滑窗循环里用了i input_len - 1的边界条件生成X的列数是 24而某个脚本里改成了 48 没同步维度就对不上了。解决把prepare_data的输出size(XTrain)打印出来确认第二维数值和sequenceInputLayer的第一个参数一致。修改滑窗长度时唯一需要同步改的三个地方分别是sequenceInputLayer的维度、prepare_data的input_len、以及全连接的输出维度如果输出步长大于 1 也要调整。6. 进阶用法用同一套数据做五模型横向对比与显著性判断6.1 写一个循环脚本统一跑五个主脚本把指标汇总成表格这五个模型跑完单次实验下一个合理的动作是横向对比。我的习惯是写一个汇总脚本调用五个主脚本后深呼吸然后把每个模型的四个指标收集起来求多次独立实验的平均值和标准差。因为单次实验的随机性不可忽略至少在相同数据和相同参数设置下每个模型独立跑三次取MSE、RMSE、MAE、R²的均值与标准差才能判断 LSTM 到底比 GRU 好多少。% 循环调用五个模型的入口脚本收集并汇总评估指标 model_names {lstm, bilstm, gru, bigru, bp}; metrics zeros(length(model_names), 4); for k 1 : length(model_names) y_pred eval([main_ model_names{k}]); % 调用对应主脚本并返回预测值 [mse, rmse, mbe, mae] MSE_RMSE_MBE_MAE(y_true, y_pred); metrics(k, :) [mse, rmse, mbe, mae]; end % 打印对比表注意MBE符号含义正偏则模型高估 T table(model_names, metrics(:,1), metrics(:,2), ... metrics(:,3), metrics(:,4), ... VariableNames, {Model, MSE, RMSE, MBE, MAE}); disp(T);这段脚本的思路是把五个主脚本的预测结果统一回收。实际执行的时候你不需要真的用eval去调用别人的脚本更好的做法是手动运行每个main*.m脚本然后把y_pred保存成pred_lstm.mat、pred_gru.mat之类的文件汇总脚本只做加载和评估。这样能规避一个坑eval(main_lstm)这个调用形式要求函数返回值和脚本内部变量名匹配五个脚本的预测输出变量名大概率不一致用load方式更稳。6.2 怎么判定两个模型的 0.005 差距是不是真的不少人在论文或报告里写「本文提出的 BIGRU 比 LSTM 的 RMSE 降低了 0.5%」作为结论但从不告诉读者这个 0.5% 是否稳定。一个务实的验证手法是使用五折交叉验证的思路把时间序列数据切成五个连续段落每次拿四段训练、一段测试分别计算 RMSE最后求五个 RMSE 的平均值和标准差。如果 BIGRU 的五次平均低于 LSTM且标准差区间不重叠那么这个差距才算有说服力。另一个值得留意的点是最优参数的转移性。在 LSTM 上调好的隐藏单元数量和初始学习率直接搬给 BIGRU 用通常不是最优的。双向网络因为两个方向的梯度路径叠加隐藏单元数量可以适当减小初始学习率也建议调低否则 BIGRU 的收敛稳定性会不如 LSTM最终误差反而更大。这就是你跑完这五个模型后最值得回顾和总结出的经验。这套包我整体跑过一遍的感觉是LSTM 和 GRU 输出容易解释BILSTM 与 BIGRU 的精度提升有限但在论文里作为复杂度对比很有价值BP 网络则是整个实验设计里不可或缺的基线参照。从那以后我每拿到一份新的负荷数据都会先跑一遍这套流程先把 BP 跑出基线再逐个上循环模型最后才在需要的场景里启用双向结构这样每一层模型的收益都能算清楚。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑