PV-RCNN代码解读——输入参数介绍

PV-RCNN:paper,code
PV-RCNN代码解读——输入参数介绍_第1张图片在上图中,本文所讲述的是左侧Data部分,也即传入foward函数之前的data处理部分,以方便如何使用该论文的方法应用于自己的数据。

思路:

(一)建立一个DemoDataset类,其中储存关于输入数据的所有信息,包含六个参数

  1. dataset_cfg=cfg.DATA_CONFIG # 数据参数
    包含数据集 / 数据路径 / 信息路径 / 数据处理器 / 数据增强器等
  2. class_names=cfg.CLASS_NAMES # 类别名
  3. training=False # 是否训练
  4. root_path=Path(args.data_path) # 根目录
  5. ext=args.ext # 扩展
  6. logger=logger # 日志

(二)bulid_network的数据处理,包含三个参数

  1. model_cfg=cfg.MODEL #模型的配置参数
  2. num_class=len(cfg.CLASS_NAMES)#类别的数量
  3. dataset=demo_dataset #输入之前处理为DemoDataset类的数据

(三)collect_batch中的数据处理

1. DemoDataset

在main函数中

    demo_dataset = DemoDataset(
        dataset_cfg=cfg.DATA_CONFIG, class_names=cfg.CLASS_NAMES, training=False,
        root_path=Path(args.data_path), ext=args.ext, logger=logger
    )

因此,我们需要创建以上文件

(1)DATA_CONFIG(重点)
第一个参数cfg.DATA_CONFIG在pv_rcnn.yaml文件中

    _BASE_CONFIG_: cfgs/dataset_configs/kitti_dataset.yaml #基本配置

根据其基本配置的路径找到kitti_dataset.yaml(最外层文件夹是tools)

DATASET: 'KittiDataset' #数据集
DATA_PATH: '../data/kitti' #数据路径

*POINT_CLOUD_RANGE: [0, -40, -3, 70.4, 40, 1] #点云范围

DATA_SPLIT: {
      #数据分割
    'train': train,
    'test': val
}

INFO_PATH: {
      #信息路径
    'train': [kitti_infos_train.pkl], #从kitti数据库中调用
    'test': [kitti_infos_val.pkl],
}

FOV_POINTS_ONLY: True #仅视点

POINT_FEATURE_ENCODING: {
      #点特征编码
    encoding_type: absolute_coordinates_encoding, #编码类型
    used_feature_list: ['x', 'y', 'z', 'intensity'], #使用的特征
    src_feature_list: ['x', 'y', 'z', 'intensity'], #src特征
}

DATA_PROCESSOR: #数据处理器
    - NAME: mask_points_and_boxes_outside_range #遮罩点和框超出范围
      REMOVE_OUTSIDE_BOXES: True #移除外框

    - NAME: shuffle_points #Shuffle点
      SHUFFLE_ENABLED: {
      #启用的Shuffle点
        'train': True,
        'test': False
      }

    - NAME: transform_points_to_voxels #将点转换为体素
*      VOXEL_SIZE: [0.05, 0.05, 0.1] #体素大小
      MAX_POINTS_PER_VOXEL: 5 # 每个体素的最高点数
      MAX_NUMBER_OF_VOXELS: {
      #体素数量上限
        'train': 16000,
        'test': 40000
      }

回到pv_rcnn.yaml,其中还补充了一些信息

DATA_CONFIG: #数据配置
    _BASE_CONFIG_: cfgs/dataset_configs/kitti_dataset.yaml #基本配置
    DATA_AUGMENTOR: #数据增强器
        DISABLE_AUG_LIST: ['placeholder'] #停用增强器
        AUG_CONFIG_LIST: #增强器
            - NAME: gt_sampling #gt采样
              USE_ROAD_PLANE: True # 使用道路平面
              DB_INFO_PATH: # 数据库信息路径 
*                  - kitti_dbinfos_train.pkl #从数据库中调用
              PREPARE: {
     
                 filter_by_min_points: ['Car:5', 'Pedestrian:5', 'Cyclist:5'],#按最低分数过滤
                 filter_by_difficulty: [-1],#按难度过滤
              }

              SAMPLE_GROUPS: ['Car:15','Pedestrian:10', 'Cyclist:10'] #样本组
              NUM_POINT_FEATURES: 4 #特征点数量
              DATABASE_WITH_FAKELIDAR: False  #不使用FAKELIDAR的数据库
              REMOVE_EXTRA_WIDTH: [0.0, 0.0, 0.0] #不删除多余的宽度
              LIMIT_WHOLE_SCENE: False #整个场景限制

            - NAME: random_world_flip #随机翻转
              ALONG_AXIS_LIST: ['x'] #沿轴

            - NAME: random_world_rotation #随机旋转
              WORLD_ROT_ANGLE: [-0.78539816, 0.78539816] #旋转角度

            - NAME: random_world_scaling #随机缩放
              WORLD_SCALE_RANGE: [0.95, 1.05] #范围

(2) CLASS_NAMES
第二个参数是cfg.CLASS_NAMES,即类别名称

CLASS_NAMES: ['Car', 'Pedestrian', 'Cyclist']

(3)training
一个Bool变量,表示是否训练

training = False

(4) root_path
根路径

args, cfg = parse_config()
root_path = Path(args.data_path)#指定点云数据文件或目录

其中parse_config的定义为

def parse_config(): #创建一个ArgumentParser对象,格式: 参数名,类型,默认值, 帮助信息
    parser = argparse.ArgumentParser(description='arg parser')
    parser.add_argument('--cfg_file', type=str, default='cfgs/kitti_models/second.yaml',
                        help='specify the config for demo') #指定演示的配置
    parser.add_argument('--data_path', type=str, default='demo_data',
                        help='specify the point cloud data file or directory')#指定点云数据文件或目录
    parser.add_argument('--ckpt', type=str, default=None, help='specify the pretrained model')#指定预训练模型
    # Check point 校验点 在系统运行中当出现查找数据请求时,系统从数据库中找出这些数据并存入内存区,这样用户就可以对这些内存区数据进行修改等
    parser.add_argument('--ext', type=str, default='.bin', help='specify the extension of your point cloud data file')
    # extension 指定点云数据文件的扩展名

    args = parser.parse_args()
    cfg_from_yaml_file(args.cfg_file, cfg)

    return args, cfg #arguments参数,configuration配制

即,args的参数包含:

  1. ‘–cfg_file’ #指定配置
  2. ‘–data_path’ #指定点云数据文件或目录
  3. ‘–ckpt’ #指定预训练模型
  4. ‘–ext’ #指定点云数据文件的扩展名

执行时需要手动输入以上参数,或会采用默认数值。
github上给出的执行范例:

python demo.py --cfg_file cfgs/kitti_models/pv_rcnn.yaml \
    --ckpt pv_rcnn_8369.pth \
    --data_path ${
     POINT_CLOUD_DATA}
    # Here ${POINT_CLOUD_DATA} could be the following format: 
    # The original KITTI .bin data within data/kitti, like data/kitti/training/velodyne/000008.bin

(5)ext

args, cfg = parse_config()
ext = args.ext #指定点云数据文件的扩展名

(6)logger

logger = common_utils.create_logger() #logger记录日志

2. build_network接受的数据

model = build_network(model_cfg=cfg.MODEL, num_class=len(cfg.CLASS_NAMES), dataset=demo_dataset)

(1)MODEL(重点)

model_cfg=cfg.MODEL

依然是在pvrcnn.yaml中

MODEL: 
    NAME: PVRCNN #名称
    VFE:#体素特征编码
        NAME: MeanVFE
    BACKBONE_3D:
        NAME: VoxelBackBone8x
    MAP_TO_BEV: #映射到BEV
        NAME: HeightCompression
        NUM_BEV_FEATURES: 256 #BEV功能个数

    BACKBONE_2D:
        NAME: BaseBEVBackbone
        LAYER_NUMS: [5, 5] #层数
        LAYER_STRIDES: [1, 2] #图层等级
        NUM_FILTERS: [128, 256] #过滤器数量
        UPSAMPLE_STRIDES: [1, 2] #上采样等级
        NUM_UPSAMPLE_FILTERS: [256, 256] #示例过滤器数量

    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': 8, #特征图跨度
                'matched_threshold': 0.6, #匹配阈值
                'unmatched_threshold': 0.45 #唯一的阈值
            },
            {
        'class_name': 'Pedestrian',
                #和car类相似
            },
            {
        'class_name': 'Cyclist',
                #和car类相似
            }
        ]

        TARGET_ASSIGNER_CONFIG:#目标分配器配置
            NAME: AxisAlignedTargetAssigner
            POS_FRACTION: -1.0 #位置分数
            SAMPLE_SIZE: 512 #样本大小
            NORM_BY_NUM_EXAMPLES: False #使用num个例子归一
            MATCH_HEIGHT: False #匹配高度
            BOX_CODER: ResidualCoder #边框编码器

        LOSS_CONFIG: #损失配置
            LOSS_WEIGHTS: {
      #损失权重
                'cls_weight': 1.0, #分类权重
                'loc_weight': 2.0, #位置权重
                'dir_weight': 0.2, #方向权重
                'code_weights': [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] #编码权重
            }

(2)类别数量

num_class=len(cfg.CLASS_NAMES)

(3)输入处理好的DemoDataset类的数据

dataset=demo_dataset

3.collect_batch的数据处理

demo_dataset类 中 collate_batch的定义:

   def collate_batch(batch_list, _unused=False):
        data_dict = defaultdict(list) #defaultdict 表示在当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值

将data_dict传入后命名为batch_list,创建一个字典data_dict

        for cur_sample in batch_list:
            for key, val in cur_sample.items():
                data_dict[key].append(val)
        batch_size = len(batch_list)
        ret = {
     }

cur_sample 表示现在的样本值(current sample),也是DemoDataset类
用data_dict记录cur_sample的内容,主要创建记录数据的list,如下

        for key, val in data_dict.items():
                if key in ['voxels', 'voxel_num_points']: #对应体素
                    ret[key] = np.concatenate(val, axis=0) #多个数组的拼接
                elif key in ['points', 'voxel_coords']: #对应关键点
                    coors = []
                    for i, coor in enumerate(val): 
                        coor_pad = np.pad(coor, ((0, 0), (1, 0)), mode='constant', constant_values=i)
                        """
                            ((0,0),(1,0))
                            在二维数组array第一维(此处便是行)前面填充0行,最后面填充0行;
                            在二维数组array第二维(此处便是列)前面填充1列,最后面填充0列
                            mode='constant'表示指定填充的参数
                            constant_values=i 表示第一维填充i
                        """
                        coors.append(coor_pad) #将coor_pad补充在coors后面
                    ret[key] = np.concatenate(coors, axis=0)
                elif key in ['gt_boxes']: #对应真值
                    max_gt = max([len(x) for x in val]) #找寻最大价值的点
                    batch_gt_boxes3d = np.zeros((batch_size, max_gt, val[0].shape[-1]), dtype=np.float32) #画可视图用的
                    for k in range(batch_size):
                        batch_gt_boxes3d[k, :val[k].__len__(), :] = val[k]
                    ret[key] = batch_gt_boxes3d
                else:
                    ret[key] = np.stack(val, axis=0) #类似concatenate,给指定axis增加维度
        ret['batch_size'] = batch_size
        return ret

你可能感兴趣的:(PV-RCNN,python,机器学习,深度学习,pytorch)