paint-brush
Scale Vision Transformers (ViT) Beyond Hugging Facepar@maziyar
4,590 lectures
4,590 lectures

Scale Vision Transformers (ViT) Beyond Hugging Face

par Maziyar Panahi2022/08/25
Read on Terminal Reader
Read this story w/o Javascript

Trop long; Pour lire

Le but de cet article est de montrer comment faire évoluer les modèles Vision Transformer (ViT) de Hugging Face et les déployer dans des environnements prêts pour la production pour une inférence accélérée et hautes performances. À la fin, nous mettrons à l'échelle un modèle ViT de Hugging Face de 25 fois (2300 %) en utilisant Databricks, Nvidia et Spark NLP.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Scale Vision Transformers (ViT) Beyond Hugging Face
Maziyar Panahi HackerNoon profile picture

Accélérez les modèles ViT de pointe dans Hugging Face 🤗 jusqu'à 2300 % (25 fois plus rapide) avec Databricks, Nvidia et Spark NLP 🚀

Je suis l'un des contributeurs au projet open source Spark NLP et tout récemment cette bibliothèque a commencé à prendre en charge les modèles de transformateurs de vision (ViT) de bout en bout. J'utilise quotidiennement Spark NLP et d'autres bibliothèques open source ML/DL pour le travail et j'ai décidé de déployer un pipeline ViT pour une tâche de classification d'images de pointe et de fournir des comparaisons approfondies entre Hugging Face et Spark NLP .

Le but de cet article est de montrer comment faire évoluer les modèles Vision Transformer (ViT) de Hugging Face et les déployer dans des environnements prêts pour la production pour une inférence accélérée et hautes performances. À la fin, nous mettrons à l'échelle un modèle ViT de Hugging Face de 25 fois (2300 %) en utilisant Databricks, Nvidia et Spark NLP.

Dans cet article je vais :

  • Une courte introduction à Vision Transformer (ViT)
  • Benchmark Hugging Face à l'intérieur du serveur Dell sur les processeurs et les GPU
  • Étalonnage Spark NLP à l'intérieur du serveur Dell sur les processeurs et les GPU
  • Benchmark Hugging Face à l'intérieur du nœud unique Databricks sur les processeurs et les GPU
  • Étalonnez Spark NLP dans Databricks Single Node sur les processeurs et les GPU
  • Benchmark Spark NLP à l'intérieur de Databricks mis à l'échelle jusqu'à 10 nœuds avec CPU et GPU
  • Résumez tout !
  • Dans un esprit de transparence totale, tous les cahiers avec leurs logs, captures d'écran, et même la feuille excel avec les chiffres sont fournis ici sur GitHub

    Introduction aux modèles Vision Transformer (ViT)

    En 2017, un groupe de chercheurs de Google AI a publié un article qui introduisait une architecture de modèle de transformateur qui modifiait toutes les normes de traitement du langage naturel (NLP). L'article décrit un nouveau mécanisme appelé auto-attention comme un nouveau modèle plus efficace pour les applications linguistiques. Par exemple, les deux familles les plus populaires de modèles basés sur des transformateurs sont GPT et BERT.

    Un peu d'histoire de Transformer https://huggingface.co/course/chapter1/4

    Il y a un excellent chapitre sur « Comment fonctionnent les transformateurs » que je recommande fortement de lire si vous êtes intéressé.

    Bien que ces nouveaux modèles basés sur Transformer semblent révolutionner les tâches NLP, leur utilisation dans Computer Vision (CV) est restée assez limitée. Le domaine de la vision par ordinateur a été dominé par l'utilisation des réseaux de neurones convolutionnels (CNN) et il existe des architectures populaires basées sur les CNN (comme ResNet). Cela avait été le cas jusqu'à ce qu'une autre équipe de chercheurs cette fois de Google Brain présente le « Vision Transformer » (ViT) en juin 2021 dans un article intitulé : « An Image is Worth 16x16 Words : Transformers for Image Recognition at Scale »

    Cet article représente une percée en matière de reconnaissance d'images en utilisant le même mécanisme d'auto-attention que celui utilisé dans les modèles basés sur des transformateurs tels que BERT et GPT, comme nous venons de le voir. Dans les modèles de langage basés sur Transformed comme BERT, l'entrée est une phrase (par exemple une liste de mots). Cependant, dans les modèles ViT, nous divisons d'abord une image en une grille de patchs de sous-image, nous incorporons ensuite chaque patch avec un projet linéaire avant que chaque patch intégré ne devienne un jeton. Le résultat est une séquence de patchs d'incorporations que nous passons au modèle similaire à BERT.

    Un aperçu de la structure du modèle ViT tel qu'introduit dans l'article original de Google Research de 2021

    Vision Transformer se concentre sur une plus grande précision mais avec moins de temps de calcul. En regardant les benchmarks publiés dans l'article, nous pouvons voir que le temps de formation par rapport à l'ensemble de données Noisy Student (publié par Google en juin 2020) a été réduit de 80 % même si l'état de précision est plus ou moins le même. Pour plus d'informations sur les performances de ViT aujourd'hui, vous devriez visiter sa page sur Papers With Code :

    Comparaison avec l'état de l'art sur les benchmarks de classification d'images populaires. ( https://arxiv.org/pdf/2010.11929.pdf )

    Il est également important de mentionner qu'une fois que vous avez formé un modèle via l'architecture ViT, vous pouvez pré-former et affiner votre transformateur comme vous le faites dans NLP. (c'est plutôt cool en fait !)

    Si nous comparons les modèles ViT aux CNN, nous pouvons voir qu'ils ont une plus grande précision avec un coût de calcul beaucoup plus faible. Vous pouvez utiliser des modèles ViT pour diverses tâches en aval dans Computer Vision telles que la classification d'images, la détection d'objets et la segmentation d'images. Cela peut également être spécifique à un domaine dans le domaine de la santé, vous pouvez pré-entraîner/affiner vos modèles ViT pour les fractures du fémur , l' emphysème , le cancer du sein , le COVID-19 et la maladie d'Alzheimer.¹

    Je laisserai des références à la fin de cet article au cas où vous voudriez approfondir le fonctionnement des modèles ViT.

    [1] : Analyse approfondie : Transformateurs de vision sur Hugging Face Optimum Graphcore https://huggingface.co/blog/vision-transformers

    Quelques modèles ViT en action

    Modèle Vision Transformer (ViT) ( vit-base-patch16–224 ) pré-formé sur ImageNet-21k (14 millions d'images, 21 843 classes) à une résolution de 224x224 et affiné sur ImageNet 2012 (1 million d'images, 1 000 classes) à résolution 224x224 :

    https://huggingface.co/google/vit-base-patch16-224

    Modèles ViT affinés utilisés pour la classification des aliments :

    https://huggingface.co/nateraw/foodhttps://huggingface.co/julien-c/hotdog-not-hotdog

    Il existe cependant des limites et des restrictions à tous les modèles DL/ML en matière de prédiction. Il n'y a pas de modèle avec une précision de 100 %, alors gardez à l'esprit lorsque vous les utilisez pour quelque chose d'important comme les soins de santé :

    L'image est tirée de : https://www.akc.org/expert-advice/lifestyle/do-you-live-in-dog-state-or-cat-state/ — Modèle ViT : https://huggingface.co /julien-c/hotdog-pas-hotdog


    Pouvons-nous utiliser ces modèles de Hugging Face ou affiner de nouveaux modèles ViT et les utiliser pour l'inférence dans la production réelle ? Comment pouvons-nous les mettre à l'échelle en utilisant des services gérés pour les calculs distribués tels qu'AWS EMR, Azure Insight, GCP Dataproc ou Databricks ?

    Espérons que certaines d'entre elles trouveront une réponse à la fin de cet article.

    Que les repères commencent !

    Quelques détails sur nos benchmarks :

    1- Jeu de données : ImageNet mini : échantillon (>3K) — complet (>34K)

    J'ai téléchargé le jeu de données ImageNet 1000 (mini) de Kaggle : https://www.kaggle.com/datasets/ifigotin/imagenetmini-1000

    J'ai choisi le répertoire train avec plus de 34 000 images et je l'ai appelé imagenet-mini car tout ce dont j'avais besoin était d'assez d'images pour faire des benchmarks qui prennent plus de temps. De plus, j'ai sélectionné au hasard moins de 10% de l'ensemble de données complet et l'ai appelé imagenet-mini-sample qui contient 3544 images pour mes plus petits benchmarks et aussi pour affiner les bons paramètres comme la taille du lot.

    2- Modèle : Le « vit-base-patch16–224 » de Google

    Nous utiliserons ce modèle de Google hébergé sur Hugging Face : https://huggingface.co/google/vit-base-patch16-224

    3- Librairies : Transformers 🤗 & Spark NLP 🚀

    Benchmarking Hugging Face sur un serveur Bare Metal

    Modèle ViT sur un Dell PowerEdge C4130

    Qu'est-ce qu'un serveur bare metal ? Un serveur bare metal est juste un ordinateur physique qui n'est utilisé que par un seul utilisateur. Il n'y a pas d'hyperviseur installé sur cette machine, il n'y a pas de virtualisations et tout est exécuté directement sur le système d'exploitation principal (Linux - Ubuntu) - les spécifications détaillées des processeurs, des GPU et de la mémoire de cette machine sont à l'intérieur des ordinateurs portables.

    Comme l'ont révélé mes tests initiaux et presque tous les articles de blog écrits par l'équipe d'ingénierie de Hugging Face comparant la vitesse d'inférence entre les moteurs DL, les meilleures performances d'inférence dans la bibliothèque Hugging Face (Transformer) sont obtenues en utilisant PyTorch sur TensorFlow. Je ne sais pas si cela est dû au fait que TensorFlow est un citoyen de seconde classe dans Hugging Face en raison de moins de fonctionnalités prises en charge, moins de modèles pris en charge, moins d'exemples, de didacticiels obsolètes et d'enquêtes annuelles des 2 dernières années auxquelles les utilisateurs ont répondu en demandant plus pour TensorFlow ou PyTorch a juste une latence plus faible dans l'inférence sur le CPU et le GPU.
    TensorFlow reste le framework de deep learning le plus utilisé

    Quelle que soit la raison, j'ai choisi PyTorch dans la bibliothèque Hugging Face pour obtenir les meilleurs résultats pour nos benchmarks de classification d'images. Ceci est un extrait de code simple pour utiliser un modèle ViT (PyTorch bien sûr) dans Hugging Face :

     from transformers import ViTFeatureExtractor, ViTForImageClassification from PIL import Image import requests url = 'http://images.cocodataset.org/val2017/000000039769.jpg'
    image = Image.open(requests.get(url, stream= True ).raw) feature_extractor = ViTFeatureExtractor.from_pretrained( 'google/vit-base-patch16-224' ) model = ViTForImageClassification.from_pretrained( 'google/vit-base-patch16-224' ) inputs = feature_extractor(images=image, return_tensors= "pt" ) outputs = model(**inputs) logits = outputs.logits # model predicts one of the 1000 ImageNet classes
    predicted_class_idx = logits.argmax(- 1 ).item() print("Predicted class:", model.config.id2label [predicted_class_idx] )

    Cela peut sembler simple pour prédire une image en entrée, mais cela ne convient pas pour de plus grandes quantités d'images, en particulier sur un GPU. Pour éviter de prédire les images de manière séquentielle et de tirer parti du matériel accéléré tel que le GPU, il est préférable d'alimenter le modèle avec des lots d'images, ce qui est possible dans Hugging Face via Pipelines . Inutile de dire que vous pouvez mettre en œuvre votre technique de traitement par lots en étendant les pipelines de Hugging Face ou en le faisant vous-même.

    Un pipeline simple pour la classification d'images ressemblera à ceci :

     from transformers import ViTFeatureExtractor, ViTForImageClassification from transformers import pipeline feature_extractor = ViTFeatureExtractor.from_pretrained( 'google/vit-base-patch16-224' ) model = ViTForImageClassification.from_pretrained( 'google/vit-base-patch16-224' ) pipe = pipeline( "image-classification" , model=model, feature_extractor=feature_extractor, device=- 1 )

    Conformément à la documentation, j'ai téléchargé/chargé google/vit-base-patch16–224 pour l'extracteur de fonctionnalités et le modèle (points de contrôle PyTorch bien sûr) pour les utiliser dans le pipeline avec la classification des images comme tâche. Il y a 3 choses dans ce pipeline qui sont importantes pour nos benchmarks :

    > périphérique : si c'est -1 (par défaut), il n'utilisera que des processeurs, tandis que s'il s'agit d'un nombre entier positif, il exécutera le modèle sur l'identifiant de périphérique CUDA associé (il est préférable de masquer les GPU et de forcer PyTorch à utiliser le processeur et pas seulement fiez-vous à ce numéro ici).

    > batch_size : Lorsque le pipeline utilisera DataLoader (lors du passage d'un jeu de données, sur GPU pour un modèle Pytorch), la taille du batch à utiliser, pour l'inférence n'est pas toujours bénéfique.

    > Vous devez utiliser DataLoader ou PyTorch Dataset pour tirer pleinement parti du traitement par lots dans les pipelines Hugging Face sur un GPU.

    Avant d'aller de l'avant avec les points de repère, vous devez savoir une chose concernant le traitement par lots dans Hugging Face Pipelines pour l'inférence, que cela ne fonctionne pas toujours. Comme indiqué dans la documentation de Hugging Face, la définition de batch_size peut ne pas du tout augmenter les performances de votre pipeline. Cela peut ralentir votre pipeline :

    https://huggingface.co/docs/transformers/main_classes/pipelines#pipeline-batching

    Pour être juste, dans mes benchmarks, j'ai utilisé une gamme de tailles de lots à partir de 1 pour m'assurer que je peux trouver le meilleur résultat parmi eux. Voici comment j'ai comparé le pipeline Hugging Face sur CPU :

     from transformers import pipeline pipe = pipeline( "image-classification" , model=model, feature_extractor=feature_extractor, device=- 1 ) for batch_size in [ 1 , 8 , 32 , 64 , 128 ]:    print ( "-" * 30 )    print ( f"Streaming batch_size= {batch_size} " )    for out in tqdm(pipe(dataset, batch_size=batch_size), total= len (dataset)):        pass

    Examinons les résultats de notre tout premier benchmark pour le pipeline de classification d'images Hugging Face sur les processeurs sur l'exemple de jeu de données ImageNet (3K):

    Pipeline de classification d'images Hugging Face sur les processeurs - prévision de 3544 images

    Comme on peut le voir, il a fallu environ 3 minutes ( 188 secondes) pour terminer le traitement d'environ 3544 images de l'échantillon de données. Maintenant que je sais quelle taille de lot (8) est la meilleure pour mon pipeline/jeu de données/matériel, je peux utiliser le même pipeline sur un jeu de données plus grand ( images 34K ) avec cette taille de lot :

    Pipeline de classification d'images Hugging Face sur les processeurs - prévision de 34745 images

    Cette fois, il a fallu environ 31 minutes ( 1 879 secondes ) pour terminer la prédiction des classes pour 34 745 images sur les processeurs.

    Pour améliorer la plupart des modèles d'apprentissage en profondeur, en particulier ces nouveaux modèles basés sur des transformateurs, il convient d'utiliser du matériel accéléré tel que le GPU. Voyons comment comparer le même pipeline sur les mêmes ensembles de données, mais cette fois sur un périphérique GPU . Comme mentionné précédemment, nous devons changer l' appareil en un identifiant d'appareil CUDA comme 0 (le premier GPU) :

     from transformers import ViTFeatureExtractor, ViTForImageClassification from transformers import pipeline import torch device = "cuda:0" if torch.cuda.is_available() else "cpu"
    print (device) feature_extractor = ViTFeatureExtractor.from_pretrained( 'google/vit-base-patch16-224' ) model = ViTForImageClassification.from_pretrained( 'google/vit-base-patch16-224' ) model = model.to(device) pipe = pipeline( "image-classification" , model=model, feature_extractor=feature_extractor, device= 0 ) for batch_size in [ 1 , 8 , 32 , 64 , 128 , 256 , 512 , 1024 ]:    print ( "-" * 30 )    print ( f"Streaming batch_size= {batch_size} " )    for out in tqdm(pipe(dataset, batch_size=batch_size), total= len (dataset)):        pass
    

    En plus de définir device=0, j'ai également suivi la méthode recommandée pour exécuter un modèle PyTorch sur un périphérique GPU via .to(device). Puisque nous utilisons du matériel accéléré (GPU), j'ai également augmenté la taille de lot maximale pour mes tests à 1024 pour trouver le meilleur résultat.

    Jetons un coup d'œil à notre pipeline de classification d'images Hugging Face sur un périphérique GPU sur l'exemple de jeu de données ImageNet (3K) :

    Pipeline de classification d'images Hugging Face sur un GPU - prévision de 3544 images

    Comme on peut le voir, il a fallu environ 50 secondes pour terminer le traitement d'environ 3544 images de notre ensemble de données imagenet-mini-sample sur un appareil GPU . Le traitement par lots a amélioré la vitesse, en particulier par rapport aux résultats provenant des processeurs, cependant, les améliorations se sont arrêtées autour de la taille de lot de 32. Bien que les résultats soient les mêmes après la taille de lot 32, j'ai choisi la taille de lot 256 pour mon plus grand benchmark à utiliser suffisamment de mémoire GPU également.

    Pipeline de classification d'images Hugging Face sur un GPU - prévision de 34745 images

    Cette fois, notre benchmark a pris environ 8:17 minutes ( 497 secondes ) pour finir de prédire les classes pour 34745 images sur un appareil GPU . Si nous comparons les résultats de nos benchmarks sur les CPU et un appareil GPU, nous pouvons voir que le GPU est ici le gagnant :

    Hugging Face (PyTorch) est jusqu'à 3,9 fois plus rapide sur GPU que sur CPU

    J'ai utilisé Hugging Face Pipelines pour charger les points de contrôle ViT PyTorch, charger mes données dans l'ensemble de données de la torche et utiliser le traitement par lots prêt à l'emploi fourni au modèle sur le CPU et le GPU. Le GPU est jusqu'à ~3,9 fois plus rapide par rapport à l'exécution des mêmes pipelines sur les processeurs.

    Nous avons amélioré notre pipeline ViT pour effectuer la classification des images en utilisant un périphérique GPU au lieu de processeurs, mais pouvons-nous améliorer davantage notre pipeline à la fois sur le processeur et le processeur graphique sur une seule machine avant de le mettre à l'échelle sur plusieurs machines ? Jetons un coup d'œil à la bibliothèque Spark NLP.

    Spark NLP : traitement du langage naturel à la pointe de la technologie

    Spark NLP est une bibliothèque de traitement du langage naturel à la pointe de la technologie ( https://github.com/JohnSnowLabs/spark-nlp )

    Spark NLP est une bibliothèque de traitement du langage naturel de pointe construite sur Apache Spark. Il fournit des annotations NLP simples, performantes et précises pour les pipelines d'apprentissage automatique qui évoluent facilement dans un environnement distribué. Spark NLP est livré avec plus de 7 000 pipelines et modèles pré-entraînés dans plus de 200 langues . Il propose également des tâches telles que la tokénisation, la segmentation des mots, le marquage des parties du discours, les incorporations de mots et de phrases, la reconnaissance d'entités nommées, l'analyse des dépendances, la vérification orthographique, la classification de texte, l'analyse des sentiments, la classification des jetons, la traduction automatique (+180 langues), Résumé et réponse aux questions, génération de texte, classification d'images (ViT) et bien d'autres tâches NLP .

    Spark NLP est la seule bibliothèque NLP open source en production qui offre des transformateurs de pointe tels que BERT , CamemBERT , ALBERT , ELECTRA , XLNet , DistilBERT , RoBERTa , DeBERTa , XLM-RoBERTa , Longformer , ELMO , Universal Sentence Encoder , Google T5 , MarianMT , GPT2 et Vision Transformer ( ViT ) non seulement pour Python et R , mais aussi pour l'écosystème JVM ( Java , Scala et Kotlin ) à grande échelle en étendant Apache Spark de manière native.

    Analyse comparative de Spark NLP sur un serveur Bare Metal

    Modèles ViT sur un Dell PowerEdge C4130

    Spark NLP possède les mêmes fonctionnalités ViT pour la classification des images que Hugging Face qui ont été ajoutées dans la récente version 4.1.0 . La fonctionnalité s'appelle ViTForImageClassification, elle contient plus de 240 modèles pré-formés prêts à l'emploi , et un code simple pour utiliser cette fonctionnalité dans Spark NLP ressemble à ceci :

     from sparknlp.annotator import * from sparknlp.base import * from pyspark.ml import Pipeline imageAssembler = ImageAssembler() \ .setInputCol( "image" ) \ .setOutputCol( "image_assembler" ) imageClassifier = ViTForImageClassification \ .pretrained( "image_classifier_vit_base_patch16_224" ) \ .setInputCols( "image_assembler" ) \ .setOutputCol( "class" ) \ .setBatchSize( 8 ) pipeline = Pipeline(stages=[ imageAssembler, imageClassifier ])

    Si nous comparons côte à côte Spark NLP et Hugging Face pour le téléchargement et le chargement d'un modèle ViT pré-formé pour une prédiction de classification d'image, à part le chargement d'images et l'utilisation de post-calculs comme argmax en dehors de la bibliothèque Hugging Face, ils sont tous les deux assez simples. De plus, ils peuvent tous les deux être enregistrés et servir plus tard de pipeline pour réduire ces lignes en une seule ligne de code :

    Chargement et utilisation de modèles ViT pour la classification d'images dans Spark NLP (à gauche) et Hugging Face (à droite)

    Comme Apache Spark a un concept appelé Lazy Evaluation , il ne démarre pas l'exécution du processus tant qu'une ACTION n'est pas appelée. Les actions dans Apache Spark peuvent être .count() ou .show() ou .write() et tant d'autres opérations basées sur RDD que je n'aborderai pas maintenant et vous n'aurez pas besoin de les connaître pour cet article. Je choisis généralement soit count() la colonne cible, soit write() les résultats sur les disques pour déclencher l'exécution de toutes les lignes du DataFrame. De plus, comme pour les benchmarks de Hugging Face, je vais parcourir les tailles de lots sélectionnées pour m'assurer que je peux avoir tous les résultats possibles sans manquer le meilleur résultat.

    Maintenant, nous savons comment charger le ou les modèles ViT dans Spark NLP, nous savons également comment déclencher une action pour forcer le calcul sur toutes les lignes de notre DataFrame à comparer, et tout ce qu'il reste à apprendre est oneDNN de oneAPI Deep Neural Bibliothèque réseau (oneDNN) . Étant donné que le moteur DL de Spark NLP est TensorFlow, vous pouvez également activer oneDNN pour améliorer la vitesse des processeurs (comme tout le reste, vous devez le tester pour vous assurer qu'il améliore la vitesse et non l'inverse). J'utiliserai également cet indicateur en plus des processeurs normaux sans oneDNN activé

    Maintenant que nous savons que tous les modèles ViT de Hugging Face sont également disponibles dans Spark NLP et comment les utiliser dans un pipeline, nous allons répéter nos benchmarks précédents sur le serveur Dell nu pour comparer CPU et GPU. Examinons les résultats du pipeline de classification d'images de Spark NLP sur les processeurs sur notre exemple de jeu de données ImageNet (3K):

    Pipeline de classification d'images Spark NLP sur un CPU sans oneDNN - prédisant 3544 images

    Il a fallu environ 2,1 minutes ( 130 secondes) pour terminer le traitement d'environ 3544 images de notre échantillon de données. Avoir un ensemble de données plus petit pour essayer différentes tailles de lot est utile pour choisir la bonne taille de lot pour votre tâche, votre ensemble de données et votre machine. Ici, il est clair que la taille de lot 16 est la meilleure taille pour que notre pipeline fournisse le meilleur résultat.

    Je voudrais également activer oneDNN pour voir si, dans cette situation spécifique, cela améliore ma référence par rapport aux processeurs sans oneDNN. Vous pouvez activer oneDNN dans Spark NLP en définissant la variable d'environnement TF_ENABLE_ONEDNN_OPTS sur 1. Voyons ce qui se passe si j'active cet indicateur et que je relance le benchmark précédent sur le CPU pour trouver la meilleure taille de lot :

    Pipeline de classification d'images Spark NLP sur un CPU avec oneDNN - prédisant 3544 images

    OK, donc clairement activer oneDNN pour TensorFlow dans cette situation spécifique a amélioré nos résultats d'au moins 14 %. Étant donné que nous n'avons rien à faire/changer et qu'il suffit de dire exporter TF_ENABLE_ONEDNN_OPTS=1, je vais également l'utiliser pour le benchmark avec un ensemble de données plus volumineux pour voir la différence. Ici, c'est environ quelques secondes plus vite, mais 14 % sur le plus grand ensemble de données peuvent réduire de quelques minutes nos résultats.

    Maintenant que je connais la taille de lot de 16 pour CPU sans oneDNN et la taille de lot de 2 pour CPU avec oneDNN activé ont les meilleurs résultats, je peux continuer à utiliser le même pipeline sur un ensemble de données plus grand ( images 34K ):

    Pipeline de classification d'images Spark NLP sur les processeurs sans oneDNN - prédisant 34745 images

    Cette fois, notre benchmark a pris environ 24 minutes ( 1423 secondes ) pour terminer la prédiction des classes pour 34745 images sur un périphérique CPU sans oneDNN activé. Voyons maintenant ce qui se passe si j'active oneDNN pour TensorFlow et utilise la taille de lot de 2 (les meilleurs résultats):

    Pipeline de classification d'images Spark NLP sur les processeurs avec oneDNN - prévision de 34745 images

    Cette fois, cela a pris environ 21 minutes ( 1278 secondes ). Comme prévu à partir de nos exemples de benchmarks, nous pouvons voir des améliorations d'environ 11% dans les résultats qui ont réduit les minutes par rapport à l'absence de oneDNN activé.

    Voyons comment comparer le même pipeline sur un périphérique GPU. Dans Spark NLP, tout ce dont vous avez besoin pour utiliser GPU est de le démarrer avec gpu=True lorsque vous démarrez la session Spark NLP :

    spark = sparknlp.start(gpu=True)
    # vous pouvez également définir la mémoire ici
    spark = sparknlp.start(gpu=True, memory="16g")

    C'est ça! Si vous avez quelque chose dans votre pipeline qui peut être exécuté sur GPU, il le fera automatiquement sans avoir besoin de faire quoi que ce soit explicitement.

    Jetons un coup d'œil à notre pipeline de classification d'images Spark NLP sur un périphérique GPU sur l'exemple de jeu de données ImageNet (3K) :

    Pipeline de classification d'images Spark NLP sur un GPU - prévision de 3544 images

    Par curiosité pour voir si ma croisade pour trouver une bonne taille de lot sur un ensemble de données plus petit était correcte, j'ai exécuté le même pipeline avec GPU sur un ensemble de données plus grand pour voir si la taille de lot 32 aura le meilleur résultat :

    Pipeline de classification d'images Spark NLP sur un GPU - prévision de 34745 images

    Heureusement, c'est la taille de lot 32 qui donne le meilleur temps. Cela a donc pris environ 4 minutes et demie ( 277 secondes).

    Je choisirai les résultats des CPU avec oneDNN car ils étaient plus rapides et je les comparerai aux résultats du GPU :

    Spark NLP (TensorFlow) est jusqu'à 4,6 fois plus rapide sur GPU que sur CPU (oneDNN)

    C'est bien! Nous pouvons voir que Spark NLP sur GPU est jusqu'à 4,6 fois plus rapide que les CPU, même avec oneDNN activé.

    Voyons comment ces résultats sont comparés aux benchmarks de Hugging Face :

    Spark NLP est 65 % plus rapide que Hugging Face sur les processeurs pour prédire les classes d'images pour l'exemple de jeu de données avec des images 3K et 47 % sur le plus grand jeu de données avec des images 34K. Spark NLP est également 79 % plus rapide que Hugging Face sur un seul ensemble de données d'inférence GPU plus grand avec des images de 34 000 et jusqu'à 35 % plus rapide sur un ensemble de données plus petit.


    Spark NLP était plus rapide que Hugging Face sur une seule machine en utilisant le CPU ou le GPU - classification d'image à l'aide de Vision Transformer (ViT)

    Spark NLP et visage étreignant sur Databricks

    Qu'est-ce qu'un Databrick ? Toutes vos données, analyses et IA sur une seule plateforme

    Databricks est une plate-forme basée sur le cloud avec un ensemble d'outils d'ingénierie et de science des données largement utilisés par de nombreuses entreprises pour traiter et transformer de grandes quantités de données. Les utilisateurs utilisent Databricks à de nombreuses fins, du traitement et de la transformation de grandes quantités de données à l'exécution de nombreux pipelines ML/DL pour explorer les données.

    Avis de non-responsabilité : c'était mon interprétation de Databricks, il comporte de nombreuses autres fonctionnalités et vous devriez les consulter : https://www.databricks.com/product/data-lakehouse

    Databricks prend en charge les clouds AWS, Azure et GCP : https://www.databricks.com/product/data-lakehouse

    Étreignant le visage dans le nœud unique Databricks avec des processeurs sur AWS

    Databricks propose un type de cluster "Single Node" lorsque vous créez un cluster adapté à ceux qui souhaitent utiliser Apache Spark avec une seule machine ou utiliser des applications non Spark, en particulier les bibliothèques Python basées sur ML et DL. Hugging Face est déjà installé lorsque vous choisissez le runtime Databricks 11.1 ML. Voici à quoi ressemblent les configurations de cluster pour mes Databricks à nœud unique (uniquement les processeurs) avant de commencer nos tests :

    Cluster à nœud unique Databricks — exécution du processeur

    Le résumé de ce cluster qui utilise l'instance m5n.8xlarge sur AWS est qu'il a 1 pilote (seulement 1 nœud), 128 Go de mémoire, 32 cœurs de CPU et qu'il coûte 5,71 DBU par heure. Vous pouvez en savoir plus sur « DBU » sur AWS ici : https://www.databricks.com/product/aws-pricing

    Cluster unique Databricks — Profil d'instance AWS

    Répliquons nos benchmarks de la section précédente (serveur Dell bare-metal) ici sur nos Databricks à nœud unique (CPU uniquement). Nous commençons par Hugging Face et notre ensemble de données de taille d'échantillon d'ImageNet pour savoir quelle taille de lot est la bonne afin que nous puissions l'utiliser pour l'ensemble de données plus grand, car cela s'est avéré être une pratique éprouvée dans les benchmarks précédents :

    Pipeline de classification d'images Hugging Face sur les processeurs à nœud unique Databricks - prévision de 3544 images

    Il a fallu environ 2 minutes et demie ( 149 secondes ) pour terminer le traitement d'environ 3544 images de notre exemple d'ensemble de données sur un Databricks à nœud unique qui n'utilise que des processeurs . La meilleure taille de lot sur cette machine utilisant uniquement des processeurs est de 8 , donc je vais l'utiliser pour exécuter le benchmark sur le plus grand ensemble de données :

    Pipeline de classification d'images Hugging Face sur les processeurs à nœud unique Databricks - prévision de 34745 images

    Sur le plus grand ensemble de données avec plus de 34 000 images, il a fallu environ 20 minutes et demie ( 1233 secondes ) pour terminer la prédiction des classes pour ces images. Pour notre prochain benchmark, nous devons disposer d'un cluster Databricks à nœud unique, mais cette fois, nous devons disposer d'un environnement d'exécution basé sur GPU et choisir une instance AWS basée sur GPU.

    Étreinte du visage dans Databricks Single Node avec un GPU sur AWS

    Créons un nouveau cluster et cette fois nous allons choisir un runtime avec GPU qui dans ce cas s'appelle 11.1 ML (inclut Apache Spark 3.3.0, GPU, Scala 2.12) et il est livré avec tous les logiciels CUDA et NVIDIA requis installés. La prochaine chose dont nous avons besoin est de sélectionner également une instance AWS qui a un GPU et j'ai choisi g4dn.8xlarge qui a 1 GPU et un nombre similaire de cœurs/mémoire que l'autre cluster. Cette instance GPU est livrée avec un Tesla T4 et 16 Go de mémoire ( 15 Go mémoire GPU utilisable).

    Cluster à nœud unique Databricks — Exécution GPU

    Ceci est le résumé de notre cluster à nœud unique comme le précédent et c'est le même en termes de nombre de cœurs et de quantité de mémoire, mais il est livré avec un GPU Tesla T4 :

    Cluster à nœud unique Databricks — Profil d'instance AWS

    Maintenant que nous avons un cluster à nœud unique avec un GPU, nous pouvons continuer nos benchmarks pour voir comment Hugging Face fonctionne sur cette machine dans Databricks. Je vais exécuter le benchmark sur le plus petit ensemble de données pour voir quelle taille de lot est la plus adaptée à notre machine basée sur GPU :

    Pipeline de classification d'images Hugging Face sur le processeur à nœud unique Databricks - prévision de 3544 images

    Il a fallu environ une minute ( 64 secondes ) pour terminer le traitement d'environ 3544 images de notre exemple d'ensemble de données sur notre cluster Databricks à nœud unique avec un périphérique GPU. Le traitement par lots a amélioré la vitesse si nous examinons le résultat de la taille de lot 1, cependant, après la taille de lot 8, les résultats sont restés à peu près les mêmes. Bien que les résultats soient les mêmes après la taille de lot 8, j'ai choisi la taille de lot 256 pour mon plus grand benchmark afin d'utiliser également plus de mémoire GPU. (pour être honnête, 8 et 256 ont à peu près les mêmes performances)

    Exécutons le benchmark sur le plus grand ensemble de données et voyons ce qui se passe avec la taille de lot 256 :

    Pipeline de classification d'images Hugging Face sur le processeur à nœud unique Databricks - prévision de 34745 images

    Sur un ensemble de données plus volumineux, il a fallu près de 11 minutes ( 659 secondes ) pour terminer la prédiction des classes pour plus de 34 000 images. Si nous comparons les résultats de nos benchmarks sur un seul nœud avec des CPU et un seul nœud fourni avec 1 GPU, nous pouvons voir que le nœud GPU ici est le gagnant :

    Hugging Face (PyTorch) est jusqu'à 2,3 fois plus rapide sur GPU que sur CPU

    Le GPU est jusqu'à ~ 2,3 fois plus rapide par rapport à l'exécution du même pipeline sur les processeurs dans Hugging Face on Databricks Single Node

    Nous allons maintenant exécuter les mêmes benchmarks en utilisant Spark NLP dans les mêmes clusters et sur les mêmes ensembles de données pour le comparer avec Hugging Face.

    Analyse comparative Spark NLP sur un nœud unique Databricks

    Tout d'abord, installons Spark NLP dans vos processeurs Databricks à nœud unique :

    Dans l'onglet Bibliothèques de votre cluster, vous devez suivre ces étapes :
    — Installer Nouveau -> PyPI -> spark-nlp==4.1.0 -> Installer
    - Installer Nouveau -> Maven -> Coordonnées -> com.johnsnowlabs.nlp:spark-nlp_2.12:4.1.0 -> Installer
    — Ajoutera ` TF_ENABLE_ONEDNN_OPTS=1 ` à `Cluster->Advacend Options->Spark->Environment variables` pour activer oneDNN

    Comment installer Spark NLP dans Databricks sur des processeurs pour Python, Scala et Java

    Spark NLP dans Databricks Single Node avec CPU sur AWS

    Maintenant que Spark NLP est installé sur notre cluster à nœud unique Databricks, nous pouvons répéter les tests de performance pour un échantillon et des ensembles de données complets sur le CPU et le GPU. Commençons par le benchmark sur les processeurs d'abord sur l'exemple d'ensemble de données :

    Pipeline de classification d'images Spark NLP sur les processeurs à nœud unique Databricks (oneDNN) - prévision de 3544 images

    Il a fallu environ 2 minutes ( 111 secondes ) pour terminer le traitement de 3544 images et prédire leurs classes sur le même cluster Databricks à nœud unique avec les processeurs que nous avons utilisés pour Hugging Face. Nous pouvons voir que la taille de lot de 16 a le meilleur résultat, donc je vais l'utiliser dans le prochain benchmark sur le plus grand ensemble de données :

    Pipeline de classification d'images Spark NLP sur les processeurs à nœud unique Databricks (oneDNN) - prévision de 34742 images

    Sur le plus grand ensemble de données avec plus de 34 000 images , il a fallu environ 18 minutes ( 1072 secondes ) pour terminer la prédiction des classes pour ces images. Ensuite, je répéterai les mêmes tests sur le cluster avec GPU.

    Nœud unique Databricks avec un GPU sur AWS

    Tout d'abord, installez Spark NLP dans votre GPU Databricks à nœud unique (la seule différence est l'utilisation de « spark-nlp-gpu » de Maven) :

    Installez Spark NLP dans votre cluster Databricks
    — Dans l'onglet Bibliothèques à l'intérieur du cluster, vous devez suivre ces étapes :
    — Installer Nouveau -> PyPI -> spark-nlp==4.1.0 -> Installer
    - Installer Nouveau -> Maven -> Coordonnées -> com.johnsnowlabs.nlp:spark-nlp-gpu_2.12:4.1.0 -> Installer

    Comment installer Spark NLP dans Databricks sur des GPU pour Python, Scala et Java

    Je vais exécuter le benchmark sur le plus petit ensemble de données pour voir quelle taille de lot est la plus adaptée à notre machine basée sur GPU :

    Pipeline de classification d'images Spark NLP sur GPU à nœud unique Databricks - prévision de 3544 images

    Il a fallu moins d'une minute ( 47 secondes ) pour terminer le traitement d'environ 3544 images de notre exemple d'ensemble de données sur nos Databricks à nœud unique avec un périphérique GPU. Nous pouvons voir que la taille de lot 8 a donné les meilleurs résultats dans ce cas d'utilisation spécifique, je vais donc exécuter le benchmark sur le plus grand ensemble de données :

    Pipeline de classification d'images Spark NLP sur le GPU à nœud unique Databricks - prévision de 34742 images

    Sur un ensemble de données plus volumineux, il a fallu près de 7 minutes et demie ( 435 secondes ) pour finir de prédire les classes pour plus de 34 000 images . Si nous comparons les résultats de nos benchmarks sur un seul nœud avec des CPU et un seul nœud fourni avec 1 GPU, nous pouvons voir que le nœud GPU ici est le gagnant :

    Spark NLP est jusqu'à 2,5 fois plus rapide sur GPU que sur CPU dans Databricks Single Node

    C'est bien! Nous pouvons voir que Spark NLP sur GPU est jusqu'à 2,5 fois plus rapide que les CPU, même avec oneDNN activé (oneDNN améliore les résultats sur les CPU entre 10 % et 20 %).

    Voyons comment ces résultats sont comparés aux benchmarks Hugging Face dans le même cluster Databricks Single Node :


    Spark NLP est jusqu'à 15 % plus rapide que Hugging Face sur les processeurs pour prédire les classes d'images pour l'exemple de jeu de données avec des images 3K et jusqu'à 34 % sur le plus grand jeu de données avec des images 34K. Spark NLP est également 51 % plus rapide que Hugging Face sur un seul GPU pour un ensemble de données plus grand avec des images 34K et jusqu'à 36 % plus rapide sur un ensemble de données plus petit avec des images 3K.


    Spark NLP est plus rapide sur les CPU et les GPU par rapport à Hugging Face dans Databricks Single Node

    Évolutivité au-delà d'une seule machine

    Jusqu'à présent, nous avons établi que Hugging Face sur GPU est plus rapide que Hugging Face sur CPU sur un serveur bare metal et Databricks Single Node. C'est ce à quoi vous vous attendez lorsque vous comparez GPU et CPU avec ces nouveaux modèles basés sur des transformateurs.

    Nous avons également établi que Spark NLP surpasse Hugging Face pour le même pipeline (modèle ViT), sur les mêmes ensembles de données, à la fois dans le serveur bare-metal et le cluster à nœud unique Databricks, et il fonctionne mieux sur les périphériques CPU et GPU. Ce n'était pas quelque chose à quoi je m'attendais. Lorsque je préparais cet article, je m'attendais à ce que l'inférence TensorFlow dans Spark NLP soit légèrement plus lente que l'inférence dans Hugging Face en utilisant PyTorch ou au moins au coude à coude. Je visais cette section, en faisant évoluer le pipeline au-delà d'une seule machine . Mais il semble que Spark NLP soit plus rapide que Hugging Face, même sur une seule machine, à la fois sur CPU et GPU , sur des ensembles de données petits et grands .

    Question : Et si vous souhaitez rendre votre pipeline ViT encore plus rapide ? Que se passe-t-il si vous avez des ensembles de données encore plus volumineux et que vous ne pouvez tout simplement pas les intégrer dans une seule machine ou si cela prend trop de temps pour obtenir les résultats ?

    Réponse : Évoluez ! Cela signifie qu'au lieu de redimensionner la même machine, ajoutez plus de machines à votre cluster. Vous avez besoin de quelque chose pour gérer tous ces travaux/tâches/planification des DAG/gérer les tâches ayant échoué/etc. et ceux-ci ont leurs frais généraux, mais si vous avez besoin que quelque chose soit plus rapide ou possible (au-delà d'une seule machine), vous devez utiliser une sorte de système distribué.

    Mise à l'échelle = rendre votre machine plus grande ou plus rapide afin qu'elle puisse supporter plus de charge.

    Scaling out = ajouter plus de machines en parallèle pour répartir une charge.

    Mise à l'échelle du visage étreignant :

    En regardant la page sur le site Web officiel de Hugging Face, on suggère que l'inférence de mise à l'échelle n'est possible qu'en utilisant des multi-GPU. Comme nous décrivons ce qu'est la mise à l'échelle, cela reste bloqué sur une seule machine :

    https://huggingface.co/docs/transformers/performance

    Aussi, sans oublier que la solution Multi-GPUs pour l' inférence dans Hugging Face n'existe pas pour le moment :

    https://huggingface.co/docs/transformers/perf_infer_gpu_many

    Il semble donc qu'il n'existe aucun moyen natif/officiel de faire évoluer les pipelines de Hugging Face. Vous pouvez implémenter votre architecture composée de certains microservices tels qu'une file d'attente de tâches, des protocoles de messagerie, un backend d'API RESTful et d'autres composants requis pour distribuer chaque demande sur différentes machines, mais cela fait évoluer les demandes par des utilisateurs individuels au lieu de faire évoluer le système réel. lui-même.

    De plus, la latence de ces systèmes n'est pas comparable à celle des systèmes distribués nativement tels qu'Apache Spark (gRPC pourrait réduire cette latence, mais toujours pas compétitif). Sans parler du problème du point de défaillance unique, de la gestion des travaux/tâches/entrées ayant échoué et des centaines d'autres fonctionnalités prêtes à l'emploi d'Apache Spark que vous devez maintenant implémenter/maintenir vous-même.

    Il y a un article de blog sur le site Web de Hugging Face décrivant la même architecture en mettant à l'échelle les points de terminaison REST pour servir plus d'utilisateurs : « Déploiement de 🤗 ViT sur Kubernetes avec TF Serving » — Je pense que d'autres entreprises utilisent des approches similaires pour faire évoluer Hugging Face, cependant , ils mettent tous à l'échelle le nombre d'utilisateurs/requêtes atteignant les points de terminaison REST d'inférence. De plus, vous ne pouvez pas mettre à l'échelle Hugging Face de cette façon sur Databricks.

    Par exemple, l'inférence à l'intérieur de fastAPI est 10 fois plus lente que l'inférence locale : https://towardsdatascience.com/hugging-face-transformer-inference-under-1-millisecond-latency-e1be0057a51c

    Une fois que Hugging Face proposera des solutions natives pour évoluer, je réexécuterai à nouveau les tests de performance. Jusque-là, il n'y a pas de mise à l'échelle lorsque vous devez parcourir l'ensemble de données à partir d'une seule machine pour atteindre les points de terminaison REST dans un algorithme à tour de rôle. (repensez à la partie où nous avons regroupé les lignes/séquences/images pour alimenter le GPU en une seule fois, alors vous l'aurez compris)

    Mise à l'échelle de Spark NLP :

    Spark NLP est une extension de Spark ML. Il s'adapte donc de manière native et transparente sur toutes les plates-formes prises en charge par Apache Spark telles que (et sans s'y limiter) Databricks, AWS EMR, Azure Insight, GCP Dataproc, Cloudera, SageMaker, Kubernetes et bien d'autres.

    Aucun changement de code n'est nécessaire ! Spark NLP peut passer d'une seule machine à un nombre infini de machines sans rien changer au code !

    Vous n'avez pas non plus besoin d'exporter des modèles hors de Spark NLP pour l'utiliser dans une bibliothèque entièrement différente afin d'accélérer ou de mettre à l'échelle l'inférence.

    Écosystème Spark NLP : intégrations optimisées, testées et prises en charge

    Databricks Multi-Node avec CPU sur AWS

    Créons un cluster et cette fois, nous choisissons Standard dans le mode Cluster . Cela signifie que nous pouvons avoir plus d'un nœud dans notre cluster, ce qui, dans la terminologie Apache Spark, signifie 1 pilote et un nombre N de travailleurs (exécuteurs).

    Nous devons également installer Spark NLP dans ce nouveau cluster via l'onglet Bibliothèques. Vous pouvez suivre les étapes que j'ai mentionnées dans la section précédente pour les Databricks à nœud unique avec processeurs. Comme vous pouvez le voir, j'ai choisi la même instance AWS basée sur le processeur que j'ai utilisée pour évaluer à la fois Hugging Face et Spark NLP afin que nous puissions voir comment elle évolue lorsque nous ajoutons plus de nœuds.

    Voici à quoi ressemblent nos configurations de cluster :

    Cluster Databricks multi-nœuds (standard) avec uniquement des processeurs

    Je réutiliserai le même pipeline Spark NLP que j'ai utilisé dans les benchmarks précédents (pas besoin de modifier le code) et je n'utiliserai également que le plus grand ensemble de données avec des images 34K. Commençons!

    Mettre à l'échelle Spark NLP sur des processeurs avec 2 nœuds

    Databricks avec 2 nœuds – CPU uniquement

    Ajoutons simplement 1 nœud de plus et faisons le total des machines qui effectueront le traitement sur 2 machines. N'oublions pas la beauté de Spark NLP lorsque vous passez d'une configuration de machine unique (votre Colab, Kaggle, Databricks Single Node ou même votre notebook Jupyter local) à une configuration de cluster à plusieurs nœuds (Databricks, EMR, GCP, Azure, Cloudera , YARN, Kubernetes, etc.), un changement de code zéro est requis ! Et je veux dire zéro ! Dans cet esprit, j'exécuterai le même benchmark à l'intérieur de ce nouveau cluster sur les ensembles de données plus grands avec des images 34K :

    Pipeline de classification d'images Spark NLP sur 2x nœuds avec CPU (oneDNN) - prédisant 34742 images

    Il a fallu environ 9 minutes ( 550 secondes ) pour terminer la prédiction des classes pour les images 34K. Comparons ce résultat sur 2x nœuds avec les résultats Spark NLP et Hugging Face sur un seul nœud Databricks (je continuerai à répéter les résultats Hugging Face sur un nœud unique comme référence car Hugging Face ne peut pas être mis à l'échelle sur plusieurs machines, en particulier sur Databricks) :

    Spark NLP est 124% plus rapide que Hugging Face avec 2x Nodes

    Auparavant, Spark NLP battait Hugging Face sur un cluster Databricks à nœud unique en utilisant uniquement les processeurs de 15 % .

    Cette fois, en n'ayant que 2 nœuds au lieu d'un nœud, Spark NLP a terminé le processus de plus de 34 000 images 124 % plus rapidement que Hugging Face.Scale Spark NLP sur des processeurs avec 4 nœuds.

    Doublez la taille de notre cluster comme avant et passez de 2x nœuds à 4x nœuds. Voici à quoi ressemblerait le cluster avec 4 nœuds :

    Databricks avec 4 nœuds – CPU uniquement

    Je vais exécuter le même benchmark sur ce nouveau cluster sur les ensembles de données plus grands avec des images 34K :

    Pipeline de classification d'images Spark NLP sur des nœuds 4x avec des processeurs (oneDNN) - prédisant 34742 images

    Il a fallu environ 5 minutes ( 289 secondes ) pour terminer la prédiction des classes pour les images 34K. Comparons ce résultat sur les nœuds 4x avec Spark NLP vs. Hugging Face sur les processeurs sur Databricks :

    Spark NLP est 327% plus rapide que Hugging Face avec 4x Nodes

    Comme on peut le voir, Spark NLP est désormais 327% plus rapide que Hugging Face sur les CPU tout en n'utilisant que 4x Nodes dans Databricks.

    Mettre à l'échelle Spark NLP sur des processeurs avec 8 nœuds

    Maintenant, doublons le cluster précédent en ajoutant 4x plus de nœuds et obtenons un total de 8x nœuds . Soit dit en passant, ce redimensionnement du cluster est assez simple, il vous suffit d'augmenter le nombre de nœuds de calcul dans vos configurations de cluster :

    Redimensionner le cluster Spark dans Databricks

    Databricks avec 8 nœuds – CPU uniquement

    Exécutons le même benchmark cette fois sur 8 nœuds :

    Pipeline de classification d'images Spark NLP sur 8x nœuds avec CPU (oneDNN) - prévision de 34742 images

    Il a fallu plus de 2 minutes et demie ( 161 secondes ) pour terminer la prédiction des classes pour les images 34K. Comparons ce résultat sur les nœuds 8x avec Spark NLP vs. Hugging Face sur les processeurs sur Databricks :

    Spark NLP est 666% plus rapide que Hugging Face avec 8x nœuds

    Comme on peut le voir, Spark NLP est désormais 666 % plus rapide que Hugging Face sur les processeurs tout en n'utilisant que 8 nœuds dans Databricks.

    Ignorons simplement le nombre de 6 ici ! (il était de 665,8 % si cela vous fait vous sentir mieux)

    Mettre à l'échelle Spark NLP sur des processeurs avec 10 nœuds

    Pour terminer la mise à l'échelle de nos prédictions de modèles ViT sur les processeurs dans Databricks à l'aide de Spark NLP, je redimensionnerai le cluster une fois de plus et l'augmenterai à 10 nœuds :

    Databricks avec 10 nœuds – CPU uniquement

    Exécutons le même benchmark cette fois sur 10 nœuds :

    Pipeline de classification d'images Spark NLP sur 10 nœuds avec processeurs (oneDNN) - prévision de 34742 images

    Il a fallu moins de 2 minutes ( 112 secondes ) pour terminer la prédiction des classes pour les images 34K. Comparons ce résultat sur 10 nœuds avec tous les résultats précédents de Spark NLP contre Hugging Face sur des processeurs sur Databricks :

    Spark NLP est 1000% plus rapide que Hugging Face avec 10x nœuds

    Et c'est ainsi que vous étendez le modèle Vision Transformer provenant de Hugging Face sur 10x Nodes en utilisant Spark NLP dans Databricks ! Notre pipeline est désormais 1000 % plus rapide que Hugging Face sur les processeurs.

    Nous avons réussi à rendre notre pipeline ViT 1000% plus rapide que Hugging Face qui est bloqué dans 1 seul nœud en utilisant simplement Spark NLP, mais nous n'avons utilisé que des CPU . Voyons si nous pouvons obtenir les mêmes améliorations en faisant évoluer notre pipeline sur un cluster GPU .

    Databricks Multi-Node avec GPU sur AWS

    Avoir un cluster Databricks multi-nœuds basé sur GPU revient à peu près à avoir un cluster à nœud unique. La seule différence est de choisir Standard et de conserver le même runtime ML/GPU avec les mêmes spécifications d'instance AWS que nous avons choisies dans nos benchmarks pour GPU sur un seul nœud.

    Nous devons également installer Spark NLP dans ce nouveau cluster via l'onglet Bibliothèques . Comme précédemment, vous pouvez suivre les étapes que j'ai mentionnées dans Single Node Databricks with a GPU.

    Cluster Databricks multi-nœuds (standard) avec GPU

    Mettre à l'échelle Spark NLP sur des GPU avec 2 nœuds

    Notre cluster GPU Databricks multinœud utilise la même instance GPU AWS de g4dn.8xlarge que celle que nous avons utilisée précédemment pour exécuter nos benchmarks afin de comparer Spark NLP à Hugging Face sur un cluster Databricks à nœud unique.

    Voici un résumé de ce à quoi cela ressemble cette fois avec 2 nœuds :

    Databricks avec 2 nœuds — avec 1 GPU par nœud

    Je vais exécuter le même pipeline dans ce cluster GPU avec 2 nœuds :

    Pipeline de classification d'images Spark NLP sur des nœuds 2x avec GPU - prévision de 34742 images

    Il a fallu 4 minutes ( 231 secondes ) pour terminer la prédiction des classes pour les images 34K . Comparons ce résultat sur 2x nœuds avec Spark NLP vs. Hugging Face sur les GPU dans Databricks :

    Spark NLP est 185 % plus rapide que Hugging Face avec 2 nœuds

    Spark NLP avec 2 nœuds est presque 3 fois plus rapide ( 185 % ) que Hugging Face sur 1 seul nœud tout en utilisant le GPU.

    Mettre à l'échelle Spark NLP sur des GPU avec des nœuds 4x

    Redimensionnons notre cluster GPU de 2x nœuds à 4x nœuds. Voici un résumé de ce à quoi cela ressemble cette fois avec 4x nœuds utilisant un GPU :

    Databricks avec 4 nœuds — avec 1 GPU par nœud

    Exécutons le même benchmark sur 4 nœuds et voyons ce qui se passe :

    Pipeline de classification d'images Spark NLP sur des nœuds 4x avec GPU - prévision de 34742 images

    Cette fois, il a fallu près de 2 minutes ( 118 secondes ) pour finir de classer toutes les images 34K de notre jeu de données. Visualisons cela juste pour avoir une meilleure vue de ce que cela signifie en termes de Hugging Face dans un seul nœud par rapport à Spark NLP dans un cluster à plusieurs nœuds :

    Spark NLP est 458% plus rapide que Hugging Face avec 4x Nodes

    C'est une augmentation de 458% des performances par rapport à Hugging Face. Nous venons de rendre notre pipeline 5,6 fois plus rapide en utilisant Spark NLP avec 4 nœuds.

    Mettez à l'échelle Spark NLP sur des GPU avec des nœuds 8x

    Ensuite, je redimensionnerai le cluster pour avoir 8 nœuds dans mes Databricks avec le résumé suivant :

    Databricks avec 8 nœuds — avec 1 GPU par nœud

    Pour rappel, chaque instance AWS ( g4dn.8xlarge ) possède 1 GPU NVIDIA T4 16 Go (15 Go de mémoire utilisable). Exécutons à nouveau le benchmark et voyons si nous pouvons repérer des améliorations, car la mise à l'échelle dans n'importe quel système distribué a ses frais généraux et vous ne pouvez pas simplement continuer à ajouter des machines :

    Pipeline de classification d'images Spark NLP sur des nœuds 8x avec GPU - prévision de 34742 images

    Il a fallu près d'une minute ( 61 secondes ) pour terminer la classification des images 34K avec 8x nœuds dans notre cluster Databricks. Il semble que nous ayons quand même réussi à améliorer les performances. Mettons ce résultat à côté des résultats précédents de Hugging Face dans un seul nœud par rapport à Spark NLP dans un cluster à plusieurs nœuds :

    Spark NLP est 980 % plus rapide que Hugging Face avec 8 nœuds.

    Spark NLP avec 8 nœuds est presque 11 fois plus rapide (980 %) que Hugging Face sur les GPU.

    Mettre à l'échelle Spark NLP sur des GPU avec 10 nœuds

    Semblable à nos benchmarks multi-nœuds sur les CPU, je voudrais redimensionner le cluster GPU une fois de plus pour avoir 10x nœuds et les faire correspondre en termes de nombre final de nœuds. Le résumé final de ce cluster est le suivant :

    Databricks avec 10 nœuds — avec 1 GPU par nœud

    Exécutons notre tout dernier benchmark dans ce cluster GPU spécifique (sans aucun changement de code) :

    Pipeline de classification d'images Spark NLP sur 10 nœuds avec GPU - prévision de 34 742 images

    Il a fallu moins d'une minute ( 51 secondes ) pour finir de prédire les classes pour plus de 34743 images . Mettons-les tous les uns à côté des autres et voyons comment nous avons progressé dans la mise à l'échelle de notre modèle Vision Transformer provenant de Hugging Face dans le pipeline Spark NLP dans Databricks :

    Spark NLP est 1200% plus rapide que Hugging Face avec 10x nœuds

    Et nous avons terminé !

    Nous avons réussi à faire évoluer notre modèle Vision Transformer provenant de Hugging Face sur 10x Nodes en utilisant Spark NLP dans Databricks ! Notre pipeline est désormais 13 fois plus rapide avec des améliorations de performances de 1200 % par rapport à Hugging Face sur GPU.

    Résumons tous ces points de repère en comparant d'abord les améliorations entre les processeurs et les GPU, puis à quel point notre pipeline peut être plus rapide en passant des processeurs Hugging Face aux nœuds 10x sur Databricks en utilisant Spark NLP sur les GPU.

    Rassembler le tout :

    Databricks : nœud unique et nœuds multiples

    Spark NLP 🚀 sur 10x nœuds avec CPU est 1000% (11x fois) plus rapide que Hugging Face 🤗 coincé dans un seul nœud avec CPU


    Spark NLP 🚀 sur 10x nœuds avec GPU est 1192% (13x fois) plus rapide que Hugging Face 🤗 coincé dans un seul nœud avec GPU

    Qu'en est-il des différences de prix entre notre instance CPU AWS et l'instance GPU AWS ? (Je veux dire, vous obtenez plus si vous payez plus, non ?)

    AWS m5d.8xlarge avec processeurs par rapport à AWS g4dn.8xlarge avec 1 GPU et spécifications similaires

    OK, donc le prix semble à peu près le même! Dans cet esprit, quelles améliorations obtenez-vous si vous passez de Hugging Face sur des CPU bloqués dans une seule machine à Spark NLP sur 10x Nodes avec 10x GPU ?

    Spark NLP sur GPU est 25 fois (2366%) plus rapide que Hugging Face sur CPU

    Spark NLP 🚀 sur 10x nœuds avec GPU est 2366% (25x fois) plus rapide que Hugging Face 🤗 dans un seul nœud avec CPU

    Derniers mots

    • Dans un esprit de transparence totale, tous les cahiers avec leurs logs, captures d'écran, et même la feuille excel avec les chiffres sont fournis ici sur GitHub
    • La mise à l'échelle de Spark NLP ne nécessite aucune modification de code. Exécuter les benchmarks d'un seul nœud Databricks aux 10 nœuds signifiait simplement réexécuter le même bloc de code dans le même bloc-notes
    • Gardez à l'esprit que ces deux bibliothèques sont accompagnées de nombreuses bonnes pratiques pour optimiser leur vitesse et leur efficacité dans différents environnements pour différents cas d'utilisation. Par exemple, je n'ai pas parlé des partitions et de leur relation avec le parallélisme et les distributions dans Apache Spark. Il existe de nombreuses configurations Spark pour affiner un cluster, en particulier en équilibrant le nombre de tâches entre les CPU et les GPU. Maintenant, la question est de savoir s'il serait possible d'accélérer l'un d'entre eux dans les mêmes environnements que nous avons utilisés pour nos benchmarks ? La réponse est 100% ! J'ai essayé de tout conserver pour les deux bibliothèques avec des valeurs par défaut et des fonctionnalités prêtes à l'emploi en faveur de la simplicité pour la majorité des utilisateurs.
    • Vous voudrez peut-être envelopper Hugging Face et d'autres bibliothèques Pythonish basées sur DL dans une UDF Spark pour les mettre à l'échelle. Cela fonctionne dans une certaine mesure comme je l'ai fait moi-même et que je le fais toujours (quand il n'y a pas de solution native). Je n'entrerai pas dans les détails de l'utilisation excessive de la mémoire, des problèmes de sérialisation possibles, d'une latence plus élevée et d'autres problèmes lorsque l'on encapsule de tels modèles basés sur des transformateurs dans une UDF. Je dirais simplement que si vous utilisez Apache Spark, utilisez la bibliothèque qui étend nativement vos fonctionnalités requises sur Apache Spark.
    • Tout au long de cet article, j'ai fait tout mon possible pour mentionner Hugging Face sur PyTorch et Spark NLP sur TensorFlow. C'est une grande différence étant donné que dans chaque benchmark effectué par Hugging Face entre PyTorch et TensorFlow, PyTorch était et est toujours le gagnant pour l'inférence. Dans Hugging Face, PyTorch a juste une latence beaucoup plus faible et il semble être beaucoup plus rapide que TensorFlow dans Transformers. Le fait que Spark NLP utilise le même TensorFlow et se démarque dans tous les benchmarks par rapport à PyTorch dans Hugging Face est un gros problème. Soit le TensorFlow dans Hugging Face est négligé, soit PyTorch est juste plus rapide en inférence par rapport à TensorFlow. Quoi qu'il en soit, j'ai hâte de voir ce qui se passera lorsque Spark NLP commencera à prendre en charge TorchScript et ONNX Runtime en plus de TensorFlow.
    • Les runtimes ML et ML GPU Databricks sont livrés avec Hugging Face installé, c'est plutôt sympa. Mais cela ne signifie pas que Hugging Face est facile à utiliser dans Databricks. La bibliothèque Transformer de Hugging Face ne prend pas en charge DBFS (le système de fichiers distribué natif de Databricks) ou Amazon S3. Comme vous le voyez dans les cahiers, j'ai dû télécharger une version compressée des jeux de données et les extraire pour les utiliser. Ce n'est pas vraiment ainsi que les utilisateurs de Databricks et d'autres plates-formes de production font les choses. Nous conservons nos données dans des systèmes de fichiers distribués, des mesures de sécurité sont mises en œuvre et la plupart d'entre elles sont suffisamment volumineuses pour ne pas être téléchargées par un ordinateur personnel. J'ai dû télécharger les jeux de données que j'avais déjà sur DBFS, les compresser, les télécharger sur S3, les rendre publics et les retélécharger dans les cahiers. Un processus assez fastidieux qui aurait pu être évité si Hugging Face pouvait prendre en charge DBFS/S3.

    Références

    Vit

    Visage étreignant

    Databrick

    Étincelle PNL