Spark + AI Summit Europe 2018

La semaine dernière, nous nous sommes rendus à Londres pour assister à la conférence de référence sur Apache Spark en Europe ; qui s’est pour l’occasion renommée en Spark + AI Summit. Au fur et à mesure des conférences, trois sujets majeurs ont émergé et nous ont permis de mieux appréhender l’évolution d’Apache Spark et la direction prise par le projet.

TL;DR

Premièrement, l’orientation prise par Databricks semble être un support de première classe pour les principaux frameworks Python de ML comme Tensorflow, Keras, PyTorch avec Spark, afin d’en faire une plateforme d’exécution distribuée clé en main dans le cloud.

Il est bon de noter que SparkML n’a pas été mis plus en avant que les autres, ce qui semble indiquer que Databricks veut supporter les principaux frameworks de ML et ne plus forcément pousser le sien.

Spark est ainsi poussé comme une plateforme de calcul distribué avec un effort particulier autour du support des algos de ML et se concentre ainsi sur les améliorations possibles afin de leur offrir les meilleures performances avec notamment le projet Hydrogen, nous reviendrons dessus plus tard.

Ensuite, il y a un vrai effort de rapprocher les data scientists et les data engineers afin de faciliter la mise en production et l’opération des pipelines Python de ML avec l’arrivée de MLFlow, qui apporte une solution à l’historisation et au packaging de ces pipelines (sur base Conda).

Mais au delà du projet MLFlow que nous allons suivre avec beaucoup d’attention, la partie AI + Datascience n’était pas à la hauteur de nos attentes.

Les tracks étaient pour la plupart des mises en avant de grosses solutions du marché (IBM Watson, Microsoft Azure, etc…), nous aurions aimé plus de détails d’implémentation.

Au final les tracks les plus intéressantes côté AI étaient des REX d’entreprises avec des modèles en production, on retiendra entre autres CardioAI qui fait de la détection de maladie à partir de radio du coeur ou encore Zalando qui fait de la recommandation en temps réel.

Nous avons aussi assisté à de nombreux retours sur l’utilisation en production de Spark avec de bons conseils pour éviter les écueils rencontrés par les géants. Ce qui donne un bon indice sur la maturité atteinte par la plateforme. On est sur une phase de stabilisation et la recherche d’amélioration de performance avec une descente de certaines tâches vers le hardware, en effet nous avons pu assister à la présentation de plusieurs accélérateurs à base de FPGA.

Pour terminer, l’écosystème pour les développeurs mûrit et s’enrichit. Spark devient un framework mainstream présent dans toute entreprise faisant du Big Data.

« Spark is the glue for your big data applications »

Le grand absent est désormais Hadoop – tout est fait pour fournir du Spark en SaaS sur le cloud.

La version longue

Apache Spark : sa genèse et son futur

La génèse

Avec les Keynotes présentées par Matei Zaharia et Reynod Xin en début de journée, nous avons eu l’occasion de revenir sur la genèse de Spark : cela va faire en effet déjà quatre années que la première release a été publiée et il était temps de faire un point sur chacune des grosses étapes qui ont marqué l’histoire du projet : Tungsten, Catalyst, le Structured Streaming et plus récemment le Continuous Processing. L’article “Apache Spark is the Talylor Swift of Big Data” de Derrick Harris a d’ailleurs été cité : force est de constater que sorti de nulle part, l’outil a su s’imposer dans un écosystème hétérogène complexe et devenir un acteur à part entière lorsque l’on est dans un contexte de type Big Data, où la volumétrie des données va de pair avec la complexité d’intégration.

Le futur

La sortie de Spark 2.4 a été évoquée avec les nouveautés que cette nouvelle mouture allait apporter, avec entres autres une consolidation du support de l’intégration avec Kubernetes :

  • un support pour exécuter des applications PySpark et SparkR conteneurisées ;
  • le support d’un mode client qui permet d’exécuter des applications interactives et des notebooks ;
  • le support de nouveaux types de volume de stockage proposés par Kubernetes.

Dans les autres nouveautés annoncées pour la version 2.4, on trouve:

Pour l’année prochaine, Spark 3.0 est également prévu, avec des nouveautés – cette fois-ci plus structurelles – principalement liées à l’arrivée du projet Hydrogen. L’idée de base est simple : considérer les pipelines de Machine Learning comme des DAG à part entière, et permettre d’avoir un moteur qui intègre à la fois les traitements de données et leur utilisation (typiquement, dans des contextes d’entraînement de modèles). Le projet Hydrogen englobe également une restructuration de la manière dont les données sont manipulées en mémoire en généralisant l’utilisation de structures vectorisées.

Une collaboration plus étroite entre data scientists et data engineers

Databricks a beaucoup insisté sur la nécessité de rapprocher les data scientists et les data engineers. Ces populations n’ayant pas les mêmes compétences et appétences, les mises en production sont généralement complexes, surtout lors de l’installation de modèle de ML. Beaucoup de présentations proposaient des approches pour rapprocher ces populations et faciliter les mises en productions en gardant de la souplesse du côté des choix de Frameworks de ML tout en facilitant l’exploitation de la plateforme. Le temps des POC de ML est révolu.

« AI first strategy »

Une plateforme unifiée

Spark est mis en valeur par sa capacité à lancer des expérimentations de ML en parallèle, pour optimiser les hyper-paramètres, avec de larges datasets distribués, exploitant l’élasticité du Cloud et des clusters de GPU.

IBM a proposé une architecture pour un apprentissage de ML via un flux Kafka, produisant à chaque itération un nouveau modèle à appliquer sur les données futures. Ces approches sont particulièrement complexes et piégeantes : il faut faire attention à la distribution des données au sein de chaque micro-batch, à la labellisation tardive des données du flux,  etc. Des algorithmes capables d’ajuster les modèles incrémentalement sont disponibles (StreamingRandomForest, etc.).

Le projet Hydrogen

Nous en parlions déjà au début de notre article : Databricks a choisi d’améliorer profondément le support des frameworks de Machine Learning sur Apache Spark. En effet, jusqu’ici,  ils ont fait le constat que ces derniers avaient une incompatibilité fondamentale avec le modèle d’exécution de Spark.

Spark est un moteur d’exécution distribué, pour cela les tâches doivent être indépendantes afin de les paralléliser et relancer une tâche de manière autonome si son exécution est interrompue à cause d’un problème technique. Les frameworks de ML sont majoritairement des suites de tâches qui commencent à se paralléliser, mais qui ne sont pas indépendantes, c’est à dire que si l’une des tâches est interrompue pour une raison quelconque, il faut tout relancer depuis le début.

De ce constat est né le projet Hydrogen. Son objectif est de faire des frameworks de ML, des citoyens de première classe sur Spark. Pour cela, deux problématiques ont été adressées, la dépendances de l’exécution des tâches et l’échange de données entre Spark et les frameworks Python.

La première a été résolue par un nouveau mode d’ordonnancement, le Gang Scheduling (le plus gros changement introduit dans l’ordonnancement depuis la création de Spark). C’est un mode tout ou rien qui correspond au besoin des frameworks de ML, il a été nommé le mode “barrier execution”, il sera disponible en partie dans Spark 2.4 et la suite arrivera pour la version 3.0.

Ensuite, l’échange de donnée a été modifié pour avoir un format de donnée commun entre la JVM et les interpréteurs pythons utilisés par les frameworks de ML. Le but étant d’éviter de convertir les données à chaque échange. L’implémentation repose sur l’utilisation de Apache Arrow, les PandaRDD ajoutés en 2.3 étaient une première expérimentation.

En effet, il a été constaté que la sérialisation/désérialisation entre la JVM et l’interpréteur python prenait jusqu’à 95% du CPU, en utilisant un format vectorisé partagé, il n’y a plus de conversion nécessaire, on obtient alors un gain conséquent en performance lors de l’utilisation d’UDF Python.

MLFlow

Matei Zahari a profité d’une Keynote pour présenter le nouveau projet de MLflow, disponible en alpha depuis début juin. Le projet, open-source, progresse rapidement.

Il a pour but de gérer le cycle de vie d’un pipeline de ML, en partant des expérimentations avec une gestion de la reproductibilité en allant jusqu’au déploiement d’un modèle entraîné.

Il est composé de 3 sous-projets :

  • MLflow Tracking qui enregistre et versionne les modèles et les données tout en permettant le requêtage des expérimentations et notamment le code, les données, la configuration, et les résultats ;
  • MLflow Projects : c’est un format de packaging pour avoir des exécutions reproductibles, peu importe la plateforme ;
  • MLflow Models qui standardise la sauvegarde des modèles de manière générique, de manière à les rendre interopérables entre différents frameworks (H2O, Keras, MLeap, PyTorch, Scikit-learn, Spark MLlib,TensorFlow, etc.).

Le hardware : le nerf de la guerre

Le hardware était un sujet qui a été abordé plus que dans les précédents Spark Summits. Le Deep Learning a émergé ces dernières années principalement grâce à la possibilité de déléguer les opérations de calcul matriciel aux GPU : les opérations en question sont sensiblement les mêmes que celles en jeu lors du rendu d’image. Mais de nouvelles puces ont déjà fait leur apparition telles que les TPU qui sont cette fois intégralement dédiées aux réseaux de neurones : les algorithmes de ML peuvent alors s’exécuter beaucoup plus rapidement et le temps d’entraînement des modèles est alors considérablement réduit.

Une alternative plus généraliste aux TPU sont les FPGA, qui ont par exemple été mises en avant par Intel qui nous a présenté comment l’architecture du code de Spark rend possible l’utilisation de ces puces programmables de manière plug’n’play : nous avons également eu une présentation d’OPAE qui permet d’abstraire l’utilisation de ces nouveaux types de puce à l’aide d’un langage de plus haut niveau.

Apache Spark sur le terrain

Apache Spark est un outil qui commence à être bien implanté en entreprise : ses performances et son intégration avec l’écosystème Hadoop n’est plus à prouver et sa polyvalence fait que son utilisation est incontournable dans le contexte de traitement de la donnée à forte volumétrie.

L’environnement de production

Un certain nombre de conférences nous ont confortés sur le fait que Spark est désormais présent au coeur des SI car ce sont en majorité des retours d’expériences en production qui nous ont été remontés… Finis les PoC, on part en production, maintenant !

« a small part of what is deployed in PROD is ML code »

Cesar Delgado et DB Tsai de Apple nous ont parlé de la manière dont Apache Spark était utilisé dans le cadre de Siri, les problématiques rencontrées et les solutions apportées. En effet, la volumétrie importante requise pour leur traitement (autour de 100TB de données par jour, stockées sur HDFS) nécessite d’avoir un code optimisé pour éviter les flux de données qui ne sont pas nécessaires (l’effet d’échelle est plus que jamais à prendre en compte en Big Data) : l’optimiseur de plan d’exécution de Spark gère mal le Column Pruning et le Predicate Pushdown lorsque qu’il y a des schémas imbriqués dans les fichiers au format parquet. Ce qui fait que le filtrage se fait applicativement, et non lors du parcours du fichier, des données inutiles sont donc remontées, ce qui est d’autant plus coûteux avec des volumétries conséquentes.

Heureusement, Baidu a contribué sur le Column Pruning et Apple a proposé un merge qui résout le second problème, les correctifs devraient être disponibles en Spark 2.4.

Toujours dans un souci d’optimisation, Jacek Laskowski (qui est à Spark que ce que Tom Kytes est à Oracle) nous a parlé d’une technique qui permet d’optimiser les traitements lorsque ces derniers se basent sur les mêmes jointures réalisées plusieurs fois. L’idée repose sur le fait d’adapter la donnée au moment de l’écriture en prévision des traitements ultérieurs : l’utilisation du bucketing sur les colonnes qui servent de clé de jointure va ainsi limiter le shuffling et minimiser le nombre de WholeStageCodegen lors de la jointure, ce qui a pour effet direct d’accélérer les traitements. Attention néanmoins : cette optimisation n’est valable que pour des sources de données qui s’appuient sur des fichiers (tels que Hive, par exemple) et n’a de sens que si elle accélère effectivement les traitements… Attention donc à toujours mesurer les performances de vos applications !

« monitor everything »

Apache Spark et code Scala

Apache Spark est un outil que l’on utilise comme une librairie et non comme un framework : aucun cadre ne nous est donné pour un développement cohérent et standardisé entre différents projets… Ce sont donc les bonnes pratiques de code habituelles qui valent, et plusieurs talks ont évoqué cela.

Albert Franzi a été le premier à faire ce rappel en insistant sur le fait qu’une application pour Apache Spark peut être modularisée comme n’importe quelle autre application : éviter les morceaux de code redondants, créer des abstractions et séparer le code en plusieurs parties sont des pratiques à suivre de manière à faciliter la maintenance et la rédaction de tests unitaires.

Cela peut paraître une évidence pour certains, mais il ne faut pas perdre de vue que la réalisation d’applications pour Apache Spark s’accompagne souvent de la découverte du Scala dont la syntaxe et les particularités sont parfois déroutantes pour le néophyte.

Ces particularités ont d’ailleurs été en partie mises en avant par Erik Erlandson et William Benton qui nous ont parlé des bonnes pratiques à suivre lorsque l’on réalise une librairie pour Spark : git flow, le pattern Pimp My Library, cross compiling avec sbt… Se reposer sur l’écosystème Scala (ou Python !) est essentiel pour avoir un code clair, propre, testé et maintenable. On peut faire du Clean Code avec Apache Spark, à condition de s’en donner les moyens !

Plusieurs librairies ont été mentionnées qui peuvent être inclues par défaut sur les projets pour faciliter le développement, telles que spark-testing-base pour faciliter la mise en place de tests unitaires et spark-daria qui ajoute un certain nombre de méthodes utilitaires qui peuvent faciliter le développement.

« figure out what you’re going to do and execute at a high standard »

Dataframe VS Dataset

La question de la pertinence de l’utilisation des Dataset en lieu et place des Dataframe se pose de plus en plus.

La Dataframe permet d’écrire des traitements performants mais ne permet pas d’appréhender la donnée manipulée de manière typée (conceptuellement, une Dataframe peut être vue comme une List[Map[String, Any]], ce qui ne nous permet pas de savoir si l’on traite des livres ou des voitures). Le Dataset quant à lui est une abstraction qui permet de typer la donnée en faisant correspondre les lignes traitées à une class (on a alors un Dataset[Book] qui rend le code plus explicite).

Le problème est que le typage fort des Datasets n’est en réalité que de la poudre aux yeux pour le développeur et le fait de ne pas comprendre qu’Apache Spark gère sa donnée avec un format binaire particulier peut poser de gros problèmes de performance : une transformation construite sur un Dataset nécessite en effet la désérialisation ligne par ligne du format binaire compact en une instance de la class correspondante, ce qui dégrade les temps d’exécution. A noter que ces problématiques ont été très bien identifiées et illustrées  par Raphaël Luta et Choucri Fahed au dernier PSUG.

Une manière de contourner ce problème nous a été présentée par Dávid Szakállas en implémentant nos propres Encoders qui permettent de faire le lien entre une instance d’une class quelconque et le format en mémoire utilisé par Apache Spark. En complément, la librairie Frameless permet de pousser l’exercice encore plus loin en s’appuyant sur la fonctionnalité d’auto-dérivation des Type Classes apportée par shapless.

A noter qu’une autre piste d’amélioration est en cours par Reynold Xin : l’idée repose sur l’interprétation du bytecode de la closure pour la transformer en une expression Catalyst (dont les traitements se basent directement sur la structure en mémoire).

Conclusion

Au premier abord, le Spark + AI Summit n’était pas à la hauteur de nos attentes: pas de révolution technique, pas de nouveaux partenariats… On est plutôt sur de la consolidation.

Avec du recul, ce manque de nouveauté est finalement logique : Apache Spark – le couteau suisse du Big Data – est un outil qui est aujourd’hui très démocratisé en entreprise et ses performances sont au rendez-vous à condition de comprendre son fonctionnement. Les problématiques à résoudre sont à présent organisationnelles : l’avenir appartient aux entreprises dont le Time to Market des applications reposant sur de l’IA, et donc sur la collaboration entre les data scientists et les data engineers, ce à quoi tente de répondre ML Flow. A noter que cette problématique n’est pas nouvelle : IBM Data Studio propose (sur le papier) une solution à ces problématiques.

« no solution replaces the need for subject matter experts »

Petite anecdote : l’annonce par Hortonworks de la fusion avec Cloudera a été mentionnée lors de la keynote de Kshitij Kumar de Zalendo. Il est intéressant de remarquer que ce rapprochement fort s’inscrit dans un contexte où les solutions intégrées dans le Cloud (comme celle de Databricks qui se base sur Azure) sont de plus en plus abouties et deviennent une option à part entière dans une optique de diminution du Time-to-Market. Le choix d’une plateforme Hadoop pour du processing distribué se justifie de moins en moins, le contexte est très concurrentiel, il reste à voir ce que cette alliance va permettre de faire, affaire à suivre…

Pour terminer, si Apache Spark vous intéresse, n’oubliez pas que nos collègues de OCTO Academy proposent des formations sur ce sujet !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


Ce formulaire est protégé par Google Recaptcha