如果我跑
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毫秒,所以它不是乘法。添加也有类似的速度,所以这些都不应该影响点积,对吧? 那么为什么使用整数计算点积比使用浮点数慢50多倍呢?
答案 0 :(得分: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使用像ATLAS这样的加速BLAS构建时,这些功能 被替换以利用更快的实现。越快 实现仅影响float32,float64,complex64和complex128 阵列。此外,BLAS API仅包括矩阵矩阵, 矩阵向量和向量矢量积。阵列产品较大 维度使用内置函数而不会加速。
所以看起来ATLAS很好地调整某些功能,但它只适用于某些数据类型,非常有趣。
所以是的,看起来我会经常使用花车...
答案 1 :(得分:7)
使用int vs float数据类型会导致执行不同的代码路径:
float的堆栈跟踪如下所示:
(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 ()
...
..而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,但看起来float调用保留在BLAS库中(可能访问一些经过优化的代码),而int调用则被踢回到numpy的PyArray_MatrixProduct2。
所以这是一个bug或BLAS只是不支持matrixproduct中的整数类型(这似乎不太可能)。
这是一个简单而廉价的解决方法:
af = a.astype(float)
np.dot(af, af).astype(int)