OpenPCDet系列 | 5.1 PointPillars算法——PillarVFE特征构建与编码模块

news2024/11/28 7:31:39

文章目录

  • PillarVFE模块
  • 1. PillarVFE初始化
  • 2. PillarVFE数据处理
    • 2.1 特征构造
    • 2.2 掩码构造
    • 2.3 特征编码

OpenPCDet的整个结构图:

在这里插入图片描述

PillarVFE模块属于VFE结构的其中一种,所以可以在PCDet中的backbone_3d目录下,可以找到vfe目录结构。在OpenPCDet\pcdet\models\backbones_3d\vfe\__init__.py文件中,可以查看所有可供选择的vfe模型结构。

# 根据MODEL中的VFE_NAME确定选择的模块
__all__ = {
    'VFETemplate': VFETemplate,
    'MeanVFE': MeanVFE,
    'PillarVFE': PillarVFE,     # PointPillar
    'ImageVFE': ImageVFE,
    'DynMeanVFE': DynamicMeanVFE,
    'DynPillarVFE': DynamicPillarVFE,
    'DynamicPillarVFESimple2D': DynamicPillarVFESimple2D
}

PillarVFE模块

这里先简单的介绍一下PointPillars算法中的PillarVFE结构。其中的VFE其实就是voxel feature encoding,而backbone3d目录下的另外一个文件pfe,其实表示的point feature encoding。前者是对voxel进行特征编码,而后者是对point进行特征编码。而在pointpillars中,不是简单的voxel表示,而是更加极端的pilllars表示。


1. PillarVFE初始化

PillarVFE的初始化具体是在Detector3DTemplate类中的build_vfe函数中实现,build_vfe在build_network中进行调用。PillarVFE模块相对于的模型设置通过传入cfg的VFE配置部分即可。使用NUM_FILTERS: [64]来设置模型的层数以及channels大小。假设这里的设置的就是NUM_FILTERS: [64],那么由于这个列表只有一个数值,所以FE网络层数只有一层。一层的VFE层一般是Linear+BN的结构(是否有BN层取决于是有设置USE_NORM)。设置后VFE层的输入channels为10,输出的channels就是64.

# 构造线性层:10 -> 64
pfn_layers = []
for i in range(len(num_filters) - 1):
    in_filters = num_filters[i]
    out_filters = num_filters[i + 1]
    pfn_layers.append(
        PFNLayer(in_filters, out_filters, self.use_norm, last_layer=(i >= len(num_filters) - 2))
    )
self.pfn_layers = nn.ModuleList(pfn_layers)    # 加入网络结构

具体结构如下所示:

在这里插入图片描述

所以,PointPillars模型初始的点云特征编码结构还是比较简单的,就是单纯的只有一层全连接来对特征进行升维操作。


2. PillarVFE数据处理

在之前已经介绍到,数据经过collect_data函数进行数据的批处理后,其传入模型的数据是一个batch_dict的形式,当batch处理后首先就是传入到了PillarVFE模块的forward函数进行处理。这里可以注意到,points的特征维度还是5(后面4维的点特征,第一维是确定当前点属于哪个点云帧),voxels的特征维度还是4(这个4就是点特征,32表示每个voxel选择的32个点,最大只有32个点,非点用0来填充)。此时与模型设置的初始维度10还是不一样的,此时还不能直接对数据进行处理。

在这里插入图片描述

在voxel点特征处理的具体过程化分化几个大概的步骤:

2.1 特征构造

对于给定的点特征以及voxel特征与每个点的网格具体位置,这里会分别构造每个voxel内每个点离voxel中心点的相对距离以及离网格的相对距离。代码如下所示:

# 1)计算voxel内每个点离voxel中心点的相对距离
# 求每个voxle的平均值(102483, 1, 3) / (102483, 1, 1) = (102483, 1, 3)
# 被求和的维度,在求和后会变为1,如果没有keepdim=True的设置,python会默认压缩该维度
points_mean = voxel_features[:, :, :3].sum(dim=1, keepdim=True) / voxel_num_points.type_as(voxel_features).view(-1, 1, 1)   # 计算每个voxel内有效点的中心坐标(无效点部分用已0表示)
f_cluster = voxel_features[:, :, :3] - points_mean  # voxel内的每个点与中心坐标的偏移量   (102483, 32, 3)

# 2) 计算voxel内每个点离网格的相对距离
# coords是网格点坐标,不是实际坐标,乘以voxel大小再加上偏移量是恢复网格中心点实际坐标
f_center = torch.zeros_like(voxel_features[:, :, :3])   # voxel内每个点与当前点网格的相对距离 (102483, 32, 3)
f_center[:, :, 0] = voxel_features[:, :, 0] - (coords[:, 3].to(voxel_features.dtype).unsqueeze(1) * self.voxel_x + self.x_offset)
f_center[:, :, 1] = voxel_features[:, :, 1] - (coords[:, 2].to(voxel_features.dtype).unsqueeze(1) * self.voxel_y + self.y_offset)
f_center[:, :, 2] = voxel_features[:, :, 2] - (coords[:, 1].to(voxel_features.dtype).unsqueeze(1) * self.voxel_z + self.z_offset)

随后,如何还选择使用点的绝对位置,那么voxel的特征就是点特征+离中心店相对距离+离网格相对距离 = 10维的特征,这里没有选择额外的使用xyz离原点的距离特征。

2.2 掩码构造

由于每个voxel中最大的有效点数量为32,一般都达不到这个数值,所以实际上的voxel是存在很多的0,也就是空值点。对于这些控制点,由于在构造特征时对其进行赋值,但是实际上不应该使用这些特征,十一要构造一个掩码矩阵抑制其作用,来与构造好的特征进行相乘。

# 3) 每个voxel点的掩码构造
voxel_count = features.shape[1]     # 32 每个voxel内最多有32个有效点
mask = self.get_paddings_indicator(voxel_num_points, voxel_count, axis=0)   # (102483, 32)
mask = torch.unsqueeze(mask, -1).type_as(voxel_features)     # (102483, 32, 1)
features *= mask

2.3 特征编码

在掩码处理后的特征就可以正式的进行升维编码处理。但是在具体的实现上时,由于一个batch的数据可能会过大,比如10w+以上的点。那么,如此庞大的点全部就进行linear处理会造成极大的随机性。这里涉及了点工程上的优化,就是对点进行分批的linear升维处理再对升维后的数据拼接在一起。随后再进行BN层+ReLU激活函数层。然后,进行一个maxpool来提取当前批次点的全局特征,作为每个voxel特征。

class PFNLayer(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels,
                 use_norm=True,
                 last_layer=False):
        super().__init__()
        ......
        self.part = 50000   # 如果当前的batch点数量太大,需要进行特殊处理

    def forward(self, inputs):
        """
        如果当前batch的点数量太大,需要进行分批进行linear处理,否则效果随机性较大,这里一个小批次的点数量设置为50000
        """
        if inputs.shape[0] > self.part:
            # nn.Linear performs randomly when batch size is too large
            num_parts = inputs.shape[0] // self.part
            part_linear_out = [self.linear(inputs[num_part*self.part:(num_part+1)*self.part])   # 分part来进行模型的升维处理
                               for num_part in range(num_parts+1)]
            x = torch.cat(part_linear_out, dim=0)   # [(50000, 32, 64), (50000, 32, 64), (2716, 32, 64)]
        else:
            x = self.linear(inputs)     # 如果点数量少于5w可以直接linear处理
        torch.backends.cudnn.enabled = False    # 取消配置最高效率算法
        x = self.norm(x.permute(0, 2, 1)).permute(0, 2, 1) if self.use_norm else x   # 对channels=64的维度进行norm
        torch.backends.cudnn.enabled = True     # 配置最高效率算法
        x = F.relu(x)   # 激活函数
        x_max = torch.max(x, dim=1, keepdim=True)[0]    # 相当于是maxpool操作(pointnet中提出)
        ......

所以其实在PillarVFE模块中,具体的模型处理是分批次的Linear+BN层归一化+ReLU激活函数+maxpool提取全局特征,对每个voxel内的32个点(包含有效点+控制)提取了全局特征就是voxel特征。随后保留当前模块的特征处理结果在batch_dict字典中,以供后续模块的继续处理。

# 4) 特征编码
# (102483, 32, 10) -> (102483, 32, 64) -> (102483, 1, 64) -> (102483, 64)
for pfn in self.pfn_layers:
    features = pfn(features)
features = features.squeeze()   # 降维
batch_dict['pillar_features'] = features    # 保留特征处理的结果
return batch_dict

至此,获取到了每个voxel的特征,也就是每个pillars的特征,batch_dict字典更新情况如下:
在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JOSEF约瑟 JL-8GA/12端子排电流继电器 整定范围宽、功耗低】

JL-8GA/12端子排电流继电器名称:端子排电流继电器型号:JL-8GA/12品牌:JOSEF约瑟功率消耗:≤5W触点容量:250V5A额定电压:58,100,110,220V 系列型号: JL-8GA/11端子排电流继电器; JL-8GA/12端子排电流继电器; JL-8GA/13端子排电流继电器&am…

MySQL(1) ---- 数据库介绍与MySQL概述

介绍 1、什么是数据库? 数据库:DateBase(DB),是存储和管理数据的仓库。数据库管理系统:DataBase Management System(DBMS),操纵和管理数据库的大型软件。SQL&#xff1…

【C语言】手把手教你文件操作

文章目录 一、前言二、文件的打开和关闭1. fopen函数2. fclose函数 三、文件的顺序读写四、文件的随机读写1. fseek函数2. ftell函数3. fwind函数 一、前言 程序运行时,数据存放在内存中,而当程序退出后,数据也就不复存在。 想做到数据持久化…

数据库管理-第七十五期 手把手教你搭19c RAC(20230516)

数据库管理 2023-05-16 第七十五期 手把手教你搭19c RAC1 基础环境2 操作系统配置2.1 /etc/hosts2.2 配置系统挂载2.3 配置本地yum源2.4 操作系统配置2.5 安装预安装RPM包并配置:2.6 创建对应目录2.7 配置时间同步 3 存储挂载3.1 存储环境3.2 存储识别3.3 多路径聚合…

生成一个手绘图为底图的导游图

1 前言 上一篇演示了制作一个简版导游图。简版导游图的优点是制作简单、快速,不需要第三方软件,缺点是略显简陋、不够专业。 本编介绍制作专业导游图的步骤,用手绘图为地图,用图形展现景区信息,能表现出丰富的景区细…

ChatGPT:使用Edge浏览器获取ChatGPT以及如何使用ChatGPT帮你制作PPT

一:前言 ChatGPT:智能AI助你畅聊天地 在现代人日益忙碌的生活中,难免需要一些轻松愉快的聊天来放松身心。而现在,有了 ChatGPT,轻松愉快的聊天变得更加智能、有趣且不受时间、地点限制! 什么是 ChatGPT&…

NSSCTF-[深育杯 2021]Press

下载链接:下载 载入IDA,查看内容 首先进入一个函数进行初始化,进入查看 unsigned __int64 sub_4007B6() {int v1; // [rsp8h] [rbp-48h]int i; // [rspCh] [rbp-44h]char src[56]; // [rsp10h] [rbp-40h] BYREFunsigned __int64 v4; // [r…

【可乐荐书】有趣的矩阵:看得懂又好看的线性代数

本栏目将推荐一些经典的、有趣的、有启发性的书籍,这些书籍涵盖了各个领域,包括文学、历史、哲学、科学、技术等等。相信这些书籍不仅可以让你获得知识,还可以让你感受到阅读的乐趣和魅力。 今天给大家推荐的书籍是:《有趣的矩阵…

【简单DP】CF1420 C1

昨天的CF心态又打崩了 好久没写DP了这道题一发过了 但是大家都会qwq 烦死 Problem - C1 - Codeforces 题意: 给定一个序列,让你找出一个子序列 使得 这个最大,a是子序列 思路: 首先子序列,自然就是DP 然后每个…

品牌活动如何策划,更利于传播?(吸引媒体报道)

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 之前做媒体的时候,参加过无数的媒体活动,现在做媒体传播也给了许多品牌一些建议,有的活动设计的很有趣,有的活动设计的很巧妙,…

响应式设计 MediaQuery和flex

一、MediaQuery(媒体查询)的概念 为不同尺寸的屏幕设定不同的css样式 示例 二、media常用参数 三、媒体查询代码示例 MediaQuery在浏览器中的显示示例 MediaQuery综合案例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8…

Go语言笔记:使用ssh包作为客户端与SSH服务器交互

文章目录 目的基础说明使用演示单次通讯连续通讯&#xff08;远程终端&#xff09; 总结 目的 Golang中可以使用 golang.org/x/crypto/ssh 包作为SSH客户端或者SSH服务使用。这篇文章将简单记录下作为客户端使用的一些内容。 Package ssh implements an SSH client and server…

QT自定义控件折线图、趋势图。

这里提供两种实现方式&#xff0c;一直自绘的自定义控件&#xff0c;一直三方SDK&#xff08;qcustomplot&#xff09;。 这里主要介绍自绘的&#xff0c;它的优点是结构简单&#xff0c;代码逻辑好修改&#xff0c;容易定制&#xff0c;缺点是功能相对单一。三方的qcustomplot…

循迹模块(应用于小车)

1.1循迹模块使用 TCRT5000传感器的红外发射二极管不断发射红外线 当发射出的红外线没有被反射回来或被反射回来但强度不够大时&#xff0c; 红外接收管一直处于关断状态&#xff0c;此时模块的输出端为高电平&#xff0c;指示二极管一直处于熄灭状态 被检测物体出现在检测范…

C++ | 数组拷贝

C | 数组拷贝 文章目录 C | 数组拷贝数组名数组拷贝1.对应位拷贝2.地址位移赋值3. memcpy内存拷贝4.字符数组拷贝 Reference 数组名 C数组间赋值不能直接通过数组名称 randy sesame进行&#xff0c;因为数组名并不是指针&#xff0c;大部分情况下&#xff0c;编译器会隐式转换…

使用nvm 管理node.js版本的安装过程

一个 nodejs 版本管理工具&#xff01;—— nvm 在项目开发过程中&#xff0c;随着框架的不断更新迭代&#xff0c;对一些环境依赖的版本也有影响&#xff0c;部分的老项目可能需要低版本的 node.js 才能正常使用&#xff0c;而后期新开发的项目可能需要更高的 node.js 版本才…

都说2023是测试员的危机年,却不断有人跳槽拿20K+,为什么?

从 2021 年上旬开始触发的经济危机逐渐蔓延到普通人的生活中&#xff0c;裁员、倒闭、跑路俨然已成为刷爆朋友圈的高频热词。随之而来的是一系列因舆论所牵动的各种焦虑感弥漫在人群中&#xff0c;无论是大公司还是之前处于风口浪尖的明星创业公司&#xff0c;几乎无一幸免。聊…

ANR实战案例3 - 应用在部分低端机ANR优化案例

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、Blocked状态1.案例一2.案例二3.案例三 二、高低端机区分1.WebView预加载 三、…

Flink基础介绍-2 架构

Flink基础介绍-1 概述 二、Flink架构2.1 Flink的设计架构2.2 Flink的运行架构2.3 Flink的系统架构 二、Flink架构 2.1 Flink的设计架构 Flink是一个分层的架构系统&#xff0c;每一层所包含的组件都提供了特定的抽象&#xff0c;用来服务于上层组件&#xff0c;Flink的分层体…

搬家货运系统软件开发功能

生活中要用到搬家的场景很多&#xff0c;租房子、买房子、换房子都要搬家&#xff0c;不管是从时间还是专业性上来说&#xff0c;很多人都更愿意找专业的搬家公司来代为处理&#xff0c;于是市面上出现了各类各样的货运搬家软件&#xff0c;让有需求的用户可以直接在线预约搬家…