Pytorch 模型梯度没有使用一些自定义代码进行更新

Pytorch model gradients no updating with some custom code

我整理了一些计算,试图计算结果的损失,并计算模型所有参数的梯度 w.r.t。那个损失。问题是计算中包含一个我希望能够(最终)调整的可调模型。现在我只是想确认当模型参数用 backward() 更新时我可以看到它们的梯度,但我不能,这就是问题所在。下面我 post 代码、输出和所需的输出。

class ExpModelTunable(torch.nn.Module):
    def __init__(self):
        super(ExpModelTunable, self).__init__()
        self.alpha = torch.nn.Parameter( torch.tensor(1.0, requires_grad=True) )
        self.beta = torch.nn.Parameter( torch.tensor(1.0, requires_grad=True) )
    
    def forward(self, t):
        return self.alpha * torch.exp(  - self.beta * t ) 

def func_f(t, t_list):
  mu = torch.tensor(0.13191110355, requires_grad=True)
  running_sum = torch.sum( torch.tensor( [ f(t-ti) for ti in t_list ], requires_grad=True ) )
  return mu + running_sum

def pytorch_objective_tunable(u, t_list):
  global U
  steps = torch.linspace(t_list[-1].item(),u.item(),100, requires_grad=True)
  func_values = torch.tensor( [ func_f(steps[i], t_list) for i in range(len(steps)) ], requires_grad=True )
  return torch.log(U) + torch.trapz(func_values, steps)

def newton_method(function, func, initial, t_list, iteration=200, convergence=0.0001):
    for i in range(iteration): 
        previous_data = initial.clone()
        value = function(initial, t_list)
        initial.data -= (value / func(initial.item(), t_list)).data

        if torch.abs(initial - previous_data) < torch.tensor(convergence):
            return initial
    return initial # return our final after iteration

# call starts
f = ExpModelTunable()
U = torch.rand(1, requires_grad=True)
initial_x = torch.tensor([.1], requires_grad=True) 
t_list = torch.tensor([0.0], requires_grad=True)
result = newton_method(pytorch_objective_tunable, func_f, initial_x, t_list)
print("Next Arrival at ", result.item())

此打印,输出正确,这里一切正常:Next Arrival at 4.500311374664307。我的问题出现在这里:

loss = result - torch.tensor(1)
loss.backward()
print( result.grad )
for param in f.parameters():
    print(param.grad)

输出:

tensor([1.])
None #this should not be None
None #this should not be None

所以我们可以看到结果变量的梯度正在更新,但是模型 f's parameters' 梯度没有得到更新。我试图回顾所有的计算,所有的代码都在这里,并确保任何东西都有 requires_grad=True 但我仍然无法让它工作。这应该行得通吗?有人有任何提示吗?谢谢。

您的代码存在一些问题。您可以直接通过查看输出张量判断模型是否至少可以启动反向传播:

>>> result
tensor([...], requires_grad=True)

它没有 grad_fn,所以您已经知道它没有连接到图表。

现在调试问题,这里有一些提示:

  • 首先,如果您打算进行反向传播,则永远不要改变 .data 或使用 .item。这基本上会杀死图表!因为之后执行的任何操作都不会附加到图表。

  • 其实大多数时候你不需要使用requires_grad。请注意 nn.Parameter 默认情况下会将 requires_grad=True 分配给张量。

  • 在 PyTorch 管道中使用列表理解时,您可以将 list 包装成 torch.stack,这对于保持整洁非常有效.

  • 如果我是你,我不会使用全局...


这是更正后的版本:

class ExpModelTunable(nn.Module):
    def __init__(self):
        super(ExpModelTunable, self).__init__()
        self.alpha = nn.Parameter(torch.ones(1))
        self.beta = nn.Parameter(torch.ones(1))
    
    def forward(self, t):
        return self.alpha * torch.exp(-self.beta*t) 

f = ExpModelTunable()
def func_f(t, t_list):
    mu = torch.tensor(0.13191110355)
    running_sum = torch.stack([f(t-ti) for ti in t_list]).sum()
    return mu + running_sum

def pytorch_objective_tunable(u, t_list):
    global U
    steps = torch.linspace(t_list[-1].item(), u.item(), 100)
    func_values = torch.stack([func_f(steps[i], t_list) for i in range(len(steps))])
    return torch.log(U) + torch.trapz(func_values, steps)
    # return torch.trapz(func_values, steps)

def newton_method(function, func, initial, t_list, iteration=1, convergence=0.0001):
    for i in range(iteration): 
        previous_data = initial.clone()
        value = function(initial, t_list)
        initial -= (value / func(initial, t_list))

        if torch.abs(initial - previous_data) < torch.tensor(convergence):
            return initial
    return initial # return our final after iteration

U = torch.rand(1, requires_grad=True)
initial_x = torch.tensor([.1]) 
t_list = torch.tensor([0.0], requires_grad=True)
result = newton_method(pytorch_objective_tunable, func_f, initial_x, t_list)

现在注意 result 附加的 grad_fn:

>>> result
tensor([...], grad_fn=<SubBackward0>)