假设我有一个简单的NN:
import torchimport torch.nn as nnimport torch.optim as optimfrom torch.nn.utils import parameters_to_vectorclass Model(nn.Module): def __init__(self): super(Model, self).__init__() self.fc1 = nn.Linear(1, 2) self.fc2 = nn.Linear(2, 3) self.fc3 = nn.Linear(3, 1) def forward(self, x): x = self.fc1(x) x = torch.relu(x) x = torch.relu(self.fc2(x)) x = self.fc3(x) return xnet = Model()opt = optim.Adam(net.parameters())
还有几个特征
features = torch.rand((3,1))
我可以正常训练它,使用:
for i in range(10): opt.zero_grad() out = net(features) loss = torch.mean(torch.square(torch.tensor(5) - torch.sum(out))) loss.backward() opt.step()
然而,我对在批次中的每个示例之后更新每一层的权重感兴趣。也就是说,通过某些对于每一层不同的量来更新实际的权重值。
我可以用以下代码打印每一层的参数:
for i in range(1): opt.zero_grad() out = net(features) print(parameters_to_vector(net.fc1.parameters())) print(parameters_to_vector(net.fc2.parameters())) print(parameters_to_vector(net.fc3.parameters())) loss = torch.mean(torch.square(torch.tensor(5) - torch.sum(out))) loss.backward() opt.step()
如何在反向传播之前更改权重值而不影响梯度?
假设我想根据以下函数更新各层的权重:
def first_layer_update(weight): return weight + 1e-3*weightdef second_layer_update(weight): return 1e-2*weightdef third_layer_update(weight): return weight - 1e-1*weight
回答:
– 使用torch.no_grad
上下文管理器。
这允许你在你的张量上执行(就地或非就地)操作,而Autograd不会跟踪这些变化。正如@***解释的那样:
def first_layer_update(weight): with torch.no_grad(): return weight + 1e-3*weightdef second_layer_update(weight): with torch_no_grad(): return 1e-2*weightdef third_layer_update(weight): with torch.no_grad(): return weight - 1e-1*weight
或者在调用它们时使用上下文管理器而不改变你的函数:
with torch.no_grad(): first_layer_update(net.fc1.weight) second_layer_update(net.fc2.weight) third_layer_update(net.fc3.weight)
– 使用@torch.no_grad
装饰器。
一种变体是使用@torch.no_grad
装饰器:
@torch.no_grad()def first_layer_update(weight): return weight + 1e-3*weight@torch.no_grad():def second_layer_update(weight): return 1e-2*weight@torch.no_grad():def third_layer_update(weight): return weight - 1e-1*weight
并以first_layer_update(net.fc1.weight)
、second_layer_update(net.fc2.weight)
等方式调用这些函数…
– 变更torch.Tensor.data
。
替代使用torch.no_grad
上下文包装你的操作的方法是,使用权重的data
属性来变更权重。这意味着以以下方式调用你的函数:
>>> first_layer_update(net.fc1.weight.data)>>> second_layer_update(net.fc2.weight.data)>>> third_layer_update(net.fc3.weight.data)
这将使用各自的更新策略变更三层的权重(不是偏置)。
简而言之,如果你想变更nn.Module
的所有参数,你可以:
>>> with torch.no_grad():... update_policy(parameters_to_vector(net.layer.parameters()))
或者
>>> update_policy(parameters_to_vector(net.layer.parameters().data))