の高性能Pythonにnumpyを導入し、自分のコンピュータ上でコードを再生する章を読んでいました。誤って私はforループでnumpyのバージョンを実行し、その結果がネイティブのpythonループに比べて驚くほど遅いことがわかりました。なぜネイティブのpythonリストのループはnumpyの配列のループより高速です
コードの簡略化されたバージョンは、I 1と0の2次元アレイXと別の2次元アレイYを定義した場合、次の、その後繰り返し、概念的X + = Y.
import time
import numpy as np
grid_shape = (1024, 1024)
def simple_loop_comparison():
xmax, ymax = grid_shape
py_grid = [[0]*ymax for x in range(xmax)]
py_ones = [[1]*ymax for x in range(xmax)]
np_grid = np.zeros(grid_shape)
np_ones = np.ones(grid_shape)
def add_with_loop(grid, add_grid, xmax, ymax):
for x in range(xmax):
for y in range(ymax):
grid[x][y] += add_grid[x][y]
repeat = 20
start = time.time()
for i in range(repeat):
# native python: loop over 2D array
add_with_loop(py_grid, py_ones, xmax, ymax)
print('for loop with native list=', time.time()-start)
start = time.time()
for i in range(repeat):
# numpy: loop over 2D array
add_with_loop(np_grid, np_ones, xmax, ymax)
print('for loop with numpy array=', time.time()-start)
start = time.time()
for i in range(repeat):
# vectorized numpy operation
np_grid += np_ones
print('numpy vectorization=', time.time()-start)
if __name__ == "__main__":
simple_loop_comparison()
XにYを追加した通りでありますその結果がどのように見える
:
# when repeat=10
for loop with native list= 2.545672655105591
for loop with numpy array= 11.622980833053589
numpy vectorization= 0.020279645919799805
# when repeat=20
for loop with native list= 5.195128440856934
for loop with numpy array= 23.241904258728027
numpy vectorization= 0.04613637924194336
私は完全にnumpyのベクトル化操作は、他の2つを凌駕することを期待するが、私はネイティブのPythonのリストよりも大幅に遅いnumpyの配列の結果についてのforループを使用していることを見て驚きました。私の理解では、キャッシュは少なくともnumpyの配列で十分に満たされていなければならず、たとえforループであっても、ベクトル化なしでリストを上回るはずです。
numpyについて、またはCPU /キャッシュ/メモリが低レベルでどのように動作するのか分かりませんでしたか?どうもありがとうございました。
EDIT:変更タイトル
、しかし'numpy'配列を持つ通常のPythonループです。 – Sraw
タイトルを編集しました。何を呼びたいのかにかかわらず、問題はパフォーマンスギャップが存在する理由です。 – dhu
3つのこと:1.)二重インデックス:既存のリストと要素を参照しているリストのリスト、2次元配列の場合は、行と要素の新しいオブジェクトを作成しています。 2.)numpy '__getitem __/__ setitem__'は、リストカウンタの部分よりも多くの複雑な種類の引数を扱います。3.)(私はその違いを十分に理解していませんが、そこにあります)list.'getgetem__'は組み込みの配列です。 '__getitem__'はメソッドラッパーです –