改进蜣螂优化算法(TDBO)和四种对比算法的Matlab程序,是我去年做了一个月的算法实验后沉淀下来的一套完整代码。当时课题需要在一批新型元启发式算法里选一个做改进,最后落在了蜣螂优化算法(Dung Beetle Optimizer, DBO)上,做完之后把改进版命名为TDBO,流程跑完发现效果确实比原始版本有明显提升,尤其是中后期收敛精度和跳出局部最优的能力。这里把整套思路和程序实现整理出来,给正在做智能优化算法方向、需要跑对比实验的读者一个参考。
这套Matlab程序解决的核心问题很直接:原始DBO在高维、多峰测试函数上容易早熟、收敛精度不稳定,通过改进策略提升综合寻优性能,再和四种主流算法在标准测试函数上做公平对比,输出收敛曲线、箱线图和统计数据。无论你是刚入门的本科生还是需要算法支撑的科研人员,这套程序都可以直接改参数、换函数、加算法模块来用。
1. 为什么盯上蜣螂算法:优化问题的“最后一公里”困境
智能优化算法这个领域,说到底是解决“没有梯度信息、搜索空间复杂、目标函数非凸”的一类优化问题。现实工程里的很多问题——路径规划、参数辨识、资源调度、结构优化——往往都是黑箱或者灰箱模型,传统梯度下降法根本无从下嘴。元启发式算法这几年很火,就是因为它们不依赖梯度,模拟自然界的某种行为机制来搜索解空间,适用范围非常宽。
蜣螂优化算法(DBO)是2022年底提出的一种群体智能算法,模拟的是蜣螂的滚球、跳舞、觅食、繁殖、偷窃等行为。这个算法的设计思路比较特别,它把种群分成了几个不同角色,不同角色执行不同的位置更新策略。滚球蜣螂负责全局探索,跳舞蜣螂在遇到障碍时调整方向,繁殖蜣螂在局部区域深耕,偷窃蜣螂则会抢夺其他个体的食物。这种多样化的行为分工,理论上比单一策略的算法更有优势。
我实际跑下来,原始DBO在某些低维单峰函数上表现确实不错,收敛速度快,计算代价也低。但是在CEC系列的高维测试函数、尤其是多峰函数上,问题就暴露了:种群多样性下降太快,后期几乎所有个体都聚集在局部最优附近,跳不出去。另外原始算法的参数对问题规模比较敏感,同样一组参数,在10维问题上效果不错,挪到30维就明显退化。
这也好理解,蜣螂算法的位置更新规则里,繁殖蜣螂和偷窃蜣螂的搜索范围受到边界限制,在搜索后期会快速收缩。如果你设计的改进策略不能让种群在后期保持足够的活力,算法就会锁定在局部最优点。
我的改进目标很明确:在不显著增加计算量的前提下,解决DBO的多样性流失问题。具体做了三件事——用Tent混沌映射改善初始种群质量,引入自适应t分布变异增强跳出局部最优的能力,再叠加动态螺旋搜索策略让算法在探索和开发之间找到更好的平衡。这套组合下来,算法在高维多峰函数上的表现比原始DBO稳了不少。
2. TDBO三大改进策略的设计逻辑与原理推演
2.1 Tent混沌映射初始化:从“随机撒点”到“均匀布点”
原始DBO和其他很多元启发式算法一样,初始化阶段用的是均匀随机数生成种群。这个方法的问题在于:随机生成的点在分布上往往不理想,有的区域密度过高,有的区域几乎是空的,尤其在高维空间,随机撒点的覆盖率差得很远。初始种群的质量直接决定了算法前期搜索的效率,如果初始解的覆盖不够,算法很容易在某个偏颇的区域里打转。
Tent混沌映射的核心价值在于能够在搜索空间内生成分布更均匀、相关性更低的初始解序列。相比Logistic混沌映射,Tent映射的均匀性更好,遍历速度也更快。它的数学表达式很简单:
x(n+1) = 2x(n), 当 0 ≤ x(n) < 0.5
x(n+1) = 2(1 - x(n)), 当 0.5 ≤ x(n) ≤ 1
这里有个细节要注意:Tent映射在迭代过程中可能会落入不动点(比如0、0.25、0.5这些点),处理方法是添加一个扰动项,或者检测到周期循环时重新随机生成。实际代码里我加了一个小随机扰动来打破这种困境,实测下来能有效避免混沌序列退化。
用Tent混沌映射替换随机初始化之后,种群在搜索空间的分布更均匀,算法前期的探索效率会有明显提升。这是TDBO改进的第一步,也是后续策略能够发挥作用的基础。
2.2 自适应t分布变异:让算法“困不住”
t分布是概率论中的一个经典分布,它的形状受自由度参数控制。自由度越小,分布的两尾越厚;自由度越大,越接近标准正态分布。这个特性用来做变异操作非常合适——迭代前期自由度小,变异步长大,有利于全局探索;迭代后期自由度变大,变异步长缩小,有利于局部精细搜索。
我采用的策略是让t分布的自由度参数随迭代次数自适应调整。具体算法是:在每次迭代中,对每个个体的位置以一定概率施加t分布变异,变异公式为:
X_new = X + t(iter) * X
其中t(iter)是服从自由度为iter的t分布随机数。迭代早期iter较小,t分布尾部厚,产生大尺度扰动的概率高,有助于跳出局部最优;迭代后期iter较大,t分布趋近正态分布,扰动幅度变小,有助于精细收敛。
这个策略对原始DBO的改进效果很明显,尤其是在多峰函数上。原始DBO在迭代中后期种群容易凝聚在局部最优附近,t分布变异相当于定期给种群“注入扰动”,让陷入局部最优的个体有机会跳出来重新搜索。不过变异概率不能设置太高,否则会破坏正常的收敛节奏。我在程序里默认设的是0.3,实际测试中这个值在多数测试函数上表现比较平衡。
2.3 动态螺旋搜索策略:探索和开发的平衡术
whale algorithm里的螺旋更新机制给我留下了很深的印象,这种搜索方式能在当前最优解附近保持一种螺旋式的收敛趋势。在TDBO里,我把类似的思想引入蜣螂算法的偷窃蜣螂位置更新阶段,设计了一种动态螺旋搜索策略。
标准螺旋更新是根据当前最优位置与个体位置之间的距离,施加一个螺旋形的衰减系数。我在这个基础上加了一个动态权重,让螺旋幅度随迭代次数递减。这样算法前期螺旋半径大,可以探索更大的区域,后期螺旋半径缩小,收敛到最优解附近。
位置更新公式大致为:
X_new = X_best + r * exp(a * l) * cos(2πl) * |X_best - X|
其中动态因子r随迭代次数线性递减。引入这个策略之后,TDBO的收敛曲线在中后期不再像原始DBO那样平坦,而是持续有下降趋势,说明算法在后期仍有持续的寻优能力。
三个策略的组合逻辑是:Tent混沌初始化解决“起步问题”,t分布变异解决“卡住问题”,螺旋搜索解决“收敛问题”。三个策略的侧重点不同,相互之间没有冲突,整体上形成了从初始化到迭代中后期的完整改进链条。
3. Matlab程序架构与核心代码实现
3.1 程序文件组织
整套Matlab程序我按模块化思路组织,核心文件包括:
TDBO.m:主算法实现,传入目标函数、维度和参数设置,返回最优解和收敛曲线DBO.m、PSO.m、GWO.m、WOA.m:四种对比算法实现main_run.m:实验主程序,统一设置参数、调用各算法、收集结果test_functions.m:测试函数集,包含Sphere、Rastrigin、Griewank、Ackley、Rosenbrock等经典函数plot_results.m:绘制收敛曲线对比图和箱线图stat_results.m:统计各算法多次运行的均值、标准差
模块化的好处是对比实验最容易出问题的地方是各算法的输入输出接口不统一,统一接口后整个实验流程好维护得多。每个算法文件都保持同样的函数签名:
function [Best_pos, Best_score, Convergence_curve] = TDBO(SearchAgents_no, Max_iteration, lb, ub, dim, fobj)这样在main_run.m里调用时只需替换函数名,其他逻辑完全复用,整个实验流程非常清晰。
3.2 三个改进模块的代码实现
Tent混沌映射初始化函数:
function Positions = Tent_init(SearchAgents_no, dim, lb, ub) % Tent混沌映射初始化种群 Positions = zeros(SearchAgents_no, dim); for i = 1:SearchAgents_no x = rand(1, dim); for j = 1:dim if x(j) < 0.5 x(j) = 2 * x(j); else x(j) = 2 * (1 - x(j)); end if x(j) < 0.05 || x(j) > 0.95 x(j) = rand; end end Positions(i, :) = lb + x .* (ub - lb); end end这段代码里的防退化判断很关键。Tent映射迭代过程中,如果值落入边界区域,就容易陷入周期循环,破坏混沌特性。加一个小扰动可以打破这种周期,保证序列的遍历性。
自适应t分布变异模块:
function Positions = t_variation(Positions, iter, SearchAgents_no, dim, lb, ub, p_mutation) % 自适应t分布变异 for i = 1:SearchAgents_no if rand < p_mutation % 自由度随迭代次数增加,t分布逐步接近正态分布 dof = max(iter, 1); % 生成t分布随机数 t_rand = trnd(dof, 1, dim); % 变异 Positions(i, :) = Positions(i, :) + t_rand .* Positions(i, :); % 边界处理 Positions(i, :) = min(max(Positions(i, :), lb), ub); end end endtrnd是Matlab自带的t分布随机数生成函数,自由度非整数时会自动插值处理,这一点很方便。边界处理后要保证变异后的个体不会超出搜索空间。
动态螺旋搜索模块:
function Positions = spiral_search(Positions, Best_pos, iter, Max_iteration, dim, lb, ub, num_steal) % 动态螺旋搜索更新偷窃蜣螂 r = 1 - iter / Max_iteration; % 动态衰减因子 for i = 1:num_steal l = 2 * rand - 1; a = 1; % 螺旋搜索 dist = abs(Best_pos - Positions(i, :)); Positions(i, :) = Best_pos + r * exp(a * l) * cos(2 * pi * l) * dist; % 边界处理 Positions(i, :) = min(max(Positions(i, :), lb), ub); end end动态因子r把螺旋的搜索范围从大慢慢缩小到小,这个“由粗到细”的思路在很多算法里被证明是有效的。
完整TDBO主函数里,我按原始DBO的逻辑框架,把上述三个模块嵌入对应阶段:Tent初始化在算法开头,t分布变异在每次迭代的末尾,螺旋搜索替换原偷窃蜣螂更新。完整代码比较长,这里不多贴,但核心框架如下:
function [Best_pos, Best_score, Convergence_curve] = TDBO(SearchAgents_no, Max_iteration, lb, ub, dim, fobj) % 初始化种群和参数 Positions = Tent_init(SearchAgents_no, dim, lb, ub); % ... 计算适应度,确定最优解等 for iter = 1:Max_iteration % 1. 滚球蜣螂更新 % 2. 繁殖蜣螂更新 % 3. 小蜣螂觅食更新 % 4. 偷窃蜣螂更新,使用spiral_search % 5. 全局自适应t分布变异 % 6. 更新最优解 end end3.3 核心参数设置与选择
我在这套程序里默认的参数设置如下:
| 参数 | TDBO | DBO | PSO | GWO | WOA |
|---|---|---|---|---|---|
| 种群数 | 30 | 30 | 30 | 30 | 30 |
| 最大迭代 | 500 | 500 | 500 | 500 | 500 |
| 变异概率 | 0.3 | - | - | - | - |
| 初始自由度 | 1 | - | - | - | - |
| c1(学习因子) | - | - | 1.5 | - | - |
| c2(学习因子) | - | - | 1.5 | - | - |
| 惯性权重ω | - | - | 0.9→0.4 | - | - |
| a(收敛因子) | - | - | - | 2→0 | - |
| b(螺旋常数) | - | - | - | - | 1 |
对比实验的公平性关键就在这里:所有算法的种群数、迭代次数、测试函数、边界条件完全一致,唯一的不同是算法本身的更新策略。这样得出的差异才能归因于算法设计,而不是实验设置的不公平。
4. 四种对比算法怎么选:基准设计决定结论可信度
4.1 选择DBO、PSO、GWO、WOA的逻辑
对比算法的选择不是随机的。我选了四类有代表性的算法:
- DBO(蜣螂优化算法):必须对比,这是改进算法的基线版本,用来验证改进策略是否有效。如果TDBO连原始DBO都打不过,那改进就是不成立的。
- PSO(粒子群算法):经典中的经典,1995年提出,几乎所有算法论文都要跟它比。PSO的优点是实现简单、收敛快,但容易早熟。它代表的是“经典群智能算法”这一类别。
- GWO(灰狼优化算法):2014年提出的算法,结构清晰,参数少,收敛性能优秀,是近年来对比实验中出镜率很高的一种。它和DBO同属“模拟动物行为”的元启发式算法,对比起来有参照价值。
- WOA(鲸鱼优化算法):2016年提出的算法,螺旋更新机制是它的标志性操作。TDBO里引入了螺旋搜索,跟WOA对比可以检验这一步改进是否有足够竞争力。
这四个算法覆盖了不同时期、不同机制的优化算法,既有经典算法也有新型算法,对比结果的说服力比只跟一两个算法比要强得多。
4.2 测试函数的选取思路
测试函数我选了5个经典函数,覆盖不同类型的问题特征:
| 函数名 | 类型 | 维度 | 搜索范围 | 理论最优值 |
|---|---|---|---|---|
| Sphere | 单峰 | 30 | [-100, 100] | 0 |
| Rosenbrock | 单峰但非凸 | 30 | [-30, 30] | 0 |
| Rastrigin | 多峰 | 30 | [-5.12, 5.12] | 0 |
| Griewank | 多峰 | 30 | [-600, 600] | 0 |
| Ackley | 多峰 | 30 | [-32, 32] | 0 |
单峰函数测试算法的收敛速度和精度,多峰函数测试算法的全局搜索能力和跳出局部最优的能力。Rosenbrock虽然只有一个全局最优,但它的最优解位于一条狭长的抛物线山谷里,算法很容易在谷中震荡,是检验精细搜索能力的好函数。
4.3 统计评价指标的设定
单次运行的结果有随机性,不能说明问题。我在程序里设置每个算法在每个函数上独立运行30次(这个次数在统计上是比较可靠的),每次运行记录收敛值,最后汇总统计。
评价指标有三个:
- 平均值:30次运行的最优适应度平均值,反映算法的整体寻优精度。
- 标准差:30次运行结果的标准差,反映算法的稳定性。
- 最优值/最差值:记录最好情况和最差情况,观察算法的鲁棒性边界。
四个对比算法加上TDBO,一共是5个算法、5个测试函数、每个跑30次,总共750次独立运行。这个计算量在Matlab里大概是几分钟到十几分钟,取决于电脑配置和函数复杂度,属于可接受的实验成本。
4.4 Wilcoxon秩和检验:统计显著性的最后防线
对于学术论文或者工程报告,只看平均值和标准差还不够。两个算法的平均值有差距,可能只是随机波动造成的。我在这套程序里专门写了一段Wilcoxon秩和检验的代码,用来判断TDBO和其他算法之间的差异是否具有统计显著性。
Wilcoxon秩和检验是一种非参数检验方法,不需要假设数据服从正态分布,特别适合算法对比这类场景。程序运行后会输出一个显著性矩阵,p值小于0.05说明两个算法的差异具有统计显著性,也就意味着TDBO的优势不是偶然的。
5. 从仿真结果看:收敛曲线和箱线图该怎么解读
5.1 典型收敛曲线的分析角度
程序运行完成后,plot_results.m会生成每个测试函数上5条收敛曲线的对比图。在看这些图的时候,我自己的经验是重点关注三个阶段:
第一个阶段是前50次迭代,看算法的起始点在哪里、前期下降速度如何。TDBO用Tent混沌初始化后,前期适应度通常比其他算法低,这说明初始种群的质量优势直接体现在了起点上。
第二个阶段是100到300次迭代,看曲线的下降斜率。如果曲线在这个阶段出现明显的平台期,说明算法陷入了局部最优、或者说种群多样性不足。TDBO因为有t分布变异和螺旋搜索的加持,在这个阶段通常能保持持续下降的趋势。
第三个阶段是最后100次迭代,看最终收敛精度和曲线的稳定性。一个优秀的算法在后期应该平滑逼近最优解,不应该出现大的波动。TDBO的螺旋搜索动态衰减因子保证了后期扰动逐步减小,所以收敛曲线后期很平滑。
在Rastrigin函数上,TDBO的收敛曲线明显低于原始DBO,而且波动更小,这说明改进策略确实解决了原始DBO早熟的问题。
5.2 数值表格怎么呈现实力差距
统计结果会以表格形式输出,像这样:
| 算法 | Sphere均值 | Sphere标准差 | Rastrigin均值 | Rastrigin标准差 |
|---|---|---|---|---|
| TDBO | 2.31e-30 | 4.52e-30 | 0 | 0 |
| DBO | 5.87e-18 | 3.21e-17 | 12.43 | 5.67 |
| PSO | 1.23e-04 | 3.14e-04 | 31.76 | 10.23 |
| GWO | 4.56e-28 | 7.23e-28 | 1.57 | 2.13 |
| WOA | 8.92e-32 | 5.11e-31 | 0 | 0 |
看这个表格,TDBO在Sphere函数上的表现不如WOA,但在Rastrigin函数上就追平了WOA。这说明不同算法在不同函数上的表现是有差异的,没有一种算法能够统治所有函数。这也是算法对比实验中最常见的结论——改进算法在某些函数上占优,在其他函数上可能打平或略逊一筹。
看标准差的时候要特别注意:均值很小但标准差很大的情况,说明算法偶尔能收敛得很好、偶尔收敛得很差,稳定性不足。TDBO改进的方向之一就是减小标准差,提高稳定性。
5.3 箱线图揭示的分布特征
箱线图是展示30次运行结果分布的最好方式。它能直观反映中位数、四分位距、异常值等信息。我在程序里用boxplot函数生成了每个测试函数上5个算法的箱线图。
看箱线图的要点是看箱体的位置和高度。箱体位置越低说明收敛精度越高,箱体高度越矮说明结果越集中、越稳定。TDBO的箱线图在多数函数上表现是:箱体位置是最低的,箱体高度也比较窄,上下须很短。这说明多次运行的结果都比较稳定地落在很小的区间内,这是算法可靠性好的体现。
如果某个算法的箱线图出现很长的上下须或者孤立的异常值点,说明这个算法在某些随机种子下会跳出很好的结果、也会陷入很差的结果,稳定性不够。
5.4 多目标视角下的性能权衡
我在实验中也做了一些归一化加权分析,把多个测试函数的结果综合成一个性能得分。这么做的好处是能给算法一个整体评分,方便做最终决策。
具体做法是:首先把每个算法在每个函数上的结果归一化到[0,1]区间,然后对同一个算法在不同函数上的归一化得分求平均。这个综合得分可以看作算法在所有测试问题上的平均表现。TDBO在我做的实验中综合得分排第一,但和WOA的差距并不大,说明两者的整体性能在伯仲之间。
从实用角度说,如果你的工程问题偏向多峰、需要全局搜索能力强的算法,TDBO有明显优势;如果是平滑的单峰问题、追求极致的收敛速度,WOA可能更快。这也是为什么对比实验的设计一定要包含不同类型的测试函数。
6. 跑通程序后必看的调试经验和参数调优
6.1 常见报错和排查思路
我在写这套程序的过程中踩过不少坑,这里列几个最常见的:
混沌序列退化问题。没用扰动项的Tent映射跑了50次迭代后,种群多样性骤降,初始化基本退化成只覆盖几个点。排查方法是打印初始种群的坐标分布,一眼就能看出来。解决办法就是代码里加的那个边界判断和随机扰动。
t分布随机数溢出。trnd在自由度极低(比如0.01)时会生成绝对值非常大的随机数,变异后个体直接飞出边界。这里要确保自由度不低于1,并且变异后做边界截断。
边界处理不一致。同一个程序里,不同模块用不同方式处理越界粒子(有的重生成、有的截断、有的镜像反射),会导致结果不稳定。我最终统一用截断法,简单可靠,收敛也不受影响。
随机数种子问题。第一次跑的时候不设置随机数种子,每次结果差异很大,看起来像是算法不稳定。我加了rng('default')和多种子策略之后,结果就稳定了。对比实验里,建议固定随机数种子以便复现。
6.2 参数敏感性分析
TDBO新增的参数主要是变异概率p_mutation和动态螺旋衰减因子。我做了简单参数扫描实验:
- p_mutation = 0.1:几乎看不出改进效果,变异太稀疏,种群还是很快陷入局部最优。
- p_mutation = 0.5:后期收敛精度下降,变异过度破坏了正常搜索节奏。
- p_mutation = 0.3:在多数测试函数上表现最优。
不同测试函数的最优变异概率其实不完全一样,但0.3这个值在综合表现上最平衡。如果你自己用的时候发现算法收敛不好,可以优先调这个参数,在0.2到0.4之间搜索。
自由度初始值我设定为1,就是因为t分布在自由度等于1时就是标准的柯西分布,尾部最厚,跳出能力最强。如果你更看重后期收敛精度,可以把自由度初始值设大一些。
6.3 从仿真到实际工程应用的延伸思路
测试函数跑通了,只是第一步。实际工程优化问题和标准测试函数最大的区别在于:目标函数计算代价高、约束条件复杂、变量之间可能存在耦合。
用这套TDBO程序做实际工程问题时,有几个可以扩展的方向:
一个是在适应度计算上做并行化。如果目标函数是仿真耗时代价很高的模型,可以用Matlab的parfor并行计算,种群30个个体分配在多核上并行评估,运行时间可以压缩数倍。
另一个是在约束处理上增强。标准测试函数都是无约束问题,但工程优化几乎都有约束。可以在适应度函数里加罚函数项,把约束违反量映射成惩罚值,这样算法就能在无约束框架下求解带约束的问题。
此外,如果是大规模高维问题(比如500维以上),TDBO的迭代速度会明显变慢,这时候需要结合问题分解策略,把高维问题拆分成多个低维子问题分别优化。这是我目前正在做的方向——把TDBO扩展到大规模优化和动态优化场景中。
6.4 关于算法改进的一些实话
做算法改进实验,最忌讳的就是把调参带来的提升当成算法设计的成果。我在最初测试TDBO时,曾经为了在某几个函数上好看而调整了参数,结果换一组测试函数就露馅了。后来我统一了所有函数上的参数设置,不允许针对特定函数调参,对比结果才真正可信。
还有一点,改进策略并不是越多越好。我也试过把重心反向学习、差分进化变异、自适应权重等一堆策略全都塞进TDBO,结果算法运行时间翻了三倍,寻优精度提升却不到5%,得不偿失。改进算法的核心是理解原始算法的缺陷,对症下药。
最后再分享一个小技巧:在使用这套程序时,建议先用单峰函数(如Sphere)验证算法的收敛能力,再用多峰函数(如Rastrigin、Ackley)验证全局搜索能力。如果一个改进算法在多峰函数上表现很好、但在单峰函数上反而退化,说明改进策略引入的扰动过大,需要调低变异概率。我自己在调TDBO时就是按照这个顺序来测试的,能快速定位问题出在哪个环节。