paint-brush
Scale Vision Transformers (ViT) Más allá de abrazar la carapor@maziyar
4,590 lecturas
4,590 lecturas

Scale Vision Transformers (ViT) Más allá de abrazar la cara

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

Demasiado Largo; Para Leer

El propósito de este artículo es demostrar cómo escalar los modelos Vision Transformer (ViT) de Hugging Face e implementarlos en entornos listos para producción para una inferencia acelerada y de alto rendimiento. Al final, escalaremos un modelo ViT de Hugging Face 25 veces (2300 %) mediante el uso de Databricks, Nvidia y Spark NLP.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Scale Vision Transformers (ViT) Más allá de abrazar la cara
Maziyar Panahi HackerNoon profile picture

Acelera los modelos ViT de última generación en Hugging Face 🤗 hasta un 2300 % (25 veces más rápido) con Databricks, Nvidia y Spark NLP 🚀

Soy uno de los colaboradores del proyecto de código abierto Spark NLP y, recientemente, esta biblioteca comenzó a admitir modelos Vision Transformers (ViT) de extremo a extremo. Utilizo Spark NLP y otras bibliotecas de código abierto ML/DL para el trabajo diario y he decidido implementar una canalización de ViT para una tarea de clasificación de imágenes de última generación y proporcionar comparaciones detalladas entre Hugging Face y Spark NLP .

El propósito de este artículo es demostrar cómo escalar los modelos Vision Transformer (ViT) de Hugging Face e implementarlos en entornos listos para producción para una inferencia acelerada y de alto rendimiento. Al final, escalaremos un modelo ViT de Hugging Face 25 veces (2300 %) mediante el uso de Databricks, Nvidia y Spark NLP.

En este artículo voy a:

  • Una breve introducción a Vision Transformer (ViT)
  • Benchmark Hugging Face dentro del servidor Dell en CPU y GPU
  • Benchmark Spark NLP dentro del servidor Dell en CPU y GPU
  • Benchmark Hugging Face dentro de Databricks Single Node en CPU y GPU
  • Benchmark Spark NLP dentro de Databricks Single Node en CPU y GPU
  • Benchmark Spark NLP dentro de Databricks escalado a 10x Nodos con CPU y GPU
  • ¡Resume todo!
  • Con el espíritu de total transparencia, todos los cuadernos con sus registros, capturas de pantalla e incluso la hoja de Excel con números se proporcionan aquí en GitHub .

    Introducción a los modelos Vision Transformer (ViT)

    En 2017, un grupo de investigadores de Google AI publicó un artículo que introdujo una arquitectura de modelo de transformador que cambió todos los estándares de procesamiento de lenguaje natural (NLP). El documento describe un mecanismo novedoso llamado autoatención como un modelo nuevo y más eficiente para las aplicaciones del lenguaje. Por ejemplo, las dos familias más populares de modelos basados en transformadores son GPT y BERT.

    Un poco de historia de Transformer https://huggingface.co/course/chapter1/4

    Hay un gran capítulo sobre " Cómo funcionan los transformadores " que recomiendo leer si está interesado.

    Aunque estos nuevos modelos basados en Transformer parecen estar revolucionando las tareas de NLP, su uso en Computer Vision (CV) se mantuvo bastante limitado. El campo de la visión artificial ha estado dominado por el uso de redes neuronales convolucionales (CNN) y existen arquitecturas populares basadas en CNN (como ResNet). Este había sido el caso hasta que otro equipo de investigadores, esta vez en Google Brain, presentó el "Transformador de visión" (ViT) en junio de 2021 en un artículo titulado: " Una imagen vale 16x16 palabras: transformadores para el reconocimiento de imágenes a escala ".

    Este documento representa un gran avance en lo que respecta al reconocimiento de imágenes mediante el uso del mismo mecanismo de autoatención que se utiliza en los modelos basados en transformadores, como BERT y GPT, como acabamos de analizar. En modelos de lenguaje basados en Transformed como BERT, la entrada es una oración (por ejemplo, una lista de palabras). Sin embargo, en los modelos ViT, primero dividimos una imagen en una cuadrícula de parches de subimagen, luego incrustamos cada parche con un proyecto lineal antes de que cada parche incrustado se convierta en un token. El resultado es una secuencia de parches de incrustaciones que pasamos al modelo similar a BERT.

    Una descripción general de la estructura del modelo ViT tal como se presentó en el artículo original de Google Research de 2021

    Vision Transformer se enfoca en una mayor precisión pero con menos tiempo de cómputo. Al observar los puntos de referencia publicados en el documento, podemos ver que el tiempo de entrenamiento con el conjunto de datos de Noisy Student (publicado por Google en junio de 2020) se redujo en un 80 %, aunque el estado de precisión es más o menos el mismo. Para obtener más información sobre el desempeño de ViT hoy, debe visitar su página en Papers With Code :

    Comparación con el estado del arte en los puntos de referencia de clasificación de imágenes populares. ( https://arxiv.org/pdf/2010.11929.pdf )

    También es importante mencionar que una vez que haya entrenado un modelo a través de la arquitectura ViT, puede entrenar previamente y ajustar su transformador tal como lo hace en NLP. (¡eso es genial en realidad!)

    Si comparamos los modelos ViT con las CNN, podemos ver que tienen una mayor precisión con un costo mucho menor para los cálculos. Puede usar modelos ViT para una variedad de tareas posteriores en Computer Vision, como la clasificación de imágenes, la detección de objetos y la segmentación de imágenes. Esto también puede ser específico del dominio en Atención médica, puede pre-entrenar/afinar sus modelos ViT para fracturas de fémur , enfisema , cáncer de mama , COVID-19 y enfermedad de Alzheimer.¹

    Dejaré referencias al final de este artículo en caso de que quiera profundizar en cómo funcionan los modelos ViT.

    [1]: Inmersión profunda: Vision Transformers en Hugging Face Optimum Graphcore https://huggingface.co/blog/vision-transformers

    Algunos modelos ViT en acción

    Modelo Vision Transformer (ViT) ( vit-base-patch16–224 ) entrenado previamente en ImageNet-21k (14 millones de imágenes, 21 843 clases) a una resolución de 224x224 y ajustado en ImageNet 2012 (1 millón de imágenes, 1000 clases) en resolución 224x224:

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

    Modelos ViT perfeccionados utilizados para la clasificación de alimentos:

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

    Sin embargo, existen limitaciones y restricciones para cualquier modelo DL/ML en lo que respecta a la predicción. No existe un modelo con una precisión del 100 %, así que tenlo en cuenta cuando los utilices para algo importante como el cuidado de la salud:

    La imagen se tomó de: https://www.akc.org/expert-advice/lifestyle/do-you-live-in-dog-state-or-cat-state/ — Modelo ViT : https://huggingface.co /julien-c/hotdog-no-hotdog


    ¿Podemos usar estos modelos de Hugging Face o ajustar nuevos modelos de ViT y usarlos para inferencia en producción real? ¿Cómo podemos escalarlos mediante el uso de servicios administrados para cómputos distribuidos como AWS EMR, Azure Insight, GCP Dataproc o Databricks?

    Con suerte, algunos de estos serán respondidos al final de este artículo.

    ¡Que comiencen los puntos de referencia!

    Algunos detalles sobre nuestros puntos de referencia:

    1- Conjunto de datos: ImageNet mini: muestra (>3K) — completo (>34K)

    He descargado el conjunto de datos ImageNet 1000 (mini) de Kaggle: https://www.kaggle.com/datasets/ifigotin/imagenetmini-1000

    Elegí el directorio de trenes con más de 34K imágenes y lo llamé imagenet-mini ya que todo lo que necesitaba eran suficientes imágenes para hacer puntos de referencia que toman más tiempo. Además, seleccioné aleatoriamente menos del 10 % del conjunto de datos completo y lo llamé imagenet-mini-sample, que tiene 3544 imágenes para mis puntos de referencia más pequeños y también para ajustar los parámetros correctos, como el tamaño del lote.

    2- Modelo: El “ vit-base-patch16–224 ” de Google

    Usaremos este modelo de Google alojado en Hugging Face: https://huggingface.co/google/vit-base-patch16-224

    3- Bibliotecas: Transformers 🤗 & Spark NLP 🚀

    Evaluación comparativa de Hugging Face en un servidor Bare Metal

    Modelo ViT en un Dell PowerEdge C4130

    ¿Qué es un servidor bare-metal? Un servidor bare - metal es solo una computadora física que solo está siendo utilizada por un usuario. No hay hipervisor instalado en esta máquina, no hay virtualizaciones y todo se ejecuta directamente en el sistema operativo principal (Linux — Ubuntu): las especificaciones detalladas de las CPU, las GPU y la memoria de esta máquina están dentro de las computadoras portátiles.

    Como han revelado mis pruebas iniciales y casi todas las publicaciones de blog escritas por el equipo de ingeniería de Hugging Face que comparan la velocidad de inferencia entre los motores DL, el mejor rendimiento para la inferencia en la biblioteca Hugging Face (Transformer) se logra usando PyTorch sobre TensorFlow. No estoy seguro de si esto se debe a que TensorFlow es un ciudadano de segunda clase en Hugging Face debido a menos funciones compatibles, menos modelos compatibles, menos ejemplos, tutoriales obsoletos y encuestas anuales durante los últimos 2 años respondidas por usuarios que preguntan más por TensorFlow. o PyTorch simplemente tiene una latencia más baja en la inferencia tanto en la CPU como en la GPU.
    TensorFlow sigue siendo el marco de aprendizaje profundo más utilizado

    Independientemente de la razón, elegí PyTorch en la biblioteca Hugging Face para obtener los mejores resultados para nuestros puntos de referencia de clasificación de imágenes. Este es un fragmento de código simple para usar un modelo ViT (PyTorch, por supuesto) en 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] )

    Esto puede parecer sencillo para predecir una imagen como entrada, pero no es adecuado para grandes cantidades de imágenes, especialmente en una GPU. Para evitar predecir imágenes secuencialmente y aprovechar hardware acelerado como GPU, es mejor alimentar el modelo con lotes de imágenes, lo que es posible en Hugging Face a través de Pipelines . No hace falta decir que puede implementar su técnica de procesamiento por lotes ya sea extendiendo las tuberías de Hugging Face o haciéndolo por su cuenta.

    Una tubería simple para la clasificación de imágenes se verá así:

     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 )

    Según la documentación, he descargado/cargado google/vit-base-patch16–224 para el extractor de características y el modelo (puntos de control de PyTorch, por supuesto) para usarlos en la canalización con la clasificación de imágenes como tarea. Hay 3 cosas en esta tubería que son importantes para nuestros puntos de referencia:

    > dispositivo : si es -1 (predeterminado), solo usará CPU, mientras que si es un número int positivo, ejecutará el modelo en la identificación del dispositivo CUDA asociado (es mejor ocultar las GPU y obligar a PyTorch a usar CPU y no solo confíe en este número aquí).

    > tamaño_lote: cuando la canalización usará DataLoader (al pasar un conjunto de datos, en GPU para un modelo Pytorch), el tamaño del lote a usar, para la inferencia, no siempre es beneficioso.

    > Debe usar DataLoader o PyTorch Dataset para aprovechar al máximo el procesamiento por lotes en canalizaciones Hugging Face en una GPU.

    Antes de avanzar con los puntos de referencia, debe saber una cosa sobre el procesamiento por lotes en Hugging Face Pipelines para la inferencia, que no siempre funciona. Como se indica en la documentación de Hugging Face, es posible que configurar batch_size no aumente en absoluto el rendimiento de su canalización. Puede ralentizar su canalización:

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

    Para ser justos, en mis puntos de referencia utilicé una variedad de tamaños de lote a partir de 1 para asegurarme de que puedo encontrar el mejor resultado entre ellos. Así es como comparé la canalización Hugging Face en la 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

    Echemos un vistazo a los resultados de nuestro primer punto de referencia para la tubería de clasificación de imágenes Hugging Face en CPU sobre el conjunto de datos ImageNet de muestra (3K):

    Tubería de clasificación de imágenes Hugging Face en CPU: predicción de 3544 imágenes

    Como se puede ver, tomó alrededor de 3 minutos ( 188 segundos) terminar de procesar alrededor de 3544 imágenes del conjunto de datos de muestra. Ahora que sé qué tamaño de lote (8) es el mejor para mi tubería/conjunto de datos/hardware, puedo usar la misma tubería en un conjunto de datos más grande ( imágenes de 34K ) con este tamaño de lote:

    Tubería de clasificación de imágenes Hugging Face en CPU: predicción de 34745 imágenes

    Esta vez tomó alrededor de 31 minutos ( 1879 segundos ) terminar de predecir clases para 34745 imágenes en CPU.

    Para mejorar la mayoría de los modelos de aprendizaje profundo, especialmente estos nuevos modelos basados en transformadores, se debe usar hardware acelerado como GPU. Echemos un vistazo a cómo comparar la misma canalización con los mismos conjuntos de datos, pero esta vez en un dispositivo GPU . Como se mencionó anteriormente, necesitamos cambiar el dispositivo a una identificación de dispositivo CUDA como 0 (la primera 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
    

    Además de establecer device=0, también seguí la forma recomendada de ejecutar un modelo PyTorch en un dispositivo GPU a través de .to(device). Dado que usamos hardware acelerado (GPU), también aumenté el tamaño máximo de lote para mis pruebas a 1024 para encontrar el mejor resultado.

    Echemos un vistazo a nuestra canalización de clasificación de imágenes Hugging Face en un dispositivo GPU sobre el conjunto de datos de ImageNet de muestra (3K):

    Tubería de clasificación de imágenes Hugging Face en una GPU: predicción de 3544 imágenes

    Como se puede ver, tomó alrededor de 50 segundos terminar de procesar alrededor de 3544 imágenes de nuestro conjunto de datos de minimuestra de imagenet en un dispositivo GPU . El procesamiento por lotes mejoró la velocidad, especialmente en comparación con los resultados provenientes de las CPU, sin embargo, las mejoras se detuvieron alrededor del tamaño de lote de 32. Aunque los resultados son los mismos después del tamaño de lote 32, he elegido el tamaño de lote 256 para mi punto de referencia más grande para utilizar suficiente memoria GPU también.

    Tubería de clasificación de imágenes Hugging Face en una GPU: predicción de 34745 imágenes

    Esta vez, nuestro punto de referencia tomó alrededor de 8:17 minutos ( 497 segundos ) para terminar de predecir clases para 34745 imágenes en un dispositivo GPU . Si comparamos los resultados de nuestros puntos de referencia en CPU y un dispositivo GPU, podemos ver que la GPU aquí es la ganadora:

    Hugging Face (PyTorch) es hasta 3,9 veces más rápido en GPU que en CPU

    Utilicé Hugging Face Pipelines para cargar los puntos de control de ViT PyTorch, cargar mis datos en el conjunto de datos de la antorcha y usar el procesamiento por lotes provisto listo para usar en el modelo tanto en la CPU como en la GPU. La GPU es hasta ~3,9 veces más rápida en comparación con la ejecución de las mismas canalizaciones en las CPU.

    Hemos mejorado nuestra canalización de ViT para realizar la clasificación de imágenes mediante el uso de un dispositivo de GPU en lugar de CPU, pero ¿podemos mejorar aún más nuestra canalización tanto en CPU como en GPU en una sola máquina antes de escalarla a varias máquinas? Echemos un vistazo a la biblioteca Spark NLP.

    Spark NLP: procesamiento de lenguaje natural de última generación

    Spark NLP es una biblioteca de procesamiento de lenguaje natural de última generación de código abierto ( https://github.com/JohnSnowLabs/spark-nlp )

    Spark NLP es una biblioteca de procesamiento de lenguaje natural de última generación construida sobre Apache Spark. Proporciona anotaciones de NLP simples, eficaces y precisas para canalizaciones de aprendizaje automático que escalan fácilmente en un entorno distribuido. Spark NLP viene con más de 7000 canalizaciones y modelos preentrenados en más de 200 idiomas . También ofrece tareas como tokenización, segmentación de palabras, etiquetado de partes del discurso, incrustaciones de palabras y oraciones, reconocimiento de entidades nombradas, análisis de dependencias, revisión ortográfica, clasificación de textos, análisis de sentimientos, clasificación de tokens, traducción automática (+180 idiomas), Resumen y respuesta a preguntas, generación de texto, clasificación de imágenes (ViT) y muchas más tareas de PNL .

    Spark NLP es la única biblioteca NLP de código abierto en producción que ofrece transformadores de última generación como BERT , CamemBERT , ALBERT , ELECTRA , XLNet , DistilBERT , RoBERTa , DeBERTa , XLM-RoBERTa , Longformer , ELMO , Universal Sentence Encoder , Google T5 , MarianMT , GPT2 y Vision Transformer ( ViT ) no solo para Python y R , sino también para el ecosistema JVM ( Java , Scala y Kotlin ) a escala al extender Apache Spark de forma nativa.

    Evaluación comparativa de Spark NLP en un servidor bare metal

    Modelos ViT en un Dell PowerEdge C4130

    Spark NLP tiene las mismas características de ViT para la clasificación de imágenes que Hugging Face que se agregaron en la versión reciente 4.1.0 . La función se llama ViTForImageClassification, tiene más de 240 modelos preentrenados listos para usar , y un código simple para usar esta función en Spark NLP se ve así:

     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 comparamos Spark NLP y Hugging Face uno al lado del otro para descargar y cargar un modelo ViT previamente entrenado para una predicción de clasificación de imágenes, además de cargar imágenes y usar cálculos posteriores como argmax fuera de la biblioteca Hugging Face, ambos son bastante sencillos. Además, ambos se pueden guardar y servir más tarde como canalización para reducir estas líneas a solo 1 línea de código:

    Carga y uso de modelos ViT para clasificación de imágenes en Spark NLP (izquierda) y Hugging Face (derecha)

    Dado que Apache Spark tiene un concepto llamado Lazy Evaluation , no inicia la ejecución del proceso hasta que se llama a una ACCIÓN . Las acciones en Apache Spark pueden ser .count() o .show() o .write() y muchas otras operaciones basadas en RDD que no abordaré ahora y que no necesitará conocer para este artículo. Por lo general, elijo contar () la columna de destino o escribir () los resultados en los discos para activar la ejecución de todas las filas en el DataFrame. Además, al igual que los puntos de referencia de Hugging Face, revisaré los tamaños de lote seleccionados para asegurarme de que puedo tener todos los resultados posibles sin perder el mejor resultado.

    Ahora, sabemos cómo cargar modelos de ViT en Spark NLP, también sabemos cómo desencadenar una acción para forzar el cálculo en todas las filas de nuestro DataFrame para comparar, y todo lo que queda por aprender es oneDNN de oneAPI Deep Neural Biblioteca de red (oneDNN) . Dado que el motor DL en Spark NLP es TensorFlow, también puede habilitar oneDNN para mejorar la velocidad en las CPU (como todo lo demás, debe probar esto para asegurarse de que mejora la velocidad y no al revés). También usaré esta bandera además de las CPU normales sin oneDNN habilitado

    Ahora que sabemos que todos los modelos ViT de Hugging Face también están disponibles en Spark NLP y cómo usarlos en una canalización, repetiremos nuestros puntos de referencia anteriores en el servidor de Dell completo para comparar CPU y GPU. Echemos un vistazo a los resultados de la canalización de clasificación de imágenes de Spark NLP en CPU sobre nuestro conjunto de datos ImageNet de muestra (3K):

    Canalización de clasificación de imágenes Spark NLP en una CPU sin oneDNN: predicción de 3544 imágenes

    Tomó alrededor de 2,1 minutos ( 130 segundos) terminar de procesar alrededor de 3544 imágenes de nuestro conjunto de datos de muestra. Tener un conjunto de datos más pequeño para probar diferentes tamaños de lote es útil para elegir el tamaño de lote adecuado para su tarea, su conjunto de datos y su máquina. Aquí está claro que el tamaño de lote 16 es el mejor tamaño para que nuestra canalización brinde el mejor resultado.

    También me gustaría habilitar oneDNN para ver si en esta situación específica mejora mi punto de referencia en comparación con las CPU sin oneDNN. Puede habilitar oneDNN en Spark NLP configurando la variable de entorno de TF_ENABLE_ONEDNN_OPTS en 1. Veamos qué sucede si habilito este indicador y vuelvo a ejecutar el punto de referencia anterior en la CPU para encontrar el mejor tamaño de lote:

    Canalización de clasificación de imágenes Spark NLP en una CPU con oneDNN: predicción de 3544 imágenes

    De acuerdo, claramente habilitar oneDNN para TensorFlow en esta situación específica mejoró nuestros resultados en al menos un 14 %. Ya que no tenemos que hacer/cambiar nada y todo lo que se necesita es exportar TF_ENABLE_ONEDNN_OPTS=1, voy a usar eso para el punto de referencia con un conjunto de datos más grande también para ver la diferencia. Aquí es unos segundos más rápido, pero el 14 % en el conjunto de datos más grande puede reducir minutos de nuestros resultados.

    Ahora que sé que el tamaño de lote de 16 para CPU sin oneDNN y el tamaño de lote de 2 para CPU con oneDNN habilitado tienen los mejores resultados, puedo continuar usando la misma canalización en un conjunto de datos más grande ( imágenes de 34K ):

    Canalización de clasificación de imágenes Spark NLP en CPU sin oneDNN: predicción de 34745 imágenes

    Esta vez, nuestro punto de referencia tomó alrededor de 24 minutos ( 1423 segundos ) para terminar de predecir clases para 34745 imágenes en un dispositivo de CPU sin oneDNN habilitado. Ahora veamos qué sucede si habilito oneDNN para TensorFlow y uso el tamaño de lote de 2 (los mejores resultados):

    Canalización de clasificación de imágenes Spark NLP en CPU con oneDNN: predicción de 34745 imágenes

    Esta vez tomó alrededor de 21 minutos ( 1278 segundos ). Como se esperaba de nuestros puntos de referencia de muestra, podemos ver alrededor del 11 % de mejoras en los resultados que redujeron los minutos en comparación con no tener oneDNN habilitado.

    Echemos un vistazo a cómo comparar la misma canalización en un dispositivo GPU. En Spark NLP, todo lo que necesita para usar GPU es iniciarlo con gpu=True cuando inicia la sesión de Spark NLP:

    chispa = chispanlp.start(gpu=Verdadero)
    # puedes configurar la memoria aquí también
    chispa = chispanlp.start(gpu=Verdadero, memoria="16g")

    ¡Eso es todo! Si tiene algo en su tubería que se puede ejecutar en GPU, lo hará automáticamente sin necesidad de hacer nada explícitamente.

    Echemos un vistazo a nuestra tubería de clasificación de imágenes Spark NLP en un dispositivo GPU sobre el conjunto de datos ImageNet de muestra (3K):

    Canalización de clasificación de imágenes NLP de Spark en una GPU: predicción de 3544 imágenes

    Por curiosidad para ver si mi cruzada para encontrar un buen tamaño de lote en un conjunto de datos más pequeño era correcta, ejecuté la misma canalización con GPU en un conjunto de datos más grande para ver si el tamaño de lote 32 tendría el mejor resultado:

    Canalización de clasificación de imágenes Spark NLP en una GPU: predicción de 34745 imágenes

    Afortunadamente, es el tamaño de lote 32 el que produce el mejor tiempo. Así que tomó alrededor de 4 minutos y medio ( 277 segundos).

    Seleccionaré los resultados de las CPU con oneDNN ya que fueron más rápidos y los compararé con los resultados de la GPU :

    Spark NLP (TensorFlow) es hasta 4,6 veces más rápido en GPU que en CPU (oneDNN)

    ¡Esto es genial! Podemos ver que Spark NLP en GPU es hasta 4,6 veces más rápido que las CPU, incluso con oneDNN habilitado.

    Echemos un vistazo a cómo se comparan estos resultados con los puntos de referencia de Hugging Face:

    Spark NLP es un 65 % más rápido que Hugging Face en CPU en la predicción de clases de imágenes para el conjunto de datos de muestra con imágenes de 3K y un 47 % en el conjunto de datos más grande con imágenes de 34K. Spark NLP también es un 79 % más rápido que Hugging Face en un solo conjunto de datos de inferencia de GPU más grande con imágenes de 34 000 y hasta un 35 % más rápido en un conjunto de datos más pequeño.


    Spark NLP fue más rápido que Hugging Face en una sola máquina al usar CPU o GPU: clasificación de imágenes con Vision Transformer (ViT)

    Spark NLP y Hugging Face en Databricks

    ¿Qué es un ladrillo de datos? Todos sus datos, análisis e inteligencia artificial en una sola plataforma

    Databricks es una plataforma basada en la nube con un conjunto de herramientas de ingeniería y ciencia de datos que muchas empresas utilizan ampliamente para procesar y transformar grandes cantidades de datos. Los usuarios usan Databricks para muchos propósitos, desde procesar y transformar grandes cantidades de datos hasta ejecutar muchas canalizaciones de ML/DL para explorar los datos.

    Descargo de responsabilidad: esta fue mi interpretación de Databricks, viene con muchas otras características y debería consultarlas: https://www.databricks.com/product/data-lakehouse

    Databricks es compatible con las nubes de AWS, Azure y GCP: https://www.databricks.com/product/data-lakehouse

    Abrazando la cara en un solo nodo de Databricks con CPU en AWS

    Databricks ofrece un tipo de clúster de "nodo único" cuando está creando un clúster que es adecuado para aquellos que desean usar Apache Spark con solo 1 máquina o usar aplicaciones que no son Spark, especialmente bibliotecas de Python basadas en ML y DL. Hugging Face ya viene instalado cuando elige el tiempo de ejecución de Databricks 11.1 ML. Así es como se ven las configuraciones de clúster para mis Databricks de un solo nodo (solo CPU) antes de comenzar con nuestros puntos de referencia:

    Clúster de un solo nodo de bricks: tiempo de ejecución de la CPU

    El resumen de este clúster que usa la instancia m5n.8xlarge en AWS es que tiene 1 controlador (solo 1 nodo), 128 GB de memoria, 32 núcleos de CPU y cuesta 5,71 DBU por hora. Puede leer sobre "DBU" en AWS aquí: https://www.databricks.com/product/aws-pricing

    Clúster único de Databricks: perfil de instancia de AWS

    Vamos a replicar nuestros puntos de referencia de la sección anterior (servidor Dell completo) aquí en nuestros Databricks de un solo nodo (solo CPU). Comenzamos con Hugging Face y nuestro conjunto de datos de tamaño de muestra de ImageNet para averiguar qué tamaño de lote es bueno para que podamos usarlo para el conjunto de datos más grande, ya que esto resultó ser una práctica comprobada en los puntos de referencia anteriores:

    Canalización de clasificación de imágenes Hugging Face en CPU de nodo único de Databricks: predicción de 3544 imágenes

    Tomó alrededor de 2 minutos y medio ( 149 segundos ) terminar de procesar alrededor de 3544 imágenes de nuestro conjunto de datos de muestra en un Databrick de un solo nodo que solo usa CPU . El mejor tamaño de lote en esta máquina que usa solo CPU es 8 , así que lo usaré para ejecutar el punto de referencia en el conjunto de datos más grande:

    Canalización de clasificación de imágenes de Hugging Face en CPU de nodo único de Databricks: predicción de 34745 imágenes

    En el conjunto de datos más grande con más de 34 000 imágenes, tomó alrededor de 20 minutos y medio ( 1233 segundos ) terminar de predecir las clases para esas imágenes. Para nuestro próximo punto de referencia, necesitamos tener un clúster de Databricks de un solo nodo, pero esta vez necesitamos tener un tiempo de ejecución basado en GPU y elegir una instancia de AWS basada en GPU.

    Abrazando la cara en un solo nodo de Databricks con una GPU en AWS

    Vamos a crear un nuevo clúster y esta vez vamos a elegir un tiempo de ejecución con GPU que en este caso se llama 11.1 ML (incluye Apache Spark 3.3.0, GPU, Scala 2.12) y viene con todo el software CUDA y NVIDIA instalado. Lo siguiente que necesitamos es seleccionar también una instancia de AWS que tenga una GPU y he elegido g4dn.8xlarge que tiene 1 GPU y una cantidad similar de núcleos/memoria que el otro clúster. Esta instancia de GPU viene con un Tesla T4 y 16 GB de memoria ( 15 GB memoria GPU utilizable).

    Clúster de un solo nodo de bricks: tiempo de ejecución de GPU

    Este es el resumen de nuestro clúster de un solo nodo como el anterior y es el mismo en cuanto a la cantidad de núcleos y la cantidad de memoria, pero viene con una GPU Tesla T4:

    Clúster de nodo único de bricks: perfil de instancia de AWS

    Ahora que tenemos un clúster de un solo nodo con una GPU, podemos continuar con nuestras pruebas comparativas para ver cómo se desempeña Hugging Face en esta máquina en Databricks. Voy a ejecutar el punto de referencia en el conjunto de datos más pequeño para ver qué tamaño de lote es más adecuado para nuestra máquina basada en GPU:

    Canalización de clasificación de imágenes Hugging Face en CPU de nodo único de Databricks: predicción de 3544 imágenes

    Tomó alrededor de un minuto ( 64 segundos ) terminar de procesar alrededor de 3544 imágenes de nuestro conjunto de datos de muestra en nuestro clúster de Databricks de un solo nodo con un dispositivo GPU. El procesamiento por lotes mejoró la velocidad si observamos el resultado del tamaño de lote 1; sin embargo, después del tamaño de lote 8, los resultados se mantuvieron prácticamente iguales. Aunque los resultados son los mismos después del tamaño de lote 8, he elegido el tamaño de lote 256 para mi punto de referencia más grande para utilizar también más memoria GPU. (para ser honesto, 8 y 256 se desempeñaron prácticamente de la misma manera)

    Ejecutemos el punto de referencia en el conjunto de datos más grande y veamos qué sucede con el tamaño de lote 256:

    Canalización de clasificación de imágenes de Hugging Face en CPU de nodo único de Databricks: predicción de 34745 imágenes

    En un conjunto de datos más grande, tomó casi 11 minutos ( 659 segundos ) terminar de predecir las clases para más de 34 000 imágenes. Si comparamos los resultados de nuestros puntos de referencia en un solo nodo con CPU y un solo nodo que viene con 1 GPU, podemos ver que el nodo de GPU aquí es el ganador:

    Hugging Face (PyTorch) es hasta 2,3 veces más rápido en GPU que en CPU

    La GPU es hasta ~2,3 veces más rápida en comparación con la ejecución de la misma canalización en CPU en Hugging Face en Databricks Single Node

    Ahora vamos a ejecutar los mismos puntos de referencia utilizando Spark NLP en los mismos grupos y sobre los mismos conjuntos de datos para compararlo con Hugging Face.

    Evaluación comparativa de Spark NLP en un databrick de un solo nodo

    Primero, instalemos Spark NLP en sus CPU de Databricks de un solo nodo:

    En la pestaña Bibliotecas dentro de su clúster, debe seguir estos pasos:
    — Instalar Nuevo -> PyPI -> spark-nlp==4.1.0 -> Instalar
    — Instalar Nuevo -> Maven -> Coordenadas -> com.johnsnowlabs.nlp:spark-nlp_2.12:4.1.0 -> Instalar
    — Agregará ` TF_ENABLE_ONEDNN_OPTS=1 ` a `Cluster->Opciones avanzadas->Spark->Variables de entorno` para habilitar oneDNN

    Cómo instalar Spark NLP en Databricks en CPU para Python, Scala y Java

    Spark NLP en Databricks Single Node con CPU en AWS

    Ahora que tenemos Spark NLP instalado en nuestro clúster de un solo nodo de Databricks, podemos repetir los puntos de referencia para una muestra y conjuntos de datos completos en CPU y GPU. Comencemos con el punto de referencia en las CPU primero sobre el conjunto de datos de muestra:

    Canalización de clasificación de imágenes Spark NLP en CPU de nodo único de Databricks (oneDNN): predicción de 3544 imágenes

    Tomó alrededor de 2 minutos ( 111 segundos ) terminar de procesar 3544 imágenes y predecir sus clases en el mismo clúster de Databricks de un solo nodo con CPU que usamos para Hugging Face. Podemos ver que el tamaño de lote de 16 tiene el mejor resultado, así que lo usaré en el próximo punto de referencia en el conjunto de datos más grande:

    Canalización de clasificación de imágenes Spark NLP en CPU de nodo único de Databricks (oneDNN): predicción de 34742 imágenes

    En el conjunto de datos más grande con más de 34 000 imágenes , tomó alrededor de 18 minutos ( 1072 segundos ) terminar de predecir las clases para esas imágenes. A continuación, repetiré los mismos puntos de referencia en el clúster con GPU.

    Nodo único de Databricks con una GPU en AWS

    Primero, instale Spark NLP en su GPU de Databricks de un solo nodo (la única diferencia es el uso de " spark-nlp-gpu" de Maven):

    Instale Spark NLP en su clúster de Databricks
    — En la pestaña Bibliotecas dentro del clúster, debe seguir estos pasos:
    — Instalar Nuevo -> PyPI -> spark-nlp==4.1.0 -> Instalar
    — Instalar Nuevo -> Maven -> Coordenadas -> com.johnsnowlabs.nlp:spark-nlp-gpu_2.12:4.1.0 -> Instalar

    Cómo instalar Spark NLP en Databricks en GPU para Python, Scala y Java

    Voy a ejecutar el punto de referencia en el conjunto de datos más pequeño para ver qué tamaño de lote es más adecuado para nuestra máquina basada en GPU:

    Canalización de clasificación de imágenes Spark NLP en GPU de nodo único de Databricks: predicción de 3544 imágenes

    Se tardó menos de un minuto ( 47 segundos ) en terminar de procesar alrededor de 3544 imágenes de nuestro conjunto de datos de muestra en nuestros Databricks de un solo nodo con un dispositivo de GPU. Podemos ver que el tamaño de lote 8 funcionó mejor en este caso de uso específico, por lo que ejecutaré el punto de referencia en el conjunto de datos más grande:

    Canalización de clasificación de imágenes Spark NLP en GPU de nodo único de Databricks: predicción de 34742 imágenes

    En un conjunto de datos más grande, tomó casi 7 minutos y medio ( 435 segundos ) terminar de predecir clases para más de 34 000 imágenes . Si comparamos los resultados de nuestros puntos de referencia en un solo nodo con CPU y un solo nodo que viene con 1 GPU, podemos ver que el nodo de GPU aquí es el ganador:

    Spark NLP es hasta 2,5 veces más rápido en GPU que en CPU en Databricks Single Node

    ¡Esto es genial! Podemos ver que Spark NLP en GPU es hasta 2,5 veces más rápido que en CPU, incluso con oneDNN habilitado (oneDNN mejora los resultados en CPU entre un 10 % y un 20 %).

    Echemos un vistazo a cómo se comparan estos resultados con los puntos de referencia de Hugging Face en el mismo clúster de nodo único de Databricks:


    Spark NLP es hasta un 15 % más rápido que Hugging Face en CPU en la predicción de clases de imágenes para el conjunto de datos de muestra con imágenes de 3K y hasta un 34 % en el conjunto de datos más grande con imágenes de 34K. Spark NLP también es un 51 % más rápido que Hugging Face en una sola GPU para un conjunto de datos más grande con imágenes de 34K y hasta un 36 % más rápido en un conjunto de datos más pequeño con imágenes de 3K.


    Spark NLP es más rápido tanto en CPU como en GPU en comparación con Hugging Face en Databricks Single Node

    Escalando más allá de una sola máquina

    Hasta ahora, establecimos que Hugging Face en GPU es más rápido que Hugging Face en CPU en un servidor bare-metal y Databricks Single Node. Esto es lo que espera cuando compara GPU y CPU con estos nuevos modelos basados en transformadores.

    También hemos establecido que Spark NLP supera a Hugging Face para la misma canalización (modelo ViT), en los mismos conjuntos de datos, tanto en el servidor sin sistema operativo como en el clúster de un solo nodo de Databricks, y funciona mejor en dispositivos de CPU y GPU. Esto, por otro lado, no era algo que esperaba. Cuando estaba preparando este artículo, esperaba que la inferencia de TensorFlow en Spark NLP fuera un poco más lenta que la inferencia en Hugging Face usando PyTorch o al menos igualada. Estaba apuntando a esta sección, escalando la canalización más allá de una sola máquina . Pero parece que Spark NLP es más rápido que Hugging Face incluso en una sola máquina, tanto en CPU como en GPU , en conjuntos de datos grandes y pequeños .

    Pregunta: ¿Qué sucede si desea que su tubería de ViT sea aún más rápida? ¿Qué sucede si tiene conjuntos de datos aún más grandes y simplemente no puede colocarlos dentro de una máquina o simplemente toma demasiado tiempo recuperar los resultados?

    Respuesta: ¡Escalamiento horizontal! Esto significa que, en lugar de cambiar el tamaño de la misma máquina, agregue más máquinas a su clúster. Necesita algo para administrar todos esos trabajos/tareas/programar DAG/administrar tareas fallidas/etc. y esos tienen sus gastos generales, pero si necesita que algo sea más rápido o posible (más allá de una sola máquina), debe usar algún tipo de sistema distribuido.

    Ampliación = hacer que su máquina sea más grande o más rápida para que pueda manejar más carga.

    Escalamiento horizontal = agregar más máquinas en paralelo para distribuir una carga.

    Cara de abrazo ampliada:

    Mirar la página en el sitio web oficial de Hugging Face sugiere que la inferencia de escala solo es posible mediante el uso de Multi-GPU. Como describimos qué es el escalado horizontal, esto todavía está atascado en una sola máquina:

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

    Además, sin mencionar que la solución Multi-GPU para inferencia en Hugging Face no existe en este momento:

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

    Por lo tanto, parece que no existe una forma nativa/oficial de ampliar las canalizaciones de Hugging Face. Puede implementar su arquitectura que consta de algunos microservicios, como una cola de trabajos, protocolos de mensajería, backend de API RESTful y algunos otros componentes necesarios para distribuir cada solicitud en diferentes máquinas, pero esto escala las solicitudes de usuarios individuales en lugar de escalar el sistema real. sí mismo.

    Además, la latencia de dichos sistemas no es comparable con los sistemas distribuidos de forma nativa, como Apache Spark (gRPC puede reducir esta latencia, pero aún así no es competitivo). Sin mencionar el problema del punto único de falla, la administración de trabajos/tareas/entradas fallidas y cientos de otras características que obtiene de Apache Spark y que ahora debe implementar/mantener usted mismo.

    Hay una publicación de blog en el sitio web de Hugging Face que representa la misma arquitectura al escalar los puntos finales REST para servir a más usuarios: " Implementación de 🤗 ViT en Kubernetes con TF Serving ". Sin embargo, creo que otras compañías están utilizando enfoques similares para escalar Hugging Face. , todos están escalando la cantidad de usuarios/solicitudes que llegan a los puntos finales REST de inferencia. Además, no puede escalar Hugging Face de esta manera en Databricks.

    Por ejemplo, la inferencia dentro de fastAPI es 10 veces más lenta que la inferencia local: https://towardsdatascience.com/hugging-face-transformer-inference-under-1-millisecond-latency-e1be0057a51c

    Una vez que Hugging Face ofrezca algunas soluciones nativas para escalar, volveré a ejecutar los puntos de referencia nuevamente. Hasta entonces, no hay escalamiento cuando tiene que recorrer el conjunto de datos desde una sola máquina para llegar a los puntos finales REST en un algoritmo de turno rotativo. (Piense de nuevo en la parte en la que agrupamos filas/secuencias/imágenes para alimentar la GPU de una sola vez, luego lo obtendrá)

    Escalamiento horizontal de Spark NLP:

    Spark NLP es una extensión de Spark ML, por lo tanto, se escala de forma nativa y sin problemas en todas las plataformas compatibles con Apache Spark, como (y no limitadas) Databricks, AWS EMR, Azure Insight, GCP Dataproc, Cloudera, SageMaker, Kubernetes y muchas más.

    ¡Se necesitan cambios de código cero! ¡Spark NLP puede escalar desde una sola máquina a un número infinito de máquinas sin cambiar nada en el código!

    Tampoco necesita exportar ningún modelo fuera de Spark NLP para usarlo en una biblioteca completamente diferente para acelerar o escalar la inferencia.

    Ecosistema Spark NLP: integraciones optimizadas, probadas y compatibles

    Databricks multinodo con CPU en AWS

    Vamos a crear un clúster y esta vez elegimos Estándar dentro del modo Clúster . Esto significa que podemos tener más de 1 nodo en nuestro clúster, lo que en la terminología de Apache Spark significa 1 controlador y N número de trabajadores (ejecutores).

    También necesitamos instalar Spark NLP en este nuevo clúster a través de la pestaña Bibliotecas. Puede seguir los pasos que mencioné en la sección anterior para Databricks de un solo nodo con CPU. Como puede ver, elegí la misma instancia de AWS basada en CPU que usé para comparar tanto Hugging Face como Spark NLP para que podamos ver cómo se escala cuando agregamos más nodos.

    Así es como se ven nuestras configuraciones de clúster:

    Clúster de varios nodos (estándar) de bricks con solo CPU

    Reutilizaré la misma canalización de Spark NLP que usé en los puntos de referencia anteriores (no es necesario cambiar ningún código) y también solo usaré el conjunto de datos más grande con imágenes de 34K. ¡Vamos a empezar!

    Escale Spark NLP en CPU con 2x nodos

    Databricks con 2x nodos: solo CPU

    Solo agreguemos 1 nodo más y hagamos el total de las máquinas que realizarán el procesamiento en 2 máquinas. No olvidemos la belleza de Spark NLP cuando pasa de una configuración de una sola máquina (su Colab, Kaggle, Databricks Single Node o incluso su computadora portátil Jupyter local) a una configuración de clúster de varios nodos (Databricks, EMR, GCP, Azure, Cloudera , YARN, Kubernetes, etc.), ¡se requiere un cambio de código cero! ¡Y me refiero a cero! Con eso en mente, ejecutaré el mismo punto de referencia dentro de este nuevo clúster en los conjuntos de datos más grandes con imágenes de 34K:

    Canalización de clasificación de imágenes Spark NLP en 2x nodos con CPU (oneDNN): predicción de 34742 imágenes

    Le tomó alrededor de 9 minutos ( 550 segundos ) terminar de predecir clases para imágenes de 34K. Comparemos este resultado en 2x nodos con Spark NLP y los resultados de Hugging Face en un solo nodo de Databricks (seguiré repitiendo los resultados de Hugging Face en un solo nodo como referencia, ya que Hugging Face no se pudo escalar en varias máquinas, especialmente en Databricks) :

    Spark NLP es un 124 % más rápido que Hugging Face con 2x nodos

    Anteriormente, Spark NLP venció a Hugging Face en un clúster de Databricks de un solo nodo usando solo CPU en un 15 % .

    Esta vez, al tener solo 2x nodos en lugar de 1 nodo, Spark NLP finalizó el proceso de más de 34 000 imágenes un 124 % más rápido que Hugging Face. Scale Spark NLP en CPU con 4x nodos

    Dupliquemos el tamaño de nuestro clúster como antes y pasemos de 2x Nodos a 4x Nodos. Así es como se vería el clúster con 4x nodos:

    Databricks con 4x nodos: solo CPU

    Ejecutaré el mismo punto de referencia en este nuevo clúster en los conjuntos de datos más grandes con imágenes de 34K:

    Canalización de clasificación de imágenes Spark NLP en 4x nodos con CPU (oneDNN): predicción de 34742 imágenes

    Le tomó alrededor de 5 minutos ( 289 segundos ) terminar de predecir clases para imágenes de 34K. Comparemos este resultado en 4x nodos con Spark NLP frente a Hugging Face en CPU en Databricks:

    Spark NLP es un 327 % más rápido que Hugging Face con 4x nodos

    Como puede verse, Spark NLP ahora es un 327 % más rápido que Hugging Face en las CPU mientras usa solo 4x nodos en Databricks.

    Escale Spark NLP en CPU con nodos 8x

    Ahora dupliquemos el clúster anterior agregando 4x Nodos más y hagamos un total de 8x Nodos . Por cierto, este cambio de tamaño del clúster es bastante fácil, solo aumenta la cantidad de trabajadores en las configuraciones de su clúster:

    Cambiar el tamaño de Spark Cluster en Databricks

    Ladrillos de datos con nodos 8x: solo CPU

    Ejecutemos el mismo punto de referencia esta vez en 8x Nodes:

    Canalización de clasificación de imágenes Spark NLP en 8x nodos con CPU (oneDNN): predicción de 34742 imágenes

    Le tomó más de 2 minutos y medio ( 161 segundos ) terminar de predecir clases para imágenes de 34K. Comparemos este resultado en 8x Nodes con Spark NLP frente a Hugging Face en CPU en Databricks:

    Spark NLP es un 666 % más rápido que Hugging Face con 8x nodos

    Como puede verse, Spark NLP ahora es un 666 % más rápido que Hugging Face en las CPU mientras usa solo 8x Nodes en Databricks.

    ¡Simplemente ignoremos el número de 6s aquí! (fue 665.8% si te hace sentir mejor)

    Escale Spark NLP en CPU con 10x nodos

    Para finalizar nuestras predicciones de modelos ViT de escalamiento horizontal en CPU en Databricks mediante Spark NLP, cambiaré el tamaño del clúster una vez más y lo aumentaré a 10x Nodos:

    Databricks con 10x nodos: solo CPU

    Ejecutemos el mismo punto de referencia esta vez en 10x Nodes:

    Canalización de clasificación de imágenes Spark NLP en 10x nodos con CPU (oneDNN): predicción de 34742 imágenes

    Le tomó menos de 2 minutos ( 112 segundos ) terminar de predecir clases para imágenes de 34K. Comparemos este resultado en 10x Nodes con todos los resultados anteriores de Spark NLP vs. Hugging Face en CPU en Databricks:

    Spark NLP es 1000% más rápido que Hugging Face con 10x Nodos

    ¡Y así es como se escala el modelo Vision Transformer proveniente de Hugging Face en 10x Nodes usando Spark NLP en Databricks! Nuestra canalización ahora es 1000 % más rápida que Hugging Face en las CPU.

    Logramos hacer que nuestra canalización de ViT sea un 1000 % más rápida que Hugging Face, que está atascada en 1 solo nodo, simplemente usando Spark NLP, pero solo usamos CPU . Veamos si podemos obtener las mismas mejoras escalando nuestra canalización en un clúster de GPU .

    Databricks multinodo con GPU en AWS

    Tener un clúster de Databricks de varios nodos basado en GPU es prácticamente lo mismo que tener un clúster de un solo nodo. La única diferencia es elegir Estándar y mantener el mismo tiempo de ejecución de ML/GPU con las mismas especificaciones de instancias de AWS que elegimos en nuestros puntos de referencia para GPU en un solo nodo.

    También necesitamos instalar Spark NLP en este nuevo clúster a través de la pestaña Bibliotecas . Igual que antes, puede seguir los pasos que mencioné en Databricks de un solo nodo con una GPU.

    Clúster de varios nodos (estándar) de bricks de datos con GPU

    Escale Spark NLP en GPU con 2x nodos

    Nuestro clúster de GPU de Databricks de varios nodos utiliza la misma instancia de GPU de AWS de g4dn.8xlarge que usamos anteriormente para ejecutar nuestros puntos de referencia para comparar Spark NLP con Hugging Face en un clúster de Databricks de un solo nodo.

    Este es un resumen de cómo se ve esta vez con 2 nodos:

    Databricks con 2x nodos: con 1 GPU por nodo

    Voy a ejecutar la misma canalización en este clúster de GPU con 2x nodos:

    Canalización de clasificación de imágenes Spark NLP en 2x nodos con GPU: predicción de 34742 imágenes

    Le tomó 4 minutos ( 231 segundos ) terminar de predecir clases para imágenes de 34K . Comparemos este resultado en 2x nodos con Spark NLP frente a Hugging Face en GPU en Databricks:

    Spark NLP es un 185 % más rápido que Hugging Face con 2x nodos

    Spark NLP con 2x Nodes es casi 3x veces más rápido ( 185 % ) que Hugging Face en 1 solo nodo mientras usa GPU.

    Escale Spark NLP en GPU con nodos 4x

    Redimensionemos nuestro clúster de GPU de 2x Nodos a 4x Nodos. Este es un resumen de cómo se ve esta vez con 4x Nodes usando una GPU:

    Databricks con 4x nodos: con 1 GPU por nodo

    Ejecutemos el mismo punto de referencia en 4x Nodes y veamos qué sucede:

    Canalización de clasificación de imágenes Spark NLP en nodos 4x con GPU: predicción de 34742 imágenes

    Esta vez tomó casi 2 minutos ( 118 segundos ) terminar de clasificar todas las imágenes de 34K en nuestro conjunto de datos. Visualicemos esto solo para tener una mejor visión de lo que esto significa en términos de Hugging Face en un solo nodo frente a Spark NLP en un clúster de varios nodos:

    Spark NLP es un 458 % más rápido que Hugging Face con 4x nodos

    Eso es un 458 % más de rendimiento en comparación con Hugging Face. Acabamos de hacer que nuestra canalización sea 5,6 veces más rápida mediante el uso de Spark NLP con nodos 4x.

    Escale Spark NLP en GPU con nodos 8x

    A continuación, cambiaré el tamaño del clúster para tener 8x nodos en mis Databricks con el siguiente resumen:

    Databricks con 8x nodos: con 1 GPU por nodo

    Solo como recordatorio, cada instancia de AWS ( g4dn.8xlarge ) tiene 1 GPU NVIDIA T4 de 16 GB (15 GB de memoria utilizable). Volvamos a ejecutar el punto de referencia y veamos si podemos detectar alguna mejora, ya que el escalado horizontal en cualquier sistema distribuido tiene sus gastos generales y no puede seguir agregando máquinas:

    Canalización de clasificación de imágenes Spark NLP en nodos 8x con GPU: predicción de 34742 imágenes

    Se tardó casi un minuto ( 61 segundos ) en terminar de clasificar imágenes de 34 000 con nodos 8x en nuestro clúster de Databricks. Parece que todavía logramos mejorar el rendimiento. Pongamos este resultado junto a los resultados anteriores de Hugging Face en un solo nodo frente a Spark NLP en un clúster de varios nodos:

    Spark NLP es 980% más rápido que Hugging Face con 8x Nodes

    Spark NLP con 8x Nodes es casi 11x veces más rápido (980 %) que Hugging Face en GPU.

    Escale Spark NLP en GPU con 10x nodos

    De manera similar a nuestros puntos de referencia de múltiples nodos en CPU, me gustaría cambiar el tamaño del clúster de GPU una vez más para tener 10x Nodos y hacerlos coincidir en términos de la cantidad final de nodos. El resumen final de este clúster es el siguiente:

    Databricks con 10x nodos: con 1 GPU por nodo

    Ejecutemos nuestro último punto de referencia en este clúster de GPU específico (sin cambios de código):

    Canalización de clasificación de imágenes Spark NLP en 10x nodos con GPU: predicción de 34742 imágenes

    Le tomó menos de un minuto ( 51 segundos ) terminar de predecir las clases para más de 34743 imágenes . Pongámoslos todos uno al lado del otro y veamos cómo progresamos escalando nuestro modelo Vision Transformer proveniente de Hugging Face en la canalización Spark NLP en Databricks:

    Spark NLP es 1200% más rápido que Hugging Face con 10x Nodos

    ¡Y hemos terminado!

    ¡Logramos escalar nuestro modelo Vision Transformer proveniente de Hugging Face en 10x Nodes usando Spark NLP en Databricks! Nuestra canalización ahora es 13 veces más rápida con mejoras de rendimiento del 1200 % en comparación con Hugging Face en GPU.

    Resumamos todos estos puntos de referencia comparando primero las mejoras entre las CPU y las GPU, y luego cuánto más rápido puede ser nuestra canalización al pasar de las CPU Hugging Face a 10x Nodes en Databricks usando Spark NLP en las GPU.

    Juntándolo todo:

    Ladrillos de datos: nodo único y nodos múltiples

    Spark NLP 🚀 en 10x Nodos con CPU es 1000% (11x veces) más rápido que Hugging Face 🤗 atascado en un solo nodo con CPU


    Spark NLP 🚀 en 10x Nodos con GPU es 1192 % (13x veces) más rápido que Hugging Face 🤗 atascado en un solo nodo con GPU

    ¿Qué pasa con las diferencias de precio entre nuestra instancia de CPU de AWS y la instancia de GPU de AWS? (Quiero decir, obtienes más si pagas más, ¿verdad?)

    AWS m5d.8xlarge con CPU frente a AWS g4dn.8xlarge con 1 GPU y especificaciones similares

    OK, ¡entonces el precio parece más o menos el mismo! Con eso en mente, ¿qué mejoras obtienes si pasas de Hugging Face en CPU atascadas en una sola máquina a Spark NLP en 10x Nodes con 10x GPU ?

    Spark NLP en GPU es 25 veces (2366 %) más rápido que Hugging Face en CPU

    Spark NLP 🚀 en 10x Nodos con GPU es 2366 % (25x veces) más rápido que Hugging Face 🤗 en un solo nodo con CPU

    Ultimas palabras

    • Con el espíritu de total transparencia, todos los cuadernos con sus registros, capturas de pantalla e incluso la hoja de Excel con números se proporcionan aquí en GitHub .
    • Escalar Spark NLP requiere cero cambios de código. Ejecutar los puntos de referencia desde un solo nodo Databricks a los 10 nodos significaba simplemente volver a ejecutar el mismo bloque de código en el mismo cuaderno.
    • Tenga en cuenta que estas dos bibliotecas vienen con muchas mejores prácticas para optimizar su velocidad y eficiencia en diferentes entornos para diferentes casos de uso. Por ejemplo, no hablé sobre las particiones y su relación con el paralelismo y las distribuciones en Apache Spark. Hay muchas configuraciones de Spark para ajustar un clúster, especialmente equilibrando la cantidad de tareas entre CPU y GPU. Ahora la pregunta es, ¿sería posible acelerar alguno de ellos dentro de los mismos entornos que usamos para nuestros puntos de referencia? ¡La respuesta es 100%! Traté de mantener todo para ambas bibliotecas con valores predeterminados y funciones listas para usar en favor de la simplicidad para la mayoría de los usuarios.
    • Es posible que desee envolver Hugging Face y otras bibliotecas Pythonish basadas en DL en un Spark UDF para escalarlas. Esto funciona hasta cierto punto, ya que lo he hecho yo mismo y todavía lo hago (cuando no hay una solución nativa). No entraré en los detalles del uso excesivo de la memoria, los posibles problemas de serialización, la latencia más alta y otros problemas cuando uno envuelve estos modelos basados en transformadores en una UDF. Solo diría que si está utilizando Apache Spark, use la biblioteca que amplía de forma nativa las funciones requeridas en Apache Spark.
    • A lo largo de este artículo, hice todo lo posible para mencionar Hugging Face en PyTorch y Spark NLP en TensorFlow. Esta es una gran diferencia dado el hecho de que en cada punto de referencia realizado por Hugging Face entre PyTorch y TensorFlow, PyTorch fue y sigue siendo el ganador de la inferencia. En Hugging Face, PyTorch tiene una latencia mucho más baja y parece ser mucho más rápido que TensorFlow en Transformers. El hecho de que Spark NLP use el mismo TensorFlow y salga adelante en todos los puntos de referencia en comparación con PyTorch en Hugging Face es un gran problema. O se descuida el TensorFlow en Hugging Face, o PyTorch es simplemente más rápido en la inferencia en comparación con TensorFlow. De cualquier manera, no puedo esperar a ver qué sucede cuando Spark NLP comience a admitir TorchScript y ONNX Runtime además de TensorFlow.
    • Los tiempos de ejecución de ML y ML GPU Databricks vienen con Hugging Face instalado, eso es bastante bueno. Pero eso no significa que Hugging Face sea fácil de usar en Databricks. La biblioteca Transformer de Hugging Face no admite DBFS (el sistema de archivos nativo distribuido de Databricks) ni Amazon S3. Como puede ver en los cuadernos, tuve que descargar una versión comprimida de los conjuntos de datos y extraerlos para usarlos. No es realmente así como hacen las cosas los usuarios de Databricks y otras plataformas en producciones. Mantenemos nuestros datos dentro de sistemas de archivos distribuidos, hay medidas de seguridad implementadas y la mayoría de ellos son lo suficientemente grandes como para que no puedan ser descargados por una computadora personal. Tuve que descargar los conjuntos de datos que ya tenía en DBFS, comprimirlos, cargarlos en S3, hacerlos públicos y volver a descargarlos en los cuadernos. Un proceso bastante tedioso que podría haberse evitado si Hugging Face fuera compatible con DBFS/S3.

    Referencias

    vit

    cara de abrazo

    Ladrillos de datos

    Chispa PNL