八. 实战: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

相关文章

基于C#实现MQTT通信实战

《基于C#实现MQTT通信实战》MQTT消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点,下面我们就来看看C#实现... 目录1、连接主机2、订阅消息3、发布消息MQTT(Message Queueing Telemetr

Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例

《Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例》本文介绍Nginx+Keepalived实现Web集群高可用负载均衡的部署与测试,涵盖架构设计、环境配置、健康检查、... 目录前言一、架构设计二、环境准备三、案例部署配置 前端 Keepalived配置 前端 Nginx

Python日期和时间完全指南与实战

《Python日期和时间完全指南与实战》在软件开发领域,‌日期时间处理‌是贯穿系统设计全生命周期的重要基础能力,本文将深入解析Python日期时间的‌七大核心模块‌,通过‌企业级代码案例‌揭示最佳实践... 目录一、背景与核心价值二、核心模块详解与实战2.1 datetime模块四剑客2.2 时区处理黄金法

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

Spring Boot集成Logback终极指南之从基础到高级配置实战指南

《SpringBoot集成Logback终极指南之从基础到高级配置实战指南》Logback是一个可靠、通用且快速的Java日志框架,作为Log4j的继承者,由Log4j创始人设计,:本文主要介绍... 目录一、Logback简介与Spring Boot集成基础1.1 Logback是什么?1.2 Sprin

ubuntu如何部署Dify以及安装Docker? Dify安装部署指南

《ubuntu如何部署Dify以及安装Docker?Dify安装部署指南》Dify是一个开源的大模型应用开发平台,允许用户快速构建和部署基于大语言模型的应用,ubuntu如何部署Dify呢?详细请... Dify是个不错的开源LLM应用开发平台,提供从 Agent 构建到 AI workflow 编排、RA

ubuntu16.04如何部署dify? 在Linux上安装部署Dify的技巧

《ubuntu16.04如何部署dify?在Linux上安装部署Dify的技巧》随着云计算和容器技术的快速发展,Docker已经成为现代软件开发和部署的重要工具之一,Dify作为一款优秀的云原生应用... Dify 是一个基于 docker 的工作流管理工具,旨在简化机器学习和数据科学领域的多步骤工作流。它

PostgreSQL 序列(Sequence) 与 Oracle 序列对比差异分析

《PostgreSQL序列(Sequence)与Oracle序列对比差异分析》PostgreSQL和Oracle都提供了序列(Sequence)功能,但在实现细节和使用方式上存在一些重要差异,... 目录PostgreSQL 序列(Sequence) 与 oracle 序列对比一 基本语法对比1.1 创建序

Nginx部署React项目时重定向循环问题的解决方案

《Nginx部署React项目时重定向循环问题的解决方案》Nginx在处理React项目请求时出现重定向循环,通常是由于`try_files`配置错误或`root`路径配置不当导致的,本文给大家详细介... 目录问题原因1. try_files 配置错误2. root 路径错误解决方法1. 检查 try_f