在這種情況下,為什么 Numpy 比串列推導慢?
向量化此網格結構的最佳方法是什么?
In [1]: import numpy as np
In [2]: mesh = np.linspace(-1, 1, 3000)
In [3]: rowwise, colwise = np.meshgrid(mesh, mesh)
In [4]: f = lambda x, y: np.where(x > y, x**2, x**3)
# Using 2D arrays:
In [5]: %timeit f(colwise, rowwise)
285 ms ± 2.25 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# Using 1D array and list-comprehension:
In [6]: %timeit np.array([f(x, mesh) for x in mesh])
58 ms ± 2.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# Equivalent result
In [7]: np.allclose(f(colwise, rowwise), np.array([f(x, mesh) for x in mesh]))
True
uj5u.com熱心網友回復:
在這種情況下,為什么 Numpy 比串列推導慢?
你基本上有兩個問題。
第一個是快取利用率,第二個版本使用較小的空間子集(3000,1) (1,3000) 進行計算,它可以很好地適合您的快取,因此x>y, x**2 , x**3都可以適合您的快取,這在一定程度上加快了速度向上,第一個版本正在為 3000x3000 陣列(900 萬個條目)計算這 3 個中的每一個,該陣列永遠不會位于您的快取中(通常約為 2-5 MB),然后呼叫 np.where 必須獲取部分資料從您的 RAM(而不是快取)進行記憶體復制,然后將其逐個回傳到您的 RAM,這是非常昂貴的。
np.where 的 numpy 實作有點不知道對齊,并且是按列訪問陣列,而不是按行訪問,因此它本質上是從 RAM 中獲取每個條目,而根本不使用快取。
你的串列理解實際上解決了這個問題,因為它在給定時間只處理一小部分資料,因此所有資料都可以放在你的快取中,但它仍然使用 np.where,它只是強迫它使用逐行訪問,因此利用您的快取。
第二個問題是x**2and的計算,x**3哪個是浮點求冪,代價很大,考慮用x*xand代替x*x*x
向量化此網格結構的最佳方法是什么?
顯然您已經用第二種方法撰寫了它。
利用快取的更快但不必要的優化是用 C 撰寫自己的代碼并從 python 中呼叫它,這樣你就不必評估,x*x or x*x*x除非你需要,也不必存盤,x>y,x*x,x*x*x但加速會“不值得麻煩。
uj5u.com熱心網友回復:
In [1]: In [2]: mesh = np.linspace(-1, 1, 3000)
...: In [3]: rowwise, colwise = np.meshgrid(mesh, mesh)
...: In [4]: f = lambda x, y: np.where(x > y, x**2, x**3)
另外讓我們制作稀疏網格:
In [2]: r1,c1 = np.meshgrid(mesh,mesh,sparse=True)
In [3]: rowwise.shape
Out[3]: (3000, 3000)
In [4]: r1.shape
Out[4]: (1, 3000)
使用稀疏網格,時間甚至比您的迭代更好:
In [5]: timeit f(colwise, rowwise)
645 ms ± 57.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [6]: timeit f(c1,r1)
108 ms ± 3.85 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [7]: timeit np.array([f(x, mesh) for x in mesh])
166 ms ± 13.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
另一個答案強調快取。其他帖子表明,適度的迭代可能比處理非常大的陣列更快,例如使用matmul. 我不知道是快取還是其他一些記憶體管理復雜問題會減慢速度。
但在3000*3000*8位元組我不確定這是這里的問題。相反,我認為這是x**2andx**3運算式所需的時間。
的引數where在傳入之前進行評估。
條件運算式花費的時間不多:
In [8]: timeit colwise>rowwise
24.2 ms ± 71.1 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
但是 (3000,3000) 陣列的冪運算式占用了大部分時間:
In [9]: timeit rowwise**3
467 ms ± 8.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
將其與稀疏等效項所需的時間進行對比:
In [10]: timeit r1**3
142 μs ± 150 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
這次快了 3288 倍;這比 O(n) 縮放要差一些。
重復乘法更好:
In [11]: timeit rowwise*rowwise*rowwise
116 ms ± 12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [f(x, mesh) for x in mesh],x**3對標量進行運算,因此速度很快,即使重復了 3000 次。
事實上,如果我們把功率計算從時序中去掉,整個陣列where是比較快的:
In [15]: %%timeit x2,x3 = rowwise**2, rowwise**3
...: np.where(rowwise>colwise, x2,x3)
89.8 ms ± 3.99 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/377305.html
