我需要通过神经网络多次反向传播,因此我设置了backward(retain_graph=True)
。
但是,这是导致
RuntimeError:CUDA内存不足
我不明白为什么会这样。
变量或权重的数量是否加倍?无论调用backward()
多少次,使用的内存量都应该保持不变吗?
答案 0 :(得分:1)
问题来源:
您是对的,无论我们调用多少次向后函数,内存在理论上都不应增加。
但是,您的问题不是由于反向传播,而是由于您在调用向后函数时将其设置为true的keep_graph变量。
当通过传递一组输入数据来运行网络时,将调用forward函数,该函数将创建一个“计算图”。 计算图包含您的网络已执行的所有操作。
然后,当您调用向后函数时,保存的计算图将“基本”向后运行,以了解应在哪个方向(称为梯度)上调整哪个权重。 因此 PyTorch将计算图保存在内存中,以便调用向后函数。
在调用了向后函数并计算了梯度之后,如doc https://pytorch.org/docs/stable/autograd.html中所述,我们从内存中释放了图形:
retain_graph(布尔型,可选)–如果为False,将释放用于计算grad的图形。请注意,几乎在所有情况下都不需要将此选项设置为True,并且通常可以以更有效的方式解决它。默认值为create_graph的值。
然后通常在训练过程中,将梯度应用于网络以最大程度地减少损失,然后重新运行网络,然后创建一个新的计算图。但是我们同时只有一个图形。
问题:
如果在调用向后函数时将keep_graph设置为true,则将网络的所有先前运行的计算图保留在内存中。
由于在网络的每次运行中,您都会创建一个新的计算图,因此,如果将它们全部存储在内存中,则可能会并最终用光内存。
在网络的第一次迭代和运行中,内存中将只有一个图。然而,在网络的第10次运行中,您的内存中有10个图形。在第10000次运行时,您的内存为10000。这是不可持续的,并且为什么在文档中不推荐使用也是可以理解的。
因此,即使问题似乎是反向传播,也实际上是计算图的存储,并且由于我们通常在每次迭代或网络运行时都调用一次正向和反向函数,因此可以理解。
解决方案:
您需要做的是找到一种方法,使您的网络和体系结构无需使用keep_graph 。使用它几乎使您无法训练网络,因为每次迭代都会增加内存的使用率,并降低训练速度,在您的情况下,甚至会导致内存不足。
您没有提到为什么需要多次反向传播,但是很少需要反向传播,而且我不知道无法进行“反向传播”的情况。例如,如果您需要访问以前运行的变量或权重,则可以将它们保存在变量中,以后再访问它们,而不用尝试进行新的反向传播。
由于其他原因,您可能需要多次反向传播,但是请相信,就像我在这种情况下一样,很可能有一种方法可以完成您尝试做的事情而无需存储以前的计算图。
如果您想分享为什么需要多次反向传播,也许其他人也可以,我可以为您提供更多帮助。
有关后退过程的更多信息:
如果您想了解有关反向过程的更多信息,则称为“雅各比向量积”。它有点复杂,由PyTorch处理。我尚未完全理解它,但是此资源似乎很好,因为它似乎比PyTorch文档(就代数而言)更没有威胁性:https://mc.ai/how-pytorch-backward-function-works/