我需要多次通过我的神经网络进行反向传播,所以我设置了backward(retain_graph=True).
然而,这导致
运行时错误:CUDA 内存不足
我不明白这是为什么。
变量或权重的数量是否翻了一番?无论backward()调用多少次,使用的内存量不应该保持不变吗?
小智 5
问题的根源:
你是对的,无论我们调用后向函数多少次,理论上内存都不应该增加。
然而,您的问题不是因为反向传播,而是因为您在调用向后函数时设置为 true 的 retain_graph 变量。
当您通过传递一组输入数据来运行您的网络时,您将调用 forward 函数,该函数将创建一个“计算图”。计算图包含网络执行的所有操作。
然后,当您调用后向函数时,保存的计算图将“基本上”向后运行,以了解应该在哪个方向(所谓的梯度)调整哪个权重。因此PyTorch 将计算图保存在内存中,以便调用后向函数。
在调用后向函数并计算梯度后,我们从内存中释放图形,如文档https://pytorch.org/docs/stable/autograd.html 中所述:
retain_graph (bool, optional) – 如果为 False,则用于计算 grad 的图将被释放。请注意,几乎在所有情况下都不需要将此选项设置为 True,并且通常可以以更有效的方式解决。默认为 create_graph 的值。
然后通常在训练期间我们将梯度应用于网络以最小化损失,然后我们重新运行网络,因此我们创建一个新的计算图。然而,我们同时在内存中只有一张图。
问题 :
如果您在调用后向函数时将 retain_graph 设置为 true,您将在内存中保留网络之前所有运行的计算图。
因为在每次运行网络时,你都会创建一个新的计算图,如果你将它们全部存储在内存中,你可能并且最终会耗尽内存。
在网络的第一次迭代和运行中,内存中将只有一个图。然而,在第 10 次运行网络时,您的内存中有 10 个图。在第 10000 次运行时,您的内存中有 10000 个。它是不可持续的,为什么在文档中不推荐它是可以理解的。
因此,即使看起来问题是反向传播,它实际上是计算图的存储,并且由于我们通常在每次迭代或网络运行时调用一次前向和后向函数,因此混淆是可以理解的。
解决方案 :
您需要做的是找到一种无需使用 retain_graph即可使您的网络和架构正常工作的方法。使用它几乎不可能训练你的网络,因为每次迭代都会增加你的内存使用量并降低训练速度,在你的情况下,甚至会导致你耗尽内存。
你没有提到为什么你需要多次反向传播,但很少需要它,我不知道它不能“解决”的情况。例如,如果您需要访问先前运行的变量或权重,您可以将它们保存在变量中,然后再访问它们,而不是尝试进行新的反向传播。
由于另一个原因,您可能需要多次反向传播,但相信我一直处于这种情况下,可能有一种方法可以在不存储以前的计算图的情况下完成您想要做的事情。
如果您想分享为什么需要多次反向传播,也许其他人和我可以为您提供更多帮助。
有关落后过程的更多信息:
如果您想了解更多关于反向过程的信息,它被称为“雅可比向量积”。它有点复杂,由 PyTorch 处理。我还没有完全理解它,但是这个资源似乎是一个很好的起点,因为它似乎没有 PyTorch 文档(在代数方面)那么令人生畏:https ://mc.ai/how-pytorch-backward-function-作品/