八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX

2024-03-04 12:28

本文主要是介绍八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • 前言
    • 0. 简述
    • 1. camera.backbone.onnx(fp16)
    • 2. camera.backbone.onnx(int8)
    • 3. camera.vtransform.onnx(fp16)
    • 4. fuser.onnx(fp16)
    • 5. fuser.onnx(int8)
    • 6. lidar.backbone.xyz.onnx
    • 7. head.bbox.onnx(fp16)
    • 总结
    • 下载链接
    • 参考

前言

自动驾驶之心推出的《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考

本次课程我们来学习下课程第八章——实战:CUDA-BEVFusion部署分析,一起来分析 BEVFusion 中各个 ONNX

课程大纲可以看下面的思维导图

在这里插入图片描述

0. 简述

本小节目标:分析 CUDA-BEVFusion 中各个 onnx 的输入输出,以及网络架构

这节给大家讲解第八章节第 7 小节,分析 BEVFusion 中的各个 onnx,这里我们拿 CUDA-BEVFusion 中导出好的 onnx 先看一看,一共有 5 个 onnx,对比看看 FP16 和 INT8 的 onnx 有什么区别,分析每个 onnx 的输入输出是什么以及它们之间是怎么连接的

1. camera.backbone.onnx(fp16)

我们先看 camera.backbone 部分,backbone 提供了两个,一个是 resnet 另一个是 swin transformer,我们这里以 resnet50 为例来讲解,我们主要看下输入输出就好了,主干部分是 resnet50 的结构,大家已经非常熟悉了

camera backbone 部分 fp16 的情况下需要看的东西并不是很多,需要注意的是 input 有两个,一个是 camera,一个是 LiDAR 到 camera 的 1ch depth map,output 也是有两个,一个是 camera feature(32ch),一个是 depth feature(118ch)

camera.backbone 的第一个输入是环视相机图像,以 nuscenes 数据集为例,相机个数为 6,高度为 256,宽度为 704,所以第一个输入的维度就是 1x6x3x256x704,如下图所示:

在这里插入图片描述

input1:camera
image(RGB)6 camera,3*256*704

通过变换矩阵将点云投影到相机上,这就是 camera.backbone 的第二个输入即 depth map,如下图所示:

在这里插入图片描述

input2:camera depth image
(1ch)6 camera,1*256*704

对于输出也有两个,大家可以回顾下上节课讲解的 BEVPool,它的输入就对应于这里的输出,如下图所示。一个是 camera_feature,维度是 6x32x88x80,分别代表着 NxHxWxC,另一个是 camera_depth_weights 即 depth 的概率图,维度是 6x118x32x88 分别代表着 NxDxHxW,这里的 D 表示对每一个特征像素 D 个 depth 的概率分布,图中 D 是 118,说明我们为图片上每个像素点估计 118 个深度值,之后对 118 个深度值做一个 softmax 看哪个点出现的可能性最大,这就是 camear backbone 的输出,它和普通的图像特征提取网络如 resnet 有所不同,多了一个深度概率分支

在这里插入图片描述

output:
camera feature:80chdepth feature:118ch

2. camera.backbone.onnx(int8)

接着我们再来看下 camera.backbone 的 INT8 的 onnx,camera backbone 部分如果是 int8 的话,我们可以看到在每一个 conv 前面都添加了 Q/DQ 节点,如下图所示,每一个 Q/DQ 节点都有对应的 scale 和 zero_shift,我们可以知道这一部分是经过 QAT 学习的,其余的没有变化(有关 QAT 学习如何添加这些 Q/DQ 节点有时间的话后面会介绍)

在这里插入图片描述

input1:camera
image(RGB)6 camera,3*256*704

可以看到每一个 Conv 前面都加了 Q/DQ 节点,每个 Conv 节点都有两个输入,一个是 activation value,一个是 weight,两个输入都需要加 Q/DQ,其实 Q/DQ 添加的过程并不是很复杂,通过 NVIDIA 提供的 pytorch_quantization 量化工具即可完成,这个我们在 TensorRT量化实战课YOLOv7量化:YOLOv7-PTQ量化(一) 中有提到过,大家感兴趣的可以看下

在这里插入图片描述

我们之前有讲过 TensorRT 里面对输入对 activation value 是 per-tensor 的量化粒度,每一个 tensor 只有一个 scale,这个大家可以从上图中看出来,y_scale 和 y_zero_point 都只有一个值,也就是 6x3x256x704 这整个 tensor 共用这一个 scale 和 zero_point

在这里插入图片描述

对于 weight 而言是 per-channel 的量化粒度,也就是说每个通道共享一个 scale 和 zero_point,这个我们从上图中也能看出来,可以看到 weight 的 Q 节点的 scale 有 64 个,对应的是 Conv 节点的 64 个通道

在这里插入图片描述

同时 zero_point 也是 64 个,只不过全为 0,如上图所示,那为什么都是 0 呢?这个我们在第五章节的时候也讲过,NVIDIA 将量化分为对称量化和非对称量化,NVIDIA 官方说如果要做非对称量化在部署阶段计算量比较大,也不好融合,所以 NVIDIA 在做量化时统一采用的是对称量化,因此 zero_point 就是 0 了

在这里插入图片描述

output:
camera feature:80chdepth feature:118ch

我们可以看其实并不是所有的节点都做了 INT8 量化,输出部分像 softmax、Transpose 就没有做 INT8 了,如上图所示

以上就是 camera.backbone 的 INT8 的 onnx 的整个结构了,值得注意的是在 resnet50int8/build 文件夹下有各种层的信息以及输出的日志文件,我们一起来看下,

在这里插入图片描述

camera.backbone.json

camera.backbone.json 文件中我们可以看到每个 layer 都有关于 INT8 量化的一些描述,我们重点来看下 camera.backbone.log,来看下层融合之后的精度

在这里插入图片描述

camera.backbone.log

我们可以看到 log 里面每个层每个节点的融合信息以及它们的精度的变化,大家可以打开简单看下

3. camera.vtransform.onnx(fp16)

我们看完 camera.backbone 之后我们来看 camera.vtransform,camera vtransform 的部分只有 fp16 的 onnx,需要看的东西并不是很多,需要注意的是,这个 vtransform 是针对 backbone 中输出进行的,三个 conv 将 360x360 大小的 input feature 进行特征学习 downsample 到 180x180

值得注意的是这里跨越了 BEVPool 这个部分,也就是说 camera.backbone 的两个输出经过 BEVPool 投影到 BEV 空间之后的输出才是作为 camera.vtransform 的输入

在这里插入图片描述

output:
80*360*360->80*180*180

4. fuser.onnx(fp16)

我们继续看,下一个是 fuser,fuser.onnx 的 fp16 模型比较简单,相比于 BEVFormer 来说 BEVFusion 的融合部分整体上只有 convolution 而没有像 BEVFormer 的 attention(spatial,temporal)。并且整体上相比于 backbone 而言,模型的深度也很浅,并且只有一个 BN,所有的 kernel 都是 3x3

在这里插入图片描述

input:
投影在 BEV 空间的 feature mapcamera 是 80ch,lidar 是 256ch估计是因为点云是 sparse 的,所以需要更大的 channel size

输入一个是 camera 一个是 lidar,camera 这边是 BEVPool 处理过投影到 BEV 上的 camera feature,维度是 1x80x180x180,lidar 这边是经过 SCN 网络提取后的 lidar feature,维度是 1x256x180x180

在这里插入图片描述

output:
通过多个 conv 将 camera feature 和 lidar feature 融合最终得到 180x180 Grid size 的 BEV 特征,ch 大小是 512

输出是融合后的 BEV 特征,维度是 1x512x180x180

5. fuser.onnx(int8)

fuser.onnx 的 int8 模型会稍微复杂一点,跟 camera.backbone(int8) 一样,每一个 conv 前都有 Q/DQ 节点,所有这里的 fuser 也是经过 QAT 进行学习到的,这里的权重已经能够在某种程度上适应 fp32->int8 的量化误差了

在这里插入图片描述

input:
投影在 BEV 空间的 feature mapcamera 是 80ch,lidar 是 256ch估计是因为点云是 sparse 的,所以需要更大的 channel size

在这里插入图片描述

output:
通过多个 conv 将 camera feature 和 lidar feature 融合最终得到 180x180 Grid size 的 BEV 特征,ch 大小是 512

6. lidar.backbone.xyz.onnx

我们再来看下 lidar.backbone.xyz.onnx 也就是点云特征提取网络的 onnx,这个其实就是 CenterPoint 的 SCN 架构直接导出的 ONNX

值得注意的是 lidar.backbone.xyz 的 onnx 比较特殊,因为这里使用的是自定义 onnx 节点,有两个自定义节点:

  • SparseConvolution
  • ScatterDense

所以在推理的时候会根据自定义 onnx 节点里的信息和输入 tensor 的信息进行推理

在这里插入图片描述

input:点云 tensor

在这里插入图片描述

output:
BEV-Grid:256*180*180

在这里插入图片描述

输入是经过处理后的点云 tensor 维度是 1x5,输出是 lidar feature 维度是 1x256x180x180,这个会输入到 fuser 模块与 camera 部分做融合得到融合后的 BEV 特征

自定义 SparseConvolution 节点里面包含了许多信息,如上图所示,这些信息将会在推理阶段用到,包括 activation,kernel_size,padding,rulebook,stride 等等

7. head.bbox.onnx(fp16)

最后我们看 head,head.bbox 部分是 fp16 推理的,使用 fuser 后的 512x180x180 的 feature map 进行前向推理,这里的 forward 过程的 onnx 详细部分没有必要看,我们只需要知道输出都有哪些:

  • height:[dim,1,200](3D 目标框的高度即 z 方向上的大小)
  • dim:[dim,3,200](3D 目标框的中心点即 center_x,center_y,center_z)
  • rot:[dim,2,200](rotation 即 sin 和 cos)
  • reg:[dim,2,200](3D 目标框的长宽即 x,y 方向上的大小)
  • vel:[dim,2,200](速度即 vx、vy,用来表示在哪个方向移动)
  • score:[dim,10,200](class confidence)

在这里插入图片描述

input:
在 BEV 空间上生成的特征图

在这里插入图片描述

output:
输出在 BEV 空间上的 3D BBox 的各种信息(高度、深度、坐标、得分等等)

在这里插入图片描述

输入是 1x512x180x180,也就是融合后的 BEV 特征,输出有 6 个,相关含义上面已经提到过了

以上就是 BEVFusion 中的各个 onnx 的分析,我们知道了每个 onnx 的输入输出以及如何衔接之后,再去阅读代码会相对简单一些

总结

这节课程我们主要学习了 BEVFusion 中的各个 onnx,分析了每个 onnx 的输入输出以及它们之间是怎么衔接的,主要包括 camera.backbone、camera.vtransform、fuser、lidar.backbone.xyz、head 五个 onnx,我们还分析了不同精度下的 onnx 差异,主要对比了 FP16 和 INT8 两种精度,INT8 下的 onnx 都插入了 Q/DQ 节点来做量化工作。

OK,以上就是第 7 小节有关 BEVFusion 中各个 onnx 分析的全部内容了,下节我们来学习 CUDA-BEVFusion 推理框架设计模式,敬请期待😄

下载链接

  • 论文下载链接【提取码:6463】
  • 数据集下载链接【提取码:data】
  • 代码和安装包下载链接【提取码:cuda】

参考

  • TensorRT量化实战课YOLOv7量化:YOLOv7-PTQ量化(一)

这篇关于八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/773171

相关文章

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

SpringBoot配置Ollama实现本地部署DeepSeek

《SpringBoot配置Ollama实现本地部署DeepSeek》本文主要介绍了在本地环境中使用Ollama配置DeepSeek模型,并在IntelliJIDEA中创建一个Sprin... 目录前言详细步骤一、本地配置DeepSeek二、SpringBoot项目调用本地DeepSeek前言随着人工智能技

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

通过Docker Compose部署MySQL的详细教程

《通过DockerCompose部署MySQL的详细教程》DockerCompose作为Docker官方的容器编排工具,为MySQL数据库部署带来了显著优势,下面小编就来为大家详细介绍一... 目录一、docker Compose 部署 mysql 的优势二、环境准备与基础配置2.1 项目目录结构2.2 基

CentOS 7部署主域名服务器 DNS的方法

《CentOS7部署主域名服务器DNS的方法》文章详细介绍了在CentOS7上部署主域名服务器DNS的步骤,包括安装BIND服务、配置DNS服务、添加域名区域、创建区域文件、配置反向解析、检查配置... 目录1. 安装 BIND 服务和工具2.  配置 BIND 服务3 . 添加你的域名区域配置4.创建区域