Python 为什么向后设置(retain_graph=True)会占用大量GPU内存?

Python 为什么向后设置(retain_graph=True)会占用大量GPU内存?,python,pytorch,Python,Pytorch,我需要通过我的神经网络多次反向传播,所以我将backwardretain\u graph设置为True 然而,这导致了 运行时错误:CUDA内存不足 我不明白这是为什么 变量或权重的数量是否增加了一倍?不管向后调用了多少次,使用的内存量不应该保持不变吗?问题的根源是: 你是对的,无论我们调用向后函数多少次,记忆都不应该在理论上增加 然而,您的问题不是因为反向传播,而是在调用backward函数时设置为true的retain_graph变量 当通过传递一组输入数据来运行网络时,调用forward函

我需要通过我的神经网络多次反向传播,所以我将backwardretain\u graph设置为True

然而,这导致了

运行时错误:CUDA内存不足

我不明白这是为什么

变量或权重的数量是否增加了一倍?不管向后调用了多少次,使用的内存量不应该保持不变吗?

问题的根源是:

你是对的,无论我们调用向后函数多少次,记忆都不应该在理论上增加

然而,您的问题不是因为反向传播,而是在调用backward函数时设置为true的retain_graph变量

当通过传递一组输入数据来运行网络时,调用forward函数,该函数将创建一个计算图。 计算图包含网络已执行的所有操作

然后,当您调用backward函数时,保存的计算图基本上会向后运行,以了解应该在哪个方向上调整哪些权重,即所谓的梯度。 因此,PyTorch将计算图保存在内存中,以便调用backward函数

调用后向函数并计算梯度后,我们从内存中释放图形,如文档中所述:

retain_graph bool,可选–如果为False,用于计算梯度的图形将被释放。请注意,在几乎所有情况下,都不需要将此选项设置为True,而且通常可以以更有效的方式进行处理。默认为create_graph的值

然后,通常在训练期间,我们将梯度应用于网络,以最小化损失,然后重新运行网络,因此我们创建一个新的计算图。然而,我们同时只有一个图形在内存中

问题是:

如果在调用backward函数时将retain_graph设置为true,则将在内存中保留网络以前所有运行的计算图

因为在网络的每一次运行中,你都会创建一个新的计算图,如果你把它们都存储在内存中,你可以而且最终会耗尽内存

在网络的第一次迭代和运行中,内存中只有一个图形。然而,在网络的第10次运行中,内存中有10个图形。在第10000次运行时,内存中有10000个。这是不可持续的,文件中不推荐的原因是可以理解的

因此,即使问题看起来是反向传播,实际上是计算图的存储,而且由于我们通常在每次迭代或网络运行时调用一次向前和向后函数,因此造成混淆是可以理解的

解决方案:

您需要做的是找到一种方法,使您的网络和体系结构在不使用保留图的情况下工作。使用它几乎不可能训练你的人际网络,因为每次迭代都会增加你的内存使用,降低训练速度,甚至会导致你的内存不足

您没有提到为什么需要多次反向传播,但很少需要,我也不知道有哪种情况下无法解决。例如,如果您需要访问以前运行的变量或权重,您可以将它们保存在变量中,然后再访问它们,而不是尝试执行新的反向传播

由于另一个原因,您可能需要多次反向传播,但我相信,在这种情况下,可能有一种方法可以在不存储以前的计算图的情况下完成您尝试执行的操作

如果你想分享为什么你需要多次反向传播,也许其他人和我可以帮你更多

有关反向过程的更多信息:

如果你想了解更多关于反向过程的知识,它被称为雅可比矢量积。它有点复杂,由PyTorch处理。我还没有完全理解它,但这一资源似乎是一个很好的起点,因为它似乎没有PyTorch文档在代数方面那么可怕:

问题的根源:

你是对的,无论我们调用向后函数多少次,记忆都不应该在理论上增加

然而,您的问题不是因为反向传播,而是在调用backward函数时设置为true的retain_graph变量

当通过传递一组输入数据来运行网络时,调用forward函数,该函数将创建一个计算图。 计算图包含网络已执行的所有操作

然后,当您调用backward函数时,保存的计算图基本上会向后运行,以了解应该在哪个方向上调整哪些权重,即所谓的梯度。 因此Pytork正在内存中保存计算图 h以调用向后函数

调用后向函数并计算梯度后,我们从内存中释放图形,如文档中所述:

retain_graph bool,可选–如果为False,用于计算梯度的图形将被释放。请注意,在几乎所有情况下,都不需要将此选项设置为True,而且通常可以以更有效的方式进行处理。默认为create_graph的值

然后,通常在训练期间,我们将梯度应用于网络,以最小化损失,然后重新运行网络,因此我们创建一个新的计算图。然而,我们同时只有一个图形在内存中

问题是:

如果在调用backward函数时将retain_graph设置为true,则将在内存中保留网络以前所有运行的计算图

因为在网络的每一次运行中,你都会创建一个新的计算图,如果你把它们都存储在内存中,你可以而且最终会耗尽内存

在网络的第一次迭代和运行中,内存中只有一个图形。然而,在网络的第10次运行中,内存中有10个图形。在第10000次运行时,内存中有10000个。这是不可持续的,文件中不推荐的原因是可以理解的

因此,即使问题看起来是反向传播,实际上是计算图的存储,而且由于我们通常在每次迭代或网络运行时调用一次向前和向后函数,因此造成混淆是可以理解的

解决方案:

您需要做的是找到一种方法,使您的网络和体系结构在不使用保留图的情况下工作。使用它几乎不可能训练你的人际网络,因为每次迭代都会增加你的内存使用,降低训练速度,甚至会导致你的内存不足

您没有提到为什么需要多次反向传播,但很少需要,我也不知道有哪种情况下无法解决。例如,如果您需要访问以前运行的变量或权重,您可以将它们保存在变量中,然后再访问它们,而不是尝试执行新的反向传播

由于另一个原因,您可能需要多次反向传播,但我相信,在这种情况下,可能有一种方法可以在不存储以前的计算图的情况下完成您尝试执行的操作

如果你想分享为什么你需要多次反向传播,也许其他人和我可以帮你更多

有关反向过程的更多信息:

如果你想了解更多关于反向过程的知识,它被称为雅可比矢量积。它有点复杂,由PyTorch处理。我还没有完全理解它,但这一资源似乎是一个很好的起点,因为它似乎没有PyTorch文档在代数方面那么可怕: