Je fais des benchmarks avec CUDA, C ++, C #, Java et j'utilise MATLAB pour la vérification et la génération de matrices. Lorsque j'effectue une multiplication matricielle avec MATLAB, des 2048x2048
matrices encore plus grandes sont multipliées presque instantanément.
1024x1024 2048x2048 4096x4096
--------- --------- ---------
CUDA C (ms) 43.11 391.05 3407.99
C++ (ms) 6137.10 64369.29 551390.93
C# (ms) 10509.00 300684.00 2527250.00
Java (ms) 9149.90 92562.28 838357.94
MATLAB (ms) 75.01 423.10 3133.90
Seul CUDA est compétitif, mais je pensais qu'au moins C ++ serait un peu proche et pas 60 fois plus lent. Je ne sais pas non plus quoi penser des résultats C #. L'algorithme est exactement le même que C ++ et Java, mais il y a un bond 2048
de géant 1024
.
Comment MATLAB effectue-t-il une multiplication matricielle si rapidement?
Code C ++:
float temp = 0;
timer.start();
for(int j = 0; j < rozmer; j++)
{
for (int k = 0; k < rozmer; k++)
{
temp = 0;
for (int m = 0; m < rozmer; m++)
{
temp = temp + matice1[j][m] * matice2[m][k];
}
matice3[j][k] = temp;
}
}
timer.stop();
Réponses:
Voici mes résultats en utilisant MATLAB R2011a + Parallel Computing Toolbox sur une machine avec une Tesla C2070:
MATLAB utilise des bibliothèques hautement optimisées pour la multiplication matricielle, raison pour laquelle la multiplication matricielle simple MATLAB est si rapide. La
gpuArray
version utilise MAGMA .Mise à jour à l'aide de R2014a sur une machine avec un Tesla K20c, et les nouvelles fonctions
timeit
etgputimeit
:Mise à jour à l'aide de R2018b sur une machine WIN64 avec 16 cœurs physiques et un Tesla V100:
(NB: à un moment donné (j'oublie quand exactement) est
gpuArray
passé de MAGMA à cuBLAS - MAGMA est encore utilisé pour certainesgpuArray
opérations)la source
Ce genre de question est récurrent et devrait recevoir une réponse plus claire que "MATLAB utilise des bibliothèques hautement optimisées" ou "MATLAB utilise le MKL" pour une fois sur Stack Overflow.
L'histoire:
La multiplication matricielle (avec matrice-vecteur, multiplication vecteur-vecteur et plusieurs des décompositions matricielles) est (sont) les problèmes les plus importants en algèbre linéaire. Les ingénieurs résolvent ces problèmes avec les ordinateurs depuis les premiers jours.
Je ne suis pas un expert en histoire, mais apparemment à l'époque, tout le monde vient de réécrire sa version FORTRAN avec de simples boucles. Une certaine normalisation est alors venue avec l'identification des «noyaux» (routines de base) dont la plupart des problèmes d'algèbre linéaire avaient besoin pour être résolus. Ces opérations de base ont ensuite été standardisées dans une spécification appelée: Basic Linear Algebra Subprograms (BLAS). Les ingénieurs pourraient alors appeler ces routines BLAS standard et bien testées dans leur code, facilitant ainsi leur travail.
BLAS:
BLAS a évolué du niveau 1 (la première version définissant les opérations vectorielles scalaires et vectorielles) au niveau 2 (opérations vectorielles-matrices) au niveau 3 (opérations matrices-matrices), et a fourni de plus en plus de «noyaux» donc standardisés plus et plus des opérations fondamentales d'algèbre linéaire. Les implémentations originales de FORTRAN 77 sont toujours disponibles sur le site Web de Netlib .
Vers de meilleures performances:
Ainsi, au fil des années (notamment entre les versions BLAS niveau 1 et niveau 2: début des années 80), le matériel a changé, avec l'avènement des opérations vectorielles et des hiérarchies de cache. Ces évolutions ont permis d'augmenter considérablement les performances des sous-programmes BLAS. Différents éditeurs sont alors venus avec leur implémentation de routines BLAS qui étaient de plus en plus efficaces.
Je ne connais pas toutes les implémentations historiques (je ne suis pas né ou enfant à l'époque), mais deux des plus notables sont sorties au début des années 2000: l'Intel MKL et le GotoBLAS. Votre Matlab utilise l'Intel MKL, qui est un très bon BLAS optimisé, et cela explique les excellentes performances que vous voyez.
Détails techniques sur la multiplication matricielle:
Alors pourquoi Matlab (le MKL) est-il si rapide à
dgemm
(multiplication matrice-matrice générale à double précision)? En termes simples: parce qu'il utilise la vectorisation et une bonne mise en cache des données. En termes plus complexes: voir l' article fourni par Jonathan Moore.Fondamentalement, lorsque vous effectuez votre multiplication dans le code C ++ que vous avez fourni, vous n'êtes pas du tout compatible avec le cache. Puisque je soupçonne que vous avez créé un tableau de pointeurs vers des tableaux de lignes, vos accès dans votre boucle interne à la k-ème colonne de "matice2":
matice2[m][k]
sont très lents. En effet, lorsque vous y accédezmatice2[0][k]
, vous devez récupérer le k-ième élément du tableau 0 de votre matrice. Ensuite, dans l'itération suivante, vous devez accédermatice2[1][k]
, qui est le k-ième élément d'un autre tableau (le tableau 1). Ensuite, dans l'itération suivante, vous accédez à un autre tableau, et ainsi de suite ... Comme la matrice entièrematice2
ne peut pas tenir dans les caches les plus élevés (ses8*1024*1024
octets sont grands), le programme doit récupérer l'élément souhaité de la mémoire principale, perdant beaucoup de temps.Si vous venez de transposer la matrice, afin que les accès soient dans des adresses mémoire contiguës, votre code s'exécuterait déjà beaucoup plus rapidement car maintenant le compilateur peut charger des lignes entières dans le cache en même temps. Essayez simplement cette version modifiée:
Vous pouvez donc voir à quel point la seule localité du cache a considérablement augmenté les performances de votre code. Désormais, les
dgemm
implémentations réelles exploitent cela à un niveau très étendu: elles effectuent la multiplication sur des blocs de la matrice définie par la taille du TLB (Translation lookaside buffer, long story short: what can effective cached), de sorte qu'ils streament vers le processeur exactement la quantité de données qu'il peut traiter. L'autre aspect est la vectorisation, ils utilisent les instructions vectorisées du processeur pour un débit d'instructions optimal, ce que vous ne pouvez pas vraiment faire à partir de votre code C ++ multiplateforme.Enfin, les personnes prétendant que c'est à cause de l'algorithme de Strassen ou Coppersmith – Winograd ont tort, ces deux algorithmes ne sont pas implémentables en pratique, à cause des considérations matérielles mentionnées ci-dessus.
la source
Voilà pourquoi . MATLAB n'effectue pas de multiplication de matrice naïve en boucle sur chaque élément comme vous l'avez fait dans votre code C ++.
Bien sûr, je suppose que vous venez d'utiliser
C=A*B
au lieu d'écrire vous-même une fonction de multiplication.la source
Matlab a incorporé LAPACK il y a quelque temps, donc je suppose que leur multiplication matricielle utilise quelque chose au moins aussi rapide. Le code source et la documentation de LAPACK sont facilement disponibles.
Vous pouvez également consulter l'article de Goto et Van De Geijn "Anatomy of High-Performance Matrix Multiplication" sur http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.1785&rep=rep1&type=pdf
la source
La réponse est que les bibliothèques LAPACK et BLAS rendent MATLAB incroyablement rapide lors des opérations matricielles, pas de code propriétaire par les gens de MATLAB.
Utilisez les bibliothèques LAPACK et / ou BLAS dans votre code C ++ pour les opérations matricielles et vous devriez obtenir des performances similaires à celles de MATLAB. Ces bibliothèques devraient être disponibles gratuitement sur n'importe quel système moderne et certaines parties ont été développées au fil des décennies dans le milieu universitaire. Notez qu'il existe plusieurs implémentations, y compris certaines sources fermées telles que Intel MKL .
Une discussion sur la façon dont BLAS obtient des performances élevées est disponible ici.
BTW, c'est une douleur sérieuse dans mon expérience d'appeler les bibliothèques LAPACK directement à partir de c (mais ça vaut le coup). Vous devez lire la documentation TRÈS précisément.
la source
Lorsque vous effectuez une multiplication matricielle, vous utilisez une méthode de multiplication naïve qui prend du temps
O(n^3)
.Il existe un algorithme de multiplication matricielle qui prend
O(n^2.4)
. Ce qui signifie quen=2000
votre algorithme nécessite environ 100 fois plus de calculs que le meilleur algorithme.Vous devriez vraiment consulter la page wikipedia pour la multiplication matricielle pour plus d'informations sur les moyens efficaces de l'implémenter.
la source
Selon votre version de Matlab, je pense qu'il utilise déjà votre GPU.
Autre chose; Matlab garde une trace de nombreuses propriétés de votre matrice; que ce soit sa diagonale, hermétienne, etc., et spécialise ses algorithmes basés sur celle-ci. Peut-être que sa spécialisation est basée sur la matrice zéro que vous lui transmettez, ou quelque chose comme ça? Peut-être est-ce la mise en cache des appels de fonction répétés, ce qui gâche votre minutage? Peut-être optimise-t-il les produits matriciels inutilisés répétés?
Pour éviter que de telles choses ne se produisent, utilisez une matrice de nombres aléatoires et assurez-vous de forcer l'exécution en imprimant le résultat sur l'écran ou le disque ou quelque chose de semblable.
la source
A.*B
fait. Donc, le PO se moque presque certainement de quelque chose.MATLAB utilise une implémentation hautement optimisée de LAPACK d'Intel connue sous le nom de Intel Math Kernel Library (Intel MKL) - en particulier la fonction dgemm . La vitesse Cette bibliothèque tire parti des fonctionnalités du processeur, notamment des instructions SIMD et des processeurs multicœurs. Ils ne documentent pas l'algorithme spécifique qu'ils utilisent. Si vous appelez Intel MKL à partir de C ++, vous devriez voir des performances similaires.
Je ne sais pas quelle bibliothèque MATLAB utilise pour la multiplication GPU, mais probablement quelque chose comme nVidia CUBLAS .
la source
La réponse générale à "Pourquoi matlab est-il plus rapide à faire xxx que d'autres programmes" est que matlab a beaucoup de fonctions intégrées et optimisées.
Les autres programmes utilisés n'ont souvent pas ces fonctions, de sorte que les gens appliquent leurs propres solutions créatives, qui sont étonnamment plus lentes que le code optimisé professionnellement.
Cela peut être interprété de deux manières:
1) La méthode commune / théorique: Matlab n'est pas beaucoup plus rapide, vous faites simplement le mauvais test
2) La manière réaliste: Pour ce truc, Matlab est plus rapide en pratique parce que les langages comme le c ++ sont trop facilement utilisés de manière inefficace.
la source
Le contraste net n'est pas seulement dû à l'incroyable optimisation de Matlab (comme déjà discuté par de nombreuses autres réponses), mais aussi à la façon dont vous avez formulé la matrice en tant qu'objet.
Il semble que vous ayez fait une liste de listes à matrice? Une liste de listes contient des pointeurs vers des listes qui contiennent ensuite vos éléments de matrice. Les emplacements des listes contenues sont attribués arbitrairement. Lorsque vous parcourez votre premier index (numéro de ligne?), Le temps d'accès à la mémoire est très important. En comparaison, pourquoi n'essayez-vous pas d'implémenter la matrice sous forme de liste / vecteur unique en utilisant la méthode suivante?
Et
Le même algorithme de multiplication doit être utilisé pour que le nombre de flop soit le même. (n ^ 3 pour les matrices carrées de taille n)
Je vous demande de le chronométrer pour que le résultat soit comparable à ce que vous aviez auparavant (sur la même machine). Avec la comparaison, vous montrerez exactement à quel point le temps d'accès à la mémoire peut être important!
la source
C'est lent en C ++ car vous n'utilisez pas le multithreading. Essentiellement, si A = BC, où ce sont toutes des matrices, la première ligne de A peut être calculée indépendamment de la 2ème ligne, etc. Si A, B et C sont toutes des matrices n par n, vous pouvez accélérer la multiplication de un facteur de n ^ 2, comme
a_ {i, j} = somme_ {k} b_ {i, k} c_ {k, j}
Si vous utilisez, par exemple, Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ], le multithreading est intégré et le nombre de threads est réglable.
la source
Parce que MATLAB est un langage de programmation initialement développé pour l'algèbre linéaire numérique (manipulations matricielles), qui possède des bibliothèques spécialement développées pour les multiplications matricielles. Et maintenant, MATLAB peut également utiliser les GPU (Graphics Processing Unit) pour cela en plus.
Et si nous regardons vos résultats de calcul:
alors nous pouvons voir que non seulement MATLAB est si rapide en multiplication matricielle: CUDA C (langage de programmation de NVIDIA) a de meilleurs résultats que MATLAB. CUDA C a également des bibliothèques spécialement développées pour les multiplications matricielles et utilise les GPU.
Brève histoire de MATLAB
Qu'est-ce que CUDA C
CUDA C utilise également des bibliothèques spécialement développées pour les multiplications matricielles comme OpenGL (Open Graphics Library). Il utilise également GPU et Direct3D (sur MS Windows).
Comparaison des vitesses d'exécution du processeur et du GPU
De l'introduction au guide de programmation CUDA C:
Lecture avancée
Sous-programmes d'algèbre linéaire de base (BLAS)
Anatomy of High-Performance Matrix Multiplication , de Kazushige Goto et Robert A. Van De Geijn
Quelques facs intéressants
la source
"additionally"
. Cela signifie: il peut être utilisé. Cela signifie également que la multiplication matricielle normale utilise toujours des bibliothèques de logiciels. Pensez-vous que je dois modifier mon message pour être plus compréhensible? Merci pour vos commentaires!