1
1

Pythonでの高速化の選択肢

Last updated at Posted at 2024-08-30

Python プログラマのスキル標準化のための項目

の目的のため、高速化アプローチについて概観するためのメモを作成する。

想定する読者

python の中級者
pypy, Numba などの上級者向けのことは書いてありません。

自作モジュールは必要なのか

  • その分野で使われだしているOSSのモジュールはないか?
  • 車輪の再発明をしなくてよい。
  • OSSのモジュールで標準化されていれば、次の作業は不要になる可能性が高い
    • CPU, GPUのサポート
    • マルチコアを使った高速化のサポート
  • 自分たちが着目している分野のOSSでどういうライブラリが使われているのかを確認しよう。
  • そのライブラリを使えば、自作ライブラリを書く量が減る。
  • 既存のライブラリに1つ機能を追加したほうが、全体がすっきりする。
  • 既存のgithubのリポジトリをforkして実装を作り、動作検証後のものを本家にPRを上げる。
  • (そうすれば、自分がメンテナンスし続けなければならないライブラリが減る。)
    以下は自作モジュールが必要な前提で書く。

処理時間を計測する

cProfile で処理時間の内訳を見よう。

-m cProfile -s cumtime を追加するだけ

  • 関数の呼び出し回数は妥当ですか?
    例:画像の正規化処理などを無駄に繰り返している。
python3 -m cProfile -s cumtime myprog.py

画像処理・画像認識の場合には、毎回の処理時間の方が重要

  • 初期化処理
  • 毎回の処理
  • 終了処理
    これらのうち、画像処理・画像認識の場合には、毎回の処理時間の方が重要。
最近の機械学習の分野では、ひっそりとデータファイルを自動でダウンロードしていることがあります。
  • 毎回のプログラムの実行の中でダウンロードするのではなく、環境構築の際にデータをダウンロードするように書き換えてはどうでしょう。

無駄に遅くしているもの

  • matplotlib での描画

  • 学習済みのモデルファイルのダウンロード

    • 環境構築の際に一度だけ実行すればよいように書き換える。
  • 学習済みのモデルファイルのtensorRTへの書き換えを立ち上げに毎回行なってしまう

    • 環境構築の際に一度だけ実行すればよいように書き換える。
  • 複数人が利用する場合には変換済みのものをダウンロードする。

  • for 文を使って画素毎に処理しているコード

numpyで明示的にループを書くと極端に遅くなる
画像処理で2重ループをなるべく書くな

  • generator で十分なところをlistにするな。
.py
for p in glob.glob("**/*.jpg"):
    print(p)

ならば、jpgファイルを全数探し終わってなくても、表示を開始する。

.py
for p in sorted(glob.glob("**/*.jpg")):
    print(p)

とすると、全数探して、並び替えを完了してからでないと表示が始まらない。

  • list.extend()で十分なところを+で代入をし直すな。
    悪い例
.py
a = [1, 2, 3]
a = a + [4, 5, 6]

良い例

.py
a = [1, 2, 3]
a.extend([4, 5, 6])

さらには、配列の大きさが予めわかっている場合には、最初にnp.zeros(shape, dtype=np.float) などとして領域を確保してから、
該当の行を代入していくということで、領域の確保に関する処理時間を減らせることがあります。

#pragma omp parallel

をキーワードに検索してみてください。

  • numpyでの実装をpytorchでの実装に書き換えて、GPUを使っての動作を高速化させる。
    ChatGPTでも次の質問に答えて例を書いてくれます。
    「numpy をpytorchに書き換える例を示してください。」

  • CPU-GPU 間のメモリ転送を減らす。

  • deploy 環境に合わせたモデルに変換する。
    例: pytorch -> TensorRT
    例: pyTorch -> onnx

数値データを保存する際にバイナリモードの形式があれば利用する。

数値データをasciiデータファイルで保存し、
asciiデータファイルを数値データとして読み込むのは
処理が重くなります。

対象のデータファイルにバイナリモードがあれば、
バイナリデータでデータを保存し、それを読み込むようにします。

例:点群データのply ファイルにもASCIIとバイナリの2つのバージョンが存在します。
利用するツールやライブラリがバイナリモードがあれば、
その分、処理が速くなります。

opencv-python のbuild 条件を確認する。

OpenCVのモジュールは、build 条件によって性能が著しく変化します。
CPUの種類に応じた最適化が入っているか
Video I/O: はどうなっているのか
などです。

GStreamer:
を使いたければ、CMakeでGStreamerを有効化する設定にして、cmake, make しなければなりません。

必ず使うとは限らないライブラリのimportは後回しにする。

スクリプトの動作改善するためには、
必ず使うとは限らないライブラリのimportは後回しにするのも手だ。

付記: docker build のキャッシュが有効になるDockerfileの記述順序

Dockerfile の記述のうち、変更を生じやすいものを後ろにする。
変更を生じない部分は、前回のdocker build の結果が利用されるので、変更部分以降しか処理されない。

参考記事

Pythonプログラムが遅い!高速化したい!そんな時は...

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1