3_lx 2023-04-06 09:51 采纳率: 75%
浏览 39
已结题

loss.backward()反向传播问题

batch_data = batches[t]
        # 获取批量数据的预测结果
        _,pred_traj,y_traj,pred_intent,_,_ = get_prediction_on_batch(batch_data, model, device)

        # None的作用主要是在使用None的位置新增一个维度
        traj_preds.append(pred_traj[0].detach()[None])
        # 当我们再训练网络的时候可能希望保持一部分的网络参数不变,只对其中一部分的参数进行调整;
        # 或者只训练部分分支网络,并不让其梯度对主网络的梯度造成影响,这时候我们就需要使用detach()函数来切断一些分支的反向传播
        # 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置, 不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。
        # 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
        # 这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播
        # 使用detach返回的tensor和原始的tensor共同一个内存,即一个修改另一个也会跟着改变。
        intent_preds.append(pred_intent[0].detach()[None])

        temp_pred_list += [pred_traj]
        temp_label_list += [y_traj]
        temp_data_list += [batch_data]
        if len(temp_pred_list) > adapt_step:
            # maintains a buffer of length adapt_step containing the past adapt_step measurements for supervised adaptation
            temp_pred_list = temp_pred_list[1:]
            temp_label_list = temp_label_list[1:]
            temp_data_list = temp_data_list[1:]

        if t < adapt_step - 1:
            continue
        # temp_label_list1 = temp_label_list[0].detach()
        # temp_pred_list1 = temp_pred_list[0].detach()
        Y = temp_label_list[0]
        Y_hat = temp_pred_list[0]
        # detach()将数据的处理设备从其他设备(如.cuda()拿到cpu上),不会改变变量类型,转换后仍然是Tensor变量。
        full_loss = (Y - Y_hat).detach().pow(2).mean().cpu().numpy().round(6)  # 整体的损失值
        cost_list.append(full_loss)
        # torch.contiguous()方法首先拷贝了一份张量在内存中的地址,然后将地址按照形状改变后的张量的语义进行排列。
        # 如果想要断开这两个变量之间的依赖(x本身是contiguous的),就要使用contiguous()针对x进行变化,感觉上就是我们认为的深拷贝。
        #  当调用contiguous()时,会强制拷贝一份tensor,让它的布局和从头创建的一模一样,但是两个tensor完全没有联系。
        Y_tau = Y[:, :adapt_step].contiguous().view((-1, 1))
        # touch.view()方法对张量改变“形状”其实并没有改变张量在内存中真正的形状,可以理解为:
        # view方法没有拷贝新的张量,没有开辟新内存,与原张量共享内存;
        # view方法只是重新定义了访问张量的规则,使得取出的张量按照我们希望的形状展现。
        Y_hat_tau = Y_hat[:, :adapt_step].contiguous().view((-1, 1))  # 部分数据的损失值
        err = (Y_tau - Y_hat_tau).detach()
        curr_cost = err.pow(2).mean().cpu().numpy()
        update_epoch = 1

        # IPython.embed()
        # κt = 1, If jt < ξ1
        #      2, If ξ1 ≤ jt < ξ2
        #      0, If jt ≥ ξ2
        if multiepoch_thresh[0] <= 0 <= multiepoch_thresh[1]:
            if curr_cost < multiepoch_thresh[0]:
                update_epoch = 1
            elif curr_cost < multiepoch_thresh[1]:
                update_epoch = 2
            else:
                update_epoch = 0
        cnt[update_epoch] += 1
        for cycle in range(update_epoch):
            def mekf_closure(index=0):
                # mekf闭包 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
                # optimizer.zero_grad()清除了优化器中所有的x的x.grad,
                # 在每次loss.backward()之前,不要忘记使用,否则之前的梯度将会累积,这通常不是我们所期望的
                optimizer.zero_grad()
                # optimizer.state 参数的缓存,需要用到什么参数就缓存到这个地方
                dim_out = optimizer.optimizer.state['dim_out'] if 'Lookahead' in optim_name else optimizer.state['dim_out']
                retain = index < dim_out - 1
                Y_hat_tau[index].backward(retain_graph=retain)  # 反向传播
                return err

            def lbfgs_closure():
                optimizer.zero_grad()
                temp_data = temp_data_list[0]
                _, temp_pred_traj, temp_y_traj, _, _, _ = get_prediction_on_batch(temp_data, model, device)
                y_tau = temp_y_traj[:, :adapt_step].contiguous().view((-1, 1))
                y_hat_tau = temp_pred_traj[:, :adapt_step].contiguous().view((-1, 1))
                loss = (y_tau - y_hat_tau).pow(2).mean()
                loss.backward()
                return loss

            if 'MEKF' in optim_name:
                # step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。
                # 因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度
                optimizer.step(mekf_closure)  # 将函数作为参数传入
            elif 'LBFGS' in optim_name:
                optimizer.step(lbfgs_closure)
            else:
                torch.autograd.set_detect_anomaly(True)
                loss = (Y_tau - Y_hat_tau).pow(2).mean()
                loss.backward()
                optimizer.step()

在运行else部分代码时,出现以下错误:
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [64, 100]], which is output 0 of AsStridedBackward0, is at version 2; expected version 1 instead.
网上找了很多方法都无法解决,希望各位能给予解决办法,谢谢

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-04-06 19:05
    关注
    不知道你这个问题是否已经解决, 如果还没有解决的话:
    • 这篇博客: RuntimeError: one of the variables needed for gradient computation has been modified by an inplace o中的 其他 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

      查看出问题的地方,会提示

       Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).
      

      这个用于定位挺好用的,但对于复杂的计算图,可能这个的放置位置我还没有细致的研究过。使用方法见下面的操作实例

      import torch
      
      with torch.autograd.set_detect_anomaly(True): #就是这句话
          a = torch.rand(1, requires_grad=True)
          c = torch.rand(1, requires_grad=True)
          
          b = a ** 2 * c ** 2
          b += 1
          b *= c + a
      
          d = b.exp_()
          d *= 5
      
          b.backward()
      

      输出如下

      sys:1: RuntimeWarning: Traceback of forward call that caused the error:
        File "tst.py", line 13, in <module>
          d = b.exp_()
      
      Traceback (most recent call last):
        File "tst.py", line 16, in <module>
          b.backward()
        File "/Users/fmassa/anaconda3/lib/python3.6/site-packages/torch/tensor.py", line 102, in backward
          torch.autograd.backward(self, gradient, retain_graph, create_graph)
        File "/Users/fmassa/anaconda3/lib/python3.6/site-packages/torch/autograd/__init__.py", line 93, in backward
          allow_unreachable=True)  # allow_unreachable flag
      RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
      

      从这里可以看出是 d = b.exp_() 出了问题,修改为d = b.exp(),即可解决

      详情见

      文献五

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月21日
  • 已采纳回答 4月13日
  • 创建了问题 4月6日

悬赏问题

  • ¥15 Delphi DBGrid弹出菜单问题
  • ¥15 java map类型数据格式,如何快速通过前缀匹配元素
  • ¥15 stc12c5a60s2、QMC5883L、LCD1602组合测量磁场所需程序
  • ¥15 vba参数转c++ SAFEARRAY
  • ¥20 Win11测试yolov4,“找不到nvcuda.dll”怎么办?
  • ¥15 simulink绘制bode图
  • ¥15 php_network_getaddresses: getaddrinfo failed: Name or service not known
  • ¥15 用msg发消息出现的问题
  • ¥15 unity3d机械臂
  • ¥20 判断两个表是否完全相同