Esecuzione di un'inferenza TensorFlow su larga scala utilizzando GPU TensorRT 5 e NVIDIA T4

Questo tutorial illustra come eseguire un'inferenza su larga scala su GPU NVIDIA TensorRT 5 e T4. NVIDIA TensorRTTM è una piattaforma per inferenza di deep learning ad alte prestazioni. Include un ottimizzatore di inferenza per il deep learning e un runtime che offrono bassa latenza e velocità effettiva elevata per le applicazioni di inferenza deep-learning.

Nel tutorial configurerai un cluster multizona per l'esecuzione di un'inferenza con un gruppo di scalabilità automatica basato sull'utilizzo della GPU.

Panoramica

Questo tutorial fornisce quanto segue:

  • Un'architettura di riferimento per l'implementazione di un sistema di inferenza di machine learning scalabile su Google Cloud, adatto a un ambiente di sviluppo. L'infrastruttura e le esigenze di sicurezza possono variare, perciò puoi regolare di conseguenza le configurazioni descritte in questo tutorial.
  • Un repository GitHub contenente script che utilizzi nel tutorial per installare il modello TensorFlow e altri componenti obbligatori.
  • Istruzioni su come quantificare il modello TensorFlow usando TensorRT, come eseguire il deployment degli script e come eseguire il deployment dell'architettura di riferimento.
  • Istruzioni su come configurare Cloud Load Balancing.

Dopo aver completato questo tutorial, avrai un modello quantizzato in addestramento in Cloud Storage e due gruppi di istanze di Compute Engine Compute Engine in aree geografiche diverse con Cloud Load Balancing per il traffico web. Questa architettura è illustrata nel diagramma seguente.

Architettura utilizzata in questo tutorial

Obiettivi

  • Inizia con un grafico preaddestrato.
  • Ottimizza il modello con TensorRT e scopri quanto è più veloce con le diverse ottimizzazioni.
  • Dopo aver finalizzato il modello, crea un cluster basato sulle VM di Deep Learning di Compute Engine, già installate con TensorFlow, TensorFlow Serving e TensorRT 5 preinstallati.

Costi

Questo tutorial utilizza i seguenti componenti fatturabili di Google Cloud:

  • Compute Engine
  • Persistent Disk
  • Cloud Storage
  • Networking
  • GPU NVIDIA T4

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud possono beneficiare di una prova gratuita.

Prima di iniziare

  1. In Google Cloud Console, vai alla pagina del selettore dei progetti.

    Vai al selettore progetti

  2. Seleziona o crea un progetto Google Cloud.

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Cloud. Scopri come verificare se la fatturazione è abilitata su un progetto.

  4. Abilita le API Compute Engine and Cloud Logging.

    Abilita le API

  5. Assicurati di avere una quota GPU sufficiente per creare VM.

Al termine di questo tutorial, puoi evitare una fatturazione continua eliminando le risorse che hai creato. Per scoprire di più, vedi Pulizia.

Preparazione dell'ambiente

In questa sezione puoi specificare le impostazioni predefinite per i valori utilizzati nel tutorial, ad esempio l'area geografica e la zona. Il tutorial utilizza us-central1 come area geografica predefinita e us-central1-b come zona predefinita.

Crea anche un file con tutte le impostazioni, in modo da poter caricare automaticamente le variabili se devi riaprire Cloud Shell e reinizializzarle.

  1. Apri Cloud Shell:

    APRI Cloud Shell

  2. Imposta la zona e l'area geografica predefinite:

    gcloud compute project-info add-metadata \
        --metadata google-compute-default-region=us-central1,google-compute-default-zone=us-central1-a
    
  3. Reinizializza la shell:

    gcloud init --console-only
    
  4. Premi 1 per le prime tre domande, quindi inserisci l'ID progetto per l'ultima domanda.

Ottimizzare il modello con TensorRT

  1. In Cloud Shell, crea un'istanza che puoi utilizzare per la preparazione del modello:

    export IMAGE_FAMILY="tf-latest-cu100"
    export INSTANCE_NAME="model-prep"
    
    gcloud compute instances create $INSTANCE_NAME \
        --image-family=$IMAGE_FAMILY \
        --machine-type=n1-standard-8 \
        --image-project=deeplearning-platform-release \
        --maintenance-policy=TERMINATE \
        --accelerator="type=nvidia-tesla-t4,count=1" \
        --metadata="install-nvidia-driver=True"
    

    Una GPU è più che sufficiente per confrontare le diverse modalità di ottimizzazione di TensorRT e per farti un'idea della velocità di una singola GPU.

  2. Dopo aver creata l'istanza VM, utilizza ssh per connetterti alla VM.

  3. Nell'istanza, scarica il modello resnetv2 dal repository ufficiale di TensorFlow per testare l'ottimizzazione di TensorRT:

    wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb
    

TensorRT può accelerare l'inferenza, ma un ulteriore miglioramento proviene dalla quantizzazione. La quantificazione dei modelli lineari converte le ponderazioni e le attivazioni da punti in virgola mobile in numeri interi. Ad esempio, se le ponderazioni iniziali del modello sono FP32 (rappresentazione in virgola mobile a 32 bit), riducendo la precisione puoi utilizzare INT8. Ma la quantizzazione non è gratuita: riducendo la rappresentazione dello spazio di archiviazione puoi ridurre al minimo l'accuratezza del modello. Tuttavia, il passaggio da FP32 a FP16 è praticamente gratuito.

Come fare a trovare il giusto compromesso tra velocità (peso dei pesi) e precisione? Esiste un codice che permette di farlo. Questo codice può misurare la precisione rispetto alla velocità e ad altre metriche. Il test è limitato ai modelli di riconoscimento delle immagini, ma non è difficile implementare un test personalizzato basato su questo codice.

  1. In Cloud Shell, scarica e implementa un test personalizzato:

    git clone https://github.com/tensorflow/models.git
    cd models
    git checkout f0e10716160cd048618ccdd4b6e18336223a172f
    touch research/__init__.py
    touch research/tensorrt/__init__.py
    cp research/tensorrt/labellist.json .
    cp research/tensorrt/image.jpg .
    
  2. Prepara il test per l'esecuzione:

    python -m research.tensorrt.tensorrt \
        --frozen_graph=$HOME/resnetv2_imagenet_frozen_graph.pb \
        --image_file=$HOME/models/image.jpg \
        --native --fp32 --fp16 --int8 \
        --output_dir=$HOME
    

    Il test richiede un grafico bloccato (il modello resnetv2 che hai scaricato in precedenza) e argomenti per le diverse modalità di quantizzazione che vuoi verificare. Il completamento di questo comando richiede del tempo.

    Al termine dell'esecuzione, l'output risultante è un confronto del risultato dell'inferenza per una versione diversa del grafico:

    confrontando il risultato di inferenza per un'altra versione del grafico

    I risultati di FP32 e FP16 sono identici e mostrano la stessa precisione. Ciò significa che, se stai bene con TensorRT, puoi iniziare subito a utilizzare FP16. Al contrario, INT8 mostra risultati leggermente meno precisi.

  3. Mostra i numeri di precisione:

    cat $HOME/log.txt
    

    Questo comando genera il seguente output:

    inferenza su log di scalabilità

TensorRT 5 mostra i seguenti risultati, tutti confrontati con quelli nativi:

  • Per FP32, la velocità effettiva è migliorata di circa il 34%, da 319,1 fps rispetto a 428,2 fps.
  • Per FP16, la velocità effettiva è migliorata di circa il 207%, da 319,1 fps a 979,6 fps.
  • Per INT8, la velocità effettiva è migliorata di circa il 376%, da 319,1 fps a 1519,5 fps.

Cosa puoi imparare da questi risultati:

  • Il passaggio dagli annunci nativi a TensorRT incide sull'incertezza. Tuttavia, se per te va bene a prezzo ridotto, probabilmente puoi andare direttamente al FP16.
  • INT8 è molto veloce, ma il prezzo è notevolmente più alto.

La sezione successiva utilizza il modello INT8.

Conversione di un modello personalizzato in TensorRT

Per convertire un modello in un grafico TensorRT, è necessario un modello salvato.

  1. In Cloud Shell, scarica il seguente modello di salvataggio preaddestrato:

    wget http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NCHW.tar.gz
    tar -xzvf resnet_v2_fp32_savedmodel_NCHW.tar.gz
    
  2. Crea uno script Python che converte il modello bloccato in un grafico TensorRT:

    cat <<EOF > convert_to_rt.py
    import tensorflow.contrib.tensorrt as trt
    import argparse
    
    parser = argparse.ArgumentParser(description="Converts TF SavedModel to the TensorRT enabled graph.")
    
    parser.add_argument("--input_model_dir", required=True)
    parser.add_argument("--output_model_dir", required=True)
    parser.add_argument("--batch_size", type=int, required=True)
    parser.add_argument("--precision_mode", choices=["FP32", "FP16", "INT8"], required=True)
    
    args = parser.parse_args()
    
    trt.create_inference_graph(
        None, None, max_batch_size=args.batch_size,
        input_saved_model_dir=args.input_model_dir,
        output_saved_model_dir=args.output_model_dir,
        precision_mode=args.precision_mode)
    EOF
    
  3. Converti il modello nel grafico TensorRT:

    python ./convert_to_rt.py \
        --input_model_dir=$HOME/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
        --output_model_dir=$HOME/resnet_v2_int8_NCHW/00001 \
        --batch_size=128 \
        --precision_mode="INT8"
    

    Ora hai un modello INT8 nella cartella $HOME/resnet_v2_int8_NCHW/00001.

  4. Esegui un'inferenza per assicurarti che tutto funzioni:

    tensorflow_model_server --model_base_path=$HOME/resnet_v2_int8_NCHW/ --rest_api_port=8888
    
  5. Per verificare che funzioni, invia il seguente input di esempio:

    curl -X POST localhost:8888/v1/models/default:predict -d '{"instances": [[[[1,1,1]]]]}'
    
  6. Se visualizzi risultati di questo comando curl, esci dall'esecuzione di inferenza premendo Ctrl+C.

  7. Per utilizzare il modello ottimizzato dal cluster, caricalo in Cloud Storage, sostituendo [GCS_PATH] con il nome del bucket di Cloud Storage:

    tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
    export GCS_PATH=[GCS_PATH]
    gsutil cp model.tar.gz $GCS_PATH
    

    La prossima volta che vuoi utilizzare questo modello, non dovrai ripetere l'intera procedura. In alternativa, puoi utilizzare il grafico bloccato INT8 che si trova nel bucket Cloud Storage:

    gs://solutions-public-assets/tensorrt-t4-gpu/model.tar.gz
    

Configurazione di un cluster

Ora che hai un modello in Cloud Storage, puoi creare un cluster. Il primo passaggio consiste nel creare un modello di VM. Il cluster utilizza il modello di VM per creare nuove istanze.

  1. In Cloud Shell, scarica il codice necessario per configurare un cluster:

    git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git
    
  2. Crea il modello VM, sostituendo [PROJECT_NAME] con il nome del progetto:

    export PROJECT_NAME=[PROJECT_NAME]
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-latest-cu100"
    
    gcloud beta compute --project=$PROJECT_NAME instance-templates create $INSTANCE_TEMPLATE_NAME \
        --machine-type=n1-standard-16 \
        --maintenance-policy=TERMINATE \
        --accelerator=type=nvidia-tesla-t4,count=4 \
        --min-cpu-platform=Intel\ Skylake \
        --tags=http-server,https-server \
        --image-family=$IMAGE_FAMILY \
        --image-project=deeplearning-platform-release \
        --boot-disk-size=100GB \
        --boot-disk-type=pd-ssd \
        --boot-disk-device-name=$INSTANCE_TEMPLATE_NAME \
        --metadata startup-script-url=gs://solutions-public-assets/tensorrt-t4-gpu/start_agent_and_inf_server.sh
    

    Il parametro metadata specifica uno script di avvio installato su ogni istanza creata dal modello VM. Lo script di avvio esegue le seguenti procedure all'avvio dell'istanza VM:

    • Installa i driver NVIDIA.
    • Installa un agente di monitoraggio per monitorare l'utilizzo della GPU.
    • Scarica il modello.
    • Avvia il servizio di inferenza.

    Quando il modello è pronto, puoi creare il gruppo di istanze gestite. Il gruppo non sarà un gruppo di scalabilità e non ci sarà un controllo di integrità. Stai creando un gruppo che ti garantisce una sola volta che saranno presenti 2 istanze in esecuzione in zone specifiche.

  3. Crea il gruppo di istanze gestite:

    gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \
        --template $INSTANCE_TEMPLATE_NAME \
        --base-instance-name deeplearning-instances \
        --size 2 \
        --zones us-central1-a,us-central1-b
    

    Il valore INSTANCE_TEMPLATE_NAME è il nome dell'istanza che hai impostato in un passaggio precedente. Scegli le zone in base alla disponibilità di GPU (non tutte le GPU sono disponibili in tutte le zone) e in base alle tue quote.

    La creazione del gruppo richiede del tempo.

  4. Verifica l'avanzamento eseguendo questo comando:

    gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1
    

    L'output ha il seguente aspetto:

    durante la creazione del gruppo

    Una volta completata la creazione, verrà visualizzato un messaggio di questo tipo:

    dopo la creazione del gruppo

  5. Apri la pagina Monitoring nella console.

    Vai alla pagina Monitoring

  6. Assicurati di essere nell'area di lavoro del progetto corretta, che viene visualizzata nell'angolo in alto a sinistra. Se visiti questa pagina per la prima volta, devi creare una nuova area di lavoro.

  7. Nella pagina Metrics Explorer, per Tipo di risorsa, seleziona GCE VM Instance, mentre per Metriche, seleziona custom/gpu_utilization:

    Pagina Metrics Explorer

    Se i dati vengono ricevuti, vedrai quanto segue:

    Grafico delle metriche con zero utilizzi

  8. In Cloud Shell, attiva la scalabilità automatica per il tuo gruppo:

    gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \
        --custom-metric-utilization metric=custom.googleapis.com/gpu_utilization,utilization-target-type=GAUGE,utilization-target=85 \
        --max-num-replicas 4 \
        --cool-down-period 360 \
        --region us-central1
    

    La parte importante qui è il percorso di utilizzo, custom.googleapis.com/gpu_utilization, che è il percorso completo della tua metrica. Inoltre, poiché hai specificato un livello di destinazione 85, ogni volta che l'utilizzo della GPU raggiunge 85, viene creata una nuova istanza nel gruppo.

Test della scalabilità automatica

Per testare la scalabilità automatica, che hai impostato nella sezione precedente, devi:

  • Utilizza SSH per connetterti a una delle istanze di GPU di deep learning.
  • Carica tutte le GPU al 100%.
  • Osserva la scalabilità del gruppo di scalabilità automatica creando un'altra istanza.

  1. Connettiti all'istanza tramite ssh.
  2. Carica la GPU al 100% per 600 secondi:

    git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git
    cd tensorflow-inference-tensorrt5-t4-gpu
    git submodule update --init --recursive
    cd third_party/gpu-burn
    make
    ./gpu_burn 600 > /dev/null &
    

    Nella console, osserva l'attività nella pagina Metrics Explorer:

    picco di attività nella pagina Metrics Explorer

  3. Crea la seconda istanza.

  4. Vai alla pagina GCE Compute > Instance Groups > Monitoring e osserva l'attività:

    picco di attività superiore nel monitoraggio

    A questo punto, il gestore della scalabilità automatica sta tentando di avviare il maggior numero possibile di istanze per ridurre il carico (senza fortuna). Ed è ciò che sta succedendo:

    l&#39;avvio di molte istanze

  5. Interrompi la rotazione delle istanze e guarda come l'attività si riduce.

Dai un'occhiata a cosa possiedi:

  • Un modello addestrato, ottimizzato con TensorRT 5 (INT8)
  • Un gruppo gestito di istanze di deep learning
  • Scalabilità automatica basata sull'utilizzo della GPU

Creazione di un Elastic Load Balancer (ELB)

Il passaggio finale consiste nel creare un bilanciatore del carico davanti alle istanze.

  1. In Cloud Shell, crea controlli di integrità per determinare se un determinato host sul tuo backend può gestire il traffico:

    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
        --request-path /v1/models/default \
        --port 8888
    
  2. Configura le porte denominate del gruppo di istanze in modo che il bilanciatore del carico possa inoltrare le richieste di inferenza tramite la porta 80 al servizio di inferenza gestito tramite la porta 8888:

    gcloud compute instance-groups set-named-ports $INSTANCE_GROUP_NAME \
        --named-ports http:8888 \
        --region us-central1
    
  3. Crea un servizio di backend:

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    
    gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
        --protocol HTTP \
        --health-checks $HEALTH_CHECK_NAME \
        --global
    

    In effetti, un servizio di backend è un gruppo di istanze con controllo di integrità.

  4. Aggiungi il tuo gruppo di istanze al nuovo servizio di backend:

    gcloud compute backend-services add-backend $WEB_BACKED_SERVICE_NAME \
        --balancing-mode UTILIZATION \
        --max-utilization 0.8 \
        --capacity-scaler 1 \
        --instance-group $INSTANCE_GROUP_NAME \
        --instance-group-region us-central1 \
        --global
    
  5. Comunica al bilanciatore del carico quale URL inoltrare al servizio di backend:

    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
        --default-service $WEB_BACKED_SERVICE_NAME
    
  6. Crea il bilanciatore del carico:

    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
        --url-map $WEB_MAP_NAME
    
  7. Crea un indirizzo IP esterno per il bilanciatore del carico:

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
        --ip-version=IPV4 \
        --global
    
  8. Verifica che l'indirizzo IP sia stato allocato:

    gcloud compute addresses list
    
  9. Rivedi la regola di forwarding utilizzata da Google Cloud per inoltrare tutte le richieste dall'IP pubblico al bilanciatore del carico:

    export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}')
    export FORWARDING_RULE="lb-fwd-rule"
    
    gcloud compute forwarding-rules create $FORWARDING_RULE \
        --address $IP \
        --global \
        --target-http-proxy $LB_NAME \
        --ports 80
    

    Dopo aver creato le regole di forwarding globali, la propagazione della configurazione può richiedere diversi minuti.

  10. Per connetterti a istanze esterne, abilita il firewall sul progetto:

    gcloud compute firewall-rules create www-firewall-80 \
        --target-tags http-server --allow tcp:80
    
    gcloud compute firewall-rules create www-firewall-8888 \
        --target-tags http-server --allow tcp:8888
    
  11. Converti l'immagine in un formato che può essere inviato al server:

    cat <<EOF > load_and_convert_image.py
    from PIL import Image
    import numpy as np
    import json
    import codecs
    
    img = Image.open("image.jpg").resize((240, 240))
    img_array=np.array(img)
    result = {
        "instances":[img_array.tolist()]
    }
    file_path="/tmp/out.json"
    print(json.dump(result, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4))
    EOF
    
  12. Esegui un'inferenza:

    wget https://pixnio.com/free-images/2017/10/31/2017-10-31-10-43-58-1032x825.jpg -O image.jpg
    python load_and_convert_image.py
    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json
    

    Se l'inferenza funziona correttamente, il risultato è simile al seguente:

    Risultato riuscito di eseguire un&#39;inferenza

Esegui la pulizia

Al termine del tutorial, puoi riorganizzare le risorse che hai creato in modo che non utilizzino più la quota e vengano addebitati costi. Le seguenti sezioni descrivono come eliminare o disattivare queste risorse.

  1. Nella console, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto da eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Passaggi successivi