关于Trying to backward through the graph a second time, but the saved intermediate 的问题

目录

问题描述

出现此问题的原因

解决的办法

方法一、

方法二、(这篇文章的重点)


问题描述

Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling .backward() or autograd.grad() the first time.

出现此问题的原因

关于Trying to backward through the graph a second time, but the saved intermediate 的问题_第1张图片

 举例来说,假如上图所示,你的模型中包含多个组成部分,比如生成对抗网络这种的或者其它。

你的训练过程是

步骤1、根据 loss1 更新 module1

步骤2、根据loss2 更新 module2

 这时,在更新过程中你的代码可能是如下这样

loss_1 = Loss1(module1(data1), Label1)
module1.zero_grad()
loss_1.backward()
optimizer1.step()  # 假如这个是module1的优化器

loss_2 = Loss2(module(data2), Label2)
module2.zero_grad()
loss_2.backward()
optimizer2.step()  # 假如是module2的优化器

========================================================================

Oh,shit,他竟然报错了。然后你开始上网查原因,什么backward()里面加 retain_graph=True 之类。兴致勃勃地去试了,发现没什么用。(+_+)?  (←此时你的表情)。

最终你无奈的面无表情的点进了这篇文章。

========================================================================

根据翻译,知道了其中有个东西想被用了两次,但是这东西不见了。

这个被用来两次的东西就是图中的module1的梯度!!!从图中可以看到,module1经过了两次反向传播的梯度流,如红色和蓝色所示。但是在经历步骤1完成后,module1的哪个东西被释放掉了。

但你可能会问:更新module2和module1有什么关系?为什么还要用module1的那个东西呢?

问得好!(●'◡'●)这就是问题的关键所在。

从图中可以看到,module2的输入数据data2可是由module1生成的。所以,在计算loss时框生成的计算图是把module1包含在内的。这就导致module2的梯度反向传播流一直从结尾回传到开头,所以必经module1。

综上,造成了矛盾,步骤1后那个东西没了,但module2的反向传播想用。

解决的办法

方法一、

在步骤1时保留那个东西。即步骤1的

loss_1.backward( retain_graph=True)

这个有时候不行,我不知道为什么。

方法二、(这篇文章的重点)

使步骤2时的反向梯度流在module2的输入处截断,也就是在步骤2时不去使用module1的那个东西了。如图中的金色箭头所示。这种方法最妥当。步骤1理论上可以解决,但是造成了算力上的浪费。

具体操作

loss_2 = Loss2(module(data2.detach()), Label2)

在 data2后面加 detach()。截断反向传播梯度流。


========================================================================
我猜你们跑通了。然后给我点个赞(lll¬ω¬)。哈哈哈哈,我不吃牛肉

关于Trying to backward through the graph a second time, but the saved intermediate 的问题_第2张图片

你可能感兴趣的:(深度学习,python)