Matlab下9种智能优化算法对比实验框架与实现要点 做算法对比实验这种事看着简单真做起来全是坑。把 CGO、SCA、GWO、CSA、SSA、HHO、WOA、PSO、TSO 这9种智能优化算法同时放到Matlab里跑一遍如果你的对比框架设计得不严谨最后得出的“谁强谁弱”结论基本站不住脚。我去年为了给一组带复杂约束的工程问题挑选合适的求解器前前后后把这9种算法代码重写了两遍才跑出能说服自己、也能说服评审的数据。这篇文章就当一次完整复盘把算法机制、实验设计、Matlab代码实现、公平比较的踩坑点一次性讲清楚。这篇内容适合两类人一是刚入门智能优化算法、想在Matlab里快速跑通主流算法做横向对比的初学者二是已经在做算法改进或应用、但对“对比实验的公信力”还不够敏感的研究者。读完你至少能获得一套可以直接复用的实验框架和9种算法的核心实现思路。1. 先把9个算法的“血缘”捋清楚1.1 从灵感来源看三大流派很多人一上来就盯着公式看结果越看越乱。我习惯先按灵感来源把算法分类因为同一类算法在调试时的关注点高度相似。第一类是“社会信息共享派”典型代表是 PSO 粒子群算法和 SSA 樽海鞘群算法。这类算法的核心是“个体之间怎么交换信息、怎么跟着优秀个体走”。PSO 靠的是速度更新每个粒子记忆自己的历史最优和全局最优SSA 则把种群排成一条链领头个体直接朝食物位置移动后面的个体跟着前一个走。这类算法收敛快、实现简单但容易扎堆早熟。第二类是“捕食与等级派”典型代表是 GWO 灰狼算法、WOA 鲸鱼算法、HHO 哈里斯鹰算法勉强能把 CSA 乌鸦搜索算法也算进来。它们的共同点是模拟捕食者围猎猎物的过程通过“包围—扰动—攻击”的策略平衡探索和开发。GWO 靠 alpha、beta、delta 三匹头狼引导WOA 靠螺旋气泡网和收缩包围二选一HHO 则是根据猎物的逃跑能量动态切换四种围攻策略。好理解但控制参数多调试时要多留个心眼。第三类是“纯数学机制派”典型代表是 SCA 正余弦算法和 CGO 混沌博弈算法。它们不依赖生物隐喻纯粹用数学算子产生搜索步长和方向。SCA 用正弦余弦的周期性波动来震荡搜索CGO 基于混沌博弈的分形思想把搜索空间当成一个不断迭代的三角区域。这类算法在复杂多峰问题上的探索能力常常出人意料但收敛速度往往不如前两类。顺带说一句这里的 SSA 我按樨鞘群算法来写。如果你看到有人用 SSA 表示麻雀搜索算法别急那只是同名缩写机制完全不同。后文的实验框架和Matlab代码对两者都是通用的只是更新方程要换一套。1.2 各算法的核心机制一句话为了让你对9种算法有个总览级印象我整理了一张表。这张表我建议你保存下来写论文也好、做汇报也好都能用上。算法缩写灵感来源核心更新逻辑主要控制参数混沌博弈优化CGO混沌博弈与分形在四个可行域之间迭代生成三角分形保留最优投影分形调整参数、投影权重正余弦算法SCA正弦余弦波动用周期性波形决定移动方向和步长r1衰减系数、r2随机数、r3权重灰狼优化CGO 改为 GWO灰狼等级捕猎alpha/beta/delta引导其余狼围绕目标更新位置a衰减系数、随机向量A、C乌鸦搜索算法CSA乌鸦藏食与偷窃以意识概率AP决定跟随或随机游走AP意识概率、飞行长度fl樽海鞘群算法SSA樽海鞘链式运动领头者朝食物移动追随者沿链式跟随c1衰减参数、位置边界哈里斯鹰优化HHO哈里斯鹰围攻猎物按猎物能量动态软/硬围攻与俯冲逃逸能量E、跳跃强度J鲸鱼优化算法WOA鲸鱼气泡网捕食收缩包围与螺旋更新以50%概率切换a衰减系数、螺旋常数b粒子群优化PSO鸟群觅食速度叠加个体与全局最优方向惯性控制飞行惯性权重w、学习因子c1/c2金枪鱼群优化TSO金枪鱼群觅食螺旋觅食与抛物线觅食两种策略交替螺旋系数、策略概率注意GWO 在表格里我特意加了提醒别打成 CGO 的同名。这两个缩写一个带 C、一个带 G代码注释里很容易因为手误写串。2. 实验设计的三个关键决策2.1 基准函数选哪些算法对比不是随便丢几个测试函数跑一遍就完事。基准函数的选择直接决定实验结论的可信度。我的做法是分三组。第一组选单峰函数比如 Sphere、Rosenbrock、Schwefel 1.2这一组重点考察算法的收敛速度。第二组选多峰函数比如 Rastrigin、Ackley、Griewank这一组重点考察算法跳出局部最优的能力。第三组选固定维度的复杂函数比如 Kowalik、Shekel、Hartman这一组用来模拟工程设计里常见的低维非线性问题。每组至少两个函数总数控制在六个到八个。函数少了结论太片面函数多了跑起来耗时太长调试期间你会崩溃。每个函数记录理论最优值这样后期统计误差时才有基准线。2.2 “公平”到底是什么公平这是算法对比里最容易被喷的地方。所谓公平不是把每个算法的代码拿过来直接跑而是要把“评价口径”统一起来。我固定下来的实验协议是这样的种群规模统一30迭代次数统一1000独立运行次数统一30次。任何算法都用相同的初始随机种子集合也就是说第k次独立运行时9种算法拿到的是同一批初始种群。这样做的好处是如果你发现某种算法在某次运行里特别差可以直接对比它的更新过程而不用怀疑是初始点不同造成的。另一个容易争议的是“算法特有参数怎么设”。我的原则是优先使用原文献推荐的默认参数。因为算法作者调出来的参数往往最能体现算法的真实潜力你非要自己乱调一通反而可能把算法调废。比如 HHO 的逃逸能量E、PSO 的惯性权重w这些参数背后都有明确的动力学含义一顿乱改会让算法行为完全变样。提示如果某个算法在你调参后效果明显变好而默认参数下效果较差说明该算法对参数敏感度偏高。这一点要写进实验分析里它本身就是有价值的结论。2.3 Matlab代码框架怎么搭9个算法、6个基准函数、30次独立运行这个组合如果不用统一框架代码会写成灾难现场。我的做法是建立一个“最小公共接口”。每个算法只暴露一个函数输入是目标函数句柄、维度、上下界、参数结构体输出是最优解、最优值和收敛历史。这样无论是加一个新算法还是换一个测试函数都只需要改一行调用其他统计代码完全不用动。另外一个很关键的细节是随机数流的管理。Matlab里rand和randn是共享一个全局随机数生成器的如果你在某个算法内部不小心多调用了一次随机数后面所有算法的随机序列都会偏移。我建议在每个算法函数开头用rng(batchSeed algIndex)显式隔离随机流确保算法之间互不污染。3. Matlab实现的核心环节3.1 统一的算法函数签名我习惯写一个统一接口长这样function [bestX, bestF, history] runGWO(fun, dim, lb, ub, params) % fun : 目标函数句柄 % dim : 变量维度 % lb, ub : 变量下界和上界 % params : 结构体包含种群规模、迭代次数等通用参数 % bestX : 最优解 % bestF : 最优值 % history : 每次迭代的最优值记录其余8个算法的函数签名完全一样只是文件名不同。这样写的好处是后面做统计对比时只需要一个循环algs {runPSO, runGWO, runWOA, runHHO, runCGO, runSCA, runCSA, runSSA, runTSO}; for i 1:length(algs) [bestX{i}, bestF{i}, history{i}] algs{i}(fun, dim, lb, ub, params); end这9个函数内部结构也尽量保持一致初始化种群 → 计算适应度 → 进入迭代循环 → 更新个体 → 边界处理 → 记录历史最优。只有中间的“更新个体”这段逻辑是每种算法自己的其余代码全部共享。这样做算出来的对比结果至少不会因为代码实现风格差异而产生系统偏差。3.2 三张有代表性的更新方程在所有更新方程里有三组我认为最值得细看PSO 的速度位移、GWO 的位置包围、WOA 的螺旋更新。搞懂了它们其他算法的代码都能看懂大半。PSO 的核心就两行一个更新速度一个更新位置v w * v c1 * rand(size(v)) .* (pbest - x) c2 * rand(size(v)) .* (gbest - x); x x v;这里惯性权重 w 控制的是“维持原有飞行趋势”的力度c1 是飞向自身经验的拉力c2 是飞向群体经验的拉力。生活化理解就是你在商场找出口既相信自己以前走过的路又看到别人朝某个方向跑于是综合决定往哪走。GWO 的更新思路稍微绕一点它先算三匹头狼的位置加权平均r1 rand(dim, 1); r2 rand(dim, 1); A1 2 * a * r1 - a; C1 2 * r2; D_alpha abs(C1 .* alpha_pos - X); X1 alpha_pos - A1 .* D_alpha; % 对 beta 和 delta 同理 X_new (X1 X2 X3) / 3;a 从2线性降到0模拟的是狼群从“大范围搜索”到“包围猎物”的过程。这一招很经典后来很多改进算法都借鉴了这种“多领导者加权”的思想。WOA 最惊艳的是收缩包围和螺旋更新的二选一机制if p 0.5 X_new best_pos - A .* D; % 收缩包围 else D abs(best_pos - X); X_new D .* exp(b).* cos(2 * pi * l) best_pos; % 螺旋 end由于 p 是0到1的随机数鲸鱼在每次迭代都以相同概率选择“直线逼近”或“螺旋逼近”这种随机切换让算法不会只朝一个方向死钻。3.3 收敛曲线和统计图怎么画跑完数据之后画图是最容易出效果的环节也是最容易画错的环节。收敛曲线我强烈建议用 semilogy 画对数纵轴因为很多函数的最优值跨越好几个数量级比如从1e2降到1e-8用线性纵轴你只能看到一条直直的线贴在x轴上毫无区分度。改成对数纵轴后每条算法的下降过程一清二楚。注意记录历史时要从第一次迭代就开始记不能漏掉初始化那一步否则第一条曲线会缺一大截。除了收敛曲线盒须图是必须有的。把每种算法30次独立运行的最优值画成盒须图开放者的“稳定性”比“最好值”更直观。比如某个算法偶尔能跑到1e-10但大部分时候都在1e-2盒须图会立刻暴露这个问题。最后再加一个Friedman排序的小表格计算出每种算法在所有基准函数上的平均排名这个表放进论文里含金量很高。4. 实测中的表现与规律4.1 先说结果没有任何算法是“全能的”跑了完整实验之后我得到的最重要结论是在不同函数上排名会大幅变化不存在一个算法在所有函数上都碾压别人。单峰函数上PSO 和 GWO 的收敛速度通常排第一梯队因为它们的信息交互机制比较简单直接能快速逼近理论最优。WOA 和 HHO 稍微慢一点因为它们在迭代前期花了大量精力在探索上。这很正常捕食类算法天生习惯先“找猎物”再“吃猎物”。多峰函数上是重头戏。Rastrigin 这类函数密密麻麻全是局部最优点PSO 和 GWO 容易陷进去出不来。反而是 SCA、CGO、HHO 这类带“周期性扰动”或“动态策略切换”的算法表现更好。SCA 的正弦余弦波动天然具备震荡逃离局部最优的能力HHO 的逃逸能量E机制让它在不同阶段选择软围攻或硬围攻本质上是对探索和开发进行了动态调节。CGO 在部分高维问题上表现很惊艳但它的实现细节对结果影响极大。不同文献里对“投影策略”“边界处理”的写法差异可能导致性能差出好几倍。如果你要用 CGO 作为对比算法一定要在论文里写清楚自己采纳的是哪一版更新规则。4.2 驯服不收敛的算法实验中我发现一个高频问题某算法的收敛曲线在迭代中期突然变平然后跳到另一个数量级再变平。这种“阶梯状收敛”说明算法在反复重启搜索方向资源被大量浪费。最典型的例子是 WOA。当种群过于集中时A 的随机性会让多数个体在最优位置附近来回震荡而不是继续逼近最优。我的解决思路是给鲸鱼算法加一个“边界惩罚”或“越界重置”逻辑让飞出搜索范围的个体被重新随机初始化既能维持种群多样性又能让那些困在局部极值区的个体获得重新起飞的机会。SSA 樨鞘群算法也会出现类似问题但原因不同。它的追随者完全追随前一个个体一旦领头者被困整条链都会停在原地。这时候把追随者的更新方程里加入随机扰动项效果立竿见影。这也是很多改进版SSA论文的核心创新点你自己动手改一遍才明白为什么大家都要改。4.3 高维扩展性的明显分水岭我还观察到一个规律当维度上升到50维甚至100维时算法之间会明显分化。SCA 和 CGO 在高维下依然能保持探索能力但收敛缓慢PSO、GWO 收敛速率下降不多但容易早熟CSA 受意识概率 AP 的影响变得极其敏感AP 稍大一点整个种群就变成随机游走AP 稍小一点又变成一起扎堆。这就引出一个实验设计建议如果你的实际工程问题是高维的对比实验里必须加上高维基准测试不能只跑30维。很多论文只报30维结果然后声称算法适合高维优化这是站不住脚的。5. 常见问题与调试实录5.1 维度不匹配和矩阵广播用 Matlab 写群体智能算法90% 的报错都来自矩阵维度不匹配。核心规则是种群矩阵的维度是pop_size × dim每一行是一个个体目标函数输入是一行向量输出是一个标量。我见过的典型错误是更新位置时写成了x x v其中 x 是pop_size × dim矩阵v 是dim × 1列向量Matlab 会进入隐式广播结果数值完全错乱。建议在算法内部第一次迭代开始前加一行断言assert(all(size(x) [pop_size, dim]), 种群维度错误);调试效率能提升一半。5.2 收敛曲线一直是平的如果某算法跑出来的收敛曲线从头到尾没有下降先别怀疑算法本身先查边界处理。最常见的情况是种群初始化后部分个体越出边界而你的目标函数在界外返回了巨大值导致这个个体的适应度很差但它又一直参与最优值更新把整个种群都“带偏”了。我常用的边界处理很简单越界个体直接拉回边界x min(max(x, lb), ub);这种做法会被明确提出叫“边界吸收”。注意不同算法最好统一使用同一种边界处理方式否则对比实验又会引入一个不公平变量。5.3 结果复现不了今天跑出一个结果明天再跑另一个数这是最常见的问题。原因基本都出在随机种子没有管理好。我的做法是在实验启动脚本里设置总种子rng(42);然后每个独立运行批次重新设置for k 1:30 rng(42 k); % 运行9种算法 end这样每次跑实验第 k 次独立运行拿到的随机序列完全一致任何人复现你论文数据时用同一个种子就能得到一模一样的结果。5.4 对比数据表格怎么造最后补一句实验结果整理成表格时最优值用均值 ± 标准差表示并加粗每行最优值。排名列用 Friedman 平均序值。这样审稿人或你的同事一眼就能看出差异显著性而不用自己手动翻曲线图。避坑提醒别只报“最好值”不报“平均值和方差”。单次最好值说明不了问题它可能只是某次运气好的随机结果。平均值和方差才是算法稳定性的硬指标。最后再说点个人体会这套9算法对比框架我前后用了接近三个月才打磨到自己满意。最初版本只用了2个测试函数、10次独立运行根本看不出算法之间的真实差距直到把基准函数扩到6个、独立运行扩到30次、统一随机种子之后实验结论才变得稳定可信。如果你现在正打算做类似的工作我建议不要一次性把9个算法全部写完而是先从 PSO 和 GWO 这两个最简单的入手把统一接口、边界处理、收敛曲线画图这些“地基”打好再逐步加入 WOA、HHO、SSA、TSO最后再加 CGO、SCA 和 CSA。每加一个算法就把前面全部算法重新跑一遍确保没有引入新的 bug。以后再扩展新算法时只需要按照同样的接口规范写一个新函数整个统计流程一秒钟都不用改。这套框架不仅省时间更重要的是它能让你把真正的精力放在分析算法行为上而不是浪费在无尽的代码调试上。