用numba njit
装饰的函数( jit(nopython=True)
的别名会产生与 numpy
不同的结果 on inplace operations(简单 @jit(nopython=False)
也会提供numpy
)的不同结果:
In [1]: import numpy as np
from numba import njit
def npfun(arr):
arr -= arr[3]
@njit
def jitfun(arr):
arr -= arr[3]
arr1 = np.ones((6,2))
arr2 = arr1.copy()
npfun(arr1)
jitfun(arr2)
arr1 == arr2
Out[1]: array([[ True, True],
[ True, True],
[ True, True],
[ True, True],
[False, False],
[False, False]], dtype=bool)
看起来 numpy
评估rhs并将其作为副本传递,而 numba
将rhs视为视图。是否有任何技术原因可以这样做?
numpy 1.13.3
numba 0.35
答案 0 :(得分:3)
您正在进行的操作:
arr -= arr[3]
以前是NumPy中未定义的行为。它最近才被定义,在NumPy 1.13.0中,已发布June 7th this year。新的,定义的行为总是表现为它复制了所有输入,尽管它试图避免在检测到它不需要时实际制作副本。
看起来Numba目前没有尝试模仿新行为,无论是因为它有多新,还是因为Numba特有的担忧。
答案 1 :(得分:2)
如果您使用带有out
参数的显式就地操作而不是增强赋值,它将帮助Numba:replace
arr -= arr[3]
与
np.subtract(arr, arr[3], out=arr)
这使得jitted版本(虽然使用@jit,而不是@njit)的功能与NumPy版本完全相同。值得注意的是,尝试@njit这个函数现在会失败,告诉你比njit不能处理out
参数。
我已经看到你了opened an issue on this,因此有可能更改扩展作业的处理以匹配NumPy。
正如hpaulj所说,Numba输出相当于循环数组的行。 Python JITter无法对NumPy底层的C代码做任何事情;它需要Python才能使用。支持NumPy方法(在某种程度上)的原因是Numba开发人员遇到了将NumPy数组操作解码为标量对象的显式Python迭代的麻烦,然后可以将其传递给LLVM。来自documentation:
- 合成实现数组表达式的Python函数:这个新的Python函数本质上就像一个Numpy ufunc,在广播数组参数中的标量值上返回表达式的结果。降低功能通过从数组表达式树转换为Python AST来实现这一点。
- 将合成Python函数编译到内核中:此时,reduce函数依赖于现有代码来降低ufunc和DUFunc内核,在定义如何降低对合成函数的调用之后调用
numba.targets.numpyimpl.numpy_ufunc_kernel()
。最终结果类似于Numba对象模式中的循环提升。
上述numpy_ufunc_kernel
收集索引,迭代。如果被迭代的对象在迭代过程中发生变异,则会使事情发生变化。