使用 Numba 的 @jit 导致数学与 Python 中使用的 Numpy 的 float32 不一致
Using Numba's @jit causing math inconsistencies with Numpy's float32 being used in Python
当使用 Numba 的 @jit
和 Numpy 的 float32
数据类型时,我得到了?截断?问题。这主要是噪音,因为它远远超出了我关心的小数位数 - 大约第 7 或第 8 位 - 但知道发生了什么以及我是否可以修复它仍然是件好事。
顺便说一下,我必须使用 float32
数据类型来节省内存!
这是我用作测试的代码:
import numpy as np
from test_numba import test_numba
np.random.seed(seed=1774);
number = 150;
inArray = np.round(np.float32((np.random.rand(number)-.5)*2),4); #set up a float32 with 4 decimal places
numbaGet = test_numba(inArray); #run it through
print("Get:\t"+str(numbaGet)+" Type: "+str(type(numbaGet)));
print("Want:\t"+str(np.mean(inArray))+" Type: "+str(type(np.mean(inArray)))); #compare to expected
结合以下功能
import numpy as np
from numba import jit #, float32
@jit(nopython=True) #nopython=True, nogil=True, parallel=True, cache=True , nogil=True, parallel=True #float32(float32),
def test_numba(inArray):
#outArray = np.float32(np.mean(inArray)); #forcing float32 did not change it
outArray = np.mean(inArray);
return outArray;
这个输出是:
Get: 0.0982406809926033 Type: <class 'float'>
Want: 0.09824067 Type: <class 'numpy.float32'>
这似乎表明 Numba 正在使它成为 Python float
class(据我所知,float64
)并进行数学运算,然后以某种方式进行精度下降。
如果我切换到 float64
,差异会大大减少。
Get: 0.09824066666666667 Type: <class 'float'>
Want: 0.09824066666666668 Type: <class 'numpy.float64'>
不确定我做错了什么。同样,在我的情况下,这是一个可以忽略的问题(从小数点后 4 位开始),但仍然想知道为什么!
原因是,numba 不使用 np.mean
,而是用 by/rolls 代替 its own version:
def array_mean_impl(arr):
# Can't use the naive `arr.sum() / arr.size`, as it would return
# a wrong result on integer sum overflow.
c = zero
for v in np.nditer(arr):
c += v.item()
return c / arr.size
前段时间我给了 an answer to a very similar question 关于 numpy.mean
和 pandas.mean
(使用 bottleneck
)之间的区别。所以那里所说的一切也适用于这里,请查看它以获取更多详细信息,简而言之:
numba
使用的朴素求和误差为 O(n)
,其中 n
是求和数。
- Numpy 使用类似于 pairwise-summation 的方法,它更精确,错误
O(log(n))
。
float32
的差异很明显,但 float64
的差异不太明显,尽管仍然存在相同的问题。
当使用 Numba 的 @jit
和 Numpy 的 float32
数据类型时,我得到了?截断?问题。这主要是噪音,因为它远远超出了我关心的小数位数 - 大约第 7 或第 8 位 - 但知道发生了什么以及我是否可以修复它仍然是件好事。
顺便说一下,我必须使用 float32
数据类型来节省内存!
这是我用作测试的代码:
import numpy as np
from test_numba import test_numba
np.random.seed(seed=1774);
number = 150;
inArray = np.round(np.float32((np.random.rand(number)-.5)*2),4); #set up a float32 with 4 decimal places
numbaGet = test_numba(inArray); #run it through
print("Get:\t"+str(numbaGet)+" Type: "+str(type(numbaGet)));
print("Want:\t"+str(np.mean(inArray))+" Type: "+str(type(np.mean(inArray)))); #compare to expected
结合以下功能
import numpy as np
from numba import jit #, float32
@jit(nopython=True) #nopython=True, nogil=True, parallel=True, cache=True , nogil=True, parallel=True #float32(float32),
def test_numba(inArray):
#outArray = np.float32(np.mean(inArray)); #forcing float32 did not change it
outArray = np.mean(inArray);
return outArray;
这个输出是:
Get: 0.0982406809926033 Type: <class 'float'>
Want: 0.09824067 Type: <class 'numpy.float32'>
这似乎表明 Numba 正在使它成为 Python float
class(据我所知,float64
)并进行数学运算,然后以某种方式进行精度下降。
如果我切换到 float64
,差异会大大减少。
Get: 0.09824066666666667 Type: <class 'float'>
Want: 0.09824066666666668 Type: <class 'numpy.float64'>
不确定我做错了什么。同样,在我的情况下,这是一个可以忽略的问题(从小数点后 4 位开始),但仍然想知道为什么!
原因是,numba 不使用 np.mean
,而是用 by/rolls 代替 its own version:
def array_mean_impl(arr):
# Can't use the naive `arr.sum() / arr.size`, as it would return
# a wrong result on integer sum overflow.
c = zero
for v in np.nditer(arr):
c += v.item()
return c / arr.size
前段时间我给了 an answer to a very similar question 关于 numpy.mean
和 pandas.mean
(使用 bottleneck
)之间的区别。所以那里所说的一切也适用于这里,请查看它以获取更多详细信息,简而言之:
numba
使用的朴素求和误差为O(n)
,其中n
是求和数。- Numpy 使用类似于 pairwise-summation 的方法,它更精确,错误
O(log(n))
。 float32
的差异很明显,但float64
的差异不太明显,尽管仍然存在相同的问题。