
上个月有个做负荷预测的师弟问我说论文里只写了PSO和GWO的对比审稿人觉得算法太老让他补充几个能直接在Matlab里跑、不装第三方工具箱、还能画出收敛曲线的智能优化算法。我从常用算法库里挑了CGO、SCA、GWO、CSA、SSA、HHO、WOA、PSO、TSO这9种统一加了测试函数、维度、种群规模和迭代次数整理了一套可以替换目标函数的Matlab代码结构。这篇文章不是把论文搬过来复述公式而是把我实际跑对比时的算法理解、参数设置和容易翻车的细节写出来。想快速做算法对比、给论文补实验或者从PSO/GWO往新算法扩展的人可以照着这套思路搭自己的实验模板。1. 9种算法放同一张表之前先把它们拆成三类很多新手拿到算法清单就开始跑跑完发现结果乱七八糟根本不知道问题出在算法本身还是参数设置。我的习惯是先看机制把9个算法按照“搜索行为来源”分成三类这样后面分析收敛曲线时才不会瞎猜。1.1 捕食追踪型GWO、WOA、HHOGWO模拟灰狼集群的等级分工。alpha、beta、delta是头狼其余omega跟随头狼更新位置。每一轮先算所有狼的适应度把前三名记为alpha、beta、delta然后用三只头狼的加权位置决定下一代位置关键参数是A2arand-a其中a从2线性降到0。A的绝对值大于1时狼群离散搜索小于1时向猎物收缩。这个算法优点是结构简单、参数极少缺点是后期种群多样性下降快多峰测试函数里很容易所有个体挤到同一个局部峰附近。WOA模拟座头鲸的气泡网捕食比GWO多一个策略分支。每轮生成一个随机数pp小于0.5时走收缩包围和GWO类似p大于等于0.5时用对数螺旋绕圈逼近猎物。同时还有一个随机探索机制避免所有鲸鱼都贴着当前最优走。正因为多了一个螺旋操作WOA的搜索路径更“绕”在复杂曲面上有时能绕出局部最优但也更容易在前中期浪费评价次数。HHO模拟哈里斯鹰围捕逃跑的兔子核心是猎物能量E从2迅速掉到0再叠加随机数q决定软围攻、硬围攻、渐进式快速俯冲等策略。它不是靠单一参数控制探索和开发而是按E绝对值和随机逃逸概率切换模式。HHO前期会到处飞后期突然集中围住某个区域所以收敛曲线经常出现“阶梯式下降”。这既是优点也是隐患在多峰问题上容易出现结果忽好忽坏的现象。1.2 群体共享信息型PSO、SSA、CSA、TSOPSO不用过多解释速度-位移模型pbest和gbest分别提供个体记忆和社会记忆。惯性权重w前期大后期小c1、c2分别控制“向自己历史最优飞”和“向群体最优飞”。优点是最好理解、实现容易、不容易出bug缺点是后期gbest不变时整个粒子群会围着同一个点抖动基本没有跳出机制。SSA这里我按樽海鞘群算法来写也就是Salp Swarm Algorithm。它在代码里的特点是“链式移动”第一个领导者更新后后面每个跟随者只参考前一个体的位置链头由食物源引导系数c1从2衰减到0控制探索和开发。链式结构的优势是种群移动有方向性但劣势也很明显领导者一旦越界整条链都会被带偏因此边界处理比别的算法更关键。需要提醒的是中文论文里也常把SSA当作麻雀搜索算法那是完全不同的机制下载代码前先确认你拿到的到底是樽海鞘还是麻雀。CSA在标题里我按乌鸦搜索算法来展开。每只乌鸦代表一个解并且会记住自己藏食物的位置。算法随机选另一只乌鸦决定跟踪还是远离参数fl控制飞行距离AP是乌鸦发觉被跟踪的概率。AP越小乌鸦越容易相信同伴算法后期过快聚集AP越大群体越警惕搜索越接近随机。我一般把AP放在0.1到0.2fl取2左右但这个组合在不同问题上并不通用。如果你在别的资料里看到CSA代表鸡群算法基本是笔误或另一套代码使用时务必先确认。TSO是被囊群优化算法模拟海洋被囊动物喷流推进和群体交流。喷流推进阶段生成新候选位置群体交流阶段参考最优个体和当前个体的差异做加权更新。很多论文版本会把控制参数写成随迭代线性递减效果上接近GWO的a。这个算法的中文资料相对少Matlab代码风格差异很大从网上下到版本后先看它内部到底是最小化还是最大化寻优否则实验方向直接跑反。1.3 几何与非生物机制型SCA、CGOSCA正弦余弦算法不走生物路线用sin和cos函数把候选解在新旧位置之间摆动。r1随迭代下降控制摆动幅度r2决定移动半径方向r3、r4产生随机性。低维问题上效果尚可维度一高很容易振荡属于“理解成本低、实战稳定性一般”的算法更适合作为教学示例或者对比实验里的“差异性补充”。CGO的完整名字是混沌博弈优化源自混沌博弈理论和分形几何。它把当前最优位置、当前个体位置、以及若干随机个体当成“顶点”每个种子在顶点围成的区域内按概率移动生成下一代。CGO机制很像分形图形每次都在缩小范围内选点最终形成局部密集搜索。实际代码里它至少有四个不同的更新分支随机性很强单次运行很难看出真实水平。算法全称/灵感位置更新核心关键参数最容易翻车的地方GWO灰狼捕猎alpha/beta/delta加权a、A、C后期多样性不足WOA座头鲸气泡网收缩包围对数螺旋a、p螺旋与随机探索比例固定HHO哈里斯鹰捕兔软硬围攻俯冲E、q、r模式跳变导致波动PSO鸟群觅食速度个体/全局最优w、c1、c2全局最优卡死SSA樽海鞘链领导者-跟随者链式c1、c2领导者越界带偏全链CSA乌鸦藏食追随/逃跑感知概率AP、fl参数敏感度过高TSO被囊群推进喷流推进群体交流衰减控制参数代码实现差异大SCA正弦余弦摆动sin/cos位置摆动r1、r2高维振荡CGO混沌博弈/分形四顶点随机投影多种随机分支单次运行极不稳定2. 关键迭代逻辑位置更新的共性和差异2.1 统一接口让9种算法都从同一个入口跑跑对比实验时最大的错误是每个算法单独写一个脚本用到的时候临时改参数。几个月后自己都忘了哪个版本对应哪张图。我后来把代码统一收成一个runOptimizer入口所有算法返回bestX、bestF、convergence后续只需要写一个测试脚本循环调用function [bestX, bestF, curve] runOptimizer(optName, objFun, dim, lb, ub, MaxIt, nPop) switch optName case PSO [bestX, bestF, curve] PSO(objFun, dim, lb, ub, MaxIt, nPop); case GWO [bestX, bestF, curve] GWO(objFun, dim, lb, ub, MaxIt, nPop); case WOA [bestX, bestF, curve] WOA(objFun, dim, lb, ub, MaxIt, nPop); case HHO [bestX, bestF, curve] HHO(objFun, dim, lb, ub, MaxIt, nPop); case SSA [bestX, bestF, curve] SSA(objFun, dim, lb, ub, MaxIt, nPop); case CSA [bestX, bestF, curve] CSA(objFun, dim, lb, ub, MaxIt, nPop); case TSO [bestX, bestF, curve] TSO(objFun, dim, lb, ub, MaxIt, nPop); case SCA [bestX, bestF, curve] SCA(objFun, dim, lb, ub, MaxIt, nPop); case CGO [bestX, bestF, curve] CGO(objFun, dim, lb, ub, MaxIt, nPop); end end这种结构的好处是你后面想换成自己的目标函数只需要保证objFun接收一个nPop×dim矩阵返回每个个体的适应度列向量所有算法代码都不用动。2.2 种群初始化必须用同一套语法初始化时我统一这么写Positions rand(nPop, dim) .* (ub - lb) lb;很多算法代码里直接写成rand(nPop,dim)*ub把lb丢了。测试函数的下界不是0时初始种群就全错。表面上看每个算法都“初始化了”实际起点范围完全不同对比结果没有意义。另外目标函数建议写成支持矩阵输入的向量化版本不要循环单个个体否则跑高维度时会非常慢。function f sphere(x) f sum(x.^2, 2); % x是nPop×dim矩阵f是nPop×1 end2.3 参数设置的常用基线不同算法参数没有一个万能组合但我整理了一套不容易出大问题的起步值算法我常设的参数为什么这么设GWOa: 2→0A2arand-a线性衰减控制探索开发WOAa: 2→0p∈[0,1]让后期螺旋更集中HHOE: 2→0q∈[0,1]E小于1后才进入围攻PSOw: 0.9→0.4c1c22经典取法审稿人不会质疑SSAc1: 2→0c2随机链头向食物源链尾跟随CSAAP0.1~0.2fl2AP太大就退化成随机搜索TSO衰减系数2→0多数开源版本默认逻辑SCAr1: 2→0控制sin/cos摆动幅度CGO随机分支选择算法本身没有固定主参数就算按这些初始值跑同一组参数在不同函数上的表现差异也很大。真正写论文时除了默认参数外最好补一个简单的参数敏感性分析不然审稿人一句“参数怎么来的”就能把实验结论打穿。3. Matlab对比实验真实跑下来应该怎么设计3.1 测试函数不能只选一个对比实验只跑一个函数说服力很低。我通常至少选三个形态不同的函数单峰Sphere或Rosenbrock多峰Rastrigin或Ackley固定维度的CEC基准。维度也要分开低维用10维中维用30维高维可以到100维。注意这里的维度指决策变量个数不是测试函数的种群数很多人会把这两个概念搞混。测试函数统一写成支持向量化输入的形式。如果拿到的函数是for循环逐个点算的建议改成矩阵运算不然9个算法×3个函数×30次独立运行时间会非常难熬。3.2 独立运行次数和统计口径智能优化算法是随机算法跑1次没有意义。我习惯每个算法每个函数独立运行30次记录每次得到的最优适应度再算均值、中位数、标准差。为什么同时看均值和中位数因为单峰函数上均值接近中位数但在Rastrigin这种多峰地形上某一次跳出局部最优会让均值大幅偏移只看均值会高估算法稳定性。有条件的话再做一个Wilcoxon秩和检验把PSO当Baseline看新算法相对Baseline的提升是否有显著性。很多审稿人看到你只贴三条收敛曲线不会说太多但看到均值好却不给统计检验就会追问显著性结果。3.3 记录收敛曲线时用评价次数而不是迭代次数这是最容易忽略的公平性问题。PSO一次迭代通常只评价nPop次适应度但HHO、CGO这类算法内部有多个分支每个分支里可能又调用了一次目标函数实际评价次数是迭代次数×nPop×分支倍数。如果你统一设定MaxIt500那9个算法的工作量其实完全不一样。我的做法是在每个算法的适应度评估处统一维护一个FEsFunction Evaluations计数器收敛曲线的横坐标用FEs而不是迭代次数。只有这样不同算法才能在“花了同样计算量”的前提下比较。顺手也把每一轮的gbest记录成curve数组convergence(t) bestF;3.4 实验脚本的标准流程一个完整的对比实验流程应该是先确定测试函数和维度再确定nPop和MaxIt然后每个算法独立跑30次每次记录最终bestX、bestF和convergence曲线。最后把所有结果汇总到一个结构体里用箱线图看分布用均值标准差做表格用秩和检验做显著性。不要急着画带阴影的收敛图先把数据形态看清楚。4. 我跑Sphere和Rastrigin之后看到的排序和反直觉结论4.1 单峰Sphere上老牌算法根本不落下风在Sphere这种简单单峰函数上我跑下来的直观感受是PSO和GWO完全能和新算法打平。PSO收敛快低维度时几乎每轮都在往下压GWO稳步下降曲线很“体面”WOA前期跳跃明显后期也能拿到接近较好的值。真正在Sphere上容易出问题的往往是SCA和CSA它们的后期收敛会出现一段明显的“平台期”感觉像步子太小卡在某个量级下不去。这里有一个反直觉的点网上很多论文里展示的漂亮曲线往往只挑了最优的一次运行结果。同一个HHO在Sphere上多跑几次前期曲线可能有很大差异有的版本甚至前50次迭代下降很少后面突然又跳一次。选哪条曲线、怎么说明稳定性比单纯说“最小适应度更低”更重要。4.2 Rastrigin上HHO、WOA和GWO各有各的挣扎方式Rastrigin函数局部最优极多10维就已经很容易把算法困住。GWO刚开始下降很快但进入后期后所有灰狼都集中到同一个局部峰附近基本没有能力再大幅跳出去。WOA的优势在于螺旋绕行偶尔能跳到相邻的峰代价是消耗更多评价次数。HHO如果能量衰减参数E设置得太快后期所有个体都会进入硬围攻模式结果被锁在局部区域但如果E衰减偏慢它又会浪费大量评价次数在外围瞎飞。CGO在Rastrigin这类函数上表现很有戏剧性单次运行有时能挖到很不错的适应度有时差得离谱。我把它当成“抽奖类”算法实验时必须增加独立运行次数否则极容易在报告里得出错误排名。TSO的行为很大程度取决于你下载到哪个实现版本有的版本做了局部搜索改进有的版本还是原始喷流推进代码水平直接决定结果。4.3 箱线图比收敛曲线更诚实多跑几次以后我把9个算法的最终适应度做成箱线图发现中位数和均值的差距经常被忽视。某个算法平均适应度更小可能是靠一次偶然的优秀结果拉高但中位数很差。所以我在报告里固定给出mean±std和中位数并且画箱线图。收敛曲线看趋势箱线图看分布两张图配合使用才不容易被审稿人挑刺。下面是我在固定10维、种群30、迭代500次时观察到的大致行为只反映相对倾向不写具体数值因为换一组参数结论就可能变算法Sphere表现Rastrigin表现稳定性我的主观建议PSO收敛稳定中位数稳定极值普通高适合做BaselineGWO稳步下降前期快后期平缓中参数a影响大WOA中后期可能跳出局部探索和开发较均衡中多峰可以试HHO前期剧烈后期集中波动大偶发好结果低必须多跑几次SSA链式移动整体性强注意越界问题中边界处理要严格CSA结果依赖AP和fl容易早聚低参数单独调TSO实现版本差异大版本决定结果低到中先确认代码逻辑SCA低维可行高维偏弱摆动明显中教学或对照用CGO单次波动大偶发优秀结果低当作随机性强的对比项5. 那些容易被忽略的工程细节不止是调参5.1 越界处理方式必须写清楚算法位置更新时很容易跳出自变量范围。常见处理有三类把越界个体拉回边界把越界坐标按边界反弹重新随机生成一个位置。很多论文完全不提这一点但影响很大。我默认使用“拉回边界”也就是Positions max(Positions, lb); Positions min(Positions, ub);这样操作简单也不算浪费个体。对SSA这类链式结构领导者一旦越界后面的跟随者可能全被带偏所以更要在每一次位置更新后马上加一次边界裁切。CGO这类多分支算法如果使用“反弹”模式数值上容易出现振荡反而不如直接截断来得稳定。5.2 最大化和最小化方向必须统一很多开源算法内部默认按最小化写但你实际可能是要最大化分类准确率或产品收益。如果直接把准确率传进去算法会拼命让准确率变小。正确做法是在目标函数里返回负准确率或者把问题转换成损失。我之前见过有人把SCA和CGO用反最后结果和另一个算法差了好几个数量级查了半天发现是优化方向写错了。5.3 gbest更新顺序的坑记录全局最优时最常见的问题是在某个分支里更新了gbest变量但下一次位置更新用的还是更新前的旧位置。这样记录曲线会正常实际上个体追逐的目标是“上一版的gbest”逻辑上存在半拍延迟。我建议每一轮迭代结束后统一评估整个种群的适应度再更新alpha、beta、delta或gbest。代码看起来多执行了一次筛选但不容易出现变量覆盖错误调试起来也省心。5.4 从测试函数迁移到真实问题时怎么办9个算法在Sphere和Rastrigin上跑得再好也不等于能直接解决工程问题。比如做光伏MPPT决策变量是占空比需要处理电压电流的非线性关系做PID整定要同时优化三个参数还要考虑系统稳定性约束。我的做法是先小规模跑通接口把objFun替换成我的实际计算模型用较小的nPop和MaxIt验证每一轮种群更新是否合理再逐步放大工作量。否则一上来就9个算法全跑光等待时间就能把人耗没。6. 选型逻辑与个人使用建议6.1 按问题类型选算法而不是按论文年份选新算法不一定适合你的问题。我的选择逻辑大概是这样做PID参数整定、电力调度这类连续参数优化PSO和GWO是稳妥的起步选项代码容易改出问题也好定位。做特征选择这类离散问题需要把连续位置转成二进制SCA和CGO的连续振荡特性反而麻烦一般先试PSO配合阈值转换。做高维复杂多峰问题WOA和HHO可以尝试但必须多跑几次看分布不要因为一次好结果就下结论。做论文对比实验最合适的组合是一老PSO或GWO、一新HHO或SSA、一小众CGO或TSO既有辨识度又不至于被质疑算法过老。如果只是自己学习元启发式算法先啃PSO和GWO再啃WOA和HHO最后再碰CGO和TSO否则你很难判断随机波动到底来自算法还是实现。6.2 发论文或写报告时实验配置要交代完整我整理实验时固定写清楚Matlab版本、操作系统、统一种群大小和迭代次数、独立运行次数、边界处理方式、每个算法的参数来源是默认还是网格搜索、收敛曲线横坐标用的是迭代次数还是评价次数。这些东西写在附录里看着琐碎但能显著提高实验可信度。有人只放三张收敛图换一版参数可能结果完全相反后面被要求复现时很难处理。6.3 最后分享一个个人习惯我自己写对比模板时所有算法都是runOptimizer这种统一接口。遇到新问题我先用PSO跑三遍得到一个“不太费力就能达到”的参考水平再用其他算法去比。如果某个新算法连PSO都打不过那大概率不是我用的测试函数太简单而是它的默认参数在你这套代码里没调好或者代码逻辑本身有问题。先用最稳的Baseline探底再让新算法上场这是最不容易冤枉某个算法、也最容易排查bug的顺序。9种算法的对比实验真正值钱的不是你能说谁最强而是你能说清楚它们各自在什么条件下强、什么条件下失效。