alv*_*vas 9 python garbage-collection memory-leaks gpu pytorch
从零使用开始:
>>> import gc
>>> import GPUtil
>>> import torch
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 0% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
然后创建一个足够大的张量并占用内存:
>>> x = torch.rand(10000,300,200).cuda()
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
然后我尝试了几种方法来查看张量是否消失。
尝试1:分离,发送到CPU并覆盖变量
不,不行。
>>> x = x.detach().cpu()
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
尝试2:删除变量
不,这也不起作用
>>> del x
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
尝试3:使用torch.cuda.empty_cache()
功能
似乎有效,但似乎还有一些挥之不去的开销...
>>> torch.cuda.empty_cache()
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 5% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
尝试4:也许清除垃圾收集器。
否,仍需5%
>>> gc.collect()
0
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 5% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
尝试5:尝试torch
完全删除(好像在del x
不工作时可以正常工作-_-)
不,不是... *
>>> del torch
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 5% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
Run Code Online (Sandbox Code Playgroud)
然后我试图检查一下gc.get_objects()
,看来里面还有很多奇怪的THCTensor
东西……
知道为什么清除缓存后内存仍在使用吗?
Sta*_*czo 16
来自PyTorch 文档:
内存管理
PyTorch 使用缓存内存分配器来加速内存分配。这允许快速内存释放而无需设备同步。但是,分配器管理的未使用内存仍将显示为在 nvidia-smi 中使用。您可以使用
memory_allocated()
和max_memory_allocated()
来监视张量占用的内存,并使用memory_cached()
和 来max_memory_cached()
监视缓存分配器管理的内存。调用empty_cache()
会释放 PyTorch 中所有未使用的缓存内存,以便其他 GPU 应用程序可以使用这些内存。但是,张量占用的 GPU 内存不会被释放,因此无法增加 PyTorch 可用的 GPU 内存量。
我将提到nvidia-smi 的部分加粗,据我所知,GPUtil 使用它。
小智 9
感谢分享!我遇到了同样的问题,我用你的例子来调试。基本上,我的发现是:
下面是一些重现实验的代码:
import gc
import torch
def _get_less_used_gpu():
from torch import cuda
cur_allocated_mem = {}
cur_cached_mem = {}
max_allocated_mem = {}
max_cached_mem = {}
for i in range(cuda.device_count()):
cur_allocated_mem[i] = cuda.memory_allocated(i)
cur_cached_mem[i] = cuda.memory_reserved(i)
max_allocated_mem[i] = cuda.max_memory_allocated(i)
max_cached_mem[i] = cuda.max_memory_reserved(i)
print(cur_allocated_mem)
print(cur_cached_mem)
print(max_allocated_mem)
print(max_cached_mem)
min_all = min(cur_allocated_mem, key=cur_allocated_mem.get)
print(min_all)
return min_all
x = torch.rand(10000,300,200, device=0)
# see memory usage
_get_less_used_gpu()
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: 3416MiB
# try delete with empty_cache()
torch.cuda.empty_cache()
_get_less_used_gpu()
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: 3416MiB
# try delete with gc.collect()
gc.collect()
_get_less_used_gpu()
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: 3416MiB
# try del + gc.collect()
del x
gc.collect()
_get_less_used_gpu()
>{0: **0**, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: 3416MiB
# try empty_cache() after deleting
torch.cuda.empty_cache()
_get_less_used_gpu()
>{0: 0, 1: 0, 2: 0, 3: 0}
>{0: **0**, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: **1126MiB**
# re-create obj and try del + empty_cache()
x = torch.rand(10000,300,200, device=0)
del x
torch.cuda.empty_cache()
_get_less_used_gpu()
>{0: **0**, 1: 0, 2: 0, 3: 0}
>{0: **0**, 1: 0, 2: 0, 3: 0}
>{0: 2400000000, 1: 0, 2: 0, 3: 0}
>{0: 2401239040, 1: 0, 2: 0, 3: 0}
> *nvidia-smi*: **1126MiB**
Run Code Online (Sandbox Code Playgroud)
尽管如此,这种方法仅适用于人们确切知道哪些变量保存着记忆的情况……我想,当人们训练深度学习模式时,情况并非总是如此,尤其是在使用第三方库时。
看起来PyTorch的缓存分配器即使没有张量也保留一些固定数量的内存,并且此分配是由第一次CUDA内存访问触发的(torch.cuda.empty_cache()
从缓存中删除未使用的张量,但缓存本身仍使用一些内存)。
即使有微小的1张量元素,后del
和torch.cuda.empty_cache()
,GPUtil.showUtilization(all=True)
报告作为用于一个巨大的张量GPU存储器的量是相同的(并且两个torch.cuda.memory_cached()
和torch.cuda.memory_allocated()
返回零)。
归档时间: |
|
查看次数: |
570 次 |
最近记录: |