Ускорение numpy.dot

У меня есть скрипт numpy, который тратит около 50% времени выполнения на следующий код:

s = numpy.dot(v1, v1)

куда

v1 = v[1:]

и v представляет собой 4000-элементный 1D ndarray из float64, хранящийся в непрерывной памяти (v.strides равен (8,)).

Любые предложения по ускорению этого?

изменить Это на оборудовании Intel. Вот результат моего numpy.show_config():

atlas_threads_info:
    libraries = ['lapack', 'ptf77blas', 'ptcblas', 'atlas']
    library_dirs = ['/usr/local/atlas-3.9.16/lib']
    language = f77
    include_dirs = ['/usr/local/atlas-3.9.16/include']

blas_opt_info:
    libraries = ['ptf77blas', 'ptcblas', 'atlas']
    library_dirs = ['/usr/local/atlas-3.9.16/lib']
    define_macros = [('ATLAS_INFO', '"\\"3.9.16\\""')]
    language = c
    include_dirs = ['/usr/local/atlas-3.9.16/include']

atlas_blas_threads_info:
    libraries = ['ptf77blas', 'ptcblas', 'atlas']
    library_dirs = ['/usr/local/atlas-3.9.16/lib']
    language = c
    include_dirs = ['/usr/local/atlas-3.9.16/include']

lapack_opt_info:
    libraries = ['lapack', 'ptf77blas', 'ptcblas', 'atlas']
    library_dirs = ['/usr/local/atlas-3.9.16/lib']
    define_macros = [('ATLAS_INFO', '"\\"3.9.16\\""')]
    language = f77
    include_dirs = ['/usr/local/atlas-3.9.16/include']

lapack_mkl_info:
  NOT AVAILABLE

blas_mkl_info:
  NOT AVAILABLE

mkl_info:
  NOT AVAILABLE

person NPE    schedule 13.05.2011    source источник
comment
Хотите дать результаты времени? FWIW, в моей скромной машине точка (., .) со случайным вектором формы (4000) займет около 6 мкс. Спасибо   -  person eat    schedule 13.05.2011
comment
@eat: та же операция на моей машине занимает менее 5 мс. Я делаю много этого, и они складываются.   -  person NPE    schedule 13.05.2011
comment
Итак, одиночный dot кажется достаточно эффективным. Однако, если вы хотите показать нам больше кода, кто-то может узнать, как оптимизировать вычисления. Спасибо   -  person eat    schedule 13.05.2011
comment
@tillsten: Да, спасибо, в несколько раз медленнее (вероятно, из-за использования временного массива).   -  person NPE    schedule 13.05.2011
comment
да, надо было сначала самому попробовать   -  person tillsten    schedule 13.05.2011
comment
@NPE, я не понял ответа. Я столкнулся с аналогичной проблемой (stackoverflow.com/questions/26609475/), и я хотел бы знать, как вы это поняли   -  person Ofer Helman    schedule 28.10.2014
comment
@OferHelman: Это было довольно давно (3,5 года), и, к сожалению, я не совсем помню. :-( Однако я, кажется, помню, что в итоге я использовал Intel MKL. Сделал ли он что-нибудь для этой конкретной проблемы, я не уверен.   -  person NPE    schedule 28.10.2014


Ответы (4)


Ваши массивы не очень большие, поэтому ATLAS, вероятно, мало что делает. Каковы ваши сроки для следующей программы Fortran? Предполагая, что ATLAS мало что делает, это должно дать вам представление о том, насколько быстрой может быть dot(), если бы не было никаких накладных расходов на Python. С gfortran -O3 я получаю скорость 5 +/- 0,5 мкс.

    program test

    real*8 :: x(4000), start, finish, s
    integer :: i, j
    integer,parameter :: jmax = 100000

    x(:) = 4.65
    s = 0.
    call cpu_time(start)
    do j=1,jmax
        s = s + dot_product(x, x)
    enddo
    call cpu_time(finish)
    print *, (finish-start)/jmax * 1.e6, s

    end program test
person matt    schedule 13.05.2011

Возможно, виновато копирование массивов, переданных в dot.

Как сказал Свен, продукт dot основан на операциях BLAS. Для этих операций требуются массивы, хранящиеся в непрерывном порядке C. Если оба массива, переданные в dot, находятся в C_CONTIGUOUS, вы должны увидеть более высокую производительность.

Конечно, если ваши два массива, переданные в точку, действительно являются одномерными (8,), то вы должны увидеть, что оба флаги C_CONTIGUOUS и F_CONTIGUOUS установлены в значение True; но если они (1, 8), то вы можете увидеть смешанный порядок.

>>> w = NP.random.randint(0, 10, 100).reshape(100, 1)
>>> w.flags
   C_CONTIGUOUS : True
   F_CONTIGUOUS : False
   OWNDATA : False
   WRITEABLE : True
   ALIGNED : True
   UPDATEIFCOPY : False


Альтернативный вариант: используйте _GEMM из BLAS, который доступен через модуль scipy.linalg.fblas. (Два массива, A и B, очевидно, расположены в порядке Фортрана, поскольку используется fblas.)

from scipy.linalg import fblas as FB
X = FB.dgemm(alpha=1., a=A, b=B, trans_b=True)
person doug    schedule 13.05.2011
comment
Просто для ясности: входной массив — 1D (а выход — скаляр). - person NPE; 13.05.2011

Единственное, что я могу придумать, чтобы ускорить это, — убедиться, что ваша установка NumPy скомпилирована с оптимизированной библиотекой BLAS (например, ATLAS). numpy.dot() — одна из немногих функций NumPy, использующих BLAS.

person Sven Marnach    schedule 13.05.2011
comment
Хорошее предложение (+1). Я обновил вопрос своей конфигурацией numpy. Похоже, он был построен против ATLAS. - person NPE; 13.05.2011
comment
@aix: Ваша конфигурация выглядит нормально для меня (хотя я не совсем уверен, как ее интерпретировать :) Если подумать, когда ваш код тратит большую часть своего времени на умножение векторов среднего размера, вы, вероятно, работаете на пределе памяти. пропускная способность, поэтому любая оптимизация приведет лишь к тому, что процессоры еще дольше будут ждать новых данных. - person Sven Marnach; 13.05.2011

numpy.dot будет использовать многопоточность, если скомпилирован правильно. Убедитесь, что он работает с top. Я знаю случаи, когда у людей не работала многопоточность в numpy w/atlas. Кроме того, стоит попробовать использовать версию numpy, скомпилированную с библиотеками Intel MKL. Они включают подпрограммы blas, которые должны быть быстрее, чем atlas на оборудовании Intel. Вы можете попробовать дистрибутив enthought python. Содержит все это и является бесплатным для людей с учетной записью электронной почты edu.

person Lucas    schedule 14.05.2011
comment
Можете ли вы предоставить ссылку, где мы можем получить версию numpy, скомпилированную с библиотеками Intel MKL? - person Ofer Helman; 28.10.2014
comment
анаконда обычно так делает - person dermen; 27.11.2017