
Zendesk では機械学習 (ML) 製品の構築でかなり多くの Python を使用しています。 機械学習アプリケーションで遭遇する一般的なパフォーマンスの問題の 1 つは、メモリ リークとスパイクです。 Python コードは通常、Hadoop、Spark、AWS Batch などの分散処理フレームワークを介してコンテナ内で実行されます。 各コンテナには、固定量のメモリが割り当てられています。 コードの実行が指定されたメモリの制限を超えると、メモリ不足のエラーによりコンテナーが終了します。 しかし、これはリソースの浪費につながり、予測できないメモリスパイクのために製品の安定性に影響を与える可能性があります。 メモリ リークの原因としては、
- 解放されていない大きなオブジェクトのリング
- コード内の参照サイクル
- 基盤となるライブラリ/拡張機能のメモリ リーク
コードの空間効率と使用されている基盤パッケージについてより良く理解するために、アプリケーションのメモリ使用量をプロファイルすることは有用な作業と言えます。 この投稿では、以下をカバーします:
- profiling memory usage of the application across time
- how to inspect memory usage at specific part of the program
- tips for debugging memory issues
Python code using the memory-profile packageで実行中のメモリ使用量を時間と共に変えて見ることができるようになりました。
# install the required packages
pip install memory_profiler
pip install matplotlib# run the profiler to record the memory usage
# sample 0.1s by defaut
mprof run --include-children python fantastic_model_building_code.py# plot the recorded memory usage
mprof plot --output memory-profile.png

include-children オプションは、親プロセスから生成された子プロセスのメモリ使用量を含めます。 グラフAは、反復モデル学習プロセスを示しており、学習データのバッチ処理に伴い、メモリが周期的に増加することがわかります。 オブジェクトは、ガベージ コレクションが開始されると解放されます。
メモリ使用量が常に増加している場合、メモリ リークの問題が発生する可能性があります。 以下は、これを説明するためのダミーのサンプルスクリプトです。

pdb-mmem オプションを使用して、メモリ使用量が特定のしきい値を超えた時点でデバッガーのブレークポイントを設定することができ、トラブルシューティングの際に便利です。
ある時点でのメモリダンプ
プログラム内の大きなオブジェクトの予想数を理解することは重要で、それらが複製されたり異なるフォーマットに変換されるべきかどうかということを理解する必要があります。

Another useful memory profiling library is objgraph which can generate objects graphs to inspect the lineage of objects.
迅速なフィードバック ループに努める
有用なアプローチは、問題のメモリ リーク コードのみを実行する小さな「テスト ケース」を作成することです。
別のプロセスでメモリ集中タスクを実行する
Python は、必ずしもオペレーティング システムに戻ってすぐにメモリを解放するわけではありません。 コードの一部が実行された後にメモリが解放されることを確実にするために、別のプロセスで実行する必要があります。 このページでは、Python ガーベッジコレクションの詳細を説明します。
デバッガーはオブジェクトへの参照を追加できる
db のようなブレークポイントデバッガーが使用されている場合、デバッガーから手動で作成および参照したオブジェクトはメモリプロファイルに残ります。 これは、オブジェクトがタイムリーにリリースされないメモリリークの誤った感覚を生み出す可能性があります。
Watch out for packages that can be leaky
Some Python libraries could have memory leaks potentially. 例えば、pandas はかなり多くの既知のメモリリーク問題を抱えています。
Happy hunting!