光学设计遇上深度学习:代理模型与可微分光线追迹实战

发布时间:2026/9/29 17:26:55
光学设计遇上深度学习:代理模型与可微分光线追迹实战 1. 光学设计与仿真为什么开始“吃”深度学习1.1 从“手动调参”到“模型驱动”的转变做光学设计的人都有一个共同体会Zemax里那几个优化函数一挂锤形优化跑一晚上第二天打开一看MTF是上去了一点但公差敏感度直接爆炸。传统光学设计的核心矛盾在于——设计变量多、评价函数非线性强、全局最优解难找。一个典型的手机镜头设计涉及十几片镜子的曲率、厚度、间距、非球面系数变量轻松上百个而评价函数里又同时塞了MTF、畸变、色差、相对照度、公差敏感度等一堆指标。这种高维非凸优化问题传统局部优化算法很容易陷进局部极小值。深度学习进来之后思路变了。不是让神经网络去替代Zemax的优化算法而是用神经网络学习“结构参数→光学性能”的映射关系把原本需要跑一次光线追迹才能得到的评价指标变成一个前向推理就能预测的代理模型。这个代理模型一旦训练好推理速度比实际光线追迹快三到四个数量级。这意味着什么意味着你可以用遗传算法、粒子群算法在代理模型上疯狂搜索全局最优解搜完之后再用Zemax做精确验证。整个设计流程从“优化-验证-再优化”的串行模式变成了“代理模型全局搜索-精确验证”的并行模式。我去年帮一个做车载镜头的小团队搭过这套流程。他们原本设计一款170度超广角镜头光靠Zemax锤形优化前后改了三个月MTF始终在0.3左右晃。后来用PyTorch搭了一个简单的全连接网络输入是8个镜片的曲率和厚度输出是MTF和畸变训练数据用Zemax的ZOS-API批量生成大概跑了8000组样本。代理模型训练完之后用差分进化算法在参数空间里搜了两天找到一组解丢回Zemax验证MTF直接到了0.45畸变还比原来小。整个周期压缩到三周。1.2 计算成像给光学设计带来的新维度传统光学设计的边界很清晰镜头负责成像传感器负责光电转换图像处理负责后处理。但计算成像把这个边界打穿了。现在做光学设计你不能只考虑“镜头能不能把光聚好”还得考虑“后端算法能不能把图像恢复好”。这就意味着光学系统和图像恢复算法需要联合优化。举个例子现在很多手机厂商在做的“超透镜计算重建”方案。超透镜的色差很大传统光学看来这是致命缺陷但如果后端有一个训练好的去色差网络这个缺陷反而变成了“可编码的信息”。光学设计师需要做的是设计一个“对算法友好”的点扩散函数而不是一个“人眼看起来完美”的点扩散函数。这种设计思路的转变直接导致光学设计师必须懂深度学习——你不懂就没法跟算法团队对话没法定义联合优化的损失函数。PyTorch在这个环节里扮演的角色很关键。因为计算成像的联合优化本质上是一个端到端的可微分系统。光学传播可以用可微分的光线追迹或者波前传播模型来表示图像恢复网络用PyTorch搭整个系统串起来做反向传播梯度可以从最终的图像质量一路传回镜头的面型参数。这种“光学-算法联合训练”的范式已经在超分辨、去模糊、深度估计等任务上验证了有效性。1.3 谁适合看这篇内容如果你是在读的 optics 方向硕士或博士正在纠结要不要学深度学习我的建议是学而且越早越好。不是让你转行去做纯算法而是让你在光学设计的工具箱里多一把锤子。你不需要成为PyTorch专家但你需要能看懂CNN的基本结构能自己搭一个简单的代理模型能用ZOS-API或者Lumerical的Python接口批量生成训练数据。如果你是从业多年的光学工程师对深度学习完全陌生也不用慌。你不需要从头学反向传播的数学推导你只需要理解三件事神经网络是一个万能函数逼近器、训练就是调参数让预测误差最小、推理就是一次前向计算。剩下的PyTorch的教程和文档已经足够详细了。2. 核心细节解析光学仿真与深度学习的结合点2.1 代理模型用神经网络替代光线追迹代理模型是光学设计里最容易落地的深度学习应用。它的核心逻辑很简单光线追迹本质上是一个确定性计算给定镜头结构参数和视场、波长配置输出是确定的MTF、点列图、畸变等指标。既然输入输出都是确定的那就可以用神经网络去拟合这个映射。具体怎么做第一步是定义输入输出空间。输入通常是镜头的结构参数向量比如曲率半径、厚度、空气间隔、非球面系数、材料折射率等。输出是光学性能指标比如特定空间频率下的MTF值、最大畸变、场曲、色差等。输入输出的维度决定了网络的规模。一般来说输入维度在10到50之间输出维度在5到20之间用3到5层全连接网络每层128到512个神经元就能达到不错的拟合精度。第二步是生成训练数据。这是最耗时的环节但也是最关键的。你需要用Zemax的ZOS-API或者Lumerical的Python API批量修改镜头参数然后运行光线追迹把输入输出对存下来。这里有个经验采样策略比样本数量更重要。如果你用均匀采样很多样本会落在明显不可用的参数区域浪费计算资源。更好的做法是用拉丁超立方采样或者基于初始设计的局部扰动采样保证样本在“有意义的参数空间”里分布均匀。第三步是训练和验证。损失函数用MSE就行优化器用Adam学习率从1e-3开始配合余弦退火。训练集和验证集按8:2划分如果验证集损失开始上升就早停。这里有个坑光学性能指标的量纲差异很大。MTF是0到1之间的无量纲数畸变可能是百分比场曲可能是微米量级。如果不做归一化网络会偏向拟合数值大的指标忽略数值小的。所以训练前一定要对输出做标准化让每个指标的均值为0、方差为1。2.2 可微分光线追迹让梯度穿过光学系统代理模型是“黑盒”思路可微分光线追迹是“白盒”思路。它的目标是让整个光学传播过程可微分这样梯度可以从最终的图像质量一路传回镜头的面型参数实现真正的端到端优化。可微分光线追迹的实现方式有两种。一种是解析法直接对光线追迹的公式求导。Snell定律、传输矩阵、非球面公式都是解析表达式理论上可以手动推导梯度。但实际操作中非球面系数的高阶项求导很繁琐容易出错。另一种是自动微分用PyTorch或者JAX把光线追迹的每一步都写成可微分操作让框架自动算梯度。这种方式更灵活也更容易调试。我试过用PyTorch实现一个简化的可微分光线追迹模型。核心是把每个面的折射写成PyTorch的tensor操作然后用torch.autograd自动求导。具体来说光线用一个方向向量和一个起点表示每经过一个面先算入射角再用Snell定律算折射角然后更新方向向量和起点。非球面的话面型公式是高度的多项式求导用PyTorch的自动微分就行。整个模型跑通之后你可以把镜头参数设为requires_gradTrue然后定义一个损失函数比如“目标MTF和当前MTF的差距”直接调loss.backward()梯度就出来了。这种方法的优势在于联合优化。你可以把光学系统和图像恢复网络串在一起损失函数定义在最终图像上梯度会同时更新镜头参数和网络权重。我见过一个做显微成像的团队用这种方式优化一个物镜和去卷积网络的联合系统最终的分辨率比单独优化物镜再单独训练网络高了将近30%。2.3 计算成像中的深度学习从端到端到物理感知计算成像的范围很广包括超分辨、去模糊、深度估计、光谱重建等。深度学习在这些任务上的应用已经非常成熟但光学设计师需要关注的是物理感知的网络设计。什么意思普通的图像恢复网络输入是一张退化图像输出是恢复图像网络结构是黑盒。但在计算成像里退化过程是有物理模型的比如PSF卷积、噪声叠加、下采样。如果你把这个物理模型嵌入网络让网络只学习“物理模型无法解释的部分”训练效率和泛化能力都会大幅提升。一个典型的例子是基于PSF卷积的去模糊网络。传统做法是直接用CNN做图像到图像的映射但这样网络需要同时学习PSF的形状和逆卷积操作训练数据需求大泛化差。更好的做法是先把PSF作为已知条件输入网络网络只学习“如何根据PSF做逆卷积”。这样网络参数量可以减少一半训练样本需求也大幅下降。PyTorch在这个环节的优势是灵活。你可以用torch.nn.Conv2d搭CNN也可以用torch.fft做频域操作还可以用torch.autograd自定义物理传播层。这种灵活性让物理感知的网络设计变得非常方便。3. 实操过程从零搭建光学设计代理模型3.1 环境搭建与工具链选择先说环境。做光学设计深度学习工具链的选择很关键。我的推荐是Zemax Python PyTorch。Zemax负责精确的光线追迹和数据生成Python负责数据处理和流程控制PyTorch负责网络训练和推理。Zemax的ZOS-API支持Python调用这是整个流程的基础。你需要安装Zemax的Python库通常叫pyzemax或者直接用ZOS-API的COM接口。安装完之后先测试一下能不能打开Zemax、加载镜头文件、修改参数、运行优化、读取MTF。这一步跑通了后面就顺了。PyTorch的安装现在很简单去官网复制命令就行。如果你有NVIDIA显卡建议装CUDA版本训练速度会快很多。没有显卡也没关系代理模型的网络规模不大CPU训练也能接受就是慢一点。安装完之后用torch.cuda.is_available()检查一下GPU是否可用。数据处理用numpy和pandas就够了。可视化用matplotlib画MTF曲线、损失曲线、散点图都很方便。整个工具链的依赖不多环境搭建半天就能搞定。3.2 数据生成用ZOS-API批量跑光线追迹数据生成是整个流程里最耗时的环节但也是最关键的。我的做法是写一个Python脚本循环执行以下步骤加载初始镜头文件.zmx随机扰动镜头参数曲率、厚度、间距等运行光线追迹读取MTF、畸变、场曲等指标把参数和指标存成CSV这里有几个细节需要注意。第一扰动范围要合理。如果你完全随机采样很多样本会落在明显不可用的区域比如曲率半径变成负数、厚度变成零。更好的做法是在初始设计的基础上做局部扰动扰动幅度控制在±10%到±20%之间。第二要处理失败样本。有些参数组合会导致光线追迹失败Zemax会报错。这时候要捕获异常跳过这个样本不要让它中断整个流程。第三要保存中间状态。数据生成可能跑几个小时甚至几天万一中途断电或者程序崩溃没有保存就全白跑了。建议每生成100个样本就存一次盘。样本数量方面我的经验是输入维度在20以内5000到10000个样本就够用了。如果输入维度更高比如非球面系数也作为变量那可能需要20000个以上。但也不是越多越好超过一定数量后模型精度提升会变得很慢边际收益递减。3.3 网络搭建与训练一个可复现的PyTorch模板网络结构不用太复杂全连接网络就够。下面是一个我常用的模板import torch import torch.nn as nn class OpticalProxyNet(nn.Module): def __init__(self, input_dim, output_dim, hidden_dim256): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.BatchNorm1d(hidden_dim), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.BatchNorm1d(hidden_dim), nn.Linear(hidden_dim, hidden_dim // 2), nn.ReLU(), nn.Linear(hidden_dim // 2, output_dim) ) def forward(self, x): return self.net(x)训练循环也很标准model OpticalProxyNet(input_dim20, output_dim8) optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max200) criterion nn.MSELoss() for epoch in range(200): model.train() for x_batch, y_batch in train_loader: optimizer.zero_grad() pred model(x_batch) loss criterion(pred, y_batch) loss.backward() optimizer.step() scheduler.step() # 验证 model.eval() with torch.no_grad(): val_loss 0 for x_val, y_val in val_loader: val_loss criterion(model(x_val), y_val).item() print(fEpoch {epoch}, Val Loss: {val_loss / len(val_loader):.6f})这里的关键是输入输出的归一化。输入用StandardScaler做标准化输出也要做标准化。训练完之后推理时记得把输出反归一化回原始量纲。3.4 代理模型上的全局优化差分进化实战代理模型训练好之后就可以在上面跑全局优化了。我常用的是差分进化算法因为它的参数少、鲁棒性好。scipy.optimize.differential_evolution就能用目标函数定义为“代理模型预测的MTF与目标MTF的差距”。具体做法是定义一个目标函数输入是镜头参数向量输出是一个标量损失。损失可以定义为(1 - MTF_avg)^2 lambda * distortion^2其中lambda是权重用来平衡MTF和畸变的重要性。然后调differential_evolution设置参数边界、种群大小、最大迭代次数跑完之后拿到最优参数丢回Zemax验证。这里有个经验代理模型的预测精度决定了全局优化的效果。如果代理模型在某个区域的预测误差很大优化算法可能会找到一组“代理模型认为很好但实际很差”的参数。所以在优化之前一定要检查代理模型在验证集上的精度。如果MTF的预测误差超过0.05那优化结果就不可信。这时候需要补充训练数据或者换一个更复杂的网络结构。4. 常见问题与排查技巧实录4.1 数据生成阶段的典型坑问题一ZOS-API连接失败。这是最常见的问题通常是因为Zemax的版本和Python库不匹配。解决方法是检查Zemax的安装路径确保COM接口注册正确。如果用的是Zemax OpticStudio需要在设置里开启“Allow API connections”。问题二光线追迹失败率过高。如果超过30%的样本追迹失败说明参数扰动范围太大了。缩小扰动幅度或者加一个“参数合理性检查”把明显不合理的参数组合提前过滤掉。问题三数据生成速度太慢。Zemax的光线追迹是单线程的跑一万个样本可能要十几个小时。加速的方法有两个一是用Zemax的批量模式减少界面刷新开销二是用多进程同时开多个Zemax实例跑不同的样本。但要注意多进程会占用大量内存机器配置不够的话反而更慢。4.2 训练阶段的典型坑问题一损失不下降。最常见的原因是学习率太大或者太小。先试1e-3如果损失震荡就降到1e-4如果下降太慢就升到1e-2。另外检查输入输出是否归一化没归一化的话训练很难收敛。问题二过拟合。训练集损失很低验证集损失很高。解决方法是加Dropout层、减小网络规模、增加训练数据。我一般会在全连接层后面加nn.Dropout(0.2)效果不错。问题三预测精度不够。如果验证集上的MTF预测误差始终大于0.05说明网络容量不够或者数据量不够。先增加网络宽度hidden_dim从256加到512如果还不行就补充训练数据。4.3 优化阶段的典型坑问题一优化结果在Zemax里验证不通过。这说明代理模型在最优解附近的预测不准。解决方法是在最优解附近补充采样用Zemax重新跑一遍把新数据加入训练集重新训练代理模型。这个过程可能需要迭代两三次。问题二优化算法陷入局部最优。差分进化的种群大小和变异因子需要调。种群大小一般设为参数维度的5到10倍变异因子在0.5到0.9之间调。如果还是陷入局部最优可以多跑几次每次用不同的随机种子。问题三优化时间太长。代理模型的推理速度虽然快但如果参数维度很高比如超过50维差分进化的搜索空间会非常大。这时候可以考虑降维用PCA把参数空间压缩到20维以内再跑优化。4.4 常见问题速查表问题现象可能原因排查方法解决方案ZOS-API连接失败版本不匹配或API未开启检查Zemax设置和Python库版本开启API连接重装匹配版本的库光线追迹失败率高参数扰动范围过大统计失败样本的参数分布缩小扰动幅度加参数合理性检查训练损失不下降学习率不当或未归一化检查学习率和数据分布调整学习率做标准化验证集损失上升过拟合对比训练集和验证集损失加Dropout减小网络增加数据代理模型预测误差大网络容量或数据量不足检查验证集误差增加网络宽度补充训练数据优化结果验证不通过代理模型在最优解附近不准在最优解附近采样验证补充采样重新训练代理模型优化陷入局部最优差分进化参数不当检查种群大小和变异因子调参多跑几次不同种子5. 光学设计师学深度学习的路径建议5.1 不要从数学推导开始很多光学背景的人学深度学习第一反应是去啃《深度学习》花书从反向传播的链式法则开始推。我的建议是不要。除非你要做算法研究否则没必要把梯度推导搞得那么清楚。你只需要理解“神经网络是一个可训练的函数逼近器”知道怎么搭网络、怎么训练、怎么评估就够了。更好的路径是先跑通一个PyTorch的官方教程比如MNIST手写数字识别。跑通之后把数据换成你自己的光学数据把网络改成全连接网络把损失函数改成MSE。这个过程可能只需要一周你就能搭出一个能用的代理模型。5.2 从代理模型入手逐步深入代理模型是最容易落地的切入点。它不需要你理解可微分光线追迹也不需要你设计复杂的网络结构。你只需要会调ZOS-API、会搭全连接网络、会跑训练循环。这个门槛很低但收益很直接——你的光学设计优化效率会大幅提升。代理模型跑通之后可以尝试更深入的方向。比如可微分光线追迹用PyTorch实现一个简化的光线追迹模型让梯度穿过光学系统。再比如物理感知的网络设计把PSF卷积嵌入网络做联合优化。这些方向的门槛更高但价值也更大。5.3 工具链的持续维护光学设计和深度学习的工具链都在快速迭代。Zemax每年更新PyTorch每几个月更新CUDA版本也在变。我的经验是不要盲目追新。如果你的工具链能跑通就不要轻易升级。升级之前先在虚拟环境里测试确认所有依赖都兼容再迁移。另外代码要模块化。数据生成、网络定义、训练循环、优化算法每个环节都写成独立的函数或类。这样当某个环节需要修改时不会影响其他部分。我见过很多人把整个流程写在一个脚本里改一行代码就全崩了调试起来非常痛苦。5.4 团队协作中的沟通要点如果你在团队里推动这件事沟通很重要。光学设计师和算法工程师的语言体系不一样。光学设计师说“MTF”“畸变”“场曲”算法工程师说“损失函数”“梯度”“过拟合”。你需要做的是建立共同的评价指标。比如把光学性能指标统一映射到一个0到1的“质量分数”这样双方都能理解。另外数据格式要统一。光学数据用CSV或者HDF5存图像数据用PNG或者numpy数组存。接口定义清楚输入是什么、输出是什么、量纲是什么。这些细节看起来琐碎但能省掉大量沟通成本。6. 一个完整的实战案例超广角镜头代理模型优化6.1 项目背景与目标去年我参与了一个车载超广角镜头的设计项目。镜头规格是焦距1.8mmF数2.0视场角170度适配1/2.7英寸传感器。初始设计是一个6片式结构MTF在50lp/mm处只有0.25畸变超过30%。目标是把MTF提升到0.4以上畸变控制在25%以内。传统优化方法跑了两个月效果不明显。后来决定用代理模型全局优化的方案。整个项目从数据生成到最终验证用了三周时间。6.2 数据生成与网络训练输入参数选了12个6片镜子的曲率半径、厚度、空气间隔。输出选了4个中心MTF、边缘MTF、最大畸变、场曲。用ZOS-API批量生成数据扰动幅度控制在初始设计的±15%以内共生成8000个有效样本。网络用3层全连接每层256个神经元ReLU激活Dropout 0.2。训练200个epoch学习率1e-3余弦退火。最终验证集上的MTF预测误差在0.03以内畸变预测误差在2%以内。6.3 全局优化与验证用差分进化算法在代理模型上搜索目标函数是(1 - MTF_avg)^2 0.5 * (distortion / 30)^2。种群大小100迭代500代跑了大概6个小时。找到的最优解丢回Zemax验证MTF提升到0.42畸变降到24%场曲也改善了。这个结果比传统优化方法好了不少而且周期从两个月压缩到三周。后来这个方案被固化成了团队的标准流程新项目都先跑代理模型优化再做精细调整。6.4 踩过的坑与经验总结这个项目里最大的坑是数据生成阶段的失败样本处理。一开始没做异常捕获跑了几千个样本之后程序崩溃之前的数据全丢了。后来改成每100个样本存一次盘并且加了异常捕获失败样本直接跳过。另一个坑是代理模型的泛化能力。训练集上的误差很小但优化出来的参数在Zemax里验证时MTF比预测值低了0.08。后来在最优解附近补充了500个样本重新训练代理模型第二次优化结果的验证误差就降到了0.02以内。经验就是代理模型不是一次训练就完事的需要迭代。先用初始数据训练一个粗略的模型跑一轮优化在最优解附近补充数据再训练再优化。两到三轮之后模型精度就足够了。7. 光学仿真与深度学习结合的未来方向7.1 从代理模型到端到端联合优化代理模型只是第一步。更彻底的做法是端到端联合优化光学系统用可微分光线追迹表示图像恢复用CNN表示整个系统串起来做反向传播。这种范式在计算成像领域已经有很多成功案例比如超透镜设计、无透镜成像、编码孔径成像。端到端联合优化的挑战在于梯度传播的稳定性。光学传播的梯度可能很小或者很大导致训练不稳定。解决方法包括梯度裁剪、残差连接、分阶段训练等。这些技巧在常规深度学习里很成熟迁移到光学领域需要做一些适配。7.2 物理感知的网络架构设计纯粹的CNN是黑盒物理感知的网络是灰盒。灰盒的好处是泛化能力强、训练数据需求小。在光学领域物理感知的网络设计有很多可能性。比如把PSF卷积作为网络的一层把光线追迹作为可微分层把噪声模型作为概率层。这些设计需要光学和深度学习的交叉知识也是未来最有价值的方向。7.3 工具链的融合趋势Zemax、Lumerical、COMSOL这些光学仿真软件都在加强Python接口。PyTorch、JAX这些深度学习框架也在加强科学计算能力。两者的融合是必然趋势。未来可能出现专门的“光学深度学习”工具链把光线追迹、波前传播、网络训练、全局优化集成在一起。对于光学设计师来说掌握Python和PyTorch就是为这个趋势做准备。我在实际项目里的体会是不要等到工具链成熟了再学那时候就晚了。现在就开始用Python调ZOS-API用PyTorch搭代理模型哪怕只是跑通一个简单的流程也比观望强。光学设计的门槛正在从“会调Zemax”变成“会调Zemax会调PyTorch”这个趋势已经很明显了。最后分享一个小技巧如果你觉得从头搭代理模型太麻烦可以先从“参数扫描简单拟合”开始。用ZOS-API批量跑几百个样本用scipy.interpolate做插值也能起到类似代理模型的效果。虽然精度不如神经网络但门槛低很多适合快速验证想法。等跑通了再换成PyTorch网络循序渐进。