Share via


Modellinferens med huggande ansiktstransformatorer för NLP

Den här artikeln visar hur du använder Hugging Face Transformers för nlp-modellinferens (natural language processing).

Genom att krama ansiktstransformatorer får du pipelineklassen för att använda den förtränade modellen för slutsatsdragning. 🤗 Transformatorpipelines har stöd för en mängd olika NLP-uppgifter som du enkelt kan använda i Azure Databricks.

Krav

  • MLflow 2.3
  • Alla kluster med biblioteket Hugging Face transformers installerat kan användas för batchinferens. Biblioteket transformers är förinstallerat på Databricks Runtime 10.4 LTS ML och senare. Många av de populära NLP-modellerna fungerar bäst på GPU-maskinvara, så du kan få bästa prestanda med hjälp av den senaste GPU-maskinvaran om du inte använder en modell som är särskilt optimerad för användning på processorer.

Använda Pandas UDF:er för att distribuera modellberäkning i ett Spark-kluster

När du experimenterar med förtränade modeller kan du använda Pandas UDF:er för att omsluta modellen och utföra beräkningar på arbets-PROCESSORer eller GPU:er. Pandas UDF:er distribuerar modellen till varje arbetare.

Du kan också skapa en Pipeline för huggande ansiktstransformatorer för maskinöversättning och använda en Pandas UDF för att köra pipelinen på arbetarna i ett Spark-kluster:

import pandas as pd
from transformers import pipeline
import torch
from pyspark.sql.functions import pandas_udf

device = 0 if torch.cuda.is_available() else -1
translation_pipeline = pipeline(task="translation_en_to_fr", model="t5-base", device=device)

@pandas_udf('string')
def translation_udf(texts: pd.Series) -> pd.Series:
  translations = [result['translation_text'] for result in translation_pipeline(texts.to_list(), batch_size=1)]
  return pd.Series(translations)

device Om du anger på det här sättet ser du till att GPU:er används om de är tillgängliga i klustret.

Pipelines för kramande ansiktsigenkänning för översättning returnerar en lista över Python-objekt dict , var och en med en enda nyckel translation_text och ett värde som innehåller den översatta texten. Denna UDF extraherar översättningen från resultaten för att returnera en Pandas-serie med bara den översatta texten. Om din pipeline har konstruerats för att använda GPU:er genom att ange device=0, omtilldelar Spark automatiskt GPU:er på arbetsnoderna om klustret har instanser med flera GPU:er.

Om du vill använda UDF för att översätta en textkolumn kan du anropa UDF i en select instruktion:

texts = ["Hugging Face is a French company based in New York City.", "Databricks is based in San Francisco."]
df = spark.createDataFrame(pd.DataFrame(texts, columns=["texts"]))
display(df.select(df.texts, translation_udf(df.texts).alias('translation')))

Returnera komplexa resultattyper

Med Hjälp av Pandas UDF:er kan du också returnera mer strukturerade utdata. I igenkänning med namnet entitet returnerar pipelines till exempel en lista över dict objekt som innehåller entiteten, dess span, typ och en associerad poäng. Även om det liknar exemplet för översättning är returtypen för anteckningen @pandas_udf mer komplex när det gäller igenkänning med namngivna entiteter.

Du kan få en uppfattning om vilka returtyper som ska användas genom kontroll av pipelineresultat, till exempel genom att köra pipelinen på drivrutinen.

I det här exemplet använder du följande kod:

from transformers import pipeline
import torch
device = 0 if torch.cuda.is_available() else -1
ner_pipeline = pipeline(task="ner", model="Davlan/bert-base-multilingual-cased-ner-hrl", aggregation_strategy="simple", device=device)
ner_pipeline(texts)

Så här ger du anteckningarna:

[[{'entity_group': 'ORG',
   'score': 0.99933606,
   'word': 'Hugging Face',
   'start': 0,
   'end': 12},
  {'entity_group': 'LOC',
   'score': 0.99967843,
   'word': 'New York City',
   'start': 42,
   'end': 55}],
 [{'entity_group': 'ORG',
   'score': 0.9996372,
   'word': 'Databricks',
   'start': 0,
   'end': 10},
  {'entity_group': 'LOC',
   'score': 0.999588,
   'word': 'San Francisco',
   'start': 23,
   'end': 36}]]

Om du vill representera detta som en returtyp kan du använda ett array fält struct som visar posterna dict som fält i struct:

import pandas as pd
from pyspark.sql.functions import pandas_udf

@pandas_udf('array<struct<word string, entity_group string, score float, start integer, end integer>>')
def ner_udf(texts: pd.Series) -> pd.Series:
  return pd.Series(ner_pipeline(texts.to_list(), batch_size=1))

display(df.select(df.texts, ner_udf(df.texts).alias('entities')))

Finjustera prestanda

Det finns flera viktiga aspekter för att justera prestanda för UDF. Den första är att använda varje GPU effektivt, vilket du kan justera genom att ändra storleken på batchar som skickas till GPU:n av Transformers-pipelinen. Den andra är att se till att DataFrame är väl partitionerad för att använda hela klustret.

Slutligen kanske du vill cachelagrar Hugging Face-modellen för att spara modellens inläsningstid eller ingresskostnader.

Välj en batchstorlek

Även om de UDF:er som beskrivs ovan bör fungera utan 1, kanske detta inte använder de resurser som är tillgängliga för arbetstagarna på ett batch_size effektivt sätt. För att förbättra prestandan justerar du batchstorleken till modellen och maskinvaran i klustret. Databricks rekommenderar att du provar olika batchstorlekar för pipelinen i klustret för att hitta bästa möjliga prestanda. Läs mer om pipeline-batchbearbetning och andra prestandaalternativ i dokumentationen om huggande ansiktsigenkänning.

Försök att hitta en batchstorlek som är tillräckligt stor så att den driver den fullständiga GPU-användningen men inte resulterar i CUDA out of memory fel. När du får CUDA out of memory fel under justeringen måste du koppla från och koppla från anteckningsboken igen för att frigöra det minne som används av modellen och data i GPU:n.

Övervaka GPU-prestanda genom att visa liveklustermåtten för ett kluster och välja ett mått, till exempel gpu0-util för GPU-processoranvändning eller gpu0_mem_util för GPU-minnesanvändning.

Finjustera parallellitet med schemaläggning på stadiumnivå

Som standard schemalägger Spark en aktivitet per GPU på varje dator. Om du vill öka parallelliteten kan du använda schemaläggning på stegnivå för att berätta för Spark hur många aktiviteter som ska köras per GPU. Om du till exempel vill att Spark ska köra två uppgifter per GPU kan du ange detta på följande sätt:

from pyspark.resource import TaskResourceRequests, ResourceProfileBuilder

task_requests = TaskResourceRequests().resource("gpu", 0.5)

builder = ResourceProfileBuilder()
resource_profile = builder.require(task_requests).build

rdd = df.withColumn('predictions', loaded_model(struct(*map(col, df.columns)))).rdd.withResources(resource_profile)

Ompartitionera data för att använda all tillgänglig maskinvara

Det andra att tänka på när det gäller prestanda är att använda maskinvaran i klustret fullt ut. I allmänhet fungerar en liten multipel av antalet GPU:er på dina arbetare (för GPU-kluster) eller antalet kärnor mellan arbetarna i klustret (för CPU-kluster). Din indatadataram kanske redan har tillräckligt med partitioner för att dra nytta av klustrets parallellitet. Om du vill se hur många partitioner dataramen innehåller använder du df.rdd.getNumPartitions(). Du kan partitionera om en DataFrame med hjälp av repartitioned_df = df.repartition(desired_partition_count).

Cachelagrat modellen i DBFS eller på monteringspunkter

Om du ofta läser in en modell från olika eller omstartade kluster kanske du också vill cachelagrar huggningsmodellen i DBFS-rotvolymen eller på en monteringspunkt. Detta kan minska ingångskostnaderna och minska tiden för att läsa in modellen på ett nytt eller omstartat kluster. Det gör du genom att TRANSFORMERS_CACHE ange miljövariabeln i koden innan du läser in pipelinen.

Till exempel:

import os
os.environ['TRANSFORMERS_CACHE'] = '/dbfs/hugging_face_transformers_cache/'

Du kan också uppnå liknande resultat genom att logga modellen till MLflow med MLflow-smakentransformers.

Notebook: Hugging Face Transformers-slutsatsdragning och MLflow-loggning

För att komma igång snabbt med exempelkod är den här notebook-filen ett exempel från slutpunkt till slutpunkt för textsammanfattning med hjälp av Hugging Face Transformers-pipelines-slutsatsdragning och MLflow-loggning.

Hugging Face Transformers-pipelines slutsatsdragningsanteckningsbok

Hämta notebook-fil

Ytterligare resurser

Du kan finjustera din Hugging Face-modell med följande guider:

Läs mer om Vad är huggande ansiktstransformatorer?