Ускорение 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.