Accélération de numpy.dot
-
13-11-2019 - |
Question
j'ai un numpy
script qui passe environ 50 % de son temps d'exécution dans le code suivant :
s = numpy.dot(v1, v1)
où
v1 = v[1:]
et v
est un 1D de 4000 éléments ndarray
de float64
stocké dans la mémoire contiguë (v.strides
est (8,)
).
Des suggestions pour accélérer cela ?
modifier C'est sur le matériel Intel.Voici le résultat de mon 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
La solution
Vos tableaux ne sont pas très grands, donc ATLAS ne fait probablement pas grand-chose.Quels sont vos horaires pour le programme Fortran suivant ?En supposant qu'ATLAS ne fait pas grand-chose, cela devrait vous donner une idée de la vitesse à laquelle dot() pourrait être s'il n'y avait pas de surcharge python.Avec gfortran -O3 j'obtiens des vitesses de 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
Autres conseils
Peut-être que le coupable copie les tableaux transmis à point.
Comme l'a dit Sven, le point le produit repose sur les opérations BLAS.Ces opérations nécessitent des tableaux stockés dans un ordre C contigu.Si les deux tableaux sont passés à point êtes en C_CONTIGUOUS, vous devriez voir de meilleures performances.
Bien sûr, si vos deux tableaux passés au point sont effectivement 1D (8,), alors vous devriez voir les deux les indicateurs C_CONTIGUOUS ET F_CONTIGUOUS définis sur True ;mais s'ils le sont (1, 8), alors vous pouvez voir un ordre mixte.
>>> 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
Une alternative:utilisez _GEMM de BLAS, qui est exposé via le module, scipy.linalg.fblas.(Les deux tableaux, A et B, sont évidemment dans l'ordre Fortran car fblas est utilisé.)
from scipy.linalg import fblas as FB
X = FB.dgemm(alpha=1., a=A, b=B, trans_b=True)
La seule chose à laquelle je peux penser pour accélérer cela est de m'assurer que votre installation NumPy est compilée avec une bibliothèque BLAS optimisée (comme ATLAS). numpy.dot()
est l'une des rares fonctions NumPy à utiliser BLAS.
numpy.dot utilisera le multithreading s'il est compilé correctement.Assurez-vous que c'est le cas avec le dessus.Je connais des cas où les gens n'ont pas fait fonctionner le multithreading dans numpy avec atlas.De plus, cela vaut la peine d'essayer d'utiliser une version numpy compilée avec les bibliothèques Intel mkl.Ils incluent des routines blas qui sont censées être plus rapides qu'Atlas sur le matériel Intel.Vous pouvez essayer la distribution Python d'Enthought.Contient tout cela et est gratuit pour les personnes disposant d’un compte de messagerie edu.