paint-brush
Scale Vision Transformers (ViT) além de abraçar o rostopor@maziyar
4,285 leituras
4,285 leituras

Scale Vision Transformers (ViT) além de abraçar o rosto

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

Muito longo; Para ler

O objetivo deste artigo é demonstrar como expandir os modelos do Vision Transformer (ViT) do Hugging Face e implantá-los em ambientes prontos para produção para inferência acelerada e de alto desempenho. No final, escalaremos um modelo ViT de Hugging Face em 25 vezes (2300%) usando Databricks, Nvidia e Spark NLP.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Scale Vision Transformers (ViT) além de abraçar o rosto
Maziyar Panahi HackerNoon profile picture

Acelere modelos ViT de última geração em Hugging Face 🤗 até 2300% (25x vezes mais rápido) com Databricks, Nvidia e Spark NLP 🚀

Sou um dos colaboradores do projeto de código aberto Spark NLP e, recentemente, esta biblioteca começou a oferecer suporte a modelos de Vision Transformers (ViT) de ponta a ponta. Eu uso Spark NLP e outras bibliotecas de código aberto ML/DL para trabalhar diariamente e decidi implantar um pipeline ViT para uma tarefa de classificação de imagem de última geração e fornecer comparações detalhadas entre Hugging Face e Spark NLP .

O objetivo deste artigo é demonstrar como expandir os modelos do Vision Transformer (ViT) do Hugging Face e implantá-los em ambientes prontos para produção para inferência acelerada e de alto desempenho. No final, escalaremos um modelo ViT de Hugging Face em 25 vezes (2300%) usando Databricks, Nvidia e Spark NLP.

Neste artigo irei:

  • Uma breve introdução ao Vision Transformer (ViT)
  • Benchmark Hugging Face dentro do servidor Dell em CPUs e GPUs
  • Benchmark Spark NLP dentro do servidor Dell em CPUs e GPUs
  • Benchmark abraçando o rosto dentro do Databricks Single Node em CPUs e GPUs
  • Benchmark Spark NLP dentro do Databricks Single Node em CPUs e GPUs
  • Benchmark Spark NLP dentro de Databricks dimensionado para 10x nós com CPUs e GPUs
  • resuma tudo!
  • No espírito de total transparência, todos os notebooks com seus logs, capturas de tela e até a planilha do Excel com números são fornecidos aqui no GitHub

    Introdução aos modelos do Vision Transformer (ViT)

    Em 2017, um grupo de pesquisadores do Google AI publicou um artigo que introduziu uma arquitetura de modelo de transformador que mudou todos os padrões de processamento de linguagem natural (NLP). O artigo descreve um novo mecanismo chamado auto-atenção como um modelo novo e mais eficiente para aplicações de linguagem. Por exemplo, as duas famílias mais populares de modelos baseados em transformadores são GPT e BERT.

    Um pouco da história do Transformer https://huggingface.co/course/chapter1/4

    Há um ótimo capítulo sobre “ Como funcionam os transformadores que eu recomendo para ler se você estiver interessado.

    Embora esses novos modelos baseados no Transformer pareçam estar revolucionando as tarefas de PNL, seu uso em Visão Computacional (CV) permaneceu bastante limitado. O campo da Visão Computacional tem sido dominado pelo uso de redes neurais convolucionais (CNNs) e existem arquiteturas populares baseadas em CNNs (como ResNet). Esse era o caso até que outra equipe de pesquisadores, desta vez no Google Brain, apresentou o “Vision Transformer” (ViT) em junho de 2021 em um artigo intitulado: An Image vale 16x16 Words: Transformers for Image Recognition at Scale

    Este artigo representa um avanço quando se trata de reconhecimento de imagem usando o mesmo mecanismo de auto-atenção usado em modelos baseados em transformadores, como BERT e GPT, como acabamos de discutir. Em modelos de linguagem baseados em transformação como BERT, a entrada é uma frase (por exemplo, uma lista de palavras). No entanto, nos modelos ViT, primeiro dividimos uma imagem em uma grade de patches de sub-imagem, então incorporamos cada patch com um projeto linear antes de cada patch incorporado se tornar um token. O resultado é uma sequência de patches de embeddings que passamos para o modelo semelhante ao BERT.

    Uma visão geral da estrutura do modelo ViT, conforme apresentado no artigo original de 2021 do Google Research

    O Vision Transformer se concentra em maior precisão, mas com menos tempo de computação. Olhando para os benchmarks publicados no artigo, podemos ver que o tempo de treinamento em relação ao conjunto de dados Noisy Student (publicado pelo Google em junho de 2020) foi reduzido em 80%, embora o estado de precisão seja mais ou menos o mesmo. Para mais informações sobre o desempenho do ViT hoje, você deve visitar sua página em Papers With Code :

    Comparação com o estado da arte em benchmarks populares de classificação de imagens. ( https://arxiv.org/pdf/2010.11929.pdf )

    Também é importante mencionar que, depois de treinar um modelo por meio da arquitetura ViT, você pode pré-treinar e ajustar seu transformador da mesma forma que faz no NLP. (isso é muito legal na verdade!)

    Se compararmos modelos de ViT com CNNs, podemos ver que eles têm maior precisão com custos de computação muito menores. Você pode usar modelos ViT para uma variedade de tarefas downstream em Visão Computacional, como classificação de imagens, detecção de objetos e segmentação de imagens. Isso também pode ser específico do domínio em Saúde. Você pode pré-treinar/ajustar seus modelos de ViT para fraturas de fêmur , enfisema , câncer de mama , COVID-19 e doença de Alzheimer

    Deixarei as referências no final deste artigo caso você queira se aprofundar em como os modelos ViT funcionam.

    [1]: Mergulho Profundo: Vision Transformers On Hugging Face Optimum Graphcore https://huggingface.co/blog/vision-transformers

    Alguns modelos ViT em ação

    Modelo Vision Transformer (ViT) ( vit-base-patch16–224 ) pré-treinado no ImageNet-21k (14 milhões de imagens, 21.843 classes) com resolução de 224x224 e ajustado no ImageNet 2012 (1 milhão de imagens, 1.000 classes) em resolução 224x224:

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

    Modelos de ViT ajustados usados para classificação de alimentos:

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

    No entanto, existem limitações e restrições para qualquer modelo DL/ML quando se trata de previsão. Não existe um modelo com 100% de precisão, portanto, lembre-se de usá-los para algo importante como Saúde:

    A imagem foi retirada de: https://www.akc.org/expert-advice/lifestyle/do-you-live-in-dog-state-or-cat-state/ — modelo ViT : https://huggingface.co /julien-c/cachorro-quente-não-cachorro-quente


    Podemos usar esses modelos do Hugging Face ou ajustar novos modelos ViT e usá-los para inferência na produção real? Como podemos dimensioná-los usando serviços gerenciados para cálculos distribuídos, como AWS EMR, Azure Insight, GCP Dataproc ou Databricks?

    Esperançosamente, algumas delas serão respondidas até o final deste artigo.

    Que comecem os benchmarks!

    Alguns detalhes sobre nossos benchmarks:

    1- Conjunto de dados: ImageNet mini: amostra (>3K) — completo (>34K)

    Baixei o conjunto de dados ImageNet 1000 (mini) do Kaggle: https://www.kaggle.com/datasets/ifigotin/imagenetmini-1000

    Eu escolhi o diretório train com mais de 34K de imagens e o chamei de imagenet-mini, pois tudo que eu precisava era de imagens suficientes para fazer benchmarks que demoram mais. Além disso, selecionei aleatoriamente menos de 10% do conjunto de dados completo e o chamei de imagenet-mini-sample , que possui 3544 imagens para meus benchmarks menores e também para ajustar os parâmetros corretos, como o tamanho do lote.

    2- Modelo: O “ vit-base-patch16–224 ” do Google

    Estaremos usando este modelo do Google hospedado no Hugging Face: https://huggingface.co/google/vit-base-patch16-224

    3- Bibliotecas: Transformers 🤗 & Spark NLP 🚀

    Comparação de rosto abraçado em um servidor Bare Metal

    Modelo ViT em um Dell PowerEdge C4130

    O que é um servidor bare-metal? Um servidor bare - metal é apenas um computador físico que está sendo usado apenas por um usuário. Não há hipervisor instalado nesta máquina, não há virtualizações e tudo está sendo executado diretamente no sistema operacional principal (Linux — Ubuntu) — as especificações detalhadas de CPUs, GPUs e a memória desta máquina estão dentro dos notebooks.

    Como meus testes iniciais e quase todas as postagens de blog escritas pela equipe de engenharia do Hugging Face comparando a velocidade de inferência entre os mecanismos DL revelaram, o melhor desempenho para inferência na biblioteca Hugging Face (Transformer) é obtido usando o PyTorch sobre o TensorFlow. Não tenho certeza se isso se deve ao TensorFlow ser um cidadão de segunda classe em Hugging Face devido a menos recursos suportados, menos modelos suportados, menos exemplos, tutoriais desatualizados e pesquisas anuais nos últimos 2 anos respondidas por usuários que perguntam mais sobre o TensorFlow ou o PyTorch apenas tem uma latência menor na inferência na CPU e na GPU.
    O TensorFlow continua sendo a estrutura de aprendizado profundo mais usada

    Independentemente do motivo, escolhi o PyTorch na biblioteca Hugging Face para obter os melhores resultados para nossos benchmarks de classificação de imagem. Este é um trecho de código simples para usar um modelo ViT (PyTorch, é claro) em 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] )

    Isso pode parecer simples prever uma imagem como uma entrada, mas não é adequado para grandes quantidades de imagens, especialmente em uma GPU. Para evitar a previsão de imagens sequencialmente e aproveitar hardware acelerado, como GPU, é melhor alimentar o modelo com lotes de imagens, o que é possível em Hugging Face via Pipelines . Desnecessário dizer que você pode implementar sua técnica de lote estendendo os Pipelines do Hugging Face ou fazendo isso por conta própria.

    Um pipeline simples para classificação de imagens ficará assim:

     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 )

    De acordo com a documentação, baixei/carreguei google/vit-base-patch16–224 para o extrator e modelo de recurso (pontos de verificação PyTorch, é claro) para usá-los no pipeline com classificação de imagem como tarefa. Há três coisas neste pipeline que são importantes para nossos benchmarks:

    > dispositivo : Se for -1 (padrão), ele usará apenas CPUs, enquanto se for um número int positivo, executará o modelo no ID do dispositivo CUDA associado. (é melhor ocultar as GPUs e forçar o PyTorch a usar a CPU e não apenas confie neste número aqui).

    > batch_size: Quando o pipeline vai usar o DataLoader (ao passar um conjunto de dados, na GPU para um modelo Pytorch), o tamanho do lote a ser usado, para inferência nem sempre é benéfico.

    > Você precisa usar DataLoader ou PyTorch Dataset para aproveitar ao máximo o agrupamento em pipelines Hugging Face em uma GPU.

    Antes de avançarmos com os benchmarks, você precisa saber uma coisa sobre o agrupamento em Hugging Face Pipelines para inferência, que nem sempre funciona. Conforme declarado na documentação do Hugging Face, definir batch_size pode não aumentar o desempenho do seu pipeline. Isso pode desacelerar seu pipeline:

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

    Para ser justo, em meus benchmarks usei uma variedade de tamanhos de lote começando em 1 para garantir que encontraria o melhor resultado entre eles. Foi assim que comparei o pipeline Hugging Face na 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

    Vamos dar uma olhada nos resultados de nosso primeiro benchmark para o pipeline de classificação de imagem Hugging Face em CPUs sobre o conjunto de dados ImageNet de amostra (3K):

    Envolvendo o pipeline de classificação de imagem facial em CPUs — prevendo 3.544 imagens

    Como pode ser visto, demorou cerca de 3 minutos ( 188 segundos) para concluir o processamento de cerca de 3.544 imagens do conjunto de dados de amostra. Agora que sei qual tamanho de lote (8) é o melhor para meu pipeline/conjunto de dados/hardware, posso usar o mesmo pipeline em um conjunto de dados maior ( imagens de 34K ) com este tamanho de lote:

    Abraçando o pipeline de classificação de imagem facial em CPUs — prevendo 34.745 imagens

    Desta vez, demorou cerca de 31 minutos ( 1.879 segundos ) para concluir a previsão de classes para 34.745 imagens nas CPUs.

    Para melhorar a maioria dos modelos de aprendizado profundo, especialmente esses novos modelos baseados em transformadores, deve-se usar hardware acelerado, como GPU. Vamos dar uma olhada em como comparar o mesmo pipeline nos mesmos conjuntos de dados, mas desta vez em um dispositivo GPU . Conforme mencionado anteriormente, precisamos alterar o dispositivo para um ID de dispositivo CUDA como 0 (a primeira 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
    

    Além de definir device=0, também segui a maneira recomendada de executar um modelo PyTorch em um dispositivo GPU via .to(device). Como estamos usando hardware acelerado (GPU), também aumentei o tamanho máximo do lote para meus testes para 1024 para encontrar o melhor resultado.

    Vamos dar uma olhada em nosso pipeline de classificação de imagem Hugging Face em um dispositivo GPU sobre o conjunto de dados ImageNet de amostra (3K):

    Envolvendo o pipeline de classificação de imagem facial em uma GPU — prevendo 3.544 imagens

    Como pode ser visto, demorou cerca de 50 segundos para concluir o processamento de cerca de 3.544 imagens de nosso conjunto de dados imagenet-mini-sample em um dispositivo GPU . O lote melhorou a velocidade, especialmente em comparação com os resultados provenientes das CPUs, no entanto, as melhorias pararam em torno do tamanho do lote de 32. Embora os resultados sejam os mesmos após o tamanho do lote 32, escolhi o tamanho do lote 256 para meu benchmark maior utilizar memória GPU suficiente também.

    Envolvendo o pipeline de classificação de imagem facial em uma GPU — prevendo 34.745 imagens

    Desta vez, nosso benchmark levou cerca de 8:17 minutos ( 497 segundos ) para concluir a previsão de classes para 34.745 imagens em um dispositivo GPU . Se compararmos os resultados de nossos benchmarks em CPUs e um dispositivo GPU, podemos ver que a GPU aqui é a vencedora:

    Hugging Face (PyTorch) é até 3,9 vezes mais rápido em GPU versus CPU

    Usei o Hugging Face Pipelines para carregar os pontos de verificação do ViT PyTorch, carregar meus dados no conjunto de dados da tocha e usar o lote fornecido pronto para uso no modelo na CPU e na GPU. A GPU é até aproximadamente 3,9 vezes mais rápida em comparação com a execução dos mesmos pipelines nas CPUs.

    Melhoramos nosso pipeline ViT para executar a classificação de imagem usando um dispositivo GPU em vez de CPUs, mas podemos melhorar ainda mais nosso pipeline em CPU e GPU em uma única máquina antes de escalá-lo para várias máquinas? Vamos dar uma olhada na biblioteca Spark NLP.

    Spark NLP: processamento de linguagem natural de última geração

    Spark NLP é uma biblioteca de processamento de linguagem natural de última geração de código aberto ( https://github.com/JohnSnowLabs/spark-nlp )

    O Spark NLP é uma biblioteca de processamento de linguagem natural de última geração construída sobre o Apache Spark. Ele fornece anotações NLP simples, de alto desempenho e precisas para pipelines de aprendizado de máquina que escalam facilmente em um ambiente distribuído. O Spark NLP vem com mais de 7.000 pipelines e modelos pré-treinados em mais de 200 idiomas . Ele também oferece tarefas como tokenização, segmentação de palavras, marcação de parte da fala, incorporação de palavras e frases, reconhecimento de entidade nomeada, análise de dependência, verificação ortográfica, classificação de texto, análise de sentimento, classificação de token, tradução automática (mais de 180 idiomas), Resumo e resposta a perguntas, geração de texto, classificação de imagens (ViT) e muitas outras tarefas de PNL .

    Spark NLP é a única biblioteca NLP de código aberto em produção que oferece transformadores de última geração, como BERT , CamemBERT , ALBERT , ELECTRA , XLNet , DistilBERT , RoBERTa , DeBERTa , XLM-RoBERTa , Longformer , ELMO , Universal Sentence Encoder , Google T5 , MarianMT , GPT2 e Vision Transformer ( ViT ) não apenas para Python e R , mas também para o ecossistema JVM ( Java , Scala e Kotlin ) em escala, estendendo o Apache Spark nativamente.

    Comparando o Spark NLP em um servidor Bare Metal

    Modelos ViT em um Dell PowerEdge C4130

    O Spark NLP tem os mesmos recursos ViT para classificação de imagem como Hugging Face que foram adicionados na recente versão 4.1.0 . O recurso é chamado de ViTForImageClassification, tem mais de 240 modelos pré-treinados prontos para uso e um código simples para usar esse recurso no Spark NLP é assim:

     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 ])

    Se compararmos o Spark NLP e o Hugging Face lado a lado para baixar e carregar um modelo ViT pré-treinado para uma previsão de classificação de imagens, além de carregar imagens e usar cálculos posteriores como argmax fora da biblioteca Hugging Face, ambos são bastante diretos. Além disso, ambos podem ser salvos e servir posteriormente como um pipeline para reduzir essas linhas a apenas 1 linha de código:

    Carregando e usando modelos ViT para classificação de imagens no Spark NLP (à esquerda) e Hugging Face (à direita)

    Como o Apache Spark possui um conceito chamado Lazy Evaluation , ele não inicia a execução do processo até que uma ACTION seja chamada. As ações no Apache Spark podem ser .count() ou .show() ou .write() e muitas outras operações baseadas em RDD que não abordarei agora e você não precisará conhecê-las para este artigo. Normalmente, escolho count() a coluna de destino ou write() os resultados em discos para acionar a execução de todas as linhas no DataFrame. Além disso, como os benchmarks Hugging Face, farei um loop pelos tamanhos de lote selecionados para garantir que posso ter todos os resultados possíveis sem perder o melhor resultado.

    Agora, sabemos como carregar o(s) modelo(s) ViT no Spark NLP, também sabemos como acionar uma ação para forçar a computação em todas as linhas em nosso DataFrame para benchmark, e tudo o que resta aprender é oneDNN de oneAPI Deep Neural Biblioteca de rede (oneDNN) . Como o mecanismo DL no Spark NLP é o TensorFlow, você também pode habilitar o oneDNN para melhorar a velocidade nas CPUs (como tudo mais, você precisa testar isso para ter certeza de que melhora a velocidade e não o contrário). Também usarei esse sinalizador além das CPUs normais sem o oneDNN ativado

    Agora que sabemos que todos os modelos ViT da Hugging Face também estão disponíveis no Spark NLP e como usá-los em um pipeline, repetiremos nossos benchmarks anteriores no servidor bare-metal Dell para comparar CPU x GPU. Vamos dar uma olhada nos resultados do pipeline de classificação de imagem do Spark NLP em CPUs em nosso conjunto de dados ImageNet de amostra (3K):

    Pipeline de classificação de imagem Spark NLP em uma CPU sem oneDNN — prevendo 3.544 imagens

    Demorou cerca de 2,1 minutos ( 130 segundos) para concluir o processamento de cerca de 3.544 imagens de nosso conjunto de dados de amostra. Ter um conjunto de dados menor para experimentar diferentes tamanhos de lote é útil para escolher o tamanho de lote certo para sua tarefa, seu conjunto de dados e sua máquina. Aqui está claro que o tamanho do lote 16 é o melhor tamanho para nosso pipeline entregar o melhor resultado.

    Eu também gostaria de habilitar o oneDNN para ver se nesta situação específica ele melhora meu benchmark comparando com as CPUs sem oneDNN. Você pode habilitar o oneDNN no Spark NLP definindo a variável de ambiente TF_ENABLE_ONEDNN_OPTS como 1. Vamos ver o que acontece se eu habilitar esse sinalizador e executar novamente o benchmark anterior na CPU para encontrar o melhor tamanho de lote:

    Pipeline de classificação de imagens Spark NLP em uma CPU com oneDNN — prevendo 3.544 imagens

    OK, habilitar claramente o oneDNN para o TensorFlow nessa situação específica melhorou nossos resultados em pelo menos 14%. Como não precisamos fazer/alterar nada e basta dizer export TF_ENABLE_ONEDNN_OPTS=1, vou usar isso para o benchmark com um conjunto de dados maior também para ver a diferença. Aqui é cerca de segundos mais rápido, mas 14% no conjunto de dados maior pode reduzir minutos de nossos resultados.

    Agora que sei que o tamanho do lote de 16 para CPU sem oneDNN e o tamanho do lote de 2 para CPU com oneDNN ativado têm os melhores resultados, posso continuar usando o mesmo pipeline em um conjunto de dados maior ( imagens de 34K ):

    Pipeline de classificação de imagens Spark NLP em CPUs sem oneDNN — prevendo 34745 imagens

    Desta vez, nosso benchmark levou cerca de 24 minutos ( 1423 segundos ) para concluir a previsão de classes para 34745 imagens em um dispositivo de CPU sem o oneDNN habilitado. Agora vamos ver o que acontece se eu habilitar oneDNN para TensorFlow e usar o tamanho do lote de 2 (os melhores resultados):

    Pipeline de classificação de imagem Spark NLP em CPUs com oneDNN — prevendo 34745 imagens

    Desta vez demorou cerca de 21 minutos ( 1278 segundos ). Conforme esperado de nossos benchmarks de amostra, podemos ver cerca de 11% de melhorias nos resultados que economizaram minutos em comparação com a não ativação do oneDNN.

    Vamos dar uma olhada em como comparar o mesmo pipeline em um dispositivo GPU. No Spark NLP, tudo o que você precisa para usar a GPU é iniciá-la com gpu=True ao iniciar a sessão Spark NLP:

    faísca = sparknlp.start(gpu=Verdadeiro)
    # você pode definir a memória aqui também
    spark = sparknlp.start(gpu=True, memory="16g")

    É isso! Se você tiver algo em seu pipeline que possa ser executado na GPU, ele o fará automaticamente, sem a necessidade de fazer nada explicitamente.

    Vamos dar uma olhada em nosso pipeline de classificação de imagem Spark NLP em um dispositivo GPU sobre o conjunto de dados ImageNet de amostra (3K):

    Pipeline de classificação de imagens Spark NLP em uma GPU — prevendo 3.544 imagens

    Por curiosidade para ver se minha cruzada para encontrar um bom tamanho de lote em um conjunto de dados menor estava correta, executei o mesmo pipeline com GPU em um conjunto de dados maior para ver se o tamanho do lote 32 teria o melhor resultado:

    Pipeline de classificação de imagens Spark NLP em uma GPU — prevendo 34.745 imagens

    Felizmente, é o tamanho do lote 32 que produz o melhor tempo. Demorou cerca de 4 minutos e meio ( 277 segundos).

    Vou pegar os resultados das CPUs com oneDNN , pois foram mais rápidos e vou compará-los com os resultados da GPU :

    Spark NLP (TensorFlow) é até 4,6 vezes mais rápido em GPU versus CPU (oneDNN)

    Isso é ótimo! Podemos ver que o Spark NLP na GPU é até 4,6 vezes mais rápido que as CPUs, mesmo com o oneDNN ativado.

    Vamos dar uma olhada em como esses resultados são comparados aos benchmarks Hugging Face:

    O Spark NLP é 65% mais rápido do que Hugging Face em CPUs na previsão de classes de imagem para o conjunto de dados de amostra com imagens de 3K e 47% no conjunto de dados maior com imagens de 34K. O Spark NLP também é 79% mais rápido que o Hugging Face em um único conjunto de dados maior de inferência de GPU com imagens de 34K e até 35% mais rápido em um conjunto de dados menor.


    O Spark NLP foi mais rápido do que o Hugging Face em uma única máquina usando CPU ou GPU — classificação de imagens usando o Vision Transformer (ViT)

    Spark NLP & Hugging Face no Databricks

    O que é Databricks? Todos os seus dados, análises e IA em uma plataforma

    Databricks é uma plataforma baseada em nuvem com um conjunto de ferramentas de engenharia de dados e ciência de dados que são amplamente utilizadas por muitas empresas para processar e transformar grandes quantidades de dados. Os usuários usam o Databricks para muitas finalidades, desde o processamento e transformação de grandes quantidades de dados até a execução de muitos pipelines ML/DL para explorar os dados.

    Isenção de responsabilidade: esta foi minha interpretação do Databricks, ele vem com muitos outros recursos e você deve dar uma olhada: https://www.databricks.com/product/data-lakehouse

    Databricks suporta nuvens AWS, Azure e GCP: https://www.databricks.com/product/data-lakehouse

    Abraçando o rosto no nó único do Databricks com CPUs na AWS

    O Databricks oferece um tipo de cluster “Single Node” quando você está criando um cluster adequado para quem deseja usar o Apache Spark com apenas 1 máquina ou usar aplicativos não Spark, especialmente bibliotecas Python baseadas em ML e DL. Hugging Face já vem instalado quando você escolhe o tempo de execução do Databricks 11.1 ML. Aqui está a aparência das configurações de cluster para meus Databricks de nó único (somente CPUs) antes de iniciarmos nossos benchmarks:

    Cluster de nó único Databricks — tempo de execução da CPU

    O resumo deste cluster que usa a instância m5n.8xlarge na AWS é que ele possui 1 driver (apenas 1 nó), 128 GB de memória, 32 núcleos de CPU e custa 5,71 DBU por hora. Você pode ler sobre “DBU” na AWS aqui: https://www.databricks.com/product/aws-pricing

    Cluster único do Databricks — perfil de instância da AWS

    Vamos replicar nossos benchmarks da seção anterior (servidor Dell bare-metal) aqui em nossos Databricks de nó único (somente CPUs). Começamos com Hugging Face e nosso conjunto de dados de tamanho de amostra do ImageNet para descobrir qual tamanho de lote é bom para que possamos usá-lo para o conjunto de dados maior, já que isso foi uma prática comprovada nos benchmarks anteriores:

    Abraçando o pipeline de classificação de imagem facial em CPUs de nó único do Databricks — prevendo 3544 imagens

    Demorou cerca de 2 minutos e meio ( 149 segundos ) para concluir o processamento de cerca de 3.544 imagens de nosso conjunto de dados de amostra em um Databricks de nó único que usa apenas CPUs . O melhor tamanho de lote nesta máquina usando apenas CPUs é 8 , então vou usá-lo para executar o benchmark no conjunto de dados maior:

    Abraçando o pipeline de classificação de imagem facial em CPUs de nó único do Databricks — prevendo 34745 imagens

    No conjunto de dados maior com mais de 34 mil imagens, demorou cerca de 20 minutos e meio ( 1233 segundos ) para concluir a previsão de classes para essas imagens. Para nosso próximo benchmark, precisamos ter um cluster Databricks de nó único, mas desta vez precisamos ter um tempo de execução baseado em GPU e escolher uma instância AWS baseada em GPU.

    Abraçando o rosto no nó único do Databricks com uma GPU na AWS

    Vamos criar um novo cluster e desta vez vamos escolher um runtime com GPU que neste caso é chamado de 11.1 ML (inclui Apache Spark 3.3.0, GPU, Scala 2.12) e vem com todos os softwares CUDA e NVIDIA necessários instalados. A próxima coisa que precisamos é selecionar também uma instância da AWS que tenha uma GPU e eu escolhi g4dn.8xlarge que tem 1 GPU e um número semelhante de núcleos/memória como o outro cluster. Esta instância de GPU vem com um Tesla T4 e 16 GB de memória ( 15 GB memória GPU utilizável).

    Cluster de nó único Databricks — tempo de execução da GPU

    Este é o resumo do nosso cluster de nó único como o anterior e é o mesmo em termos de número de núcleos e quantidade de memória, mas vem com uma GPU Tesla T4:

    Cluster de nó único do Databricks — perfil de instância da AWS

    Agora que temos um cluster de nó único com uma GPU, podemos continuar nossos benchmarks para ver o desempenho do Hugging Face nesta máquina no Databricks. Vou executar o benchmark no conjunto de dados menor para ver qual tamanho de lote é mais adequado para nossa máquina baseada em GPU:

    Abraçando o pipeline de classificação de imagem facial na CPU de nó único do Databricks — prevendo 3.544 imagens

    Demorou cerca de um minuto ( 64 segundos ) para concluir o processamento de cerca de 3.544 imagens de nosso conjunto de dados de exemplo em nosso cluster Databricks de nó único com um dispositivo GPU. O lote melhorou a velocidade se observarmos o resultado do tamanho do lote 1, no entanto, após o tamanho do lote 8, os resultados praticamente permaneceram os mesmos. Embora os resultados sejam os mesmos após o tamanho do lote 8, escolhi o tamanho do lote 256 para meu benchmark maior para utilizar mais memória da GPU também. (para ser honesto, 8 e 256 tiveram praticamente o mesmo desempenho)

    Vamos executar o benchmark no conjunto de dados maior e ver o que acontece com o tamanho do lote 256:

    Abraçando o pipeline de classificação de imagem facial na CPU de nó único do Databricks — prevendo 34745 imagens

    Em um conjunto de dados maior, levou quase 11 minutos ( 659 segundos ) para concluir a previsão de classes para mais de 34 mil imagens. Se compararmos os resultados de nossos benchmarks em um único nó com CPUs e um único nó que vem com 1 GPU, podemos ver que o nó GPU aqui é o vencedor:

    Hugging Face (PyTorch) é até 2,3 vezes mais rápido em GPU versus CPU

    A GPU é até aproximadamente 2,3 vezes mais rápida em comparação com a execução do mesmo pipeline em CPUs em Hugging Face em Databricks Single Node

    Agora vamos executar os mesmos benchmarks usando o Spark NLP nos mesmos clusters e nos mesmos conjuntos de dados para compará-lo com o Hugging Face.

    Comparando o Spark NLP em um único nó Databricks

    Primeiro, vamos instalar o Spark NLP em suas CPUs Databricks de nó único:

    Na guia Bibliotecas dentro do seu cluster, você precisa seguir estas etapas:
    — Instalar Novo -> PyPI -> spark-nlp==4.1.0 -> Instalar
    — Instalar Novo -> Maven -> Coordenadas -> com.johnsnowlabs.nlp:spark-nlp_2.12:4.1.0 -> Instalar
    — Adicionará ` TF_ENABLE_ONEDNN_OPTS=1 ` a `Cluster->Advacend Options->Spark->Environment variables` para habilitar oneDNN

    Como instalar o Spark NLP no Databricks em CPUs para Python, Scala e Java

    Spark NLP em Databricks Single Node com CPUs na AWS

    Agora que temos o Spark NLP instalado em nosso cluster de nó único Databricks, podemos repetir os benchmarks para uma amostra e conjuntos de dados completos na CPU e na GPU. Vamos começar com o benchmark em CPUs primeiro sobre o conjunto de dados de amostra:

    Pipeline de classificação de imagem Spark NLP em CPUs de nó único Databricks (oneDNN) — prevendo 3544 imagens

    Demorou cerca de 2 minutos ( 111 segundos ) para concluir o processamento de 3.544 imagens e prever suas classes no mesmo cluster Databricks de nó único com CPUs que usamos para Hugging Face. Podemos ver que o tamanho do lote de 16 tem o melhor resultado, então usarei isso no próximo benchmark no conjunto de dados maior:

    Pipeline de classificação de imagem Spark NLP em CPUs de nó único Databricks (oneDNN) — prevendo 34742 imagens

    No conjunto de dados maior com mais de 34 mil imagens , demorou cerca de 18 minutos ( 1.072 segundos ) para concluir a previsão de classes para essas imagens. Em seguida, repetirei os mesmos benchmarks no cluster com GPU.

    Databricks Single Node com uma GPU na AWS

    Primeiro, instale o Spark NLP em sua GPU Single Node Databricks (a única diferença é o uso de “ spark-nlp-gpu” do Maven):

    Instale o Spark NLP em seu cluster Databricks
    — Na guia Bibliotecas dentro do cluster, você precisa seguir estas etapas:
    — Instalar Novo -> PyPI -> spark-nlp==4.1.0 -> Instalar
    — Instalar Novo -> Maven -> Coordenadas -> com.johnsnowlabs.nlp:spark-nlp-gpu_2.12:4.1.0 -> Instalar

    Como instalar o Spark NLP no Databricks em GPUs para Python, Scala e Java

    Vou executar o benchmark no conjunto de dados menor para ver qual tamanho de lote é mais adequado para nossa máquina baseada em GPU:

    Pipeline de classificação de imagem Spark NLP na GPU de nó único do Databricks — prevendo 3544 imagens

    Demorou menos de um minuto ( 47 segundos ) para concluir o processamento de cerca de 3.544 imagens de nosso conjunto de dados de amostra em nossos Databricks de nó único com um dispositivo GPU. Podemos ver que o tamanho do lote 8 teve o melhor desempenho neste caso de uso específico, então executarei o benchmark no conjunto de dados maior:

    Pipeline de classificação de imagem Spark NLP na GPU de nó único Databricks — prevendo 34742 imagens

    Em um conjunto de dados maior, levou quase 7 minutos e meio ( 435 segundos ) para concluir a previsão de classes para mais de 34 mil imagens . Se compararmos os resultados de nossos benchmarks em um único nó com CPUs e um único nó que vem com 1 GPU, podemos ver que o nó GPU aqui é o vencedor:

    O Spark NLP é até 2,5 vezes mais rápido em GPU versus CPU em Databricks Single Node

    Isso é ótimo! Podemos ver que o Spark NLP na GPU é até 2,5 vezes mais rápido que as CPUs, mesmo com oneDNN ativado (oneDNN melhora os resultados em CPUs entre 10% a 20%).

    Vamos dar uma olhada em como esses resultados são comparados aos benchmarks Hugging Face no mesmo cluster Databricks Single Node:


    O Spark NLP é até 15% mais rápido do que Hugging Face em CPUs na previsão de classes de imagem para o conjunto de dados de amostra com imagens 3K e até 34% no conjunto de dados maior com imagens 34K. O Spark NLP também é 51% mais rápido do que Hugging Face em uma única GPU para um conjunto de dados maior com imagens de 34K e até 36% mais rápido em um conjunto de dados menor com imagens de 3K.


    Spark NLP é mais rápido em CPUs e GPUs vs. Hugging Face em Databricks Single Node

    Dimensionamento além de uma única máquina

    Até agora, estabelecemos que o Hugging Face na GPU é mais rápido do que o Hugging Face nas CPUs em um servidor bare-metal e Databricks Single Node. Isso é o que você espera ao comparar GPU x CPU com esses novos modelos baseados em transformador.

    Também estabelecemos que o Spark NLP supera o Hugging Face para o mesmo pipeline (modelo ViT), nos mesmos conjuntos de dados, tanto no servidor bare-metal quanto no cluster de nó único Databricks, e tem melhor desempenho em dispositivos de CPU e GPU. Por outro lado, isso não era algo que eu esperava. Quando eu estava preparando este artigo, esperava que a inferência do TensorFlow no Spark NLP fosse um pouco mais lenta do que a inferência no Hugging Face usando PyTorch ou pelo menos pescoço a pescoço. Eu estava mirando nesta seção, dimensionando o pipeline além de uma única máquina . Mas parece que o Spark NLP é mais rápido que o Hugging Face, mesmo em uma única máquina, tanto na CPU quanto na GPU , em conjuntos de dados pequenos e grandes .

    Pergunta: E se você quiser tornar seu pipeline de ViT ainda mais rápido? E se você tiver conjuntos de dados ainda maiores e simplesmente não conseguir encaixá-los em uma máquina ou se demorar muito para obter os resultados de volta?

    Resposta: Expansão! Isso significa que, em vez de redimensionar a mesma máquina, adicione mais máquinas ao seu cluster. Você precisa de algo para gerenciar todos esses trabalhos/tarefas/agendamento de DAGs/gerenciar tarefas com falha/etc. e esses têm suas despesas gerais, mas se você precisa que algo seja mais rápido ou possível (além de uma única máquina), você deve usar algum tipo de sistema distribuído.

    Ampliação = tornar sua máquina maior ou mais rápida para que ela possa lidar com mais carga.

    Expansão = adicionar mais máquinas em paralelo para distribuir uma carga.

    Ampliando o Rosto de Abraço:

    Observar a página no site oficial do Hugging Face sugere que a inferência de escala só é possível usando Multi-GPUs. Conforme descrevemos o que é o escalonamento horizontal, ele ainda está preso em uma única máquina:

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

    Além disso, sem contar que a solução Multi-GPUs para inferência em Hugging Face não existe no momento:

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

    Portanto, parece que não há uma maneira nativa/oficial de expandir os pipelines do Hugging Face. Você pode implementar sua arquitetura consistindo em alguns microsserviços, como uma fila de tarefas, protocolos de mensagens, back-end de APIs RESTful e alguns outros componentes necessários para distribuir cada solicitação em diferentes máquinas, mas isso dimensiona as solicitações de usuários individuais em vez de dimensionar o sistema real em si.

    Além disso, a latência desses sistemas não é comparável com sistemas distribuídos nativamente, como o Apache Spark (o gRPC pode diminuir essa latência, mas ainda não é competitivo). Sem mencionar o problema de ponto único de falha, gerenciamento de trabalhos/tarefas/entradas com falha e centenas de outros recursos que você obtém imediatamente do Apache Spark que agora você precisa implementar/manter sozinho.

    Há uma postagem de blog no site do Hugging Face retratando a mesma arquitetura, dimensionando os endpoints REST para atender a mais usuários: “ Implantando 🤗 ViT no Kubernetes com TF Servindo ” - acredito que outras empresas estão usando abordagens semelhantes para expandir o Hugging Face, no entanto , todos estão dimensionando o número de usuários/solicitações que atingem os terminais REST de inferência. Além disso, você não pode dimensionar Hugging Face dessa maneira no Databricks.

    Por exemplo, a inferência dentro do fastAPI é 10 vezes mais lenta que a inferência local: https://towardsdatascience.com/hugging-face-transformer-inference-under-1-millisecond-latency-e1be0057a51c

    Depois que o Hugging Face oferecer algumas soluções nativas para escalar, executarei novamente os benchmarks. Até então, não há escalonamento quando você precisa percorrer o conjunto de dados de uma única máquina para atingir os pontos de extremidade REST em um algoritmo round-robin. (pense novamente sobre a parte em que agrupamos linhas/sequências/imagens para alimentar a GPU de uma só vez, então você entenderá)

    Escalando o Spark NLP:

    O Spark NLP é uma extensão do Spark ML, portanto, escala nativamente e perfeitamente em todas as plataformas suportadas pelo Apache Spark, como (e não limitado) Databricks, AWS EMR, Azure Insight, GCP Dataproc, Cloudera, SageMaker, Kubernetes e muitos mais.

    Zero alterações de código são necessárias! O Spark NLP pode escalar de uma única máquina para um número infinito de máquinas sem alterar nada no código!

    Você também não precisa exportar nenhum modelo do Spark NLP para usá-lo em uma biblioteca totalmente diferente para acelerar ou dimensionar a inferência.

    Ecossistema Spark NLP: integrações otimizadas, testadas e suportadas

    Databricks Multi-Node com CPUs na AWS

    Vamos criar um cluster e desta vez escolhemos Standard dentro do modo Cluster . Isso significa que podemos ter mais de 1 nó em nosso cluster, o que na terminologia do Apache Spark significa 1 Driver e N número de Trabalhadores (Executores).

    Também precisamos instalar o Spark NLP neste novo cluster por meio da guia Bibliotecas. Você pode seguir as etapas que mencionei na seção anterior para Databricks de nó único com CPUs. Como você pode ver, escolhi a mesma instância da AWS baseada em CPU que usei para comparar Hugging Face e Spark NLP para que possamos ver como ela se expande quando adicionamos mais nós.

    É assim que nossas configurações de Cluster se parecem:

    Databricks cluster de vários nós (padrão) com apenas CPUs

    Vou reutilizar o mesmo pipeline Spark NLP que usei em benchmarks anteriores (sem necessidade de alterar nenhum código) e também usarei apenas o conjunto de dados maior com imagens de 34K. Vamos começar!

    Escale o Spark NLP em CPUs com 2x nós

    Databricks com 2x nós — apenas CPUs

    Vamos apenas adicionar mais 1 nó e fazer o total das máquinas que farão o processamento para 2 máquinas. Não vamos esquecer a beleza do Spark NLP quando você passa de uma configuração de máquina única (seu Colab, Kaggle, Databricks Single Node ou até mesmo seu notebook Jupyter local) para uma configuração de cluster de vários nós (Databricks, EMR, GCP, Azure, Cloudera , YARN, Kubernetes, etc.), a alteração do código zero é necessária! E eu quero dizer zero! Com isso em mente, executarei o mesmo benchmark dentro deste novo cluster nos conjuntos de dados maiores com imagens de 34K:

    Pipeline de classificação de imagens Spark NLP em nós 2x com CPUs (oneDNN) — prevendo 34742 imagens

    Demorou cerca de 9 minutos ( 550 segundos ) para concluir a previsão de classes para imagens de 34K. Vamos comparar este resultado em 2x Nodes com Spark NLP e Hugging Face resultados no nó único do Databricks (continuarei repetindo os resultados do Hugging Face em um único nó como referência, pois o Hugging Face não pode ser dimensionado em várias máquinas, especialmente em Databricks) :

    O Spark NLP é 124% mais rápido que o Hugging Face com 2x Nodes

    Anteriormente, o Spark NLP vencia o Hugging Face em um cluster Databricks de nó único usando apenas CPUs em 15% .

    Desta vez, por ter apenas 2x nós em vez de 1 nó, o Spark NLP finalizou o processo de mais de 34 mil imagens 124% mais rápido do que Hugging Face. Dimensione o Spark NLP em CPUs com 4x nós

    Vamos dobrar o tamanho do nosso cluster como antes e passar de 2x nós para 4x nós. É assim que o cluster ficaria com nós 4x:

    Databricks com 4x nós — apenas CPUs

    Executarei o mesmo benchmark neste novo cluster nos conjuntos de dados maiores com imagens de 34K:

    Pipeline de classificação de imagens Spark NLP em nós 4x com CPUs (oneDNN) — prevendo 34742 imagens

    Demorou cerca de 5 minutos ( 289 segundos ) para concluir a previsão de classes para imagens de 34K. Vamos comparar este resultado em 4x Nodes com Spark NLP vs. Hugging Face em CPUs em Databricks:

    O Spark NLP é 327% mais rápido que o Hugging Face com 4x Nodes

    Como pode ser visto, o Spark NLP agora é 327% mais rápido do que o Hugging Face em CPUs enquanto usa apenas 4x Nodes em Databricks.

    Escale o Spark NLP em CPUs com 8x nós

    Agora vamos dobrar o cluster anterior adicionando 4x mais nós e fazer o total de 8x nós . A propósito, esse redimensionamento do cluster é bem fácil, basta aumentar o número de workers nas configurações do cluster:

    Redimensionando o Spark Cluster no Databricks

    Databricks com 8x nós — apenas CPUs

    Vamos executar o mesmo benchmark desta vez em 8x Nodes:

    Pipeline de classificação de imagens Spark NLP em nós 8x com CPUs (oneDNN) — prevendo 34742 imagens

    Demorou mais de 2 minutos e meio ( 161 segundos ) para concluir a previsão de classes para imagens de 34K. Vamos comparar este resultado em 8x Nodes com Spark NLP vs. Hugging Face em CPUs em Databricks:

    O Spark NLP é 666% mais rápido que o Hugging Face com 8x Nodes

    Como pode ser visto, o Spark NLP agora é 666% mais rápido do que o Hugging Face em CPUs enquanto usa apenas 8x nós em Databricks.

    Vamos apenas ignorar o número de 6s aqui! (foi 665,8% se te faz sentir melhor)

    Escale o Spark NLP em CPUs com 10x nós

    Para concluir nossas previsões de dimensionamento de modelos ViT em CPUs em Databricks usando o Spark NLP, redimensionarei o cluster mais uma vez e o aumentarei para 10x nós:

    Databricks com 10x nós — apenas CPUs

    Vamos executar o mesmo benchmark desta vez em 10x Nodes:

    Pipeline de classificação de imagens Spark NLP em nós 10x com CPUs (oneDNN) — prevendo 34742 imagens

    Levou menos de 2 minutos ( 112 segundos ) para concluir a previsão de classes para imagens de 34K. Vamos comparar este resultado em 10x Nodes com todos os resultados anteriores do Spark NLP vs. Hugging Face em CPUs em Databricks:

    O Spark NLP é 1000% mais rápido que o Hugging Face com 10x Nodes

    E é assim que você dimensiona o modelo do Vision Transformer vindo do Hugging Face em 10x Nodes usando o Spark NLP no Databricks! Nosso pipeline agora é 1000% mais rápido do que o Hugging Face nas CPUs.

    Conseguimos tornar nosso pipeline ViT 1000% mais rápido do que o Hugging Face, que fica preso em um único nó, simplesmente usando o Spark NLP, mas usamos apenas CPUs . Vamos ver se podemos obter as mesmas melhorias escalando nosso pipeline em um cluster de GPU .

    Databricks Multi-Node com GPUs na AWS

    Ter um cluster Databricks de vários nós baseado em GPU é praticamente o mesmo que ter um cluster de nó único. A única diferença é escolher Standard e manter o mesmo ML/GPU Runtime com as mesmas especificações de instância da AWS que escolhemos em nossos benchmarks para GPU em um único nó.

    Também precisamos instalar o Spark NLP neste novo cluster por meio da guia Bibliotecas . Assim como antes, você pode seguir as etapas que mencionei em Databricks de nó único com uma GPU.

    Databricks cluster de vários nós (padrão) com GPUs

    Escale o Spark NLP em GPUs com 2x nós

    Nosso cluster de GPU Databricks de vários nós usa a mesma instância de GPU da AWS de g4dn.8xlarge que usamos anteriormente para executar nossos benchmarks para comparar Spark NLP vs. Hugging Face em um cluster Databricks de nó único.

    Este é um resumo do que parece desta vez com 2 nós:

    Databricks com 2x nós — com 1 GPU por nó

    Vou executar o mesmo pipeline neste cluster de GPU com 2x nós:

    Pipeline de classificação de imagens Spark NLP em nós 2x com GPUs — prevendo 34742 imagens

    Levou 4 minutos ( 231 segundos ) para concluir a previsão de classes para imagens de 34K . Vamos comparar este resultado em 2x Nodes com Spark NLP vs. Hugging Face em GPUs em Databricks:

    O Spark NLP é 185% mais rápido que o Hugging Face com 2x Nodes

    Spark NLP com 2x Nodes é quase 3x vezes mais rápido ( 185% ) do que Hugging Face em 1 único nó enquanto usa GPU.

    Escale o Spark NLP em GPUs com 4x nós

    Vamos redimensionar nosso cluster de GPU de 2x nós para 4x nós. Este é um resumo da aparência desta vez com 4x Nodes usando uma GPU:

    Databricks com 4x nós — com 1 GPU por nó

    Vamos executar o mesmo benchmark em 4x Nodes e ver o que acontece:

    Pipeline de classificação de imagens Spark NLP em nós 4x com GPUs — prevendo 34742 imagens

    Desta vez, levou quase 2 minutos ( 118 segundos ) para terminar de classificar todas as imagens de 34K em nosso conjunto de dados. Vamos visualizar isso apenas para ter uma visão melhor do que isso significa em termos de Hugging Face em um único nó versus Spark NLP em um cluster de vários nós:

    O Spark NLP é 458% mais rápido que o Hugging Face com 4x Nodes

    Isso representa um aumento de 458% no desempenho em comparação com o Hugging Face. Acabamos de tornar nosso pipeline 5,6 vezes mais rápido usando o Spark NLP com 4x nós.

    Escale o Spark NLP em GPUs com 8x nós

    Em seguida, redimensionarei o cluster para ter 8x Nodes em meus Databricks com o seguinte resumo:

    Databricks com 8x nós — com 1 GPU por nó

    Só para lembrar, cada instância da AWS ( g4dn.8xlarge ) tem 1 GPU NVIDIA T4 de 16 GB (15 GB de memória utilizável). Vamos executar novamente o benchmark e ver se podemos identificar melhorias, pois a expansão em qualquer sistema distribuído tem suas despesas gerais e você não pode simplesmente continuar adicionando máquinas:

    Pipeline de classificação de imagens Spark NLP em nós 8x com GPUs — prevendo 34742 imagens

    Demorou quase um minuto ( 61 segundos ) para concluir a classificação de imagens de 34K com 8x nós em nosso cluster Databricks. Parece que ainda conseguimos melhorar o desempenho. Vamos colocar este resultado ao lado dos resultados anteriores de Hugging Face em um único nó versus Spark NLP em um cluster de vários nós:

    O Spark NLP é 980% mais rápido que o Hugging Face com 8x Nodes

    O Spark NLP com 8x Nodes é quase 11x vezes mais rápido (980%) do que o Hugging Face em GPUs.

    Escale o Spark NLP em GPUs com 10x nós

    Semelhante aos nossos benchmarks de vários nós em CPUs, gostaria de redimensionar o cluster de GPU mais uma vez para ter 10x nós e combiná-los em termos do número final de nós. O resumo final deste cluster é o seguinte:

    Databricks com 10x nós — com 1 GPU por nó

    Vamos executar nosso último benchmark neste cluster de GPU específico (sem alterações de código):

    Pipeline de classificação de imagens Spark NLP em nós 10x com GPUs — prevendo 34742 imagens

    Levou menos de um minuto ( 51 segundos ) para concluir a previsão de classes para mais de 34.743 imagens . Vamos colocá-los um ao lado do outro e ver como progredimos ao expandir nosso modelo Vision Transformer vindo de Hugging Face no pipeline Spark NLP em Databricks:

    O Spark NLP é 1200% mais rápido que o Hugging Face com 10x Nodes

    E terminamos!

    Conseguimos escalar nosso modelo Vision Transformer vindo de Hugging Face em 10x Nodes usando Spark NLP em Databricks! Nosso pipeline agora é 13 vezes mais rápido, com melhorias de desempenho de 1200% em comparação com Hugging Face na GPU.

    Vamos resumir todos esses benchmarks comparando primeiro as melhorias entre CPUs e GPUs e, em seguida, quão mais rápido nosso pipeline pode ser indo de Hugging Face CPUs para 10x Nodes em Databricks usando Spark NLP em GPUs.

    Juntando tudo:

    Databricks: nó único e vários nós

    O Spark NLP 🚀 em 10x Nodes com CPUs é 1000% (11x vezes) mais rápido que o Hugging Face 🤗 preso em um único node com CPUs


    O Spark NLP 🚀 em 10x nós com GPUs é 1192% (13x vezes) mais rápido que o Hugging Face 🤗 preso em um único nó com GPU

    E quanto às diferenças de preço entre nossa instância de CPU da AWS e a instância de GPU da AWS? (Quero dizer, você ganha mais se pagar mais, certo?)

    AWS m5d.8xlarge com CPUs vs. AWS g4dn.8xlarge com 1 GPU e especificações semelhantes

    OK, então o preço parece praticamente o mesmo! Com isso em mente, quais melhorias você obtém se mudar de Hugging Face em CPUs presas em uma única máquina para Spark NLP em 10x Nodes com 10x GPUs ?

    Spark NLP em GPUs é 25x vezes (2366%) mais rápido que Hugging Face em CPUs

    O Spark NLP 🚀 em 10x nós com GPUs é 2366% (25x vezes) mais rápido que o Hugging Face 🤗 em um único nó com CPUs

    palavras finais

    • No espírito de total transparência, todos os notebooks com seus logs, capturas de tela e até a planilha do Excel com números são fornecidos aqui no GitHub
    • O escalonamento do Spark NLP requer zero alteração de código. Executar os benchmarks de um único nó Databricks para os 10 nós significava apenas executar novamente o mesmo bloco de código no mesmo notebook
    • Lembre-se de que essas duas bibliotecas vêm com muitas práticas recomendadas para otimizar sua velocidade e eficiência em diferentes ambientes para diferentes casos de uso. Por exemplo, não falei sobre partições e sua relação com paralelismo e distribuições no Apache Spark. Existem muitas configurações do Spark para ajustar um cluster, especialmente equilibrando o número de tarefas entre CPUs e GPUs. Agora a questão é, seria possível acelerar qualquer um deles dentro dos mesmos ambientes que usamos para nossos benchmarks? A resposta é 100%! Tentei manter tudo para ambas as bibliotecas com valores padrão e recursos prontos para uso em favor da simplicidade para a maioria dos usuários.
    • Talvez você queira agrupar Hugging Face e outras bibliotecas Pythonish baseadas em DL em um Spark UDF para escalá-las. Isso funciona até certo ponto, como eu mesmo fiz e ainda faço (quando não há solução nativa). Não entrarei em detalhes sobre uso excessivo de memória, possíveis problemas de serialização, latência mais alta e outros problemas quando se agrupa tais modelos baseados em transformadores em uma UDF. Eu diria apenas que se você estiver usando o Apache Spark, use a biblioteca que está estendendo nativamente seus recursos necessários no Apache Spark.
    • Ao longo deste artigo, fiz o possível para mencionar o Hugging Face no PyTorch e o Spark NLP no TensorFlow. Essa é uma grande diferença, visto que em todos os benchmarks feitos pelo Hugging Face entre PyTorch e TensorFlow, o PyTorch foi e ainda é o vencedor em inferência. No Hugging Face, o PyTorch tem uma latência muito menor e parece ser muito mais rápido que o TensorFlow nos Transformers. O fato de o Spark NLP usar o mesmo TensorFlow e ficar à frente em todos os benchmarks em comparação com o PyTorch em Hugging Face é um grande negócio. O TensorFlow em Hugging Face é negligenciado ou o PyTorch é apenas mais rápido na inferência em comparação com o TensorFlow. De qualquer forma, mal posso esperar para ver o que acontecerá quando o Spark NLP começar a suportar TorchScript e ONNX Runtime, além do TensorFlow.
    • Os tempos de execução ML e ML GPU Databricks vêm com o Hugging Face instalado, isso é muito bom. Mas isso não significa que o Hugging Face seja fácil de usar no Databricks. A biblioteca Transformer da Hugging Face não oferece suporte a DBFS (o sistema de arquivos distribuído nativo do Databricks) ou Amazon S3. Como você vê nos notebooks, tive que baixar uma versão compactada dos conjuntos de dados e extraí-los para usá-los. Não é assim que os usuários no Databricks e outras plataformas em produções fazem as coisas. Mantemos nossos dados em sistemas de arquivos distribuídos, existem medidas de segurança implementadas e a maioria delas é grande o suficiente para não ser baixada por um computador pessoal. Tive que baixar os conjuntos de dados que já tinha no DBFS, compactá-los, carregá-los no S3, torná-los públicos e baixá-los novamente nos notebooks. Um processo bastante tedioso que poderia ter sido evitado se o Hugging Face pudesse suportar DBFS/S3.

    Referências

    ViT

    rosto abraçado

    Databricks

    Spark PNL