纵横交叉算法优化BP神经网络的电力负荷预测MATLAB实现
2026/9/19 11:05:29 网站建设 项目流程

简介:资源为电力负荷预测方向的学术论文PDF,面向电力系统调度、负荷预测研究人员及深度学习、神经网络学习者,针对传统BP神经网络对含冲击负荷地区高频分量预测精度不足、泛化能力弱的问题,给出了一种基于小波变换与纵横交叉算法优化的改进方案。文中通过小波分解负荷序列,利用纵横交叉算法对神经网络的权重与阈值进行全局寻优,并用实际电网算例验证模型在冲击负荷场景下的预测精度与泛化能力。资源仅有1个PDF文档,约357KB,完整收录论文正文、图表、公式及参考文献,适合想快速了解该方法原理、流程与实验对比结果的读者。目前已有103人浏览学习,下载后可直接阅读原始文献,获取CSO算法设计思想、小波分解重构架构、网络训练策略以及实际预测结果分析等细节,便于复现实验或作为写作参考。

1. 为什么要用纵横交叉算法去优化神经网络的负荷预测模型

电力负荷预测并不是查一度电的历史记录就算完。一条完整的日负荷曲线会同时被温度、湿度、日类型、前一天用电行为等多个因素叠加影响,非线性强,普通回归模型根本拉不动。BP 这类前馈神经网络能刻画这种非线性,可它的权重训练依赖梯度下降,初值不好或样本噪声大时,很容易停在局部最优附近,负荷尖峰段怎么都拟合不上。纵横交叉优化(Crisscross Optimization,常缩写为 CSO)是一种不依赖梯度的群智能算法,特征是同时做横向交叉和纵向交叉两种搜索,正适合用来替换 BP 原生的随机初始化加梯度训练。下面从输入构造、BP 基线和 CSO 调权流程一路走下来,MATLAB 代码可以直接落地,适合正在做负荷预测建模或竞赛题的工程师参考。

2. 纵横交叉算法的两个算子在负荷预测里各管什么

2.1 横向交叉:在父代连线附近构造更宽的搜索区间

纵横交叉优化的核心结构是“横向交叉 + 纵向交叉”两个算子。横向交叉先对当前种群做随机两两配对,然后对配对的两个个体,在同一维度上各自生成一个后代。常见的生成公式是:

Ms1(a,d) = r1 * a(d) + (1 - r1) * b(d) + c1 * (a(d) - b(d)) Ms2(b,d) = r2 * b(d) + (1 - r2) * a(d) + c2 * (b(d) - a(d))

r1、r2 是 (0,1) 均匀随机数,c1、c2 取 (-1,1)。前半截是父代线性混合,后半截是差分修正,和差分进化有点像,但差分进化只对一个主向量加扰动,这里是对两个方向同时做,搜索区域是一个以两个父代为中心点的斜四边形,比单纯在连线中点取点要宽。对负荷预测这种响应曲面很不光滑的问题来说,这样的搜索步长能在早期覆盖到更多局部盆地。

2.2 纵向交叉:主动解耦被平铺的权重维度

BP 网络要优化的量不是一个标量,而是把好几层的权重矩阵、阈值向量全部展开成一个一维向量。这个平铺过程会把原本硬件上独立的两组权重变成相邻的维度,梯度下降走起来容易“牵一发动全身”。纵向交叉随机取同一个体的两个维度,把其中一个维度的取值按权重 r 和另一个维度作线性混合,也就是维度之间的交叉。

这样做有两个直接好处:一是跳出只沿坐标轴移动的局限,二是当某两个维度高度相关时,用这种“跳变”能更快摆脱鞍点,比只做横向的种群扰动更稳。负荷预测的输入特征里,温度和湿度往往存在耦合,历史负荷的前日值与前两日值也高度相关,这些耦合关系反映到权重向量上,就表现为若干维度之间存在较强的相关结构,纵向交叉恰好处理的是这部分冗余。

2.3 和粒子群、遗传算法相比,CSO 更适合调高维权重

对比项粒子群 (PSO)遗传算法 (GA)纵横交叉算法 (CSO)
信息交换方式个体朝历史最优与全局最优靠拢选择、交叉、变异随机组合成对横向组合 + 跨维纵向组合
对超参数的敏感度高,惯性权重进退两难高,交叉率变异率耦合低,主调种群规模和迭代数
权重向量超过 100 维速度项频繁抖动,早熟常见变异步长难匹配量纲纵向交叉主动消除维间冗余
负荷预测场景的表现训练误差低但验证集抖动收敛慢,结果复现性差收敛适中,验证误差更集中
实现难度中,两个算子需要分别写

BP 网络的可训练参数在本文这种 6-12-6-1 结构里是一百多维起步,PSO 的“跟最优走”策略在高维空间里会退化成向某些优秀维度的堆叠。GA 保持多样性的能力还行,但交叉率、变异率一旦没调好,后期搜索步长会被锁死。CSO 的两个算子分工明确,横向负责种群采样宽度,纵向负责维度间解耦,我在做负荷预测模型调参时通常只改种群规模和迭代次数,省下来的时间都拿去调整输入特征。

2.4 用最小的一段代码看一眼横向交叉

下面是一段 MATLAB 函数,对应 2.1 节里的两行公式:

function [Ms1, Ms2] = hc_once(a, b, d) % HC_ONCE 横向交叉算子对单个维度的计算 % a, b : 两个父代个体向量 % d : 当前维度序号 r1 = rand(); % 与 b 混合的比例 r2 = rand(); c1 = -1 + 2 * rand(); % 差分修正系数,落在 [-1,1] c2 = -1 + 2 * rand(); Ms1 = r1 * a(d) + (1 - r1) * b(d) + c1 * (a(d) - b(d)); Ms2 = r2 * b(d) + (1 - r2) * a(d) + c2 * (b(d) - a(d)); end

这段代码只做单个维度的单次交叉,真正优化中要把它套进“种群配对 + 逐维循环 + 边界处理 + 贪心更新”四步里。注意 c1、c2 的随机幅度是 2,即最大差分扩到两倍,这样做能保证后代偶尔跳出父代连线的包围区间,否则交叉搜索就退化成了局部平均。运行它不需要神经网络工具箱,只要有基础 MATLAB 就能验证:固定两个向量 a、b 跑一千次,后代点会形成围绕连线两侧的锥形分布,随机差分项是形成这个形状的唯一来源。

3. 用 MATLAB 把 BP 负荷预测基线先搭起来

3.1 输入特征与样本切分顺序

负荷预测模型有日、周、时等多个粒度,标题里这种“先造特征、再用浅层网络回归”的做法主要针对短期日负荷预测。常见做法是取以下 6 个特征构成一个 n×6 矩阵:

列位特征说明数据来源
1前一日同时刻负荷历史负荷库
2前两日同时刻负荷历史负荷库
3前一周同时刻负荷历史负荷库
4温度气象接口
5湿度气象接口
6节假日标志日历

注意,节假日标志不要编码成 1~7 的整数序号,BP 会把这些数字当作连续量,把“周日”和“周一”之间的距离当成数值大小。惯用一个 0/1 标志就够了,最多再做 one-hot 展开。样本切分要按时间顺序,不能用随机抽样的方式打乱,否则相邻天的信息会提前泄漏进训练集,验证集误差会好看得失真。

3.2 隐藏层结构与激活函数的选择

用两层隐藏层处理日负荷这种数据,第一层 12 个神经元、第二层 6 个神经元的 BP 网络结构算是常见的起步形态。起步节点数可以由经验公式估算:隐藏层节点数取round(sqrt(m + n) + a),其中 m 是输入维度,n 是输出维度,a 在 1 到 10 之间浮动。6 个输入、1 个输出代入后,第一层给 8 到 13 都不会太离谱,这里取 12 是为了保留一点余量。第二层减半取 6,让网络先把输入压缩到低维表示,再映射到负荷值。

两层隐藏层都用 tansig,输出层用 purelin。原因:负荷标签做归一化后落在 [-1,1],tansig 的饱和区能提供必要的非线性;输出层用线性激活能让预测值不受 [-1,1] 硬限制,反归一化后的量纲还原也更稳。

3.3 BP 基线的完整训练代码

% 数据划分:按时间切块,避免随机抽样的时间泄漏 row = size(X, 1); idxTr = 1:round(row * 0.7); idxVa = round(row * 0.7) + 1:row; Xtr = X(idxTr, :); Ytr = y(idxTr, :); Xva = X(idxVa, :); Yva = y(idxVa, :); % 归一化到 [-1,1],和 tansig 的动态范围保持一致 [Xtr_n, psX] = mapminmax(Xtr'); [Ytr_n, psy] = mapminmax(Ytr'); Xva_n = mapminmax('apply', Xva', psX); Yva_n = mapminmax('apply', Yva', psy); % 建 6-12-6-1 网络 net = feedforwardnet([12 6]); net.layers{1}.transferFcn = 'tansig'; net.layers{2}.transferFcn = 'tansig'; net.layers{3}.transferFcn = 'purelin'; net.trainFcn = 'trainlm'; % Levenberg-Marquardt net.trainParam.showWindow = false; net.trainParam.epochs = 800; net.trainParam.goal = 1e-5; net.divideFcn = 'divideblock'; % 按块划分,不打乱时序 [net, ~] = train(net, Xtr_n, Ytr_n); pred_norm = sim(net, Xva_n); mse_bp = mean((pred_norm - Yva_n).^2); fprintf('BP 验证集 MSE = %.6f\n', mse_bp);

这里有几个参数需要解释。mapminmax默认把数据映射到 [-1,1];训练时保存的psXpsy必须留着,后面做测试集预测时用apply的方式复用同一套归一化参数,不能用测试集重新计算最小值和最大值。feedforwardnet([12 6])生成两层隐藏层,trainlm在几千条样本下收敛快,但如果样本量超过十万,建议换成trainscg,否则trainlm的雅可比矩阵会吃掉大量内存。divideblock是最后一块区域做验证,保证验证样本在时间上晚于训练样本。

3.4 先画 BP 神经网络拟合曲线,再判断基线是否可用

直接看误差数字往往不够,把pred_norm反归一化后画出来,可以直观地看 BP 神经网络拟合曲线在什么位置掉链子:

pred_load = mapminmax('reverse', pred_norm, psy); Yva_load = mapminmax('reverse', Yva_n, psy); plot(1:length(Yva_load), Yva_load, '-'); hold on; plot(1:length(pred_load), pred_load, '--'); legend('真实负荷', 'BP 预测');

如果这条曲线的早晚高峰段贴合度尚可、误差相对均匀,说明数据本身没大问题;如果只在少数尖峰样本上误差大,而平段误差很小,那么大概率是梯度法把网络带进了局部最优。这时候再引入纵横交叉算法才有意义,否则就是在给一个已经够用的模型额外加复杂度。

4. 纵横交叉算法嵌入 BP 的完整代码与参数表

4.1 优化对象是权重向量,不是网络结构

CSO 只负责调整权重和阈值,网络结构仍然按 6-12-6-1 保持固定。把所有可训练参数展平成向量后,每个个体就是一个候选权重集,个体长度 D 等于:

D = 12*6 + 12 + 6*12 + 6 + 6*1 + 1 = 169

这 169 维里,权重占 150 维,阈值占 19 维。在 MATLAB 里用reshape把它们还原成矩阵再前向计算即可。注意reshape默认按列优先展开,只要编码和解码使用同一套顺序,具体怎么排并不影响搜索能力。

4.2 适应度函数与训练、验证、测试三块数据的职责

标准做法是让 CSO 直接把神经网络的权重训练过程顶替掉,适应度取验证集上的均方误差。也就是说,CSO 每评估一个个体,就把个体还原成权重,在验证集上做一次前向计算,得到 MSE;不调用train,不做 BP 反向传播。数据要切三块:训练 60%、验证 20%、测试 20%,CSO 的适应度只看验证集,测试集在整个优化结束后才打开一次。如果所有数据都参与适应度打分,最后的误差会自我欺骗。

4.3 CSO-BP 主循环代码

function [gBest, gBestVal] = cso_bp(Xtr, Ytr, Xva, Yva, M, maxIter) % CSO_BP 纵横交叉算法优化 BP 权重 % 结构固定 6-12-6-1,输入 X 为 n×6,目标 Y 为 n×1 dims = [12*6, 12, 6*12, 6, 6*1, 1]; D = sum(dims); lb = -5 * ones(1, D); ub = 5 * ones(1, D); pop = lb + rand(M, D) .* (ub - lb); fit = zeros(M, 1); for i = 1:M fit(i) = nn_mse(pop(i,:), Xva, Yva, dims); end [gBestVal, idx] = min(fit); gBest = pop(idx, :); for iter = 1:maxIter % ---------- 横向交叉 ---------- perm = randperm(M); for p = 1:2:(M-1) i = perm(p); j = perm(p+1); Ms1 = zeros(1, D); Ms2 = zeros(1, D); for d = 1:D r1 = rand(); r2 = rand(); c1 = -1 + 2 * rand(); c2 = -1 + 2 * rand(); Ms1(d) = r1*pop(i,d) + (1-r1)*pop(j,d) + c1*(pop(i,d)-pop(j,d)); Ms2(d) = r2*pop(j,d) + (1-r2)*pop(i,d) + c2*(pop(j,d)-pop(i,d)); end Ms1 = min(max(Ms1, lb), ub); Ms2 = min(max(Ms2, lb), ub); f1 = nn_mse(Ms1, Xva, Yva, dims); f2 = nn_mse(Ms2, Xva, Yva, dims); if f1 < fit(i), pop(i,:) = Ms1; fit(i) = f1; end if f2 < fit(j), pop(j,:) = Ms2; fit(j) = f2; end end % ---------- 纵向交叉 ---------- for i = 1:M if rand() > 0.5, continue; end d1 = randi(D); d2 = randi(D); if d1 == d2, continue; end Ms = pop(i, :); r = rand(); Ms(d1) = r * pop(i,d1) + (1 - r) * pop(i,d2); Ms = min(max(Ms, lb), ub); f = nn_mse(Ms, Xva, Yva, dims); if f < fit(i), pop(i,:) = Ms; fit(i) = f; end end [bestVal, idx] = min(fit); if bestVal < gBestVal gBestVal = bestVal; gBest = pop(idx, :); end end end

配套的适应度函数:

function mse = nn_mse(theta, Xva, Yva, dims) % 把个体还原成权重,前向计算验证集 MSE W1 = reshape(theta(1:dims(1)), 12, 6); b1 = theta(dims(1)+1 : sum(dims(1:2)))'; W2 = reshape(theta(sum(dims(1:2))+1 : sum(dims(1:3))), 6, 12); b2 = theta(sum(dims(1:3))+1 : sum(dims(1:4)))'; W3 = reshape(theta(sum(dims(1:4))+1 : sum(dims(1:5))), 1, 6); b3 = theta(sum(dims(1:5))+1 : sum(dims(1:6)))'; a1 = tanh(Xva * W1' + b1); a2 = tanh(a1 * W2' + b2); pred = a2 * W3' + b3; mse = mean((pred - Yva).^2); end

两个函数要放在同一个cso_bp.m文件里,或者都定义在同一个脚本末尾。横向交叉里的randperm(M)把种群顺序打乱后两两配对,保证每代配对关系都不同;min(max(Ms, lb), ub)是边界约束,把越界分量压回 [-5,5]。纵向交叉里rand() > 0.5控制参与概率,也就是说每次迭代只有一半个体做纵向交叉,和参数表的Vc = 0.5对应。

4.4 CSO-BP 关键参数表

参数常用范围本次取值取值依据
种群规模 M10~4030个体太少容易丢失搜索宽度,太多则单代评估成本上升
最大迭代次数30~10050负荷预测验证集 MSE 通常在 30 代后进入缓慢下降区
横向交叉概率 Hc1,每代执行1横向交叉是主要搜索动力,不建议调小
纵向交叉概率 Vc0.2~0.80.5过大破坏已有优秀维度组合,过小失去解耦作用
权重边界[-5,5] 或 [-10,10][-5,5]输入输出归一化后,大权重容易导致饱和
适应度函数验证集 MSE/MAPE验证集 MSEMSE 对大残差敏感,利于剔除尖峰段坏解

5. 验证纵横交叉负荷预测模型的三个门槛与实际技巧

5.1 用一组独立数据做最终判决

CSO 优化结束后,把最优个体gBest还原成权重,在从未参与过适应度计算的测试集上跑一次前向,再反归一化回真实量纲:

pred_norm = forward_net(gBest, Xte_n, dims); pred_load = mapminmax('reverse', pred_norm', psy)'; MAPE = mean(abs(pred_load - Yte_raw) ./ Yte_raw) * 100; RMSE = sqrt(mean((pred_load - Yte_raw).^2));

Xte_n是用第 3 章保存的psX归一化后的测试输入,Yte_raw是测试集原始负荷值。这里的forward_net可以直接从nn_mse里把前向计算那段抽出来,返回值改成pred。只有这份测试集误差才有资格和 BP 基线做对比;拿验证集误差对比,两边都不可信。

5.2 三个容易翻车的地方

第一,随机 K 折不能直接用。负荷数据是时间序列,随机抽样会把未来信息混进训练集,优化时看起来误差很低,换到真实预测第二天就露馅。第二,归一化参数必须复用训练集保存下来的psXpsy,不能用测试集重新计算,否则预测值还原后会带进测试集的统计信息。第三,CSO 的适应度函数里一旦用了测试集,模型就等于提前看到了考试答案,后期调参全部失去意义。

5.3 后期调参的两个方向

当纵横向交叉优化的结果在训练集和验证集都低、测试集偏高时,优先把纵向交叉概率Vc从 0.5 降到 0.3,让维度解耦动作更克制,而不是盲目增加迭代次数。当结果整体偏高、曲线平段贴得不错但尖峰跟不上时,把种群规模 M 加到 50,维持横向交叉的搜索宽度。负荷预测的尖峰段通常由极端温度触发,这类样本在数据集中占比小,只有靠横向交叉不断在父代周围制造差分扰动,才有机会让权重组合覆盖到这类稀疏样本。最后把反归一化后的预测曲线和真实曲线叠在一起,早晨尖峰与晚高峰两侧的贴合程度,就是这套模型在你这套数据上真实能力的直观体现。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询