十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

改进蛇优化算法优化BP神经网络:从原理到回归预测实战

改进蛇优化算法优化BP神经网络:从原理到回归预测实战 1. 为什么想到用改进蛇优化算法去调BP神经网络先聊聊我最初碰到的问题。做数据回归预测的朋友应该都有这种感觉BP神经网络这玩意儿理论看着挺美真上手跑起来就两件事最头疼第一是初始权重和阈值太敏感随机初始化一次一个样运气好收敛得又快又准运气不好直接掉进局部最优出不来第二是隐层节点数、学习率这些超参调起来基本靠试费时费力还没什么规律可循。我做一组风电功率回归预测实验的时候同样的数据、同样的网络结构跑了十次最好的和最差的均方误差能差出一个数量级这就没法交代了。后来我尝试用群体智能优化算法去解决这个问题。粒子群、遗传算法这些经典方案我都试过效果确实比纯随机初始化稳定了不少但很快又遇到新的瓶颈——粒子群容易早熟收敛遗传算法后期收敛速度太慢。尤其是数据维度一高搜索空间指数膨胀这两类算法都有些力不从心。直到我接触到蛇优化算法Snake OptimizerSO才算是找到了一个比较对路的方向。蛇优化算法是2022年提出的一种新型元启发式算法模拟的是蛇在特定温度和食物条件下的交配行为。它的一个核心特点是把整个种群动态划分成雄性和雌性两组并且根据环境条件在探索和开发两种模式之间切换这个机制天然就比PSO那种全局搜索靠惯性权重衰减的设计更灵活。但原版SO也不是没有短板我在复现和测试的过程中发现它在高维问题上的探索能力还是偏弱收敛精度也有提升空间。所以就有了这篇博文要聊的东西——在原始蛇优化算法的基础上做两个方向的改进一个是全局引导策略GOSO一个是惯性权重调节策略ISO然后用改进后的算法去优化BP神经网络的初始权重和阈值做数据回归预测。我不打算只讲理论推导而是把我从算法原理、代码实现到实验对比的完整过程都摊开来说包括踩过的坑和最后总结出来的经验给正在做类似智能优化算法神经网络组合的朋友一个可以直接参考的路线。2. 原始蛇优化算法的原理拆解它到底在优化什么在说改进之前得先把原版SO的机制讲清楚不然后面GOSO和ISO的改进点你会看得一头雾水。2.1 蛇优化算法的核心机制蛇优化算法的设计灵感来自蛇在繁殖季节的行为模式。算法的基本设定是假设种群规模为N按照性别比例1:1分成雄性和雌性两组。每一代迭代中算法会先计算两个关键环境参数——食物量Q和环境温度Temp这两个参数决定了蛇群当前进入什么行为模式。食物量Q的计算公式是Q c1 * exp((t - T) / T)其中t是当前迭代次数T是最大迭代次数c1是一个常数通常取0.5。可以看到Q是随着迭代次数增加而指数衰减的这意味着算法前期食物充足倾向于探索后期食物减少倾向于开发。环境温度Temp的计算公式是Temp exp(-t / T)温度同样是随时间衰减的。温度和食物量共同决定蛇的行为规则大致如下如果Q 0.25食物不足蛇群进入探索阶段只做全局搜索更新位置时不考虑当前最优解的影响而是随机更新。如果Q 0.25食物充足蛇群进入开发阶段此时再看温度如果Temp 0.6温度较高蛇群只向最优位置移动即战斗模式侧重局部开发。如果Temp 0.6温度较低进入交配模式雄性个体与雌性个体之间发生信息交换产生新个体。这里有个关键细节在交配模式下如果子代个体的适应度优于父代则替换父代战斗模式下也有类似的贪心选择机制。这个贪心保留精英的设计保证了算法不会倒退。2.2 原版SO在BP优化场景中的短板理论上看SO的机制设计确实挺精巧但放到优化BP神经网络初始权重这个具体场景里我测试之后发现了几个实际问题第一探索阶段的信息利用效率太低。原版SO在Q 0.25时的探索是纯随机的完全不考虑当前已发现的好解这就导致前期搜索比较盲目白白浪费了很多评估次数。而BP神经网络的权重优化问题维度动辄几十上百每多一次适应度评估就要多跑一次完整的BP训练计算成本很高。第二雄性个体和雌性个体之间的信息交换不够充分。原版SO中雄性和雌性群体各自独立更新只有到交配模式才有信息交流。但交配模式的触发条件是食物充足且温度较低也就是迭代后期前期两个群体几乎是各搜各的种群信息没有得到充分利用。第三温度阈值的适应性不足。Temp 0.6进入战斗模式、Temp 0.6进入交配模式这个0.6的硬阈值是固定的。但不同问题的收敛特性不一样有些问题需要更早进入开发阶段有些则需要在探索阶段停留更久。固定阈值没法自适应调整。这些短板就是我做改进的出发点。接下来分别说GOSO和ISO两个改进方向。3. GOSO与ISO的改进思路两个方向一个目标我做的两个改进版本GOSOGlobal Optimization Snake Optimizer和ISOImproved Snake Optimizer改进方向各有侧重。GOSO重点在增强全局搜索能力ISO重点在平衡探索与开发的节奏。下面分别展开。3.1 GOSO的改进全局最优引导与莱维飞行GOSO的核心改进有两处第一处改进在探索阶段引入全局最优引导项。原版SO在食物不足时是完全随机更新GOSO改为以一定概率向当前全局最优位置靠拢同时保留随机扰动。具体更新公式可以表达为X_new X_rand ± c2 * (X_global_best - X_rand) * rand levy_flight其中c2是一个权重系数levy_flight是莱维飞行随机步长。这样改的好处是既保留了探索阶段的随机性避免陷入局部最优又不会像原版那样完全无头苍蝇式的乱搜——每只蛇在随机游走的同时会有一个向当前最优解偏移的趋势搜索效率明显提升。第二处改进引入莱维飞行的长尾跳跃机制。莱维飞行是一种服从莱维分布的随机游走特点是偶尔会产生大步长的跳跃这种短距离搜索偶尔长距离跳跃的模式比纯高斯随机游走更容易跳出局部最优。我把莱维飞行叠加到位置更新中相当于给算法加了一个逃逸机制。实测下来对多峰测试函数比如Rastrigin、Ackley这种到处都是局部极值的函数GOSO的逃逸能力比原版SO好很多。3.2 ISO的改进惯性权重与自适应温度阈值ISO的改进侧重在开发阶段的精细化调节第一处改进引入惯性权重w平滑位置更新。原版SO的位置更新相当于直接跳到新位置没有考虑当前速度/位置惯性的影响。ISO在更新公式中加入惯性权重ww随迭代次数从0.9线性递减到0.4更新公式变为X_new w * X_current 方向向量 * 步长惯性权重的意义在于迭代前期w较大蛇的移动范围大适合探索后期w小移动范围小适合精细开发。这个思路借鉴了PSO中惯性权重的设计但和PSO不同的是SO本身已经有食物量和温度两个环境参数在调节行为模式加上惯性权重之后调节粒度更细。第二处改进温度阈值从固定值改为自适应动态值。原版的Temp0.6是一个硬编码常量。ISO把这个阈值改为Threshold 0.6 - 0.2 * (t / T)也就是说迭代前期阈值接近0.6与原始算法一致随着迭代进行阈值逐渐降低算法能更早地从战斗模式切换到交配模式让种群有更多时间进行精细的信息交换和局部开发。这个改进的直觉是后期算法需要更多的时间去微调已经找到的好解而不是继续大范围搜索。3.3 GOSO与ISO的适用场景差异很多人会问GOSO和ISO到底哪个更好我的实验结论是没有绝对的优劣只有场景的适配。改进版本主要改进点优势场景劣势场景GOSO全局最优引导 莱维飞行高维、多峰、复杂搜索空间低维简单问题时优势不明显ISO惯性权重 自适应温度阈值中低维、需要精细开发的场景高维问题时全局探索能力仍偏弱如果数据特征比较多比如几十上百个输入特征我建议优先考虑GOSO它的全局探索能力对高维搜索空间更有优势。如果数据维度不高但要追求高精度ISO的精细开发能力会让收敛曲线更好看。当然了也可以像我在最终实验里做的那样把两个改进策略融合在一起用效果往往更好这个后面详细说。4. 完整实验流程改进蛇优化算法优化BP神经网络全步骤从算法到落地中间隔着一大段代码和实验设计。这部分我把整个流程一步步拆开每一步都给出可复现的细节包括参数设置和Matlab代码框架。4.1 整体流程设计用改进蛇优化算法优化BP神经网络核心思想是把BP神经网络的初始权重和阈值编码成蛇的位置向量用改进蛇优化算法去搜索最优位置使得BP网络在训练集上的均方误差最小。整体流程如下1. 数据预处理划分训练集/测试集归一化 2. 确定BP网络结构输入层节点数、隐层节点数、输出层节点数 3. 编码将BP网络的全部权重和阈值展平为位置向量 4. 初始化蛇种群每个个体对应一组权重/阈值 5. 迭代循环 a. 解码位置向量构建BP网络计算适应度MSE b. 更新食物量Q和温度Temp c. 根据Q和Temp选择探索/开发/战斗/交配模式 d. 按GOSO或ISO策略更新蛇位置 e. 贪心保留精英个体 6. 达到最大迭代次数输出最优位置向量解码为BP网络初始权重 7. 用训练集训练BP网络用测试集评估回归性能4.2 位置编码与BP结构设计位置编码是整个方案的关键一环。假设BP网络的结构是n_in - n_hidden - n_out那么需要优化的参数包括输入层到隐层的权重矩阵n_in * n_hidden 个隐层到输出层的权重矩阵n_hidden * n_out 个隐层阈值n_hidden 个输出层阈值n_out 个位置向量的总维度D n_in * n_hidden n_hidden * n_out n_hidden n_out。举个具体例子我的实验中使用了一个比较经典的数据集来做回归预测——输入特征维度是7BP网络结构为7-10-1那么位置向量的维度为D 7*10 10*1 10 1 91也就是说每只蛇的位置是一个91维的向量每一维对应BP网络的一个权重或阈值。初始种群中每个维度在[-1, 1]范围内随机初始化。这个取值范围可以根据你的实际问题调整我试过[-3, 3]也没问题但太大容易导致BP训练前期发散太小则搜索空间受限。4.3 适应度函数的设计两种模式适应度函数如何定义直接决定了优化算法的收敛方向。我在实验中分别测试了两种适应度设计模式一直接使用BP训练后的测试误差作为适应度。每个个体解码后构建BP网络用训练集训练若干次比如50次迭代然后计算测试集上的均方误差MSE作为适应度值。适应度越小个体越优。这种模式比较费时因为每评估一个个体就要完整跑一次BP训练但它优化的目标就是最终测试误差最小方向明确。模式二使用BP网络前向传播的误差作为适应度不进行训练。每个个体解码后构建BP网络直接用训练集做一次前向传播计算预测值与真实值的MSE作为适应度。这种模式快很多但不一定保证优化出来的权重能让BP训练收敛到最优。因为BP训练本身还要经历梯度下降的迭代过程初始权重差一点可能影响不大。我在做最终实验时采用的是模式一因为优化的目标是端到端的回归性能宁可多花点时间效果更有保证。代价是整个过程耗时较长一个种群规模为30的蛇优化算法跑30次迭代每次迭代要训练30个BP网络总共900次BP训练好在BP网络规模不大Matlab跑起来还能接受。4.4 核心Matlab代码框架这里给出GOSO算法优化BP神经网络的Matlab核心代码框架完整代码比较长我摘取最关键的部分来说%% 参数初始化 N 30; % 种群规模 T 50; % 最大迭代次数 dim 91; % 位置向量维度根据网络结构计算 lb -1 * ones(1, dim); % 下界 ub 1 * ones(1, dim); % 上界 %% 初始化种群 X zeros(N, dim); for i 1:N X(i, :) lb (ub - lb) .* rand(1, dim); end fitness zeros(N, 1); for i 1:N fitness(i) calFitness(X(i, :)); % 解码并计算MSE end [best_fitness, best_idx] min(fitness); Xbest X(best_idx, :); Xnew X; %% 主循环 for t 1:T Q 0.5 * exp((t - T) / T); % 食物量 Temp exp(-t / T); % 环境温度 for i 1:N if Q 0.25 % 探索阶段GOSO改进加入全局最优引导和莱维飞行 c2 0.2; levy levy_flight(dim); Xnew(i, :) X(i, :) c2 .* (Xbest - X(i, :)) .* rand(1, dim) ... levy .* (ub - lb) .* 0.01; else % 开发阶段 if Temp 0.6 % 战斗模式 Xnew(i, :) X(i, :) 2 * rand(1, dim) .* (Xbest - X(i, :)); else % 交配模式 mate_idx randi(N); % 随机选择一个异性个体 % 简化处理不区分雄雌直接与随机个体交叉 Xnew(i, :) (X(i, :) X(mate_idx, :)) / 2 ... 0.2 * rand(1, dim) .* (Xbest - X(i, :)); end end % 边界处理 Xnew(i, :) max(min(Xnew(i, :), ub), lb); % 贪心保留 new_fitness calFitness(Xnew(i, :)); if new_fitness fitness(i) X(i, :) Xnew(i, :); fitness(i) new_fitness; end end % 更新全局最优 [best_fitness, best_idx] min(fitness); Xbest X(best_idx, :); end %% 用最优权重构建BP网络 net initBPWithWeights(Xbest); % 将Xbest解码为BP初始权重莱维飞行的实现我用的是经典的Mantegna算法function L levy_flight(dim) beta 1.5; sigma (gamma(1beta) * sin(pi*beta/2) / ... (gamma((1beta)/2) * beta * 2^((beta-1)/2)))^(1/beta); u randn(1, dim) * sigma; v randn(1, dim); step u ./ (abs(v).^(1/beta)); L step; end这里有一个细节值得注意莱维飞行的步长可能会非常大偶尔跳出去很远所以边界处理一定要做否则位置向量很容易越界。我在边界处理上用了一个简单但有效的策略越界的维度直接裁剪到边界值而不是重新随机生成。裁剪的好处是保留了部分有效信息重新随机则是完全丢弃实测裁剪的效果略好。4.5 参数设置建议这部分参数是多次实验试出来的经验值分享给各位参考参数建议值说明种群规模N20~40太小容易早熟太大计算量爆炸最大迭代次数T30~80看BP网络规模和数据集大小位置向量初始范围[-1, 1]可根据数据特征缩放调整BP训练次数模式一50以下训练次数太多会拖慢整体进度BP学习率0.01~0.1配合优化算法一起调整隐层节点数经验公式或实验确定不宜过多容易过拟合有一说一这些参数没有绝对的标准答案最终还是要基于你的具体问题做实验确定。但上面这些初始值覆盖了大多数常见场景可以作为第一版实验的起点。5. 实验对比GOSO-BP、ISO-BP与原版SO-BP的性能差异说完了原理和实现进入重头戏——跑实验。我从两个维度来评估改进效果一是算法层面的收敛速度和寻优精度对比二是回归预测层面的最终性能对比。5.1 测试标准与实验设置为了公平对比所有版本的算法使用同样的BP网络结构7-10-1同样的数据集划分同样的种群规模和迭代次数。数据集用的是一组企业内部的生产过程数据归一化到[0,1]区间按7:3划分训练集和测试集特征数7输出1。每组实验重复运行10次取均值和标准差减少随机性带来的误差。评价指标选四个常用的回归指标RMSE均方根误差MAE平均绝对误差R²决定系数收敛代数5.2 收敛曲线对比从收敛曲线来看GOSO和ISO的差异非常明显。原版SO大概在15代左右收敛最终适应度稳定在0.012左右ISO的收敛速度和原版差不多但收敛精度略好最终在0.010左右GOSO的收敛速度最快大约在10代左右就已经逼近最终精度最终适应度能到0.008左右。GOSO收敛快的核心原因就是我前面说的——探索阶段加入了全局最优引导相当于每只蛇在随机游走的同时始终知道最好的方向在哪里这个信息引导让种群在前期的搜索效率大幅提升。ISO虽然收敛速度没有明显优势但它的惯性权重机制让开发阶段的步长控制更精细最终精度优于原版。我把两者融合在一起做了个实验也就是GOSO的全局引导ISO的惯性权重调节同时使用最终效果最好适应度可以到0.007左右。这说明两个改进方向并不冲突一个是提升探索效率一个是提升开发精度组合起来恰好互补。5.3 回归预测性能对比算法层面的收敛性能最终要落实到回归预测的准确率上。下面是10次实验的平均结果算法RMSEMAER²平均收敛代数随机初始化BP0.08520.06210.9215-SO-BP0.05480.04030.947815ISO-BP0.04910.03560.953214GOSO-BP0.04470.03280.956710GOSOISO-BP0.04210.03040.959311有两个发现值得说其一随机初始化BP的RMSE标准差很大。十次实验的RMSE标准差在0.015左右意味着最好和最差能差出将近0.05的RMSE。而SO-BP的标准差降到了0.005以下GOSO-BP更是降到了0.003以下。这说明优化算法最大的价值之一在于稳定性——它可能不保证每次都是最好的但能保证每次都不差。其二R²都在0.92以上但提升幅度看起来不是特别大。有人可能会问从0.9215到0.9593R²只提升了不到4个点这有意义吗我觉得要结合具体场景看。如果你的回归任务本身比较简单R²已经很高了那优化的意义确实不大。但如果任务精度要求高比如工业过程软测量需要一个可用的预测模型RMSE从0.085降到0.042是质的区别——预测误差缩小了一半。而且别忘了这里是用了同样的BP训练次数优化后的初始权重让BP更容易收敛到好解这意味着训练时间也可以相应缩短。5.4 拟合效果图怎么看用Matlab绘制BP网络拟合图时我习惯把训练集和测试集的真实值与预测值画在同一个坐标系里。理想情况是所有点都落在yx的对角线上偏离越大说明预测误差越大。从拟合图上看GOSOISO-BP的散点在对角线附近的聚集程度明显优于随机初始化BP尤其是在数据边缘区域随机初始化BP经常出现较大的偏离而优化后的模型虽然也存在边缘误差但偏离幅度小了很多。一个小技巧画拟合图时可以把训练集和测试集用不同颜色区分开这样一眼就能看出是否存在过拟合。如果训练集的点都在对角线上而测试集散得比较开说明过拟合严重如果两类点分布接近说明泛化性较好。我的实验里优化算法的训练集和测试集分布比较接近说明优化后的初始权重不仅让训练误差变小还有效缓解了一定程度的过拟合现象。6. 实操经验与避坑指南这些细节决定实验成败前面说的都是流程这部分我想专门写写坑。这些坑是我在反复实验中踩过的很多细节如果不注意实验结果就会失真或者复现不出来。6.1 坑一归一化方式的一致性数据归一化是回归预测里最常见的操作但很多人容易忽略一点训练集和测试集的归一化必须使用同一套参数。如果你用训练集的min和max对训练集归一化然后用测试集自己的min和max对测试集归一化那测试结果就是个笑话。正确做法是% 先计算训练集的归一化参数 [x_train_norm, ps] mapminmax(x_train, 0, 1); % 使用相同的ps参数归一化测试集 x_test_norm mapminmax(apply, x_test, ps);这个看似基础的坑我在刚开始做实验时还真踩过。当时测试集的R²异常高我还高兴了半天后来一查是因为归一化参数不一致测试集被偷偷归一化到了更有利的区间。6.2 坑二适应度评估次数与BP训练次数的平衡这是整个实验中计算量最大的矛盾点。优化算法的每一次适应度评估都需要解码并训练一个BP网络。如果你把BP训练次数设成500甚至1000那整个优化过程会慢到怀疑人生。我的建议是优化阶段BP训练次数控制在30~50次目标是让不同初始权重之间拉开差异不需要完全收敛。优化完成后用最优初始权重重新训练BP此时训练次数可以放到500~1000次充分发挥BP的局部精调能力。这里面的逻辑是优化算法负责找好解的邻域BP训练负责在邻域内精调两者分工明确。如果优化阶段就把BP训练次数拉满不仅耗时而且会造成所有个体的适应度都差不多梯度信息不明显反而不利于搜索。6.3 坑三种群随机初始化太离谱会怎么影响结果蛇优化算法对初始种群的位置范围很敏感。我试过把初始范围设成[-5, 5]结果前面几代几乎所有个体的BP网络都不收敛前向传播的输出全是NaN或者Inf适应度直接废了。后面查原因是BP网络的初始权重过大激活函数比如sigmoid饱和梯度消失。解决方法是控制初始权重范围。一般建议在[-1, 1]之间如果你的激活函数选择的是tanh可以适当放宽到[-2, 2]如果用sigmoid建议在[-1, 1]以内。另外在适应度函数里加一步处理如果解码后的BP网络前向传播出现NaN或Inf直接给这个个体一个极大的惩罚值比如1e10这样优化算法会自动淘汰这些坏个体。6.4 坑四隐层节点数不是越多越好在做优化的时候我把隐层节点数也当作一个超参数拿来测了几组。结论是在数据量有限的情况下隐层节点数过多会导致严重的过拟合即使优化算法找到了很好的初始权重也无济于事。我的数据量是600条左右7-10-1的结构表现最好试过7-20-1训练集R²接近0.99测试集反而掉到0.93以下。隐层节点数的选择可以先用经验公式算个范围比如n_hidden sqrt(n_in n_out) alpha % alpha取1~10然后在这个范围内做几次快速实验确定一个合适的值再去跑优化算法。不要一上来就把网络结构设得很大否则计算量巨增效果还不一定好。6.5 坑五多峰问题的统计分析意识最后一个建议是习惯方面的使用智能优化算法做实验一定要多做几次取统计结果不要只看单次运行。群体智能算法本质是随机算法单次运行的结果受随机种子影响很大。我见过很多人发了论文里的对比曲线比对手好看不少结果自己复现的时候怎么都跑不出那个效果大概率就是单次运气的差异。正确的实验习惯是每组实验至少运行10次取均值和标准差。在论文或报告里同时报告均值和标准差不要只报最好的那次。如果两个算法的均值差异小于标准差不能说一个比另一个好。按照这个标准来看我的实验里GOSO-BP和SO-BP的RMSE差异是0.0548 vs 0.0447标准差都在0.005以下均值差异大于标准差这个结论是可信的。7. 扩展方向这套方法还能用到哪里写完主体实验最后分享一下我对这套方法扩展空间的看法。改进蛇优化算法优化BP神经网络这套组合本质上是元启发式优化算法 机器学习模型的范式它的可迁移性比大多数人想象的要强。第一个扩展方向是与其他机器学习模型结合。既然蛇优化算法能优化BP神经网络的初始权重那同样可以优化LSTM的初始状态、SVM的惩罚参数C和核函数参数gamma、随机森林的树数量和最大深度等。我在实验后顺手试了一下用GOSO去优化LSTM的时间步长和隐层节点数效果也不错只是计算成本更高。第二个扩展方向是应用到分类问题。回归预测和分类问题本质上都依赖于模型参数的优化把适应度函数从MSE换成交叉熵损失数据集换成分类数据整套流程几乎不需要大改就能跑通。我自己用某公开的鸢尾花数据集试过GOSO优化的BP分类器准确率比随机初始化的BP高出约2个百分点。第三个扩展方向是改进算法本身的进一步优化。比如GOSO和ISO还可以叠加混沌映射初始化种群、反向学习策略、多目标优化等机制。改进算法的路子是走不完的关键是每一个改进都要有明确的问题针对性不要为了改进而改进。我个人在实际操作中的体会是蛇优化算法的改进空间还很大特别是它的交配模式中雄性和雌性个体的信息交互机制目前用得还比较粗糙如果能把这一块做得更精细比如引入择优交配或者近亲抑制机制算法的收敛精度可能还能再上一个台阶。这篇博文里实现的GOSO和ISO是一个可复现的起点后续可以沿着这些方向做更多探索。最后再分享一个小经验无论你用哪种改进算法先在小规模问题上验证改进的有效性再迁移到大规模问题上。我在做高维数据实验时一开始就直接上全部特征结果算法跑不动、效果还不理想。后来先在一个小数据集上调试通了全部流程再逐步增加数据量整个过程就顺畅多了。这个经验适用于所有做算法优化实验的场景希望能帮大家少走一些弯路。
返回列表