ホームページ >バックエンド開発 >Python チュートリアル >コンテキスト デコレータを使用した Pytorch のメモリ リーク問題のデバッグ

コンテキスト デコレータを使用した Pytorch のメモリ リーク問題のデバッグ

王林
王林転載
2023-04-10 11:31:071520ブラウズ

デコレーターは、Python コンテキスト マネージャーの特定の実装です。この記事では、pytorch GPU デバッグの例を通じてそれらの使用方法を説明します。すべての状況で機能するとは限りませんが、非常に便利であることがわかりました。

コンテキスト デコレータを使用した Pytorch のメモリ リーク問題のデバッグ

メモリ リークの問題のデバッグ

メモリ リークをデバッグするには、さまざまな方法があります。この記事では、コード内で問題のある行を特定するための便利な方法を紹介します。この方法は、特定の場所を簡潔な方法で見つけるのに役立ちます。

行ごとの手動デバッグ

問題が発生した場合、一般的に使用される古典的な方法は、次の例のように、デバッガーを使用して行ごとにチェックすることです。

    ##検索エンジンで pytorch のすべてのテンソルの合計数を計算する方法に関するコード スニペットを探します。たとえば、tensor-counter-snippet
  • コードにブレークポイントを設定します
  • tensor-counter-snippet を使用して tensor の合計数を取得します
  • デバッガーを使用して次のステップを実行します
  • tensor-counter-snippet を再実行し、tensor 数が正しいかどうかを確認します増加しました
  • 上記の手順を複製します
これは機能しますが、かなり面倒なようです。これを関数にカプセル化し、必要なときに呼び出すことができるため、既存のコードを変更する必要がほとんどなくなり、デコレータの関数を導入することになります。

Python デコレーター

デコレーターはコードのどの部分でもラップできます。ここでは、追加のテンソルがあるかどうかを確認するためにデコレーターを使用していますが、実行の前後にテンソルの数を計算する必要があるため、カウンターも必要です。パターンは次のようになります。

def memleak_wrapper(func):
def wrap(*args, **kwargs):
print("num tensors start is ...")
out = func(*args, **kwargs)
print("num tensors end is ...")
return out
return wrap@memleak_wrapper
 def function_to_debug(x):
print(f"put line(s) of code here. Input is {x}")
out = x + 10
return outout = function_to_debug(x=1000)
 print(f"out is {out}")
 
 #输入类似这样
 #num tensors start is ...
 #put line(s) of code here. Input is 1000
 #num tensors end is ...
 #outis 1010

このコードを実行するには、チェックしたいコード行を関数 (function_to_debug) に入れる必要があります。ただし、依然として多くのコードを手動で挿入する必要があるため、これは最良の方法ではありません。もう 1 つは、コード ブロックが複数の変数を生成する場合、これらの下流変数を使用するための追加のソリューションを見つける必要があることです。

コンテキスト デコレーター

上記の問題を解決するには、関数デコレーターの代わりにコンテキスト マネージャーを使用できます。コンテキスト マネージャーの最も広く使用されている例は、with ステートメントを使用してコンテキストをインスタンス化することです。以前は最も一般的なものは次のとおりでした。

with open("file") as f:
…

Python の contextlib ライブラリを使用すると、Python ユーザーは独自のコンテキスト マネージャーを簡単に作成できます。したがって、この記事では、ContextDecorator を使用して、上記のデコレータを使用しようとした作業を完了します。その理由は、開発と使用が簡単であるためです。

 from contextlib import ContextDecorator
 
 class check_memory_leak_context(ContextDecorator):
def __enter__(self):
print('Starting')
return self
 
def __exit__(self, *exc):
print('Finishing')
return False

ContextDecorator には、コンテキストに入るときまたはコンテキストから出るときに呼び出される、enter() と exit() という 2 つのメソッドがあります。 __exit__ の *exc パラメータは、受信した例外を表します。

ここで、これを使用して上記の問題を解決します。

ContextDecorator を使用してメモリ リークを見つける

テンソルの総数を計算する必要があるため、計算プロセスを関数 get_n_tensors() にカプセル化して、テンソルを次の時点で計算できるようにします。コンテキストの始まりと終わり 数量:

class check_memory_leak_context(ContextDecorator):
def __enter__(self):
self.start = get_n_tensors()
return self def __exit__(self, *exc):
self.end = get_n_tensors()
increase = self.end — self.start
 
if increase > 0:
print(f”num tensors increased with"
f"{self.end — self.start} !”)
else:
print(”no added tensors”)
return False

増加がある場合は、コンソールに出力します。

get_n_tensor() はガベージ コレクター (gc) を使用し、pytorch 用にカスタマイズされていますが、他のライブラリ用に簡単に変更できます:

 import gc
 def get_n_tensors():
tensors= []
for obj in gc.get_objects():
try:
if (torch.is_tensor(obj) or
(hasattr(obj, ‘data’) and
torch.is_tensor(obj.data))):
tensors.append(obj)
except:
pass
return len(tensors)

これは現在使用でき、次の目的で使用できます。 any コードの行 (またはブロック) は次のコンテキストを使用します:

 x = arbitrary_operation(x)
 ...
 with check_memory_leak_context():
y = x[0].permute(1, 2, 0).cpu().detach().numpy()
x = some_harmless_operation()
 ...
 x = another_arbitrary_operation(x)

新しいテンソルがコンテキスト デコレーターによってラップされた行内で作成された場合、それが出力されます。

概要

これは、開発中に別のファイルに配置できる非常に優れたコード スニペットです。この記事の完全なコードは次のとおりです:

https:// gist.github.com/MarkTension/4783697ebd5212ba500cdd829b364338

最後に、この小さな記事が、コンテキスト マネージャーとは何か、コンテキスト デコレーターの使用方法、コンテキスト デコレーターを pytorch のデバッグに適用する方法を理解するのに役立つことを願っています。

以上がコンテキスト デコレータを使用した Pytorch のメモリ リーク問題のデバッグの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。