ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

传感器端计算:把第一层智能塞进像素阵列,破解边缘AI功耗难题

传感器端计算:把第一层智能塞进像素阵列,破解边缘AI功耗难题 传感器端计算in-sensor computing这两年在我的项目里出现的频率越来越高。之前做低功耗视觉识别时最折磨人的不是模型选型而是数据刚出像素阵列就已经把功耗和带宽吃掉大半后端再强也只能干瞪眼。后来我把一部分卷积和特征提取直接搬进传感器内部整个系统的功耗、延迟、数据量都被重新洗了一遍牌。这篇文章打算把这轮方案验证的完整过程写下来包括为什么非算在传感器上不可、算法怎么适配、仿真验证流程怎么搭以及我在工程里踩过的几个大坑给正在研究终端感知和边缘AI的朋友做个参考。1. 传感器端计算的本质把“第一层智能”塞进像素阵列1.1 它到底在算什么又在哪里算传感器端计算简单说就是把传统图像传感器“只负责光电转换、然后丢数据”的单一职责改成“光电转换 第一层信息提取”二合一。传统路线上像素阵列完成曝光、读出后原始数据要通过MIPI或并行总线一帧一帧搬到SoC再进ISP、内存最后才轮到神经网络推理。而in-sensor computing的做法是在感光阵列内部或紧邻阵列的列级电路里先把一些特定的乘加运算做完输出的已经不是原始像素而是特征图、目标框候选区、或“有事件发生”的稀疏标记。打个比方传统方案是超市把所有货物都运回总仓再让拣货员满仓库找你要的那瓶水。传感器端计算等于在货架上就地放了小机器人它看一眼就知道“这瓶水在第几排第几列”你只需要去取结果。整个过程省掉了大规模货物搬运。这里的“货物”就是图像数据“搬运”就是像素读出和总线传输。1.2 为什么非要在传感器上算而不是在MCU或云端算核心原因两个字能耗再加两个字延迟。我在项目里做过一组粗算一颗720p的CMOS传感器跑30帧每帧原始数据大概在1MB以上如果走10bit ADC一秒的数据量是300MB上下。这些数据先要从像素一行一行扫描读出再经过模拟前端、数字接口、DMA最后进DDR。每一次读取和搬运单位能耗远大于一次数学运算本身。业界有一个经常被引用的数字一次8bit整数乘加操作能耗大约是0.2到0.5pJ但一次从DRAM读取8bit数据可能要几十到几百pJ差了两个数量级。换句话说很多边缘AI系统的功耗大头根本不是“算”而是“挪数据”。传感器端计算的思路就是既然挪数据这么贵那就让数据待在产生它的地方先算完第一层再往外挪。这样数据量被大幅压缩后级处理器的压力也小很多。延迟也一样传统链路从曝光到推理结果出来至少要经过“曝光→读出→传输→ISP→推理”几个环节而在传感器端往往在曝光积分的过程中就完成了初步判断事件从检测到响应的延迟可以做到微秒到亚毫秒级这对机械臂抓取、无人机避障、AR手势识别这类场景极其关键。1.3 模拟域计算和数字域计算到底怎么选刚开始接触这个方向时我被“模拟域计算”这个概念绕了很久。实际上它没那么玄。传统图像传感器里像素的光电二极管受光照后会产生光电流光电流在浮置扩散区或积分电容上电荷累积最终变成电压。模拟域计算就是利用这个物理过程直接做乘加把入射光强当成输入权重用可控电导或可编程电容的物理量表示照在多个像素上的光电流经过不同大小的“权重通道”后直接流进同一个汇总节点电荷一累加卷积结果就出来了。整个MAC过程是物理发生的不需要先做ADC也不需要寄存器参与。数字域计算就好理解得多。它是在像素阵列旁边或每一列下面放一些数字存储单元提前存好卷积核权重等像素值读出后用数字电路做逐位累加。好处是精度高、抗噪声能力强支持更复杂的网络结构坏处是每个像素或每组像素都要塞数字逻辑面积开销大单元密度低传感器分辨率很难做高。选型时主要看场景如果只需要做目标有无判断、运动感知这种低复杂度任务模拟域是最优的功耗可以压到极致如果要做实时分类、多目标检测这类对精度敏感的算法宁可让出一些面积做数字域也得保证精度稳定。1.4 别再把它和边缘计算搞混有一个观念我花了不少时间才向团队里的人解释清楚就是传感器端计算和边缘计算、TinyML不是一回事。TinyML是把模型部署在MCU或低功耗DSP上数据还是先把原始像素从传感器读出来再交给MCU内存去处理边缘计算更是如此只是把推理位置从云端挪到网关或本地服务器。它们都没有碰“像素读出搬移”这个最贵的环节。对比一下三种方案环节云端计算边缘计算/MCU传感器端计算数据量传输全量原始数据全量或压缩原始数据特征图/事件/目标框延迟几百毫秒到秒级十毫秒级微秒到亚毫秒级系统功耗最高较高最低隐私风险高中低部署灵活性依赖网络中等受传感器硬件约束传感器端最吸引我的地方在于它在物理层就把数据隐私和带宽问题一起解决了。一些敏感场景下原始图像根本不需要离开传感器外部只能拿到算法提取后的结构化信息这比任何加密方案都天然。2. 核心技术点拆解与方案选型2.1 三条主流实现路线各适合什么场景我按自己的项目经验把目前看到的传感器端计算实现分成了三条路线。第一条是像素内卷积路线也是最容易理解的一种。它在像素阵列里做局部感受野的加权求和一个输出像素对应周围一片输入像素的加权和。这种方案适合做第一层卷积、边缘检测、图像滤波这类空域操作。工程上常见做法是用3x3或7x7的卷积核扫描全图把分块特征直接以模拟量形式输出。优点是全图特征提取效率高缺点是精度受底噪影响大卷积核一般只能做固定权重动态调整能力弱。第二条是事件驱动神经形态路线。这类传感器不是按帧输出图像而是每个像素独立判断光照变化是否超过阈值超过就输出一个脉冲事件。因为只有“变化了”的信息才输出静态背景完全不产生数据所以数据稀疏性极高。事件相机可以用来做人眼跟踪、高速运动检测、振动监测在低功耗场景里表现非常惊艳。但它不适合需要纹理细节的任务因为静止物体根本不产生事件。第三条是感算一体的光电存储路线把存储器和感光层做垂直集成像素本身就具备存内计算能力。这类器件可以用电荷俘获状态或忆阻器电导来编码权重光输入直接乘上电导值完成MAC。它的密度和能效理论上最高但目前成熟度较低商业化器件很少主要还停留在实验室和原型验证阶段。我对一般项目团队的建议是短期落地选第一条先解决产品能效问题对数据稀疏性有特殊要求的选第二条高风险高回报第三条可以持续关注但别过早绑进产品路线。2.2 算法怎么迁过来量化、轻量化、稀疏化传感器端的计算资源比CPU和GPU稀缺得多模型不可能直接用常规CNN。我自己总结了一套适配流程顺序很固定看大家能不能也用上。优先做权重低比特化。第一层卷积的权重往往可以压到1bit到2bit因为浅层特征以边缘和纹理为主对数值精度不敏感。1bit权重意味着乘加操作变成XNOR加popcount硬件实现非常简单面积和功耗都省到极致。我把一个手写数字识别网络的第一层从8bit压到1bit后精度只掉了0.7%传感器端的面积却能缩小一半。其次使用深度可分离卷积结构替代标准卷积。标准3x3卷积要做输出通道数乘输入通道数次乘加深度可分离卷积把空间卷积和通道融合分开做计算量降低到原来的九分之一左右。这个结构很适合传感器端因为每一层都很浅通道数也少压缩效果非常明显。最后做事件稀疏化或RoI区域裁剪。不是所有像素都需要进入计算。我做的场景里绝大多数画面属于背景真正需要分析的区域只占很小比例。我让传感器先做一个粗粒度的“变化检测”只把变化区域切成小块做高精度分析其他区域直接跳过功耗可以再省一到两个数量级。这一步对系统级收益最大但需要算法工程师和硬件工程师一起设计单纯改软件很难把效果做到极致。2.3 核心指标可以怎么估算、怎么对比选传感器端方案时我一般看四个指标分别是能效、端到端延迟、输出数据带宽、有效精度保持度。能效用TOPS/W表示就是每瓦每秒能完成多少次万亿次操作。传统AI加速芯片的能效一般在1到10 TOPS/W而传感器端模拟计算路线可以做到几十甚至上百TOPS/W前提是只算浅层卷积。延迟上传统摄像头从曝光到推理结果出来的链路延迟通常在30到100毫秒换成传感器端后可以压到1毫秒内。带宽更不用说输出从原始图像变成目标框坐标或事件流之后数据量能少三个数量级。有效精度保持度是个容易被忽略的指标。传感器端的计算是在模拟噪声、像素不均匀性、工艺漂移等非理想条件下进行的模型在普通GPU上达到95%精度放到传感器端后可能只有80%都不到。我建议在项目预研阶段就把器件层面的非理想因素建模进训练和验证流程别等硬件回来了再亡羊补牢。2.4 传感器与算法协同设计是绕不开的关卡这是我对整个方向最深的一个感悟。传感器端计算不是一个单纯的算法问题也不是单纯的器件问题而是两者联合设计的问题。传统开发流程里算法工程师拿到图像数据传感器工程师负责搭光电链路两端开发是解耦的到了in-sensor computing解耦模式直接失效传感器的噪声、动态范围、量化精度会直接影响模型第一层卷积的数值分布而模型的结构也反过来决定传感器像素阵列的拓扑和读出策略。所以我在方案规划阶段就坚持让算法团队加入传感器模型仿真的环节把传感器输出建模成“理想图像 噪声 量化 非线性 运动伪影”把这个遮蔽后的图像当成训练数据的一部分。这一步做和不做最终板级精度的差距经常在5到10个百分点以上。下面第三部分我会把一套完整可复现的仿真验证流程分享出来。3. 从零搭一套可复现的传感器端计算验证流程3.1 为什么要先做仿真验证而不是直接流片传感器端计算的硬件门槛很高小团队很难一开始就流片验证。我的做法是先做一个“物理感知仿真”把传感器端计算的行为模型跑在PyTorch里先用软件把算法和噪声的关系摸透再决定要不要往硬件走。这样做的原因很简单传感器端很多设计失误比如量化位宽不够、权重溢出、噪声放大在仿真阶段就能暴露不用花几十万块流片费用去试错。我这次验证选的是一个具体任务在模拟成像传感器上用第一层卷积直接提取图像局部特征再判断画面里是否出现了指定目标的区域。这个任务不复杂但足够把传感器端计算的关键链路跑一遍。平台用的是Python和PyTorch代码结构大致是这样先模拟一个带有量子噪声的传感器输出再定义一组量化卷积核在像素级做乘加最后对输出结果特征图做判断。3.2 模拟传感器像素阵列的光电响应传感器像素的输出不是理想灰度值它要经过光电转换、电荷积分、复位噪声、读出噪声、ADC量化等环节。我在仿真里用一个简单的模型来概括这些效应把一帧理想图像变成带噪的数字化原始图像。import torch import torch.nn as nn import torch.nn.functional as F gauss torch.distributions.normal.Normal(torch.tensor([0.0]), torch.tensor([1.0])) def simulate_raw_image(ideal_img, qe0.5, full_well30000.0, read_noise1.5, bit_depth10): 模拟CMOS像素阵列输出 ideal_img: 0~1范围理想灰度图 qe: 量子效率按比例转换光子数 full_well: 像素满阱容量 read_noise: 读出噪声标准差单位电子数 bit_depth: ADC量化位宽 photon_count ideal_img * qe * full_well shot_noise torch.sqrt(photon_count) * gauss.sample(ideal_img.shape).squeeze(-1) electron_count photon_count shot_noise electron_count torch.clamp(electron_count, 0, full_well) noisy_voltage electron_count read_noise * gauss.sample(ideal_img.shape).squeeze(-1) quantization_level 2 ** bit_depth pixel_value torch.round(noisy_voltage / full_well * (quantization_level - 1)) return pixel_value / (quantization_level - 1)这个函数做了三件事一是用泊松分布近似光子散粒噪声光子数越少噪声越大对应暗光环境下图像变花二是加入电阻热噪声导致的读出噪声三是模拟ADC量化把连续电压转成整数像素值。这一层仿真是我建议所有做传感器端算法的团队都不要省略的因为第一层卷积是对原始像素值直接操作噪声和量化的影响会被卷积核的权重放大。3.3 定义像素内卷积核和权重量化传感器端第一层卷积的权重需要提前烧录或配置到像素电路的存储单元里。这次我用的是3x3卷积核分别模拟两个常用的浅层特征算子边缘检测算子和高斯平滑算子。同时我模拟了8bit和2bit两种量化情况用来对比权重量化对特征提取的影响。def quantize_weight(weight, bits2): 把权重量化到[-1,1]区间的低比特值 scale 2 ** (bits - 1) - 1 quantized torch.clamp(weight, -1, 1) quantized torch.round(quantized * scale) / scale return quantized edge_kernel torch.tensor([[[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]]], dtypetorch.float32) smooth_kernel torch.tensor([[[[1, 2, 1], [2, 4, 2], [1, 2, 1]]]], dtypetorch.float32) / 16.0 edge_8bit quantize_weight(edge_kernel, bits8) edge_2bit quantize_weight(edge_kernel, bits2)这里有个很关键的点传感器端的第一层卷积一般是不可学习的固定核或者只在出厂时做一次离线训练。因为像素内的模拟权重一旦流片后就很难动态更新算法工程师必须接受“第一层固定、后续层可调”的约束。我通常做法是把后续可学习部分的网络结构设计得足够强大让第一层固定特征提取后的损失可以靠浅层全连接或1x1卷积来补足。3.4 在模拟图像上完成像素内卷积我用的测试图像是一张带有边缘物体的合成灰度图。先经过3.2节的传感器仿真变成带噪原始图然后分别用2bit和8bit的卷积核做卷积比较输出特征图的信噪比。batch raw_image.unsqueeze(0).unsqueeze(0) # 增加 batch 和 channel 维 def conv_with_noise(feature_map, kernel): # 使用卷积操作同时给输出加一点列固定模式噪声 out F.conv2d(feature_map, kernel, padding1) col_noise torch.randn(out.shape[0], out.shape[1], out.shape[2], 1) * 0.02 return out col_noise out_8bit conv_with_noise(batch, edge_8bit) out_2bit conv_with_noise(batch, edge_2bit)这段代码虽然只有几行但它抓住了传感器端卷积的核心差异。8bit权重下边缘特征能保持清晰的梯度响应2bit权重下卷积核的高频响应会变得粗糙但依然能勾勒出物体边界。这个实验给我最大的启示是即便是1bit权重只要传感器噪声控制得当浅层特征的质量并不会崩溃真正伤精度的是后层深度网络对误差的累积。3.5 关键参数计算功耗和延迟怎么估仿真验证不只验证精度也要在数字上验证能效收益。我按下面的逻辑估算整个系统的功耗。传统链路中一帧100x100的灰度图像10bit ADC输出每像素读出功耗大约按50pJ算那么读出10000像素就要0.5微焦。如果后续在MCU上跑一个3x3卷积按每像素MAC需要8次乘法加8次加法估算10000像素约160万次操作每次操作按0.3pJ算加起来约0.48微焦加上数据搬移消耗整帧处理的能耗基本在1微焦以上。传感器端链路的能耗模型完全不同。像素在积分过程中直接做加权求和等于把一次3x3卷积的9次乘加压缩成一次电荷累积每输出一个特征像素只消耗一次模拟MAC的能耗大约0.05pJ还是100x100输出特征图总MAC能耗只有0.005微焦相比传统链路低了两个数量级。再加上不需要大量数据搬移不需要ADC全量量化整个系统端到端功耗可以压缩到原来的十分之一甚至更低。延迟方面也很明显。传统链路至少需要一行一行读出整帧之后才能开始第一层卷积传感器端在曝光积分阶段就完成了卷积曝光完成时特征图已经躺在输出节点上。对全局快门传感器这意味着输出一个特征图的时间约等于曝光时间省掉的至少是读出行扫描和传输的几十毫秒。3.6 验证结果怎么看、怎么继续往下走仿真跑完之后我一般会看三张图原始图像、8bit卷积特征图、2bit卷积特征图。如果2bit和8bit特征图的边缘形态趋势一致说明这个任务可以在低比特权重下继续往下做如果差异过大就要检查噪声模型是不是过于严苛或者任务本身不适合传感器端第一层处理。下一步是在仿真里加入更真实的光照变化、卷帘快门效应和像素坏点。我建议把坏点模拟也放到仿真早期因为坏点会直接导致卷积核的响应被污染后处理阶段再想修复就非常被动。仿真通过后再去做FPGA或SoC原型可以避免很多低级错误。4. 工程落地时踩过的坑和排查经验4.1 固定模式噪声怎么就成了精度杀手仿真阶段我犯过一个错误用的噪声模型过于干净没有加入列固定模式噪声和像素固定模式噪声。真实传感器中由于工艺偏差每一列放大器的增益、暗电流、偏置电压都不同导致满帧图像上出现固定的“条纹”或“斑点”。这个固定模式噪声在视觉观感上可能不明显但一旦经过3x3卷积核加权就会变成明显的列状高响应假边缘。解决方案有两层。第一层是硬件校准做相关双采样和列级校正可以在一定程度上抑制但无法完全消除。第二层是算法补偿把固定模式噪声做成扰动项在训练模型的第一层之前注入让网络学会自动忽略这些固定伪影。我实测下来搭配算法补偿后传感器端第一层输出的信噪比能提高约3dB。大家在自己仿真时也务必确认代码里是不是把列噪声当独立变量加进去了不要顺手用一个全图高斯噪声代替。4.2 模拟计算的温度漂移和工艺漂移传感器端模拟计算最让人头疼的问题是漂移。模拟器件对温度极为敏感同一个卷积核在25度和60度下的有效权重可能差了5%以上。这会导致在实验室调试很好的模型装进户外设备后精度骤降。工艺漂移则表现为不同批次的传感器之间权重偏差不一致换一颗传感器就得重新校准对量产来说非常痛苦。我踩过温度漂移的坑之后现在做传感器端设计时会给第一层卷积的权重留出校准通道。具体做法是把部分权重参数做成可微调的小规模数字模拟转换在设备启动时先运行一段校准图案根据输出反推出当前温度下的权重偏移量再做一次补偿。这个思路不增加太多硬件成本但能让模型适应温度范围扩大好几倍。4.3 数据分布漂移同一颗传感器不同光线下的适配传感器端计算还有一个隐性风险就是数据分布漂移。同一颗传感器在不同光照条件、不同色温环境下输出的特征图分布差异很大。我在一个物体检测例子里发现模型在室内灯光下检测率92%换到户外阴天就降到80%原因正是第一层卷积的输出范围被光照压缩了。针对这类问题的建议是算法侧在特征层加入光照归一化模块把第一层输出做自适应缩放或者干脆在训练数据里做光照增强覆盖不同曝光条件下的数值范围。更激进的做法是在传感器端加一个简单的自动曝光反馈让像素积分时间随光照动态调整但这个需要硬件参与项目周期允许的话可以一起规划。4.4 工具链割裂和团队协作问题工程落地中最容易被低估的是工具链问题。传感器端计算同时涉及传感器设计工具、模拟电路仿真、神经网络框架、嵌入式部署工具生态极不成熟。算法工程师习惯用PyTorch导出模型但传感器的流片环境用的是Cadence或Synopsys两边模型格式完全不互通。我现在的做法是强制要求仿真流程中所有数据都从“可复现的数值文件”中流转把PyTorch的权重导出成标准numpy数组或CSV再让硬件组自己做转换避免被单一工具链绑死。团队协作上最大的挑战是让算法工程师和模拟工程师互相理解彼此的语言。我的经验是每周同步一次算法组把最新精度数据反馈给硬件组硬件组把噪声波形图反馈给算法组双方对着同一张特征图讨论问题效率远高于各自闷头调参。4.5 关于这个方向的一点体会传感器端计算不是万能的它最大的优势在于把“数据搬运”这个隐形瓶颈彻底干掉。但如果任务需要高频更新权重、需要处理复杂语义、需要大范围场景理解传统边缘计算仍然不可替代。我的建议是把它当作系统设计中“最前端的一道加速器”而不是替代所有计算单元的银弹。实际项目里一个好的落地方式是分级处理传感器端负责极低成本的“有没有、动没动、在哪个区域”判断一旦判断需要更细的语义分析才触发后级更高功耗的计算单元。这样既能保留传感器端计算的低功耗优势又不牺牲复杂任务的处理能力。真正把传感器端计算用好的人不是把一切算法都塞进像素里而是知道哪一层计算该留在像素里哪一层该交给后面的硬件去跑。
返回列表