2012-08-08 50 views
13

很抱歉有這麼多問題。我在Intel Core 2 Duo上運行Mac OSX 10.6。我正在爲我的研究運行一些基準,並且遇到了令我感到困惑的另一件事。Numpy dot產品非常緩慢地使用整數

如果我運行

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'np.dot(a,a)'

我得到以下輸出:10 loops, best of 3: 142 msec per loop

但是,如果我跑

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'np.dot(a,a)'

我得到以下輸出:10 loops, best of 3: 7.57 sec per loop

然後,我跑到

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'a*a'然後

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'a*a'

兩個跑,每圈約7.6毫秒,所以它不是乘法。添加也有類似的速度,所以這些都不應該影響點積,對吧? 那麼爲什麼使用ints計算點積要比使用浮點數慢50倍呢?

+0

我也一樣在Linux上 - 我得到float64約3秒和INT3210秒(這是一臺老機器)。不是50的因素,但仍然很奇怪。 – Luke 2012-08-08 01:37:51

回答

12

很有趣,我很好奇,想看看它是如何實現的,所以我做:

>>> import inspect 
>>> import numpy as np 
>>> inspect.getmodule(np.dot) 
<module 'numpy.core._dotblas' from '/Library/Python/2.6/site-packages/numpy-1.6.1-py2.6-macosx-10.6-universal.egg/numpy/core/_dotblas.so'> 
>>> 

所以它看起來像使用BLAS庫其。

這樣:

>>> help(np.core._dotblas) 

從中我發現這一點:

當numpy的與加速BLAS像ATLAS建成,這些功能 被替換,以利用更快的實現。更快的 實現僅影響float32,float64,complex64和complex128 數組。此外,BLAS API僅包括矩陣 - 矩陣,矩陣 - 矢量和矢量 - 矢量產品。具有較大 維度的陣列產品使用內置函數並且不加速。

所以它看起來像ATLAS細調某些功能,但它只適用於某些數據類型,非常有趣。

所以是它看起來我將使用浮動更加頻繁...

+0

我更喜歡你的答案:) – Luke 2012-08-08 02:05:38

+0

@Luke感謝+1爲你做回溯,它也是另一種有用的方法。 – 2012-08-08 02:06:52

+0

很高興知道。當我去上班時,我會用同樣的方法來看看MKL是否也是如此。謝謝您的幫助。盧克更喜歡這個答案,所以你得到了接受。 – Nino 2012-08-08 21:12:20

7

使用INT VS浮點數據類型將導致執行不同的代碼路徑:

浮法堆棧跟蹤看起來像這樣:

(gdb) backtr 
#0 0x007865a0 in dgemm_() from /usr/lib/libblas.so.3gf 
#1 0x007559d5 in cblas_dgemm() from /usr/lib/libblas.so.3gf 
#2 0x00744108 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85d9090>, <numpy.ndarray at remote 0x85d9090>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:798 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

..while對於int堆棧跟蹤看起來像這樣:

(gdb) backtr 
#0 LONG_dot (ip1=0xb700a280 "\t", is1=4, ip2=0xb737dc64 "\a", is2=4000, op=0xb6496fc4 "", n=1000, __NPY_UNUSED_TAGGEDignore=0x85fa960) 
at numpy/core/src/multiarray/arraytypes.c.src:3076 
#1 0x00659d9d in PyArray_MatrixProduct2 (op1=<numpy.ndarray at remote 0x85dd628>, op2=<numpy.ndarray at remote 0x85dd628>, out=0x0) 
at numpy/core/src/multiarray/multiarraymodule.c:847 
#2 0x00742b93 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85dd628>, <numpy.ndarray at remote 0x85dd628>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:254 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

兩個調用導致dotblas_matrixproduct,但現在看來,浮動通話中的BLAS庫保持(可能訪問某些精心優化的代碼),而int call被踢回numpy的PyArray_MatrixProduct2。

所以這是一個bug或BLAS只是不支持matrixproduct中的整數類型(這似乎不太可能)。

下面是一個簡單和廉價的解決方法:

af = a.astype(float) 
np.dot(af, af).astype(int) 
+0

值得注意的是,如果您的數據具有非常大的值,則此解決方法可能會導致錯誤,並且可能需要複製整個矩陣,因此如果矩陣非常大,則代價很大。 – Dougal 2012-08-08 04:26:26

+0

謝謝,盧克。該解決方法確實複製了矩陣,結果相當麻煩(對於內存問題),但就時間而言,1e4x1e4矩陣的速度要快上千倍!任何更大的數字,使用整數測試乘法運算速度太慢。 @Dougal這隻適用於大於2^52的數字,使用64位浮點數,對吧?數字不會大於這個數字,如果可能的話,我想利用這個加速。 – Nino 2012-08-08 21:11:17

+0

@Nino Yep,在那裏。 BLAS庫不適合整數類型,而且numpy的內置'dot'太慢了。如果內存問題是一個問題,你可以考慮寫一個ctypes接口來完成[Eigen](http://eigen.tuxfamily.org/)中的乘法或類似的操作,這應該會更快。 – Dougal 2012-08-08 21:26:59