Python Pytork梯度不';t流过张量的克隆体

Python Pytork梯度不';t流过张量的克隆体,python,pytorch,Python,Pytorch,我试图让我的模型学习某种功能。我有可训练的参数self.a、self.b、self.c。我试图通过使用tanh强制self.b处于某个范围内。但是,当我运行代码时,它显示为渐变正在通过原始参数(self.b),而不是通过克隆(self.b_opt) 导入火炬 导入torch.nn作为nn 将torch.optim导入为optim 类模型(nn.Module): 定义初始化(自): 超级(模型,自我)。\uuuu初始化 self.a=torch.nn.Parameter(torch.rand(1,

我试图让我的模型学习某种功能。我有可训练的参数
self.a、self.b、self.c
。我试图通过使用
tanh
强制
self.b
处于某个范围内。但是,当我运行代码时,它显示为渐变正在通过原始参数(
self.b
),而不是通过克隆(
self.b_opt

导入火炬
导入torch.nn作为nn
将torch.optim导入为optim
类模型(nn.Module):
定义初始化(自):
超级(模型,自我)。\uuuu初始化
self.a=torch.nn.Parameter(torch.rand(1,requires_grad=True))
self.b=torch.nn.参数(torch.rand(1,需要_grad=True))
self.c=torch.nn.Parameter(torch.rand(1,requires_grad=True))
self.b_opt=torch.tanh(self.b.clone())
model_net=model()
#学习功能=5*(r>2)*(3)
optimizer=optim.Adam(model_net.parameters(),lr=0.1)
对于范围内的历元(10):
对于范围(5)内的r:
optimizer.zero_grad()
损耗=5*(r>2)*(3)-模型净a*火炬.sigmoid((r-模型净b\u opt))*(模型净c)
损失。向后(保留图=真)
optimizer.step()
#印刷品(a型)
打印(型号\网络b)
打印(model_net.b_opt)
#打印(型号c)
打印()
>>>参数包含:
张量([0.4298],需要_grad=True)
张量([0.7229],梯度fn=)
参数包含:
张量([-0.0277],需要_grad=True)
张量([0.7229],梯度fn=)
参数包含:
张量([-0.5007],需要_grad=True)
张量([0.7229],梯度fn=)

梯度确实会流经
b_opt
,因为它是损失函数中的张量。但是,它不是叶张量(它是对张量操作的结果,特别是
克隆
tanh
,您可以使用
model_net.b_opt.is_leaf
)进行检查,这意味着它允许传播梯度,但不累积梯度(
b_opt.grad
)。不能通过backprop更新
b_opt
的值

然而,
b
的值被更新的事实证明梯度确实流动!您实际需要的是每次更新
b
时重新计算
b_opt
,因为在这里,
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)

令人惊叹的!这很有道理,也很有效。谢谢
loss = 5 * (r > 2) * (3) - model_net.a * torch.sigmoid((r - tanh(model_net.b))) * (model_net.c)