Значительные различия в производительности в зависимости от числовых значений - PullRequest
0 голосов
/ 21 ноября 2018

Я обнаружил странную разницу в производительности при оценке выражения в Numpy.

Я выполнил следующий код:

import numpy as np
myarr = np.random.uniform(-1,1,[1100,1100])

, а затем

%timeit np.exp( - 0.5 * (myarr / 0.001)**2 )
>> 184 ms ± 301 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

и

%timeit np.exp( - 0.5 * (myarr / 0.1)**2 )
>> 12.3 ms ± 34.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Это почти в 15 раз быстрее вычисления во втором случае!Обратите внимание, что единственным отличием является коэффициент 0,1 или 0,001.

В чем причина такого поведения?Могу ли я что-то изменить, чтобы сделать первый расчет так же быстро, как второй?

Ответы [ 2 ]

0 голосов
/ 24 ноября 2018

Это может привести к денормализованным числам, которые замедляют вычисления.

Вы можете отключить денормализованные числа с помощью библиотеки daz:

import daz
daz.set_daz()

Дополнительная информация: x87 и SSE с плавающей точкой в ​​IA-32: Flush-To-Zero (FTZ) и Denormals-Are-Zero (DAZ) :

Во избежание проблем с сериализацией и производительностьюИз-за ненормальных значений и числа недостаточного значения используйте инструкции SSE и SSE2, чтобы установить режимы сброса в ноль и Denormals-Are-Zero в аппаратном обеспечении для обеспечения максимальной производительности для приложений с плавающей запятой.

Примечаниечто в 64-битном режиме вычисления с плавающей точкой используют инструкции SSE, а не x87.

0 голосов
/ 22 ноября 2018

Используйте Intel SVML

У меня нет работы numexpr с Intel SVML, но numexpr с рабочим SVML должен работать так же хорошо, как Numba.Тесты Numba показывают абсолютно то же самое поведение без SVML, но работают намного лучше с SVML.

Код

import numpy as np
import numba as nb

myarr = np.random.uniform(-1,1,[1100,1100])

@nb.njit(error_model="numpy",parallel=True)
def func(arr,div):
  return np.exp( - 0.5 * (myarr / div)**2 )

Время

#Core i7 4771
#Windows 7 x64
#Anaconda Python 3.5.5
#Numba 0.41 (compilation overhead excluded)
func(myarr,0.1)                      -> 3.6ms
func(myarr,0.001)                    -> 3.8ms

#Numba (set NUMBA_DISABLE_INTEL_SVML=1), parallel=True
func(myarr,0.1)                      -> 5.19ms
func(myarr,0.001)                    -> 12.0ms

#Numba (set NUMBA_DISABLE_INTEL_SVML=1), parallel=False
func(myarr,0.1)                      -> 16.7ms
func(myarr,0.001)                    -> 63.2ms

#Numpy (1.13.3), set OMP_NUM_THREADS=4
np.exp( - 0.5 * (myarr / 0.001)**2 ) -> 70.82ms
np.exp( - 0.5 * (myarr / 0.1)**2 )   -> 12.58ms

#Numpy (1.13.3), set OMP_NUM_THREADS=1
np.exp( - 0.5 * (myarr / 0.001)**2 ) -> 189.4ms
np.exp( - 0.5 * (myarr / 0.1)**2 )   -> 17.4ms

#Numexpr (2.6.8), no SVML, parallel
ne.evaluate("exp( - 0.5 * (myarr / 0.001)**2 )") ->17.2ms
ne.evaluate("exp( - 0.5 * (myarr / 0.1)**2 )")   ->4.38ms

#Numexpr (2.6.8), no SVML, single threaded
ne.evaluate("exp( - 0.5 * (myarr / 0.001)**2 )") ->50.85ms
ne.evaluate("exp( - 0.5 * (myarr / 0.1)**2 )")   ->13.9ms
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...