簡體   English   中英

為什么與使用兩個 Numpy arrays 的向量化相比,使用 Numpy 數組和 int 進行算術運算時減法更快?

[英]Why is subtraction faster when doing arithmetic with a Numpy array and a int compared to using vectorization with two Numpy arrays?

我對為什么這段代碼感到困惑:

start = time.time()
for i in range(1000000):
    _ = 1 - np.log(X)
print(time.time()-start)

執行速度比這個實現快:

start = time.time()
for i in range(1000000):
    _ = np.subtract(np.ones_like(X), np.log(X))
print(time.time()-start)

我的理解是它應該是相反的,因為在第二個實現中我正在利用矢量化提供的加速,因為它能夠同時操作 X 中的元素而不是順序操作,這就是我假設第一個實現的方式功能。

有人可以為我解釋一下嗎,因為我真的很困惑? 謝謝!

您的代碼的兩個版本都是矢量化的。 您為嘗試向量化第二個版本而創建的數組只是開銷。


NumPy 矢量化不是指硬件矢量化。 如果編譯器足夠聰明,它可能最終會使用硬件矢量化,但 NumPy 並沒有明確使用 AVX 或任何東西。

NumPy 向量化是指編寫一次對整個 arrays 進行操作的 Python 級代碼,而不是使用一次對多個操作數進行操作的硬件指令。 它是 Python 級別的向量化,而不是機器語言級別的向量化。 這種寫顯式循環的好處是 NumPy 可以在 C 級循環中執行工作,而不是 Python,避免了大量的動態調度、裝箱、拆箱、通過字節碼評估循環等。

從這個意義上說,您的代碼的兩個版本都是矢量化的,但是第二個版本在寫入和讀取巨大的數組時浪費了一堆 memory 和 memory 帶寬。

此外,即使我們談論的是硬件級矢量化, 1 -版本也與其他版本一樣適用於硬件級矢量化。 您只需將標量1加載到向量寄存器的所有位置並照常進行。 與第二個版本相比,它涉及到 memory 的傳輸要少得多,因此可能仍然比第二個版本運行得更快。

時間基本相同。 正如其他人指出的那樣,沒有任何類型的硬件或多核並行化,只是解釋的 Python 和編譯的numpy函數的混合。

In [289]: x = np.ones((1000,1000))

In [290]: timeit 1-np.log(x)                                                    
15 ms ± 1.94 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [291]: timeit np.subtract(np.ones_like(x), np.log(x))                        
18.6 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

np.ones_like排除在計時循環之外:

In [292]: %%timeit y = np.ones_like(x) 
     ...: np.subtract(y,np.log(x)) 
     ...:  
     ...:                                                                       
15.7 ms ± 441 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

2/3 的時間花在log function 中:

In [303]: timeit np.log(x)                                                      
10.7 ms ± 211 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [306]: %%timeit y=np.log(x) 
     ...: np.subtract(1, y)                                                                  
3.77 ms ± 5.16 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

如何生成1的變化只是時序的一小部分。

使用“廣播”,使用標量和數組或數組和數組進行數學運算同樣容易。

1 ,無論是標量(實際上是一個形狀為()的數組),都被廣播到 (1,1) 然后到 (1000,1000),所有這些都沒有復制。

我當然不是 numpy 專家,但我的猜測是第一個例子只使用一個向量,第二個例子首先創建了一個向量 1,然后減去。 后者需要雙倍數量的 memory 和一個額外的步驟來創建向量 1。

在 x86 CPU 上,兩者可能都是某種 AVX 指令,一次處理 4 個數字。 當然,除非您使用的是 SIMD 寬度大於矢量長度的精美 CPU,並且此 CPU 受 numpy 支持。

案例 A 在 mpu 上僅運行一個迭代器,而案例 B 在兩個與 X 一樣大的向量上具有兩個迭代器,如果未優化,則需要在線程中進行大量上下文切換。 案例 B 是案例 A 的更通用版本...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM