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.

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 pipeline
  • Dockerfile utilizzato per creare l’immagine che sarà distribuita su Cloud Run.
  • La cartella Model contenente pytorch_model.bin, config.json e vocab.txt.
    • Modello: DistilBERT base uncased finetuned SST-2
    • Per scaricare la cartella Model, seguire le istruzioni nel pulsante.
    • Non è necessario conservare rust_model.ot o tf_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.