Использование @jit в Numba, приводящее к математическим несоответствиям с использованием float32 от Numpy в Python - PullRequest
0 голосов
/ 19 января 2019

При использовании 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'>

И это, кажется, указывает на то, что Нумба делает его классом Python float (насколько я понимаю, float64) и выполняет математику, а затем каким-то образом теряет точность.

Если я переключаюсь на float64, разница значительно уменьшается.

Get:    0.09824066666666667 Type: <class 'float'>
Want:   0.09824066666666668 Type: <class 'numpy.float64'>

Не уверен, что я делаю не так с этим. Опять же, в моем случае это игнорируемая проблема (начиная с 4 десятичных знаков), но все же хотелось бы знать, почему!

1 Ответ

0 голосов
/ 22 января 2019

Причина в том, что numba не использует np.mean, но заменяет его на / развертывает свою собственную версию :

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

Некоторое время назад я дал ответ на очень похожий вопрос о различиях между numpy.mean и pandas.mean (который использует bottleneck). Таким образом, все сказанное здесь применимо и здесь, пожалуйста, посмотрите на это для более подробной информации, здесь в двух словах:

  • Наивное суммирование, используемое numba, имеет ошибку O(n), где n - количество слагаемых.
  • Numpy использует подход, аналогичный парному суммированию , который более точен с ошибкой O(log(n)).
  • Различия очевидны для float32, но менее очевидны для float64, хотя та же проблема сохраняется.
...