【三维目标检测】SASSD(二)

        SASSD数据和源码配置调试过程请参考上一篇博文:【目标检测>三维目标检测SASSD(一)_Coding的叶子的博客-CSDN博客。本文主要详细介绍SASSD网络结构及其运行中间状态。

1 SASSD模型总体过程

        SASSD模型的整体结构如下图所示。SASSD与基于Anchor的目标检测模型的结构基本保持一致,其核心特点在于采用了一个类似语义分割的辅助网络(Auxiliary Network)来学习区分前景点和背景点,从而辅助候选框特征提取,使产生的候选框质量更高。辅助网络这一点与PointRCNN和VoteNet的部分思想很接近。不同之处在于,SASSD提取体素中心点特征时融合了不同尺度下近邻体素的特征,从而使得网络可以有效获取到局部结构特征(Structure Aware)。另一方面,这个辅助网络仅在训练时用到,在推理时则完全拆解下来,从而使得模型在实际部署过程种不增加额外开销。因此,SASSD辅助网络的作用在于提高模型训练精度。

2 主要模块解析

2.1 体素化

        源码中用于实现体素化的入口函数为self.voxelize(points),具体实现函数为Voxelization(voxel_size=[0.05, 0.05, 0.1], point_cloud_range=[0, -40, -3, 70.4, 40, 1], max_num_points=5, max_voxels=16000, deterministic=True)。函数输入分别为:

        (1)points,Nx4,原始点云,N表示点云数量,4表示特征维度,特征为坐标x、y、z与反射强度r。

        (2)voxel_size:单位体素的尺寸,x、y、z方向上的尺度分别为0.05m、0.05m、0.1m。

        (3)point_cloud_range:x、y、z方向的距离范围,结合(2)中体素尺寸可以得到总的体素数量为1408x1600x41,即92364800(41x1600x1408)。

        (4)max_num_points:定义每个体素中取值点的最大数量,默认为5,在voxelnet中T=35。

        (5)max_voxels:表示含有点云的体素最大数量,默认为16000。当数量超过16000时,仅保留16000,当数量不足16000时,则保留全部体素。

        (6)deterministic:取值为True时,表示每次体素化的结果是确定的,而不是随机的。

        体素化输出结果如下:

        (1)voxels:Mx5x4,体素中各个点的原始坐标和反射强度,M(M≤16000)个体素,每个体素最多5个点。

        (2)num_points:Mx1,每个体素中点的数量,最小数量为1,最大数量为5。

        coors:体素自身坐标,坐标值为整数,表示体素的按照单位尺度得到的坐标,Mx4,[batch_id, x, y, z]

2.2 体素特征提取VFE(voxel_encoder)

        在voxelnet中,体素特征通过SVFE层提取,即连续两层VFE,其中VFE层提取体素特征用的是PointNet网络。而在该源码中,VFE层被进行了简化HardSimpleVFE(voxel_encoder),即对每个体素中的点求平均值,用平均值作为体素特征,取平均时点的数量由num_points决定。Mx5x4的voxels经过VFE后的维度为Mx4(voxel_features),即在第二个维度点的数量上进行了平均。体素特征提取相当于用新的4个维度特征来表示体素内一组点的共同特征。体素特征提取的入口函数为self.voxel_encoder(voxel_dict['voxels'], voxel_dict['num_points'], voxel_dict['coors'])

2.3 稀疏卷积特征提取 middle_encoder

        类比VoxelNet中的CML(Convolutional Middle Layer)层,voxelnet中直接用三维卷积进行特征提取,而CenterPoint则采用了连续三维稀疏卷积进行特征提取,函数入口为self.pts_middle_encoder(voxel_features, coors, batch_size)。三维稀疏卷积只是普通三维卷积的一种快速计算方法。CenterPoint提取的空间特征spatial_features维度为256x180x180,具体稀疏卷积提取过程如下。

SparseEncoderSASSD
voxel_features(30920x4)->稀疏表示,Mx4,41x1600x1408, x
-> 3维稀疏卷积SPConv(4, 16, 1),Mx16,41x1600x1408, x
-> 3维稀疏卷积SPConv(16, 16, 1),Mx16,41x1600x1408, x1
-> 3维稀疏卷积SPConv(16, 32, 2)、SPConv(32, 32, 1)、SPConv(32, 32, 1),M2x32,21x800x704, x2
-> 3维稀疏卷积SPConv(32, 64, 2)、SPConv(64, 64, 1, 1)、SPConv(64, 64, 1),M3x64,11x400x352, x3
-> 3维稀疏卷积SPConv(64, 64, 2)、SPConv(64, 64, 1)、SPConv(64, 64, 1),M4x64,5x200x176, x4
-> 3维稀疏卷积SPConv(64, 128, [2, 1, 1]) M5x128,2x200x176,即128x2x200x176
 -> Resshape,256x200x176,spatial_features

2.4 辅助网络  auxiliary network

        2.3节中间特征层除提取到空间特征spatial_features之外,还提取到了不同尺度的体素特征x1、x2、x3、x4。体素特征提取时每个体素的特征坐标用内部点的平均坐标来表示,这样可以用一个点来近似表示相应体素。辅助网络将距离平均坐标点最近的K个体素坐标的特征加权求和作为取特征,类似于PointNet++中的上采样操作。这相当于为每个体素平均中心点赋予了新的不同尺度特征。

        加权后特征经过全连接分类和回归得到point_cls(Mx1)和point_reg (Mx3)。

        主要程序过程如下。

points_mean = torch.zeros_like(voxel_features)
points_mean[:, 0] = coors[:, 0] #batch_id
points_mean[:, 1:] = voxel_features[:, :3]#voxel内点坐标平均值
#x1
M x 16
p0 = self.make_auxiliary_points(encode_features[0], points_mean, offset=(0, -40., -3.), voxel_size=(.1, .1, .2))
Mx32
p1 = self.make_auxiliary_points(encode_features[1], points_mean, offset=(0, -40., -3.), voxel_size=(.2, .2, .4))
Mx64
p2 = self.make_auxiliary_points(encode_features[2],points_mean,offset=(0, -40., -3.),voxel_size=(.4, .4, .8))
pointwise = torch.cat([p0, p1, p2], dim=-1) Mx112
Linear(112, 64) Mx64
pointwise = self.point_fc(pointwise)
Linear(64, 1) Mx1
point_cls = self.point_cls(pointwise)
Linear(64, 3) Mx3
point_reg = self.point_reg(pointwise)
point_misc = (points_mean, point_cls, point_reg)

2.5 辅助损失

        SSD的辅助网络损失计算函数入口为self.middle_encoder.aux_loss(*point_misc, gt_bboxes_3d)。输入只有gt_boxes_3d而没有label说明只会做前景和背景的区分。真实标签主要通过根据点是否在目标内进行判别。中心回归偏移center_offset 是体素中心相对于所在目标中心的偏移。辅助损失中类别损失函数为FocalLoss,回归损失函数为SmoothL1Loss。

pts_in_flag, center_offset = self.calculate_pts_offsets(new_xyz, boxes3d)
#点是否在目标内。共K个真实目标,独热码的形式进行表述
KxM Mx3
pts_in_flag = points_in_boxes_all(points[None, ...], boxes[None, ...])
pts_label Mx1标签
FocalLoss
aux_loss_cls = sigmoid_focal_loss(point_cls, rpn_cls_target, weight=cls_weights, avg_factor=pos_normalizer)
前景点和背景点判别
aux_loss_reg = smooth_l1_loss(point_reg, center_targets, beta=1 / 9.)
SmoothL1loss

2.6 主干网络backbone特征提取

        SASSD的主干网络采用的是SECOND结构,通过两条同类提取两种不同尺度的特征图。第一条通路是2.3中的空间特征spatial_features 256x200x176经连续6个3x3卷积得到128x200x176维度的特征,记为out1。第二条通路是out1继续经过连续6个3x3卷积(其中第一个步长为2)得到256x100x88维度的特征,记为out2。out1和out2为主干网络输出结果。主干网络关键入口函数为self.backbone(feats_dict['spatial_features']) 。

输入:x = self.backbone(feats_dict['spatial_features'])
out1:256x200x176 -> 128x200x176
Sequential(
  (0): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (1): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (2): ReLU(inplace=True)
  (3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (4): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (5): ReLU(inplace=True)
  (6): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (7): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (8): ReLU(inplace=True)
  (9): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (10): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (11): ReLU(inplace=True)
  (12): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (13): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (14): ReLU(inplace=True)
  (15): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (16): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (17): ReLU(inplace=True)
)
Out2:128x200x176 -> 256x100x88
Sequential(
  (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
  (1): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (2): ReLU(inplace=True)
  (3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (4): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (5): ReLU(inplace=True)
  (6): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (7): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (8): ReLU(inplace=True)
  (9): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (10): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (11): ReLU(inplace=True)
  (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (13): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (14): ReLU(inplace=True)
  (15): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (16): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
  (17): ReLU(inplace=True
)
Out = [out1, out2] [128x200x176, 256x100x88]

2.7 上采样拼接 self.neck

        Neck网络分别对out1、out2进行上采样,out1的维度从128x200x176转换为256x200x176,out2的维度也从256x2100x88转换为256x200x176,两者维度完全相同。out1和out2拼接后得到Neck网络的输出结果,即neck_feats,维度为512x200x176。

​        分别对out1、out2进行上采样:

        out1:128x200x176 -> 256x200x176

        out2:256x100x88 -> 256x200x176

        拼接out:256x200x176、256x200x176 -> 512x200x176 (neck_feats)

2.8 检测头 self.bbox_head

        200x176维度特征图上每个位置对应三种尺寸、两种方向共6种候选框anchor。

        分类head:512x200x176特征经过conv_cls(512, 18)得到18x200x176个预测结果,对应6个候选框和3种目标类别。

        位置head:512x200x176特征经过conv_reg(512,42)得到42x200x176个预测结果,对应6个候选框和7个位置参数(x, y ,z, l, w, h, θ)。

        方向head:512x200x176特征经过conv_reg(512,12)得到12x200x176个预测结果,对应6个候选框和两个方向参数。

Anchor3DHead(
  (loss_cls): FocalLoss()
  (loss_bbox): SmoothL1Loss()
  (loss_dir): CrossEntropyLoss(avg_non_ignore=False)
  (conv_cls): Conv2d(512, 18, kernel_size=(1, 1), stride=(1, 1))
  (conv_reg): Conv2d(512, 42, kernel_size=(1, 1), stride=(1, 1))
  (conv_dir_cls): Conv2d(512, 12, kernel_size=(1, 1), stride=(1, 1))

loss_inputs = outs + (gt_bboxes_3d, gt_labels_3d, img_metas)

losses = self.bbox_head.loss(*loss_inputs, gt_bboxes_ignore=gt_bboxes_ignore)

2.9 RPN损失函数

        RPN损失函数详细介绍请参考【目标检测>三维目标检测】VoxelNet(三):模型详解_Coding的叶子的博客-CSDN博客_voxelnet,主要包括分类损失FocalLoss、三维目标框回归损失SmoothL1Loss和方向损失CrossEntropyLoss。

2.10 总体损失函数

        总体损失函数包括辅助损失和rpn损失,如下所示。

aux_loss_cls:FocalLoss
aux_loss_reg:SmoothL1Loss
loss_cls:FocalLoss
loss_bbox:SmoothL1Loss
loss_dir: CrossEntropyLoss

2.11 顶层结构

        顶层结构主要包含以下三部分:

        (1)特征提取:self.extract_feat,得到 512x200x176特征,见2.7节。

        (2)检测头:见2.8节。

        (3)损失函数:见2.10节。

 def forward_train(self, points, img_metas, gt_bboxes_3d, gt_labels_3d, gt_bboxes_ignore=None):
    x, point_misc = self.extract_feat(points, img_metas, test_mode=False)
    aux_loss = self.middle_encoder.aux_loss(*point_misc, gt_bboxes_3d)
    outs = self.bbox_head(x)
    loss_inputs = outs + (gt_bboxes_3d, gt_labels_3d, img_metas)
    losses = self.bbox_head.loss(*loss_inputs, gt_bboxes_ignore=gt_bboxes_ignore)
    losses.update(aux_loss)
    return losses

3 训练命令

python tools/train.py configs/sassd/sassd_6x8_80e_kitti-3d-3class.py

4 运行结果

【python三维深度学习】python三维点云从基础到深度学习_Coding的叶子的博客-CSDN博客_python点云拼接三维点云基础知识到深度学习,将按照以下目录持续进行更新。更新完成的部分可以在三维点云专栏中查看。含数据与python源码。https://blog.csdn.net/suiyingy/article/details/124017716


http://www.niftyadmin.cn/n/1257488.html

相关文章

【三维目标检测】SSN(一)

SSN是用于点云三维目标检测的模型算法,发表在ECCV 2020 《SSN: Shape Signature Networks for Multi-class Object Detection from Point Clouds》,论文地址为“https://arxiv.org/abs/2004.02774”。SSN核心在于提出了shape-aware heads grouping和shap…

ChatGPT介绍世界杯历史与编写足球游戏python程序

ChatGPT聊天机器人最近非常流行,是由OpenAI于本月发布的。花了一点时间注册了一个账号,如有需要帮助注册的可以随时与我交流。注册过程相对有一些复杂。 除了常规的聊天对话功能之外,ChatGPT聊天机器具备强大的文本生成能力,例如博…

mmdetection3d S3DIS (持续更新)

Mmdetection3d集成了大量3D深度学习算法,其中很大一部分可以在室内三维数据集S3DIS上运行。本节重点介绍S3DIS数据集及其在mmdetection3d中的预处理程序。 1 S3DIS S3DIS(Stanford Large-Scale 3D Indoor Spaces Dataset )数据集是斯坦福大学…

【三维目标检测】FCAF3D(一)

FCAF3D是一种anchor-free的全卷积室内三维目标检测算法,由三星公司发表在ECCV 2022 《FCAF3D: Fully Convolutional Anchor-Free 3D Object Detection》,论文地址为“https://arxiv.org/abs/2112.00322”。现有的 3D 物体检测方法使得对物体几何形状的先…

transformer 4 RuntimeError: Expected tensor for argument #1 ‘indices‘ to have scalar type Long

在使用transformer 4.0时,报错误提示RuntimeError: Expected tensor for argument #1 indices to have scalar type Long; but got torch.IntTensor instead (while checking arguments for embedding)。该问题主要时由于tensor的类型导致的,解决方法是在…

【python三维深度学习】python三维点云从基础到深度学习

从三维基础知识到深度学习,将按照以下目录持续进行更新。更新完成的部分可以在三维点云专栏中查看。https://blog.csdn.net/suiyingy/category_11740467.htmlhttps://blog.csdn.net/suiyingy/category_11740467.html 1、点云格式介绍(已完成&#xff09…

jquery 点击弹出层自身以外的任意位置,关闭弹出层

<!--弹出层---> <div class"mask"> <div class"wrap"></div> </div> /***弹出层效果***/ $(".header").find(".a5").click(function(e){ e.stopPropagation();//阻止冒泡 $(.mask).css("displa…

SSL/TLS 服务器瞬时 Diffie-Hellman 公共密钥过弱

服务器漏洞&#xff1a;SSL/TLS 服务器瞬时 Diffie-Hellman 公共密钥过弱【原理扫描】 解决方案 一. http服务器相关配置 1.首先生成大于1024bit(例如2048bit)的dhkeyopenssl dhparam -out dhparams.pem 2048 2.然后在对应服务器中配置Apache2.4.8及以后版本 使用如下配置命令…