在 PyTorch 中,当为 GPU 张量分配新值时,GPU 内存会被释放吗?

Mol*_*eVX 5 python pytorch

当 PyTorch 中的 Cuda 变量被分配新值时,它再次成为 CPU 变量(如下面的代码所示)。那么这种情况下,之前GPU上的变量占用的内存是否会被自动释放呢?

import torch

t1 = torch.empty(4,5)

if torch.cuda.is_available():
  t1 = t1.cuda()

print(t1.is_cuda)

t1 = torch.empty(4,5)
print(t1.is_cuda)
Run Code Online (Sandbox Code Playgroud)

上述代码的输出是:

True
False
Run Code Online (Sandbox Code Playgroud)

jod*_*dag 7

在Python中,一旦没有剩余的引用,对象就会被释放。由于您分配t1引用一个全新的张量,因此不再引用原始 GPU 张量,因此该张量被释放。也就是说,当 PyTorch 被指示释放 GPU 张量时,它往往会缓存该 GPU 内存一段时间,因为通常情况下,如果我们使用过 GPU 内存一次,我们可能会想再次使用一些,并且 GPU 内存分配相对较慢。如果您想强制清除 GPU 内存缓存,可以使用torch.cuda.empty_cache. 使用此功能不会直接增加单个 PyTorch 实例中可用的 GPU 内存,因为 PyTorch 会自动调用它以尝试避免 GPU 内存不足错误。

重申一下,GPU 张量实际上并没有“变成”CPU 张量。在Python中,变量名是对对象的引用。你的代码真正做的是分配t1引用一个新的CPU张量对象。在内部,Python 计算每个对象的引用数量。当该计数变为零时,该对象将立即被释放。

警告(引用循环):在无法访问引用循环的情况下,引用计数会失败。当对象包含对另一个对象的引用但对循环中任何对象的引用均不可访问时,就会出现无法访问的引用循环。为了处理这个问题,Python 使用了一个间歇性执行的垃圾收集模块。该模块使用更复杂的算法来检测和释放属于无法访问的引用循环的对象。在这些情况下,当循环变得无法访问时,不一定会释放内存,而是在激活内部垃圾收集器后会释放内存。这是自动发生的并且相对不可预测。如果需要,可以使用 python 内置的垃圾收集接口来查询、配置或手动执行垃圾收集器gc

根据前面的讨论,如果您确实想确保在 PyTorch 中释放无法访问的 GPU 内存(即使在无法访问引用周期的情况下),您可以使用

import gc
gc.collect()
torch.cuda.empty_cache()
Run Code Online (Sandbox Code Playgroud)