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 :
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
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
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/food — https://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.
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 🚀
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 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.
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)
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.
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
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.
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)
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
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!
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.
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)
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 .
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
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.
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.
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.
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.
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
Vit
Visage étreignant
Databrick
Étincelle PNL