Accelerando Numpy.dot
-
13-11-2019 - |
Domanda
io ho un numpy
Script che spende circa il 50% del suo runtime nel seguente codice:
s = numpy.dot(v1, v1)
dove
v1 = v[1:]
e v
è un 1D da 4000 elementi ndarray
di float64
memorizzato in memoria contigua (v.strides
è (8,)
).
Qualche suggerimento per accelerare questo?
modificare Questo è su hardware Intel. Ecco l'output del mio 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
Soluzione
I tuoi array non sono molto grandi, quindi Atlas probabilmente non sta facendo molto. Quali sono i tuoi tempi per il seguente programma Fortran? Supponendo che Atlas non stia facendo molto, questo dovrebbe darti un'idea di quanto velocemente () potrebbe essere se non ci fosse un sovraccarico di Python. Con Gfortran -O3 ottengo velocità di 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
Altri suggerimenti
Forse il colpevole sta copiando gli array passati punto.
Come ha detto Sven, il punto Il prodotto si basa su operazioni BLAS. Queste operazioni richiedono array memorizzati in ordine C contiguo. Se entrambi gli array sono passati a punto sono in c_contigue, dovresti vedere prestazioni migliori.
Naturalmente, se i tuoi due array sono passati al punto sono effettivamente 1D (8), allora dovresti vedere Entrambi le flag C_contigue e f_contigue impostate su true; Ma se sono (1, 8), allora puoi vedere l'ordine misto.
>>> 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
Un'alternativa: usa _gemm da blas, che è esposto attraverso il modulo, Scipy.Linalg.fblas. (I due array, A e B, sono ovviamente in ordine di Fortran perché fblas viene usato.)
from scipy.linalg import fblas as FB
X = FB.dgemm(alpha=1., a=A, b=B, trans_b=True)
L'unica cosa a cui riesco a pensare per accelerare questo è assicurarsi che l'installazione numpy sia compilata su una libreria BLAS ottimizzata (come Atlas). numpy.dot()
è una delle poche funzioni numpy che utilizzano Blas.
numpy.dot utilizzerà multithreading se compilato correttamente. Assicurati che lo faccia con TOP. Conosco casi in cui le persone non hanno ottenuto il multithreading in Numpy con Atlas per funzionare. Inoltre, vale la pena provare a utilizzare una versione numpy che viene compilata contro le librerie Intel MKL. Includono routine BLAS che dovrebbero essere più veloci dell'Atlante sull'hardware Intel. Potresti provare Python Distro di enthought. Contiene tutto questo ed è gratuito per le persone con un account e -mail EDU.