提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本文主要介绍MMDetection中Pointpillars训练文件代码,文件名为
“mmdetection3d/configs/pointpillars/pointpillars_hv_secfpn_8xb6-160e_kitti-3d-3class.py”
一、原代码
# 模型配置文件的路径
_base_ = [
'../_base_/models/pointpillars_hv_secfpn_kitti.py',
'../_base_/datasets/kitti-3d-3class.py',
'../_base_/schedules/cyclic-40e.py', '../_base_/default_runtime.py'
]
# 点云的范围定义
point_cloud_range = [0, -39.68, -3, 69.12, 39.68, 1]
# 数据集设置
data_root = 'data/kitti/' # 数据集根目录
class_names = ['Pedestrian', 'Cyclist', 'Car'] # 类别名称
metainfo = dict(classes=class_names) # 类别信息
backend_args = None # 后端参数
# 数据采样策略定义
db_sampler = dict(
data_root=data_root, # 数据集的根目录
info_path=data_root + 'kitti_dbinfos_train.pkl', # 数据集信息文件的路径
rate=1.0, # 采样率,表示采样的比例,1.0 表示全部采样
prepare=dict(
filter_by_difficulty=[-1], # 根据难度过滤样本的设置,这里的-1表示不进行难度过滤
filter_by_min_points=dict(Car=5, Pedestrian=5, Cyclist=5) # 根据最小点数过滤样本的设置,对不同类别的物体设置了最小点数要求
),
classes=class_names, # 类别名称列表
sample_groups=dict(Car=15, Pedestrian=15, Cyclist=15), # 不同类别的采样组数,这里每个类别都设置了采样15次
points_loader=dict(
type='LoadPointsFromFile', # 加载点云数据的方式,这里是从文件加载
coord_type='LIDAR', # 点云的坐标类型,LIDAR 表示激光雷达坐标
load_dim=4, # 加载的点云维度
use_dim=4, # 使用的点云维度
backend_args=backend_args # 后端参数
),
backend_args=backend_args # 后端参数
)
# 训练数据处理流程
train_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=4,
use_dim=4,
backend_args=backend_args),
dict(type='LoadAnnotations3D', with_bbox_3d=True, with_label_3d=True),
dict(type='ObjectSample', db_sampler=db_sampler, use_ground_plane=True),
dict(type='RandomFlip3D', flip_ratio_bev_horizontal=0.5),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.78539816, 0.78539816],
scale_ratio_range=[0.95, 1.05]),
dict(type='PointsRangeFilter', point_cloud_range=point_cloud_range),
dict(type='ObjectRangeFilter', point_cloud_range=point_cloud_range),
dict(type='PointShuffle'),
dict(
type='Pack3DDetInputs',
keys=['points', 'gt_labels_3d', 'gt_bboxes_3d'])
]
# 测试数据处理流程
test_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=4,
use_dim=4,
backend_args=backend_args),
dict(
type='MultiScaleFlipAug3D',
img_scale=(1333, 800),
pts_scale_ratio=1,
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='Pack3DDetInputs', keys=['points'])
]
# 训练数据加载器配置
train_dataloader = dict(
dataset=dict(dataset=dict(pipeline=train_pipeline, metainfo=metainfo)))
# 测试数据加载器配置
test_dataloader = dict(dataset=dict(pipeline=test_pipeline, metainfo=metainfo))
val_dataloader = dict(dataset=dict(pipeline=test_pipeline, metainfo=metainfo))
# 优化器配置
lr = 0.001 # 学习率
epoch_num = 80 # 训练轮数
optim_wrapper = dict(
optimizer=dict(lr=lr), clip_grad=dict(max_norm=35, norm_type=2)) # 优化器配置
# 学习率调整策略
param_scheduler = [
dict(
type='CosineAnnealingLR',
T_max=epoch_num * 0.4,
eta_min=lr * 10,
begin=0,
end=epoch_num * 0.4,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingLR',
T_max=epoch_num * 0.6,
eta_min=lr * 1e-4,
begin=epoch_num * 0.4,
end=epoch_num * 1,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingMomentum',
T_max=epoch_num * 0.4,
eta_min=0.85 / 0.95,
begin=0,
end=epoch_num * 0.4,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingMomentum',
T_max=epoch_num * 0.6,
eta_min=1,
begin=epoch_num * 0.4,
end=epoch_num * 1,
convert_to_iter_based=True)
]
# 训练配置
train_cfg = dict(by_epoch=True, max_epochs=epoch_num, val_interval=2)
val_cfg = dict()
test_cfg = dict()
二、概述
这段代码涉及到训练深度学习模型的一些重要配置,下面我将逐一详细解释每个部分的含义和作用:
-
lr = 0.001
:lr
是学习率(learning rate)的缩写。- 学习率是用于控制模型参数更新步长的超参数,它决定了每次参数更新的大小。
- 在这里,学习率被设置为0.001,表示在每次参数更新时,每个参数的值都会按照0.001倍的步长进行更新。
-
epoch_num = 80
:epoch_num
表示训练的轮数(epochs)。- 一个轮是指整个训练数据集被完整地输入到模型中一次。
- 在这里,训练被设置为总共进行80轮。
-
optim_wrapper = dict(optimizer=dict(lr=lr), clip_grad=dict(max_norm=35, norm_type=2))
:optim_wrapper
是一个包含优化器相关设置的字典。optimizer
字段表示优化器的配置,这里使用了一个带有学习率设置的优化器。clip_grad
字段表示梯度裁剪(gradient clipping)的配置,用于防止梯度爆炸问题。max_norm
表示梯度的最大范数(norm)值,如果梯度的范数超过这个值,就会进行梯度裁剪。norm_type
表示使用的范数类型,这里是L2范数。
-
param_scheduler
:param_scheduler
是一个包含学习率和动量(momentum)调整策略的列表。- 这里使用了四个不同的调整策略,它们会随着训练的进行动态地改变学习率和动量。
- 每个调整策略是一个字典,包含以下字段:
type
:调整策略的类型,可以是学习率调整或动量调整。T_max
:调整的周期,即在多少个训练轮次之后重新开始调整。eta_min
:学习率或动量的最小值。begin
和end
:指定调整的开始和结束轮次。by_epoch
:指定是否按照轮次进行调整。convert_to_iter_based
:指定是否将调整策略转换为基于迭代次数的策略。
这段代码中的 lr
、epoch_num
、optim_wrapper
和 param_scheduler
配置了训练深度学习模型所需的学习率、训练轮数、优化器和学习率/动量调整策略等重要参数,以帮助训练过程更好地收敛和优化模型。不同的学习率和调整策略可以对模型的性能产生重要影响,需要根据具体问题和数据集进行调整和优化。
三、根据难度和最小点数过滤样本
“根据难度和最小点数过滤样本” 是一种在目标检测和物体识别任务中常用的数据预处理策略。这个策略的目的是在训练数据集中选择适合模型训练的样本,同时排除那些难以处理或质量不佳的样本。下面详细解释这两个过滤条件的含义:
-
根据难度过滤样本:
在目标检测任务中,通常会将样本按照难度分为不同级别,例如简单、中等和困难。这个难度级别可以根据不同数据集的定义而有所不同,但通常与物体的大小、遮挡程度、姿态等因素有关。
- 简单样本:通常指那些容易检测的物体,例如大型、无遮挡、正立的物体。
- 中等样本:具有一定难度的样本,可能有一些遮挡或非常小的物体。
- 困难样本:指那些非常具有挑战性的样本,可能存在严重遮挡、极小的物体或非常复杂的姿态等情况。
通过根据难度过滤样本,可以选择训练集中特定难度级别的样本,以确保模型能够适应不同难度级别的场景。
-
根据最小点数过滤样本:
在点云数据中,每个物体通常由一组点云表示。样本的质量和可用性与点云的密度和数量有关。根据最小点数过滤样本的策略旨在排除那些点云数量太少的样本,因为这样的样本可能难以有效地用于训练。
例如,如果目标检测任务中,要求每个物体至少包含一定数量的点云,比如5个点云点,那么根据最小点数过滤样本的策略会排除那些点云数量少于5的物体,以确保训练样本的质量和可用性。
综合来看,“根据难度和最小点数过滤样本” 是一种在数据预处理阶段,根据物体的难度级别和点云的数量,筛选出符合条件的样本,以构建用于训练深度学习模型的训练集。这样的策略有助于提高模型的鲁棒性和泛化能力,因为它允许模型在各种不同难度级别和点云密度下进行训练。筛选过程可以根据具体任务和数据集的要求进行调整。
四、余弦退火部分(学习率lr,动量Momentum)
代码如下:
# 学习率设置,控制参数更新的步长
lr = 0.001
# 训练轮数,一个轮表示整个训练数据集被完整输入模型一次
epoch_num = 80
# 优化器配置,包含学习率设置和梯度裁剪配置
optim_wrapper = dict(
optimizer=dict(lr=lr), # 学习率设置为0.001
clip_grad=dict(max_norm=35, norm_type=2) # 梯度裁剪配置,防止梯度爆炸
)
# 学习率和动量调整策略列表
param_scheduler = [
dict(
type='CosineAnnealingLR', # 学习率调整策略类型:余弦退火
T_max=epoch_num * 0.4, # 调整周期为总轮数的40%
eta_min=lr * 10, # 最小学习率设为初始学习率的10倍
begin=0, # 开始轮数
end=epoch_num * 0.4, # 结束轮数
by_epoch=True, # 按轮数调整
convert_to_iter_based=True), # 转换为基于迭代次数的策略
dict(
type='CosineAnnealingLR',
T_max=epoch_num * 0.6,
eta_min=lr * 1e-4,
begin=epoch_num * 0.4,
end=epoch_num * 1,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingMomentum', # 动量调整策略类型:余弦退火
T_max=epoch_num * 0.4,
eta_min=0.85 / 0.95,
begin=0,
end=epoch_num * 0.4,
by_epoch=True,
convert_to_iter_based=True),
dict(
type='CosineAnnealingMomentum',
T_max=epoch_num * 0.6,
eta_min=1,
begin=epoch_num * 0.4,
end=epoch_num * 1,
convert_to_iter_based=True)
]
动量调整是深度学习优化算法中的一种技巧,通常用于随机梯度下降(SGD)和其变种的优化器中,如带动量的随机梯度下降(Momentum SGD)或带动量的Adam优化器(Adam with Momentum)等。
在梯度下降中,每次更新参数时,会根据当前梯度的方向和大小来移动参数,以尽量减小损失函数的值。然而,在复杂的损失曲面上,存在很多局部极小值和平原区域,这可能导致梯度下降收敛速度较慢或陷入局部最小值。动量调整的目的是加速模型参数的更新,并帮助模型跳出局部极小值和平原区域。
动量调整的核心思想是引入一个动量项(momentum),该项表示前几次梯度更新的累积方向和大小。这样做的好处是,即使当前梯度指向局部极小值或平原区域,动量也可以帮助模型在一定程度上继续前进,直到找到更陡峭的下降方向。
通常,动量调整的计算公式如下:
v(t+1) = beta * v(t) + learning_rate * gradient
parameter(t+1) = parameter(t) - v(t+1)
其中:
v(t)
是在时间步t
的动量(velocity)。beta
是动量系数,通常取值在0到1之间,控制了动量的积累程度。较大的beta
表示更多的动量积累。learning_rate
是学习率,控制了每次参数更新的步长。gradient
是当前时间步的梯度。
总的来说,动量调整允许模型在梯度更新方向上积累速度,从而加速收敛过程,并提高了模型跳出局部最小值的可能性。这使得训练深度神经网络更加稳定和高效。