我正在尝试让我的模型学习某个功能。我有可训练的参数 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>)
答案 0 :(得分:1)
gradient 确实流经 b_opt
,因为它是您的损失函数中涉及的张量。但是,它不是叶张量(它是张量运算的结果,特别是 clone
和 tanh
,您可以使用 model_net.b_opt.is_leaf
检查),这意味着它允许梯度被传播但不累积它们(b_opt.grad
不存在)。您无法通过反向传播更新 b_opt
的值。
然而,b
的值被更新的事实证明梯度确实流动了!您实际需要的是每次更新 b_opt
时重新计算 b
,因为这里您的 b_opt
在 init
函数中被一次性计算。那将是类似
...
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)