轻量级深度补全网络DepthNet:从算法设计到FPGA部署的嵌入式AI实践
1. 项目概述与核心挑战
在自动驾驶的感知系统中,激光雷达(LiDAR)和摄像头是两大核心传感器。摄像头能提供丰富的纹理和颜色信息,但缺乏精确的距离感知;而激光雷达能提供精确的三维点云距离信息,但其数据天生是稀疏的。以Velodyne的64线激光雷达HDL-64E为例,当将其点云投影到一张高分辨率相机图像上时,大约只有10%的像素拥有有效的深度值。这种稀疏性就像一张布满孔洞的深度地图,无法直接用于需要稠密三维信息的任务,如高精度障碍物检测、可行驶区域分割和路径规划。
深度补全(Depth Completion)技术就是为了解决这个“孔洞”问题而生的。它的目标很简单:输入一张稀疏的深度图(由LiDAR点云投影得到)和/或对应的RGB图像,输出一张每个像素都有深度值的稠密深度图。这听起来像是图像修复或插值,但难点在于,它并非简单的数学插值。一个窗户玻璃或车身上的反光区域,在LiDAR扫描中可能是空白的(无返回点),但算法需要根据周围的结构和图像语义信息,“猜”出这些区域应有的合理深度。因此,深度补全是一个典型的从稀疏信号中恢复稠密信息的病态逆问题,高度依赖对场景几何和语义的理解。
近年来,基于卷积神经网络(CNN)的方法在该领域取得了显著进展。然而,SOTA模型(如Ma等人提出的Sparse-to-Dense网络)为了追求极致的精度,往往设计得非常庞大和复杂,参数量动辄数千万。这类网络需要依赖高端GPU(如NVIDIA Tesla V100)进行推理,功耗高达数百瓦。这对于车载嵌入式平台来说是完全不可接受的。自动驾驶车辆的计算单元通常基于功耗受限的嵌入式SoC或FPGA,需要在有限的几十瓦功耗预算下,实现复杂的环境感知算法。因此,将深度补全算法“轻量化”并部署到嵌入式硬件上,是实现其真正落地应用的关键。
DepthNet项目正是瞄准了这一痛点。我们的目标不是一味追求在标准数据集上刷出更高的指标,而是在精度和效率之间寻找一个极致的平衡点,设计一个专为嵌入式实时处理而生的轻量级深度补全网络,并最终在FPGA上实现完整的硬件加速系统。我们最终实现的网络,参数量仅为SOTA网络的0.53%,在保持可比精度的前提下,在PYNQ-ZCU104 FPGA平台上对HDL-64E LiDAR数据实现了11.1 FPS的实时处理。下面,我将详细拆解我们是如何一步步实现这个目标的。
2. DepthNet网络架构设计与核心思想
2.1 两阶段学习框架:先粗后精
直接让一个CNN从极其稀疏的输入中预测稠密输出,任务非常艰巨。受传统计算机视觉方法的启发,我们采用了一个“先粗后精”的两阶段策略。这个思路的核心在于分解任务难度。
第一阶段:基于距离变换的粗估计 在原始稀疏深度图中,一个空的像素点,其深度值最有可能与其最近的有效像素点深度相近。这是一种基于空间邻近性的合理先验。我们采用距离变换算法来快速实现这一点。该算法为图像中每个像素计算其到最近有效深度像素的欧氏距离,并将该有效像素的深度值赋予它。这个过程计算复杂度低(线性复杂度),能快速生成一张粗糙但完整的深度图。这张图虽然边缘模糊、细节缺失,但它为后续网络提供了一个良好的初始估计,将网络的任务从“无中生有”转变为“精修优化”。
第二阶段:基于残差学习的CNN精修 我们将第一阶段得到的粗估计深度图作为CNN的输入之一(另一个输入是原始的稀疏深度图)。CNN的任务不再是预测完整的深度值,而是预测一个残差图。残差图代表了粗估计深度图与真实稠密深度图之间的差异。最终输出是粗估计深度图加上预测的残差图。
为什么残差学习更有效?
- 降低学习难度:网络只需学习相对较小的修正量,而非从零开始回归一个很大的深度值,优化过程更稳定、更容易收敛。
- 保留先验信息:粗估计图已经包含了基本的几何结构,网络可以专注于修复其错误(如物体边缘、反光区域),而不是重新学习整个场景结构。
- 改善梯度流:在深度网络中,残差连接有助于缓解梯度消失问题,使得更深的网络也能被有效训练。
我们的完整流程是:原始稀疏深度图 -> 距离变换 -> 生成粗估计图 -> CNN预测残差图 -> 粗估计图 + 残差图 = 最终稠密深度图。
2.2 编码器-解码器骨干网络
CNN部分采用了经典的编码器-解码器结构,这是稠密预测任务(如分割、深度估计)的常用架构。
- 编码器:负责下采样,提取多层次、抽象的特征。我们借鉴了ResNet-18的设计思想,但做了大量简化。没有直接使用完整的ResNet-18,因为其对于我们的任务来说仍然过重。我们设计了一个包含4个编码器块的轻量级结构。每个编码器块包含两个3x3卷积层,并使用步长为2的卷积进行下采样,替代了传统的池化层,以保留更多信息。在第三个编码器块后,我们移除了残差连接中的前向跳跃连接(如图2a中红色标记部分),以进一步减少参数和计算量。
- 解码器:负责上采样,将压缩的特征图恢复至原始分辨率,并融合编码器阶段提取的细节特征。每个解码器块由转置卷积(Deconvolution,即带学习参数的上采样)和卷积层组成。通过跳跃连接,将编码器对应层的高分辨率特征与解码器的上采样特征进行拼接,帮助网络更好地恢复细节,尤其是物体边界。
整个网络结构如图3所示,输入为256x1216的单通道稀疏深度图,经过编码器压缩再经解码器扩展,最终输出同分辨率的残差图。
2.3 深度可分离卷积:极致的轻量化
编码器-解码器结构搭建了网络骨架,但真正的“瘦身”秘诀在于深度可分离卷积技术的全面应用。这是将MobileNet系列的思想成功迁移到深度补全任务的关键。
标准卷积 vs. 深度可分离卷积
假设我们有一个输入特征图,尺寸为 H x W x Cin,要得到输出特征图 H x W x Cout,使用 K x K 的卷积核。
- 标准卷积:每个输出通道的每个像素,都需要与所有输入通道的
K x K区域进行卷积求和。其参数量为K * K * Cin * Cout,计算量巨大。 - 深度可分离卷积:拆分为两步:
- 深度卷积:每个输入通道单独使用一个
K x K的卷积核进行卷积,产生Cin个中间特征图。参数量:K * K * Cin。 - 逐点卷积:使用
1 x 1的卷积核,对上述Cin个特征图进行线性组合,生成Cout个输出通道。参数量:1 * 1 * Cin * Cout。
- 深度卷积:每个输入通道单独使用一个
参数量缩减分析
根据公式 P_SC / P_DS = 1/Cout + 1/K²,当 Cout 较大(如32, 64, 128)且 K=3 时,深度可分离卷积的参数量可以缩减为标准卷积的约 1/9 到 1/10。在我们的网络中,我们将所有标准3x3卷积和3x3转置卷积都替换为了其深度可分离版本。
对精度的影响与权衡 深度可分离卷积的假设是跨通道相关性和空间相关性可以解耦,这通常会带来轻微的精度损失。在我们的实验中,应用深度可分离技术后,网络参数量进一步减少了7.3倍,但误差性能仅有小幅变化(RMSE上升12.8%, MAE下降2.3%)。考虑到参数量从97.3万骤降至13.4万,这种程度的精度折损在嵌入式场景下是完全可接受的。更重要的是,深度可分离卷积的计算模式更易于在FPGA等硬件上进行高效并行和内存优化。
3. 网络训练、评估与性能分析
3.1 数据集与训练细节
我们使用自动驾驶领域权威的KITTI深度补全数据集进行训练和评估。该数据集提供了同步采集的相机图像、稀疏的Velodyne 64线LiDAR点云,以及通过累积多帧LiDAR扫描和人工标注生成的半稠密地面真值深度图。
- 输入预处理:我们将LiDAR点云投影到相机坐标系,生成一张与图像对齐的稀疏深度图,尺寸为256x1216。同时,我们对地面真值深度图进行相同的裁剪和缩放。空像素(无深度值)在训练时会被掩码掉,不参与损失计算。
- 损失函数与优化器:采用均方误差作为损失函数,直接优化预测的稠密深度图与地面真值之间的差距。优化器选用Adam,初始学习率为1e-4,并采用学习率衰减策略(每轮训练后减半)。
- 训练设置:批量大小设为4,在单张RTX 2080 Ti GPU上训练了6个轮次。整个训练过程大约需要12小时。
3.2 评估指标解读
我们使用四个标准指标来全面评估深度补全的质量:
- RMSE:均方根误差。它对大的误差非常敏感,一个预测严重错误的像素会显著拉高RMSE值。它衡量的是深度图的整体误差水平,但容易被异常值影响。
- MAE:平均绝对误差。它对所有误差一视同仁,能更好地反映深度图的平均精度。
- iRMSE 和 iMAE:逆深度误差。它们计算的是深度倒数(可近似理解为“视差”)的误差。由于深度倒数在近处变化快、远处变化慢,这两个指标更侧重于评估近处区域的深度预测精度。对于自动驾驶来说,近处物体的精确距离感知至关重要。
3.3 性能对比与结果分析
我们将DepthNet与当时的SOTA方法(Sparse-to-Dense)进行了全面对比,结果令人振奋。
| 网络 | 参数量 | RMSE (mm) ↓ | MAE (mm) ↓ | iRMSE (1/km) ↓ | iMAE (1/km) ↓ | 推理速度 (GPU) |
|---|---|---|---|---|---|---|
| Sparse-to-Dense (SOTA) | 25.4M | 814.73 | 249.95 | 2.80 | 1.21 | 24 fps (Tesla V100) |
| DepthNet (标准版) | 0.973M | 846.73 | 226.73 | 3.21 | 1.31 | 58 fps (GTX 2080 Ti) |
| DepthNet (深度可分离版) | 0.134M | 956.73 | 221.95 | 3.50 | 1.34 | 43 fps (GTX 2080 Ti) |
关键发现:
- 参数量巨幅缩减:标准版DepthNet参数量仅为SOTA的3.8%,而深度可分离版更是降至惊人的0.53%!这为嵌入式部署扫清了最大的障碍。
- 精度权衡:我们的网络在MAE指标上优于SOTA(降低9.3%),这意味着我们预测的深度图平均误差更小。但在RMSE上略差(增加3.9%),说明我们网络中可能存在少量误差较大的像素点。这是一个有趣的权衡:我们获得了更好的整体平均精度,但牺牲了对极端误差的控制。
- 近处精度优势:iRMSE和iMAE指标我们稍差,但这需要结合数据集分析。KITTI的地面真值在远处本身稀疏且噪声大,所有方法在远处都不准。我们的方法可能将更多“注意力”放在了优化整体和近处区域。
- 推理速度:即使在消费级GPU上,我们的网络也展现了更快的推理速度。深度可分离版速度略有下降,这是因为其计算从计算密集型转向了更多的内存访问(IO密集型),但这恰恰使其更适合在FPGA上进行定制化加速。
实操心得:指标选择的艺术 在工程实践中,不要盲目追求某个单一指标(如RMSE)的SOTA。需要根据应用场景选择核心指标。对于自动驾驶,车辆近处的感知精度(MAE和近处区域的误差)远比远处一个像素的严重错误(拉高RMSE)更重要。我们的网络设计有意或无意地契合了这一原则。
图4直观展示了DepthNet的效果:输入稀疏点云(仅约5%像素有值),网络能够生成细节丰富、边界清晰的稠密深度图,并成功重建出可信的3D场景。
4. 面向FPGA的硬件加速架构设计
将训练好的轻量级网络部署到FPGA上,并实现端到端的实时处理,是项目的另一大核心。我们选择了Xilinx ZCU104开发板(基于Zynq UltraScale+ MPSoC),它集成了ARM处理器和可编程逻辑(FPGA),非常适合软硬协同设计。
4.1 系统级软硬划分
整个深度补全流水线被巧妙地划分到ARM(PS端)和FPGA(PL端):
- ARM处理器(软件任务):
- 驱动与数据采集:移植并运行Velodyne LiDAR的Linux驱动,通过以太网实时接收原始点云数据包。
- 坐标投影:利用标定好的外参矩阵,将3D LiDAR点云投影到2D相机图像平面,生成原始的稀疏深度图。这是一个矩阵乘法操作。
- 距离变换:对稀疏深度图执行快速距离变换算法,生成粗估计深度图。 ARM处理后的数据(粗估计图+稀疏图)通过AXI总线传输至FPGA侧的DDR内存中。
- FPGA逻辑(硬件加速器):
- CNN推理引擎:这是设计的核心,一个高度定制化的深度学习处理器(DPU),专门用于加速DepthNet的前向传播。
- 数据调度与控制:负责从DDR中读取输入特征图和权重,将中间结果写回DDR,并控制整个计算流程。
这种划分充分利用了ARM处理器的灵活性和FPGA的并行计算能力。预处理步骤(投影、变换)虽然计算不复杂,但涉及控制流和标准库调用,用ARM实现更高效;而计算密集、规则性强的CNN推理部分,则交给FPGA进行并行加速。
4.2 计算引擎的微架构设计
我们的CNN加速器需要高效支持三种核心操作:深度卷积、逐点卷积和深度转置卷积。我们为每种操作设计了专用的计算单元,并由一个中央调度器根据网络层序列进行调用。
1. 逐点卷积单元 逐点卷积本质上是输入通道和输出通道之间的全连接操作,即向量-矩阵乘法。我们实现了32个并行的乘法累加阵列。每个阵列包含32个乘法器(对应输入通道的一个切片),其后跟着一个加法树和一个累加器。这种设计可以一次性计算输出特征图一个像素点的32个通道的值,实现了通道维度的并行。
2. 深度卷积单元 深度卷积是标准的空间卷积,但每个输入通道独立进行。我们实现了32个并行的3x3卷积核阵列。每个阵列包含9个乘法器(对应一个3x3卷积窗口)和一个加法树。这样,可以同时处理32个输入通道在同一空间位置上的卷积操作,实现了通道维度的并行。
3. 深度转置卷积单元的优化 这是硬件设计中的一大亮点。转置卷积(或叫分数步长卷积)的朴素实现是在输入特征图间插入零,然后进行标准卷积,这会导致大量与零的无效乘法运算。
我们采用了零跳过优化算法。以2倍上采样、3x3核为例,输出特征图的每个2x2块,只由输入特征图的一个2x2块和旋转后的卷积核计算得到,公式如图7和公式(6)-(9)所示。通过精心设计数据流和计算顺序,我们完全避免了与填充零的乘法,仅保留了必要的边缘填充操作,将计算效率提升了近4倍。
4. 激活函数与内存映射 激活函数采用LeakyReLU,其硬件实现非常简单,只需一个比较器、一个乘法器(乘以0.2)和一个多路选择器。 内存设计是FPGA加速器的关键。我们为权重和偏置分配了片上BRAM缓冲区,但由于总参数量仅约150KB,我们只缓存了一半最常用的参数,在带宽和资源间取得平衡。对于特征图,我们分配了10个尺寸为152x32x32的片上缓冲区,对于通道数小于256的中间层,可以实现全缓存,避免频繁访问低速的DDR内存。此外,我们还为逐点卷积单元单独配置了高精度缓冲区,以减少计算过程中的精度损失。
4.3 FPGA实现结果与性能分析
最终设计在ZCU104平台上以200MHz时钟频率运行。资源利用率如下表所示:
| 资源类型 | 可用总量 | 已用量 | 利用率 |
|---|---|---|---|
| LUT | 230k | 154k | 67% |
| FF | 460k | 220k | 48% |
| DSP | 1,728 | 1,696 | 98.1% |
| BRAM | 312 | 273 | 87.5% |
设计瓶颈与权衡:
- DSP资源是瓶颈:高达98.1%的利用率表明我们的计算并行度几乎达到了该芯片的极限。DSP切片是执行乘加运算的核心,其数量直接决定了峰值算力。任何进一步的并行化提升都会受限于此。
- 内存资源消耗大:为了减少DDR访问延迟、提高数据复用,我们使用了大量的BRAM来缓存特征图和参数。87.5%的利用率是性能提升的必要代价。
性能指标:
- 单帧处理时间:90.1 ms。
- 吞吐率:11.1 FPS (1 / 0.0901s)。
- 总操作数:15.14 G(网络一次前向传播的浮点运算次数)。
- 计算效率:168.1 GOPS (15.14G ops / 0.0901s)。
这个性能意味着,我们的FPGA系统能够实时处理Velodyne HDL-64E激光雷达的数据(其典型扫描频率为10Hz),完全满足自动驾驶的实时性要求。整个系统的功耗远低于GPU方案,展示了在嵌入式平台上实现复杂视觉感知任务的可行性。
5. 开发部署中的实际问题与解决方案
5.1 数据对齐与标定误差处理
在实际部署中,最大的挑战之一来自于传感器标定误差。LiDAR和相机之间的外参矩阵标定存在微小误差,这会导致点云投影到图像上时,出现几个像素的错位。在训练时,我们使用的是KITTI提供的精确标定数据。但在真实车辆上,标定误差不可避免。
解决方案:
- 训练数据增强:在训练阶段,我们模拟了标定误差。对投影后的稀疏深度图,在水平和垂直方向进行随机几个像素的平移。这相当于让网络学习对小的投影误差不敏感,增强了模型的鲁棒性。
- 在线标定验证:在系统启动时,可以运行一个简单的在线检查程序。例如,通过检测场景中明显的、易于识别的边缘(如地面与墙面的交界线)在深度图和图像上是否对齐,来诊断标定偏差,必要时触发重新标定或软件补偿。
5.2 动态范围与量化策略
网络在PC上使用32位浮点数训练,但FPGA上使用高精度浮点(如FP32)会消耗大量DSP和逻辑资源。必须进行量化,通常采用定点数。
实操步骤:
- 统计分析:在验证集上运行浮点模型,统计每一层卷积输入、输出、权重的数据分布(最大值、最小值、均值、方差)。
- 确定定点格式:对于每一层,根据统计结果确定整数位宽和小数位宽。例如,格式
Qm.n表示有m位整数,n位小数。激活层后通常需要更高的动态范围。 - 量化感知训练:在训练后期,在计算图中插入“伪量化”节点,模拟定点舍入和溢出效应,让网络权重适应量化带来的噪声。这是保证量化后精度不显著下降的关键。
- 硬件实现:在FPGA中,根据确定的位宽设计定点乘法器和加法器。对于我们的设计,最终对特征图使用
Q8.8格式(16位),对权重使用Q2.14格式(16位),在精度损失(<1% RMSE增加)和资源节省之间取得了良好平衡。
5.3 内存带宽优化与数据复用
深度可分离卷积虽然是轻量化的,但其深度卷积步骤是内存访问密集型的(每个通道独立操作,数据复用率低)。FPGA的片上内存带宽远高于访问外部DDR的带宽。
我们的优化技巧:
- 输入/输出缓冲:为每个处理单元(PE)配备双缓冲或乒乓缓冲。当PE在处理当前数据块时,DMA控制器正在将下一个数据块预取到另一个缓冲区中,隐藏了数据传输延迟。
- 权重驻留:由于网络参数量小,我们可以将全部或大部分卷积核权重缓存在片上BRAM中,整个推理过程只需在开始时从DDR加载一次权重,避免了频繁的权重读取。
- 循环分块与展开:通过调整循环嵌套的顺序和展开因子(
#pragma HLS UNROLL),来最大化数据在寄存器间的复用,减少对缓冲区的访问次数。例如,在深度卷积中,我们部分展开了通道循环,一次处理多个通道的同一空间位置,提高了计算并行度。
5.4 系统集成与实时流水线
要让整个系统(LiDAR驱动、数据预处理、FPGA加速、结果输出)稳定实时运行,需要精心设计流水线。
我们的架构:
ARM和FPGA并行工作,处理不同的数据帧。ARM处理完第N帧数据并存入DDR后,立即开始处理第N+1帧。与此同时,FPGA从DDR读取第N帧数据开始计算。这样就形成了一个高效的流水线,FPGA的处理时间(90ms)被ARM的数据准备时间所掩盖,系统整体吞吐率取决于最慢的阶段,最终实现了11.1 FPS的稳定输出。
踩坑记录:DMA传输的同步 最初我们使用简单的轮询方式等待DMA传输完成,发现ARM端经常阻塞,导致整体帧率下降。后来改为中断驱动的DMA传输:ARM启动DMA后即可继续执行其他任务;DMA传输完成后触发中断,在中断服务例程中设置标志位。ARM主循环检查该标志位,再进行下一帧数据的传输准备。这充分释放了ARM的性能,是达到实时性能的关键一步。
6. 总结与展望
DepthNet项目展示了一条清晰的路径:如何将一个计算密集型的先进感知算法,通过算法创新(两阶段残差学习、深度可分离卷积)和硬件协同设计(FPGA定制化架构),成功部署到资源受限的嵌入式实时平台上。我们不仅提出了一个参数量仅为SOTA网络0.53%的轻量级网络,更关键的是,我们提供了一套从算法设计、训练优化到硬件部署的完整方案。
在实际操作中,我深刻体会到,嵌入式AI不仅仅是“训练一个轻量模型然后部署”那么简单。它需要算法工程师和硬件工程师的深度协作。算法设计时必须心中有“硬件”,考虑计算模式是否规整、内存访问是否高效、是否易于量化;硬件设计时必须理解“算法”,知道哪些层是计算瓶颈、哪些数据可以复用、如何为特定的操作(如转置卷积)设计最优硬件单元。
这个项目后续还有诸多可以探索的方向:例如,引入相机RGB图像作为引导信息的多模态融合,能否在几乎不增加计算量的前提下进一步提升边界处的深度预测精度?再如,利用神经网络架构搜索技术,针对特定的FPGA资源约束(如DSP数量、BRAM大小)自动搜索更优的网络结构。对于更高阶的自动驾驶应用,还可以探索将深度补全与目标检测、语义分割任务在一个统一的轻量网络中完成,实现多任务学习,进一步节省计算资源。这条路还很长,但DepthNet无疑为自动驾驶的嵌入式实时三维感知提供了一个坚实而高效的起点。