Pytorch RuntimeError:张量的元素 0 不需要 grad 并且没有 grad_fn

Posted

技术标签:

【中文标题】Pytorch RuntimeError:张量的元素 0 不需要 grad 并且没有 grad_fn【英文标题】:Pytorch RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn 【发布时间】:2020-08-31 16:08:49 【问题描述】:

此代码构建如下:我的机器人拍照,一些 tf 计算机视觉模型计算目标对象在图片中的位置开始。此信息(x1 和 x2 坐标)被传递给 pytorch 模型。它应该学会预测正确的运动激活,以便更接近目标。运动完成后,机器人再次拍照,tf cv 模型应计算电机激活是否使机器人更接近所需状态(x1 在 10,x2 坐标在 at31)

但是每次我运行代码 pytorch 都无法计算梯度。

我想知道这是一些数据类型问题还是更一般的问题:如果不直接从 pytorch 网络的输出计算损失,是否无法计算梯度?

我们将不胜感激任何帮助和建议。

#define policy model (model to learn a policy for my robot)
import torch
import torch.nn as nn
import torch.nn.functional as F 
class policy_gradient_model(nn.Module):
    def __init__(self):
        super(policy_gradient_model, self).__init__()
        self.fc0 = nn.Linear(2, 2)
        self.fc1 = nn.Linear(2, 32)
        self.fc2 = nn.Linear(32, 64)
        self.fc3 = nn.Linear(64,32)
        self.fc4 = nn.Linear(32,32)
        self.fc5 = nn.Linear(32, 2)
    def forward(self,x):
        x = self.fc0(x)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = F.relu(self.fc4(x))
        x = F.relu(self.fc5(x))
        return x

policy_model = policy_gradient_model().double()
print(policy_model)
optimizer = torch.optim.AdamW(policy_model.parameters(), lr=0.005, betas=(0.9,0.999), eps=1e-08, weight_decay=0.01, amsgrad=False)

#make robot move as predicted by pytorch network (not all code included)
def move(motor_controls):
#define curvature
 #   motor_controls[0] = sigmoid(motor_controls[0])
    activation_left = 1+(motor_controls[0])*99
    activation_right = 1+(1- motor_controls[0])*99

    print("activation left:", activation_left, ". activation right:",activation_right, ". time:", motor_controls[1]*100)

#start movement

#main
import cv2
import numpy as np
import time
from torch.autograd import Variable
print("start training")
losses=[]
losses_end_of_epoch=[]
number_of_steps_each_epoch=[]
loss_function = nn.MSELoss(reduction='mean')

#each epoch
for epoch in range(2):
    count=0
    target_reached=False
    while target_reached==False:
        print("epoch: ", epoch, ". step:", count)
###process and take picture
        indices = process_picture()
###binary_network(sliced)=indices as input for policy model
        optimizer.zero_grad()
###output: 1 for curvature, 1 for duration of movement
        motor_controls = policy_model(Variable(torch.from_numpy(indices))).detach().numpy()
        print("NO TANH output for motor: 1)activation left, 2)time ", motor_controls)
        motor_controls[0] = np.tanh(motor_controls[0])
        motor_controls[1] = np.tanh(motor_controls[1])
        print("TANH output for motor: 1)activation left, 2)time ", motor_controls)
###execute suggested action
        move(motor_controls)
###take and process picture2 (after movement)
        indices = (process_picture())
###loss=(binary_network(picture2) - desired
        print("calculate loss")
        print("idx", indices, type(torch.tensor(indices)))
     #   loss = 0
      #  loss = (indices[0]-10)**2+(indices[1]-31)**2
       # loss = loss/2
        print("shape of indices", indices.shape)
        array=np.zeros((1,2))
        array[0]=indices
        print(array.shape, type(array))
        array2 = torch.ones([1,2])
        loss = loss_function(torch.tensor(array).double(), torch.tensor([[10.0,31.0]]).double()).float()
        print("loss: ", loss, type(loss), loss.shape)
       # array2[0] = loss_function(torch.tensor(array).double(), 
        torch.tensor([[10.0,31.0]]).double()).float()
        losses.append(loss)
#start line causing the error-message (still part of main)
###calculate gradients
        loss.backward()
#end line causing the error-message (still part of main)

###apply gradients        
        optimizer.step()

#Output (so far as intented) (not all included)

#calculate loss
idx [14. 15.] <class 'torch.Tensor'>
shape of indices (2,)
(1, 2) <class 'numpy.ndarray'>
loss:  tensor(136.) <class 'torch.Tensor'> torch.Size([])

#Error Message:
Traceback (most recent call last):
  File "/home/pi/Desktop/GradientPolicyLearning/PolicyModel.py", line 259, in <module>
    array2.backward()
  File "/home/pi/.local/lib/python3.7/site-packages/torch/tensor.py", line 134, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/pi/.local/lib/python3.7/site-packages/torch/autograd/__init__.py", line 99, in 
 backward
    allow_unreachable=True)  # allow_unreachable flag
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

【问题讨论】:

【参考方案1】:

如果您在预测中调用.detach(),则会删除渐变。由于您首先从模型中获取索引,然后尝试反向支持错误,因此我建议

prediction = policy_model(torch.from_numpy(indices))
motor_controls = prediction.clone().detach().numpy()

这将使预测与可以反向传播的计算梯度保持原样。 现在你可以做

loss = loss_function(prediction, torch.tensor([[10.0,31.0]]).double()).float()

注意,如果它抛出错误,你可能想要调用 double 的预测。

【讨论】:

感谢您的回答!所以你不认为我只在“移动机器人并推断出(新状态-期望状态)”之后而不是直接从网络的输出中计算误差会是一个问题吗? 等等,我刚刚纠正了代码中的错误,即损失中的一个张量应该具有梯度,以便损失具有可以反向传播的梯度。我还没有研究 RL,因此我不知道策略梯度是如何实现的。如果我在这方面误导了你,我很抱歉 别担心。任何帮助表示赞赏:) 我可以试试你的建议,但不幸的是它没有帮助。而不是你建议的“loss = loss_function(prediction, torch.tensor([[10.0,31.0]]).double()).float()” 我使用“loss = loss_function(torch.from_numpy(indices).double (), torch.tensor([[15.0,26.0]]).double()).float()" 因为我不想直接奖励输出,但我想奖励网络输出(转换为电机)的效果激活)具有网络状态。基本上我仍然收到以下错误: RuntimeError: element 0 of tensors does not require grad and doesn't have a grad_fn 正如我所说,为了让反向传播发挥作用,损失函数应该接受一个带有梯度的参数。基本上,模型输出到其效果的转换必须是一个作用于模型输出以保存梯度的函数。这就是为什么我说我不知道​​策略梯度是如何做到这一点的。【参考方案2】:

如果不直接从 PyTorch 网络的输出计算损失,确实不可能计算梯度,因为那样你将无法应用用于优化梯度的链式法则。

【讨论】:

感谢您的快速回复!我很难理解错误是如何回溯以改变权重的。对网络来说,错误的大小不应该是重要的,而不是它是如何计算的或它到底是由什么引起的吗?我的意思是不是我也可以编写自己的损失函数。那么 Pytorch/TF 应该如何知道计算出的误差/损失如何与输入和网络的权重相关联?

以上是关于Pytorch RuntimeError:张量的元素 0 不需要 grad 并且没有 grad_fn的主要内容,如果未能解决你的问题,请参考以下文章

RuntimeError:张量 a (4000) 的大小必须与非单维 1 的张量 b (512) 的大小相匹配

如何在pytorch中连接两个不同尺寸的张量

如何修复pytorch中的“输入和隐藏张量不在同一设备上”

上一批Pytorch损失函数错误

如何根据 Pytorch 中列表的值定义掩码函数

pytorch 笔记 torch.roll