pytorch冻结权重并更新param_groups

时间:2018-11-05 17:36:50

标签: python machine-learning computer-vision pytorch

param_groups设置冻结pytorch中的权重。

因此,如果您想在训练期间冻结体重:

for param in child.parameters():
    param.requires_grad = False

优化器还必须进行更新,以不包括非梯度权重:

optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=opt.lr, amsgrad=True)

如果要使用不同的weight_decay /学习率作为偏见和权重/这也允许使用不同的学习率:

param_groups = [{'params': model.module.bias_parameters(), 'weight_decay': args.bias_decay},
                {'params': model.module.weight_parameters(), 'weight_decay': args.weight_decay}]

param_groups定义了 dics list 并将其传递到SGD中,如下所示:

optimizer = torch.optim.Adam(param_groups, args.lr,
                                 betas=(args.momentum, args.beta))

如何冻结单个体重?在dic列表上运行filter或是否有一种方法可以分别向优化器添加张量?

1 个答案:

答案 0 :(得分:4)

实际上,我认为您不必更新optimizer。移交给Parameters的{​​{1}}只是参考。

因此,当您更改optimizer标志时,它将立即被更新。

但是,即使由于某种原因,情况并非如此-将requires_grad标志设置为requires_grad后,您就无法再计算任何 新渐变 (参见底部的False和零梯度),因此,如果您使用{{1} }只会停留在None

因此,如果没有渐变,则也无需从optimizer.zero_grad()中排除这些渐变。因为zero如果没有梯度,无论您使用哪种学习率,都将无能为力。

这是一个显示此行为的小例子:

optimizer

输出:

optimizer

在这里您可以看到没有计算梯度。您可能已经注意到,import torch import torch.nn as nn import torch.optim as optim n_dim = 5 p1 = nn.Linear(n_dim, 1) p2 = nn.Linear(n_dim, 1) optimizer = optim.Adam(list(p1.parameters())+list(p2.parameters())) p2.weight.requires_grad = False for i in range(4): dummy_loss = (p1(torch.rand(n_dim)) + p2(torch.rand(n_dim))).squeeze() optimizer.zero_grad() dummy_loss.backward() optimizer.step() print('p1: requires_grad =', p1.weight.requires_grad, ', gradient:', p1.weight.grad) print('p2: requires_grad =', p2.weight.requires_grad, ', gradient:', p2.weight.grad) print() if i == 1: p1.weight.requires_grad = False p2.weight.requires_grad = True 的梯度在开始时是p1: requires_grad = True , gradient: tensor([[0.8522, 0.0020, 0.1092, 0.8167, 0.2144]]) p2: requires_grad = False , gradient: None p1: requires_grad = True , gradient: tensor([[0.7635, 0.0652, 0.0902, 0.8549, 0.6273]]) p2: requires_grad = False , gradient: None p1: requires_grad = False , gradient: tensor([[0., 0., 0., 0., 0.]]) p2: requires_grad = True , gradient: tensor([[0.1343, 0.1323, 0.9590, 0.9937, 0.2270]]) p1: requires_grad = False , gradient: tensor([[0., 0., 0., 0., 0.]]) p2: requires_grad = True , gradient: tensor([[0.0100, 0.0123, 0.8054, 0.9976, 0.6397]]) ,后来在停用梯度之后,p2的梯度是None,而不是tensor([[0., 0., 0., 0., 0.]])

之所以会这样,是因为p1只是被Nonep1.weight.grad修改的变量。

因此,backward()刚开始用optimizer.zero_grad()初始化,在将梯度写入或累积到此变量之后,它们不会自动清除。但是因为p1.weight.grad被调用,所以它们被设置为零并保持这样,因为None不再能够使用optimizer.zero_grad()计算新的梯度。

您还可以将backward()语句中的代码更改为:

requires_grad=False

因此,一旦重置为if,他们将保持原状并停留在if i == 1: p1.weight.requires_grad = False p1.weight.grad = None p2.weight.requires_grad = True

None

我希望这对您有意义!