Pythonは解析型言語として便利な機能を持つ一方、コードの実行速度には問題も指摘されることがあります。特に、Pythonはインタプリタ言語であり、動的型付けを採用しているため、ループを多用する計算処理ではC言語やFortranなどのコンパイル言語に比べて遅くなる傾向があります。例えば、大量のデータを処理する数値計算や機械学習の前処理において、純粋なPythonコードでは非効率になるケースがよくあります。
そのため、変数が多い複雑な計算を行う際には、NumPyやNumExprのようなライブラリを使用することで大きなパフォーマンス向上が期待できます。本記事では、これらのライブラリを用いた行列・計算の速度比較を解説します。
1. Pythonベースコード
まず、基本的なPythonコードを使用した計算の実行速度を試しました。
import math
loops = 2500000
a = range(1, loops)
def f(X):
return 3 * math.log(X) + math.cos(X) ** 2
%timeit r = [f(X) for X in a]
実行結果
838 ms ± 29.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
結果: Pythonの標準的なループ処理では、計算速度が遅いことが分かりました。
2. NumPyの利用
同じ計算をNumPyに移行しました。
import numpy as np
a = np.arange(1, loops)
%timeit r = 3 * np.log(a) + np.cos(a) ** 2
実行結果
59.5 ms ± 2.09 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
結果: NumPyを使用することで、計算の実行速度は大幅に向上しました。これは、NumPyがC言語で最適化された計算をバックエンドで行っているためです。
3. NumExprを使ったコンパイルと効率化
NumExprを使用して同じ計算を実行します。NumExprは、数式を文字列として受け取り、それをJIT(Just-In-Time)コンパイルによって最適化します。この最適化では、以下の点が考慮されます。
- メモリアクセスの最適化: NumExprはキャッシュフレンドリーな計算を行うため、メモリの帯域幅を有効に活用し、パフォーマンスを向上させます。
- 並列計算の活用: 内部的にスレッドプールを使用し、複数のCPUコアで計算を並列化することで、高速化を実現します。
- 一括演算の実施: 式全体を一度に解析し、可能な限りベクトル化して処理を行うため、Pythonのループよりも効率的です。
import numexpr as ne
ne.set_num_threads(1)
f = '3 * log(a) + cos(a) ** 2'
%timeit r = ne.evaluate(f)
実行結果
42.6 ms ± 1.48 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
結果: NumExprはNumPyよりもさらに高速化されました。
4. 複数スレッドの利用
NumExprの複数スレッドを使用して効率を向上させます。
スレッド数の選択とスケーラビリティの限界
- CPUのコア数とスレッド数: スレッド数はCPUの物理コア数と等しくするのが最適とされています。ただし、ハイパースレッディング(HT)対応のCPUでは論理コア数に近づけることで効果が出ることもあります。
- メモリ帯域の影響: スレッド数を増やしすぎると、メモリ帯域の制約によりオーバーヘッドが増加し、逆に速度低下を引き起こす可能性があります。
- タスクの種類: キャッシュ効率が高い計算では、最適なスレッド数を調整することが重要です。
ne.set_num_threads(4)
f = '3 * log(a) + cos(a) ** 2'
%timeit r = ne.evaluate(f)
実行結果
17.2 ms ± 685 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
結果: NumExprでは複数スレッドを活用することで、CPUコアを最大限に活用し、さらなる高速化を実現しました。
まとめ
各ライブラリの適用ケース
- NumPy: 数値計算全般に適しており、特に小~中規模のデータ処理に有効。画像処理、統計分析、機械学習の前処理などで活用される。
- NumExpr: より大規模な計算処理に向いており、数百万~数千万の要素を持つデータセットの処理で効果を発揮。金融モデリングやシミュレーションなどで利用される。
- 複数スレッドの利用: マルチコア環境を活かして並列処理を行うことで、計算負荷の高いタスク(機械学習、ビッグデータ解析など)のパフォーマンスを最大化できる。
NumExprの複数スレッドの活用により、最大効率の計算が可能になり、Pythonの実行性能を向上させる有力な手段となります。大量のデータ処理や機械学習、シミュレーションなど、計算負荷の高いアプリケーションにおいて特に有効です。
コメント