我无法弄清楚为什么numba在这里击败numpy(超过3x)。我是否在这里进行基准测试时遇到了一些根本性的错误?看起来像numpy的完美情况,不是吗?请注意,作为一个检查,我还运行了一个组合numba和numpy(未显示)的变体,正如预期的那样,与没有numba的numpy相同。
(顺便说一下,这是一个后续问题:Fastest way to numerically process 2d-array: dataframe vs series vs array vs numba)
import numpy as np
from numba import jit
nobs = 10000
def proc_numpy(x,y,z):
x = x*2 - ( y * 55 ) # these 4 lines represent use cases
y = x + y*2 # where the processing time is mostly
z = x + y + 99 # a function of, say, 50 to 200 lines
z = z * ( z - .88 ) # of fairly simple numerical operations
return z
@jit
def proc_numba(xx,yy,zz):
for j in range(nobs): # as pointed out by Llopis, this for loop
x, y = xx[j], yy[j] # is not needed here. it is here by
# accident because in the original benchmarks
x = x*2 - ( y * 55 ) # I was doing data creation inside the function
y = x + y*2 # instead of passing it in as an array
z = x + y + 99 # in any case, this redundant code seems to
z = z * ( z - .88 ) # have something to do with the code running
# faster. without the redundant code, the
zz[j] = z # numba and numpy functions are exactly the same.
return zz
x = np.random.randn(nobs)
y = np.random.randn(nobs)
z = np.zeros(nobs)
res_numpy = proc_numpy(x,y,z)
z = np.zeros(nobs)
res_numba = proc_numba(x,y,z)
结果:
In [356]: np.all( res_numpy == res_numba )
Out[356]: True
In [357]: %timeit proc_numpy(x,y,z)
10000 loops, best of 3: 105 µs per loop
In [358]: %timeit proc_numba(x,y,z)
10000 loops, best of 3: 28.6 µs per loop
我在2012年macbook air(13.3)标准anaconda发行版上运行了这个版本。如果相关,我可以提供有关我的设置的更多详细信息。
答案 0 :(得分:26)
我认为这个问题突出了(某种程度上)从更高级语言调用预编译函数的局限性。假设在C ++中你写了类似的东西:
for (int i = 0; i != N; ++i) a[i] = b[i] + c[i] + 2 * d[i];
编译器在编译时看到所有这一切,整个表达式。它可以在这里做很多非常聪明的事情,包括优化临时(和循环展开)。
然而,在python中,考虑一下发生了什么:当你使用numpy时,每个''+''在np数组类型上使用运算符重载(这只是连续内存块的薄包装,即低级意义上的数组),并调出一个fortran(或C ++)函数,它可以超快速地进行加法。但它只是添加一个,并吐出一个临时的。
我们可以看到,在某种程度上,虽然numpy非常棒且方便且非常快,但它会减慢速度,因为虽然看起来它正在调用快速编译的语言以进行艰苦的工作,但编译器却无法获得看到整个节目,它只是提供了孤立的小位。这对于编译器来说是非常不利的,尤其是现代编译器,它们非常智能,并且在代码编写良好时可以在每个周期中退出多个指令。
另一方面,Numba使用了一个jit。因此,在运行时它可以确定不需要临时值,并优化它们。基本上,Numba有机会将程序编译为一个整体,numpy只能调用本身已经预编译的小原子块。答案 1 :(得分:20)
当你问numpy时:
x = x*2 - ( y * 55 )
内部翻译为:
tmp1 = y * 55
tmp2 = x * 2
tmp3 = tmp2 - tmp1
x = tmp3
每个temp都是必须分配,操作然后解除分配的数组。另一方面,Numba一次处理一件物品,而不必处理这些开销。
答案 2 :(得分:7)
Numba通常比Numpy甚至Cython更快(至少在Linux上)。
这是一个情节(从Numba vs. Cython: Take 2偷来的):
在此基准测试中,已计算出成对距离,因此这可能取决于算法。
请注意,在其他平台上可能会有所不同,请参阅Winpython(来自WinPython Cython tutorial):
答案 3 :(得分:3)
除了进一步混淆原始问题外,我还会在这里添加更多内容以回应Jeff,Jaime,Veedrac:
def proc_numpy2(x,y,z):
np.subtract( np.multiply(x,2), np.multiply(y,55),out=x)
np.add( x, np.multiply(y,2),out=y)
np.add(x,np.add(y,99),out=z)
np.multiply(z,np.subtract(z,.88),out=z)
return z
def proc_numpy3(x,y,z):
x *= 2
x -= y*55
y *= 2
y += x
z = x + y
z += 99
z *= (z-.88)
return z
我的机器今天似乎比昨天运行得更快,所以这里它们与proc_numpy相比(proc_numba的定时与以前相同)
In [611]: %timeit proc_numpy(x,y,z)
10000 loops, best of 3: 103 µs per loop
In [612]: %timeit proc_numpy2(x,y,z)
10000 loops, best of 3: 92.5 µs per loop
In [613]: %timeit proc_numpy3(x,y,z)
10000 loops, best of 3: 85.1 µs per loop
请注意,当我编写proc_numpy2 / 3时,我开始看到一些副作用,所以我复制了x,y,z并传递了副本而不是重复使用x,y,z。此外,不同的函数有时在精度上略有不同,因此有些函数没有通过相等测试,但如果你区分它们,它们就非常接近。我认为这是由于创建或(不创建)临时变量。 E.g:
In [458]: (res_numpy2 - res_numba)[:12]
Out[458]:
array([ -7.27595761e-12, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, -7.27595761e-12, 0.00000000e+00])
此外,它很小(大约10微秒),但使用浮动文字(55而不是55)也会为numpy节省一点时间,但无助于numba。