Accélérez 100 fois numpy, scikit et pandas avec Rust et LLVM: entretien avec le développeur Weld

Bonjour, Habr! Je vous présente la traduction de l'article "Entretien avec le principal contributeur de Weld: accélération de 100% numpy, scikit et pandas avec Rust et LLVM" .

Après avoir travaillé pendant plusieurs semaines avec des outils de science des données en Python et R, j'ai commencé à me demander s'il existe une représentation intermédiaire (IR) comme CUDA qui peut être utilisée dans différents langages. Il doit y avoir quelque chose de mieux que la réimplémentation et l'optimisation des mêmes méthodes dans chaque langue. En plus de cela, il serait bien d'avoir un runtime commun pour optimiser l'ensemble du programme, plutôt que chaque fonction individuellement.

Après plusieurs jours de recherche et de test de divers projets, j'ai trouvé Weld(vous pouvez lire l' article académique ).

À ma grande surprise, l'un des auteurs Weld est Matei Zaharia (Matei Zaharia), le créateur de Spark.

J'ai donc contacté Shoumik Palkar , le principal contributeur de Weld, et je l'ai interviewé. Showmick est un étudiant diplômé au Département d'informatique de l'Université de Stanford, où il est entré sur les conseils de Matey Zakharia.

La soudure n'est pas encore prête pour une utilisation industrielle, mais très prometteuse. Si vous êtes intéressé par l'avenir de la science des données et de Rust en particulier, vous allez adorer cette interview.

Publicité de l'auteur de l'article original
image
«Not a Monad Tutorial», Weld . !

, mail@fcarrone.com @unbalancedparen.

Pourquoi Weld a-t-il été conçu, pour quels problèmes est-il résolu?


L'objectif de Weld est d'augmenter la productivité des applications qui utilisent des API de haut niveau telles que NumPy et Pandas. Le principal problème qu'il résout est les optimisations inter-fonctionnelles et inter-bibliothèques qui ne sont pas fournies par d'autres bibliothèques aujourd'hui. En particulier, de nombreuses bibliothèques largement utilisées ont des implémentations modernes d'algorithmes pour des fonctions individuelles (par exemple, l'algorithme de jointure rapide implémenté dans Pandas par C, ou la multiplication matricielle rapide dans NumPy), mais elles ne permettent pas d'optimiser la combinaison de ces fonctions. Par exemple, empêcher les analyses de mémoire inutiles lors de la multiplication de matrice suivie d'une agrégation.

Weld fournit un environnement d'exécution commun qui permet aux bibliothèques d'exprimer des calculs dans une représentation intermédiaire commune (IR). Cet IR peut ensuite être optimisé à l'aide de l'optimiseur du compilateur, puis compilé à la volée (JIT) en code machine parallèle avec des optimisations telles que la fusion de boucles, la vectorisation, etc. L'IR de Weld est initialement parallèle, de sorte que les programmes qui y sont exprimés peuvent toujours être parallélisés de manière triviale.

Nous avons également un nouveau projet appelé annotations fractionnées, qui sera intégré à Weld et conçu pour réduire la barrière à l'inclusion de telles optimisations dans les bibliothèques existantes.

Ne serait-il pas plus facile d'optimiser numpy, pandas et scikit? C'est beaucoup plus rapide?


Weld offre une optimisation de la combinaison de fonctions dans ces bibliothèques, tandis que l'optimisation des bibliothèques peut accélérer les appels de fonctions individuelles uniquement. En fait, bon nombre de ces bibliothèques sont déjà très bien optimisées pour chaque fonction individuelle, mais offrent des performances inférieures aux limites des équipements modernes, car elles n'utilisent pas le parallélisme ou n'utilisent pas efficacement la hiérarchie de la mémoire.

Par exemple, de nombreuses fonctions NumPy pour les tableaux multidimensionnels (ndarray) sont implémentées dans le langage C de bas niveau, mais chaque fonction nécessite une analyse complète des données d'entrée. Si ces tableaux ne rentrent pas dans les caches CPU, la plupart du temps d'exécution peut être consacré au chargement des données à partir de la mémoire principale, plutôt qu'à effectuer des calculs. Weld peut afficher des appels de fonction individuels et effectuer des optimisations, telles que la combinaison de boucles qui stockeront des données dans des caches ou des registres CPU. De telles optimisations peuvent améliorer les performances de plus d'un ordre de grandeur dans les systèmes multicœurs, car elles offrent une meilleure évolutivité.

image

Les intégrations des prototypes Weld avec Spark (en haut à gauche), NumPy (en haut à droite) et TensorFlow (en bas à gauche) montrent une amélioration jusqu'à 30 fois supérieure à leurs propres implémentations d'infrastructure sans modification du code de l'application utilisateur. L'optimisation entre bibliothèques de Pandas et NumPy (en bas à droite) peut améliorer les performances de deux ordres de grandeur.

Qu'est-ce que Baloo?


Baloo est une bibliothèque qui implémente un sous-ensemble de l'API Pandas utilisant Weld. Il a été développé par Radu Jica, un Master en CWI (Centrum Wiskunde & Informatica, Amsterdam). Le but de Baloo est d'appliquer les types d'optimisation ci-dessus aux pandas pour améliorer les performances à un seul thread, réduire l'utilisation de la mémoire et garantir la concurrence.

Weld / Baloo prend-il en charge les opérations externes (comme, par exemple, Dask) pour le traitement de données qui ne tiennent pas en mémoire?


Weld et Baloo ne prennent actuellement pas en charge les opérations externes (out-of-core, mémoire externe), même si nous serons heureux de recevoir le développement open source dans cette direction!

Pourquoi avez-vous choisi Rust et LLVM pour implémenter Weld? Êtes-vous venu à Rust tout de suite?


Nous avons choisi Rust parce que:

  • Il a un temps d'exécution minimal (en fait, il vérifie simplement les limites des tableaux) et est facile à intégrer dans d'autres langages tels que Java et Python
  • Il contient des paradigmes de programmation fonctionnels, tels que la correspondance de modèles, qui facilitent l'écriture de code, par exemple, pour optimiser le compilateur de correspondance de modèles
  • ( Rust crates), .

Nous avons choisi LLVM car il s'agit d'un framework de compilation open source largement utilisé et pris en charge. Nous générons LLVM directement au lieu de C / C ++, nous n'avons donc pas besoin du compilateur C. Cela réduit également le temps de compilation, car nous n'analysons pas le code C / C ++.

Rust n'était pas la première langue dans laquelle Weld était implémenté. La première implémentation était sur Scala, qui a été choisie en raison de ses types de données algébriques et de la présence d'une fonctionnalité aussi puissante que la correspondance de modèles. Cela a simplifié l'écriture de l'optimiseur, qui est la partie principale du compilateur. Notre optimiseur d'origine a été conçu comme Catalyst, un optimiseur extensible dans Spark SQL.

Nous nous sommes éloignés de Scala car il était trop difficile d'incorporer le langage basé sur JVM dans d'autres runtimes et langages.

Weld CPU GPU, RAPIDS, data science Python GPU?


La principale différence entre Weld et des systèmes tels que RAPIDS est qu'il vise à optimiser les applications contenant différents noyaux (fonctions en termes CUDA) en compilant à la volée, et non à optimiser les implémentations de fonctions individuelles. Par exemple, le backend Weld GPU compilera un seul noyau CUDA optimisé pour l'application finale, au lieu d'invoquer des noyaux séparés.

De plus, Weld IR est indépendant du matériel, ce qui lui permet d'être utilisé à la fois pour le GPU et le CPU, ainsi que pour les équipements non standard tels que les processeurs vectoriels.
Bien sûr, Weld croise essentiellement d'autres projets dans le même domaine, y compris RAPIDS, et est créé sous leur influence.

Les environnements d'exécution tels que Bohrium (implémente l'informatique paresseuse dans NumPy) et Numba (bibliothèque Python, compilateur de code JIT) partagent les objectifs de haut niveau de Weld. Et les systèmes d'optimisation comme Spark SQL influencent directement la conception des soudures.

Weld a-t-il d'autres utilisations en plus des optimisations de bibliothèque de science des données?


L'un des aspects les plus intéressants de Weld IR est qu'il prend en charge nativement la concurrence des données. Cela signifie que la parallélisation de boucle dans Weld IR est toujours sûre. Cela rend Weld IR attrayant pour de nouveaux types d'équipements.

Par exemple, les employés de NEC ont utilisé Weld pour exécuter des charges de travail Python sur un processeur vectoriel personnalisé à large bande passante, ajoutant simplement un nouveau backend à un IR Weld existant.

L'IR peut également être utilisé pour implémenter une couche d'opérations physiques dans une base de données. Et nous prévoyons d'ajouter des fonctionnalités qui nous permettront également de compiler un sous-ensemble de Python en code Weld.

Les bibliothèques sont-elles prêtes à être utilisées dans de vrais projets? Et sinon, quand pouvez-vous espérer un résultat fini?


De nombreux exemples et références sur lesquels nous avons testé ces bibliothèques sont tirés de la charge de travail réelle. Par conséquent, nous aimerions vraiment que les utilisateurs essaient la version actuelle dans leurs applications et laissent leurs commentaires. Et, surtout, ils ont proposé leurs propres correctifs.

En général, pour le moment, on ne peut pas dire que dans les applications réelles, tout fonctionnera hors de la boîte.

Nos prochaines versions au cours des prochains mois se concentreront exclusivement sur la convivialité et la fiabilité des bibliothèques Python. Notre objectif est de rendre les bibliothèques suffisamment bonnes pour être incluses dans de vrais projets. Et aussi la possibilité d'utiliser des versions de bibliothèque non-Weld dans des endroits où le support n'a pas encore été ajouté.

Comme je l'ai noté dans la première question, le projet d'annotation Split ( code source et article académique ) devrait simplifier cette transition.

Les annotations fractionnées sont un système qui vous permet d'ajouter des annotations au code existant pour déterminer comment le fractionner, le transformer et le paralléliser. Il fournit l'optimisation que nous considérons comme la plus efficace dans Weld (stockage de blocs de données dans des caches CPU entre les appels de fonction, au lieu d'analyser l'ensemble des données). Mais les annotations fractionnées sont beaucoup plus faciles à intégrer que Weld, car elles utilisent le code de bibliothèque existant sans compter sur le compilateur IR. Il facilite également la maintenance et le débogage, ce qui améliore la fiabilité.

Les bibliothèques qui ne disposent pas encore d'une prise en charge complète de Weld peuvent utiliser des annotations fractionnées. Cela nous permettra d'ajouter progressivement la prise en charge de Weld en fonction des commentaires des utilisateurs, tout en incorporant de nouvelles optimisations.

All Articles