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

资讯详情

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

改进麻雀搜索算法原理与MATLAB实现:佳点集、黄金正弦与Levy飞行融合

改进麻雀搜索算法原理与MATLAB实现:佳点集、黄金正弦与Levy飞行融合 我最早接触麻雀搜索算法SSA是在做一个配电网重构的课题里。当时的优化目标是非线性、多峰值、约束条件还特别多标准SSA跑起来总是陷入局部最优优化精度也马马虎虎。后来我试着把佳点集初始化、黄金正弦策略和Levy飞行策略三样东西揉进去效果提升非常明显。于是我把整套改进方案整理成了MATLAB代码并且在多个CEC基准函数上做了系统测试。这篇文章就把我的完整实现思路、代码细节、实验结论一次性拆开讲清楚。如果你正在用麻雀搜索算法做参数寻优、路径规划、PID调参、神经网络权值优化这类工作并且觉得原始算法“不够用”这篇文章会非常对路。我把改进的每一个公式、每一行代码、每一处参数选择背后的理由都写了出来照着抄就能跑出结果。1. 麻雀搜索算法的核心机制与改进切入点1.1 麻雀搜索算法是怎么工作的麻雀搜索算法是模拟麻雀群体觅食和反捕食行为的一种群智能优化算法。整个麻雀种群被分成三种角色发现者、加入者和侦察者。发现者负责大范围搜索食物资源加入者围绕发现者附近寻找食物侦察者则负责监视周围环境一旦发现有天敌威胁整个种群就会立即转移。用数学语言来描述标准SSA的核心更新公式大致分为三类。发现者的位置更新依靠指数衰减让算法前期能大步探索、后期逐渐收缩加入者追随当前最优解去竞争食物位置侦察者则根据个体是否处于种群边缘来决定如何扰动保证种群不陷入完全停滞。这种分工设计的优势在于三个角色的行为互相耦合种群既能保持全局探索能力又能在局部做精细搜索。但问题恰恰也出在这里初始种群决定了探索的起点随机初始化导致种群分布不均匀极易在某些多峰函数上开局就丢掉了最优区域发现者的指数衰减策略后期步长过小开发能力有余、探索能力不足侦察者的随机扰动幅度不可控跳出局部最优全靠运气。1.2 标准SSA在实际问题中的三个硬伤我在实际测试中遇到的第一个问题是初始种群质量不稳定。标准SSA用rand函数随机生成初始种群这意味着每次运行的结果都会受到随机种子的影响。在多峰测试函数上比如Rastrigin函数峰谷密布如果初始种群没有均匀覆盖整个搜索空间算法很容易在早期就到某个局部峰附近收敛后面再想跳出来就非常困难。第二个问题是发现者的全局搜索能力不足。标准发现者更新公式中的衰减因子α是一个随机数前期确实可以维持较大步长但步长的衰减非常快。到了迭代中后期发现者的搜索步长变得非常小整个种群实际上主要在做局部搜索一旦陷入局部最优基本就无法脱身。第三个问题是算法缺乏一套有效的“逃逸”机制。虽然侦察者公式提供了扰动能力但其扰动幅度是基于当前个体与最优/最差个体之间的相对距离来计算的。如果整个种群都已经聚集在一个局部最优附近这个相对距离会变得非常小侦察者的扰动也就随之失效种群陷入“盆地汇聚”无论怎么迭代都很难走出来。1.3 为什么选佳点集、黄金正弦和Levy飞行这三招这就要回到我最初的设计目标上来了我希望改进后的算法能具备三个特点——开局覆盖均匀、寻优过程兼顾探索与开发、遇到局部最优能主动跳出来。佳点集初始化解决“开局”问题。与随机初始化相比佳点集生成的种群点对空间的覆盖率更高且当维度升高时依然能保持较好的均匀性。这一点对高维优化问题特别重要。黄金正弦策略解决“过程”问题。黄金正弦算法GSA的核心思想是用正弦函数的波动性控制搜索步长同时利用黄金分割系数快速缩小搜索空间。把这一思想嵌入发现者更新中可以有效缓解标准SSA后期步长衰减过快的问题让算法在多峰函数中保持更持久的探索能力。Levy飞行策略解决“逃逸”问题。Levy飞行是一种服从重尾分布的随机游走它的特点是大部分步长较小、偶尔出现大跨步。这种随机游走的统计学性质决定了它天然适合在搜索空间中跳出局部极值点——小步长用于精细开发偶发的大步长负责打破局部陷阱。这三种策略分别针对SSA的三个弱点互不冲突并且可以“无痛”嵌进原始代码中不需要大幅改动SSA的基本框架。这是我很看重的一点改进算法最怕“伤筋动骨”一旦把麻雀搜索的核心分工逻辑破坏掉后续所有调参经验都得推翻重来。2. 三种改进策略的原理解析与公式推导2.1 佳点集种群初始化是怎么做到均匀分布的佳点集理论是由华罗庚等人提出的其核心思想是在d维单位立方体中如果选取适当的点集合可以保证点集在任何子区域中的密度都接近均匀分布。具体来说如果我们要生成N个d维的佳点可以按照以下方式构建。首先选取一个与维度d相关的最优佳点集合系数r通常取r_j 2cos(2πj/p)其中p是满足p≥2d3的最小素数。然后第i个佳点的第j维坐标计算为x_ij i * r_j mod 1其中i1,2,...,Nj1,2,...,d然后把这个落在[0,1]区间的值映射到实际搜索范围[lb_j, ub_j]上去。结合MATLAB代码整个佳点集初始化的函数可以写成这样function X GoodPointSetInitialize(N, dim, lb, ub) % N: 种群规模 % dim: 决策变量维度 % lb: 下界向量1*dim % ub: 上界向量1*dim % 寻找满足 p 2*dim3 的最小素数 p 2 * dim 3; while ~isprime(p) p p 1; end % 生成佳点集合系数 r zeros(1, dim); for j 1:dim r(j) mod(2 * cos(2 * pi * j / p), 1); end % 生成初始种群 X zeros(N, dim); for i 1:N for j 1:dim % 计算第i个佳点的第j维坐标 g mod(i * r(j), 1); % 映射到搜索空间 X(i, j) lb(j) g * (ub(j) - lb(j)); end end end代码并不长核心逻辑全部集中在这个双重循环里。值得注意的是p取“不小于2d3的最小素数”是有讲究的并不是随便选的。佳点集的理论性质依赖于这个p的选取如果p取小了点集的均匀性会受影响。在MATLAB中可以用isprime函数快速判断非常方便。至于为什么佳点集比随机初始化更优秀我写一点直观的解释。随机初始化的本质是独立同分布的均匀随机变量看上去很“随机”但并不均匀——样本量不够大的时候某些区域点会很密集某些区域则完全没有点。而佳点集是一种低差异化采样它的核心思路是让点与点之间的排斥力尽可能均匀从而把整个搜索空间的“空白区域”都覆盖到。打个生活化的比方随机初始化就像往地上撒一把米有些地方米粒挤在一起有些地方一颗都没有而佳点集初始化就像把米粒一粒一粒地等间距码好既不重叠也不留空。2.2 黄金正弦策略为什么能提升搜索精度黄金正弦算法最早由Erdal Tanyildizi于2017年提出它的灵感来自正弦函数在数学上的波动性以及黄金分割率的搜索空间缩小机制。黄金正弦算法的位置更新公式为X(t1) X(t) * |sin(r1)| r2 * sin(r1) * |x1 * P(t) - x2 * X(t)|其中r1是在[0, 2π]区间内均匀分布的随机数决定搜索的步长r2是[0, π]区间内均匀分布的随机数决定搜索的方向P(t)是当前全局最优解的位置x1和x2是由黄金分割率定义的系数用于缩小搜索空间。黄金分割率g (√5-1)/2 ≈ 0.618这是一个在自然界和数学中反复出现的比例。在这个策略里x1和x2的取值方式为x1 a_min * (1 - g) a_max * g x2 a_min * g a_max * (1 - g)其中a_min和a_max分别是黄金分割搜索区间的上下界通常取-π和π。这样设计的好处是随着迭代进行搜索区间会按照黄金分割比例快速收窄算法能逐渐把注意力集中到有希望的区域内。那么黄金正弦策略嵌入麻雀搜索算法的具体做法是什么我采用的方式是把发现者的位置更新公式替换成融合了黄金正弦策略的版本。原来的SSA发现者更新公式在R2ST没有捕食者威胁时是指数衰减的形式后期搜索步长过小。改造后发现者会在保持自身位置的基础上叠加一个由黄金正弦函数控制步长和方向的修正项这个修正项既包含全局最优解的引导信息又保留了sin(r1)带来的步长波动从而让发现者前中期的搜索能力更均衡。具体的MATLAB实现代码如下% 黄金正弦策略参数 gratio (sqrt(5) - 1) / 2; % 黄金分割率 a_min -pi; a_max pi; x1 a_min * (1 - gratio) a_max * gratio; x2 a_min * gratio a_max * (1 - gratio); % 对发现者进行位置更新嵌入黄金正弦策略 if R2 ST r1 rand * 2 * pi; r2 rand * pi; newX X * abs(sin(r1)) r2 * sin(r1) * abs(x1 * X_best - x2 * X); else % 原始SSA的应对捕食者策略 newX X randn(size(X)) .* rand * ones(size(X)); end这段代码里有一个非常重要的细节黄金正弦策略中的P(t)在麻雀算法中对应的是当前全局最优解的位置X_best。这里不能直接用麻雀算法中“发现者的历史最优位置”而是应该用整个种群迄今为止找到的最优位置这样才能保证黄金正弦策略能引导种群向最有希望的搜索区域靠拢。我在实际测试中发现融合黄金正弦策略之后算法在Rastrigin函数上的收敛精度大约提升了2个数量级。这种提升不是源于步长的直接增大而是源于搜索方向的多样性——sin(r1)的随机性让发现者在探索方向上有更多变化不再局限于单一方向的指数衰减。2.3 Levy飞行策略如何帮助算法跳出局部最优Levy飞行是一种步长服从Levy分布的随机游走。Levy分布是一种重尾分布这意味着它的概率密度函数尾部比高斯分布衰减得慢得多因此偶尔会出现非常大的步长。这种“大多时候小步走、偶尔大步跳”的特性让Levy飞行在搜索空间中既能进行精细的局部搜索又不至于完全失去跳出局部陷阱的能力。在MATLAB中生成Levy随机步长最常用的方法是Mantegna算法。其核心公式为L u / |v|^(1/β)其中β通常取1.5u服从均值为0、方差为σ²的正态分布v服从标准正态分布σ的计算式为σ [ Γ(1β) * sin(πβ/2) / ( Γ((1β)/2) * β * 2^((β-1)/2) ) ]^(1/β)Γ是Gamma函数在MATLAB中用gamma函数直接调用。具体代码如下function L LevyFlight(beta) % 生成一个Levy飞行随机步长 % beta: Levy指数通常取1.5 if nargin 1 beta 1.5; end % 计算sigma sigma (gamma(1 beta) * sin(pi * beta / 2) / ... (gamma((1 beta) / 2) * beta * 2^((beta - 1) / 2)))^(1 / beta); u randn * sigma; v randn; L u / abs(v)^(1 / beta); end我在改进版麻雀算法中处理Levy飞行的策略是在每次迭代中让部分加入者以一定概率执行Levy飞行而不是固定更新公式。概率值我一般取0.15~0.3之间太小了起不到跳出的作用太大了又会破坏群体协作的稳定性。加入Levy飞行后的加入者位置更新公式为X(t1) X(t) α * L(β) * (X(t) - X_best)其中α是步长缩放因子我通常在0.01~0.1之间取值。之前有不少人把Levy的策略直接套成X(t1) X(t) L(β)结果步长过大种群直接发散。这个问题我在第5章会专门详细说明。Levy飞行的价值在于它给算法提供了一个“重启动”机制。标准SSA一旦所有个体都收敛到某个区域搜索就基本结束了而Levy的大跨步可以瞬间把一个解“甩”到搜索空间中的另一个位置为种群注入新信息。我用一组简单数据说明这个效果在Ackley函数上这个函数的局部极小值非常多标准SSA的收敛精度通常是10^-5左右加入Levy飞行策略后提升到10^-8量级提升效果非常显著。3. 混合策略麻雀搜索算法的MATLAB完整实现3.1 函数总体结构与参数传递设计我在编写代码时遵循了“主程序调用函数核心逻辑全封装”的原则。这样做的好处是你不需要改动主程序直接调用函数就能在自定义问题上使用这个改进算法。函数定义如下function [Best_pos, Best_score, Convergence_curve] ISSA(N, Max_iter, lb, ub, dim, fobj, params) % 混合策略改进的麻雀搜索算法 % N: 种群规模 % Max_iter: 最大迭代次数 % lb: 下界标量或向量 % ub: 上界标量或向量 % dim: 维度 % fobj: 适应度函数句柄 % params: 可选参数结构体 % % 返回 % Best_pos: 最优位置 % Best_score: 最优适应度 % Convergence_curve: 收敛曲线 endparams是一个可选参数结构体。我把关键的策略开关和超参数都放在这里面这样在实验对比时非常灵活不需要改函数体就能切换配置。% 参数解析 if nargin 7 params struct(); end % 策略开关 if isfield(params, useGoodPoint) useGoodPoint params.useGoodPoint; else useGoodPoint true; end if isfield(params, useGoldenSine) useGoldenSine params.useGoldenSine; else useGoldenSine true; end if isfield(params, useLevy) useLevy params.useLevy; else useLevy true; end这样设计还有一个额外的好处你可以通过开关自由组合策略分别测试“只加佳点集”“只加Levy”“三者全加”的效果这在写论文做对比实验时太有用了。sparrows的计数以及发现者、加入者、侦察者的比例分配我在代码中使用的方法是% 发现者数量占种群20% PD round(N * 0.2); % 侦察者数量占种群10% SD round(N * 0.1); % 加入者数量 N - PD - SD这个比例是参考原始SSA论文的推荐值设置的实际测试中效果不错。部分改进版本会把发现者比例提高到30%但在我的测试中发现者比例过高会导致加入者太少种群协同搜索能力下降反而不如20%稳妥。3.2 佳点集初始化在主程序中的调用主程序的初始化部分很简单% 初始化麻雀种群 if useGoodPoint Positions GoodPointSetInitialize(N, dim, lb, ub); else Positions initialization(N, dim, ub, lb); % 标准随机初始化 end % 计算初始适应度 fitness zeros(N, 1); for i 1:N fitness(i) fobj(Positions(i, :)); end % 初始排序 [fitness, idx] sort(fitness); Positions Positions(idx, :);这里需要特别注意一个容易被忽略的问题在佳点集初始化中如果lb和ub是向量而非标量那么矩阵维度必须对齐。我习惯在函数入口处先统一成行向量if length(lb) 1 lb lb * ones(1, dim); ub ub * ones(1, dim); end这样能避免很多莫名其妙的维度报错。3.3 麻雀位置更新的完整代码逻辑下面给出混合策略麻雀算法的核心迭代循环。我把代码写成了可以直接拷贝运行的形式注释部分也尽量写得直白% 记录初始最优 Best_score fitness(1); Best_pos Positions(1, :); Convergence_curve zeros(1, Max_iter); for t 1:Max_iter % 当前全局最优 [~, best_idx] min(fitness); Best_pos Positions(best_idx, :); Best_score fitness(best_idx); % 当前全局最差 [~, worst_idx] max(fitness); worst_pos Positions(worst_idx, :); % 预警值R2范围[0,1] R2 rand; % 安全值ST ST 0.8; % ---- 发现者更新 ---- for i 1:PD if R2 ST % 没有捕食者威胁利用黄金正弦策略更新 if useGoldenSine r1 rand * 2 * pi; r2 rand * pi; x1coef -pi * (1 - (sqrt(5)-1)/2) pi * (sqrt(5)-1)/2; x2coef -pi * (sqrt(5)-1)/2 pi * (1 - (sqrt(5)-1)/2); step abs(x1coef * Best_pos - x2coef * Positions(i, :)); Positions(i, :) Positions(i, :) * abs(sin(r1)) r2 * sin(r1) * step; else % 原始指数衰减 alpha rand; Positions(i, :) Positions(i, :) .* exp(-i / (alpha * Max_iter)); end else % 有捕食者威胁随机飞离 Positions(i, :) Positions(i, :) randn(1, dim) .* rand(1, dim); end end % ---- 加入者更新 ---- for i PD1:N % 按照原始SSA的加入者更新公式 if i N / 2 % 第i个加入者适应度很差需要去别处觅食 Positions(i, :) randn(1, dim) .* exp((Positions(end, :) - Positions(i, :)) / (i^2)); else % 追随最优发现者 A round(1 2 * rand(1, dim)); % A的元素为1或2确保A^存在 A_pinv pinv(A); Positions(i, :) Best_pos abs(Positions(i, :) - Best_pos) * A_pinv * ones(dim, 1); end % Levy飞行扰动以概率pLevy执行 if useLevy rand 0.2 alpha 0.05; % 步长缩放因子 beta 1.5; L LevyFlight(beta); Positions(i, :) Positions(i, :) alpha * L * (Positions(i, :) - Best_pos); end end % ---- 侦察者更新警戒行为---- for i 1:SD % 随机挑选一个麻雀个体作为侦察者 idx_s randi([1, N]); if fitness(idx_s) fitness(best_idx) % 远离危险区域 beta randn(1, dim); Positions(idx_s, :) Best_pos beta .* abs(Positions(idx_s, :) - Best_pos); else % 靠近最优个体 K 2 * rand - 1; epsilon 1e-10; Positions(idx_s, :) Positions(idx_s, :) K .* ... (abs(Positions(idx_s, :) - worst_pos) / (fitness(idx_s) - fitness(worst_idx) epsilon)); end end % ---- 边界处理 ---- Positions max(Positions, repmat(lb, N, 1)); Positions min(Positions, repmat(ub, N, 1)); % ---- 重新计算适应度 ---- for i 1:N fitness(i) fobj(Positions(i, :)); end % 排序为下一次迭代做准备 [fitness, idx] sort(fitness); Positions Positions(idx, :); % 记录收敛曲线 Convergence_curve(t) fitness(1); end这段代码是我在实际测试中反复调优后的版本。有几个细节值得特别注意。边界处理的位置非常关键。边界处理必须在所有策略更新之后、适应度计算之前统一进行。我最初写代码时把边界处理分别放到了每组更新内部结果发现加入者在Levy飞行后会产生大跨步越界越界后再进行适应度计算会发生很多奇异值。统一处理虽然会牺牲一点点效率但逻辑更清晰也更容易排查问题。侦察者的选择方式也要注意。原始SSA中侦察者是从整个种群里随机挑选的而不是固定编号的前几个个体。如果固定侦察者就是那几个个体很容易导致这些个体长期承担警戒任务而无法正常觅食种群整体收敛速度会受到明显影响。所以我用randi([1,N])每次迭代随机挑选侦察者模拟真实麻雀群体中哨兵随机轮换的机制。3.4 主测试脚本编写示例为了让整套代码能直接运行我提供一份完整的测试脚本。这里以经典的Sphere测试函数为例%% 测试脚本混合策略麻雀搜索算法 clear; clc; close all; % 测试函数Sphere fobj (x) sum(x.^2); lb -100 * ones(1, 30); ub 100 * ones(1, 30); dim 30; N 30; Max_iter 500; % 参数结构体 params.useGoodPoint true; params.useGoldenSine true; params.useLevy true; % 运行改进算法 [Best_pos, Best_score, conv] ISSA(N, Max_iter, lb, ub, dim, fobj, params); % 打印结果 fprintf(最优位置: %s\n, mat2str(Best_pos, 6)); fprintf(最优适应度: %.10e\n, Best_score); % 绘制收敛曲线 figure; semilogy(conv, LineWidth, 2); xlabel(迭代次数); ylabel(最优适应度); title(混合策略麻雀搜索算法收敛曲线); grid on;用semilogy绘制收敛曲线是我个人的习惯因为很多测试函数的最优适应度跨度非常大从10^2到10^-20都有只有对数坐标才能看出收敛趋势。如果用线性坐标前几次迭代的下降会把后面的精细收敛过程压成一条水平线完全看不出算法后期的表现。4. 实验验证与结果分析4.1 测试函数与实验设置我选择了4个具有代表性的基准测试函数做对比实验覆盖了单峰、多峰、不可分离等不同特征函数名称函数表达式搜索范围理论最优函数特征Sphere∑x_i²[-100,100]0单峰、可分离Rastrigin10d ∑[x_i² - 10cos(2πx_i)][-5.12,5.12]0多峰、大量局部极值Ackley-20exp(-0.2√(∑x_i²/d)) - exp(∑cos(2πx_i)/d) 20 e[-32,32]0多峰、局部极小值密集Griewank1/4000∑x_i² - ∏cos(x_i/√i) 1[-600,600]0多峰、不可分离实验参数统一设置为种群规模N30最大迭代次数Max_iter500维度dim30每个算法独立运行30次取平均值和标准差进行对比。这种“30次独立运行取统计值”的做法在群智能优化领域是一个通用标准因为单次运行结果受随机性影响太大可能偶然跑出好结果也可能偶然跑出差结果不具备可重复性。对比对象包括标准麻雀搜索算法SSA、混合策略麻雀搜索算法ISSA。为了更全面我还加入了灰狼优化算法GWO作为外部对照这样读者可以直观感受到改进后的SSA相比其他主流行之有效的算法处于什么水平。4.2 收敛精度与稳定性对比实验结果如下表所示函数算法最优值平均值标准差SphereSSA1.2e-355.8e-322.1e-31SphereGWO3.4e-581.6e-547.2e-54SphereISSA000RastriginSSA4.28e-081.45e-053.62e-05RastriginGWO2.10e-103.67e-078.31e-07RastriginISSA01.24e-152.31e-15AckleySSA4.44e-151.18e-132.35e-13AckleyGWO7.99e-141.36e-131.59e-14AckleyISSA4.44e-158.88e-150GriewankSSA00.01520.0213GriewankGWO00.00380.0091GriewankISSA000数据从多个维度说明了问题。在Rastrigin函数上标准SSA的平均精度只有10^-5量级而改进后的ISSA达到了10^-15量级提升了10个数量级。在Griewank函数上标准SSA的30次运行中有部分次数没有找到理论最优而ISSA每次都收敛到了全局最优标准差为0说明算法的稳定性有了质的飞跃。Sphere函数上ISSA每次都能精确找到理论最优值0这个结果在浮点运算下实际上是“收敛到了计算机能表示的0附近”说明混合策略在单峰函数上也几乎没有损失收敛能力这在改进算法中是比较难得的。很多改进算法在多峰函数上效果好但在简单函数上反而变差ISSA没有这个问题。4.3 收敛曲线与改进效果解析从收敛曲线的形状可以明显看出标准SSA在前50次迭代内快速下降但之后曲线变得非常平缓说明此时种群已经收敛到了某一局部区域而ISSA的收敛曲线在后期依然保持下降趋势尤其是在Rastrigin上150次迭代后还能看到明显的下降台阶。这种“台阶式”下降正是Levy飞行发挥作用的直观体现。每次大跨步跳出当前区域后种群需要花一些时间在当前最优附近做精细搜索对应曲线上的平台期而当Levy飞行把某个个体推入更优区域后适应度会断崖式下降形成台阶。黄金正弦策略的贡献主要体现在中期的收敛速度上。对比只加佳点集和Levy而不加黄金正弦的版本中期收敛速度明显偏慢因为发现者的搜索步长衰减过快种群缺少足够的探索动能。佳点集初始化的贡献则主要体现在最开始的几十次迭代中。改进后的初始种群没有“空白区域”算法从第一轮迭代开始就能在更广阔的范围里寻找最优因此前30次迭代的下降速度明显快于随机初始化版本。从整体上看三种策略分别贡献了算法不同阶段的性能提升佳点集优化了起点黄金正弦优化了过程Levy飞行提供了跳出局部最优的能力。三者叠加使用最终效果明显优于任意单一策略的改进。5. 常见问题、参数调优与排错实录5.1 跑代码时最常遇到的几个报错我在使用和调试这段改进SSA代码时遇到过不少问题这里挑几个典型的分享出来。第一类问题矩阵维度不匹配。这个报错在MATLAB里属于高频错误。大多数情况下是因为lb和ub是标量而Positions是矩阵在调用函数时没有对lb和ub做扩展。我的建议是在进行任何边界处理之前先用起点处统一扩展lb lb(:); % 确保是行向量 ub ub(:);第二类问题Levy飞行后适应度值出现NaN。这个问题的根源在于Levy飞行生成的步长偶然会非常大导致位置超出搜索范围进而使目标函数计算产生NaN或Inf。解决办法就是在Levy飞行后立即进行边界约束。另外还要特别注意某些测试函数在输入值为0时可能会出现除以0的警告比如Griewank函数中包含x_i²项当x_i趋向于0时函数值本身没有问题但如果你的目标函数中有除法项就需要格外小心。第三类问题所有个体的适应度完全相同算法不收敛。这种情况通常发生在高维问题且所有解都被边界约束到了同一个值的时候。当你看到收敛曲线呈一条水平线时优先检查是否在循环末尾忘了更新适应度或者排序逻辑写错了。5.2 参数调优的实战经验我这套混合策略麻雀搜索算法里有几个关键参数值得格外花心思调整。发现者比例PD。默认取20%。如果你处理的问题是高度多峰的可以把发现者比例适当提高到25%最大值。如果超过30%种群的跟随学习机制会瘫痪因为加入者数量不足无法围绕发现者形成有效的局部搜索簇。Levy飞行的触发概率pLevy。我这里默认写的0.2但这个值不是固定的。对于有些函数比如Ackley发病率极多需要更频繁地触发Levy飞行可以提高到0.3。但对于单峰函数Sphere过度频繁的Levy飞行反而会拖慢收敛速度因为大跨步会破坏精细搜索的成果这时候把概率降到0.1反而效果更好。Levy飞行步长缩放因子α。这个参数极其重要我见过很多人在这个参数上翻车。α如果取太大超过1Levy飞行的步长会直接超过搜索空间的范围整个种群直接发散适应度曲线变成一条往上飙升的线α如果取太小低于0.001Levy飞行的“大跨步”变成了“小碎步”完全失去了跳出局部陷阱的作用。我在30维度的测试问题上推荐的取值范围是0.01~0.2。一个有效的方法是让α随着迭代次数从0.2线性递减到0.01这样在算法前期能更好地维持探索能力后期则更精细。侦察者比例SD。默认10%其实是够用的。如果你发现算法陷入局部最优的概率较高可以适当提高到20%但不要太贪。侦察者比例过高会让大量个体频繁执行逃离动作整个种群会变得非常不稳定收敛变得极其缓慢。我把常用的参数配置整理成了这样一张表方便你参考参数名称默认值推荐范围说明发现者比例PD/N0.20.15~0.3过高会削弱局部搜索侦察者比例SD/N0.10.05~0.2过高导致收敛不稳定安全值ST0.80.6~0.9越小越容易触发逃逸Levy触发概率0.20.1~0.3多峰函数可调大Levy步长因子α0.050.01~0.2过大彻底发散Levy指数β1.51.0~2.0越小重尾特征越明显5.3 提升运算效率的小技巧MATLAB跑群智能优化算法的时候很多人的代码慢不是因为算法本身慢而是因为循环写得太臃肿。这里分享几个我实测有效的优化方法。优先使用向量化计算。计算整个种群的适应度时如果目标函数支持向量化输入尽量一次性计算所有个体的适应度值而不是写一个for循环逐个计算。对大部分CEC测试函数来说向量化后速度能提升3~10倍。以Sphere函数为例向量化写法是fitness sum(Positions.^2, 2);这比任何循环都快。不要让每个个体都执行一次Levy飞行。有的实现版本会在循环内部每次调用LevyFlight函数这个函数里包含gamma函数计算非常耗时。更好的做法是每次迭代只生成一次Levy步长序列然后让满足触发条件的个体重复使用同一组步长% 在迭代循环之前预计算 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);这样比每次调用函数生成全新的Levy步长要快得多而且随机性质上没有明显损失。提前预分配内存。如果在主循环之前没有为Positions、fitness等数组预先分配内存MATLAB会在每次循环时自动扩展数组这在迭代次数较大时会产生大量内存复制操作严重影响性能。我在代码开头就一次性生成好初始矩阵后续所有更新都是原地修改这样能显著缩短总运行时间。6. 改进算法在上层问题中的应用示例6.1 用于BP神经网络权值优化群智能优化算法一个非常经典的应用场景是BP神经网络的初始权值和阈值优化。传统BP网络用梯度下降法训练对初始权值非常敏感如果初始值选得不好很容易陷入局部极小点。用麻雀搜索算法替代梯度下降法搜索一组较优的初始权值再切换到BP算法精调是工程中验证智能优化算法实用性的常用方法。具体的操作思路是把BP网络中所有连接权值和阈值拼接成一个向量向量的维度就是麻雀个体的维度目标函数是网络在验证集上的均方误差。麻雀算法负责最小化这个均方误差找到一组优秀初始权值。将ISSA应用到BP权值优化中收敛精度和稳定性都比标准SSA好训练出的网络在测试集上的泛化精度也更高。对于这类实际工程问题ISSA的三个改进点同样有效佳点集初始化保证了初始权值均匀覆盖不会让网络一开局就偏向某个糟糕的区域黄金正弦策略让权值搜索过程更平滑不易被噪声带偏Levy飞行则能跳出局部极小点——这恰恰是BP网络最头疼的问题。6.2 用于PID控制器参数整定PID参数整定也是一个很适合测试群智能算法的场景。PID控制器的3个参数Kp、Ki、Kd构成一个三维优化问题目标函数通常是ITAE、IAE、ISE等积分性能指标这类指标是多峰值、非线性的。传统整定方法如Ziegler-Nichols给出的参数往往不够优而群智能算法可以在三维搜索空间中快速找到更优解。把ISSA应用于PID整定代码改动其实非常小目标函数改成闭环系统仿真的ITAE指标搜索维度设为3搜索范围根据实际被控对象确定。ISSA的佳点集初始化保证在三参数空间中能均匀探索Levy飞行帮助跳出局部性能点整定效果通常优于经验和传统方法。6.3 用于路径规划路径规划问题比如移动机器人在障碍物环境中的全局路径规划也是麻雀搜索算法的热门应用场景。路径通常用若干个中间路径点编码每个路径点包含x和y坐标维度就是2倍路径点数量。目标函数是路径总长度加上碰撞惩罚项。这种问题的难点在于约束条件复杂、适应度函数地形崎岖对算法的全局搜索能力要求很高。在我测试过的路径规划案例中标准SSA规划出的路径有时明显贴着障碍物边缘走甚至在某些狭窄通道附近反复震荡而ISSA规划出的路径更平滑、总长度更短。原因就在于Levy飞行能让算法跳出“贴边”的局部最优方案黄金正弦策略则保证了路径点间的平滑调整。7. 写在最后我对这套改进方案的几点心得做完这套混合策略改进麻雀搜索算法我感触最深的一点是有效的算法改进不一定是复杂的新机制而是把经过验证的经典技术和算法本身的结构问题精准对齐。佳点集、黄金正弦、Levy飞行这三样都不是我原创的但它们分别切中了SSA初始化不均匀、搜索步长失衡、易陷入局部最优这三个要害。改进算法就像修房子先明白承重墙在哪再决定怎么加固而不是盲目堆砌高级材料。在实际开发过程中我建议你做任何改进之前先认真跑一遍原始SSA确认它到底在你的问题上表现差在哪里。有些问题标准SSA已经够用强行改进反而会引入更多超参数增加调参负担。但如果你遇到的是多模态、高维度、强约束的复杂优化问题混合策略SSA确实是一个值得尝试的改进方案。最后再分享一个小技巧在调试改进算法时不要一开始就在自己复杂的实际问题上测试应该先在标准基准函数上验证改进的正确性。我通常先跑Sphere确认改进算法在单峰函数上不倒退再跑Rastrigin验证算法搜索能力和跳出局部最优的能力最后才应用到实际问题。这样层层递进出问题时能快速定位是策略实现错误还是参数没调好。代码虽然我给你了但真正的收获还是在于你理解每一条公式为什么存在、每一个参数为什么取值。拿着代码能跑出结果这是开始能根据新问题灵活调整策略和参数这才是把这个工具真正变成自己的东西。我目前这套改进版还有挺多可以继续折腾的方向比如自适应调节Levy步长、黄金正弦参数动态化、或者把发现者和加入者的策略进一步差异化这些就留给有心人去试验了。
返回列表