PyTorch 梯度不会流过张量的克隆

时间:2021-04-20 15:22:59

标签: python pytorch

我正在尝试让我的模型学习某个功能。我有可训练的参数 self.a, self.b, self.c。我正在尝试使用 self.b 强制 tanh 处于特定范围内。但是,当我运行代码时,它显示为梯度流经原始参数 (self.b),但不流经克隆 (self.b_opt)

import torch
import torch.nn as nn
import torch.optim as optim

class model(nn.Module): 
        def __init__(self):
            super(model, self).__init__()
            self.a = torch.nn.Parameter(torch.rand(1, requires_grad=True))
            self.b = torch.nn.Parameter(torch.rand(1, requires_grad=True))
            self.c = torch.nn.Parameter(torch.rand(1, requires_grad=True))

            self.b_opt = torch.tanh(self.b.clone())

model_net = model()
#function to learn = 5 * (r > 2) * (3) 
optimizer = optim.Adam(model_net.parameters(), lr = 0.1)

for epoch in range(10):
  for r in range(5):
    optimizer.zero_grad()
    loss = 5 * (r > 2) * (3) - model_net.a * torch.sigmoid((r - model_net.b_opt)) * (model_net.c)

    loss.backward(retain_graph=True)
    optimizer.step()
  #print(model_net.a)
  print(model_net.b)
  print(model_net.b_opt)
  #print(model_net.c)
  print()

>>> Parameter containing:
tensor([0.4298], requires_grad=True)
tensor([0.7229], grad_fn=<TanhBackward>)

Parameter containing:
tensor([-0.0277], requires_grad=True)
tensor([0.7229], grad_fn=<TanhBackward>)

Parameter containing:
tensor([-0.5007], requires_grad=True)
tensor([0.7229], grad_fn=<TanhBackward>)

1 个答案:

答案 0 :(得分:1)

gradient 确实流经 b_opt,因为它是您的损失函数中涉及的张量。但是,它不是叶张量(它是张量运算的结果,特别是 clonetanh,您可以使用 model_net.b_opt.is_leaf 检查),这意味着它允许梯度被传播但不累积它们(b_opt.grad 不存在)。您无法通过反向传播更新 b_opt 的值。

然而,b 的值被更新的事实证明梯度确实流动了!您实际需要的是每次更新 b_opt 时重新计算 b,因为这里您的 b_optinit 函数中被一次性计算。那将是类似

...
loss.backward(retain_graph=True)
optimizer.step()
self.b_opt = torch.tanh(self.b.clone())
...

一个更简单的方法是完全摆脱b_opt,并用

代替你的损失
loss = 5 * (r > 2) * (3) - model_net.a * torch.sigmoid((r - tanh(model_net.b))) * (model_net.c)
相关问题