其实我认为你不必更新optimizer。交给optimizer 的Parameters 只是参考。
因此,当您更改 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
输出:
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,后来在停用渐变后,p1 是 tensor([[0., 0., 0., 0., 0.]]) 而不是 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
因此,一旦重置为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]])
我希望这对你有意义!