Mide y ajusta el rendimiento de un sistema de inferencia de TensorFlow con Triton Inference Server y Tesla T4

En este instructivo, se muestra cómo medir el rendimiento del sistema de inferencia de TensorFlow que creaste en la parte 2 de esta serie y aplicar el ajuste de parámetros para mejorar la capacidad de procesamiento del sistema. El instructivo no está diseñado para proporcionar los datos de rendimiento de un sistema en particular. En cambio, ofrece orientación general sobre el proceso de medición del rendimiento.

La cantidad concreta de métricas de rendimiento, como “Total de solicitudes por segundo (RPS)” y “Tiempo de respuesta”, difieren según el modelo entrenado, las versiones de software y las configuraciones de hardware.

Objetivos

  • Definir el objetivo de rendimiento y las métricas
  • Medir el rendimiento de referencia
  • Realizar la optimización del gráfico
  • Medir la conversión de FP16
  • Medir la cuantización INT8
  • Ajustar la cantidad de instancias

Costos

Además de usar la GPU de NVIDIA T4, en este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Cuando finalices este instructivo, podrás borrar los recursos creados para evitar que se te siga facturando. Para obtener más información, consulta cómo hacer una limpieza.

Antes de comenzar

Antes de comenzar con este instructivo, debes terminar de compilar el sistema de inferencia según las instrucciones de la parte 2 de esta serie. Usa las siguientes interfaces para seguir este instructivo:

En la terminal SSH, establece el directorio actual como el subdirectorio client:

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

En este instructivo, ejecutarás todos los comandos desde ese directorio.

Define el objetivo de rendimiento

Cuando mides el rendimiento de los sistemas de inferencia, debes definir el objetivo de rendimiento y las métricas de rendimiento apropiadas según el caso de uso del sistema. Para que sea más simple, en este instructivo se suponen los siguientes objetivos de rendimiento:

  • El 95% de las solicitudes recibe respuestas en 100 ms.
  • La capacidad de procesamiento total (solicitudes por segundo) mejora sin afectar el objetivo anterior.

Con estas suposiciones, deberás medir la capacidad de procesamiento de los siguientes modelos ResNet-50 con diferentes optimizaciones. Cuando un cliente envía solicitudes de inferencia, especifica el modelo con uno de los nombres de modelo en esta tabla. También aplica el ajuste de parámetros para mejorar la capacidad de procesamiento del modelo.

Nombre del modelo Optimización
original Modelo original (sin optimización con TF-TRT)
tftrt_fp32 Optimización de gráficos
(tamaño del lote: 64, grupos de instancias: 1)
tftrt_fp16 Conversión a FP16 y optimización de gráficos
(tamaño de lote: 64, grupos de instancias: 1)
tftrt_int8 Cuantización con INT8 y optimización de gráficos
(tamaño de lote: 64, grupos de instancias: 1)
tftrt_int8_bs16_count4 Cuantización con INT8 y optimización de gráficos
(tamaño de lote: 16, grupos de instancias: 4)

Mide el rendimiento de referencia

Comienzas con TF-TRT como modelo de referencia para medir el rendimiento del modelo original no optimizado. Debes comparar el rendimiento de otros modelos con el original para evaluar de forma cuantitativa la mejora en el rendimiento. Cuando implementaste Locust, ya se configuró para enviar solicitudes del modelo original.

  1. Abre la consola de Locust y confirma que la cantidad de clientes (denominados secundarios) sea 10. Si es inferior a 10, los clientes siguen iniciándose. En ese caso, espera unos minutos hasta que sea 10.
  2. Establece la Cantidad de usuarios que se simularán en 3000 y la Velocidad de generación en 5.
  3. Aumenta la cantidad de usos simulados de 5 por segundo hasta que alcance los 3,000 haciendo clic en Comenzar a generar.

    Inicia un nuevo generador de Locust.

  4. Haz clic en Gráficos para mostrar lo siguiente:

    Inicia un nuevo generador de Locust.

    Observa que, si bien el valor Solicitudes totales por segundo aumenta de forma lineal, el valor Tiempos de respuesta (ms) aumenta en consecuencia.

  5. Cuando el valor del percentil 95 de los tiempos de respuesta supere los 100 ms, haz clic en Detener para parar la simulación. Si mueves el puntero del mouse sobre el gráfico, puedes verificar la cantidad de solicitudes por segundo que corresponden al momento en que el valor del percentil 95 de los tiempos de respuesta superó los 100 ms.

    En la captura de pantalla siguiente, el número de solicitudes por segundo es 253.1.

    Gráfico que muestra 253.1 solicitudes por segundo

    Te recomendamos que repitas esta medición varias veces y tengas un promedio para representar la fluctuación.

  6. Reinicia 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. Regresa al paso 1 para repetir la medición.

Optimiza los gráficos

En esta sección, medirás el rendimiento del modelo tftrt_fp32 que se optimiza mediante TF-TRT para la optimización de gráficos. Esta es una optimización común que es compatible con la mayoría de las tarjetas de GPU de NVIDIA.

  1. Reinicia la herramienta de prueba de carga. Usa el recurso configmap para especificar el modelo como 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. Reinicia el servidor de Triton:

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

    Espera unos minutos hasta que los procesos del servidor estén listos.

  3. Repite la medición de rendimiento que realizaste en la sección anterior.

    En las siguientes capturas de pantalla, la cantidad de solicitudes por segundo es 381.

    Grafo que muestra el tiempo de respuesta con solicitudes por segundo de 381.

    Gráfico que muestra 381 solicitudes por segundo

    Estas imágenes muestran la mejora del rendimiento de la optimización del gráfico TF-TRT.

Conversión a FP16

En esta sección, medirás el rendimiento del modelo tftrt_fp16 que está optimizado con TF-TRT para la optimización de gráficos y la conversión a FP16. Esta es una optimización disponible para NVIDIA Tesla T4.

  1. Reinicia la herramienta de prueba de carga. Usa el recurso configmap para especificar el modelo como 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. Reinicia el servidor de Triton:

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

    Espera unos minutos hasta que los procesos del servidor estén listos.

  3. Repite la medición de rendimiento que realizaste en la sección anterior. En el siguiente ejemplo, la cantidad de solicitudes por segundo es 1,072.5.

    Gráfico que muestra el tiempo de respuesta con 1,072.5 solicitudes por segundo

    Gráfico que muestra 1,072.5 solicitudes por segundo

    Estas imágenes muestran la mejora en el rendimiento de la conversión de FP16, además de la optimización del gráfico de TF-TRT.

Cuantización con INT8

En esta sección, medirás el rendimiento del modelo tftrt_int8 que está optimizado con TF-TRT para la optimización de gráficos y la cuantización con INT8. Esta optimización está disponible para NVIDIA Tesla T4.

  1. Reinicia la herramienta de prueba de carga. Usa el recurso configmap para especificar el modelo como 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. Reinicia el servidor de Triton:

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

    Espera unos minutos hasta que los procesos del servidor estén listos.

  3. Repite la medición de rendimiento que realizaste en la sección anterior.

    En las siguientes capturas de pantalla, la cantidad de solicitudes por segundo es 1,085.4.

    Gráfico que muestra el tiempo de respuesta con 1,085.4 solicitudes por segundo

    Gráfico que muestra 1,085.4 solicitudes por segundo

    Este resultado es casi el mismo que la conversión a FP16. No se observa una ventaja por usar la cuantización con INT8. En teoría, la GPU NVIDIA Tesla T4 puede manejar modelos de cuantización con INT8 más rápido que los modelos de conversión a FP16. En este caso, puede haber un cuello de botella distinto del rendimiento de la GPU. Puedes confirmarlo con los siguientes datos de uso de GPU en el panel de Grafana. Ten en cuenta que el uso es inferior al 40%, lo que significa que el modelo no puede usar pal máximo el rendimiento de la GPU.

    Gráfico que muestra un uso de GPU de menos del 40%

    Como se muestra en la siguiente sección, es posible facilitar este cuello de botella aumentando la cantidad de grupos de instancias. Por ejemplo, aumenta la cantidad de grupos de instancias de 1 a 4 y disminuye el tamaño del lote de 64 a 16. Este enfoque mantiene la cantidad total de solicitudes procesadas en una sola GPU en 64.

Ajusta la cantidad de instancias

En esta sección, medirás el rendimiento del modelo tftrt_int8_bs16_count4. Este modelo tiene la misma estructura que tftrt_int8, pero debes cambiar el tamaño del lote y la cantidad de grupos de instancias como se describe al final de la sección anterior.

  1. Reinicia Locust. Usa el recurso configmap para especificar el modelo como tftrt_int8_bs16_count4. Al mismo tiempo, aumenta la cantidad de Pods de cliente de Locust para generar suficientes cargas de trabajo a fin de medir la limitación de rendimiento del modelo.

    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. Reinicia el servidor de Triton:

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

    Espera unos minutos hasta que los procesos del servidor estén listos.

  3. Repite la medición de rendimiento que realizaste en la sección anterior. Pero, en este caso, establece Frecuencia de Hat a15 porque lleva mucho tiempo alcanzar el límite de rendimiento si se establece Frecuencia de generación como 5. En el siguiente ejemplo, el número de solicitudes por segundo es 2,236.26.

    Grafo que muestra el tiempo de respuesta con 2236.6 solicitudes por segundo

    Grafo que muestra 2236.6 solicitudes por segundo

    Cuando ajustas la cantidad de instancias, casi duplicas las solicitudes por segundo. Observa que el uso de GPU alcanzó alrededor del 75% en el panel de Grafana.

    Gráfico que muestra un uso de GPU del 75%

Escala con varios nodos

Cuando escalas con varios nodos, mides el rendimiento de un mismo Pod. Debido a que los procesos de inferencia se ejecutan de forma independiente en Pods que no comparten nada, puedes suponer que la capacidad de procesamiento total escalará de manera lineal con la cantidad de Pods. Esta suposición se aplica siempre que no haya cuellos de botella, como el ancho de banda de la red entre clientes y servidores de inferencia.

Sin embargo, es importante comprender cómo se balancean las solicitudes de inferencia entre varios servidores de inferencia. Triton usa el protocolo de gRPC para establecer una conexión TCP entre un cliente y un servidor. Debido a que Triton vuelve a usar la conexión establecida para enviar varias solicitudes de inferencia, las solicitudes de un solo cliente siempre se envían al mismo servidor. A fin de distribuir solicitudes para varios servidores, debes usar varios clientes.

Limpia

Borra el proyecto

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

¿Qué sigue?