使用量ゼロから:
_>>> import gc
>>> import GPUtil
>>> import torch
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 0% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
次に、十分に大きなテンソルを作成し、記憶を独占します。
_>>> x = torch.Rand(10000,300,200).cuda()
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
次に、テンソルが消えるかどうかを確認する方法をいくつか試しました。
試行1:切り離し、CPUに送信し、変数を上書き
いいえ、動作しません。
_>>> x = x.detach().cpu()
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
Attempt 2:変数を削除する
いいえ、これも機能しません
_>>> del x
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 26% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
Attempt 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% |
_
Attempt 4:ガベージコレクターをクリアします。
いいえ、5%はまだ消費されています
_>>> gc.collect()
0
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 5% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
Attempt 5:torch
を完全に削除してみてください(_del x
_が機能しなかったときに機能するように-_-)
いいえ、そうではありません... *
_>>> del torch
>>> GPUtil.showUtilization()
| ID | GPU | MEM |
------------------
| 0 | 0% | 5% |
| 1 | 0% | 0% |
| 2 | 0% | 0% |
| 3 | 0% | 0% |
_
そして、私はgc.get_objects()
を確認しようとしましたが、内部にはまだ奇妙なTHCTensor
の要素がたくさんあるようです...
キャッシュをクリアした後も、なぜメモリがまだ使用されているのでしょうか?
テンソルがない場合でも、PyTorchのキャッシングアロケーターが一定量のメモリを予約しているように見え、この割り当ては最初のCUDAメモリアクセスによってトリガーされます(torch.cuda.empty_cache()
は未使用のテンソルをキャッシュから削除しますが、キャッシュ自体はまだです一部のメモリを使用します)。
小さな1要素のテンソルを使用しても、del
とtorch.cuda.empty_cache()
の後に、GPUtil.showUtilization(all=True)
は、巨大なテンソル(および両方のtorch.cuda.memory_cached()
およびtorch.cuda.memory_allocated()
はゼロを返します)。
PyTorchのドキュメントには、かなり関連性があるように見える部分があります。
https://pytorch.org/docs/stable/notes/cuda.html#memory-management
メモリ管理
PyTorchは、キャッシュメモリアロケーターを使用してメモリ割り当てを高速化します。これにより、デバイスを同期せずに高速でメモリの割り当てを解除できます。ただし、アロケータが管理する未使用のメモリは、nvidia-smiで使用されているかのように表示されます。 memory_allocated()およびmax_memory_allocated()を使用して、テンソルによって占有されているメモリを監視し、memory_cached()およびmax_memory_cached()を使用して、キャッシングアロケータによって管理されているメモリを監視できます。 empty_cache()を呼び出すと、すべての未使用のキャッシュメモリがPyTorchから解放され、他のGPUアプリケーションで使用できるようになります。ただし、テンソルによって占有されているGPUメモリは解放されないため、PyTorchで使用できるGPUメモリの量を増やすことはできません。
nvidia-smiについて言及している部分を太字にしました。私の知る限り、これはGPUtilで使用されています。