赞
踩
整个OpenPCdet的Dense head模块包含下面这些模块。Pointpillar使用的AnchorHeadSingle
模块
__all__ = {
'AnchorHeadTemplate': AnchorHeadTemplate,
'AnchorHeadSingle': AnchorHeadSingle,
'PointIntraPartOffsetHead': PointIntraPartOffsetHead,
'PointHeadSimple': PointHeadSimple,
'PointHeadBox': PointHeadBox,
'AnchorHeadMulti': AnchorHeadMulti,
'CenterHead': CenterHead,
'VoxelNeXtHead': VoxelNeXtHead,
'TransFusionHead': TransFusionHead,
}
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 通常包含用于预测物体边界框、分类和其他属性的层。这些头部网络通常由密集的卷积和特征融合层组成,以从密集的点云数据中提取丰富的特征,并用于目标检测和分类任务。这种头部网络结构设计旨在更好地处理点云中的丰富信息,以提高物体检测和定位的准确性和鲁棒性。
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_cls
和 self.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模块
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。