八. 实战: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量化(一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/425554.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ArrayList集合源码分析

ArrayList集合源码分析 文章目录 ArrayList集合源码分析一、字段分析二、构造方法分析三、方法分析四、总结 内容如有错误或者其他需要注意的知识点,欢迎指正或者探讨补充,共同进步。 一、字段分析 //默认初始化容量。这里和Vector一样,只是…

Maven实战(2)之搭建maven私服

一, 背景: 如果使用国外镜像,下载速度比较慢; 如果使用阿里云镜像,速度还算OK,但是假如网速不好的时候,其实也是比较慢的; 如果没有网的情况下更加下载不了. 二, 本地仓库、个人/公司私服、远程仓库关系如下: 三, 下载安装nexus私服 略

Git 指令深入浅出【1】—— 文件管理

Git 指令深入浅出【1】—— 文件管理 一、新建仓库二、配置1. 基本指令2. 免密配置3. 简化指令 三、管理文件1. 常用文件管理指令(1)基本指令工作区暂存区版本库 (2)日志(3)查看修改 2. 版本回退&#xff0…

每日五道java面试题之mysql数据库篇(三)

目录: 第一题. 百万级别或以上的数据如何删除?第二题. 前缀索引第三题. 什么是最左前缀原则?什么是最左匹配原则?第四题. B树和B树的区别第五题. 使用B树和B树好处 第一题. 百万级别或以上的数据如何删除? 关于索引:…

奇酷网络董事长吴渔夫:以AI思维引领游戏制作,慢工出细活

文 | 大力财经 奇酷网络是一家以“AI游戏”为核心理念的创业公司,其独特的运营模式和理念备受瞩目。公司采用基于“AI思维”的运作方式,形成了与传统互联网思维鲜明对比的“超级个体公司”模式。尽管全职员工仅有两名,但公司CEO采取“以一打…

CPU漏洞之Spectre

一、前言 在过去的几十年里,一些微架构设计技术促进了处理器速度的提高。其中一个进步是推测执行(Speculative execution),它被广泛用于提高性能,猜测CPU未来可能的执行方向,并提前执行这些路径上的指令。比如说,程序…

HarmonyOS—配置编译构建信息

在进行应用/服务的编译构建前,需要对工程和编译构建的Module进行设置。API Version 9、API Version 8与API Version 4~7的构建体系不同,因此在设置编译构建信息时也存在差异: API Version 9:需要对构建配置文件、构建脚本、应用依…

Cloud+Consul

Cloud整合Zookeeper代替Eureka-CSDN博客 Consul简介 Consul是一套开源的分布式服务发现和配置管理系统 What is Consul? | Consul | HashiCorp DeveloperConsul is a service networking solution that delivers service discovery, service mesh, and network security ca…

【C++航海王:追寻罗杰的编程之路】CC++内存管理你知道哪些?

目录 1 -> C/C内存分布 2 -> C语言中动态内存管理方式:malloc/calloc/realloc/free 3 -> C内存管理方式 3.1 -> new/delete操作内置类型 3.2 -> new和delete操作自定义类型 4 -> operator new与operator delete函数 4.1 -> operator ne…

ProxySQL实现mysql8主从同步读写分离

ProxySQL基本介绍 ProxySQL是 MySQL 的高性能、高可用性、协议感知代理。以下为结合主从复制对ProxySQL读写分离、黑白名单、路由规则等做些基本测试。 先简单介绍下ProxySQL及其功能和配置,主要包括: 最基本的读/写分离,且方式有多种&…

spring注解驱动系列--自动装配

Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;依赖注入是spring ioc的具体体现,主要是通过各种注解进行属性的自动注入。 一、Autowired:自动注入 一、注解介绍 1、默认优先按照类型去…

Geostationary statellites与polar-orbiting satellites区别

Geostationary statellitespolar-orbiting satellites周期24小时不定,高度决定轨道与赤道平行与赤道垂直高度赤道正上方、唯一不唯一具体计算 m v 2 R h G M m ( R h ) 2 m\frac{v^2}{Rh}G\frac{Mm}{(Rh)^2} mRhv2​G(Rh)2Mm​ m v 2 R h G M m ( R h ) 2 m\f…

文件上传漏洞

目录 什么是文件上传漏洞? 文件上传漏洞常见场景 文件上传代码实现 文件上传漏洞原理 webshell 大马介绍: 小马介绍: 一句话木马介绍: 木马的生成方式 weevely生成木马 一句话木马大全 一句话木马插入后的使用方式 文件…

4. LockSupport与线程中断

文章目录 引言LockSupport线程中断机制什么是中断机制?说说一下 java.lang.Thread 类下的三个方法的区别 线程中断机制中断机制相关 API 三个方法的说明public void interrupt()public static boolean interrupted()public boolean isInterrupted() 经典面试题中的中断机制考点…

【k8s 访问控制--认证与鉴权】

1、身份认证与权限 前面我们在操作k8s的所有请求都是通过https的方式进行请求,通过REST协议操作我们的k8s接口,所以在k8s中有一套认证和鉴权的资源。 Kubenetes中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种策路等。通…

Linux学习:初始Linux

目录 1. 引子:1.1 简述:操作系统1.2 学习工具 2. Linux操作系统中的一些基础概念与指令2.1 简单指令2.2 ls指令与文件2.3 cd指令与目录2.4 文件目录的新建与删除指令2.5 补充指令1:2.6 文件编辑与拷贝剪切2.7 文件的查看2.8 时间相关指令2.9 …

基于C语言实现内存型数据库(kv存储)

基于C语言实现内存型数据库(kv存储) 文章目录 基于C语言实现内存型数据库(kv存储)1. 项目背景1.1 Redis介绍1.2 项目预期及基本架构 2. 服务端原理及代码框架2.1 网络数据回环的实现2.2 array的实现2.3 rbtree的实现2.4 btree的实现2.5 hash的实现2.6 dhash的实现2.7 skiplist的…

Python并发编程:多线程-信号量,Event,定时器

一 信号量 信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行,如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群路人争抢公…

蓝桥杯倒计时 41天 - 二分答案-最大通过数-妮妮的月饼工厂

最大通过数 思路&#xff1a;假设左边能通过 x 关&#xff0c;右边能通过 y 关&#xff0c;x∈[0,n]&#xff0c;通过二分&#xff0c;在前缀和中枚举右边通过的关卡数&#xff0c;保存 xy 的最大值。 #include<bits/stdc.h> using namespace std; typedef long long ll…

Windows下用crashRpt让C++程序崩溃自动生成dump

背景 我们的Windows c程序如果在客户或者没有代码调试的环境下崩溃了。我们只能从机器异常报错里得知寥寥无几的信息&#xff0c;如果程序崩溃时&#xff0c;能自动触发当前堆栈信息的收集&#xff0c;那么对于开发人员复现BUG就尤为重要 CrashRpt CrashRpt主要功能 1.崩溃报…