はじめに
Pythonは最近とても人気で、機械学習だけでなく様々な分野で幅広く使われています。
しかし、Pythonには実行速度が遅いという弱点があります。
高速なC言語などと比べて数百倍遅く、科学計算などでは残念ながらPythonは選択肢に入りません。
しかし私はPythonが好きで、{}
やend
を書いたり、いちいち変数宣言なんてしたくないので、高速化する方法を調べました。
調べてみたところ、Pythonを高速化する一つ一つの方法の詳しい解説記事は見つかりました。
しかし、網羅するような逆引きのまとめがなかったので、記事を書くことにしました。
それぞれの方法を調べましたが、実際に使用したことがないものが多いため、記事で間違いがありましたら、ぜひ指摘してください。
また、ここに載っていない高速化方法などありましたら、ぜひコメント欄で教えてください。
よろしくお願いします。
目次
書いた内容は、規模が大きい順に並べました。
項番 | 項目 | 概要 |
---|---|---|
1 | 1. クラスタレベル | 複数コンピュータをつなげて分散処理する方法 |
2 | 2. コンピュータレベル | 単一PC内で高速化する方法 |
3 | 3. Python処理系、コンパイラレベル | 特定のPythonの種類、コンパイラを使用して高速化する方法 |
4 | 4. Pythonライブラリレベル | 高速なライブラリを使用する方法 |
5 | 5. コーディングレベル | 高速に動作するようなコードを書く方法 |
6 | 6. 番外編:高速な他言語のプログラムを呼び出す | 他の高速な言語を使用する方法 |
7 | 7. 番外編2:ハードウェアの選択 | CPUやGPUなどハードウェアの選び方 |
1. クラスタレベル
複数のマシンを使用するクラスタレベルで分散処理することで高速化する方法です。
もうここまでくると Python というプログラミング言語レベルではなくなりますが、高速化の選択肢として説明します。
Hadoop
大量のデータを複数マシンに分散して処理させるオープンソースのプラットフォーム。
Google社内基盤技術をオープンソースとして実装したものらしいです。
Apache Spark
カリフォルニア大学バークレー校で開発された分散処理フレームワーク。
Hadoopよりもメモリをうまく使うことで、機械学習を高速で実行できるようにしたものです。
2. コンピュータレベル
1台のコンピュータの中で高速化する方法です。
高速化のアプローチとしては、並列化、GPGPUの選択があります。
2-1. 並列化
一つのマシンの中で、プログラムを並列化して実行して高速化する方法です。
詳しくは東京大学の情報基盤センターが無料で公開している動画がわかりやすいです。
ちなみに並行処理と並列処理がありますが、違いは詳しくはクリック
Pythonライブラリを使用した並列化
Pythonのプログラムは、ライブラリを使用することで比較的簡単にできます。
ライブラリとして、multiprocessing
、threading
、concurrent.futures
などがあります。
マルチプロセス、マルチスレッドを一緒に紹介している記事が多いので、区別せずにリンクを貼ります。
MPI
分散メモリ型計算機の プロセス間 の通信規格らしい。
スパコンで並列処理するために使用されることが多い。
詳しくは東京大学の情報基盤センターが無料で公開している動画がわかりやすいです。
いわゆる マルチプロセス
もともとC、C++、Fortranから呼び出すものだが、Pythonからもmpi4py
というライブラリを使用することで利用できる。
座学「並列プログラミング入門」in 金沢 第2講 並列処理とMPIの基礎
座学「並列プログラミング入門」in 金沢 第4講 Hybrid並列化技法(MPIとOpenMPの応用)PDF
名古屋大学情報基盤センター MPIの基礎
東京大学情報基盤センター MPI基礎:並列プログラミング入門
神戸大学計算科学教育センター MPIによる並列化実装
OpenMP
共有メモリ型マシンで並列プログラミングを可能にするAPIです。スパコンでよく使われます。
いわゆる マルチスレッド
C、C++、Fortranについて標準化が行われています。
Cython経由でOpenMPを使用できるらしいですが、Pythonではあまり実用的ではなさそうです。
座学「並列プログラミング入門」in 金沢 第3講 OpenMPの基礎PDF
座学「並列プログラミング入門」in 金沢 第4講 Hybrid並列化技法(MPIとOpenMPの応用)PDF
名古屋大学情報基盤センター OpenMPの基礎
理化学研究所 OpenMPによるスレッド並列計算
2-2. GPGPU
GPGPUとは、General Purpose GPUの略で、GPUを画像処理以外に使用する技術です。ディープラーニングやマイニングに使用されているのが有名です。
GPUは汎用性がCPUと比べて低いですが、行列計算などがとても高速です。
そのため、GPUを処理の一部で使用することで高速化が可能です。
ただし、メモリ上にある配列をGPUのメモリに移して、計算後に戻すために時間がかかるため、場合によってはより時間がかかってしまうこともあります。
CuPy
NumPy互換のインターフェースを持ち、GPUを使うことができるライブラリです。
日本のベンチャー企業Preferred Networksが開発しました。(Chainerを作っていた会社)
おそらく一番使いやすくて有名です。
変数は明示的にプログラムでメモリ-GPU間を移動させる必要があります。
TensorFlow
ディープラーニング界の2大フレームワークの片割れです。
ディープラーニング自体テンソル同士の演算(行列同士の演算)であるため、ディープラーニング以外にも使用可能です。
GPUとCPUを使い分けることを前提にして設計されているため、メモリ-GPU間の変数の移動を自動で行ってくれます。
ただしディープラーニング以外で使用しているのをみたことがないので、情報が少なく学習が大変かもしれません。
PyCUDA
本来C/C++で使用するCUDAを、Pythonから呼び出せるようにバインディングしたライブラリです。
おそらくCUDAに関する知識がないと使えなさそうです。
そしてネット上にあまり情報がないです。
Numba.cuda
後に解説するNumba
というライブラリにCUDAを使用するものが含まれているらしいです。
おそらくCUDAに関する知識がないと使えなさそうです。
ネット上にあまり情報がない。
3. Python処理系、コンパイラレベル
普通のPythonはCPythonといって、C言語で書かれた処理系らしいです。
しかし他にもJavaで実装されたJython
、C#で実装されたIronPython
があったり、JITコンパイラによってコンパイルを最適化して高速化してくれるものがります。
この章では、高速化してくれる処理系、コンパイラに関してまとめました。
↑のサイトに比較したものがわかりやすくまとめられていますが、
軽くまとめると実行速度は
C++ > 越えられない壁 > Codon > Numba > Cython > PyPy > Cpython(デフォ)
のようです。
また、私見ですが、元のコードをどれだけ書き換えないで済むかで比較すると、
Cpython(デフォ) > PyPy(書き換え不要) > Numba(関数の前に@jitを書くだけ) > Codon(型ヒントを追加) > Cython(独特の型宣言や関数定義) > 超えられない壁 > C++(別言語)
といったような状況のようです。
3-1. 処理系
PyPy
CPythonを制限したRPythonで実装されたPython処理系で、かつJITコンパイルをするものらしいです。
競プロでよく使われるみたいですが、PyPy
について説明したwebサイトが少ないです。
3-2. コンパイラ
Numba
比較的簡単に高速化できる方法が、Numba
ライブラリを使用することです。
コードを最適化して事前にコンパイルすることで、数十倍速くなることもあるそうです。
コードをほぼ書き換えずに(正確には、インポートして関数の前にデコレータを付け足すなどして)高速化することができます。
Cython
Pythonが遅いならPythonのコードをcに変換してコンパイルしまおうという発想。
C言語になるので、とても高速(ちゃんと書けば100倍)になりますが、Pythonコード内で型宣言をする必要があるみたいです。
Numba
と比べて、C言語の動作環境を作ったりと導入までがめんどくさそうです。
Codon
ほぼPythonのコードで、コンパイル時にネイティブなマシンコードにすることで高速化を実現した新しいコンパイラです。
新しいのでまだ情報が全然ありません。
4. Pythonライブラリレベル
Pythonプログラム内で使用することで高速化につながるライブラリを紹介します。
NumPy
C言語とFortranで書かれた、高速に配列(行列)の計算をするライブラリです。
非常に有名で、しょっちゅう出てきます。
ただし、numpy.arrayをforループで回すと遅くなるなどの落とし穴があるみたいなので注意しましょう。
20220914追記
numpyは裏でBLASを呼び出しているらしいですが、このBLASの種類によって計算速度が異なるそうです。
最速はintel製のIntel MKL
で、conda
でnumpy
をインストールするとこれが入っていますが、pip
でインストールするとOpenBLAS
が使用され、遅くなってしまうそうです。
どちらのBLASが入っているかは以下のようにして確認できます。
import numpy as np
np.__config__.show()
pickle
データの読み込む際に、pickle
を使用すると速くなります。
pickle
はPythonオブジェクトをバイナリファイルにするPickle 化
をするライブラリで、Python以外では読み込めませんが、とても高速に(十数倍)読み込むことができるというメリットがあります。
5. コーディングレベル
Pythonのプログラムの書き方次第で高速化できる方法はたくさんあります。
この章では、Pythonの理解、アルゴリズム、メモリの理解についてまとめます。
5-1. Pythonの理解
Python特有の高速化方法があります。
例えば、内包表記
や、importの方法についてです。
5-2. アルゴリズム
アルゴリズムは、Pythonだけでなく、すべてのプログラムに通用する基本的な考え方です。
アルゴリズムの速度の指標として、$O(n^2)$ や $O(n\log{n})$ や $O(2^n)$ といった計算量オーダーを使用します。
アルゴリズムには、探索、ソート、最適化などさまざまな種類があり、それぞれにさまざまなアルゴリズムが存在しますが、紹介しきれないのでまとめて紹介します。
世界的なアルゴリズムのバイブル The Art of Computer Programming(Amazon)
5-3. メモリの理解
プログラムが配列をメモリに格納する方法は、Row-major order方式
とColumn-major order方式
があります。
Python(numpy)はRow-major order方式
なので、2次元なら(A[0][0], A[0][1], A[0][2], A[1][0], ...という順に、3次元なら[k,j,i]順にアクセスすると速いそうです。
高速化について
座学「並列プログラミング入門」in 金沢 第1講 プログラム高速化の基礎PDF
メモリ格納について
6. 番外編:高速な他言語のプログラムを呼び出す
ここまで基本的にPythonについての高速化の方法をまとめてきました。
この章では、「Pythonが遅い言語なら、他のの高速な言語で書いたプログラムを呼び出して使えばいいじゃん」という発想のもと、その方法をまとめます。
今回は、有名な高速な言語として、Fortran
, C
, C++
, julia
についてまとめました。
6-1. Fortran
ctypes
を使用する方法と、f2py
を使用する方法がある。
6-2. C
どうやらCでラッパーを作る方法と、ctypes
ライブラリを使うの二種類があるらしい
ちょっと私の理解不足で、うまく説明できませんでした。
ラッパー
ctypes
6-3. C++
どうやらpybind11
ライブラリを使う方法と、swig
を使う方法があるらしい。
6-4. julia
7. ハードウェアの選択
プログラムを実行しているのはコンピュータです。
ならば、スペックの高いコンピュータを使用すれば実行速度は速くなります。
といっても、相当なこと(ものすごいボトルネックの解消など)がない限り数倍の高速化などにはならないと思います。
スペックの高いコンピュータ についてまとめていきます。
PCパーツ全体
OS
正確にはソフトウェアですが、パソコンを買うときに決まるようなものなのでここで紹介します。
有名なOSといえばwindowsとlinuxでしょう。
機械学習はlinuxのほうがwindowよりも倍ぐらい速いみたいです。
他の普通のプログラムはlinuxのほうがwindowよりもほんのちょっと速いみたいですが、大した差がないみたいです。
CPU
CPUで重要になってくる要素は動作周波数、コア数(並列数)、キャッシュの3つです。
動作周波数は高ければ高いほど1秒間に演算できる回数が増え、プログラムの実行速度向上が見込めます。さらに、CPIと言って一命令数当たりにかかるクロック数の数も世代がたつにつれて向上しているようですが、正直プログラムが早くなるかは内容によるのでなんとも言えなさそうです。
コア数は並列処理をする場合、効いてきます
これはプログラムが並列処理に対応しているか、並列処理が効きやすいプログラム化で変わってきます。
キャッシュは、メモリからデータをとってくる代わりにCPUに近いキャッシュにデータを置いておくというものであり、AMDがRyzen5800X3Dなどのようにゲーム向けにキャッシュを増やしたCPUを販売していますが、プログラムで改善が望めるかはわかりません。
いろいろ書きましたが、基本的に世代が新しくて動作周波数が高いものを買えばよさそうです。
ただし並列化するならコア数、スレッド数が多いものを買うといいです。
GPU
GPGPUや、ディープラーニングをするなら一番重要です。
GPUで重要になってくることは、演算性能とメモリ、ディープラーニング用のコアがあるかなどでしょう。
演算性能は、1秒間に浮動小数点演算が何回できるかという指標であり、コアの数が大きいほど大きくなる傾向があり、基本的にはGPUの性能はこれで測ります。
メモリについて、特に近年のディープラーニングではモデルのサイズがどんどん大きくなっており、メモリの大きさ次第で実行できるプログラムも変わってくるため重要になってきています。
ディープラーニング専用のコアを搭載するGPUも出てきており、NvidiaならRTコア、AppleならNeural Engineなどがあります。
メモリ
プログラム実行時にメモリをたくさん使うなら、メモリ容量を十分確保する必要があります。
また、動作周波数や転送速度なども種類がありますが、詳しくは触れません。
ストレージ(HDD、SSD)
保存したデータの読み出し、データの書き込みに時間がかかっているなら、SSDの中でも高速なものにすることで高速化が見込めます。
SSDといってもさらに普通のSATA接続のものから高速なNVMeSSD、さらにNVMeSSDの中でもgen4、gen5など世代があります。
最後に
Pythonの実行を高速化する方法をまとめました。
思った以上に様々な方法があり、また規模も全然違うため、分類してまとめるのが大変でした。
しかし書き終わってみると、かなり高速化について浅く広い知識が付きました。
それぞれのプログラムにあった高速化方法があると思うので、ぜひ逆引きとして使用してください。
また、何か間違い、他の高速化方法などありましたら、遠慮なくコメントしてください。
よろしくお願いします。
その他参考になったサイト