Il mio viaggio verso una pipeline di trasformatori senza server su Google Cloud
'Viaggio verso pipeline trasformatori senza server su Google Cloud'
Un post di blog di un membro della community di nome Maxence Dominici
Questo articolo parlerà del mio percorso per implementare la pipeline di analisi del sentiment con i transformers
su Google Cloud. Inizieremo con una breve introduzione ai transformers
e poi passeremo alla parte tecnica dell’implementazione. Infine, riassumeremo questa implementazione e valuteremo ciò che abbiamo raggiunto.
L’obiettivo
Volevo creare un micro-servizio che rilevi automaticamente se una recensione di un cliente lasciata su Discord è positiva o negativa. Ciò mi avrebbe permesso di trattare il commento di conseguenza e migliorare l’esperienza del cliente. Ad esempio, se la recensione fosse stata negativa, avrei potuto creare una funzione che contattasse il cliente, si scusasse per la scarsa qualità del servizio e lo informasse che il nostro team di supporto lo avrebbe contattato il prima possibile per assistere lui/lei e, sperabilmente, risolvere il problema. Dal momento che non prevedo di ricevere più di 2.000 richieste al mese, non ho imposto alcun vincolo sulle prestazioni riguardo al tempo e alla scalabilità.
La libreria Transformers
Ero un po’ confuso all’inizio quando ho scaricato il file .h5. Pensavo che fosse compatibile con tensorflow.keras.models.load_model
, ma non era così. Dopo alcuni minuti di ricerca sono riuscito a capire che il file era un checkpoint dei pesi anziché un modello Keras. Dopo questo, ho provato l’API offerta da Hugging Face e ho letto un po’ di più sulla funzione di pipeline che offrono. Poiché i risultati dell’API e della pipeline erano ottimi, ho deciso che avrei potuto servire il modello tramite la pipeline sul mio server.
Di seguito è riportato l’esempio ufficiale dalla pagina GitHub di Transformers.
- La partnership Amazon SageMaker e Hugging Face
- Comprensione dell’attenzione sparsa a blocchi di BigBird
- Addestramento Distribuito Addestra BART/T5 per la Sintesi utilizzando 🤗 Transformers e Amazon SageMaker
from transformers import pipeline
# Assegna una pipeline per l'analisi del sentiment
classifier = pipeline('sentiment-analysis')
classifier('Siamo molto felici di includere la pipeline nel repository dei transformers.')
[{'label': 'POSITIVE', 'score': 0.9978193640708923}]
Implementazione dei transformers su Google Cloud
Ho scelto GCP perché è l’ambiente cloud che utilizzo nella mia organizzazione personale.
Passo 1 – Ricerca
Sapevo già che potevo utilizzare un servizio API come flask
per servire un modello transformers
. Ho cercato nella documentazione di Google Cloud AI e ho trovato un servizio per ospitare modelli Tensorflow chiamato AI-Platform Prediction. Ho trovato anche App Engine e Cloud Run, ma ero preoccupato per l’utilizzo della memoria per App Engine e non ero molto familiare con Docker.
Passo 2 – Test su AI-Platform Prediction
Dato che il modello non è un modello salvato “puro TensorFlow” ma un checkpoint, e non potevo trasformarlo in un “modello TensorFlow puro”, ho capito che l’esempio in questa pagina non avrebbe funzionato. Da lì ho capito che potevo scrivere del codice personalizzato, che mi avrebbe permesso di caricare la pipeline
anziché gestire il modello, il che sembrava più semplice. Ho anche appreso che potevo definire un’azione di pre-predizione e post-predizione, che potrebbe essere utile in futuro per il pre-elaborazione o post-elaborazione dei dati per le esigenze dei clienti. Ho seguito la guida di Google ma ho incontrato un problema poiché il servizio è ancora in versione beta e non tutto è stabile. Questo problema è descritto qui.
Passo 3 – Test su App Engine
Sono passato ad App Engine di Google poiché è un servizio con cui sono familiare, ma ho incontrato un problema di installazione con TensorFlow a causa di un file di dipendenza di sistema mancante. Ho quindi provato con PyTorch che ha funzionato con un’istanza F4_1G, ma non poteva gestire più di 2 richieste sulla stessa istanza, il che non è molto performante.
Passo 4 – Test su Cloud Run
Infine, sono passato a Cloud Run con un’immagine docker. Ho seguito questa guida per avere un’idea di come funziona. In Cloud Run, ho potuto configurare una memoria più elevata e più vCPU per effettuare la predizione con PyTorch. Ho abbandonato TensorFlow poiché PyTorch sembra caricare il modello più velocemente.
Implementazione della pipeline serverless
La soluzione finale è composta da quattro componenti diverse:
main.py
gestisce la richiesta alla pipelineDockerfile
utilizzato per creare l’immagine che sarà distribuita su Cloud Run.- La cartella Model contenente
pytorch_model.bin
,config.json
evocab.txt
.- Modello: DistilBERT base uncased finetuned SST-2
- Per scaricare la cartella Model, seguire le istruzioni nel pulsante.
- Non è necessario conservare
rust_model.ot
otf_model.h5
poiché utilizzeremo PyTorch.
requirement.txt
per l’installazione delle dipendenze
Il contenuto del file main.py
è molto semplice. L’idea è ricevere una richiesta GET
contenente due campi. Prima la recensione che deve essere analizzata, secondo la chiave API per “proteggere” il servizio. Il secondo parametro è opzionale, l’ho utilizzato per evitare di configurare l’oAuth2 di Cloud Run. Dopo aver fornito questi argomenti, carichiamo la pipeline che è costruita basandosi sul modello distilbert-base-uncased-finetuned-sst-2-english
(fornito sopra). Alla fine, viene restituito al cliente la migliore corrispondenza.
import os
from flask import Flask, jsonify, request
from transformers import pipeline
app = Flask(__name__)
model_path = "./model"
@app.route('/')
def classify_review():
review = request.args.get('review')
api_key = request.args.get('api_key')
if review is None or api_key != "MyCustomerApiKey":
return jsonify(code=403, message="richiesta non valida")
classify = pipeline("sentiment-analysis", model=model_path, tokenizer=model_path)
return classify("that was great")[0]
if __name__ == '__main__':
# Questo viene utilizzato solo durante l'esecuzione in locale. Durante il
# deployment su Google Cloud Run, un processo di webserver come Gunicorn servirà l'app.
app.run(debug=False, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
Ecco il Dockerfile
che verrà utilizzato per creare un’immagine Docker del servizio. Specifichiamo che il nostro servizio funziona con python:3.7 e che è necessario installare le nostre dipendenze. Poi utilizziamo gunicorn
per gestire il nostro processo sulla porta 5000
.
# Usa Python37
FROM python:3.7
# Consente la visualizzazione immediata di dichiarazioni e messaggi di log nei log di Knative
ENV PYTHONUNBUFFERED True
# Copia requirements.txt nell'immagine Docker e installa i pacchetti
COPY requirements.txt /
RUN pip install -r requirements.txt
# Imposta il WORKDIR sulla cartella
COPY . /app
# Espone la porta 5000
EXPOSE 5000
ENV PORT 5000
WORKDIR /app
# Utilizza gunicorn come punto di ingresso
CMD exec gunicorn --bind :$PORT main:app --workers 1 --threads 1 --timeout 0
È importante notare gli argomenti --workers 1 --threads 1
che significano che voglio eseguire la mia app su un solo worker (= 1 processo) con un singolo thread. Questo perché non voglio avere 2 istanze attive contemporaneamente perché potrebbe aumentare la fatturazione. Uno degli svantaggi è che ci vorrà più tempo per elaborare se il servizio riceve due richieste contemporaneamente. Dopo di ciò, ho impostato il limite a un solo thread a causa dell’utilizzo di memoria necessario per caricare il modello nella pipeline. Se utilizzassi 4 thread, potrei avere solo 4 Gb / 4 = 1 Gb per eseguire l’intero processo, il che non è sufficiente e porterebbe a un errore di memoria.
Infine, il file requirement.txt
Flask==1.1.2
torch===1.7.1
transformers~=4.2.0
gunicorn>=20.0.0
Istruzioni per il deployment
Prima di tutto, sarà necessario soddisfare alcuni requisiti come avere un progetto su Google Cloud, abilitare la fatturazione e installare il gcloud
cli. Puoi trovare ulteriori dettagli al riguardo nella guida di Google – Prima di iniziare,
In secondo luogo, dobbiamo costruire l’immagine docker e distribuirla su Cloud Run selezionando il progetto corretto (sostituisci ID-PROGETTO
) e impostando il nome dell’istanza come ai-customer-review
. Puoi trovare ulteriori informazioni sulla distribuzione nella guida di Google – Distribuzione su .
gcloud builds submit --tag gcr.io/ID-PROGETTO/ai-customer-review
gcloud run deploy --image gcr.io/ID-PROGETTO/ai-customer-review --platform managed
Dopo alcuni minuti, sarà necessario anche aumentare la memoria allocata per l’istanza di Cloud Run da 256 MB a 4 Gb. Per farlo, vai alla Console di Cloud Run del tuo progetto.
Dovresti trovare l’istanza, fai clic su di essa.
Dopo di che avrai un pulsante blu con etichetta “modifica e distribuisci nuova revisione” in cima allo schermo, fai clic su di esso e ti verranno richiesti molti campi di configurazione. In fondo dovresti trovare una sezione “Capacità” dove puoi specificare la memoria.
Prestazioni
Gestire una richiesta richiede meno di cinque secondi dal momento in cui invii la richiesta, inclusi il caricamento del modello nel pipeline e la previsione. L’avvio a freddo potrebbe richiedere altri 10 secondi circa.
Possiamo migliorare le prestazioni di gestione delle richieste riscaldando il modello, cioè caricandolo all’avvio anziché ad ogni richiesta (ad esempio, variabile globale), in questo modo guadagniamo tempo e utilizzo della memoria.
Costi
Ho simulato il costo in base alla configurazione dell’istanza Cloud Run con il simulatore di prezzi di Google
Per il mio micro-servizio, ho pianificato di avere circa 1.000 richieste al mese, in modo ottimistico. 500 potrebbero essere più probabili per il mio utilizzo. Ecco perché ho considerato 2.000 richieste come limite superiore durante la progettazione del mio microservizio. A causa di questo basso numero di richieste, non mi sono preoccupato molto per la scalabilità, ma potrei tornarci se la mia fatturazione aumenta.
Tuttavia, è importante sottolineare che pagherai lo storage per ogni gigabyte dell’immagine di build. È approssimativamente €0,10 per Gb al mese, il che va bene se non conservi tutte le tue versioni sul cloud dal momento che la mia versione è leggermente superiore a 1 Gb (Pytorch per 700 Mb e il modello per 250 Mb).
Conclusione
Utilizzando il pipeline di analisi del sentiment di Transformers, ho risparmiato una quantità non trascurabile di tempo. Invece di addestrare/ottimizzare un modello, ho potuto trovare uno già pronto per essere utilizzato in produzione e avviare la distribuzione nel mio sistema. Potrei ottimizzarlo ulteriormente in futuro, ma come mostrato nei miei test, l’accuratezza è già incredibile! Mi sarebbe piaciuto avere un modello “puro TensorFlow”, o almeno un modo per caricarlo in TensorFlow senza dipendenze da Transformers per utilizzare la piattaforma AI. Sarebbe anche bello avere una versione leggera.