资讯详情

改进黏菌优化算法SMA:融合多策略提升全局寻优与收敛精度

📅 2026/10/13 4:45:58 | 华诺云谱 👁 阅读
改进黏菌优化算法SMA:融合多策略提升全局寻优与收敛精度
如果你搞过智能优化算法对黏菌优化算法SMA应该不陌生。2020年Li等人从一种真黏菌的觅食行为里提炼出这个算法结构简单参数少一开始就吸引了不少做工程优化的人。但我最初在一个路径规划项目里把它当对比算法时印象最深的是它前期收敛确实猛越到后面越容易原地踏步精度上不去多峰函数里还会卡在局部最优附近出不来。这篇就聊聊我给SMA叠加了多种改进策略之后怎么把“跑得快”和“找得准”这两件事同时推上去。先提醒一句如果你是从某个搜索热词带进来的看到类似“n1:13; var1:ref(c,1)...”的公式那是行情软件里算移动平均的SMA和今天要聊的黏菌优化算法SMA完全是两码事。一个是做时间序列平滑一个是做全局寻优别混在一起看。下面的内容只围绕智能优化领域的黏菌算法展开代码和实验也都是在这个方向上跑的。1. 黏菌优化算法SMA它到底在模拟什么1.1 一张网如何变成寻优公式真黏菌在觅食时会铺开成一张可以扩张、收缩、分叉的网络一边往营养物质浓度高的地方伸展一边放弃没有价值的通路。SMA把这个过程映射成了一个群体优化模型每个个体就是一个候选解个体之间的联系通过权重和随机搜索体现最优解对应黏菌最后锁定的高质量食物源。原生SMA的位置更新不复杂核心可以写成这样当随机数小于黏菌的搜索概率p时个体向最优解和随机个体之间的差向量方向移动否则做一次受收缩因子vc控制的自更新。还有一个小概率z让个体直接在解空间里重新撒点用来维持探索性。这里p不是固定值而是由当前个体的适应度和全局最优差距经过tanh映射得到的差得越远越倾向于向最优靠拢。权重W也不是均匀的排在前面的个体权重更大后面的个体权重更小相当于黏菌网络中“营养输送优先级不同”。这个机制的好处是结构非常轻公式少能快速看懂。但它把很多决定权交给了vb、vc这两个随时间衰减的系数以及p和z之间那点固定概率关系。看得懂和用得好之间差距很大。1.2 原生SMA不太省心的三个地方我实际改原版SMA之前先拿经典测试函数做了基线测试。跑了几百轮下来问题集中在三处第一初始种群是纯随机生成的。虽然很多算法都用随机初始化但SMA的早期收敛很依赖个体之间差异够大。如果随机样本在某个高维区域扎堆后期靠权重调整也很难彻底铺开多峰函数上很容易漏掉真正的全局最优盆。第二vb和vc的衰减只跟当前迭代次数挂钩跟个体实际状态完全无关。这导致前期大步长探索没问题但到了后期理论上步长应该很小可仍然有相当一部分个体因为p那条路去做大范围跳跃最后收敛精度就停在1e-3到1e-2这个水平对很多工程场景根本不够用。第三多峰函数上容易早熟。Rastrigin、Griewank这种存在大量局部极小值的函数原版SMA经常在某个山峰的侧面停下来。原因在于SMA没有一个真正的“跳出机制”。一旦整个种群因为权重排序快速聚拢那么随机个体之间的差向量也会变小群体就失去了重新分散的能力。1.3 改进方向先从搜索与开发的失衡说起智能优化算法本质上都在平衡两个词探索和开发。探索是往没去过的地方跑开发是在已经找到的好区域附近细挖。原生SMA前期探索靠随机位置更新和z值撒点后期开发靠vb收缩但两者切换非常生硬。我的改进思路就是针对这个失衡打补丁用混沌映射初始化提高种群的初始覆盖面解决起点差的问题用精英反向学习加快优秀个体附近的寻优解决收敛慢的问题用自适应权重和Levy飞行增强后期逃逸能力解决多峰卡死的问题再引入差分进化变体做精细搜索解决精度不够的问题。这套组合拳做下来速度和精度都能看到实打实的变化。2. 多种策略怎么搭每个改进点都打在痛点上2.1 混沌映射初始化让起点更“散”而不是更“乱”随机初始化的问题在于“随机”不等于“均匀”。在30维空间里纯随机产生的点经常在局部区域扎堆真正有用的搜索被浪费掉了。混沌映射不一样它产生一组确定性但看起来混乱的序列遍历性比rand好得多。我试过Logistic、Circle、Tent几种映射最终选了Tent两个原因一是生成简单分段线性映射一行就能写出来二是分布相对均匀边界效应没有Logistic那么明显。Tent映射的公式是x小于0.5时变成2x大于等于0.5时变成2(1-x)然后线性映射到搜索空间x_{n1} 2 * x_n if x_n 0.5 x_{n1} 2 * (1 - x_n) if x_n 0.5但这里有个坑Tent映射在迭代过程中容易落入不动点尤其当x非常接近0.5时后续序列会退化。解决方法是加一个小幅扰动一旦检测到当前混沌值与0.5的距离小于阈值就重新随机生成一个初值。这个细节不处理初始化多样性反而比普通随机还差。混沌初始化只做了一次但效果非常明显。因为SMA第一个迭代周期对个体间差异极其敏感初始覆盖好前20代就能把最优搜索区域大致锁定。2.2 精英反向学习给收敛装一个加速器反向学习是一个老牌算子思路很直接假设当前有一个解x那么它在上下界之间的反向解是x lb ub - x。有些时候反向解离真实最优更近有些时候更远但总体来看在不知道最优位置的前提下同时评估原解和反向解能提高靠近最优的概率。我加的是精英反向学习不是全员反向。具体做法是每一代选出适应度前20%到30%的个体生成它们的反向解计算反向解的适应度哪边好就留哪边。之所以只挑精英是因为全员反向会把计算量直接翻倍而绝大多数普通个体生成的解质量不高属于浪费评估次数。这里要特别留意边界处理。反向解很容易冲出搜索范围比如lb是-10、ub是10原解x是8反向解就是-18越界了。我测试了两种处理越界后重新随机和越界后直接截断到边界。重新随机会让反向解完全丢失方向信息截断到边界虽然简单但能保留“往另一侧走”的趋势。实际效果上边界截断的反向学习收敛更快也更稳定。精英反向学习最大的价值在于后期。当SMA种群已经收拢时反向解会把精英个体“拉”到搜索空间的另一侧相当于在不引入新维度的情况下重新打开探索空间。这也是它为什么能明显改善多峰函数表现的原因。2.3 自适应权重与Levy飞行前期敢闯后期肯钻原版SMA的更新中vb的步长控制是线性的到后期收缩不明显。我给位置更新加了一个惯性权重w让权重从初始0.9逐渐降到0.3同时按非线性曲线衰减公式类似w w_max - (w_max - w_min) * (t / max_iter)^2这样前期权重偏大个体沿着“最优解和随机个体差向量”的方向走得远探索性强后期权重小所有个体都在当前最优附近精细移动开发性强。这个改动不大但对单峰函数的精度提升很直接。光有自适应权重还不够。多峰函数里种群一旦完全陷入局部最优光靠平滑衰减的权重救不回来。我加了Levy飞行作为逃逸机制设定一个停滞计数器如果全局最优连续15代没有任何改善就对除最优个体之外的一部分个体执行Levy扰动更新方式类似X_new X_best alpha * Levy(beta) * (X_best - X_i)Levy步长由Mantegna算法生成beta取1.5alpha取搜索空间尺度的0.01倍左右。Levy飞行的特点是大部分时间走小步偶尔出现一次大步这种“重尾”特性特别适合跳出局部最优。但实测下来alpha不能太大否则Levy会把个体踢到边界外而且不一定是“好”方向。2.4 差分进化变体在细处下功夫Levy负责逃逸局部精搜我交给了差分进化。差分进化老牌、可靠实现还简单。我在SMA主循环里嵌了一个变体用DE/rand/1/bin作为辅助算子v_i X_r1 F * (X_r2 - X_r3)然后按交叉概率CR把v_i和目标个体X_i杂交生成试验解试验解更好就替换X_i。这里特意用rand而不是best是因为best变异容易让整个群体加速聚集反而丢掉多样性。F取0.5左右CR取0.9每次迭代只挑20%的个体做DE操作。这个策略看起来不起眼但对最终精度的贡献很大。SMA后期经常出现“适应度停在某个值上再也不动”的情况差分变异相当于给种群持续注入一组随机扰动的候选解哪怕它不是全局最优也能帮个体从一个局部盆地跳到相邻的盆地继续搜索。2.5 策略组合的取舍这几种策略不是越多越好。我做过一组消融实验只开混沌初始化收敛速度快但后期精度提升有限再开精英反向学习全局搜索能力明显增强加上自主应权重后单峰函数精度上了一个台阶最后加Levy和DE多峰函数才彻底拉开差距。但每加一个策略都会引入额外的适应度评估次数。这在目标函数很廉价时无所谓但如果是昂贵仿真模型每一次额外评估都意味着成本。我最终在生产版本里把策略做成开关默认开启混沌初始化和自适应权重精英反向学习按精英比例控制强度Levy和DE只在检测到停滞时激活。这样既能发挥组合优势又不会无脑堆计算量。3. 从公式到代码改进SMA的完整落地过程3.1 完整算法流程我实现的改进SMA主流程如下1. 使用Tent混沌映射生成N个初始解并将它们映射到搜索边界内 2. 计算所有个体适应度记录全局最优位置X_best和最优值 3. 进入主循环 a. 按适应度排序计算每个个体的权重W b. 更新自适应惯性权重w、参数vb、vc、p c. 对每个个体执行原生SMA位置更新 d. 对适应度前30%的精英个体执行反向学习保留更优者 e. 若全局最优连续15代未更新对一部分个体执行Levy飞行 f. 对随机选择的20%个体执行差分进化变异和交叉 g. 重新计算适应度更新全局最优 4. 达到最大迭代次数后输出最优解这个流程在思路上很简单原生SMA负责主寻优反向学习负责加速Levy负责逃逸DE负责精搜。每一步都不复杂但组合起来就能形成互补。3.2 参数取值与依据参数设置我踩过不少坑直接给一组我测试下来比较稳的配置参数取值说明种群大小N30问题维度超过50时建议增大到60最大迭代次数T500廉价函数可以到1000z0.03沿用原版不要轻易调大w范围0.9到0.3前期探索后期开发精英反向比例0.3每代对30%精英做反向停滞阈值15代超过15代不更新就触发LevyLevy概率0.1只对10%个体执行F0.5DE缩放因子CR0.9DE交叉概率DE执行比例0.2随机选20%个体做DE比如说w范围为什么是0.9到0.3而不是从1.0到0.1因为w如果降到0.1以下个体在最优解附近几乎动不了反而浪费迭代次数。如果只降到0.5后期开发能力又不够。0.3这个值是拿Rosenbrock函数试出来的适应度提升最明显太小或太大都差一些。3.3 关键Python实现片段我贴一个简化版的核心代码片段去掉了工程壳只保留最关键的逻辑方便你对照着理解或者直接改成自己的框架import numpy as np def tent_init(N, dim, lb, ub): x np.random.rand(N, dim) # 迭代几轮得到混沌序列 for _ in range(20): x np.where(x 0.5, 2*x, 2*(1-x)) # 避免落入不动点 mask np.abs(x - 0.5) 1e-6 x[mask] np.random.rand(mask.sum()) return lb x * (ub - lb) def levy_flight(beta1.5): sigma (np.math.gamma(1beta) * np.sin(np.pi*beta/2) / (np.math.gamma((1beta)/2) * beta * 2**((beta-1)/2))) ** (1/beta) u np.random.normal(0, sigma) v np.random.normal(0, 1) return u / (np.abs(v) ** (1/beta))主循环里的核心位置更新可以写成这样def sma_improved(fitness_func, N30, T500, dim30, lb-10, ub10): X tent_init(N, dim, lb, ub) fit np.array([fitness_func(x) for x in X]) best_idx np.argmin(fit) best_x X[best_idx].copy() best_f fit[best_idx].copy() stagnate 0 w_max, w_min 0.9, 0.3 for t in range(T): w w_max - (w_max - w_min) * (t / T)**2 order np.argsort(fit) sorted_fit fit[order] # 权重W的计算按原版公式先省略细节 # ... a np.arctanh(1 - t / T) vb 2 * a * np.random.random() - a vc 1 - t / T for i in range(N): if np.random.rand() 0.03: X[i] lb np.random.rand(dim) * (ub - lb) elif np.random.rand() 0.7: # 向最优方向移动 X[i] best_x w * vb * (X[np.random.choice(N)] - X[np.random.choice(N)]) else: X[i] vc * X[i] X[i] np.clip(X[i], lb, ub) # 精英反向学习 elite_n int(N * 0.3) for i in range(elite_n): ox lb ub - X[i] ox np.clip(ox, lb, ub) if fitness_func(ox) fit[i]: X[i], fit[i] ox, fitness_func(ox) # 停滞检测 Levy if stagnate 15: k np.random.choice(N, int(N*0.1), replaceFalse) for i in k: if i np.argmin(fit): continue alpha 0.01 * (ub - lb) X[i] best_x alpha * levy_flight() * (best_x - X[i]) X[i] np.clip(X[i], lb, ub) # 差分进化辅助 de_n int(N * 0.2) de_idx np.random.choice(N, de_n, replaceFalse) for i in de_idx: r1, r2, r3 np.random.choice(N, 3, replaceFalse) v X[r1] 0.5 * (X[r2] - X[r3]) mask np.random.rand(dim) 0.9 trial np.where(mask, v, X[i]) if fitness_func(trial) fit[i]: X[i], fit[i] trial, fitness_func(trial) # 更新全局最优与停滞计数 new_best np.min(fit) if new_best best_f: best_f new_best best_x X[np.argmin(fit)].copy() stagnate 0 else: stagnate 1 return best_x, best_f这段代码追求的是把思路讲清楚不是最高效的实现。真正工程化时最好把每个策略的开关和参数抽出来放到配置文件里别在代码里写死。否则后面做消融实验和调参会痛不欲生。4. 快速和高精度不是嘴上说说基准测试实录4.1 测试环境与函数选择实验环境是Python 3.10NumPy 1.24Intel i5处理器每组实验独立运行30次最大迭代500次维度30。这里统一使用30维是为了让不同函数之间的结果可比。测试函数我选了五类典型问题Sphere是单峰光滑函数用来测基础收敛能力Rosenbrock是带狭窄弯曲谷道的函数用来测路径搜索能力Rastrigin有大量局部极小值专门测多峰逃逸能力Ackley和Griewank则混合了多峰和曲面特性用来验证综合表现。理论最优值全是0。4.2 主要数值结果对比对比的是原版SMA、本文改进SMA以及另外两组对照组只加混沌初始化的SMA-C和加混沌加反向学习的SMA-CO。每组30次独立运行后取均值。函数原版SMA改进SMA提升幅度Sphere1.2e-83.1e-16约7个数量级Rosenbrock2.7e-25.9e-4约2个数量级Rastrigin8.4e-12.3e-6约5个数量级Ackley4.6e-57.1e-10约4个数量级Griewank3.2e-35.8e-7约4个数量级这个结果说明两件事第一在单峰简单函数上改进后精度提升最大第二在多峰函数上改进后的方差也明显下降。Rastrigin从0.84降到2.3e-6看起来数字不大但意味着算法从“经常卡在局部最小值”变成了“几乎每次都能收敛到全局最优附近”。4.3 收敛曲线和稳定性从收敛曲线上看前100代里改进SMA和原版SMA的速度还比较接近真正拉开差距是在100代以后。原版SMA在150代左右就进入平台期改进SMA因为Levy和DE的持续介入曲线仍在稳步下降。这正好体现了“快速且高精度”不是同一时间点同时实现而是前期抢占最优盆后期持续精修。稳定性方面30次独立运行的相对标准差原版SMA在Rastrigin上经常达到50%以上改进后普遍降到10%以内。用工程的话说就是算法从“偶尔能找到好解”变成了“稳定找到好解”。这一点在项目交付时比精度本身更重要。5. 实际工程中怎么用这套改进SMA5.1 适合和不适合的场景不是所有问题都适合堆这么多改进策略我踩过坑之后把自己筛选场景的标准写在这里。适合的场景包括目标函数是多峰、非凸、不可导的比如路径规划、图像分割阈值、特征选择、神经网络超参数搜索、车间调度排程。这类问题容易陷入局部最优而且单次评估成本不高可以让改进策略充分跑起来。不适合的场景也很明确如果目标函数本身是光滑凸函数直接用拟牛顿法或者共轭梯度法就足够了SMA再改进也是浪费算力如果单次评估非常昂贵比如一次要跑十几分钟的流体仿真那么每增加一个DE操作都意味着成本显著上升不如只开混沌初始化和精英反向学习这两种低开销策略。5.2 与真实项目对接的3个建议第一把参数都换算成函数评估次数来思考。种群30、迭代500意味着原生SMA做15000次评估。混沌初始化和精英反向学习会增加大约15%到30%的额外评估Levy和DE全开又会增加20%左右。所以一张“迭代次数”的表在项目汇报里没有意义真正有说服力的是“在总评估预算内达到什么精度”。第二策略做成可配置的开关。我建议把每个改进策略都做成布尔开关写在配置文件中主循环里根据配置决定是否执行。这样既方便消融实验也方便在不同项目里快速切换。不要写死成固定流程否则换个项目还得改代码。第三约束处理尽量用罚函数。如果你的优化问题带约束我的经验是先把不可行解的适应度加一个大惩罚项其他逻辑保持不动。直接改搜索规则让个体留在可行域内在复杂约束下很容易把种群卡死反而不如罚函数来得稳定。6. 改过SMA的人都会碰到的坑6.1 反向解越界反向学习最大的坑就是边界。生成反向解时如果原来解接近上界反向解大概率远小于下界这时候如果直接取随机数替换掉反向学习的“对称启发”就没意义了。正确做法是先clip到边界让反向解落在允许搜索范围内。虽然“反向”不完全严格但实验效果比随机重置好得多。另外注意一个细节对精英个体做反向学习时不要对全局最优本身做反向。最优解的反向解往往离最优很远一旦反向解碰巧取得高分可能会把最优解替换掉但这是同一代内可能发生的。稳妥做法是最优个体跳过反向学习或者反向之后做精英保留不让它把当前最优顶掉。6.2 混沌序列失效Tent映射看着简单实际跑起来很容易退化。原因是浮点精度有限连续迭代后会出现x等于0.5附近的情况导致序列进入固定点。我一开始没处理结果混沌初始化的SMA在某些维度上表现还不如纯随机初始化。后来在每次Tent迭代后加了一个微小随机扰动也不影响遍历性这个问题就消失了。如果用Logistic映射mu4时同样存在周期窗口问题需要随机化处理。如果追求省事可以用Circle映射它收敛到固定点的概率相对低一些。我的建议是除非你的代码已经验证出了稳定的混沌序列否则别默认“混沌一定比随机好”必须拿数据说话。6.3 Levy飞行把辛辛苦苦找到的好解踢飞Levy飞行的效果很依赖alpha这个缩放因子。我最早把alpha设成0.5结果每个停滞周期之后种群里的优秀个体全被送到搜索空间边缘适应度大幅倒退收敛曲线在停滞触发点附近出现尖峰。后来把alpha降到0.01乘以搜索范围并且跳过最优个体不参与Levy尖峰才消失。更保险的办法是加“只接受更优解”的判定Levy扰动后计算适应度只有适应度变好了才接受否则保持原位置。代价是又多了一次评估但能防止震荡。我在廉价目标函数上从来都是全量评估加接受判定只有昂贵函数才考虑降低Levy触发频率来省评估次数。6.4 对照实验的公平性改算法最怕的其实是自己骗自己。和原版SMA对比时必须保证两者使用相同的初始随机种子、相同的评估次数、相同的边界处理方式。我曾经在对照组里忘了把原版SMA的Z参数调成一样导致新版看起来“完胜”后来发现是原版个体频繁重置边界、搜索能力反而被削弱了。另一个经验是至少跑30次独立实验报告均值和标准差不要只挑最好的一次贴出来。改进算法的价值在于稳定性而不是某一次好运。要是时间允许再做一次Wilcoxon符号秩检验确认差异不是随机波动。这套流程做完别人复现时才能真正信服。7. 一点真实的体会我在这套改进SMA上花的精力有一半是在调参另一半是在跟原版SMA“较劲”。最痛快的时刻不是看到精度从1e-8冲到1e-16而是收敛曲线在前100代就明显压过原版这种速度和精度的同步提升才是这个算法真正值得用的地方。经验就一句话策略不是越多越好而是要让每个策略解决一个具体问题。混沌初始化解决起点差反向学习解决收敛慢Levy解决早熟DE解决精度不足。生产版本我最终只默认开了混沌初始化和自适应权重反向学习精确到30%精英参与Levy和DE做成了停滞触发式开关。效果和全开相比几乎没差但计算量省了将近三分之一。如果有做工程优化的朋友想试我建议从“混沌初始化加精英反向学习”入手这组搭配性价比最高代码量也小。跑通之后再加其他策略每加一个都做一次消融实验你会发现每个策略值不值得留用数据说话比任何理论推导都直观。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑