IA"/>
【IA
结果:
IA-SSD为目前最快的3d点云目标检测网络,在单个RTX 2080Ti上速度高达 85 FPS!
论文地址:.11139
代码: 演示视频: =3jP2o9KXunA
85FPS的速度是由低内存占用量和高度并行性实现的,所以不能够用在实时应用中,论文中也有比较:
“Mem”和“Paral”表示推理期间每帧的GPU内存占用量以及可以在一个RTX2080Ti(11GB)上并行化的最大批量数量。”速度⊥”, ”速度⊤” 是处理一帧或全负载GPU存储器时的推理速度,†表示将场景分成四个平行部分以加速第一采样层。
可以看到,得益于IA-SSD极小的显存占用,在测试时可以并行处理100帧点云图像,从而做到极快的速度,但在实时应用中不会同时得到多帧点云图像,所以这里的高速度具有一定的局限性,不过IA-SSD极小的显存占用仍然是一个优点。
出发点:
通过实验发现,许多重要的前景点在最后的边界框回归步骤之前已经被丢弃了。因此其检测性能,特别是对行人等小物体的检测,受到了根本上的限制:
图示为前景点(即汽车、行人和自行车)的实例召回率
16384个点的输入点云通过4个下采样层逐渐下采样到256个点,可以看到使用D-FPS方法最后256个点的召回率在行人上降至不足70%,而文章中提出的方法仍能保持95%以上。注意,论文所提出的方法,前两层中使用的还是D-FPS,只有最后两层不同。
解决方案:
为了尽可能地保留前景点,转向利用每个点的潜在语义,因为随着分层聚合在每一层进行操作,学习到的点特征可能包含更丰富的语义信息。基于这一思想,提出了以下两种面向任务的采样方法:
1.Class-aware Sampling 类别感知采样
该采样策略旨在学习每个点的语义,以实现选择性下采样。
两个MLP层附加到编码层以进一步估计每个点的语义类别。从原始边界框注释生成的逐点一热语义标签用于监督。
for k in range(len(confidence_mlp)):shared_mlp.extend([nn.Conv1d(out_channels,confidence_mlp[k], kernel_size=1, bias=False),nn.BatchNorm1d(confidence_mlp[k]),nn.ReLU()])out_channels = confidence_mlp[k]shared_mlp.append(nn.Conv1d(out_channels, num_class, kernel_size=1, bias=True),)
(128,1024)--> (128,1024) --> (3,1024) 1024个点,每个点为3个类别的得分
(256,512)--> (256,512) --> (3,512) 512个点,每个点为3个类别的得分
cls_features_max, class_pred = cls_features_tmp.max(dim=-1)score_pred = torch.sigmoid(cls_features_max) # B,Nscore_picked, sample_idx = torch.topk(score_pred, npoint, dim=-1)
取得分高的前n个点
交叉熵损失计算:
2.Centroid-aware Sampling 质心感知采样
赋予更接近实例质心的点更高的权重
f*,b*,l*,r*,u*,d*分别表示一个点到边界框的6个表面(前,后,左,右,上和下)的距离
在这种情况下,更接近盒子质心的点可能具有更高的掩模得分(最大值为1),而位于表面上的点将具有0的掩模得分。在训练期间,软点掩模将用于基于空间位置为边界框内的点分配不同的权重,因此隐含地将几何先验结合到网络训练中。
加权交叉熵损失计算:
3.Contextual Centroid Prediction 上下文质心预测
仿照VoteNet网络,预测一个与中心的偏移。质心预测损失公式如下:
网络结构:
输入点云首先经过几个SA层,然后是实例感知的下采样,以逐步减少内存和计算成本。保留的代表点进一步输入上下文质心感知模块,例如中心预测和建议生成。最后输出3D边框和相关的类标签。
网络可分为两部分:
- backbone_3d: IASSD_Backbone
- point_head : IASSD_Head
IASSD_Backbone有六层:
层数 | 采样方法 | Grouping半径 | 点数 | 特征 | 注 |
0 | D-FPS | [0.2,0.8] | 4096 | 64 | |
1 | D-FPS | [0.8,1.6] | 1024 | 128 | |
2 | Ctr-aware | [1.6,4.8] | 512 | 256 | |
3 | Ctr-aware | 无 | 256 | 256 | 无Grouping,只从512个点中选256个前景概率高的 |
4 | Vote | 无 | 256 | 非采样,通过256个点的特征投票得到物体中心点,即产生新的256个点 | |
5 | 无 | [4.8, 6.4] | 256 | 512 | 无采样,由vote产生的点grouping得到近邻点聚合特征 |
IASSD_Head:
center_cls_preds = self.cls_center_layers(center_features) # (total_centers, num_class)center_box_preds = self.box_center_layers(center_features) # (total_centers, box_code_size)
输出: center_cls_preds (256,3)
center_box_preds (256,30)
总结思考:
IA-SSD专注于前景点的采样,设计了一种显存占用很小,效果达到了SOTA的网络,但在每个点的语义预测时方法较简单,可能会受到类别不平衡分布的影响。
另外,在检测中只考虑了前景点,背景点在类别和回归框预测中难道没有影响吗, 能否将部分背景点也考虑在内呢?
本人小白一枚,有不对的地方望大佬指正。
代码解读:
本文代码是基于OpenPCDet实现的,所以如果你了解OpenPCDet,那么看懂IA-SSD的代码并不难。
贴上整体的网络结构方便理解:
IASSD((backbone_3d): IASSD_Backbone((SA_modules): ModuleList((0): PointnetSAModuleMSG_WithSampling( #第一层网络,可对照前面的表格(groupers): ModuleList((0): QueryAndGroup() #最远点采样(1): QueryAndGroup())(mlps): ModuleList( #grouping后的点送入mlp(0): Sequential((0): Conv2d(4, 16, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(16, 16, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(16, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU())(1): Sequential((0): Conv2d(4, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(32, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU()))(aggregation_layer): Sequential( #聚合两个半径grouping得到的特征(0): Conv1d(96, 64, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()))(1): PointnetSAModuleMSG_WithSampling((groupers): ModuleList((0): QueryAndGroup()(1): QueryAndGroup())(mlps): ModuleList((0): Sequential((0): Conv2d(67, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(64, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU())(1): Sequential((0): Conv2d(67, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(64, 96, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(96, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU()))(aggregation_layer): Sequential((0): Conv1d(256, 128, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU())(confidence_layers): Sequential( #预测每个点前景的概率(0): Conv1d(128, 128, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv1d(128, 3, kernel_size=(1,), stride=(1,))))(2): PointnetSAModuleMSG_WithSampling((groupers): ModuleList((0): QueryAndGroup()(1): QueryAndGroup())(mlps): ModuleList((0): Sequential((0): Conv2d(131, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(128, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU())(1): Sequential((0): Conv2d(131, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU()))(aggregation_layer): Sequential((0): Conv1d(512, 256, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU())(confidence_layers): Sequential((0): Conv1d(256, 256, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv1d(256, 3, kernel_size=(1,), stride=(1,))))(3): PointnetSAModuleMSG_WithSampling( #这层网络只选前景点概率大的256个点,(groupers): ModuleList() #不grouping(mlps): ModuleList())(4): Vote_layer( #预测质心(mlp_modules): Sequential((0): Conv1d(256, 128, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU())(ctr_reg): Conv1d(128, 3, kernel_size=(1,), stride=(1,)))(5): PointnetSAModuleMSG_WithSampling((groupers): ModuleList((0): QueryAndGroup()(1): QueryAndGroup())(mlps): ModuleList((0): Sequential((0): Conv2d(259, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(256, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU())(1): Sequential((0): Conv2d(259, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Conv2d(256, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(4): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Conv2d(512, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)(7): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(8): ReLU()))(aggregation_layer): Sequential((0): Conv1d(1536, 512, kernel_size=(1,), stride=(1,), bias=False)(1): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()))))(point_head): IASSD_Head((cls_loss_func): WeightedClassificationLoss() (reg_loss_func): WeightedSmoothL1Loss()(ins_loss_func): WeightedClassificationLoss()(cls_center_layers): Sequential((0): Linear(in_features=512, out_features=256, bias=False)(1): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Linear(in_features=256, out_features=256, bias=False)(4): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Linear(in_features=256, out_features=3, bias=True))(box_center_layers): Sequential((0): Linear(in_features=512, out_features=256, bias=False)(1): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(2): ReLU()(3): Linear(in_features=256, out_features=256, bias=False)(4): BatchNorm1d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(5): ReLU()(6): Linear(in_features=256, out_features=30, bias=True)))
)
更多推荐
【IA
发布评论