4. 全局优化算法(二):模拟退火算法(Simulated Annealing)在光学设计中的应用

模拟退火,这名字听着挺物理的。说白了,它就是从金属冶炼里偷师来的一个优化思路。你想想看,金属加热到高温再慢慢冷却,内部晶格会重新排列,最终达到一个能量最低的稳定状态。我们做光学设计时,不也是在找那个「能量最低」——也就是像差最小、评价函数最优——的结构吗?

我最早接触这个算法是在做一款变焦镜头的时候。当时局部优化陷在一个局部极小值里出不来,试了好几个起始点都不行。后来一咬牙上了模拟退火,虽然跑了整整一个周末,但最后确实找到了一个更好的解。嗯,从那以后,我对这个算法就多了几分敬畏。

4.1 模拟退火的核心思想

传统局部优化为什么容易卡住?因为它只接受「变好」的方向。一旦周围全是「变差」的方向,它就停在那了。模拟退火不一样——它允许在优化过程中,以一定的概率接受「变差」的解。

这个概率由两个因素决定:

  • 当前温度 T:温度越高,接受差解的概率越大
  • 评价函数的变化量 ΔE:变差得越多,被接受的概率越小

接受概率的数学形式是:

P(accept) = exp(-ΔE / T)

当 T 很大时,哪怕 ΔE 很大,exp(-ΔE/T) 也接近 1,几乎什么解都敢接受。随着 T 逐渐降低,接受差解的概率越来越小。到了低温阶段,算法就基本退化成局部搜索了。

关键理解:模拟退火不是「乱跳」,而是「有策略地试探」。高温期负责全局探索,低温期负责局部精化。这个「探索-利用」的平衡,是它区别于随机搜索的核心。

4.2 模拟退火在 Code V 中的实现

Code V 的全局优化引擎里,模拟退火是作为 Global Synthesis 的一个子策略存在的。你不需要手动写退火循环,只需要设置几个关键参数。

我一般这样启动一个模拟退火优化:

! 进入全局优化模式
GLO

! 设置模拟退火参数
SA T_START=100 T_END=0.01 COOL_RATE=0.95

! 启动优化
OPT

! 查看优化过程
SA PLOT

这几个参数什么意思?我一个个说:

参数 含义 我的经验值
T_START 起始温度,控制初始探索范围 50~200,结构越复杂取越大
T_END 终止温度,决定收敛精度 0.01~0.001,越小越精细
COOL_RATE 降温速率,每次迭代 T = T * COOL_RATE 0.90~0.98,越接近1跑得越久

我的习惯:第一次跑模拟退火时,我会把 COOL_RATE 设到 0.98,T_START 设到 150。虽然跑得慢,但能确保搜索空间覆盖得足够广。等找到大致区域后,再缩小参数范围做精细优化。

4.3 模拟退火的运行流程

为了让你更直观地理解这个过程,我画了一张流程图:

模拟退火算法运行流程 初始化结构 + 参数 计算当前评价函数 E 随机扰动结构参数 计算新评价函数 E' ΔE = E' - E ΔE ≤ 0 或 P(accept) 通过? 是 → 接受新结构 否 → 保持原结构 降温 T = T × COOL_RATE 重复迭代直到 T ≤ T_END 或达到最大迭代次数

4.4 参数调优的实战经验

参数怎么设,直接决定了模拟退火是「神兵利器」还是「玩具」。我踩过不少坑,分享几个关键点:

起始温度 T_START

设得太低,算法一开始就「冻住」了,跟局部优化没区别。设得太高,前几百次迭代全在瞎跳,浪费时间。

我一般这样估算:先跑一次局部优化,看看评价函数的大致范围。如果评价函数在 10~100 之间波动,T_START 取 50~100 就够。如果评价函数是 1000 量级,T_START 得拉到 200 以上。

降温速率 COOL_RATE

这个参数最坑人。0.99 和 0.95 看起来只差 0.04,但迭代次数差了好几倍。举个例子:

  • COOL_RATE = 0.95,从 100 降到 0.01,需要约 180 次迭代
  • COOL_RATE = 0.99,同样降温范围,需要约 920 次迭代

所以,如果你时间充裕,用 0.98~0.99 慢慢降温,找到的解通常更好。如果只是快速验证,0.90~0.95 就够了。

我曾经犯过的错:有一次做投影镜头设计,我把 COOL_RATE 设成了 0.999,想着「越慢越好」。结果跑了三天三夜还没收敛,最后强行中断了。后来我学乖了——先设 0.95 跑一轮,看看趋势,再决定要不要加细。

扰动幅度

Code V 里没有直接设置扰动幅度的参数,但你可以通过变量范围来控制。我的建议是:

  • 曲率半径:初始扰动范围设为当前值的 ±10%
  • 厚度:设为当前值的 ±5%
  • 非球面系数:设为当前值的 ±20%

随着温度降低,扰动幅度会自动缩小,这是模拟退火内置的机制。

4.5 模拟退火 vs. 其他全局算法

很多学员问我:「模拟退火和遗传算法,到底哪个好?」我的回答是——看场景。

对比维度 模拟退火 遗传算法 我的选择建议
收敛速度 中等,受降温速率影响大 较慢,需要多代进化 时间紧选模拟退火
全局搜索能力 强,高温期能跳出局部陷阱 很强,种群多样性保证覆盖 结构复杂选遗传算法
局部精化能力 弱,低温期精度有限 弱,需要配合局部优化 两者都需要后处理
参数调优难度 中等,3~4个关键参数 较高,种群大小、交叉率、变异率 新手先试模拟退火
适用场景 中等复杂度、变量数 20~50 高复杂度、变量数 50+ 根据变量数选择

我的实战策略:先用模拟退火跑一轮快速扫描,找到几个有潜力的区域。然后把这些区域作为起始点,用局部优化做精化。如果模拟退火的结果不满意,再上遗传算法做更彻底的搜索。这个「先快后慢、先粗后细」的思路,帮我省了不少时间。

4.6 一个完整的实战案例

最后,我给你看一个我实际用过的脚本。这是一个 4 片式手机镜头,变量包括 6 个曲率半径和 2 个非球面系数:

! 加载镜头文件
IN lens.len

! 设置变量
VARIABLE
  CURV 1 2 3 4 5 6
  ASP 1 2

! 进入全局优化
GLO

! 设置模拟退火参数
SA T_START=80 T_END=0.01 COOL_RATE=0.96

! 设置评价函数
AUT

! 开始优化
OPT

! 保存中间结果
SA SAVE "sa_intermediate.len"

! 优化完成后,用局部优化精化
GLO OFF
OPT

! 查看最终结果
LIS

这个脚本跑完大概需要 2~3 小时(看电脑配置)。优化完成后,我一般会对比一下模拟退火前后的评价函数值——通常能下降 30%~50%。

一个小技巧:模拟退火跑完后,别急着关。用 SA PLOT 命令看一下评价函数随迭代的变化曲线。如果曲线在低温段还在剧烈波动,说明降温太快了,下次把 COOL_RATE 调大一点。如果曲线早早平了,说明 T_START 可能设低了。

模拟退火不是万能的,但它是你全局优化工具箱里一把好用的「瑞士军刀」。掌握好参数调优的节奏,它能在你陷入局部极小值时,帮你打开一扇新的大门。