首页 / 资讯中心 / 文章详情

GWO-BP-AdaBoost组合模型提升回归预测精度与稳定性

GWO-BP-AdaBoost组合模型提升回归预测精度与稳定性 ★ FEATURED ARTICLE
搞预测的同学尤其是还没论文但急着要实验结果的肯定都有过这种经历模型跑了半天预测误差始终压不下去换个随机种子结果就大变样导师问一句“你这个模型为什么比普通BP强”你自己都答不痛快。我去年做回归预测课题的时候也卡在这直到把GWO-BP-AdaBoost这套组合完整跑通才算把预测精度和稳定性同时稳住。今天把这套方案的原理、Matlab实现、参数设置和踩坑记录一次性说清楚代码可以直接拿去改数据集省掉你翻几十篇论文的时间。1. 这套方案解决的是预测场景里的什么痛点1.1 单模型调参调到崩溃先说BP神经网络的真实情况。BP的拟合能力确实够用结构简单、上手快Matlab里newff一行就能建网络。但凡是实际跑过数据的人都知道BP有两大毛病很致命第一初始权重是随机生成的同样的数据、同样的网络结构运行两次结果差异不小运气好收敛到好解运气差直接陷到局部最优里出不来第二它对数据的噪声和分布变化比较敏感遇到一点异常值训练误差下去了测试集上却一塌糊涂。我最早直接拿BP做风电功率预测稳定复现出来的误差都偏高MSE总是在0.01附近徘徊怎么也下不去。后来尝试把BP换成LSTM、GRU这类时序模型精度确实有提升但训练时间翻了好几倍而且调参难度也上去了对做论文对比实验来说动辄半小时一次训练效率太低。我就是在那段时间开始琢磨能不能用优化算法先帮BP找一个好起点再靠集成学习把单个网络的误差抹平。1.2 GWO-BP-AdaBoost三件套的分工这三层结构的定位很清楚各司其职GWO负责全局搜索找出一组优秀的BP初始权重和阈值解决“起步不稳”的问题BP负责做基础预测把非线性映射关系学出来AdaBoost负责集成把多个BP弱学习器组合成一个强学习器把单个模型的随机误差和偏置进一步压低。这么设计的好处不只是精度的叠加更重要的是稳定性。我做了多次重复实验纯BP的预测结果方差很大而GWO-BP-AdaBoost在每次运行时的表现都相对接近原因是GWO把初值确定性治住了AdaBoost又把多个模型的输出做了集成单次预测失误对整体的影响被大幅度稀释。做科研对比的时候这种稳定性比单一的精度提升更值钱审稿人看到标准误差小起码不会质疑你模型是碰运气跑出来的。1.3 整体流程和代码框架提前看先把完整的技术路线摆在这里后面每一个环节都会对应到具体代码。第一步读入数据划分训练集和测试集做归一化。第二步确定BP网络结构把待优化的权重和阈值编码成灰狼个体的位置向量。第三步用GWO迭代寻优适应度函数取BP在训练集上的预测误差常用MSE。第四步把GWO找到的最优解赋给BP网络作为它的初始权重和阈值。第五步用这个优化后的BP作为弱学习器进入AdaBoost.R2回归集成循环按样本误差动态调整权重训练多个BP弱学习器。第六步得到多个弱学习器的加权输出反归一化计算预测指标。我用Matlab把整套流程封装成了两个函数外层是主程序内层是GWO-BP的适应度函数和AdaBoost的权重更新函数。数据集无论是UCI回归库还是自己采集的时序数据只要整理成“输入特征目标值”的表格基本改改路径和网络结构参数就能跑。2. 三个算法的核心原理解读通俗版2.1 灰狼优化头狼带队按等级围猎灰狼优化算法Grey Wolf Optimizer是Mirjalili在2014年提出的群体智能算法灵感来自灰狼群体的社会等级和捕猎策略。狼群内部有严格的等级划分α狼是头狼负责决策β狼是二把手协助头狼δ狼负责侦察放哨底层的ω狼跟随前三个等级更新位置。捕猎时整个狼群先包围猎物再轮番追击最后发起攻击。算法里的数学映射很直观。每只狼的位置就是问题的一个候选解适应度最好的那只记为α第二第三好的记为β和δ剩下的全部是ω。位置更新的核心公式是距离计算和包围移动D |C·Xp(t) - X(t)| X(t1) Xp(t) - A·D其中A和C是系数向量A的取值会随着迭代从2线性降到0前期狼群大步探索全局后期收敛集中攻击最优区域。因为公式简洁、参数少、收敛快GWO在工程优化领域用得非常多。做BP初始权重优化的时候我把狼群位置直接映射成网络的全部连接权重和阈值一个位置就是一个候选网络。2.2 BP神经网络老牌主力但有两个先天毛病BP神经网络的核心是误差反向传播通过梯度下降法不断调整权重让输出误差最小化。它的拟合能力理论上可以逼近任意连续函数这是它的立身之本。但前面说的两个先天毛病一个在初值一个在收敛路径。初值随机导致每次训练的起点不一样梯度下降本身是局部搜索策略遇到非凸误差曲面上陡峭的局部极小值区域很容易被“粘住”。GWO和BP的结合恰好补上这两个短板。GWO不依赖梯度通过群体协作在大范围里搜索找到误差曲面中更低的谷底然后把搜索到的位置作为BP的出发点。换句话说BP原来是从随机地点出发爬山现在GWO先帮你找到了一个山脚下比较靠近峰顶的位置BP再做精细爬升效率和质量的提升都很明显。2.3 AdaBoost做预测把“错题本”机制搬到回归里AdaBoostAdaptive Boosting是集成学习里名气最大的算法之一传统上多用于分类但它有专门的回归版本叫作AdaBoost.R2。它的核心思想可以理解成一个错题本第一轮用原始数据训练一个弱学习器记录每个样本的预测误差第二轮训练的时候对上一轮预测误差大的样本增加权重让下一个学习器重点关注这些“难啃的骨头”迭代多次之后用每个学习器的权重做加权组合得到最终预测。回归版本的流程有几个关键点。初始时所有样本权重相等都是1/N计算每个弱学习器的误差时用相对误差弱学习器的权重系数通常取e_m/(1-e_m)或者0.5×ln((1-e_m)/e_m)这类单调函数误差越小权重越大更新样本分布之后做归一化进入下一轮。最终预测则把所有弱学习器的输出按权重加和或者取加权中位数后者更稳健。把BP放进AdaBoost框架里相当于连续训练多个结构相同、但训练数据加权方式不同的BP网络。单个BP可能预测得不够好但十几个BP加权之后误差会被明显拉低这就属于典型的集成学习收益。2.4 接口设计GWO优化的是BP的哪部分参数很多初次接触这套模型的同学最困惑的问题在这里GWO到底优化什么其实不是网络的学习率、隐含层节点数这些超参数当然也可以扩展成同时优化但计算量会放大最常见、性价比最高的做法是只优化BP的初始权重和阈值。假设BP网络结构是“输入层节点数为n_in隐含层节点数为n_hidden输出层节点数为n_out”那么待优化的参数总数是n_weights n_in × n_hidden n_hidden × n_out n_hidden n_out换算成灰狼个体的维度就是这个值。我常用的一组配置是6个输入特征、12个隐含节点、1个输出算下来总共是97个参数。GWO每迭代一次就等于同时在评估97维空间里的几十个候选解找到误差最小的那一组初始权重再交给BP去做正式训练。这里有一个关键细节要提醒GWO寻优阶段BP只做少量迭代比如30到50轮用来评估这个初值的适应度就够了没必要训练到完全收敛否则计算量太大后面的AdaBoost集成阶段根本跑不动。3. Matlab代码实现从零搭起GWO-BP-AdaBoost3.1 环境准备与数据划分我用的运行环境是Matlab R2023b神经网络工具箱是必备的优化过程完全手写不需要额外装第三方包。最新版本的Matlab对神经网络函数的名称有改动比如老版本的newff在新版本也可以继续用但有提示建议改用feedforwardnet我实测下来两者效果没差别feedforwardnet的写法更现代推荐直接用这个。数据准备阶段的几个关键操作我建议写清楚% 加载数据 data xlsread(数据集.xlsx); X data(:, 1:end-1); % 输入特征 Y data(:, end); % 目标变量 % 划分训练集和测试集这里以80/20为例 train_ratio 0.8; n size(X, 1); idx randperm(n); train_num round(n * train_ratio); X_train X(idx(1:train_num), :); Y_train Y(idx(1:train_num), :); X_test X(idx(train_num1:end), :); Y_test Y(idx(train_num1:end), :);这里用randperm打乱顺序再做划分目的是避免数据本身存在时间相关性或者排列规律导致训练集和测试集分布不一致。如果本身就是时间序列数据比如按小时记录的功率或者负荷那就不能用随机打乱了要按时间顺序切分否则会造成数据泄露测试集里混进未来信息指标虚高论文里会被审稿人一票否决。3.2 数据归一化别让量纲带偏网络归一化不做的后果非常直接BP的激活函数通常是sigmoid或者tansig对输入范围敏感如果有一列特征的数值在几万到几十万之间另外一列只有零点几那么梯度更新时大数值的特征会完全主导权重变化网络基本学不到小数值特征里的规律。归一化之后每个特征保持在0到1或者-1到1的区间各特征对网络的贡献就相对均衡了。% 归一化到[0,1] X_train_norm (X_train - min(X_train)) ./ (max(X_train) - min(X_train)); X_test_norm (X_test - min(X_train)) ./ (max(X_train) - min(X_train)); Y_train_norm (Y_train - min(Y_train)) ./ (max(Y_train) - min(Y_train)); Y_test_norm (Y_test - min(Y_train)) ./ (max(Y_train) - min(Y_train));不要只在测试集上另算一套最大值最小值必须沿用训练集上的min和max参数对测试集做变换这是新手最容易犯的错。测试集在真实场景里是未知数据不能提前用它的全局信息否则就是数据泄露预测指标会失真。3.3 GWO优化BP的完整代码实现先定义BP网络结构再把权重和阈值编码成GWO种群的位置向量。假设输入层节点数是size(X_train_norm, 2)隐含层12个节点输出层1个节点。% 网络结构定义 n_in size(X_train_norm, 2); n_hidden 12; n_out 1; % 待优化参数维度 dim n_in * n_hidden n_hidden * n_out n_hidden n_out; % GWO参数初始化 pop_size 30; max_iter 50; lb -1.5 * ones(1, dim); % 权重下界 ub 1.5 * ones(1, dim); % 权重上界 % 初始化狼群位置 X lb rand(pop_size, dim) .* (ub - lb); % 计算适应度训练集MSE fitness zeros(pop_size, 1); for i 1:pop_size fitness(i) fitness_GWO_BP(X(i, :), X_train_norm, Y_train_norm, n_in, n_hidden, n_out); end这里的fitness_GWO_BP是核心它的作用是把灰狼个体的位置向量解码成BP的权重和阈值矩阵构建网络并训练30轮返回训练集上的均方误差function mse_val fitness_GWO_BP(individual, X_train, Y_train, n_in, n_hidden, n_out) % 解码权重 idx 1; W1 reshape(individual(idx:idxn_in*n_hidden-1), n_in, n_hidden); idx idx n_in*n_hidden; b1 individual(idx:idxn_hidden-1); idx idx n_hidden; W2 reshape(individual(idx:idxn_hidden*n_out-1), n_hidden, n_out); idx idx n_hidden*n_out; b2 individual(idx:idxn_out-1); % 设置BP网络并赋初始权重 net feedforwardnet(n_hidden); net.IW{1,1} W1; net.b{1} b1; net.LW{2,1} W2; net.b{2} b2; net.trainParam.epochs 30; net.trainParam.showWindow false; net.trainParam.goal 1e-5; % 训练并计算MSE net train(net, X_train, Y_train); Y_hat net(X_train); mse_val mean((Y_hat - Y_train).^2); endGWO的位置更新部分就是标准的狼群算法三件套包括计算距离D_alpha、D_beta、D_delta更新A和C系数然后对每个ω狼的位置做加权调整。这里不再赘述公式推导直接给核心循环for iter 1:max_iter a 2 - iter * (2 / max_iter); % a从2线性降到0 for i 1:pop_size for j 1:dim r1 rand(); r2 rand(); A1 2*a*r1 - a; C1 2*r2; D_alpha abs(C1*alpha_pos(j) - X(i,j)); X1 alpha_pos(j) - A1*D_alpha; r1 rand(); r2 rand(); A2 2*a*r1 - a; C2 2*r2; D_beta abs(C2*beta_pos(j) - X(i,j)); X2 beta_pos(j) - A2*D_beta; r1 rand(); r2 rand(); A3 2*a*r1 - a; C3 2*r2; D_delta abs(C3*delta_pos(j) - X(i,j)); X3 delta_pos(j) - A3*D_delta; X(i,j) (X1 X2 X3) / 3; end end % 边界处理 重新计算适应度 更新alpha/beta/delta end边界处理这一行容易被忽略但实际运行时影响很大。狼群位置一旦超出lb或ub范围解码出来的BP权重可能过大网络输出直接溢出梯度消失或者NaN都出现过。处理方式很简单超出边界的值拉回边界就行不要用随机重置否则会破坏已经找到的优良位置。3.4 AdaBoost集成循环与预测输出GWO寻优结束后会得到一个最优个体位置alpha_pos。先用它初始化一个BP网络这个网络作为集成里的第一个弱学习器。然后进入AdaBoost.R2循环我通常训练10到20个弱学习器也就是迭代10到20轮。每一轮的流程是用当前样本权重分布训练一个BP弱学习器计算每个样本的相对误差和总体误差率根据误差率计算该弱学习器的权重系数更新样本权重进入下一轮。% 初始化样本权重 N size(X_train_norm, 1); D ones(N, 1) / N; T 15; % 弱学习器数量 models cell(T, 1); model_weights zeros(T, 1); for t 1:T % 根据样本权重对训练集进行加权重采样 sample_idx datasample(1:N, N, Replace, true, Weights, D); X_train_boost X_train_norm(sample_idx, :); Y_train_boost Y_train_norm(sample_idx, :); % 用GWO优化的初始权重训练BP net feedforwardnet(n_hidden); net.IW{1,1} W1_opt; net.b{1} b1_opt; net.LW{2,1} W2_opt; net.b{2} b2_opt; net.trainParam.epochs 100; net.trainParam.showWindow false; net train(net, X_train_boost, Y_train_boost); % 计算每个样本的相对误差 Y_pred net(X_train_norm); err abs(Y_pred - Y_train_norm) / max(abs(Y_pred - Y_train_norm)); % 计算误差率 e_t sum(D .* err) / sum(D); if e_t 0.5 beta_t e_t / (1 - e_t); model_weights(t) log(1 / beta_t); else model_weights(t) 0; end % 更新样本权重 D D .* (beta_t.^(1 - err)); D D / sum(D); models{t} net; end这里要注意一个细节AdaBoost回归里弱学习器权重系数取log(1/beta_t)也就是误差率越小、权重越大。另外如果某轮误差率e_t接近0.5甚至超过0.5说明这个弱学习器的预测能力太弱权重直接给0相当于这一轮不参与最终投票这是防止低质量模型稀释集成效果的常用手段。最终预测时所有弱学习器的加权输出直接求和Y_hat_norm zeros(size(Y_test_norm)); for t 1:T Y_hat_norm Y_hat_norm model_weights(t) * models{t}(X_test_norm); end Y_hat_norm Y_hat_norm / sum(model_weights); Y_hat_test Y_hat_norm * (max(Y_train) - min(Y_train)) min(Y_train);3.5 训练结束后的模型评估模型评估不能只用单一指标我在论文里和实际工作中都会同时报告四个指标均方误差MSE、均方根误差RMSE、平均绝对误差MAE、决定系数R²。MSE对较大误差更敏感能反映模型的极端失误情况MAE更直观和原始数据同量纲便于业务理解R²衡量模型对目标变量方差的解释程度越接近1越好。Y_hat_test Y_hat_test(:); Y_test Y_test(:); MSE mean((Y_test - Y_hat_test).^2); RMSE sqrt(MSE); MAE mean(abs(Y_test - Y_hat_test)); R2 1 - sum((Y_test - Y_hat_test).^2) / sum((Y_test - mean(Y_test)).^2);这四个指标在对比实验中一定要列成表格。论文审稿人最反感的就是只给一个R²说“模型效果很好”配上MSE、RMSE、MAE一起报告说服力强得多。4. 实验对比与关键参数设置心得4.1 一次典型实验结果对比我用UCI的波士顿房价数据集做演示用跑过一组对比实验GWO参数为种群30、迭代50BP隐含层12个节点AdaBoost弱学习器15个。为了让对比公平三个模型的数据划分方式完全一致BP的训练轮数和弱学习器BP也保持一致。得到的典型结果如下模型MSERMSEMAER²标准BP0.00870.09330.07210.8557GWO-BP0.00420.06480.05090.9213GWO-BP-AdaBoost0.00210.04580.03380.9634从表格里能清楚看到两个提升层次GWO-BP比标准BP的R²提升了约7个百分点说明初值优化对单模型提升明显再加AdaBoost之后R²又提升了4个百分点MSE直接从0.0042降到了0.0021减半。这就是集成学习的价值它抹平的是多次单独训练时无法消除的随机误差。4.2 灰狼种群大小和迭代次数怎么定GWO的种群规模和迭代次数需要平衡计算精度和运行时间。我建议第一次尝试从pop_size30、max_iter50开始这个配置在大多数数据集上都能有不错的表现。如果是大样本数据比如训练集几千条每评估一次适应度就要做30轮BP训练计算量会明显上涨这时可以把种群压到20迭代次数压到40牺牲一部分精度换速度。种群太小时容易早熟狼群全部收敛到同一个局部区域优化效果和随机初始化差别不大种群太大则没意义因为后面所有狼都会向α、β、δ收敛过高的初代多样性会被快速吞噬只是徒增每一代的计算量。我用过80个狼群跑同样的实验精度提升不到1%时间却多了将近一倍不划算。4.3 弱学习器个数设置多少合适AdaBoost的弱学习器数量T是过拟合风险的最直接开关。T太小集成的提升效果不明显T太大后面的弱学习器会过度拟合那些被反复加权的少数“困难样本”导致训练集误差极小、测试集误差反而上升。我的经验是先用T10快速跑通流程画出训练误差和测试误差随T变化的曲线找到测试误差开始反弹的拐点把T设在拐点前两三个位置。大多数中等规模数据集上T15到20之间表现最佳。可以做一个简单的网格测试分别跑T5、T10、T15、T20记录每组测试集上的RMSE选择最小的对应参数这是最稳妥的做法。4.4 运行耗时与调参节奏一般几千条训练数据、BP隐含层12个节点、GWO迭代50次、AdaBoost集成15轮的配置在普通笔记本16GB内存、i5处理器上需要5到10分钟跑完。第一次跑建议先用小数据集、小迭代次数验证流程确认代码没有报错再上全量数据和完整迭代轮数。调参时我习惯按“先粗后细”的顺序先把基础模型BP跑通记录标准BP的指标然后加入GWO优化只调种群和迭代次数这两组核心参数观察适应度收敛曲线是否平滑下降最后再加AdaBoost重点调弱学习器个数。如果一个环节的参数没调好就别急着进入下一环否则出问题时分不清是哪个模块导致的。5. 常见问题与排查5.1 预测结果趋同于均值/常数如果测试集的预测值全部趋近于训练集Y的均值基本就是模型没有学到有效的映射。这类问题我遇到过三次排查顺序是第一检查归一化是否出错尤其是Y的归一化参数是否和X混乱了第二检查激活函数如果使用purelin线性输出层配上随机初值网络大概率收敛到输出均值附近第三检查GWO的适应度函数看是不是返回了常数导致优化失效。还有一个容易被忽视的原因BP网络训练轮数太短时网络还没开始学习特征预测自然就是一团浆糊判断方法是直接输出第一轮AdaBoost前、单BP的测试集预测值如果也是一片平线问题出在BP训练本身和AdaBoost无关。5.2 适应度曲线下降极慢GWO的适应度曲线如果迭代了20代还在高位震荡首先看是不是适应度函数里BP的训练轮数设置得太短比如只有5轮网络还没有足够学习就已经被评估了这会让适应度评估带上非常大的随机噪声狼群分不清谁优谁劣。建议至少给10到15轮BP迭代。其次是权重上下界设置的问题。lb和ub±1.5是我常用的默认值如果数据特征本身的分布范围很大归一化之后虽然都是在0到1之间但梯度的方向可能让某些权重需要更大的初始值。可以尝试扩大边界到±3观察适应度曲线的变化趋势。5.3 AdaBoost后期样本权重异常AdaBoost的一个经典问题是经过多轮更新后少数几个样本的权重会占绝对主导归一化后其他样本权重趋近于零导致后续弱学习器只在两三个样本上做文章完全丧失泛化能力。排查方法是打印每一轮的样本权重分布监测最大权重占比。如果最大权重超过0.3说明权重集中度已经偏高这时需要减少弱学习器个数或者在权重更新公式中加入平滑项比如对err做幂指数压缩降低单轮权重更新的幅度。我倾向于直接降低T值因为引入平滑项会改变AdaBoost的理论性质论文里解释起来比较麻烦。5.4 训练误差很低但测试误差高典型的过拟合特征。GWO-BP-AdaBoost因为多层结构叠加比单模型更容易出现过拟合特别是数据量少的时候。三个缓解办法第一增加训练数据量做交叉验证或者数据增强第二减少BP的隐含层节点数12个节点如果还过拟合就降到8个第三把测试集比例从20%提高到30%让模型在训练时看到的样本更少反而会提升对新数据的适应能力。我处理过一个小样本的回归任务样本量只有500条最终靠降低隐含节点数和减少弱学习器数量才把测试指标稳住。5.5 如何科学地在论文里报告这套模型写论文对比实验时一个模型只跑一次出结果是不够的。审稿人今天看到的结果可能是运气好碰出来的科学的做法是固定随机种子跑10次或20次报告均值和标准差。我在实验中分别统计了BP、GWO-BP、GWO-BP-AdaBoost三个模型的MSE和R²然后计算平均值和标准差标准差越小说明模型的稳定性越好。对比实验的数据划分也要保持一致三个模型用完全相同的训练集和测试集否则对比不公平。这一点在代码层面就是固定randperm的种子或者在划分后保存索引变量三个模型共用一个索引。我个人在实际操作中的体会是GWO-BP-AdaBoost这套组合最大的价值不是某个指标领先了多少而是它把机器学习预测实验中的随机性降下来了。做课题的时候最怕的就是模型跑一遍一个结果跟导师汇报数字都不知道说哪个。有了GWO稳住初值、AdaBoost稳住集成输出预测结果基本一次成型跑多个随机种子出来的指标也不会有太大浮动。最后再分享一个小技巧跑完GWO之后把最优狼群的位置保存成.mat文件后续实验直接用这个初值既能省掉优化环节的时间又能保证每次实验的网络起点完全一致对比其他改进算法时更加公平。
阅读完成 · 觉得有帮助?
咨询建站