Openpcdet 系列 Pointpillar代码逐行解析之检测头(DENSE_HEAD)模块

Openpcdet 的DENSE_HEAD模块

在这里插入图片描述

整个OpenPCdet的Dense head模块包含下面这些模块。Pointpillar使用的AnchorHeadSingle
模块

__all__ = {
    'AnchorHeadTemplate': AnchorHeadTemplate,
    'AnchorHeadSingle': AnchorHeadSingle,
    'PointIntraPartOffsetHead': PointIntraPartOffsetHead,
    'PointHeadSimple': PointHeadSimple,
    'PointHeadBox': PointHeadBox,
    'AnchorHeadMulti': AnchorHeadMulti,
    'CenterHead': CenterHead,
    'VoxelNeXtHead': VoxelNeXtHead,
    'TransFusionHead': TransFusionHead,
}

Pointpillar Dense Head配置文件

NAME: AnchorHeadSingle: 这是头部网络的名称,可能指明了这个头部的类型或特征。

CLASS_AGNOSTIC: False: 这表示头部网络不是“类别不可知”的,也就是说,它在处理不同类别的目标时会考虑类别信息。

USE_DIRECTION_CLASSIFIER: True: 这指示网络是否使用方向分类器来预测目标的朝向。

DIR_OFFSET, DIR_LIMIT_OFFSET, NUM_DIR_BINS:
这些参数涉及到方向分类器的设置,比如方向偏移、方向限制偏移和方向的分箱数量等。

ANCHOR_GENERATOR_CONFIG: 这是一个列表,包含了针对不同类别的锚点生成器的配置信息。每个类别都有自己的配置信息,包括:

class_name: 目标类别的名称,比如 ‘Car’(车辆)、‘Pedestrian’(行人)、‘Cyclist’(骑行者)。
anchor_sizes: 锚点的尺寸,以列表形式给出,每个列表表示一个锚点的长、宽、高。 anchor_rotations:
锚点的旋转角度,通常用于处理物体可能的不同朝向。 anchor_bottom_heights: 锚点底部的高度,这是与地面的距离。
align_center: 是否对齐物体中心。 feature_map_stride: 特征图步长,与生成锚点的网络结构相关。
matched_threshold, unmatched_threshold: 匹配和不匹配的阈值,用于锚点和实际目标之间的匹配。

DENSE_HEAD:
        NAME: AnchorHeadSingle
        CLASS_AGNOSTIC: False

        USE_DIRECTION_CLASSIFIER: True
        DIR_OFFSET: 0.78539
        DIR_LIMIT_OFFSET: 0.0
        NUM_DIR_BINS: 2

        ANCHOR_GENERATOR_CONFIG: [
            {
                'class_name': 'Car',
                'anchor_sizes': [[3.9, 1.6, 1.56]],
                'anchor_rotations': [0, 1.57],
                'anchor_bottom_heights': [-1.78],
                'align_center': False,
                'feature_map_stride': 2,
                'matched_threshold': 0.6,
                'unmatched_threshold': 0.45
            },
            {
                'class_name': 'Pedestrian',
                'anchor_sizes': [[0.8, 0.6, 1.73]],
                'anchor_rotations': [0, 1.57],
                'anchor_bottom_heights': [-0.6],
                'align_center': False,
                'feature_map_stride': 2,
                'matched_threshold': 0.5,
                'unmatched_threshold': 0.35
            },
            {
                'class_name': 'Cyclist',
                'anchor_sizes': [[1.76, 0.6, 1.73]],
                'anchor_rotations': [0, 1.57],
                'anchor_bottom_heights': [-0.6],
                'align_center': False,
                'feature_map_stride': 2,
                'matched_threshold': 0.5,
                'unmatched_threshold': 0.35
            }
        ]

Dense head功能讲解

DENSE_HEAD 是指密集点云检测模型中的头部网络结构。密集点云检测旨在处理点云中更密集的数据,通常涉及更高密度的点云数据,需要更复杂的网络结构来有效地处理这些信息。

DENSE_HEAD 通常包含用于预测物体边界框、分类和其他属性的层。这些头部网络通常由密集的卷积和特征融合层组成,以从密集的点云数据中提取丰富的特征,并用于目标检测和分类任务。这种头部网络结构设计旨在更好地处理点云中的丰富信息,以提高物体检测和定位的准确性和鲁棒性。

Dense Head 之 AnchorHeadSingle代码讲解

class AnchorHeadSingle(AnchorHeadTemplate):

这一行定义了一个名为 AnchorHeadSingle 的类,并且这个类继承自 AnchorHeadTemplate 类。

def __init__(self, model_cfg, input_channels, num_class, class_names, grid_size, point_cloud_range,
             predict_boxes_when_training=True, **kwargs):

这是类的初始化函数,它接受多个参数来配置和构建头部网络。

super().__init__(
    model_cfg=model_cfg, num_class=num_class, class_names=class_names, grid_size=grid_size, point_cloud_range=point_cloud_range,
    predict_boxes_when_training=predict_boxes_when_training
)

使用 super() 调用父类的初始化方法,并传递一系列参数来配置头部网络。

self.num_anchors_per_location = sum(self.num_anchors_per_location)

这一行计算了每个位置的锚点数量之和,并将结果保存在 self.num_anchors_per_location 中。

self.conv_cls = nn.Conv2d(
    input_channels, self.num_anchors_per_location * self.num_class,
    kernel_size=1
)

创建了一个卷积层 self.conv_cls,用于预测每个锚点位置的类别概率。

self.conv_box = nn.Conv2d(
    input_channels, self.num_anchors_per_location * self.box_coder.code_size,
    kernel_size=1
)

创建了另一个卷积层 self.conv_box,用于预测每个锚点位置的边界框坐标。

if self.model_cfg.get('USE_DIRECTION_CLASSIFIER', None) is not None:
    self.conv_dir_cls = nn.Conv2d(
        input_channels,
        self.num_anchors_per_location * self.model_cfg.NUM_DIR_BINS,
        kernel_size=1
    )
else:
    self.conv_dir_cls = None

根据配置选择是否创建方向分类器的卷积层。

self.init_weights()

调用 init_weights() 方法来初始化网络层的权重。

这段代码主要是初始化了网络结构,并创建了用于预测类别、边界框以及方向(如果启用)的卷积层。它提供了头部网络所需的基本设定和功能。

def init_weights(self):
    pi = 0.01
    nn.init.constant_(self.conv_cls.bias, -np.log((1 - pi) / pi))
    nn.init.normal_(self.conv_box.weight, mean=0, std=0.001)

这是 init_weights() 方法,用于初始化网络层的权重。它使用了 PyTorch 的初始化方法来设置权重。

  • self.conv_cls.bias 的初始化使用了常数初始化方法,根据逻辑来设置偏置的初始值。

  • self.conv_box.weight 使用了正态分布初始化方法,给权重设置了均值和标准差。

def forward(self, data_dict):
    spatial_features_2d = data_dict['spatial_features_2d']

    cls_preds = self.conv_cls(spatial_features_2d)
    box_preds = self.conv_box(spatial_features_2d)

    cls_preds = cls_preds.permute(0, 2, 3, 1).contiguous()  # [N, H, W, C]
    box_preds = box_preds.permute(0, 2, 3, 1).contiguous()  # [N, H, W, C]

    self.forward_ret_dict['cls_preds'] = cls_preds
    self.forward_ret_dict['box_preds'] = box_preds

这是 forward() 方法,用于执行前向传播。它接收一个 data_dict 字典,其中包含了特征数据。

  • 从输入数据中提取了空间特征 spatial_features_2d

  • 将特征通过 self.conv_clsself.conv_box 卷积层进行处理,生成类别预测 cls_preds 和边界框预测 box_preds

  • 调整预测结果的形状,以适应后续处理的需要,并将结果保存在 self.forward_ret_dict 字典中。

if self.conv_dir_cls is not None:
    dir_cls_preds = self.conv_dir_cls(spatial_features_2d)
    dir_cls_preds = dir_cls_preds.permute(0, 2, 3, 1).contiguous()
    self.forward_ret_dict['dir_cls_preds'] = dir_cls_preds
else:
    dir_cls_preds = None

如果启用了方向分类器,将空间特征通过 self.conv_dir_cls 卷积层处理,生成方向预测 dir_cls_preds

if self.training:
    targets_dict = self.assign_targets(
        gt_boxes=data_dict['gt_boxes']
    )
    self.forward_ret_dict.update(targets_dict)

如果处于训练状态,调用 self.assign_targets 方法为每个锚点位置分配目标,并将结果更新到 self.forward_ret_dict 中。

以上是前向传播的一部分,处理了预测和目标分配(在训练时)的逻辑。接下来的代码段将处理预测框的生成和输出。

if not self.training or self.predict_boxes_when_training:
    batch_cls_preds, batch_box_preds = self.generate_predicted_boxes(
        batch_size=data_dict['batch_size'],
        cls_preds=cls_preds, box_preds=box_preds, dir_cls_preds=dir_cls_preds
    )
    data_dict['batch_cls_preds'] = batch_cls_preds
    data_dict['batch_box_preds'] = batch_box_preds
    data_dict['cls_preds_normalized'] = False

这段代码逻辑用于生成预测的框,它将根据网络的预测情况进行不同的处理:

  • 如果不处于训练状态,或者在训练时需要预测框 (predict_boxes_when_training=True),则执行以下操作:
    • 调用 self.generate_predicted_boxes 方法生成预测的类别和边界框。
    • 将生成的类别预测 batch_cls_preds 和边界框预测 batch_box_preds 存储到 data_dict 中。
    • 设置 cls_preds_normalized 标志为 False,表示类别预测未经归一化。
return data_dict

最后,将更新后的 data_dict 返回作为前向传播的结果。

这段代码的作用是在非训练状态下或者在训练时需要预测框时,生成预测结果,并将这些结果添加到 data_dict 中,然后将其作为输出返回。这些结果可能用于后续的评估或其他处理。

引用

Openpcdet 系列 Pointpillar代码逐行解析
OpenPCDet 环境安装
OpenPCDet KITTI数据加载过程 (Pointpillar模型)
Openpcdet 系列 Pointpillar代码逐行解析之Voxel Feature Encoding (VFE)模块
Openpcdet 系列 Pointpillar代码逐行解析之MAP_TO_BEV模块

Openpcdet 系列 Pointpillar代码逐行解析之BACKBONE_2D模块

Openpcdet 系列 Pointpillar代码逐行解析之检测头(DENSE_HEAD)模块

Openpcdet 系列 Pointpillar代码逐行解析之POST_PROCESSING模块

  • 23
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack_Man_N

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值