Modeldeductie met hugging Face Transformers voor NLP
In dit artikel leest u hoe u Hugging Face Transformers gebruikt voor modeldeductie van natuurlijke taalverwerking (NLP).
Het knuffelen van Face-transformaties biedt de klasse pijplijnen voor het gebruik van het vooraf getrainde model voor deductie. 🤗 Transformatorpijplijnen ondersteunen een breed scala aan NLP-taken die u eenvoudig kunt gebruiken in Azure Databricks.
Vereisten
- MLflow 2.3
- Elk cluster waarop de Hugging Face-bibliotheek
transformers
is geïnstalleerd, kan worden gebruikt voor batchdeductie. Detransformers
bibliotheek is vooraf geïnstalleerd op Databricks Runtime 10.4 LTS ML en hoger. Veel van de populaire NLP-modellen werken het beste op GPU-hardware, dus u krijgt mogelijk de beste prestaties met recente GPU-hardware, tenzij u een model gebruikt dat speciaal is geoptimaliseerd voor gebruik op CPU's.
Pandas UDF's gebruiken om modelberekeningen in een Spark-cluster te distribueren
Wanneer u experimenteert met vooraf getrainde modellen, kunt u Pandas UDF's gebruiken om het model te verpakken en berekeningen uit te voeren op werkrol-CPU's of GPU's. Pandas UDF's distribueren het model naar elke werkrol.
U kunt ook een Pijplijn voor Face Transformers voor het omzetten van machines maken en een Pandas UDF gebruiken om de pijplijn uit te voeren op de werkrollen van een Spark-cluster:
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)
Door de device
op deze manier in te stellen, zorgt u ervoor dat GPU's worden gebruikt als deze beschikbaar zijn op het cluster.
De Face-pijplijnen voor het omhelzen voor vertaling retourneren een lijst met Python-objecten dict
, elk met één sleutel translation_text
en een waarde die de vertaalde tekst bevat. Met deze UDF wordt de vertaling uit de resultaten geëxtraheerd om een Pandas-reeks te retourneren met alleen de vertaalde tekst. Als uw pijplijn is gemaakt voor het gebruik van GPU's door de instelling in te stellen device=0
, worden GPU's automatisch opnieuw toegewezen aan de werkknooppunten als uw cluster exemplaren met meerdere GPU's heeft.
Als u de UDF wilt gebruiken om een tekstkolom te vertalen, kunt u de UDF in een select
instructie aanroepen:
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')))
Complexe resultaattypen retourneren
Met Pandas UDF's kunt u ook meer gestructureerde uitvoer retourneren. In de herkenning van benoemde entiteiten retourneren pijplijnen bijvoorbeeld een lijst dict
met objecten die de entiteit, het bereik, het type en een bijbehorende score bevatten. Hoewel dit vergelijkbaar is met het voorbeeld voor vertaling, is het retourtype voor de @pandas_udf
aantekening complexer in het geval van herkenning van benoemde entiteiten.
U kunt een idee krijgen van de retourtypen die moeten worden gebruikt door middel van inspectie van de pijplijnresultaten, bijvoorbeeld door de pijplijn op het stuurprogramma uit te voeren.
In dit voorbeeld gebruikt u de volgende code:
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)
De aantekeningen opleveren:
[[{'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}]]
Als u dit wilt weergeven als een retourtype, kunt u een array
van struct
de velden gebruiken, waarin de dict
vermeldingen worden weergegeven als de velden van de 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')))
Prestaties afstemmen
Er zijn verschillende belangrijke aspecten voor het afstemmen van de prestaties van de UDF. De eerste is om elke GPU effectief te gebruiken, die u kunt aanpassen door de grootte van batches te wijzigen die door de transformatorpijplijn naar de GPU worden verzonden. De tweede is om ervoor te zorgen dat het DataFrame goed is gepartitioneerd om het hele cluster te gebruiken.
Ten slotte kunt u het Hugging Face-model in de cache opslaan om de laadtijd van het model of de kosten voor inkomend verkeer te besparen.
Een batchgrootte kiezen
Hoewel de hierboven beschreven UDF's out-of-the-box met een batch_size
van 1 moeten werken, kunnen de resources die beschikbaar zijn voor de werknemers mogelijk niet efficiënt worden gebruikt. Om de prestaties te verbeteren, kunt u de batchgrootte afstemmen op het model en de hardware in het cluster. Databricks raadt aan om verschillende batchgrootten voor de pijplijn in uw cluster uit te proberen om de beste prestaties te vinden. Lees meer over pijplijnbatches en andere prestatieopties in de documentatie van Hugging Face.
Probeer een batchgrootte te vinden die groot genoeg is, zodat het het volledige GPU-gebruik aanstuurt, maar er geen fouten optreden CUDA out of memory
. Wanneer u fouten ontvangt CUDA out of memory
tijdens het afstemmen, moet u het notebook loskoppelen en opnieuw koppelen om het geheugen vrij te geven dat wordt gebruikt door het model en de gegevens in de GPU.
Bewaak DE GPU-prestaties door de metrische gegevens van het livecluster voor een cluster weer te geven en een metrische waarde te kiezen, zoals gpu0-util
voor GPU-processorgebruik of gpu0_mem_util
voor GPU-geheugengebruik.
Parallellisme afstemmen met planning op faseniveau
Standaard plant Spark één taak per GPU op elke machine. Als u parallelle uitvoering wilt verhogen, kunt u planning op faseniveau gebruiken om Spark te laten weten hoeveel taken per GPU moeten worden uitgevoerd. Als u bijvoorbeeld wilt dat Spark twee taken per GPU uitvoert, kunt u dit op de volgende manier opgeven:
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)
Gegevens opnieuw partitioneren om alle beschikbare hardware te gebruiken
De tweede overweging voor prestaties is het volledig gebruik van de hardware in uw cluster. Over het algemeen werkt een klein veelvoud van het aantal GPU's op uw werkrollen (voor GPU-clusters) of het aantal kernen voor de werkrollen in uw cluster (voor CPU-clusters). Uw invoerdataframe heeft mogelijk al voldoende partities om te profiteren van de parallelle uitvoering van het cluster. Als u wilt zien hoeveel partities het DataFrame bevat, gebruikt u df.rdd.getNumPartitions()
. U kunt een DataFrame opnieuw partitioneren met behulp van repartitioned_df = df.repartition(desired_partition_count)
.
Cache van het model in DBFS of op koppelpunten
Als u vaak een model laadt vanuit verschillende of opnieuw opgestarte clusters, kunt u het Hugging Face-model ook opslaan in het DBFS-hoofdvolume of op een koppelpunt. Dit kan de kosten voor inkomend verkeer verlagen en de tijd verminderen om het model te laden op een nieuw of opnieuw opgestart cluster. Hiervoor stelt u de TRANSFORMERS_CACHE
omgevingsvariabele in uw code in voordat u de pijplijn laadt.
Voorbeeld:
import os
os.environ['TRANSFORMERS_CACHE'] = '/dbfs/hugging_face_transformers_cache/'
U kunt ook vergelijkbare resultaten bereiken door het model te registreren bij MLflow met de MLflow-smaaktransformers
.
Notebook: Face Transformers deductie en MLflow-logboekregistratie
Om snel aan de slag te gaan met voorbeeldcode, is dit notebook een end-to-end-voorbeeld voor tekstsamenvatting met behulp van pijplijnen voor facetransformaties en MLflow-logboekregistratie.
Notitieblok voor Face Transformers-pijplijnen omhelzen
Aanvullende bronnen
U kunt uw Hugging Face-model verfijnen met de volgende handleidingen:
- Gegevens voorbereiden voor het afstemmen van Hugging Face-modellen
- Hugging Face-modellen verfijnen voor één GPU
Meer informatie over wat zijn Hugging Face Transformers?