ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

用光做卷积:微透镜阵列光学计算系统解析

用光做卷积:微透镜阵列光学计算系统解析 简介文档围绕微透镜阵列光学实现卷积运算展开面向光子计算、光学神经网络与图像处理方向的研究者和工程师聚焦如何以微透镜阵列结合透镜构建光学系统在光域模拟二维卷积操作以突破电子计算在速度与能耗上的瓶颈。内容从二维离散卷积的same、valid、full类型入手逐步讲解系统结构设计与矩阵解释微透镜阵列将输入图像划分为窗口并并行匀光透镜L1/L2完成乘加运算P2处可放置强度调制元件作为卷积核并通过理论推导说明该结构能实现任意正值的传输矩阵。全文给出清晰的公式、结构示意图和可行性分析可帮助读者理解光学卷积层的原理也可为光学卷积神经网络中的卷积与池化层硬件实现提供参考。压缩包内为1个docx格式文档约207KB篇幅精炼但知识点集中适合科研入门或课程设计参考。截至当前已有120人学习。1. 光学卷积做一个乘法为什么值得兴师动众做过图像处理的人都知道一张 512×512 的图过一遍 3×3 卷积理论上要跑 26 万次乘加。到了 CNN 里这个量还要再乘上通道数和层数训练一次 ResNet 的浮点运算量是以亿为单位的。传统电子芯片靠晶体管吞吐这些计算功耗和延迟都压在这个乘法器上摩尔定律放缓之后大家开始琢磨能不能换个介质来做矩阵乘法。光有一个天然优势光子不带电荷互相穿过不干扰透镜一照就是二维并行一次传播完成的乘加数量取决于空间分辨率而不是时钟频率。这篇文章拆的项目就是把「输入图像和卷积核做卷积」这件事用微透镜阵列配合两片透镜在光路上直接算出来。输出端放个 CMOS 就能读结果电学部分只负责加载数据和接收光强。适合对光学计算、光电混合加速、以及想把成像系统做成计算单元的人读。2. 把滑动窗口看成共享权重卷积的矩阵乘法本质2.1 从二维离散卷积到矩阵乘法要理解光学怎么做卷积得先把卷积的运算形式换一种写法。假设输入图像为x [[6, 3, 5], [2, 7, 1], [3, 1, 2]]卷积核为 k [[4, 2], [1, 5]]步长为 1做 valid 卷积输出中的第一个元素是左上角 2×2 窗口与核逐元素相乘再求和也就是 6×4 3×2 2×1 7×5。这个逐窗口的「乘加」在数学上可以重排成一次矩阵乘法把每个窗口内的像素按列堆叠成一个列向量把所有窗口对应的列向量拼在一起再把卷积核拉成一行。这样整个卷积就变成了一行向量乘以一个矩阵。y [4, 2, 1, 5] × [[6, 3, 2, 7], [3, 5, 7, 3], [2, 7, 1, 1], [7, 1, 1, 2]]可以验证这个结果按列展开恰好就是滑动窗口卷积的输出。这个变换的意义在于它让「卷积」与「矩阵乘法」之间画了等号。矩阵乘法在光路里是可以直接实现的——用一个强度调制面给每个光线乘一个系数再用透镜把同一组的乘积光强叠加到一个点上。下面要讲的光学系统本质上就是在做这件事。2.2 三种卷积类型的光学实现差异卷积按边界处理方式分为 full、same、valid 三种区别只在于输入图像边缘是否补零、输出尺寸如何裁剪。在光学实现里这对应的是输入面加载图像时是否在边缘补黑色像素也就是让对应位置的像素透射率为 0。补零本身不需要额外器件只需要在空间光调制器加载图案时把边缘像素设成不透光状态。卷积类型输出尺寸仅限奇数核光学实现方式注意事项valid(H-kh1) × (W-kw1)输入直接投影不做边缘处理输出面尺寸最小光能利用率低sameH × W输入边缘补 (kh-1)/2 圈零需保证补零像素透射率严格为 0full(Hkh-1) × (Wkw-1)输入边缘补 kh-1 圈零输出面范围最大需要更大的探测器2.3 光学实现卷积的三个前提条件从上面的矩阵乘法表示可以看出光学系统要做的事情实际上只有两件乘法——每个像素乘上对应的核系数加法——同一个窗口内乘完的结果在输出面叠加到一起。要完成这两件事需要满足三个前提第一能把输入图像按窗口划分成互不重叠的小块并且每个小块能独立走一条光路。第二每个小块内相同位置的像素需要被乘上相同的系数这要求来自不同窗口、但窗口内位置相同的光线在调制面上落在同一个位置。第三调制之后同一个窗口内的光线需要被重新汇聚到一起这样才能完成求和。微透镜阵列恰好同时满足前两个前提每一个微透镜单元对应一个窗口而微透镜单元的周期性排列让不同窗口中位置相同的光线具有相同的出射方向从而在透镜焦平面上汇聚到同一个点。这个「方向相同即聚焦同点」的原理是整个系统的核心机制。3. 微透镜阵列卷积系统的结构与核心参数3.1 系统光路布局整个光学系统的结构沿光轴方向依次是输入面 P0 → 微透镜阵列 MLA → 透镜 L1 → 强度调制面 P2 → 透镜 L2 → 输出面。其中微透镜阵列上每个透镜单元的焦距为 f1L1 的焦距为 f2L2 的焦距为 f3。输入图像放置在微透镜阵列的前焦面附近光经过 MLA 后被分割成与窗口数量一致的子光束每一束子光束经过 L1 后在 P2 面上形成一个与窗口内像素排列对应、但来自不同窗口相同位置的信息被叠合在一起的强度分布。3.2 微透镜尺寸与窗口划分微透镜单元的尺寸直接决定了卷积核的窗口大小。假设输入是 4×4 的图像卷积核是 2×2、步长为 2那么图像被划分为 4 个不重叠的 2×2 窗口每个窗口对应一个微透镜单元。窗口划分的关键约束是步长必须等于窗口尺寸否则相邻窗口之间会有间隙或重叠光学上就无法用固定的微透镜阵列一次完成划分。这一点在后面的应用部分会再讨论如何用预处理绕开限制。需要特别强调的是微透镜阵列在这里的作用并不是成像而是做「方向编码」。每个微透镜把窗口内的四条光线变成四束具有不同出射角的光线不同窗口内位于相同相对位置的光线由于在各自微透镜上的入射位置相同出射角也相同。L1 的作用就是把方向相同的光线汇聚到 P2 面上同一个点——同方向的光线经过薄透镜后汇聚于焦平面同一点这是几何光学的基本性质。于是 P2 面上接收到的分布就是按窗口内相对位置排列的、来自所有窗口对应位置的叠加。3.3 关键器件与参数表实际搭建时器件的选型比公式推导要更敏感。下面是这类系统的典型参数及选择理由参考自类似的「光学卷积 / 光学 4f 系统」工程实现器件典型参数选型理由与注意事项微透镜阵列 MLA单元节距 0.5~2 mmf1 5~20 mm单元尺寸必须与图像像素尺寸匹配节距过小时 MLA 加工公差会直接导致窗口间串扰透镜 L1f2 100~200 mm焦距越长P2 面的光斑越大越容易对准强度调制元件但系统总长也会增加强度调制面 P2超表面或 SLM透过率 0~1超表面无源、响应快但一旦制作完成不可编程SLM 可编程但刷新率受限透镜 L2f3 80~150 mm与 L1 配合组成成像系统需要满足输出实像条件见下文公式探测器CMOS 或 CCD放置在 L2 的像方焦平面附近需要与 P2 的像面共轭3.4 实像输出条件P2 面经过强度调制以后光线方向没有被改变因此只是让每个像素的振幅乘上了一个系数。要完成窗口内求和需要让这些光线经过 L2 成像到输出面。这里有一个需要留意的约束由于 L1 已经将同方向光线汇聚到 P2而 P2 处相当于次级光源L2 加上 L1 的组合等效焦距与物距之间的关系决定了输出面能否得到实像。设计时需要满足L f2 × f3 / Δ其中 L 是 P1 物面到等效系统主面的距离Δ 是 L1 后焦面到 L2 的距离。这个条件如果不满足输出面得到的是虚像CMOS 无法直接接收。实际工程中我一般会先按这个公式估算 L 的范围再用 Zemax 或 CODE V 做一遍真实光线追迹验证因为公式是基于理想薄透镜的实际厚透镜的主面位置会有偏移。4. 只能做 0~1 的正核酉矩阵与光学系统的算力边界4.1 线性无损系统的传输矩阵为什么是酉矩阵把光路看成一个线性系统输入是一个向量 [m, n]^T经过一个传输矩阵 T [[a, b], [c, d]] 后输出 [h, k]^T。如果系统是无损的能量守恒要求输入输出模长相等即m² n² h² k² (a² b²)m² (c² d²)n² 2(ac bd)mn由于该等式对任意 m、n 都要成立所以必须有a² b² 1 c² d² 1 ac bd 0这正是酉矩阵的定义条件。也就是说任何只由透镜、反射镜、棱镜构成的无源光学系统其传输矩阵必然是酉矩阵。换句更直白的话说透镜只能重新分配光能量不能让总能量变多。4.2 振幅调制与奇异值分解的对应关系在当时设计的系统里P2 面上的强度调制元件超表面是一个关键器件。它只改变光线的振幅不改变传播方向数学上对应一个对角矩阵——每个元素是某个空间位置上的透过率值域为 [0, 1]。从奇异值分解的角度看任意一个矩阵 M 都可以写成M U Σ V†其中 U 和 V 都是酉矩阵Σ 是对角矩阵。在光路中L1 与 L2 组成的成像系统分别充当 U 和 V 的角色而 P2 处的强度调制面充当 Σ。表面上看似乎任意矩阵的奇异值分解都能在光路上找到对应元件从而实现任意的传输矩阵。但实际上这里有一个微妙的限制成像系统的传输矩阵虽然是酉矩阵但它是固定的——L1 和 L2 的相对位置一旦确定U 和 V 就被冻结了只有 Σ 是可调的而且只能取主对角线为非负实数、且每个元素在 0 到 1 之间的对角矩阵。4.3 这意味着什么这带来两个层面的结论。第一这个光学系统可以实现任意非负卷积核——因为任何非负矩阵都可以通过调节 P2 面的透过率分布来直接编码。高斯平滑、均值滤波这些正算子可以直接做。第二它无法直接实现含负系数的卷积核比如 Prewitt、Sobel、拉普拉斯算子。这倒不是说光学卷积就此失效而是需要在算法层面做等价变换把负系数拆成两个正核的差分或者给整个核加一个正偏置、再做一次光强相减。具体做法在后面的应用部分展开。能力项电学卷积该光学系统说明核的取值任意实数/复数仅 0~1 正实数负核需拆分成多次正核运算核的更新速度纳秒级超表面不可变 / SLM 毫秒级训练阶段用 SLM推理阶段用固定超表面并行度取决于 GPU 核心数空间并行一行光路处理整幅图像对高分辨率图像优势明显精确度浮点精度受光学噪声与元件公差影响约 8-bit 等效适合推理不适合高精度训练由于这种结构天然只能做正值卷积核想把它嵌入到 CNN 里当作卷积层需要在网络设计时就把核的取值约束到 [0,1]或者在网络输出前加一个激活/裁剪操作。这在一些量化神经网络如 BinaryNet、DoReFa-Net里反而是一种自然的匹配。如果目标算子含负值我一般会采用「双通道差分」的做法即将负核分解为两个正核运算后再相减作为后续在实验中验证的方案。5. 用光线追迹验证系统可行性传输矩阵仿真与参数调试5.1 光线传输矩阵建模在搭建真实光路之前可以用几何光学的传输矩阵方法做一次数值仿真验证上述「窗口划分 → 聚焦 → 调制 → 叠加」的各个环节是否成立。把一条光线表示为一个三维向量 [r, θ, e]^Tr 是光线距主光轴的高度θ 是与光轴的夹角e 是光强。自由空间传播距离 L、薄透镜、强度调制面的传输矩阵分别写为import numpy as np def propagate(L): # 自由空间传播距离 L return np.array([[1, L, 0], [0, 1, 0], [0, 0, 1]]) def thin_lens(f): # 薄透镜焦距 f只改变方向不改变高度和强度 return np.array([[1, 0, 0], [-1 / f, 1, 0], [0, 0, 1]]) def amplitude_mask(tau): # 强度调制面tau 为透射率(0~1) return np.array([[1, 0, 0], [0, 1, 0], [0, 0, tau]])三个矩阵对应三种物理过程光在均匀介质中直线传播经过薄透镜发生偏折经过调制面只改变振幅。特别要注意的是这种三维向量表示法把光强放在向量第三维因此调制面矩阵第三行乘上透射率 τ而前两行空间与角度不变对应「不改变传播方向」。5.2 微透镜阵列的光轴偏移处理微透镜阵列与单片透镜的关键区别在于每个微透镜单元有自己的光轴而矩阵追迹默认以主光轴为参考。因此在追迹到 MLA 前表面时需要为每条光线加上一个光轴偏移量 offset 单元序号 × 单元节距使其以自己所属微透镜的光轴为参考完成该微透镜的折射计算后再减去同一个偏移量将参考轴恢复为主光轴。这一步如果漏掉光线的角度会完全错误后续所有聚焦位置都不对。代码段中体现为# 假设一个一维 MLA节距 p单元数为 n offsets np.arange(n) * p # 入射光线追迹到 MLA 前表面 rays np.vstack([r, theta, intensity]) # 切换到各微透镜自己的光轴坐标系 rays_local rays.copy() rays_local[0] - offsets[:, None] # 应用微透镜折射 rays_local thin_lens(f1) rays_local # 回到主光轴坐标系 rays_global rays_local.copy() rays_global[0] offsets[:, None]这段代码展示了一个一维 MLA 的光轴切换逻辑二维情况只是把 offsets 变成二维网格、对行和列分别处理。参数说明p 是微透镜节距对应一个窗口的空间尺寸f1 是微透镜焦距决定了光线经过 MLA 后出射角的离散度offsets 的维度必须与窗口数量对齐否则会出现窗口间串扰。仿真中常见的错误是把 MLA 当作单透镜一次求完导致 P2 面上的汇聚点位置出现周期性偏差。5.3 在 P2 面做哈达玛积调制到达 P2 面后需要根据光线所处的位置 r 对强度做调制而不是直接乘一个全局矩阵。原因在于 P2 面上不同空间位置对应卷积核的不同系数。实现上可以先按 r 的值分组将同一 r 的光线索引找出来再给这些光线赋予同一个透射率 τ_i与原强度做哈达玛积def apply_kernel_at_p2(rays, r_positions, kernel_values): 在 P2 面按空间位置提取透射率 :param rays: 当前追迹状态shape (3, n_rays) :param r_positions: 光线对应的空间位置数组 :param kernel_values: 卷积核展开后按位置排列的透射率数组 :return: 调制后的光线 modulated rays.copy() for i, tau in enumerate(kernel_values): idx np.where(np.isclose(r_positions, r_positions[i]))[0] modulated[2, idx] * tau return modulated这里的 idx 是「位置相同的光线」索引。因为来自不同窗口、但窗口内相同位置的光线在 P2 面会汇聚到同一个 r它们需要乘上同一个核系数。用哈达玛积而不是矩阵乘法是为了保持光线维度的独立性也符合调制面「逐点透过率」的物理意义。核系数数组 kernel_values 的长度等于窗口内像素数即微透镜单元内的采样点数。这里实际仿真时的采样间隔决定了 r 的离散精度不论是否仿真最终产物都是强度的二维空间分布。5.4 输出面与仿真参数参考在输出面处把所有 r 相同的光线强度相加再按 r 重排就得到实际的卷积输出分布。这就完成了从「光线独立传播」到「光强叠加」的转换。仿真时沿光轴每隔 0.5 mm 取一个采样面把所有截面的光强记录下来可以得到类似图 5 所示的光路扩散过程。一维卷积核 [0, 1, 0] 的仿真结果表现为只在中间窗口对应的输出位置出现亮斑两侧位置光强接近零。更改 P2 面的透射率分布例如换成 [1, 0, 0]输出亮斑就会转移到对应位置。仿真参数参考如下参数典型取值说明微透镜节距 p1 mm对应一个窗口宽度微透镜焦距 f110 mm决定 P2 面上光斑间距L1 焦距 f2100 mm决定 P2 面位置采样间隔0.5 mm越小越能看到光路局部变化但计算量增大光线数409664×64足够呈现光强分布且仿真耗时可控在这个仿真中容易踩的坑有两个。第一个是光轴偏移量在二维情况下的方向如果只处理了 x 方向而忘了 y 方向P2 面的光斑会在 y 方向错位输出图像会呈现「纵向模糊」第二个是 P2 面调制时用数值相等而非位置索引相等来判断 r 相同导致部分光线没被调制输出出现半透明条纹。正确做法是先在仿真里打印出 r_positions 的取值集合核对去重后的数量是否等于窗口内像素数再做调制。6. 从固定算子到可学习卷积核光学卷积层的工程落地6.1 锐化算子的光学变形把负核拆成差分由于 P2 面的透过率只能取 0~1Prewitt、Sobel 这类带负系数的算子无法直接编码。常见的做法是把算子拆成两个正核。以 Prewitt 的 x 方向梯度核为例原始核为[-1, 0, 1; -1, 0, 1; -1, 0, 1]可以拆成[0, 0, 1; 0, 0, 1; 0, 0, 1]减去[1, 0, 0; 1, 0, 0; 1, 0, 0]。在光路上做两次卷积第一次用正核 A 得到光强分布 I_A第二次用正核 B 得到 I_B最终梯度为 I_A - I_B在电学域做减法。代价是需要两倍的光学曝光时间但好处是所有核的系数仍然在 [0,1] 范围内超表面不用做任何特殊处理。这个方案在实验中的效果较原版算子略差一些——原因是两次透射率分布的动态范围被压缩但用于边缘检测任务时输出灰度级仍然够用。6.2 通用光学卷积层架构把整个系统接到 CNN 里当卷积层推荐用两个 SLM 加一个 CMOS 的架构。SLM1 加载输入图像SLM2 替代超表面加载当前层的卷积核CMOS 接收输出。流程是先把当前层的输入图像投到 SLM1把卷积核权重编码到 SLM2CMOS 曝光并读取输出然后由外部处理器把输出重排后投回 SLM1更新 SLM2 为下一层卷积核进入下一层计算。因为 SLM2 是可编程的这就规避了超表面一次性制造、不可修改的问题。这里的 SLM1 需要是相位型或振幅型均可关键是像素间的填充率要高避免窗口间串扰。6.3 用预重排破解步长限制前文提到光学系统默认步长等于窗口尺寸也就是卷积和池化同时发生。如果要在光学卷积层中实现 stride1最简单的方式是把输入图像在加载到 SLM1 之前先做一次重排。具体做法是把原图中卷积核每滑动一次所覆盖的窗口从原图里裁剪出来、按列堆叠、重排成一个更大的图像再投到 SLM1 上。这样光学系统仍然按「窗口大小 核大小」的方式工作但屏幕上每个窗口实际对应的是原图滑动位置的一个裁剪块等效步长就变成了 1。实现 same 或 full 卷积时只需要在重排前对原图进行补零操作。由于 SLM 上对应补零位置的像素透射率设为 0这些像素不会对输出光强产生贡献等效于在输入端完成了边缘填充。重排的像素映射关系可以用以下逻辑生成# 假设输入为 img核大小为 k步长为 s # 生成滑动窗口坐标后做列堆叠重排 windows [] for i in range(0, img.shape[0] - k 1, s): for j in range(0, img.shape[1] - k 1, s): patch img[i:ik, j:jk] windows.append(patch.reshape(-1)) # 每个窗口列堆叠后按行排成 SLM 上的输入图案 slm_pattern np.vstack(windows).T.flatten()这里的核心逻辑是把每个窗口内的像素按行展开所有窗口再按列方向依次排列最后展平成一个一维序列再 reshape 回二维图案加载到 SLM。这样投影到微透镜阵列上时每个微透镜单元对应一个窗口窗口与窗口之间在空间上互不重叠。注意np.vstack(windows).T的作用是保证同一窗口内的像素位于 SLM 图案的同一列区域从而被同一个微透镜单元覆盖。这个重排过程在实验里我用 Python 实现不到 50 行代码耗时主要花在校验窗口坐标与原图索引的一一对应关系上。调试时先拿一个 4×4 的随机矩阵验证映射关系把重排结果再逆变换回来能还原出原图像即说明映射正确再放到光路上做真实实验。本文还有配套的精品资源点击获取
返回列表