PyTorch参数初始化及Finetunning

前言

PyTorch的代码中很多都有显式的参数初始化过程(默认的初始化形式是什么?),本文将对其做一个总结。

参数初始化

参数的初始化其实就是对参数进行赋值。网络中所需要学习的参数其实都是Variable,它其实是对Tensor的封装,同时提供了datagrad等接口,这就意味着我们可以直接对这些参数进行赋值操作。这就是PyTorch简洁高效所在。

img

PyTorch中有多种初始化方式,但是其作者所推崇的方式如下:

1
2
3
4
5
6
7
def weight_init(m):
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, math.sqrt(2. / n))
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1)
m.bias.data.zero_()

Finetunning

通常在加载了预训练模型的参数之后,我们需要finetune模型,一般有以下两种方式:

局部微调

冻结其它层,只调节最后的几层。其实不训练也就意味着不进行梯度计算,PyTorch中提供的requires_grad使得对训练的控制变得非常简单。

1
2
3
4
5
6
7
8
model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
param.requires_grad = False
# 替换最后的全连接层,新构造的模块的参数默认requires_grad=True
model.fc = nn.Linear(512, 100)

# 只优化最后的分类层
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)

全局微调

对全局都进行finetune,但是希望该换过的层和其它层的学习率不同,这是可以把其它层和新层在optimizer中单独赋予不同的学习率。如下:

1
2
3
4
5
6
7
8
ignored_params = list(map(id, model.fc.parameters()))
base_params = filter(lambda p: id(p) not in ignored_params,
model.parameters())

optimizer = torch.optim.SGD([
{'params': base_params},
{'params': model.fc.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)

其中base_params使用1e-3来训练,model.fc.parameters使用1e-2来训练,momentum是二者共有的。

Reference