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

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

s = numpy.dot(v1, v1)

где

v1 = v[1:]

и v - это 4000-элементный 1D ndarray of float64, хранящийся в непрерывной памяти (v.strides is (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

Ответ 1

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

    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

Ответ 2

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

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

Конечно, если ваши два массива, переданные в точку, действительно являются 1D (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, очевидно, находятся в порядке Fortran, потому что используется fblas.)

from scipy.linalg import fblas as FB
X = FB.dgemm(alpha=1., a=A, b=B, trans_b=True)

Ответ 3

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

Ответ 4

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