取决于数值的Numpy性能差异

时间:2018-11-21 15:36:14

标签: python performance numpy

在评估Numpy中的表达式时,我发现了一个奇怪的性能差异。

我执行了以下代码:

import numpy as np
myarr = np.random.uniform(-1,1,[1100,1100])

然后

%timeit np.exp( - 0.5 * (myarr / 0.001)**2 )
>> 184 ms ± 301 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit np.exp( - 0.5 * (myarr / 0.1)**2 )
>> 12.3 ms ± 34.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

在第二种情况下,计算速度提高了将近15倍!注意,唯一的区别是系数为0.1或0.001。

这种行为的原因是什么?我可以更改某些内容以使第一个计算与第二个一样快吗?

2 个答案:

答案 0 :(得分:1)

使用Intel SVML

我在numexpr上无法使用Intel SVML,但是在numexpr上可以使用SVML应该与Numba一样好。 Numba基准测试在没有SVML的情况下表现出完全相同的行为,但是在SVML的情况下表现更好。

代码

import numpy as np
import numba as nb

myarr = np.random.uniform(-1,1,[1100,1100])

@nb.njit(error_model="numpy",parallel=True)
def func(arr,div):
  return np.exp( - 0.5 * (myarr / div)**2 )

时间

#Core i7 4771
#Windows 7 x64
#Anaconda Python 3.5.5
#Numba 0.41 (compilation overhead excluded)
func(myarr,0.1)                      -> 3.6ms
func(myarr,0.001)                    -> 3.8ms

#Numba (set NUMBA_DISABLE_INTEL_SVML=1), parallel=True
func(myarr,0.1)                      -> 5.19ms
func(myarr,0.001)                    -> 12.0ms

#Numba (set NUMBA_DISABLE_INTEL_SVML=1), parallel=False
func(myarr,0.1)                      -> 16.7ms
func(myarr,0.001)                    -> 63.2ms

#Numpy (1.13.3), set OMP_NUM_THREADS=4
np.exp( - 0.5 * (myarr / 0.001)**2 ) -> 70.82ms
np.exp( - 0.5 * (myarr / 0.1)**2 )   -> 12.58ms

#Numpy (1.13.3), set OMP_NUM_THREADS=1
np.exp( - 0.5 * (myarr / 0.001)**2 ) -> 189.4ms
np.exp( - 0.5 * (myarr / 0.1)**2 )   -> 17.4ms

#Numexpr (2.6.8), no SVML, parallel
ne.evaluate("exp( - 0.5 * (myarr / 0.001)**2 )") ->17.2ms
ne.evaluate("exp( - 0.5 * (myarr / 0.1)**2 )")   ->4.38ms

#Numexpr (2.6.8), no SVML, single threaded
ne.evaluate("exp( - 0.5 * (myarr / 0.001)**2 )") ->50.85ms
ne.evaluate("exp( - 0.5 * (myarr / 0.1)**2 )")   ->13.9ms

答案 1 :(得分:1)

这可能会产生非规范化的数字,从而减慢计算速度。

您可能想使用daz库来禁用非规范化的数字:

import daz
daz.set_daz()

更多信息:x87 and SSE Floating Point Assists in IA-32: Flush-To-Zero (FTZ) and Denormals-Are-Zero (DAZ)

  

为避免由于异常和下溢次数导致的序列化和性能问题,请使用SSE和SSE2指令在硬件中设置``齐平为零''和``归零为零''模式,以为浮点应用程序实现最高性能。 / p>

请注意,在64位模式下,浮点计算使用SSE指令,而不是x87。