Ben*_* K. 7 python machine-learning computer-vision pytorch
冻结pytorch中的砝码以进行param_groups设置。
因此,如果您想在训练期间冻结体重:
for param in child.parameters():
param.requires_grad = False
Run Code Online (Sandbox Code Playgroud)
优化器也必须更新为不包括非梯度权重:
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=opt.lr, amsgrad=True)
Run Code Online (Sandbox Code Playgroud)
如果要weight_decay对偏倚和权重使用不同的/学习率/这也允许不同的学习率:
param_groups = [{'params': model.module.bias_parameters(), 'weight_decay': args.bias_decay},
{'params': model.module.weight_parameters(), 'weight_decay': args.weight_decay}]
Run Code Online (Sandbox Code Playgroud)
param_groups定义了一个dic 列表,并将其传递SGD如下:
optimizer = torch.optim.Adam(param_groups, args.lr,
betas=(args.momentum, args.beta))
Run Code Online (Sandbox Code Playgroud)
冻结单个砝码如何实现?在dic列表上运行filter或是否可以将张量单独添加到优化器?
实际上,我认为您不必更新optimizer。该Parameters交给optimizer只是引用。
因此,当您更改requires_grad标志时,它将立即被更新。
但是,即使由于某种原因而并非如此-将requires_grad标记设置为,False您就无法再为此重量计算任何新的梯度(请参见底部的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
Run Code Online (Sandbox Code Playgroud)
输出:
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]])
Run Code Online (Sandbox Code Playgroud)
在这里您可以看到没有计算梯度。您可能已经注意到for的渐变p2是None在开始,之后是tensor([[0., 0., 0., 0., 0.]])for的,p1而不是None在取消激活渐变之后。
之所以如此,p1.weight.grad是因为只是一个由backward()和修改的变量optimizer.zero_grad()。
因此,开始时p1.weight.grad仅使用初始化None,将梯度写入或累积到此变量后,它们不会自动清除。但是由于optimizer.zero_grad()称为,它们被设置为零并保持这种状态,因为backward()无法再使用来计算新的梯度requires_grad=False。
您还可以将if-statement中的代码更改为:
if i == 1:
p1.weight.requires_grad = False
p1.weight.grad = None
p2.weight.requires_grad = True
Run Code Online (Sandbox Code Playgroud)
因此,一旦重置为None原样,便保持不变None:
p1: requires_grad = True , gradient: tensor([[0.2375, 0.7528, 0.1501, 0.3516, 0.3470]])
p2: requires_grad = False , gradient: None
p1: requires_grad = True , gradient: tensor([[0.5181, 0.5178, 0.6590, 0.6950, 0.2743]])
p2: requires_grad = False , gradient: None
p1: requires_grad = False , gradient: None
p2: requires_grad = True , gradient: tensor([[0.4797, 0.7203, 0.2284, 0.9045, 0.6671]])
p1: requires_grad = False , gradient: None
p2: requires_grad = True , gradient: tensor([[0.8344, 0.1245, 0.0295, 0.2968, 0.8816]])
Run Code Online (Sandbox Code Playgroud)
我希望这对您有意义!
| 归档时间: |
|
| 查看次数: |
3852 次 |
| 最近记录: |