【MLP-BEV(5)】BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View 探索检测BEV3D的优势
最近在学习BEV 的head的设计,在BEVDet和BEVFormer里,使用了不同的3D detection head(BEVDet用了centerpoint,BEVFormer用了deformable detr)。BEVDet在鸟瞰图 (BEV) 中执行3D对象检测,其中定义了大多数目标值,并且可以轻松执行路线规划。我们仅重用现有模块来构建其框架,但通过构建专有数据增强策略并升级非最大抑制策略来显着提高其性能。
BEVDet 一直都在更新(截至2024年),包括:
深度:激光雷达监督的深度为 BEVDepth。
长期:时间建模中的 cat 8 历史框架。 默认为 1。
Stereo:一种私有实现,在执行 model.view_transformer.depth_net 之前将cost-volumn与图像特征连接起来。
这些都是后话,我们还是先看看 BEVDet 的本体部分。下一篇论文,我们来分析 4D 或者 poolv2.

文章目录
-
论文信息
-
1 Introduction
-
2 Related Works
-
- 2.1 Vision-based 2D Perception
- 2.2 Semantic Segmentation in BEV
- 2.3 Vision-based 3D Object Detection
-
3 Methodology
-
-
3.1 Network Structure
-
- Image-view Encoder
- View Transformer
- BEV Encoder
- Head
-
3.2 The Customized Data Augmentation Strategy
-
- BEV Space Learning with Data Augmentation.BEV空间学习与数据增强。
-
3.3 Scale-NMS
-
-
4 Experiment
-
- 4.1 Experimental Settings
- 4.2 Benchmark Results
- 4.3 Ablation Studies
-
总结创新点
-
代码分析
论文信息
文章:https://arxiv.org/abs/2112.11790
1 Introduction
基于图像视图的方法,如FCOS3D [49] 和PGD [50],在多摄像机3D物体检测具有领先的性能。
基于BEV的检测,如PON [39],Lift-Splat-Shoot [444],和VPN [31]。
我们探索了在 BEV 中检测3D对象的优势,期望与最新的基于图像视图的方法相比具有卓越的性能,并且具有BEV语义分割的一致范例。
尽管构建BEVDet的框架很简单,但构建其强大的性能并非易事。在验证BEVDet的可行性时,为了合理的性能,将BEVDet的数据处理策略和参数编号设置为FCOS3D [49] 和PGD [50] 等基于图像视图的3D对象检测器。
出乎意料的是,在训练过程中发现了严重的过度拟合问题 。
- 首先,为提升Splat-Shoot,应用复杂的数据增强策略以实现正则化效果。但是,只有在没有 BEV 编码器的情况下,才具有积极效果,否则,会降低性能。
- 另一方面,批量大小是N 的子序列模块的数量。训练数据不足也是BEV空间学习过度拟合的部分原因。
- 此外,我们观察到视图转换器以像素方式将图像视图空间与BEV空间连接起来,这从数据增强的角度将它们解耦。这使得图像视图中的数据增强对子序列模块 (即BEV编码器和3D对象检测头) 没有正则化作用。
因此,作为补充,在BEV空间中进行了其他数据增强操作,例如翻转,缩放和旋转,以确保模型在这些方面的鲁棒性。这在防止BEVDet过度拟合方面效果很好
此外,我们升级了经典的非最大抑制 (NMS) 策略,以提高其在3D物体检测场景中的适应性。通过删除顺序执行的运算符,进一步加快了推理过程。通过这些修改,BEVDet在现有范例之间提供了准确性和推理延迟之间的出色权衡。
在nuScenes [1] val集上,高速版本BEVDet-Tiny以704 × 256的图像大小实现了更高的精度 (即31.2% 地图和39.2% NDS),这仅仅是竞争对手的1/8 (即,在FCOS3D中29.5% 地图和37.2% 1600 × 900图像大小的NDS [49])。缩小图像尺寸可将计算预算减少89%,并提供9.2倍的显着加速 (即,具有215.3 GFLOPs和15.6 FPS的BEVDet v.s. FCOS3D具有2,008.2 GFLOPs和1.7 FPS)。通过构建另一个被称为BEVDet-Base的高精度配置,我们报告了39.3% 地图和47.2% NDS的新记录。此外,与现有范例相比,在BEV空间中明确编码特征使BEVDet能够感知目标的平移,比例,方向和速度。在消融研究中可以发现BEVDet的更多特征。
2 Related Works
2.1 Vision-based 2D Perception
Image Classificatio
图像分类基于视觉的2D感知的深度学习的复兴可以追溯到AlexNet [19] 进行图像分类。
从那时起,研究界通过提高残差 [14],高分辨率 [43],基于注意力 [7] 和许多其他类型的结构 [8,15,16,35,45] 来不断推动图像编码器的性能边界。同时,强大的图像编码能力也提高了其他复杂任务的性能,例如对象检测 [23,38],语义分割 [18,52], 姿态估计 [17,43]。作为一项简单的任务,图像分类的解决模式由Softmax [19] 及其导数主导。由网络结构决定,图像编码器的容量在这个问题中起着至关重要的作用,并且是研究界的主要关注点。
Object Detection
普通对象检测既要求类别标签又要求所有预定义对象的定位边界框,是一项更为复杂的任务,其中范例也起着至关重要的作用。两阶段方法Faster r-cnn [38],一阶段方法RetinaNet [23] 及其衍生物 [2,4,13,46,57] 是该领域的主要方法 [24,41]。受Mask r-cnn [13] 的启发,多任务学习一直是研究和工业界的一个吸引人的范例,因为它通过共享骨干和共同培训来节省计算资源的巨大潜力。范式创新在这一领域的巨大影响激励我们利用卓越的范式在自动驾驶场景中获得更好的感知性能,在自动驾驶场景中,任务更加复杂,多任务学习相当吸引人。
2.2 Semantic Segmentation in BEV
自动驾驶中的主要感知任务之一是矢量还原其周围环境的地图。这可以通过在BEV中针对可行驶区域,停车场,车道分隔线,停车线等目标进行语义分割来实现。在基准测试中具有领先性能的基于视觉的方法 [1] 总是具有类似的框架 [31,444,39,54]。
在此框架中,有四个主要组件:
- 用于编码图像视图中的特征的图像视图编码器,
- 用于将特征从图像视图转换为BEV的视图变换器,
- 用于进一步编码BEV中的特征的BEV编码器
- 以及用于按像素分类的头。
BEV语义分割管道的成功鼓励我们将其扩展到3D对象检测任务,期望BEV中的特征可以很好地捕获3D对象的某些目标,例如比例,方向和速度。此外,我们还在寻求一种可扩展的范例,在该范例中,可以以高精度和高效率实现多任务学习
2.3 Vision-based 3D Object Detection
D物体检测是自动驾驶中的另一个关键感知任务。在过去的几年中,KITTI [9] 基准测试推动了单眼3D物体检测的快速发展 [20、27、29、36、47、48、58、61、64]。但是,有限的数据和单一的视图使其无法开发更复杂的任务。最近,已经发布了一些具有更多数据和多个视图的大型基准 [1,44],为多摄像机3D对象检测中的范例开发提供了新的视角。基于这些基准,已经开发了一些具有竞争力的性能的多摄像机3D物体检测范例。例如,受到FCOS [46] 在2D中的成功的启发
FCOS3D [49] 将3D物体检测问题视为2D物体检测问题,并仅在图像视图中进行感知。得益于目标属性与图像外观之间的强空间相关性,它可以很好地预测这一点,但在感知目标的平移,速度和方向方面却相对较差。在DETR [3] 之后,DETR3D [51] 提出以注意模式检测3D对象,其精度与FCOS3D相似。尽管DETR3D只需要一半的计算预算,但复杂的计算管道将其推理速度降低到与FCOS3D相同的水平。PGD [50] 通过搜索和解决突出的缺点 (即对目标深度的预测),进一步发展了FCOS3D范式。这在基线上提供了显着的准确性改进,但代价是更多的计算预算和额外的推理延迟。现有范例在准确性和时间效率之间的权衡有限。这促使我们寻求和开发新的产品,以大幅推动该领域的性能边界。
有一些先驱 [5,21,36],他们利用了BEV中的3D物体检测任务。其中,也受到Lift-Splat-Shoot 的启发,[36] 是与我们最相似的一个。他们将Lift-Splat-Shoot范例应用于单眼3D物体检测,并通过参考LiDARs进行深度预测的监督,使其在KITTI [9] 基准中具有竞争力。在DD3D的并发工作中可以找到一个紧密的想法 [32]。不同的是,在不依赖LiDARs的情况下,我们通过基于视图变压器的解耦效果构建独家数据增强策略来升级此范例。这是一种更可行的方法,并且在使BEVDet范例在现有方法之间具有竞争力方面起着至关重要的作用。
3 Methodology

3.1 Network Structure
如图1所示,具有模块化设计的BEVDet由四种模块组成: 图像视图编码器,视图变换器,BEV编码器和任务特定头。我们通过构造Tab中列出的具有不同结构的几种导数来研究BEVDet的可行性。1.

Image-view Encoder
图像视图编码器将输入图像编码为高级功能。为了利用多分辨率特征的功能,imageview编码器包括用于高级特征提取的主干和多分辨率特征融合的颈部。默认情况下,我们使用经典的ResNet [14] 和最新的基于注意的SwinTransformer [26] 作为原型研究的骨干。取代项包括DenseNet [16] 、HRNet [43] 等。关于颈部模块,我们使用经典的FPN [22] 和 [33] 中提出的颈部结构,在下文中称为fpn-lss。Fpn-lss只需将具有1/32输入分辨率的特征上采样即可1/16输入分辨率,并将其与主干生成的特征连接。更复杂的颈部模块尚未被利用,如PAFPN [25] 、NAS-FPN [10] 等。
View Transformer
视图转换器将特征从图像视图转换为BEV。我们应用 [33] 中提出的视图变换器来构建BEVDet原型。采用的视图变换器以图像视图特征为输入,并通过分类方式密集预测深度。然后,将分类分数和派生的图像视图特征用于渲染预定义的点云。最后,可以通过沿垂直方向 (即,如图1所示的Z坐标轴) 应用池化操作来生成BEV特征。实际上,我们将深度预测的默认范围扩展到 [1,60] 米,间隔为1.25 × r,其中r表示输出特征的分辨率。
BEV Encoder
BEV编码器进一步编码BEV空间中的特征。尽管该结构类似于具有主干和颈部的图像视图编码器的结构,但它可以高精度地感知一些关键提示,例如在BEV空间中定义的比例,方向和速度。我们遵循 [33] 利用具有经典残差块的ResNet [14] 来构造主干,并通过应用fpn-lss来组合具有不同分辨率的特征。
Head
特定于任务的头部是基于BEV功能构建的。从常识 [1] 来看,自动驾驶中的3D物体检测针对的是行人,车辆,障碍物等可移动物体的位置,比例,方向和速度。在没有任何修改的情况下,我们直接在CenterPoint [56] 的第一阶段采用3D物体检测头进行原型验证,并与基于LiDAR的管道 (如PointPillar [21] 和VoxelNet [60]) 进行公平比较。中心点的第二个细化阶段尚未应用。
3.2 The Customized Data Augmentation Strategy
The Isolated View Spaces孤立的视图空间 :视图变换器 [33] 以像素方式将特征从图像视图转换为BEV。具体地说,给定一个像素 ,在特定深度d的情况下, 在三维空间中对应的坐标为:

其中 I 是3 × 3相机本征矩阵。
具有翻转、裁剪和旋转等操作的常见数据增强策略可以公式化为3 × 3变换矩阵A [17] ,在输入图像上应用数据增强策略时 ,反变换A^{−1}应在视图变换 [33] 中应用,以保持BEV空间中特征和目标之间的空间一致性:

在图像视图空间中应用的增强策略不会改变BEV空间中特征的空间分布。这使得在图像视图空间中执行复杂的数据增强策略对于BEVDet是可行的。
BEV Space Learning with Data Augmentation.BEV空间学习与数据增强。
关于BEV空间中的学习,由于每个样本包含多个相机图像 (例如,nuScenses基准中的每个样本包含6个图像 [1]),因此数据的数量少于图像视图空间中的数据数量。因此,在BEV空间中的学习容易陷入过度拟合 。由于视图变换器在增强视角中隔离了两个视图空间,因此我们构造了另一种增强策略,该策略特定于对BEV空间学习的正则化影响。
遵循最新的基于激光雷达的方法 [34,55,56,63],采用了2D空间中的常见数据增强操作,包括翻转,缩放和旋转。
在实践中,对视图变换器的输出特征 和3D对象检测目标 进行操作,以保持其空间一致性。值得注意的是,这种数据增强策略是建立在视图变换器可以将imageview编码器与后续模块解耦的前提下的。
这是BEVDet的特定特征,在其他方法中可能无效 [49-51]。
Wang, T., Zhu, X., Pang, J., Lin, D.: FCOS3D: Fully Convolutional One-Stage
Monocular 3D Object Detection. arXiv preprint arXiv:2104.10956 (2021)
50. Wang, T., Zhu, X., Pang, J., Lin, D.: Probabilistic and Geometric Depth: Detecting
Objects in Perspective. arXiv preprint arXiv:2107.14160 (2021)
51. Wang, Y., Guizilini, V., Zhang, T., Wang, Y., Zhao, H., Solomon, J.: DETR3D:
3D Object Detection from Multi-view Images via 3D-to-2D Queries. arXiv preprint
arXiv:2110.06922 (2021)
\hat{X}=\sum^{a}_{b}(x+y)
3.3 Scale-NMS
BEV空间中不同类别的空间分布与图像视图空间中的空间分布完全不同。
- 在图像视图空间中,由于相机的透视成像机制,所有类别共享相似的空间分布。因此,具有固定阈值的经典非最大抑制 (NMS) [40] 策略可以很好地调整所有类别的预测结果,以符合先验 (例如,在2D对象检测中,两个实例之间的边界框相交超过联合 (IOU) 指示符始终低于0.5的特定阈值 [11、23、37、38、46])。
- 然而,它在BEV空间中是不同的。
- 在BEV空间中,各个类的占用区域本质上是不同的,并且实例之间的重叠应关闭为零。结果,预测结果之间的IOU分布因类别而异。例如,如图2所示,像行人和交通锥这样的对象在地平面中占据很小的区域,其总是小于算法的输出分辨率 (例如,在中心点 [56] 中0.8米)。常见的物体检测范例 [23,38,46,56] 冗余地生成预测。每个对象的小占用面积可能会使冗余结果与真实的正结果没有交集。这会使依赖IOU访问真阳性和假阳性之间的空间关系的经典NMS失活。
为了克服上述问题,我们在本文中提出了Scale-NMS。Scale-NMS在执行经典NMS算法之前,根据其类别缩放每个对象的大小。这样,调整了真实阳性和冗余结果之间的IOU分布,以与经典的NMS匹配。如图2的第二行所示,在预测小对象时,Scale-NMS通过放大对象大小来建立结果之间的空间关系,这使得经典NMS能够根据IOU指示符来丢弃冗余的NMS。实际上,我们将Scale-NMS应用于除屏障之外的所有类别,因为屏障的大小各不相同。缩放因子是特定于类别的。它们是通过在验证集上进行超参数搜索而生成的。

4 Experiment
4.1 Experimental Settings
Dataset 我们对大型基准nuScenes [1] 进行了综合实验。nuScenes基准包括来自6个摄像机的1000个场景。它是基于视觉的3D对象检测 [32,49-51] 和BEV语义分割 [31,444,39,54] 的最新流行基准。这些场景被正式分成700/150/150场景,用于训练/验证/测试。多达1.4M带注释的3D边界框,可用于10个类别: 汽车,卡车,公共汽车,拖车,建筑车辆,行人,摩托车,自行车,障碍物和交通 锥。在中心点 [56] 之后,我们定义了地平面中51.2米内的感兴趣区域 (ROI),默认情况下分辨率 (即中心点 [56] 中的体素大小) 为0.8米。
Evaluation Metrics
对于3D物体检测,我们报告了官方预定义的指标: 平均平均精度 (mAP),平均平移误差 (ATE),平均比例误差 (ASE),平均方向误差 (AOE),平均速度误差 (AVE),平均属性误差 (AAE),和NuScenes检测评分 (NDS)。
mAP 类似于2D对象检测 [24] 中的mAP,用于测量精度和召回率,但基于地面平面上2D中心距离的匹配而不是并集 (IOU) [1]
NDS是综合判断检测能力的其他指标的组合。其余度量被设计用于计算相应方面 (例如,平移,比例,方向,速度和属性) 的正结果的精度。
练参数模型使用AdamW [28] 优化器进行训练,其中梯度剪辑利用学习率2e-4,在8个NVIDIA GeForce RTX 3090 gpu上的总批处理大小为64。对于基于ResNet [14] 的图像视图编码器,我们应用了逐步学习率策略,该策略将历元17和20的学习率降低了0.1倍。关于基于SwinTransformer [26] 的图像视图编码器,我们应用循环策略 [53],该策略在第一个40% 计划中线性地增加从2e-4到1e-3的学习率,并在剩余时期线性地减少从1e-3到0的学习率。默认情况下,总计划在20个时期内终止。
Data Processing
我们使用Win × Hin表示输入图像的宽度和高度。在训练过程中,默认情况下,1600 × 900分辨率 [1] 的源图像:
- 通过随机翻转,范围为s ∈ [Win/1600-0.06,Win/1600 0.11] 的随机缩放,
- 范围为r ∈ [− 5.4的随机旋转,5.4 °],
- 最后裁剪到Win × Hin的大小。裁剪在水平方向上随机进行,但在垂直方向上固定((y1, y2) = (max(0, s ∗ 900 − Hin), y1 + Hin)), 其中y1和y2是目标区域的上限和下限。)
在BEV空间中,通过随机翻转、以 [-22.5 °,22.5 °] 的范围随机旋转和以 [0.95,1.05] 的范围随机缩放来增强输入特征和3D对象检测目标。
在CenterPoint [56] 之后,所有模型都使用CBGS [62] 进行训练。
在测试时间内,输入图像按s = Win/1600 + 0.04的因子缩放,并裁剪为Win × Hin分辨率,区域定义为:(x1, x2, y1, y2) = (0.5 ∗ (s ∗ 1600 −Win), x1 +Win, s ∗ 900 −Hin, y1 +Hin).
Inference Speed
我们基于MMDetection3D [6] 进行所有实验。所有推理速度和计算预算都经过测试,无需增加数据。对于像FCOS3D [49] 和PGD [50] 这样的单眼范例,推理速度除以系数6 (即单个样本 [1] 中的图像数量),因为它们将每个图像作为独立样本。值得注意的是,“速度除法”的操作可能不是最佳方法,因为批处理模式中的处理可以加快单目范式的推断。
我们通过用另一个等效实现替换视图转换中的累积和运算来加速提出的BEVDet范式。
详细信息可在消融研究部分找到。

4.2 Benchmark Results
nuScenes val集我们将提出的BEVDet与其他范例进行了全面比较,例如FCOS3D [49],其升级版PGD [50] 和DETR3D [51]。它们的参数数量,计算预算,推理速度和nuScenes val集的准确性都在选项卡中列出。2.
作为被称为BEVDet-Tiny的高速版本,我们将参数的数量设置为接近竞争对手,并为其配备704 × 256的小输入分辨率。仅1/8竞争者的输入大小 (即,BEVDet-Tiny的704 × 256 v.s.FCOS3D,DETR3D和PGD的1600 × 900),BEVDet-Tiny仅需要215.3的GFLOPs计算预算,并且可以在15.6 FPS中进行处理。它31.2% 地图和39.2% NDS进行评分,比FCOS3D (29.5% 地图和37.2% NDS) 和DETR3D (30.3% 地图和37.4% NDS) 具有更高的精度。然而,它需要少得多的计算预算 (2,008.2 FCOS3D的GFLOPs,1,016.8 DETR3D的GFLOPs) 并且具有更快的推理速度 (1.7 FCOS3D的FPS,2.0 DETR3D的FPS)。具有1600 × 640输入分辨率的BEVDet-Base需要2962.6 GFLOPs分数39.3% mAP和47.2% NDS。凭借竞争性的推理速度,BEVDet-Base的性能优于所有已发布的结果。它显著地超过了前面的领先方法PGD + 5.8% mAP和 + 6.3% NDS的幅度。值得注意的是,尽管BEVDet-Base的计算预算几乎是DETR3D的3倍 [51],但BEVDet-Base可以以1.9 FPS的可比速度进行处理。简单的设计使BEVDet能够比现有范例更快地运行。
考虑到真正积极结果的平移 (ATE) 、比例 (ASE) 、方向 (AOE) 、速度 (AVE) 和属性 (AAE) 误差,BEVDet在预测目标的平移、比例、方向和速度方面表现良好 ,这与常识一致,即代理更容易在BEV中捕获这些信息。但是,与基于图像视图的方法 (例如FCOS3D和PGD) 相比,BEVDet在预测目标属性方面表现不佳。我们推测属性判断依赖于外观提示,这对于代理在图像视图中更容易感知 。这两种观点的结合是解决这一问题的有希望的解决方案,将在今后的工作中进行研究。
nuScenes test set 对于nuScenes测试一下集,我们在train集和val集上训练BEVDet-Base配置。采用测试一下时间增加的单一模型。如选项卡中列出的。3,BEVDet在nuScenes基于视觉的3D异议排行榜上排名第一,得分为42.2% 地图和48.2% NDS,超过了先前的领先方法PGD [50] 3.6% 地图和3.4% NDS。这与那些依赖于激光雷达传感器进行预训练的人相当,如DD3D [32] 和DETR3D [51]。还值得注意的是,基于视觉的BEVDet的准确性与基于经典激光雷达的方法pointpills [21] (即30.5% 地图和45.3% NDS) 相当。
4.3 Ablation Studies

Data Augmentation
BEVDet-Tiny在标签中。1,我们研究了BEVDet的性能是如何通过定制的数据增强策略来开发的。
我们采用20个时期的固定训练时间表,并报告训练过程中的最佳表现和最后一个时期的最终表现。通过报告和比较两者,我们分析了数据增强策略如何影响饱和点的性能,以及数据增强在多大程度上缓解了过度拟合问题。考虑了一些关键因素,包括图像视图空间数据增强 (IDA),BEV空间数据增强 (BDA) 和BEV编码器 (BE)。我们在Tab中列出了不同配置的性能。4.
作为基线,我们只需将基于激光雷达的方法CenterPoint [56] 中的头部输入特征替换为 [444] 中提出的视图转换器生成的特征。在此配置选项卡中。如图4 (A) 所示,不存在所有增强策略。在训练过程中,指标图在23.0% 的第4个时期早期变得饱和,并在随后的时期陷入过拟合。最后,在epoch 20处的性能仅与最佳5.6% 的下降17.4%,这比基于图像视图的方法FCOS3D (29.5%) 差得多。
通过在配置选项卡中应用图像视图空间数据增强 (IDA)。如图4 (B) 所示,训练过程的饱和被推迟到第10期 (20.5%),最终得分17.8%。这种配置的最佳性能甚至比基线还要差 (即,表4 (A))。相比之下,配置选项卡。图4 © 的BEV-空间数据增强 (BDA) 的峰值在第15期具有26.2% 地图,最后在第20期获得23.6% 地图。这在峰值点超过基线 + 3.2% mAP的大范围。BDA在培训BEVDet方面比IDA发挥着更重要的作用。通过在配置选项卡中组合IDA和BDA。如图4 (D) 所示,地图性能在31.6% 的时期17达到峰值,最后在时期20得分31.2%。与基线相比,组合数据增强策略在峰值点提供 + 8.6% mAP的显著性能提升。在epoc20处的性能退化被降低到-0.4%。值得注意的是,当BDA不存在时,IDA会对性能产生负面影响,但相反会产生积极影响
为了研究BEV编码器 (BE) 的影响,我们在配置选项卡中删除BE。4 (E、F、G和H)。比较配置选项卡。在图4 (D) 和 (H) 中,BE通过1.7% 图提高了BEVDet的精度,表明它是构建BEVDet性能的关键组件之一。通过比较配置选项卡。4 (F) 与 (G) 一起,我们发现IDA在不存在BDA时可以提供积极的影响,而在存在BE时则相反。我们推测,只有在BDA的存在下,BEV编码器的强大感知能力才能建立。这可以通过比较配置选项卡的最佳性能来验证。4 (A,B,C和D) 分别具有 (E,F,G和H)。
Scale-NMS
我们采用BEVDet-Tiny in Tab。1用于NMS策略的消融研究。如选项卡所示。5,按类别分类,我们将Scale-NMS与经典NMS和CenterPoint [56] 中提出的Circular-NMS进行了比较。拟议的Scale-NMS显著提高了具有小占用区域的类别的性能,如行人 (+ 4.8% AP) 和交通锥 (+ 7.5% AP)。其他规模相对较大的类别也受益于Scale-NMS 。卡车 (+ 0.3% AP) 、拖车 (+ 0.7% AP) 和建筑车辆 (+ 0.3% AP)。因此,整体性能图从29.5% 提升到31.2%,提高了 + 1.7%。

Resolution

信号通道的分辨率对于BEVDet至关重要。它不仅影响模型的准确性,而且在计算预算和推理延迟中起着关键作用。由于BEVDet涉及两个视图空间,因此这里研究了两个主要的通道分辨率: 输入图像的分辨率和BEV编码器输入特征的分辨率。我们在Tab中进行了几个消融实验。6具有一些典型设置。根据结果,输入图像的分辨率对精度有很大影响。
BEVDet与1408 × 512输入大小选项卡E在具有704 × 256输入大小选项卡的4.5% mAP上具有优势C.
值得注意的是,随着输入大小的增加,BEV编码器和头的计算预算不变,BEVDet计算预算的增量受到限制。此外,较大的输入大小对预测目标的平移,规模和方向也具有持续的积极影响。
关于BEV编码器输入功能的分辨率,在大多数经典的基于激光雷达的方法中,它也可以被视为体素大小 [56,60]。提高BEV编码器输入功能的分辨率可以提高mAP,mATE和mAOE指标上模型的准确性,但代价是更高的计算预算和推理延迟。
图像视图编码器中的主干类型
我们通过在Tab中构造具有不同结构的BEVDet的3个导数来研究主干类型在图像视图编码器中的影响。1.它们都是在包含相似数量的参数的原则下构造的。如选项卡中列出的。7,采用两种输入分辨率。当将图像视图编码器的主干类型从ResNet-R50 [14] 更改为具有704 × 256低输入分辨率的SwinTransformer-Tiny [26] 时,增益为 + 1.4% mAP和 + 1.3% NDS (即,带有29.8% 地图和37.9% NDS v.s. BEVDet的BEVDet-R50-带有31.2% 地图和39.2% NDS的微小)。BEVDet-R50在预测目标的速度,而BEVDet-Tiny在预测目标的平移和方向方面具有出色的性能。
关于BEVDet-R101,当采用704 × 256的小输入尺寸时,增益仅是BEVDet-R50上的 + 0.4% 映射和 + 0.2% NDS。然而,当应用1056 × 384的较大输入尺寸时,增益是 + 1.2% 映射和 + 0.7% NDS。我们推测更大的感受野在扩大输入大小方面起着重要作用。
总结创新点
- 构建BEVDet的框架很简单,但构建其强大的性能并非易事。
- 数据增强策略
- NMS 新的研究
在View Transformer 采用的 LSS的方案。Head 的centerpoint方案。BEV Encoder 类似与骨干部分的结构。
代码分析
1、mmdet3d/models/detectors/bevdet.py
class BEVDet(...):
def __init__(...):
...
def forward_test(...):
if not isinstance(img_inputs[0][0], list):
return self.simple_test(...)
def simple_test(...):
img_feats, _, _ = self.extract_feat(...)
# 参考centerpoint
bbox_pts = self.simple_test_pts(img_feats, img_metas, rescale=rescale)
def extract_feat(...):
img_feats, depth = self.extract_img_feat(...)
pts_feats = None
return (img_feats, pts_feats, depth)
def extract_img_feat(...):
# 提取环视图片的特征
x = self.image_encoder(img[0])
# BEV 特征
x, depth = self.img_view_transformer([x] + img[1:7])
# -> mmdet3d/models/necks/view_transformer.py
x = self.bev_encoder(x)
return [x],depth
2、mmdet3d/models/necks/view_transformer.py
Voxel pooling的关键步骤为voxel_pooling_prepare_v2,为了更好的理解,在代码下方准备了图例来进行理解。
class LSSViewTransformer(...):
def create_frustum(...):
...
def forward(self, input):
""" Transform image-view feature into bird-eye-view feature.
Args:
input: [image-view feature,rots,trans,intrins,post_rots,post_trans]
image-view feature:环视图片特征
rots:由相机坐标系->车身坐标系的旋转矩阵
trans:相机坐标系->车身坐标系的平移矩阵
intrinsic:相机内参
post_rots:由图像增强引起的旋转矩阵
post_trans:由图像增强引起的平移矩阵
"""
# LIFT, x:[6, 139, 16, 44]
# 前self.D为预测的离散距离,后self.out_channels为深度特征
x = self.depth_net(x)
# 深度
depth_digit = x[:, :self.D, ...]
# 特征
tran_feat = x[:, self.D:self.D + self.out_channels, ...]
# 深度概率分布
depth = depth_digit.softmax(dim=1)
# 转化到bev空间
return self.view_transform(input, depth, tran_feat)
def view_transform(...):
return self.view_transform_core(input, depth, tran_feat)
def view_transform_core(...):
'''
Args:
input:[1, 6, 512, 16, 44],环视相机特征
depth:[6, 59, 16, 44],# 深度概率分布
tran_feat: [6, 80, 16, 44],深度特征
'''
if ...:
...
else:
# 获得点云
coor = self.get_lidar_coor(*input[1:7])
# 将点云投影到BEV空间
# 讲解链接可参考 https://zhuanlan.zhihu.com/p/586637783
bev_feat = self.voxel_pooling_v2(...)
# bev_feat:[1, 80, 128, 128] depth:[6, 59, 16, 44]
return bev_feat,depth
def get_lidar_coor(...):
# self.frustum 视锥
# 减去数据增强的平移矩阵
points = self.frustum.to(rots) - post_trans.view(B, N, 1, 1, 1, 3)
# 乘以图像预处理的旋转矩阵的逆矩阵
points = torch.inverse(post_rots).view(B, N, 1, 1, 1, 3, 3).matmul(points.unsqueeze(-1))
# 图像坐标系 -> 归一化相机坐标系 -> 相机坐标系 -> 车身坐标系
# lamda * [xs, ys, 1 ] -> lamda * xs ,lamda * ys , lamda,在多个项目中都有体现,像素坐标系转相机坐标系
points = torch.cat((points[..., :2, :] * points[..., 2:3, :], points[..., 2:3, :]), 5)
# 相机内参
combine = rots.matmul(torch.inverse(cam2imgs))
# 相机坐标系转车身坐标系
points = combine.view(B, N, 1, 1, 1, 3, 3).matmul(points).squeeze(-1)
points += trans.view(B, N, 1, 1, 1, 3)
# bad 为BEV 特征下的增强矩阵,这里为单位矩阵
# 解释来源为 https://github.com/Megvii-BaseDetection/BEVDepth/issues/44
points = bda.view(B, 1, 1, 1, 1, 3,3).matmul(points.unsqueeze(-1)).squeeze(-1)
return points
def voxel_pooling_v2(self, coor, depth, feat):
"""
Args:
coor:车身坐标系下的视锥点坐标
depth:离散深度概率分布
feat:深度特征
"""
ranks_bev, ranks_depth, ranks_feat, interval_starts, interval_lengths = self.voxel_pooling_prepare_v2(coor)
def voxel_pooling_prepare_v2(...):
"""Data preparation for voxel pooling
"""
B, N, D, H, W, _ = coor.shape
num_points = B * N * D * H * W # 总视锥点个数
ranks_depth = torch.range(0, num_points - 1, dtype=torch.int, device=coor.device) # 0~249215
# 每一层feat的位置索引 [0,1,2,3..4223,0,1,2...,4223,...,0,1,2...,4223]
ranks_feat = ...
# 将原点移动到左下角并且将坐标系转到BEV空间的尺度
# [-51.2,51.2] -> [0,102.4] -> [0,128]
coor = ((coor - self.grid_lower_bound.to(coor)) / self.grid_interval.to(coor))
coor = coor.long().view(num_points, 3
# 记录当前视锥点在哪个batch
batch_idx = torch.range(0, B - 1).reshape(B, 1). expand(B, num_points // B).reshape(num_points, 1).to(coor)
coor = torch.cat((coor, batch_idx), 1)
# 过滤掉不在bev空间下的视锥点
kept = (coor[:, 0] >= 0) & (coor[:, 0] < self.grid_size[0]) & \
(coor[:, 1] >= 0) & (coor[:, 1] < self.grid_size[1]) & \
(coor[:, 2] >= 0) & (coor[:, 2] < self.grid_size[2])
if len(kept) == 0:
return None, None, None, None, None
# 挑选BEV空间下的视锥点
coor, ranks_depth, ranks_feat = coor[kept], ranks_depth[kept], ranks_feat[kept]
# 利用视锥 点的batch,x,y 计算出 视锥点在BEV特征下的全局索引(128*128)
ranks_bev = coor[:, 3] * (self.grid_size[2] * self.grid_size[1] * self.grid_size[0])
ranks_bev += coor[:, 2] * (self.grid_size[1] * self.grid_size[0])
ranks_bev += coor[:, 1] * self.grid_size[0] + coor[:, 0]
# 排序,将BEV空间下,全局索引为相同的值排列在一起
order = ranks_bev.argsort()
ranks_bev, ranks_depth, ranks_feat = ranks_bev[order], ranks_depth[order], ranks_feat[order]
kept = torch.ones(ranks_bev.shape[0], device=ranks_bev.device, dtype=torch.bool)
# 错位比较,可以使得索引位置相同的,收个位置为True,如图所示。
kept[1:] = ranks_bev[1:] != ranks_bev[:-1]
interval_starts = torch.where(kept)[0].int()
if len(interval_starts) == 0:
return None, None, None, None, None
interval_lengths = torch.zeros_like(interval_starts)
# 每个为True的索引位置,向前累加的长度
interval_lengths[:-1] = interval_starts[1:] - interval_starts[:-1]
interval_lengths[-1] = ranks_bev.shape[0] - interval_starts[-1]
return ranks_bev.int().contiguous(), ranks_depth.int().contiguous(
), ranks_feat.int().contiguous(), interval_starts.int().contiguous(
), interval_lengths.int().contiguous()
Voxel Pooling 图例

5、mmdet3d/ops/bev_pool_v2/src/bev_pool_cuda.cu
void bev_pool_v2(...) {
"""
Args:
c:80,bev特征channel维度
n_intervals:Nd,位置为true的索引的集合
其他参数见上方的 voxel_pooling_prepare_v2函数
"""
# 索引位置为True的视锥点,每个视锥点的特征深度为80 一共开辟 视锥点个数*80个thread
# 共有(int)ceil(((double)n_intervals * c / 256)) 个block ,每个block有 256个线程 ,为每个深度特征的每一层(80层)创建一个thread
bev_pool_v2_kernel<<<(int)ceil(((double)n_intervals * c / 256)), 256>>>(...);
}
__global__ void bev_pool_v2_kernel(...) {
// out:输出的bev特征 [1,1,128,128,80]
int idx = blockIdx.x * blockDim.x + threadIdx.x; //当前thread的全局索引
int index = idx / c; // 当前处理哪一个视锥点
int cur_c = idx % c; // 当前处理哪一个视锥点的第 cur_c 层的数据 (共80层)
if (index >= n_intervals) return;
int interval_start = interval_starts[index]; // 为True的索引
int interval_length = interval_lengths[index]; // 向前累加多少个长度
float psum = 0; //某层深度特征的累加和
const float* cur_depth;
const float* cur_feat;
// 累加
for(int i = 0; i < interval_length; i++){
cur_depth = depth + ranks_depth[interval_start+i]; # 视锥点的预测深度
cur_feat = feat + ranks_feat[interval_start+i] * c + cur_c; # 视锥点深度特征
psum += *cur_feat * *cur_depth; # 相乘
}
const int* cur_rank = ranks_bev + interval_start; // ranks_bev + interval_start 在bev特征的位置索引(128*128)中的位置索引
float* cur_out = out + *cur_rank * c + cur_c; // 在BEV特征中的位置索引(128*128*80)中的位置索引
*cur_out = psum;
}
(代码部分完)
