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 模拟退火的运行流程
为了让你更直观地理解这个过程,我画了一张流程图:
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 可能设低了。
模拟退火不是万能的,但它是你全局优化工具箱里一把好用的「瑞士军刀」。掌握好参数调优的节奏,它能在你陷入局部极小值时,帮你打开一扇新的大门。