目录
- 模型微调
- 修改第一处:更少的训练回合Epoch
- 修改第二处:更小的学习率Learning Rate
- 修改第三处:使用预训练模型
- 权重初始化
- 实际使用案例
- init_cfg 的具体使用规则
- 初始化器配置汇总
本文基于 MMDetection官方文档,对模型微调和权重初始化进行第三方讲解。
模型微调
在 COCO 数据集上预训练的检测器可以作为其他数据集优质的预训练模型。
微调超参数与默认的训练策略不同。它通常需要更小的学习率和更少的训练回合。根据配置文件最上方继承父类文件路径_base_
的位置找到与优化和训练测试相关的配置文件,我选择的Faster R-CNN子配置文件的对应父类文件位于mmdetection/configs/common/ms_3x_coco.py
,为了不修改官方已经继承的配置文件,我们可以选择新建一个文件进行,例如修改为mmdetection/configs/common/ms_3x_coco_finetuning.py
。在进行下列步骤之前,请确保数据集与配置文件相匹配,并且检测头roi_head
的num_classes
与数据集类别数相匹配,参考利用MMDetection在自定义数据集上进行训练。
修改第一处:更少的训练回合Epoch
train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=8, val_interval=1)
# max_epochs = 12 → 8
修改第二处:更小的学习率Learning Rate
optim_wrapper = dict(
type='OptimWrapper',
optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001))
# lr = 0.002 → 0.001
修改第三处:使用预训练模型
load_from = '/home/miqi/mmdetection/checkpoints/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.pth'
权重初始化
在训练过程中,适当的初始化策略有利于加快训练速度或获得更⾼的性能。 MMCV 提供了一些常⽤的初始化模块的⽅法,如 nn.Conv2d
。 MMdetection中的模型初始化主要使⽤ init_cfg
。
实际使用案例
例如在mmdetection/mmdet/models/necks/fpn.py
中
@MODELS.register_module()
class FPN(BaseModule):
def __init__(
self,
in_channels: List[int],
out_channels: int,
num_outs: int,
start_level: int = 0,
end_level: int = -1,
add_extra_convs: Union[bool, str] = False,
relu_before_extra_convs: bool = False,
no_norm_on_lateral: bool = False,
conv_cfg: OptConfigType = None,
norm_cfg: OptConfigType = None,
act_cfg: OptConfigType = None,
upsample_cfg: ConfigType = dict(mode='nearest'),
init_cfg: MultiConfig = dict(
type='Xavier', layer='Conv2d', distribution='uniform')
) -> None:
super().__init__(init_cfg=init_cfg)
我们可以对该文件的init_cfg
部分进行修改,但这样会破坏该组件与其他配置文件之间的的集成性,最好的方法是在子类配置文件中复写init_cfg
部分,例如在mmdetection/configs/_base_/models/faster-rcnn_r50_fpn.py
中的model
设置模块找到neck
组件
# model settings
model = dict(
type='FasterRCNN',
neck=dict(
type='FPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
num_outs=5))
将__init__
初始化中的'Xavier'
修改为'kaiming'
并复写入neck
组件的init_cfg
,这一步就是完成了对卷积层从Xavier初始化更换为使用Kaiming初始化的操作
neck=dict(
type='FPN',
in_channels=[256, 512, 1024, 2048],
out_channels=256,
num_outs=5,
init_cfg = dict(
type='kaiming', layer='Conv2d', distribution='uniform'))
init_cfg 的具体使用规则
-
用
layer
键初始化模型如果我们只定义了
layer
, 它只会在layer
键中初始化网络层。注意:
layer
键对应的值是 Pytorch 的带有 weights 和 bias 属性的类名(因此不⽀持MultiheadAttention
层)。
-
定义⽤于初始化具有相同配置的模块的
layer
键。init_cfg = dict(type='Constant', layer=['Conv1d', 'Conv2d', 'Linear'], val=1) # ⽤相同的配置初始化整个模块
-
定义⽤于初始化具有不同配置的层的
layer
键。init_cfg = [dict(type='Constant', layer='Conv1d', val=1), dict(type='Constant', layer='Conv2d', val=2), dict(type='Constant', layer='Linear', val=3)] # nn.Conv1d 将被初始化为 dict(type='Constant', val=1) # nn.Conv2d 将被初始化为 dict(type='Constant', val=2) # nn.Linear 将被初始化为 dict(type='Constant', val=3)
- 使⽤
override
键初始化模型
-
当使⽤属性名初始化某些特定部分时,我们可以使⽤
override
键,override
中的值将忽略 init_cfg 中的值。# layers: # self.feat = nn.Conv1d(3, 1, 3) # self.reg = nn.Conv2d(3, 3, 3) # self.cls = nn.Linear(1,2) init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2, override=dict(type='Constant', name='reg', val=3, bias=4)) # self.feat and self.cls 将被初始化为 dict(type='Constant', val=1, bias=2) # 叫 'reg' 的模块将被初始化为 dict(type='Constant', val=3, bias=4)
-
如果 init_cfg 中的
layer
为 None,则只会初始化 override 中有 name 的⼦模块,⽽ override 中的 type 和其他参数可以省略。# layers: # self.feat = nn.Conv1d(3, 1, 3) # self.reg = nn.Conv2d(3, 3, 3) # self.cls = nn.Linear(1,2) init_cfg = dict(type='Constant', val=1, bias=2, override=dict(name='reg')) # self.feat and self.cls 将被 Pytorch 初始化 # 叫 'reg' 的模块将被 dict(type='Constant', val=1, bias=2) 初始化
-
如果我们不定义
layer
或override
键,它不会初始化任何东西。 -
无效的使用
# override 没有 name 键的话是无效的 init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2, override=dict(type='Constant', val=3, bias=4)) # override 有 name 键和其他参数但是没有 type 键也是无效的 init_cfg = dict(type='Constant', layer=['Conv1d','Conv2d'], val=1, bias=2, override=dict(name='reg', val=3, bias=4))
-
使⽤预训练模型初始化模型
init_cfg = dict(type='Pretrained', checkpoint='torchvision://resnet50')
初始化器配置汇总
我们可以通过配置 init_cfg
为模型中任意组件灵活地选择初始化方式。目前我们可以在 init_cfg
中配置以下初始化器:
Initializer | Registered name | Function |
---|---|---|
ConstantInit | Constant | 将 weight 和 bias 初始化为指定常量,通常用于初始化卷积 |
XavierInit | Xavier | 将 weight Xavier 方式初始化,将 bias 初始化成指定常量,通常用于初始化卷积 |
NormalInit | Normal | 将 weight 以正态分布的方式初始化,将 bias 初始化成指定常量,通常用于初始化卷积 |
TruncNormalInit | TruncNormal | 将 weight 以被截断的正态分布的方式初始化,参数 a 和 b 为正态分布的有效区域;将 bias 初始化成指定常量,通常用于初始化 Transformer |
UniformInit | Uniform | 将 weight 以均匀分布的方式初始化,参数 a 和 b 为均匀分布的范围;将 bias 初始化为指定常量,通常用于初始化卷积 |
KaimingInit | Kaiming | 将 weight 以 Kaiming 的方式初始化,将 bias 初始化成指定常量,通常用于初始化卷积 |
Caffe2XavierInit | Caffe2Xavier | Caffe2 中 Xavier 初始化方式,在 Pytorch 中对应 “fan_in”, “normal” 模式的 Kaiming 初始化,,通常用于初始化卷 |
Pretrained | PretrainedInit | 加载预训练权重 |
本贴后续会利用Faster R-CNN对预训练权重初始化和常用初始化进行实验,详情教程请见MMEgine权重初始化。