web-dev-qa-db-fra.com

blas multithread en python / numpy

J'essaie d'implémenter un grand nombre de multiplications matrice-matrice en Python. Au départ, je supposais que NumPy utiliserait automatiquement mes bibliothèques BLAS filetées depuis que je l'ai construit sur ces bibliothèques. Cependant, quand je regarde top ou quelque chose d'autre, il semble que le code n'utilise pas du tout de thread.

Avez-vous des idées sur ce qui ne va pas ou sur ce que je peux faire pour utiliser facilement les performances BLAS?

44
Lucas

NumPy n'utilise pas tous BLAS, seulement certaines fonctions - en particulier dot(), vdot() et innerproduct() et plusieurs fonctions du numpy.linalg module. Notez également que de nombreuses opérations NumPy sont limitées par la bande passante mémoire pour les grandes baies, il est donc peu probable qu'une implémentation optimisée apporte une amélioration. Le fait que le multi-threading puisse donner de meilleures performances si vous êtes limité par la bande passante mémoire dépend fortement de votre matériel.

17
Sven Marnach

J'ai déjà posté ceci dans un autre fil mais je pense que ça va mieux dans celui-ci:

MISE À JOUR (30.07.2014):

Je relance la référence sur notre nouveau HPC. Le matériel ainsi que la pile de logiciels ont changé par rapport à la configuration de la réponse d'origine.

J'ai mis les résultats dans une feuille de calcul Google (contient également les résultats de la réponse d'origine).

Matériel

Notre HPC possède deux nœuds différents, l'un avec les processeurs Intel Sandy Bridge et l'autre avec les nouveaux processeurs Ivy Bridge:

Sandy (MKL, OpenBLAS, ATLAS):

  • [~ # ~] cpu [~ # ~] : 2 x 16 Intel (R) Xeon (R) E2560 Sandy Bridge @ 2.00GHz (16 Cores )
  • [~ # ~] bélier [~ # ~] : 64 Go

Lierre (MKL, OpenBLAS, ATLAS):

  • [~ # ~] cpu [~ # ~] : 2 x 20 Intel (R) Xeon (R) E2680 V2 Ivy Bridge @ 2,80 GHz (20 Cœurs, avec HT = 40 cœurs)
  • [~ # ~] bélier [~ # ~] : 256 Go

Logiciel

La pile logicielle est pour les deux nœuds le sam. Au lieu de GotoBLAS2 , OpenBLAS est utilisé et il y a aussi un ATLAS multithread BLAS défini sur 8 threads (codé en dur).

  • [~ # ~] os [~ # ~] : Suse
  • Compilateur Intel : ictce-5.3.0
  • Numpy: 1.8.0
  • OpenBLAS: 0.2.6
  • ATLAS: : 3.8.4

Benchmark du produit scalaire

Le code de référence est le même que ci-dessous. Cependant, pour les nouvelles machines, j'ai également utilisé la référence pour les tailles de matrice 5000 et 8000 .
Le tableau ci-dessous inclut les résultats de référence de la réponse d'origine (renommé: MKL -> Nehalem MKL, Netlib Blas -> Nehalem Netlib BLAS, etc.)

Matrix multiplication (sizes=[1000,2000,3000,5000,8000])

Performances à un seul thread:  single threaded performance

Performance multi-thread (8 threads):  multi-threaded (8 threads) performance

Threads vs Matrix size (Ivy Bridge MKL) Matrix-size vs threads

Suite Benchmark

benchmark suite

Performances à un seul thread:  enter image description here

Performances multi-thread (8 threads):  enter image description here

Conclusion

Les nouveaux résultats de référence sont similaires à ceux de la réponse d'origine. OpenBLAS et [~ # ~] mkl [~ # ~] effectuer au même niveau, à l'exception du test Eigenvalue . Le test Eigenvalue ne fonctionne que raisonnablement bien sur OpenBLAS dans mode thread unique . En mode multi-thread, les performances sont moins bonnes.

Le "Tableau de la taille de la matrice par rapport aux threads" montre également que bien que MKL et OpenBLAS évoluent généralement bien avec le nombre de cœurs/threads, cela dépend de la taille de la matrice. Pour les petites matrices, l'ajout de cœurs supplémentaires n'améliorera pas beaucoup les performances.

Il y a également une augmentation des performances d'environ 30% de Sandy Bridge à Ivy Bridge ce qui pourrait être dû à une fréquence d'horloge plus élevée (+ 0,8 GHz) et/ou à une meilleure architecture.


Réponse originale (04.10.2011):

Il y a quelque temps, j'ai dû optimiser certains calculs/algorithmes d'algèbre linéaire qui étaient écrits en python en utilisant numpy et BLAS donc j'ai comparé/testé différentes configurations numpy/BLAS.

Plus précisément, j'ai testé:

  • Numpy avec ATLAS
  • Numpy avec GotoBlas2 (1.13)
  • Numpy avec MKL (11.1/073)
  • Numpy avec Accelerate Framework (Mac OS X)

J'ai exécuté deux benchmarks différents:

  1. produit scalaire simple de matrices de différentes tailles
  2. Suite de référence qui peut être trouvée ici .

Voici mes résultats:

Machines

Linux (MKL, ATLAS, No-MKL, GotoBlas2):

  • [~ # ~] os [~ # ~] : Ubuntu Lucid 10.4 64 bits.
  • [~ # ~] cpu [~ # ~] : 2 x 4 Intel (R) Xeon (R) E5504 à 2,00 GHz (8 cœurs)
  • [~ # ~] bélier [~ # ~] : 24 Go
  • Compilateur Intel : 11.1/073
  • Scipy : 0,8
  • Numpy : 1,5

Mac Book Pro (Accelerate Framework):

  • [~ # ~] os [~ # ~] : Mac OS X Snow Leopard (10.6)
  • [~ # ~] cpu [~ # ~] : 1 Intel Core 2 Duo 2,93 Ghz (2 cœurs)
  • [~ # ~] bélier [~ # ~] : 4 Go
  • Scipy : 0,7
  • Numpy : 1,3

Serveur Mac (Accelerate Framework):

  • [~ # ~] os [~ # ~] : Mac OS X Snow Leopard Server (10.6)
  • [~ # ~] cpu [~ # ~] : 4 X Intel (R) Xeon (R) E5520 @ 2,26 Ghz (8 cœurs)
  • [~ # ~] bélier [~ # ~] : 4 Go
  • Scipy : 0,8
  • Numpy : 1.5.1

Benchmark des produits

Code :

import numpy as np
a = np.random.random_sample((size,size))
b = np.random.random_sample((size,size))
%timeit np.dot(a,b)

Résultats :

 Système | taille = 1000 | taille = 2000 | taille = 3000 | 
 netlib BLAS | 1350 ms | 10900 ms | 39200 ms | 
 ATLAS (1 CPU) | 314 ms | 2560 ms | 8700 ms | 
 MKL (1 CPU) | 268 ms | 2110 ms | 7120 ms | 
 MKL (2 CPU) |  - | 3660 ms | 
 MKL (8 CPU) | 39 ms | 319 ms | 1000 ms | 
 GotoBlas2 (1 CPU) | 266 ms | 2100 ms | 7280 ms | 
 GotoBlas2 (2 CPU) | 139 ms | 1009 ms | 3690 ms | 
 GotoBlas2 (8 CPU) | 54 ms | 389 ms | 1250 ms | 
 Mac OS X (1 CPU) | 143 ms | 1060 ms | 3605 ms | 
 Mac Server (1 CPU) | 92 ms | 714 ms | 2130 ms | 

Dot product benchmark - chart

Suite Benchmark

Code :
Pour plus d'informations sur la suite de référence, voir --- (ici
.

Résultats :

 Système | valeurs propres | svd | det | inv | dot | 
 netlib BLAS | 1688 ms | 13102 ms | 438 ms | 2155 ms | 3522 ms | 
 ATLAS (1 CPU) | 1210 ms | 5897 ms | 170 ms | 560 ms | 893 ms | 
 MKL (1 CPU) | 691 ms | 4475 ms | 141 ms | 450 ms | 736 ms | 
 MKL (2 CPU) | 552 ms | 2718 ms | 96 ms | 267 ms | 423 ms | 
 MKL (8 CPU) | 525 ms | 1679 ms | 60 ms | 137 ms | 197 ms | 
 GotoBlas2 (1 CPU) | 2124 ms | 4636 ms | 147 ms | 456 ms | 743 ms | 
 GotoBlas2 (2 CPU) | 1560 ms | 3278 ms | 116 ms | 295 ms | 460 ms | 
 GotoBlas2 (8 CPU) | 741 ms | 2914 ms | 82 ms | 262 ms | 192 ms | 
 Mac OS X (1 CPU) | 948 ms | 4339 ms | 151 ms | 318 ms | 566 ms | 
 Mac Server (1 CPU) | 1033 ms | 3645 ms | 99 ms | 232 ms | 342 ms | 

Benchmark suite - chart

Installation

L'installation de [~ # ~] mkl [~ # ~] comprenait l'installation de la suite complète de compilateurs Intel, qui est assez simple. Cependant, en raison de certains bugs/problèmes, la configuration et la compilation de numpy avec le support MKL était un peu compliquée.

GotoBlas2 est un petit paquet qui peut être facilement compilé comme une bibliothèque partagée. Cependant, à cause d'un bug vous devez recréer la bibliothèque partagée après l'avoir construite afin de l'utiliser avec numpy.
En plus de ce bâtiment, il ne fonctionnait pas pour une plate-forme à cibles multiples. J'ai donc dû créer un fichier . So pour chaque plateforme pour laquelle je veux avoir une libgoto2.so optimisée fichier.

Si vous installez numpy depuis le référentiel d'Ubuntu, il installera et configurera automatiquement numpy pour utiliser [~ # ~] atlas [~ # ~] . L'installation de l'atlas [~ # ~] [~ # ~] à partir de la source peut prendre un certain temps et nécessite des étapes supplémentaires (fortran, etc.).

Si vous installez numpy sur une machine Mac OS X avec Fink ou Ports Mac , il configurera numpy pour utiliser [~ # ~] atlas [~ # ~] ou Accelerate Framework d'Apple . Vous pouvez vérifier en exécutant ldd sur le fichier numpy.core._dotblas ou en appelant numpy.show_config () .

Conclusions

[~ # ~] mkl [~ # ~] donne les meilleurs résultats, suivi de près GotoBlas2 .
Dans le test de valeurs propres , GotoBlas2 fonctionne étonnamment moins bien que prévu. Je ne sais pas pourquoi c'est le cas.
Accelerate Framework d'Apple fonctionne vraiment bien, en particulier en mode thread unique (par rapport aux autres implémentations BLAS).

GotoBlas2 et [~ # ~] mkl [~ # ~] échelle très bien avec le nombre de fils. Donc, si vous devez gérer de grandes matrices, le faire fonctionner sur plusieurs threads vous aidera beaucoup.

Dans tous les cas, n'utilisez pas l'implémentation par défaut de netlib blas car elle est beaucoup trop lente pour un travail de calcul sérieux.

Sur notre cluster, j'ai également installé ACML d'AMD et les performances étaient similaires à [~ # ~] mkl [~ # ~ ] et GotoBlas2 . Je n'ai pas de chiffres difficiles.

Personnellement, je recommanderais d'utiliser GotoBlas2 car il est plus facile à installer et gratuit.

Si vous souhaitez coder en C++/C, consultez également Eigen qui est censé surpasser MKL/GotoBlas2 dans certains - cases et est également assez facile à utiliser.

105
Ümit

Il est possible que parce que la multiplication Matrix x Matrix soit contrainte par la mémoire, l'ajout de cœurs supplémentaires sur la même hiérarchie de mémoire ne vous donne pas grand-chose. Bien sûr, si vous voyez une accélération substantielle lorsque vous passez à votre implémentation Fortran, je peux me tromper.

Je crois comprendre que la mise en cache appropriée est beaucoup plus importante pour ce type de problèmes que la puissance de calcul. Vraisemblablement BLAS le fait pour vous.

Pour un test simple, vous pouvez essayer d'installer Enthought's python pour comparaison. Ils sont liés à Intel Math Kernel Library qui, je crois, exploite plusieurs cœurs si disponible.

2
MRocklin

Avez-vous entendu parler de MAGMA? Algèbre matricielle sur GPU et architecture multicœur http://icl.cs.utk.edu/magma/

Le projet MAGMA vise à développer une bibliothèque d'algèbre linéaire dense similaire à LAPACK mais pour des architectures hétérogènes/hybrides, à commencer par les systèmes actuels "Multicore + GPU".

1
Lindon