使用 Nod.AI 单目深度探测模型在 DPU 上进行 Vitis-AI 深度检测
引言
深度估算在业界长期都是一个颇具挑战性的问题,包括基于视觉和非基于视觉的深度估算技术。非基于视觉的深度估算传感器,如激光雷达、激光和 TOF (飞行时间)等,通常具有最优精度,但只能进行粗略的深度估算。基于视觉的深度估算技术能生成高密度深度图,但精度相对较低。随着深度学习技术的发展,基于视觉的深度估算可通过低成本摄像头来获得与其他高成本深度估算传感器相媲美的性能。
基于视觉的深度估算可分为两大类:基于学习的深度估算和立体深度估算。立体深度估算采用立体几何结构来计算立体视图中的匹配特征点的差异。立体深度估算不能预测盲区深度,而且盲区中的场景是无纹理、无特征的。基于学习的深度估算能提供预测所有像素深度的解决方案。
此外,基于学习的深度估算可分为监督学习和自监督学习。监督深度估算需要的图像应具有实际深度作为标识。考虑到训练模型需要收集大量的数据,这将花费大量的时间和资源来收集实际的深度数据。监督深度估算也难以扩展至不同场景。因此,自监督深度估算解决方案是目前业界最实用和最合理的解决方案。
Nod.AI 的自监督深度估算解决方案是一种业界一流的深度估算技术。不管是彩色还是灰度图像,它都能预测所有像素的深度。为了训练模型,它使用单目图像序列进行自监督训练,无需借助实际的深度数据。
Nod.AI 深度估算方法
Nod.AI 方法的优势
- 全自监督训练
- 高 FPS:DPU 上约为 100 FPS
- 高精度:与其他基于学习的深度估算算法相比,具有业界一流的精度
- 预测高密度深度图:预测所有像素的深度
- 均支持室内外场景
- 可扩展至边缘设备和云端设备
解决方案架构
推断管道
Nod.AI 使用编码器—解码器网络对给定图像进行粗略的深度估算,随后采用双边滤波器对深度图进行微调。

Nod.AI 的快速双边滤波器将输入 RGB 图像作为“参考”图像,并将预测的深度图作为“目标值” t ,并将一些深度图的像素置信作为 c 。目标是通过重组置信大的输入深度图来微调输入深度图,同时保持平滑并紧密对齐基准图像的边缘。
Nod.AI 采用 “splat/blur/slice” 程序加速双边滤波。将像素值“泼洒”到网格上的一小组顶点上(软直方图操作),随后顶点值被模糊了,过滤后的像素值通过模糊顶点值的“切片”产生(插值)。
培训管道
Nod.AI 使用单目图像序列进行自监督深度训练。在训练过程中,我们训练的深度网络支持多个常见的主干如 Mobilenet 和 ResNet ,同时也训练了一个单独的的姿势网络。姿势网络预测一对图像帧之间的平移和旋转。
为表述训练损失,我们尝试最大限度地减少预测合成图形和目标图像之间的近似光度重投影误差。如下图所示,我们用 It’ 来表达源图像的相关 6-DOF 姿势,对应源图像 It ‘s 姿势为 Tt->t’ 。获得目标图像的深度图 Dt 后,我们可最大限度减少光度重投影误差 Lphoto:
Lphoto = pe(It, It’->t)
It’->t = It’
这里的pe是光度投影误差,proj操作符投影深度Dt到It’中的2D坐标,姿态Tt->t’ 而内部函数为K
Vitis AI 和 DPU
Vitis AI 开发环境加速赛灵思硬件平台上的 AI 推断,包括边缘设备和 Alveo 加速器卡。它由优化的 IP 核心、工具、库、模型和示例设计构成。在设计过程中就考虑到高效性和易用性,能充分发挥赛灵思 FPGA 和自适应计算加速平台(ACAP)上的 AI 加速潜力,也能让不具备 FPGA 知识的用户更轻松地开发深度学习推断应用,把底层 FPGA 和 ACAP 的复杂问题以抽象的方式展现出来。

赛灵思深度学习处理器单元( DPU )是一款专用于卷积神经网络的可编程引擎。该单元包括寄存器配置模块、数据控制器模块和卷积计算模块。DPU 有专用指令集,能让 DPU 在众多卷积神经网络中高效工作。DPU IP 可集成为选定的 Zynq-7000 SoC 和 Zynq UltraScale + MPSoC 器件的可编程逻辑(PL)中的组模块,并直接连接到处理系统 (PS)。
Nod.AI 在赛灵思边缘设备上部署深度估算解决方案,包括 ZCU102 和 ZCU104 。还可将深度估算解决方案部署至 Alveo U50 等云端设备上。
使用 Vitis AI 和 DPU 进行 Nod.AI 的深度估算
在模型部署过程中,大部分情况下,我们按照赛灵思 Vitis AI 用户指南 (https://www.xilinx.com/support/documentation/sw_manuals/vitis_ai/1_0/ug1414-vitis-ai.pdf) 和 Vitis AI library (https://github.com/Xilinx/Vitis-AI) 进行。就像 ResNet-50 的示例代码步骤一样,我们用以下四个步骤来部署深度估算模型:
对神经网络模型进行量化
我们修改 vai_q_tensorflow 脚本以量化 TensorFlow 冻结深度模型。虽然用户指南建议使用训练图像校准模型能获得最好的结果,但我们发现在部署深度估算模型的情况下,使用随机数据校准神经网络能获得最佳性能,而用训练数据子集校准则可能导致后量化模型过度拟合。
编译神经网络模型
Vitis AI 提供 vai_c_tensorflow.py 用于编辑后量化模型。您可能遇到这样的问题:即便是量化成功了,但编译器发生故障,并报告如下所示的错误信息:
**************************************************
* VITIS_AI Compilation - Xilinx Inc.
**************************************************
/opt/vitis_ai/compiler/arch/dpuv2/ZCU102/ZCU102.json
[libprotobuf FATAL /home/dnnc/3rd-party/google/protobuf/repeated_field.h:1182] CHECK failed: (index) < (current_size_):
terminate called after throwing an instance of 'google::protobuf::FatalException'
what(): CHECK failed: (index) < (current_size_):
这很可能是因为模型中有一些操作符将数据类型转换为浮点数和乘法。在删除这些操作符后,就能成功编译该模型。
使用 Vitis AI 编程接口编程
Vitis AI 提供 Unified C++ 和 Python API 用于 Edge 与 Cloud 在 FPGA 上部署模型。编译后生成 elf 文件,我们可将其链接到程序中,并调用 DpuRunner 进行模型推断。
Vitis AI 运行时 API 非常简单。大多数与计算机视觉相关的任务需要使用OpenCV 库。幸运的是,赛灵思有一个内建的 OpenCV 库能直接使用,也足以满足使用要求。
目前,将 DNNDK 和 Vitis AI 一起储存在库中。在部署期间采用 DNNDK 编程时,我们在后量化模型和编译模型之间遇到一个性能不匹配的问题。我们发现,这是因为输入张量必须使用 dpuGetInputTensorScale() API 的值进行扩展,而输出张量也必须使用 dpuGetOutputTensorScale() API 的值进行扩展。
深度估算模型的多项操作符尚未得到 Vitis AI 的支持,因此我们必须自行部署。例如,我们部署了sigmoid 层,随后将其应用至模型的最后一层。
运行并评估已部署的 DPU 应用
即便遵循以上步骤,成功部署模型也并非易事。有时我们需要修改模型结构以解决一些性能降级问题。
我们在首次部署时遇到后量化模型严重的性能降级问题,并发现需要将 BiasAdd of Conv2D 替换为 Batchnorm 操作符,这样才能提高量化友好性。示例代码如下所示:
In training:
output = tf.nn.relu(tf.layers.batch_normalization(conv2d(input, weights), training=True))
In inference and evaluation:
output = tf.nn.relu(tf.layers.batch_normalization(conv2d(input, weights), training=False))
下面是原始 TensorFlow float32 模型、 DPU 上后量化模型和 EdgeTPU 上后量化模型之间的深度性能对比。相对于 EdgeTPU 而言,DPU 显示出更清晰的深度图并更好地保留了深度边缘和深度细节。

精度、速度和性能
精度
Methods |
Supervision |
Accuracy Metric (higher is better) |
Error Metric (lower is better) |
|||
δ < 1.25 |
δ < 1.25^2 |
δ < 1.25^2 |
Absolute Relative Error |
Root Mean Square Error |
||
DORN [1] |
Y |
0.828 |
0.965 |
0.992 |
0.115 |
0.509 |
DepthNet Nano [2] |
Y |
0.816 |
0.958 |
0.989 |
0.139 |
0.599 |
Zhou et al. [3] |
N |
0.674 |
0.9 |
0.968 |
0.208 |
0.712 |
TrainFlow [4] |
N |
0.701 |
0.912 |
0.978 |
0.189 |
0.686 |
Nod Depth |
N |
0.7266 |
0.9332 |
0.9794 |
0.1778 |
0.5841 |
Nod Depth + Postprocess |
N |
0.7419 |
0.947 |
0.988 |
0.1702 |
0.5508 |
Nod Depth on DPU (Post Quantization) |
N |
0.701 |
0.9294 |
0.984 |
0.1958 |
0.5854 |
Nod Depth on TPU (Post Quantization) |
N |
0.7018 |
0.9244 |
0.9832 |
0.195 |
0.6062 |
速度
Resolution |
GPU* |
CPU** |
DPU*** |
EdgeTPU |
320*240 |
192fps |
23fps |
90fps |
50fps |
640*480 |
90fps |
10fps |
25fps |
- |
* GPU: Titan Xp
** CPU: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
*** ZCU102 with 3x DPU B4096@300MHz. 关于 DPU 的详细信息, please refer to 请参阅 DPU 产品指南.
正如我们所看到的,在紧凑的嵌入式平台上运行 DPU ,可实现实时推断速度,其运行速度大幅快于桌面 CPU 和 EdgeTPU。
与强大的桌面 GPU 的 Titan Xp相比,DPU 表现出单位功耗性能提高 3.5 -5.9 倍的优势。
性能:
以下给出 Nod.AI 深度估算在赛灵思 ZCU104 开发板上的运行原理。通过深度涂色来显示距离,颜色越深表明距离越近,颜色越浅则表明距离越远。

产品路线图
- 不断提高精度和可扩展性
- 支持更高分辨率
- 提高后量化模型精度
- 利用模型神经网络搜索和修剪技术进一步加速模型推断
参考材料
[1]:Huan Fu, Mingming Gong, Chaohui Wang, Kayhan Batmanghelich, and Dacheng Tao. Deep ordinal regression network for monocular depth estimation. In CVPR, pages 2002–2011, 2018.
[2]:Linda Wang, Mahmoud Famouri, and Alexander Wong. DepthNet Nano: A Highly Compact Self-Normalizing Neural Network for Monocular Depth Estimation. In CVPR, 2020.
[3]:Junsheng Zhou, Yuwang Wang, Kaihuai Qin, and Wenjun Zeng. Moving indoor: Unsupervised video depth learning in challenging environments. In ICCV, pages 8618–8627, 2019.
[4]:Wang Zhao Shaohui Liu Yezhi Shu Yong-Jin Liu. Towards Better Generalization: Joint Depth-Pose Learning without PoseNet. In CVPR, 2020.