mmdetection3d的配置文件放置在config/base下面,下面有4种类型组件:数据集(dataset),模型(model),训练策略 (schedule) 和运行时的默认设置 (default runtime)。由 base 下的组件组成的配置,被我们称为 原始配置 (primitive)。
我们以kitti为例,对于数据集的一些基本信息存储在_base_/datasets下面。 这里主要定义了数据集的位置/名称/类别/点云范围,把他们打包好,送进pipeline中 pipeline分别是train和eval对于数据的一些预处理。随后定义data 这里主要是把kitti数据集的信息及训练参数打包好。包括samples per gpu、和储存data的路径及配置文件的路径。 以pillar为例。它的一些模型文件存储在model中,里面很详细地记录了pillar网络的一些定义参数。例如voxel的大小 点云的范围、anchor的生成等等。我们如果要对于网络进行修改 可以直接继承这个网络的config文件 然后对于一些参数进行修改即可。 如果你在构建一个与任何现有方法不共享结构的全新方法,可以在 configs 文件夹下创建一个新的例如 xxx_rcnn 文件夹。 schedule则是一些常见的训练策略,例如kitti数据集常用cyclic_40e.py文件,主要是定义了训练中用到的学习率等参数。 config文件夹中包含各个detector的配置文件,例如,如果在 PointPillars 的基础上做了一些修改,用户首先可以通过指定 base = …/pointpillars/hv_pointpillars_fpn_sbn-all_4x8_2x_nus-3d.py 来继承基础的 PointPillars 结构,然后修改配置文件中的必要参数以完成继承。 配置文件命名也有一些规律:
{model}[model setting]{backbone}{neck}[norm setting][misc][gpu x batch_per_gpu]{schedule}{dataset} {xxx} 是被要求填写的字段而 [yyy] 是可选的。
{model}:模型种类,例如 hv_pointpillars (Hard Voxelization PointPillars)、VoteNet 等。
[model setting]:某些模型的特殊设定。
{backbone}: 主干网络种类例如 regnet-400mf、regnet-1.6gf 等。
{neck}:模型颈部的种类包括 fpn、secfpn 等。
[norm_setting]:如无特殊声明,默认使用 bn (Batch Normalization),其他类型可以有 gn (Group Normalization)、sbn (Synchronized Batch Normalization) 等。 gn-head/gn-neck 表示 GN 仅应用于网络的头部或颈部,而 gn-all 表示 GN 用于整个模型,例如主干网络、颈部和头部。
[misc]:模型中各式各样的设置/插件,例如 strong-aug 意味着在训练过程中使用更强的数据增广策略。
[batch_per_gpu x gpu]:每个 GPU 的样本数和 GPU 数量,默认使用 4x8。
{schedule}:训练方案,选项是 1x、2x、20e 等。 1x 和 2x 分别代表训练 12 和 24 轮。 20e 在级联模型中使用,表示训练 20 轮。 对于 1x/2x,初始学习率在第 8/16 和第 11/22 轮衰减 10 倍;对于 20e,初始学习率在第 16 和第 19 轮衰减 10 倍。
{dataset}:数据集,例如 nus-3d、kitti-3d、lyft-3d、scannet-3d、sunrgbd-3d 等。 当某一数据集存在多种设定时,我们也标记下所使用的类别数量,例如 kitti-3d-3class 和 kitti-3d-car 分别意味着在 KITTI 的所有三类上和单独车这一类上进行训练。
官方文档给出了votenet的配置文件注释:
model = dict(
type='VoteNet',
backbone=dict(
type='PointNet2SASSG',
in_channels=4,
num_points=(2048, 1024, 512, 256),
radius=(0.2, 0.4, 0.8, 1.2),
num_samples=(64, 32, 16, 16),
sa_channels=((64, 64, 128), (128, 128, 256), (128, 128, 256),
(128, 128, 256)),
fp_channels=((256, 256), (256, 256)),
norm_cfg=dict(type='BN2d'),
sa_cfg=dict(
type='PointSAModule',
pool_mod='max',
use_xyz=True,
normalize_xyz=True)),
bbox_head=dict(
type='VoteHead',
num_classes=18,
bbox_coder=dict(
type='PartialBinBasedBBoxCoder',
num_sizes=18,
num_dir_bins=1,
with_rot=False,
mean_sizes=[[0.76966727, 0.8116021, 0.92573744],
[1.876858, 1.8425595, 1.1931566],
[0.61328, 0.6148609, 0.7182701],
[1.3955007, 1.5121545, 0.83443564],
[0.97949594, 1.0675149, 0.6329687],
[0.531663, 0.5955577, 1.7500148],
[0.9624706, 0.72462326, 1.1481868],
[0.83221924, 1.0490936, 1.6875663],
[0.21132214, 0.4206159, 0.5372846],
[1.4440073, 1.8970833, 0.26985747],
[1.0294262, 1.4040797, 0.87554324],
[1.3766412, 0.65521795, 1.6813129],
[0.6650819, 0.71111923, 1.298853],
[0.41999173, 0.37906948, 1.7513971],
[0.59359556, 0.5912492, 0.73919016],
[0.50867593, 0.50656086, 0.30136237],
[1.1511526, 1.0546296, 0.49706793],
[0.47535285, 0.49249494, 0.5802117]]),
vote_moudule_cfg=dict(
in_channels=256,
vote_per_seed=1,
gt_per_seed=3,
conv_channels=(256, 256),
conv_cfg=dict(type='Conv1d'),
norm_cfg=dict(type='BN1d'),
norm_feats=True,
vote_loss=dict(
type='ChamferDistance',
mode='l1',
reduction='none',
loss_dst_weight=10.0)),
vote_aggregation_cfg=dict(
type='PointSAModule',
num_point=256,
radius=0.3,
num_sample=16,
mlp_channels=[256, 128, 128, 128],
use_xyz=True,
normalize_xyz=True),
feat_channels=(128, 128),
conv_cfg=dict(type='Conv1d'),
norm_cfg=dict(type='BN1d'),
objectness_loss=dict(
type='CrossEntropyLoss',
class_weight=[0.2, 0.8],
reduction='sum',
loss_weight=5.0),
center_loss=dict(
type='ChamferDistance',
mode='l2',
reduction='sum',
loss_src_weight=10.0,
loss_dst_weight=10.0),
dir_class_loss=dict(
type='CrossEntropyLoss',
reduction='sum',
loss_weight=1.0),
dir_res_loss=dict(
type='SmoothL1Loss',
reduction='sum',
loss_weight=10.0),
size_class_loss=dict(
type='CrossEntropyLoss',
reduction='sum',
loss_weight=1.0),
size_res_loss=dict(
type='SmoothL1Loss',
reduction='sum',
loss_weight=3.3333333333333335),
semantic_loss=dict(
type='CrossEntropyLoss',
reduction='sum',
loss_weight=1.0)),
train_cfg = dict(
pos_distance_thr=0.3,
neg_distance_thr=0.6,
sample_mod='vote'),
test_cfg = dict(
sample_mod='seed',
nms_thr=0.25,
score_thr=0.8,
per_class_proposal=False))
dataset_type = 'ScanNetDataset'
data_root = './data/scannet/'
class_names = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door', 'window',
'bookshelf', 'picture', 'counter', 'desk', 'curtain',
'refrigerator', 'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin')
train_pipeline = [
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=True,
with_label_3d=True,
with_mask_3d=True,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33, 34,
36, 39),
max_cat_id=40),
dict(type='PointSample',
num_points=40000),
dict(type='IndoorFlipData',
flip_ratio_yz=0.5,
flip_ratio_xz=0.5),
dict(
type='IndoorGlobalRotScale',
shift_height=True,
rot_range=[-0.027777777777777776, 0.027777777777777776],
scale_range=None),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')),
dict(
type='Collect3D',
keys=[
'points', 'gt_bboxes_3d', 'gt_labels_3d', 'pts_semantic_mask',
'pts_instance_mask'
])
]
test_pipeline = [
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='PointSample',
num_points=40000),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')),
dict(type='Collect3D',
keys=['points'])
]
eval_pipeline = [
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')),
with_label=False),
dict(type='Collect3D',
keys=['points'])
]
data = dict(
samples_per_gpu=8,
workers_per_gpu=4,
train=dict(
type='RepeatDataset',
times=5,
dataset=dict(
type='ScanNetDataset',
data_root='./data/scannet/',
ann_file='./data/scannet/scannet_infos_train.pkl',
pipeline=[
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=True,
with_label_3d=True,
with_mask_3d=True,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24,
28, 33, 34, 36, 39),
max_cat_id=40),
dict(type='PointSample', num_points=40000),
dict(
type='IndoorFlipData',
flip_ratio_yz=0.5,
flip_ratio_xz=0.5),
dict(
type='IndoorGlobalRotScale',
shift_height=True,
rot_range=[-0.027777777777777776, 0.027777777777777776],
scale_range=None),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table',
'door', 'window', 'bookshelf', 'picture',
'counter', 'desk', 'curtain', 'refrigerator',
'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin')),
dict(
type='Collect3D',
keys=[
'points', 'gt_bboxes_3d', 'gt_labels_3d',
'pts_semantic_mask', 'pts_instance_mask'
])
],
filter_empty_gt=False,
classes=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin'))),
val=dict(
type='ScanNetDataset',
data_root='./data/scannet/',
ann_file='./data/scannet/scannet_infos_val.pkl',
pipeline=[
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='PointSample', num_points=40000),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table',
'door', 'window', 'bookshelf', 'picture',
'counter', 'desk', 'curtain', 'refrigerator',
'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin')),
dict(type='Collect3D', keys=['points'])
],
classes=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door', 'window',
'bookshelf', 'picture', 'counter', 'desk', 'curtain',
'refrigerator', 'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin'),
test_mode=True),
test=dict(
type='ScanNetDataset',
data_root='./data/scannet/',
ann_file='./data/scannet/scannet_infos_val.pkl',
pipeline=[
dict(
type='LoadPointsFromFile',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='PointSample', num_points=40000),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table',
'door', 'window', 'bookshelf', 'picture',
'counter', 'desk', 'curtain', 'refrigerator',
'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin')),
dict(type='Collect3D', keys=['points'])
],
classes=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door', 'window',
'bookshelf', 'picture', 'counter', 'desk', 'curtain',
'refrigerator', 'showercurtrain', 'toilet', 'sink', 'bathtub',
'garbagebin'),
test_mode=True))
evaluation = dict(pipeline=[
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='DefaultFormatBundle3D',
class_names=('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin'),
with_label=False),
dict(type='Collect3D', keys=['points'])
])
lr = 0.008
optimizer = dict(
type='Adam',
lr=0.008)
optimizer_config = dict(
grad_clip=dict(
max_norm=10,
norm_type=2))
lr_config = dict(
policy='step',
warmup=None,
step=[24, 32])
checkpoint_config = dict(
interval=1)
log_config = dict(
interval=50,
hooks=[dict(type='TextLoggerHook'),
dict(type='TensorboardLoggerHook')])
runner = dict(type='EpochBasedRunner', max_epochs=36)
dist_params = dict(backend='nccl')
log_level = 'INFO'
find_unused_parameters = True
work_dir = None
load_from = None
resume_from = None
workflow = [('train', 1)]
gpu_ids = range(0, 1)
常见的一些修改方法 _delete=true的使用 通过设置 delete=True 来忽略基础配置文件里的一些域内容。
model = dict( type=‘MVXFasterRCNN’, pts_voxel_layer=dict(…), pts_voxel_encoder=dict(…), pts_middle_encoder=dict(…), pts_backbone=dict(…), pts_neck=dict( type=‘FPN’, norm_cfg=dict(type=‘naiveSyncBN2d’, eps=1e-3, momentum=0.01), act_cfg=dict(type=‘ReLU’), in_channels=[64, 128, 256], out_channels=256, start_level=0, num_outs=3), pts_bbox_head=dict(…))
base = ‘…/base/models/hv_pointpillars_fpn_nus.py’ model = dict( pts_neck=dict( delete=True, type=‘SECONDFPN’, norm_cfg=dict(type=‘naiveSyncBN2d’, eps=1e-3, momentum=0.01), in_channels=[64, 128, 256], upsample_strides=[1, 2, 4], out_channels=[128, 128, 128]), pts_bbox_head=dict(…))
配置文件里会使用一些中间变量,例如数据集中的 train_pipeline/test_pipeline。 值得注意的是,当修改子配置文件中的中间变量后,用户还需再次将其传入相应字段。 例如,我们想在训练和测试中,对 PointPillars 使用多尺度策略 (multi scale strategy),那么 train_pipeline/test_pipeline 就是我们想要修改的中间变量。
base = ‘./nus-3d.py’ train_pipeline = [ dict( type=‘LoadPointsFromFile’, load_dim=5, use_dim=5, file_client_args=file_client_args), dict( type=‘LoadPointsFromMultiSweeps’, sweeps_num=10, file_client_args=file_client_args), dict(type=‘LoadAnnotations3D’, with_bbox_3d=True, with_label_3d=True), dict( type=‘GlobalRotScaleTrans’, rot_range=[-0.3925, 0.3925], scale_ratio_range=[0.95, 1.05], translation_std=[0, 0, 0]), dict(type=‘RandomFlip3D’, flip_ratio_bev_horizontal=0.5), dict(type=‘PointsRangeFilter’, point_cloud_range=point_cloud_range), dict(type=‘ObjectRangeFilter’, point_cloud_range=point_cloud_range), dict(type=‘ObjectNameFilter’, classes=class_names), dict(type=‘PointShuffle’), dict(type=‘DefaultFormatBundle3D’, class_names=class_names), dict(type=‘Collect3D’, keys=[‘points’, ‘gt_bboxes_3d’, ‘gt_labels_3d’]) ] test_pipeline = [ dict( type=‘LoadPointsFromFile’, load_dim=5, use_dim=5, file_client_args=file_client_args), dict( type=‘LoadPointsFromMultiSweeps’, sweeps_num=10, file_client_args=file_client_args), dict( type=‘MultiScaleFlipAug3D’, img_scale=(1333, 800), pts_scale_ratio=[0.95, 1.0, 1.05], flip=False, transforms=[ dict( type=‘GlobalRotScaleTrans’, rot_range=[0, 0], scale_ratio_range=[1., 1.], translation_std=[0, 0, 0]), dict(type=‘RandomFlip3D’), dict( type=‘PointsRangeFilter’, point_cloud_range=point_cloud_range), dict( type=‘DefaultFormatBundle3D’, class_names=class_names, with_label=False), dict(type=‘Collect3D’, keys=[‘points’]) ]) ] data = dict( train=dict(pipeline=train_pipeline), val=dict(pipeline=test_pipeline), test=dict(pipeline=test_pipeline))
这里,我们首先定义了新的 train_pipeline/test_pipeline,然后将其传入 data。
|