【MIT-BEVFusion代码解读】第二篇:LiDAR的encoder部分

news2024/12/21 22:50:45

文章目录

  • 1. Voxelization
  • 2. backbone
    • 2.1 稀疏卷积介绍
    • 2.2 SparseEncoder
      • (1)输入输出及参数说明
      • (2)流程


BEVFusion相关的其它文章链接:

  1. 【论文阅读】ICRA 2023|BEVFusion:Multi-Task Multi-Sensor Fusion with Unified Bird‘s-Eye View Representation
  2. MIT-BEVFusion训练环境安装以及问题解决记录
  3. 【MIT-BEVFusion代码解读】第一篇:整体结构与config参数说明
  4. 【MIT-BEVFusion代码解读】第二篇:LiDAR的encoder部分

encoder部分分为LiDARcamera两部分。这一篇文章主要介绍lidarencoder部分,lidarencoder主要有两部分,分别是voxelizebackbone,其中backbone部分使用的是SparseEncoder方式。
在这里插入图片描述

1. Voxelization

train.py部分中,使用build_model构建模型,其中使用注册器register根据type类型创建BEVFusion实例。这部分我们主要关注lidarenconder部分。

lidarvoxelization分为harddynamic voxelization,我们这里使用的是hard voxelization。创建voxel后再根据voxlizebackbone创建lidarencoders

if encoders.get("lidar") is not None:
    if encoders["lidar"]["voxelize"].get("max_num_points", -1) > 0:
    	# hard voxelization
        voxelize_module = Voxelization(**encoders["lidar"]["voxelize"])
    else:
    	# dynamic voxelization
        voxelize_module = DynamicScatter(**encoders["lidar"]["voxelize"])
    # 根据voxlize和backbone创建lidar的encoders
    self.encoders["lidar"] = nn.ModuleDict(
        {
            "voxelize": voxelize_module,
            "backbone": build_backbone(encoders["lidar"]["backbone"]),
        }
    )
    self.voxelize_reduce = encoders["lidar"].get("voxelize_reduce", True)

先来看一下voxelization部分的参数。如果对激光的体素化有所了解,这部分参数应该很好理解。

# 单个voxel最大点云个数
max_num_points: 10 
# voxel的大小[x, y, z]
voxel_size: [0.075, 0.075, 0.2] 
# 点云范围[x_min, y_min, z_min, x_max, y_max, z_max]
point_cloud_range: [-54.0, -54.0, -5.0, 54.0, 54.0, 3.0] 
# (training, testing)的最大点云个数
max_voxels: [120000, 160000]

激光的voxelization部分使用的是hard_voxelize代码,它是用c++实现,具体也不介绍了,这里只介绍一下它的调用部分。

这里输入points的某一帧的大小为[236137, 5],第一位为点的个数,第二位为每个点的属性,分别表示[x, y, z, intensity, timestamp_diff],其中最后一个timestamp_diff是指时间戳差异。

class _Voxelization(Function):
    @staticmethod
    def forward(
        ctx, points, voxel_size, coors_range, max_points=35, max_voxels=20000, deterministic=True
    ):
    	# 判断使用哪一种voxelization方法
        if max_points == -1 or max_voxels == -1:
            coors = points.new_zeros(size=(points.size(0), 3), dtype=torch.int)
            dynamic_voxelize(points, coors, voxel_size, coors_range, 3)
            return coors
        else:
        	# voxel.shape = [120000, 10, 5])
            voxels = points.new_zeros(size=(max_voxels, max_points, points.size(1)))
            # coors.size = [120000, 3])
            coors = points.new_zeros(size=(max_voxels, 3), dtype=torch.int)
            # num_points_per_voxel.shape = [120000]
            num_points_per_voxel = points.new_zeros(size=(max_voxels,), dtype=torch.int)
            # deterministic=True
            voxel_num = hard_voxelize(
                points,
                voxels,
                coors,
                num_points_per_voxel,
                voxel_size,
                coors_range,
                max_points,
                max_voxels,
                3,
                deterministic,
            )
            # select the valid voxels
            voxels_out = voxels[:voxel_num]
            coors_out = coors[:voxel_num]
            num_points_per_voxel_out = num_points_per_voxel[:voxel_num]
            return voxels_out, coors_out, num_points_per_voxel_out

2. backbone

2.1 稀疏卷积介绍

稀疏卷积常用于3D项目(如3D点云分割)中,由于点云数据是稀疏的,无法使用标准的卷积操作。同理,2D任务中,如果只处理其中一部分像素,也需要使用稀疏卷积,这样有助于模型加速。​ 本质上就是通过建立哈希表,保存特定位置的计算结果

稀疏卷积和普通卷积没有区别,最重要的区别在于卷积的数据的存储方式计算方法,这种计算方法可以增加计算稀疏点云的效率,其他的都是完全相同的(但SubMConv3d还是稍微有点区别的,只有中心kernel覆盖值才计算),唯一多了一个indice_key,这是为了在indice相同的情况下重复利用计算好的rulebookhash表,减少计算。

backbone根据注册器的type调用的是SparseEncoder方法。常用的两种3D稀疏卷积SparseConv3d(稀疏卷积)和SubMConv3d(子流形卷积):

  1. 系数卷积regular output definition,就像普通的卷积一样,只要kernel 覆盖一个 active input site,就可以计算出output site。对应论文:SECOND: Sparsely Embedded Convolutional Detection
  2. 子流形卷积:、submanifold output definition。只有当kernel的中心覆盖一个 active input site时,卷积输出才会被计算。对应论文:3D Semantic Segmentation with Submanifold Sparse Convolutional Networks

稀疏卷积是非常高效的,因为我们只计算非零元素(元素指的是像素或者体素)的卷积,而不需要计算所有的元素。稀疏卷积中的卷积计算,不用滑动窗口方法,而是根据rulebook计算所有的原子操作

2.2 SparseEncoder

BEVFusionLiDAR部分使用的backbone,调用的是spconv中的SparseEncoder函数。

(1)输入输出及参数说明

  • 参数说明
  • order("conv", "norm", "act"),稀疏卷积模块的顺序。make_sparse_convmodule会根据order的顺序创建稀疏卷积的子模块。其中三个主要模块self.conv_inputself.encoder_layersself.conv_out都是make_sparse_convmodule所创建。
  • block_type : 有两种形式,默认的是conv_module,另一种是basicblock形式。BEVFusion中的block_type使用的是basicblock
  • conv_type :卷积的形式,有SubMConv3dSparseConv3d形式、
  • 输入数据
  • 特征:[N, num_channels]
  • 索引:[N, (batch_idx, x, y, z)]batch_idxbatchsize的索引,坐标 xyz 顺序为体素化坐标系索引。

在代码中输入表现形式如下:

# 体素化后的点, 每个点的数据[x,y,z,i,ts]
voxel_features.shape = [nums, 5]
# 每个点对应的坐标,[batch_size, x, y, z]
# 第一位batch表示对应的第几个batch,x,y,z对应的是voxel索引。
coors.shape = [nums, 4]
  • 输出数据

最终输出BEV特征,维度大小为(N, C * D, H, W)

# 输出特征图的大小,N = 4, C=
# N: 表示batchsize大小
# H、W:特征图大小
# (N, C, D, H, W) = (4, 128, 2, 180, 180)
spatial_features.shape = (N, C * D, H, W) = [4, 256, 180, 180])

(2)流程

SparseEncoder的流程如下所示,这里的encoder_layers中使用的是basicblock

在这里插入图片描述

conv_inputencoder_layersconv_out的具体结构如下所示。

  • conv_input
SparseSequential(
  (0): SubMConv3d()
  (1): BatchNorm1d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (2): ReLU(inplace=True)
)
  • encoder_layers

encoder_layers根据self.encoder_channels =[[16, 16, 32], [32, 32, 64], [64, 64, 128], [128, 128]]创建layer,可以看出总共创建4个layer,每个layer的基本组成为SparseBasicBlockSparseConv3d。它们的具体结构如下所示。

SparseSequential(
  (encoder_layer1): SparseSequential(
    (0): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (1): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): SparseSequential(
      (0): SparseConv3d()
      (1): BatchNorm1d(32, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
  )
  (encoder_layer2): SparseSequential(
    (0): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(32, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(32, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (1): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(32, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(32, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): SparseSequential(
      (0): SparseConv3d()
      (1): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
  )
  (encoder_layer3): SparseSequential(
    (0): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (1): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(64, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (2): SparseSequential(
      (0): SparseConv3d()
      (1): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
  )
  (encoder_layer4): SparseSequential(
    (0): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
    (1): SparseBasicBlock(
      (conv1): SubMConv3d()
      (bn1): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (conv2): SubMConv3d()
      (bn2): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
    )
  )
)
  • conv_out
SparseSequential(
  (0): SparseConv3d()
  (1): BatchNorm1d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (2): ReLU(inplace=True)
)

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

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

相关文章

VPN远程同时连接:IPsec站点到站点方式及L2TPoverIPsecVPN方式

一、实验目的及拓扑 实验目的:企业总部与分支通过IPsecVPN建立点对点连接,移动端通过L2TP方式与企业总部连接 二、基本配置 1、如图所示配置接口地址 2、总部接口区域配置 [FW1]dis zone local priority is 100 interface of the zone is (0): # …

【数值计算方法】常微分方程初值问题的数值解法

常微分方程初边值问题数值解 第九章 1. 引言 微分方程 :含有未知函数及其导数或微分的等式; 除了少数特殊类型的微分方程能用解析方法求得精确解外 , 多数情况找不到解的解析表达式 本章研究两类常微分问题: 一阶常微分方程的初值问题 ; 两阶常微分方程边值问题 一…

C#小结:如何在VS2022中使用菜单栏中的Git管理代码

目录 第一部分:基础操作 第一步,登录官网,设置好邮箱,然后右上角新建仓库 第二步,提交代码到远程仓库中 第三步,查看和比对自己修改的内容 第四步,查看该项目所有提交历史记录 第五步&…

LAMM: Label Alignment for Multi-Modal Prompt Learning

系列论文研读目录 文章目录 系列论文研读目录文章题目含义AbstractIntroductionRelated WorkVision Language ModelsPrompt Learning MethodologyPreliminaries of CLIPLabel AlignmentHierarchical Loss 分层损失Parameter Space 参数空间Feature Space 特征空间Logits Space …

CSP-CCF 202009-1 检测点查询

一、问题描述 二、解答 提醒:本题不宜开方,距离间的比较用平方来比较更好 思路:使用三次for循环,逐一找到最小、第二小、第三小 注:这里用到了limits.h头文件,里面包含了int的最大值INT_MAX #include&l…

搭建企业博客:塑造品牌可信度与优化SEO的利器

引言 在数字化时代,信息的传播速度超乎想象,企业如何在这个信息爆炸的环境中脱颖而出,成为连接消费者、塑造品牌形象的关键。企业博客,作为一种低成本、高效率的营销与沟通工具,正逐渐成为企业策略中不可或缺的一环。…

阅读台灯什么品牌好?不良商家最常用的四大阅读台灯套路,需警惕

阅读台灯什么品牌好?市场上的护眼台灯种类繁多,众多选择中不乏以低价吸引消费者的产品,这也导致了部分家长对于护眼台灯的价值产生了质疑,认为它们不过是不必要的开销。确实,一些低质的护眼灯不仅使用了劣质材料&#…

利用minikube部署k8s集群并部署lnmp服务

部署minikube 参考官网进行安装部署 利用minikube部署k8s集群 1. 部署k8s集群 minikube start k8s集群部署lnmp 1. 将如下内容存储为lnmp.yaml文件 --- apiVersion: v1 kind: Namespace metadata: name: lnmp --- apiVersion: v1 kind: PersistentVolumeClaim metadata: na…

请注意,这是第一届程序化售卖广告的奥运会

作者:刀客doc 巴黎奥运会收官了。很多人在谈郑钦文的商业价值、哪个品牌押中了奥运冠军时,却忽略了一个新闻: 这是第一届程序化售卖广告的奥运会:NBC环球通过旗下的流媒体平台 Peacock,以程序化方式销售巴黎奥运会期…

基于java的私人牙科诊所管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于java的私人牙科诊所管理系统,java项…

文心一言 VS 讯飞星火 VS chatgpt (325)-- 算法导论22.5 1题

一、如果在图G中加入一条新的边,G中的强连通分量的数量会发生怎样的变化?如果要写代码,请用go语言。 文心一言: 在图G中加入一条新的边,其对强连通分量(Strongly Connected Components, SCCs)…

海量数据处理商用短链接生成器平台 - 1

第一章 海量数据处理商用短链接生成器平台介绍 第1集 什么是短链接生成器 短链接生成器是一种工具,可以将较长的链接转换成较短的链接。这种工具在许多场景中都很有用,包括营销、社交媒体分享和数据报告等。以下是一些关于短链接生成器的优点和作用&…

VS实用调试技巧(程序员的必备技能)

调试的重要性 在我们写代码的时候,如果程序出现了bug,那么下一步就是找到bug并修复bug!而这个找问题的过程就被称为调试(英文叫debug,消灭bug的意思)。 调试能观察到程序内部执行的细节,可以增加程序员对…

5大低代码开源平台案例研究

在当今快速发展的数字化时代,企业面临着越来越复杂的技术挑战和市场竞争。为了保持竞争力并加速业务创新,许多公司正在转向低代码开源平台。然而,选择合适的低代码平台并将其成功实施,依然是一个挑战。 本文将深入探讨五个成功案…

OpenAI gym: How to get pixels in CartPole-v0

题意:OpenAI Gym:如何在 CartPole-v0 中获取像素? 问题背景: I would like to access the raw pixels in the OpenAI gym CartPole-v0 environment without opening a render window. How do I do this? 我想在 OpenAI Gym 的 …

RAC11G场景下OLR文件丢失导致节点GI无法启动

环境说明 RHEL7.911.2.0.4 RAC,双节点。 问题描述 巡检发现节点2的GI无法启动,发现是olr文件丢失导致。 问题复现 故意把OLR删掉,重启后发现GI无法启动 查看/etc/oracle/olr.loc --查看/etc/oracle/olr.loc 该文件记录有olr文件位置和…

密探 -- 渗透测试工具 v1.14 版

1.如何运行 在jdk8环境下(在jdk8以上的高版本请参考常见问题1的处理方案)运行以下语句运行: java -jar mitan-jar-with-dependencies.jar 若不想输入这么长太长语句,可以通过以下脚本的方式启动: Mac/Linux 环境下,…

计算机网络——运输层(进程之间的通信、运输层端口,UDP与TCP、TCP详解)

运输层协议概述 进程之间的通信 运输层向它上面的应用层提供通信服务。 当网络边缘部分的两台主机使用网络核心部分的功能进行端到端的通信时,都要使用协议栈中的运输层;而网络核心部分中的路由器在转发分组时只用到下三层的功能。 Q1:我们…

【最短路径算法】

每日格言:想去的地方很遥远,我们也只能自己走 前言 最短路径算法是一类用于解决图中两点间寻找最短路径问题的算法。这里我们只具体介绍利用matlab中的函数实现,迪克斯特拉算法和弗洛伊德算法大家有兴趣可上网了解一下。这类算法在多个领域都…

安全稳定的镭速高端制造业文件传输摆渡系统

在现代制造业的高速发展中,高端制造领域尤为依赖高效的文件传输系统,这类系统不仅促进了企业内部的合作,还加强了与合作伙伴的紧密联系,成为推动创新和决策的关键因素。镭速文件传输系统正是为了满足这一需求而设计,其…