Misurazione e ottimizzazione delle prestazioni di un sistema di inferenza TensorFlow utilizzando Triton Inference Server e Tesla T4

Questo tutorial mostra come misurare le prestazioni del sistema di inferenza TensorFlow creato nella parte 2 di questa serie e come applicare l'ottimizzazione dei parametri per migliorare la velocità effettiva del sistema. Il tutorial non è pensato per fornire i dati sulle prestazioni di un determinato sistema. ma offre indicazioni generali sulla procedura di misurazione del rendimento.

Il numero concreto delle metriche relative alle prestazioni come "Richieste totali al secondo" (RPS) e "Tempo di risposta" variano a seconda del modello addestrato, delle versioni del software e delle configurazioni hardware.

Obiettivi

  • Definisci l'obiettivo di rendimento e le metriche.
  • Misura il rendimento di riferimento.
  • Esegui l'ottimizzazione del grafico.
  • Misura la conversione FP16.
  • Misurare la quantizzazione INT8.
  • Modifica il numero di istanze.

Costi

Oltre a utilizzare la GPU NVIDIA T4, questo tutorial utilizza i seguenti componenti fatturabili di Google Cloud:

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

Prima di iniziare

Prima di iniziare questo tutorial, devi terminare la creazione del sistema di inferenza seguendo la parte 2 di questa serie. Puoi utilizzare le seguenti interfacce per eseguire il tutorial:

Nel terminale SSH, imposta la directory corrente sulla sottodirectory client:

cd $HOME/gke-tensorflow-inference-system-tutorial/client

In questo tutorial, esegui tutti i comandi di questa directory.

Definizione dell'obiettivo di rendimento

Quando misuri le prestazioni dei sistemi di inferenza, devi definire l'obiettivo di rendimento e le metriche di prestazioni appropriate in base al caso d'uso del sistema. Per semplicità, questo tutorial presuppone i seguenti obiettivi di rendimento:

  • Il 95% delle richieste riceve risposte entro 100 ms
  • La velocità effettiva totale (richieste al secondo) migliora senza superare l'obiettivo precedente.

Utilizzando queste ipotesi, misuri la velocità effettiva dei seguenti modelli ResNet-50 con ottimizzazioni diverse. Quando un client invia richieste di inferenza, specifica il modello utilizzando il nome del modello in questa tabella. Applichi anche l'ottimizzazione dei parametri per migliorare la velocità effettiva del modello.

Nome modello Ottimizzazione
original Modello originale (nessuna ottimizzazione con TF-TRT)
tftrt_fp32 Ottimizzazione del grafico
(dimensione del batch: 64, gruppi di istanze: 1)
tftrt_fp16 Conversione in FP16 oltre all'ottimizzazione del grafico
(dimensione del batch: 64, gruppi di istanze: 1)
tftrt_int8 Quantizzazione con INT8 oltre all'ottimizzazione del grafico
(dimensione del batch: 64, gruppi di istanze: 1)
tftrt_int8_bs16_count4 Quantizzazione con INT8 oltre all'ottimizzazione del grafico
(dimensione del batch: 16, gruppi di istanze: 4)

Misurazione del rendimento di riferimento

Inizi utilizzando TF-TRT come base per misurare le prestazioni del modello originale non ottimizzato. Confrontate le prestazioni di altri modelli con quelle dell'originale per valutare quantitativamente il miglioramento delle prestazioni. Quando hai eseguito il deployment di Locust, era già configurato per inviare richieste per il modello originale.

  1. Apri la console di Locust e verifica che il numero di client (denominati slave) sia 10. Se il numero è inferiore a 10, significa che i client sono ancora in fase di avvio. In questo caso, attendi qualche minuto finché non diventa 10.
  2. Imposta Numero di utenti da simulare su 3000 e Frequenza di trattamento su 5.
  3. Aumenta il numero di utilizzi simulati di 5 al secondo fino a raggiungere 3000 clic facendo clic su Avvia scia.

    Avvio di un nuovo sciame di locuste.

  4. Fai clic su Grafici per visualizzare i seguenti grafici.

    Avvio di un nuovo sciame di locuste.

    Osserva che mentre il valore Richieste totali al secondo aumenta in modo lineare, il valore Tempi di risposta (ms) aumenta di conseguenza.

  5. Quando il 95% percentile dei tempi di risposta supera i 100 ms, fai clic su Interrompi per interrompere la simulazione. Se sposti il puntatore del mouse sul grafico, puoi controllare il numero di richieste al secondo corrispondenti a quando il valore di 95% percentile dei tempi di risposta ha superato 100 ms.

    Nello screenshot seguente, il numero di richieste al secondo è 253,1.

    Grafico che mostra 253,1 richieste al secondo.

    Ti consigliamo di ripetere questa misurazione più volte e di prendere una media per tenere conto della fluttuazione.

  6. Riavvia Locust:

    kubectl delete -f deployment_master.yaml -n locust
    kubectl delete -f deployment_slave.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    kubectl apply -f deployment_slave.yaml -n locust
    
  7. Torna al passaggio 1 per ripetere la misurazione.

Ottimizzazione dei grafici

In questa sezione misurerai le prestazioni del modello tftrt_fp32 ottimizzato utilizzando TF-TRT per l'ottimizzazione del grafico. Si tratta di un'ottimizzazione comune compatibile con la maggior parte delle schede GPU NVIDIA.

  1. Riavvia lo strumento di test del carico. Utilizza la risorsa configmap per specificare il modello come tftrt_fp32.

    kubectl delete configmap locust-config -n locust
    kubectl create configmap locust-config \
        --from-literal model=tftrt_fp32 \
        --from-literal saddr=${TRITON_IP} \
        --from-literal rps=10 -n locust
    kubectl delete -f deployment_master.yaml -n locust
    kubectl delete -f deployment_slave.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    kubectl apply -f deployment_slave.yaml -n locust
    
  2. Riavvia il server di Triton:

    kubectl scale deployment/inference-server --replicas=0
    kubectl scale deployment/inference-server --replicas=1
    

    Attendi qualche minuto finché i processi del server non saranno pronti.

  3. Ripeti la misurazione del rendimento effettuata nella sezione precedente.

    Negli screenshot seguenti, il numero di richieste al secondo è 381.

    Grafico che mostra il tempo di risposta con richieste al secondo di 381.

    Grafico che mostra 381 richieste al secondo.

    Queste immagini mostrano il miglioramento delle prestazioni dell'ottimizzazione del grafico TF-TRT.

Conversione in FP16

In questa sezione misurerai il rendimento del modello tftrt_fp16 ottimizzato con TF-TRT per l'ottimizzazione del grafico e la conversione FP16. Questa è un'ottimizzazione disponibile per NVIDIA Tesla T4.

  1. Riavvia lo strumento di test del carico. Utilizza la risorsa configmap per specificare il modello come tftrt_fp16.

    kubectl delete configmap locust-config -n locust
    kubectl create configmap locust-config \
        --from-literal model=tftrt_fp16 \
        --from-literal saddr=${TRITON_IP} \
        --from-literal rps=10 -n locust
    kubectl delete -f deployment_master.yaml -n locust
    kubectl delete -f deployment_slave.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    kubectl apply -f deployment_slave.yaml -n locust
    
  2. Riavvia il server di Triton:

    kubectl scale deployment/inference-server --replicas=0
    kubectl scale deployment/inference-server --replicas=1
    

    Attendi qualche minuto finché i processi del server non saranno pronti.

  3. Ripeti la misurazione del rendimento effettuata nella sezione precedente. Nell'esempio seguente, il numero di richieste al secondo è 1072,5.

    Grafico che mostra il tempo di risposta con 1072,5 richieste al secondo.

    Grafico che mostra 1072,5 richieste al secondo.

    Queste immagini mostrano il miglioramento del rendimento della conversione FP16 in aggiunta all'ottimizzazione del grafico TF-TRT.

Quantificazione con INT8

In questa sezione misurerai le prestazioni del modello tftrt_int8 ottimizzato con TF-TRT per l'ottimizzazione del grafico e la quantificazione di INT8. Questa ottimizzazione è disponibile per NVIDIA Tesla T4.

  1. Riavvia lo strumento di test del carico. Utilizza la risorsa configmap per specificare il modello come tftrt_int8.

    kubectl delete configmap locust-config -n locust
    kubectl create configmap locust-config \
        --from-literal model=tftrt_int8 \
        --from-literal saddr=${TRITON_IP} \
        --from-literal rps=10 -n locust
    kubectl delete -f deployment_master.yaml -n locust
    kubectl delete -f deployment_slave.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    kubectl apply -f deployment_slave.yaml -n locust
    
  2. Riavvia il server di Triton:

    kubectl scale deployment/inference-server --replicas=0
    kubectl scale deployment/inference-server --replicas=1
    

    Attendi qualche minuto finché i processi del server non saranno pronti.

  3. Ripeti la misurazione del rendimento effettuata nella sezione precedente.

    Nei seguenti screenshot, il numero di richieste al secondo è 1085,4.

    Grafico che mostra il tempo di risposta con 1085,4 richieste al secondo.

    Grafico che mostra 1085,4 richieste al secondo.

    Questo risultato è quasi lo stesso della conversione FP16. Non hai il vantaggio di utilizzare la quantificazione di INT8. In teoria, NVIDIA Tesla T4 GPU è in grado di gestire modelli di quantificazione INT8 più rapidamente dei modelli di conversione FP16. In questo caso, potrebbe esserci un collo di bottiglia diverso dalle prestazioni della GPU. Puoi confermarlo dai seguenti dati sull'utilizzo della GPU nella dashboard di Grafana. Tieni presente che l'utilizzo è inferiore al 40%, il che significa che il modello non può utilizzare completamente le prestazioni della GPU.

    Grafico che mostra un utilizzo della GPU inferiore al 40%.

    Come mostra la sezione successiva, potresti ridurre questo collo di bottiglia aumentando il numero di gruppi di istanze. Ad esempio, aumenta il numero di gruppi di istanze da 1 a 4 e diminuisci le dimensioni del batch da 64 a 16. Questo approccio mantiene il numero totale di richieste elaborate su una singola GPU a 64.

Modifica del numero di istanze

In questa sezione misurerai le prestazioni del modello tftrt_int8_bs16_count4. Questo modello ha la stessa struttura di tftrt_int8, ma modifica le dimensioni del batch e il numero di gruppi di istanze come descritto alla fine della sezione precedente.

  1. Riavvia Locust. Utilizza la risorsa configmap per specificare il modello come tftrt_int8_bs16_count4. Allo stesso tempo, aumenta il numero di pod client Locust per generare carichi di lavoro sufficienti a misurare la limitazione delle prestazioni del modello.

    kubectl delete configmap locust-config -n locust
    kubectl create configmap locust-config \
        --from-literal model=tftrt_int8_bs16_count4 \
        --from-literal saddr=${TRITON_IP} \
        --from-literal rps=10 -n locust
    kubectl delete -f deployment_master.yaml -n locust
    kubectl delete -f deployment_slave.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    kubectl apply -f deployment_slave.yaml -n locust
    kubectl scale deployment/locust-slave --replicas=20 -n locust
    
  2. Riavvia il server di Triton:

    kubectl scale deployment/inference-server --replicas=0
    kubectl scale deployment/inference-server --replicas=1
    

    Attendi qualche minuto finché i processi del server non saranno pronti.

  3. Ripeti la misurazione del rendimento effettuata nella sezione precedente. In questo caso, imposta l'opzione Percentuale di accesso su 15 perché il raggiungimento del limite di rendimento richiede molto tempo se imposti l'opzione Percentuale di Hatch su 5. Nell'esempio seguente, il numero di richieste al secondo è 2236,6.

    Grafico che mostra il tempo di risposta con 2236,6 richieste al secondo.

    Grafico che mostra 2236,6 richieste al secondo.

    Modificando il numero di istanze, quasi il doppio delle richieste al secondo. Nota che l'utilizzo della GPU ha raggiunto circa il 75% nella dashboard di Grafana.

    Grafico che mostra un utilizzo della GPU del 75%.

Scalabilità con più nodi

Quando esegui la scalabilità con più nodi, misuri le prestazioni di un singolo pod. Dato che i processi di inferenza vengono eseguiti in modo indipendente su pod diversi, su scala condivisa, si può supporre che la velocità effettiva totale venga scalata in modo lineare in base al numero di pod. Questa supposizione si applica purché non siano presenti colli di bottiglia, come la larghezza di banda di rete tra i client e i server di inferenza.

Tuttavia, è importante comprendere come vengono bilanciate le richieste di inferenza tra più server di inferenza. Triton utilizza il protocollo gRPC per stabilire una connessione TCP tra un client e un server. Poiché Triton riutilizza la connessione stabilita per l'invio di più richieste di inferenza, le richieste di un singolo client vengono sempre inviate allo stesso server. Per distribuire le richieste per più server, devi utilizzare più client.

Esegui la pulizia

Elimina il progetto

  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