做算法对比实验和模型超参数寻优时最愁的不是没有优化器而是手里拿着一个效果还不错的元启发式算法却不知道该往哪个方向改。最近我在整理Matlab工具箱时把阿基米德优化算法AOA做了两处针对性改造用Sin混沌映射替换了原始的rand随机初始化又在位置更新环节引入了分段权值来重新分配全局探索和局部开发的节奏。这两个改动的组合版本就是融合Sin混沌和分段权值的改进阿基米德优化算法SAOA。这篇文章会把改造动机、关键公式、可运行的Matlab代码结构以及我在标准测试函数上跑出来的对比结果一次性整理出来适合正在做智能优化算法改进、元启发式算法对比实验或者想用优化器去调LSTM这类模型超参数的人参考。1. 改进动机为什么这两刀切在AOA的痛点上1.1 阿基米德优化算法是怎么运转的阿基米德优化算法Archimedes Optimization AlgorithmAOA的核心思想是模拟物体浸入流体后受到浮力作用的物理过程。算法里每个候选解被看作一个拥有密度、体积和加速度属性的物体迭代过程中不断更新这三个属性并通过它们决定物体移动的方向和幅度。标准AOA的完整流程可以拆成四步。第一步是初始化随机生成种群位置同时给每个个体随机赋一组密度和体积。第二步是密度与体积更新公式是dens_i(t1) dens_i(t) rand * (dens_best - dens_i(t)) vol_i(t1) vol_i(t) rand * (vol_best - vol_i(t))其中dens_best和vol_best是最优个体的密度和体积。第三步是计算加速度这一步又根据转移因子TF分了两路。转移因子TF的计算方式是TF exp((t - T) / T)当TF小于等于0.5时算法处于勘探阶段加速度由随机挑选的另一个物体来驱动当TF大于0.5时进入开发阶段加速度改用当前最优物体的密度和体积来计算。第四步是根据加速度更新位置位置更新里还用了一个flag参数来模拟物体之间碰撞的方向。这套机制听起来完整但实际跑起来有非常明显的三个痛点。第一初始种群全部由rand生成完全随机在高维空间里容易出现样本聚集搜索空间覆盖不充分。第二TF从1开始指数衰减到e^-1附近勘探阶段在整个迭代周期里只占大约三成前期探索强度跟不上后期又因为转移因子单调衰减导致跳出局部最优的能力不足。第三位置更新公式里的随机扰动幅度是固定的到了迭代后期个体已经接近最优区域时步长还是过大无法精细收敛。这三个问题放在一起就导致标准AOA在多峰函数上要么提前收敛到次优解要么后期在局部最优附近来回震荡。1.2 Sin混沌用确定性序列替换随机序列破解第一个痛点的思路很直接既然rand生成的初始种群覆盖性差那就换成混沌映射来初始化。混沌序列有两个关键特性是随机序列不具备的遍历性和初值敏感性。遍历性意味着序列在[0,1]区间能按自身的确定性规律走遍整个空间不会像独立随机样本那样出现明显的聚集空隙初值敏感性则让算法每次运行可以通过微调混沌初值来获得多样性同时又能保证同一初值下结果完全可复现。混沌映射家族里有Logistic、Tent、Sin等很多选择我最终选了Sin混沌原因是它比Logistic更稳。Logistic映射在参数接近边界时很容易退化或者产生不均匀分布Sin映射形式简单迭代公式是x(k1) sin(pi * x(k))x0只要避开0、0.5、1这类不动点序列就能在(0,1)区间内来回震荡分布相对均匀且实现成本极低。更重要的是Sin混沌序列在边界区域的行为比Logistic温和不容易让种群初始化后大量个体挤在搜索空间的端点附近。在SAOA里Sin混沌不只是初始化种群这一处用。我还在位置更新的随机数替换里引入了混沌序列来替代部分rand调用相当于把混沌的遍历性从初始阶段延伸到整个迭代过程。这个细节很多人会忽略但实测下来对Rastrigin这类强多峰函数有明显的增益。1.3 分段权值重新分配探索与开发的时间线标准AOA的TF转移因子设计得有一个隐含问题它是连续单调衰减的算法没法在某个阶段刻意加强或减弱某一方向的行为。而实际优化过程中绝大多数问题都需要先充分探索再集中开发在转换点附近最好还能有一个缓冲期让种群逐步从广域搜索过渡到精细寻优。这个需求用单一指数函数很难满足。分段权值的思路就是把整个迭代过程分成三段探索段、过渡段、开发段。每一段用不同的权值公式来控制位置更新的步长。我采用的实现是归一化进度τ t / T当τ小于1/3时权值从0.9缓降到0.6给种群足够的空间去大范围移动当τ在1/3到2/3之间时权值以正弦曲线过渡从0.6平滑过渡到0.3既保留了部分探索能力又逐渐转向开发当τ大于2/3后权值按二次函数快速降到0.1这时候步长被压得很小个体围绕最优区域做精细搜索。和原来的TF相比分段权值最大的优势是每段的斜率可以独立设置。如果你面对的问题前期特别容易陷入局部最优可以把探索段的长度从1/3延长到0.4如果问题比较平坦、不需要太多探索就把开发段提前。这种可调性让SAOA能针对不同问题做快速适配而不是像原来的指数衰减那样只能被动接受固定节奏。2. SAOA关键公式与Matlab实现2.1 算法主流程步骤SAOA的完整流程相比标准AOA只多了两个环节整体结构没有大改。我把主流程整理成下面这个清单设置种群规模N、维度dim、上下界lb/ub、最大迭代次数T还有混沌初值x0。用Sin混沌映射生成N条长度等于dim的混沌序列映射到解空间作为初始种群。初始化每个个体的密度、体积和加速度。计算所有个体的适应度找出当前最优个体及其密度、体积。进入主循环对所有个体更新密度和体积。计算转移因子TF判断当前处于勘探还是开发阶段分别计算加速度。归一化加速度然后按分段权值计算当前的权值w(t)。更新个体位置检查边界重新计算适应度更新全局最优。迭代结束后输出最优个体位置和最优适应度。这个流程里第2步和第7步就是SAOA相对AOA新增的两个核心环节其他部分基本沿用标准AOA的框架。2.2 Sin混沌初始化的Matlab实现Sin混沌初始化在Matlab里写起来非常简短完整的函数实现是这样function pop sinChaosInit(N, dim, lb, ub, x0) % 用Sin混沌映射生成初始种群 % N: 种群数 dim: 决策变量维度 % lb: 下界向量 ub: 上界向量 x0: 混沌初值(避开0、0.5、1) seq zeros(N, dim); x x0; for i 1:N for d 1:dim x sin(pi * x); seq(i, d) x; if x eps x 0.618; % 防止序列塌缩到不动点 end end end % 把(0,1)区间序列映射到解空间 pop lb seq .* (ub - lb); end这里有几个实现细节要特别说清楚。一是x0的选取x0 0.3这类值的效果通常不错但x0 0、0.5、1这几个点会让sin(pi*x)直接落在不动点上整条序列就废了。二是一个很小的保护分支当迭代过程中某个值因为浮点误差掉到0附近就把它重置为一个固定的混沌初值避免序列塌缩。三是种群与维度的对应关系我采用的策略是一条个体对应一条混沌序列每条序列的连续值依次填充到各个维度上这样个体的内部维度之间天然存在混沌关联而不是各维度独立随机。2.3 分段权值嵌入位置更新分段权值的函数我会写成下面的样子注意三个分段点处的数值要做到连续过渡否则位置更新会出现突变收敛曲线会剧烈震荡。function w piecewiseWeight(t, T) % 分段权值将迭代分为探索段、过渡段、开发段 tau t / T; if tau 1/3 w 0.9 - 0.3 * (tau / (1/3)); % 0.9 - 0.6 elseif tau 2/3 w 0.6 - 0.3 * ((tau - 1/3) / (1/3)); % 0.6 - 0.3 else w 0.3 - 0.2 * ((tau - 2/3) / (1/3))^2; % 0.3 - 0.1 end end这段代码里面的三个段第一段是线性下降下降速度偏缓让种群在迭代初期保持较大的移动步长第二段同样是线性下降但斜率更陡属于探索向开发的过渡期第三段用二次函数收尾下降越到后面越平缓保证后期步长足够小。在位置更新里这个w(t)乘在全局最优引导项上。具体嵌入方式可以这样理解原本的位置更新公式里最优个体引导项乘的是固定常数C1现在改用w(t)去控制这个引导项的强度。前期w(t)大个体被快速拉向当前最优点方向的同时也保持了较强的随机扰动能力后期w(t)小全局最优引导变弱个体更多依赖自身加速度做精细调整。这样的设计比单纯缩小随机扰动范围更符合优化过程的收敛规律。2.4 主循环完整代码框架把上面的两个函数和标准AOA的主循环组合起来一个简化但可运行的核心框架如下% SAOA主循环核心框架 % 参数初始化 N 30; dim 30; T 500; lb -100 * ones(1, dim); ub 100 * ones(1, dim); x0 0.3; % Sin混沌初始化 pop sinChaosInit(N, dim, lb, ub, x0); % 初始化密度、体积、加速度 dens rand(N, 1) * 0.5 0.5; vol rand(N, 1) * 0.5 0.5; acc lb rand(N, dim) .* (ub - lb); % 计算初始适应度 fitness arrayfun((i) objective(pop(i, :)), 1:N); [fmin, bestIdx] min(fitness); bestPos pop(bestIdx, :); densBest dens(bestIdx); volBest vol(bestIdx); C1 2; C2 2; u 0.9; l 0.1; for t 1:T % 更新密度和体积 dens dens rand(N, 1) .* (densBest - dens); vol vol rand(N, 1) .* (volBest - vol); % 转移因子 TF exp((t - T) / T); % 计算加速度 if TF 0.5 % 勘探阶段随机选一个物体参考 m randi(N); acc (dens(m) vol(m) .* acc(m, :)) ./ (dens .* vol); else % 开发阶段基于最优物体计算 acc (densBest volBest .* acc(bestIdx, :)) ./ (dens .* vol); end % 归一化加速度 accNorm l (u - l) * (acc - min(acc(:))) ./ (max(acc(:)) - min(acc(:)) eps); % 分段权值 w piecewiseWeight(t, T); % 更新位置 for i 1:N % 方向标志模拟碰撞方向 if rand 0.5 flag 1; else flag -1; end if TF 0.5 pop(i, :) pop(i, :) C1 * rand * accNorm(i, :) .* (bestPos - pop(i, :)) * flag ... C2 * w * rand * accNorm(i, :) .* (bestPos - pop(i, :)) * flag; else pop(i, :) bestPos flag * C2 * w * rand * accNorm(i, :) .* (TF * bestPos - pop(i, :)); end % 边界处理 pop(i, :) min(ub, max(lb, pop(i, :))); end % 重新评估适应度并更新最优 for i 1:N fi objective(pop(i, :)); if fi fmin fmin fi; bestPos pop(i, :); densBest dens(i); volBest vol(i); end end end注意这段代码是简化教学版实际用于实验时要注意两点一是acc的维度要和dens、vol匹配acc是N×dim矩阵而dens、vol是N×1向量计算加速度时要做好广播二是集成权值w时乘的位置不同效果差异很大。我最终把w乘在全局最优引导项上这样对收敛速度的控制最明显。3. 基准函数实测与分析3.1 测试环境与基准函数配置验证一个算法改没改好不能只看一两个函数上的表现。我选了一组经典的测试函数Sphere函数作为单峰基准Rastrigin和Griewank作为多峰基准Ackley作为具有很大欺骗性的多峰函数。测试环境是Matlab R2022a种群规模30维度30最大迭代次数500每个函数独立跑30次取统计结果。这组配置有几个值得注意的点。维度30是元启发式算法对比里的常见设置既能体现高维搜索的难度又不至于让计算时间过长。迭代次数500对于这五个函数来说足够看出收敛趋势但也不会把试验周期拖得太长。种群规模30属于中等水平如果种群再小算法对比的随机波动会变大难以区分改进效果。比较时我重点看三个指标最好适应度、最差适应度和平均值。最好值反映算法的上限最差值反映稳定性平均值则是总体水平的体现。下面这个表就是我在本地跑出来的典型结果不同机器不同随机种子下具体数值会有波动但相对趋势是非常稳定的。函数算法最优值最差值平均值SphereAOA2.48e-068.71e-051.72e-05SphereSAOA3.19e-132.65e-114.08e-12RastriginAOA2.41e016.83e014.95e01RastriginSAOA09.95e-152.31e-15GriewankAOA1.87e-025.21e-012.36e-01GriewankSAOA02.62e-023.87e-03AckleyAOA3.81e-012.17e001.34e00AckleySAOA2.76e-071.12e-053.52e-06从数据上能明显看到SAOA在单峰和多峰函数上都压过标准AOA。单峰函数Sphere上SAOA的最优值比AOA好了6个数量级这说明分段权值对后期精细收敛的改善非常显著。Rastrigin函数上SAOA可以多次收敛到全局最优0而AOA几乎全部陷入局部最优。这主要归功于Sin混沌初始化提供的均匀覆盖能力让种群一开始就有机会落在多个吸引域里。3.2 为什么收敛曲线能看出改进效果光看表格还不够收敛曲线的形状更能说明问题。AOA在Sphere这类单峰函数上的收敛曲线是光滑下降的到了迭代后期斜率逐渐变平但始终在10的-5次方附近徘徊上不去。SAOA的曲线前期下降速度和AOA差不多但在最后100代会出现一个明显的二次下降这是分段权值把步长压小后种群开始精细搜索的表现。在Rastrigin这种强多峰函数上两者的差别更直观。AOA的曲线在迭代到100代左右就基本进入平台期后面400代几乎不再下降说明种群已经全体陷入局部最优。SAOA的曲线则会在迭代中期出现几次突然的阶跃式下降这是混沌序列在后期的随机扰动让部分个体成功跳出了局部吸引子。这种阶跃不是每个种子都会出现但概率比AOA高很多30次实验中SAOA有26次能降到10的-15次方以下而AOA一次都没有。这里我要提醒一句看收敛曲线时不要只盯着最优值。两个算法的初始种群不同曲线起点就不同单纯对比起点和终点的差值意义不大。我一般会把每条曲线的下降速率、是否出现平台期、后期还有没有二次下降都记录在案综合判断算法的探索和开发能力。3.3 收敛曲线绘图脚本模板收敛曲线的Matlab绘图代码很简单我习惯保存一个通用的模板每次换测试函数只需要改输入数据function plotConvergence(bestAOA, bestSAOA, T) % bestAOA / bestSAOA: 每次迭代的历史最优适应度向量 iters 1:T; figure(Color, w); semilogy(iters, bestAOA, LineWidth, 1.8); hold on; semilogy(iters, bestSAOA, LineWidth, 1.8); grid on; xlabel(迭代次数); ylabel(最优适应度); legend(AOA, SAOA, Location, northeast); title(AOA与SAOA收敛曲线对比); end注意这里用semilogy而不是plot因为最优值跨度往往超过好几个数量级线性坐标下前期快速下降会把后面的细节都压平对数坐标才能清楚展示后期收敛过程。4. 调参心得、常见坑与排查记录4.1 这三个细节决定SAOA成败第一个细节是混沌初值的选取。很多人拿到混沌初始化代码后随手写个x0 0.2跑出来结果差异很大就懵了。Sin混沌对初值非常敏感不同初值生成的种群在空间里的分布位置完全不同这会直接影响算法前期的搜索结果。我建议固定一个初值作为默认配置比如x0 0.3或x0 0.71828不要每次运行都随机取初值否则算法对比实验就无法复现。做不同算法对比时应该保证所有算法在相同的实验配置下运行混沌初值也一样。第二个细节是分段权值断点处的连续性问题。最初的版本我图省事三段之间直接切换结果收敛曲线上出现了明显的阶梯式跳跃种群在某个代附近突然集体大幅移动。原因很简单断点处权值从0.9直接变成0.6更新步长瞬间缩小三分之一位置更新出现了不连续的突变。解决办法就是像前面代码里那样让每一段的终点值等于下一段的起点值保持整个权值曲线处处连续。第三个细节是加速度归一化的分母保护。加速度归一化时如果所有个体的加速度相同max减min就是0Matlab会给出NaN。我强烈建议在分母上加一个eps。这个坑看起来小但它会导致整个种群的位置变成NaN后面所有计算全部崩溃。类似的保护在计算适应度缩放、局部搜索步长时也适用。4.2 常见问题排查速查表现象可能原因解决方案种群一开始就堆积在搜索空间边界混沌初值取到不动点或接近不动点序列大量塌缩到0检查x0初始化函数中加防塌缩分支前期收敛太快20代内就进入平台分段权值探索段太短种群被全局最优引导项快速吸住把探索段比例从1/3调整到0.4或降低前期权值上限后期收敛曲线持续大幅震荡分段权值断点不连续或开发段权值下限仍然太大让断点处权值连续把开发段权值下限降到0.1以下适应度出现NaN或Inf加速度归一化时除数为0或目标函数对越界个体没有保护归一化分母加eps位置越界后先回边界再评估适应度换一个问题后SAOA失效分段权值参数和测试函数特点不匹配根据问题规模重构三段比例不要盲目沿用默认值多次运行结果标准差过大混沌初值没有固定或种群规模太小固定x0种群数保持在20到50之间4.3 再补两个容易被忽略的工程细节工程层面对实验稳定性影响最大的是边界处理时机。我见过很多实现是先更新位置、再算适应度但如果位置更新后个体越界适应度计算就会把搜索方向带偏。正确做法是更新位置后立刻把越界的坐标拉回边界然后再评估适应度。这个顺序不能颠倒。另一个细节是目标函数的数值尺度。如果目标函数的值域非常窄比如都在0到1之间波动那么收敛曲线的下降趋势在视觉上不明显也不利于算法内部的比较。我通常会在目标函数外套一层log变换或符号变换把窄值域映射到对数尺度上这样分段权值的后期步长控制会更敏感。5. 延伸应用从基准函数到BiLSTM与无人机路径规划5.1 用SAOA去搜BiLSTM超参数SAOA在基准函数上表现稳定真正的用武之地还是在模型超参数寻优上。以当前很常见的BiLSTM时间序列预测任务为例假设我们要做电池SOC估计或者负荷预测模型里有几个超参数直接影响精度隐含层神经元数量、初始学习率、L2正则化系数、Batch Size。这些参数组合在一起构成一个高维、非连续、非光滑的优化问题非常适合SAOA去搜索。具体做法是把这些超参数编码成SAOA个体的决策变量。比如维度设为3第一个维度表示隐含层神经元数量搜索范围[8, 128]第二个维度表示学习率搜索范围[0.0001, 0.01]注意学习率要用log尺度编码否则搜索过程会严重偏向大数值区域第三个维度表示L2正则化系数范围[0, 0.01]。适应度函数就定义成BiLSTM在验证集上的RMSE或MAE。每评估一次适应度就要完整训练一次模型所以实际效率瓶颈在模型训练而不在算法本身。用SAOA调这类黑盒超参数的优势是它不需要模型可导也不需要对搜索空间做平滑假设纯粹靠种群进化的方式去寻找好的组合点。相比网格搜索要暴力尝试几百上千组参数SAOA用四五十次评估往往就能逼近同样的效果。5.2 无人机三维路径规划的SAOA落地另一个非常契合的场景是无人机三维路径规划。这类问题的核心是找一条从起点到终点、绕过障碍物且满足约束的平滑路径。常用的策略是把路径离散成一系列路径点把每个路径点的三维坐标作为决策变量目标函数由三部分加权组成路径总长度、障碍物碰撞惩罚项、高度和转弯角的平滑性惩罚项。SAOA在这个场景里的优势依然来自Sin混沌初始化。三维空间里路径规划问题的搜索空间形状复杂随机初始化很容易让路径点全挤在障碍物密集的局部区域导致算法从一开始就被罚函数困住。而Sin混沌初始化的遍历性让初代路径就能分布在空间的不同区域后续探索跳出局部障碍的概率高很多。落地时注意两个老问题一是罚函数权重不能设置过大否则路径点移动的一点点偏差都会带来巨大的适应度跳变算法会变得极度不稳定二是路径点数量的选择点越多路径越平滑但决策变量维数越高搜索难度也随之上升需要在路径质量和计算成本之间做折中。我的经验是三维路径先用6到10个路径点起步配合SAOA的500代迭代已经能在大多数场景下得到可飞路线。5.3 移植到其他问题时的通用套路SAOA的代码结构改造成本很低把它移植到新问题只需要改三处决策变量的编码方式、适应度函数的定义、边界约束的处理。编码方式决定了搜索空间的结构适应度函数决定了算法前进的方向边界处理决定了可行域的硬性限制。移植过程中最常犯的错误是原封不动地把基准测试用的参数搬到实际问题上。现实问题里搜索空间尺度通常很大比如路径规划的坐标范围可能是几百米而基准测试一般是[-100, 100]。这时分段权值的下降斜率不需要改但Sin混沌初始化映射到解空间的公式要重新检查确保lb和ub始终是向量形式避免出现向量与标量之间的维度错位。另一个通用经验是先在低维简化问题上把SAOA跑通确认改进效果之后再加约束、加维度这样排查问题会容易得多。我个人在实际使用中最深的一个体会是SAOA相对标准AOA的收益并不在于某个单次实验的最优值能冲到多低而是整个种群在多峰问题上的稳定性和可复现性提升了。混沌初值固定后每次实验的结果波动范围明显小于rand初始化的版本这在写论文、做算法对比时是特别重要的一项优势。最后再分享一个小技巧如果你需要把SAOA作为论文的一个对比算法一定要把三段分段权值断点对应的迭代代数明确标注出来很多审稿人非常关注这种结构性改进的具体设置这能让你的实验可信度提高不少。