Ожидается ли, что эффективный квадратный евклидовый код расстояния numba будет медленнее, чем эффективный аналог numpy? - PullRequest
0 голосов
/ 04 июня 2018

Я изменяю наиболее эффективный код из ( Почему этот код numba в 6 раз медленнее, чем код numpy? ), чтобы он мог обрабатывать x1, будучи (n, m)

@nb.njit(fastmath=True,parallel=True)
def euclidean_distance_square_numba_v5(x1, x2):
    res = np.empty((x1.shape[0], x2.shape[0]), dtype=x2.dtype)
    for a_idx in nb.prange(x1.shape[0]):
        for o_idx in range(x2.shape[0]):
            val = 0.
            for i_idx in range(x2.shape[1]):
                tmp = x1[a_idx, i_idx] - x2[o_idx, i_idx]
                val += tmp * tmp 
            res[a_idx, o_idx] = val 
    return res

Тем не менее, это все еще не более эффективно, чем более эффективная версия numpy:

def euclidean_distance_square_einsum(x1, x2):
    return np.einsum('ij,ij->i', x1, x1)[:, np.newaxis] + np.einsum('ij,ij->i', x2, x2) - 2*np.dot(x1, x2.T)

с вводом как

a = np.zeros((1000000,512), dtype=np.float32)
b = np.zeros((100, 512), dtype=np.float32)

Время, которое я получил, составляет 2.4723422527313232 для кода numba и 0.8260958194732666 дляКод NUMPY.

1 Ответ

0 голосов
/ 05 июня 2018

Да, это ожидаемо.

Первое, что вы должны знать: точка-продукт - это рабочая лошадка numpy-версии, здесь для немного меньших массивов:

>>> def only_dot(x1, x2):
        return - 2*np.dot(x1, x2.T)

>>> a = np.zeros((1000,512), dtype=np.float32)
>>> b = np.zeros((100, 512), dtype=np.float32)

>>> %timeit(euclidean_distance_square_einsum(a,b))
6.08 ms ± 312 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit(euclidean_only_dot(a,b))
5.25 ms ± 330 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

то есть 85% времени уходит на это.

Когда вы смотрите на код нумбы, это выглядит как несколько странная / необычная / более сложная версия умножения матрицы на матрицу - можно было увидетьнапример, те же три цикла.

Итак, вы пытаетесь превзойти один из лучших оптимизированных алгоритмов.Вот, например, кто-то пытается это сделать и терпит неудачу .Моя установка использует MKL-версию Intel, которая должна быть более сложной, чем реализация по умолчанию, которую можно найти здесь .

Иногда, после всего веселья, нужно признать, что собственное «заново изобретенное колесо» не так хорошо, как современное колесо… но только тогда можно по-настоящему оценитьего производительность.

...