Ejecuta cargas de trabajo de inferencia de TensorFlow con TensorRT5 y NVIDIA T4 GPU

En este instructivo, se trata cómo ejecutar inferencias de aprendizaje profundo en cargas de trabajo a gran escala con GPU NVIDIA TensorRT5 que se ejecutan en Compute Engine.

Antes de comenzar, ten en cuenta la siguiente información importante:

  • La inferencia de aprendizaje profundo es la etapa del proceso de aprendizaje automático en la que se usa un modelo entrenado para reconocer, procesar y clasificar los resultados.
  • NVIDIA TensorRT es una plataforma optimizada para ejecutar cargas de trabajo de aprendizaje profundo.
  • Las GPU se usan para acelerar las cargas de trabajo con grandes volúmenes de datos, como el aprendizaje automático y el procesamiento de datos. Hay una gran variedad de GPU NVIDIA disponibles en Compute Engine . En este instructivo, se usan las GPU T4, ya que están diseñadas específicamente para cargas de trabajo de inferencia de aprendizaje profundo.

Objetivos

En este instructivo, se abordan los siguientes procedimientos:

  • Preparación de un modelo con un grafo previamente entrenado.
  • Prueba de velocidad de inferencia para un modelo con diferentes modos de optimización.
  • Conversión de un modelo personalizado en TensorRT.
  • Configuración de un clúster multizona. El clúster multizona se configura de la siguiente manera:
    • Está compilado en imágenes de VM de aprendizaje profundo de Google. Estas imágenes se preinstalan con TensorFlow, TensorFlow Serving y TensorRT5.
    • El ajuste de escala automático está habilitado. En este instructivo, el ajuste de escala automático tiene base en el uso de la GPU.
    • El balanceo de cargas está habilitado.
    • Firewall está habilitado.
  • Ejecución de una carga de trabajo de inferencia en el clúster multizona.

Descripción general de la arquitectura de alto nivel de la configuración del instructivo.

Costos

El costo de la ejecución de este instructivo varía según la sección.

El precio estimado para preparar tu modelo y probar las velocidades de inferencia a diferentes velocidades de optimización es de alrededor de $22.34 por día. Este costo se estima según las siguientes especificaciones:

  • 1 instancia de VM: n1-standard-8 (8 CPU virtuales, RAM de 30 GB)
  • 1 GPU NVIDIA Tesla T4

El precio estimado para configurar tu clúster multizona es de alrededor de $154.38 por día. Este costo se estima según las siguientes especificaciones:

  • 2 instancias de VM: n1-standard-16 (16 CPU virtuales, RAM de 60 GB)
  • 4 GPU NVIDIA Tesla T4 para cada instancia de VM
  • SSD de 100 GB para cada instancia de VM
  • 1 regla de reenvío

Estos costos se estimaron con la calculadora de precios.

Antes de comenzar

Configuración del proyecto

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En GCP Console, en la página de selección de proyecto, selecciona o crea un proyecto de GCP.

    Ir a la página de selección de proyecto

  3. Comprueba que la facturación esté habilitada en tu proyecto.

    Descubre cómo puedes habilitar la facturación

  4. Habilita lasCompute Engine and Cloud Machine Learning APIAPI.

    Habilita lasAPI

Configuración de las herramientas

Para usar la herramienta de línea de comandos de gcloud en este instructivo, realiza las siguientes acciones:

  1. Instala la herramienta de línea de comandos de gcloud o actualízala a la última versión.
  2. Configura una región y una zona predeterminadas (opcional).

Prepara el modelo

En esta sección, se abarca la creación de una instancia de máquina virtual (VM) que se usa para ejecutar el modelo. En esta sección, también se aborda cómo descargar un modelo del catálogo oficial de modelos TensorFlow.

  1. Crea la instancia de VM.

    export IMAGE_FAMILY="tf-1-12-cu100"
    export ZONE="us-central1-b"
    export INSTANCE_NAME="model-prep"
    gcloud compute instances create $INSTANCE_NAME \
        --zone=$ZONE \
        --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"
    
  2. Selecciona un modelo. En este instructivo, se usa el modelo ResNet. Este modelo ResNet está entrenado en el conjunto de datos ImageNet que está en TensorFlow.

    Para descargar el modelo ResNet a tu instancia de VM, ejecuta el siguiente comando:

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

    Guarda la ubicación de tu modelo ResNet en la variable $WORKDIR.

    export WORKDIR=[MODEL_LOCATION]
    

Ejecuta la prueba de velocidad de inferencia

En esta sección, se abarcan los siguientes procedimientos:

  • Configuración del modelo ResNet.
  • Ejecución de pruebas de inferencia en diferentes modos de optimización.
  • Revisión de los resultados de las pruebas de inferencia.

Descripción general del proceso de prueba

TensorRT puede mejorar la velocidad de rendimiento de las cargas de trabajo de inferencia, sin embargo, la mejora más importante proviene del proceso de cuantización.

La cuantización del modelo es el proceso mediante el cual se reduce la precisión de los pesos de un modelo. Por ejemplo, si el peso inicial de un modelo es FP32, puedes reducir la precisión a FP16, INT8 o incluso INT4. Es importante elegir el compromiso correcto entre la velocidad (precisión de los pesos) y la exactitud de un modelo. Por suerte, TensorFlow incluye una funcionalidad que hace exactamente esto y mide la exactitud frente a la velocidad o algunas otras métricas como la capacidad de procesamiento, la latencia, el porcentaje de conversiones de nodos y el tiempo total de entrenamiento.

Procedimiento

  1. Configura el modelo ResNet. A fin de configurar el modelo, ejecuta los siguientes comandos:

    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. Ejecuta la prueba. Este comando tarda un poco en completarse.

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

    En el que:

    • $WORKDIR es el directorio en el que descargaste el modelo ResNet.
    • Los argumentos --native son los diferentes modos de cuantización que deseas probar.
  3. Revisa los resultados. Cuando se complete la prueba, puedes hacer una comparación de los resultados de la inferencia para cada modo de optimización.

    Predictions:
    Precision:  native [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty',     u'lakeside, lakeshore', u'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus']
    Precision:  FP32 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  FP16 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  INT8 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'grey         whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', u'lakeside, lakeshore']
    

    Para ver los resultados completos, ejecuta el siguiente comando:

    cat $WORKDIR/log.txt
    

    Resultados del rendimiento.

    A partir de los resultados, puedes ver que FP32 y FP16 son idénticos. Esto significa que, si te sientes cómodo trabajando con TensorRT, puedes comenzar a usar FP16 de inmediato. INT8, muestra resultados un poco peores.

    Además, puedes ver que la ejecución del modelo con TensorRT5 muestra los siguientes resultados:

    • Con la optimización FP32, el rendimiento mejora un 40%, de 314 fps a 440 fps. Al mismo tiempo, la latencia disminuye casi un 30%, por lo que es 0.28 ms en lugar de 0.40 ms.
    • Con la optimización FP16, en lugar del grafo nativo de TensorFlow, la velocidad aumenta un 214%, de 314 a 988 fps. Al mismo tiempo, la latencia disminuye en 0.12 ms, una disminución de casi el triple.
    • Con INT8, se puede notar una aceleración del 385%, de 314 fps a 1,524 fps, con una latencia que disminuye a 0.08 ms.

Convierte un modelo personalizado en TensorRT

Para esta conversión, puedes usar un modelo INT8.

  1. Descarga el modelo. Para convertir un modelo personalizado en un grafo TensorRT, necesitas un modelo guardado. Para obtener un modelo ResNet INT8 guardado, ejecuta el siguiente comando:

    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. Convierte el modelo en el grafo de TensorRT con TFTools. Para convertir el modelo con TFTools, ejecuta el siguiente comando:

    git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
    cd ml-on-gcp/dlvm/tools
    python ./convert_to_rt.py \
        --input_model_dir=$WORKDIR/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
        --output_model_dir=$WORKDIR/resnet_v2_int8_NCHW/00001 \
        --batch_size=128 \
        --precision_mode="INT8"
    

    Ahora tienes un modelo INT8 en tu directorio $WORKDIR/resnet_v2_int8_NCHW/00001.

    Para asegurarte de que todo esté configurado como corresponde, intenta ejecutar una prueba de inferencia.

    tensorflow_model_server --model_base_path=$WORKDIR/resnet_v2_int8_NCHW/ --rest_api_port=8888
    
  3. Sube el modelo a Cloud Storage. Este paso es necesario para que el modelo se pueda usar desde el clúster de varias zonas que se configura en la siguiente sección. Para subir el modelo, sigue estos pasos:

    1. Archiva el modelo.

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
      
    2. Sube el archivo.

      export GCS_PATH=<gcs_path>
      gsutil cp model.tar.gz $GCS_PATH
      

      Si es necesario, puedes obtener un grafo inmovilizado de INT8 desde Cloud Storage en esta URL:

      gs://cloud-samples-data/dlvm/t4/model.tar.gz
      

Configura un clúster de varias zonas

Crea el clúster

Ahora que tienes un modelo en la plataforma de Cloud Storage, puedes crear un clúster.

  1. Crea una plantilla de instancias. Una plantilla de instancias es un recurso útil para crear instancias nuevas. Consulta Plantillas de instancias.

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-1-12-cu100"
    export PROJECT_NAME="your_project_name"
    
    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://cloud-samples-data/dlvm/t4/start_agent_and_inf_server_4.sh
    
    • En esta plantilla de instancias, se incluye una secuencia de comandos de inicio especificada por el parámetro de metadatos.
    • Ejecuta esta secuencia de comandos de inicio durante la creación de la instancia en cada instancia que use esta plantilla.
    • Esta secuencia de comandos de inicio realiza los siguientes pasos:
      • Instala un agente de supervisión que supervisa el uso de la GPU en la instancia.
      • Descarga el modelo.
      • Inicia el servicio de inferencia.
    • En la secuencia de comandos de inicio, tf_serve.py contiene la lógica de inferencia. En este ejemplo, se incluye un archivo python muy pequeño con base en el paquete TFServe.
    • Para ver la secuencia de comandos de inicio, consulta startup_inf_script.sh.
  2. Crea un grupo de instancias administrado (MIG). Este grupo de instancias administrado es necesario para configurar varias instancias en ejecución en zonas específicas. Las instancias se crean en función de la plantilla de instancias que se generó en el paso anterior.

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    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
    
    • Puedes crear esta instancia en cualquier zona disponible que sea compatible con las GPU T4. Asegúrate de tener cuotas de GPU disponibles en la zona.
    • La creación de la instancia demora un poco. Puedes consultar el progreso mediante la ejecución del siguiente comando:

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      
      gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1
      

      Creación de la instancia

    • Cuando se crea el grupo de instancias administrado, debería aparecer un resultado similar al siguiente:

      La instancia en ejecución

  3. Confirma que las métricas están disponibles en la página de Stackdriver Monitoring de Google Cloud.

    1. En Google Cloud Console, selecciona Monitoring o usa el siguiente botón:

      Ir a Monitoring

    2. Si el Explorador de métricas aparece en el panel de navegación, haz clic en Explorador de métricas. De lo contrario, selecciona Recursos y, luego, Explorador de métricas.

    3. Busca gpu_utilization.

      Inicio de Monitoring

    4. Si entran datos, deberías ver algo como lo siguiente:

      Monitoring en ejecución

Habilitar ajuste de escala automático

  1. Habilita el ajuste de escala automático para el grupo de instancias administrado.

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    
    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
    

    custom.googleapis.com/gpu_utilization es la ruta completa de acceso a nuestra métrica. El ejemplo especifica el nivel 85, es decir, cuando el uso de GPU llega a 85, la plataforma crea una instancia nueva en nuestro grupo.

  2. Prueba el ajuste de escala automático. Para probar el ajuste de escala automático, sigue estos pasos:

    1. Establece una conexión SSH a la instancia. Consulta Conéctate a instancias.
    2. Usa la herramienta gpu-burn para cargar tu GPU al 100% de uso durante 600 segundos:

      git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
      cd ml-on-gcp/third_party/gpu-burn
      git checkout c0b072aa09c360c17a065368294159a6cef59ddf
      make
      ./gpu_burn 600 > /dev/null &
      
    3. Ve a la página de Stackdriver Monitoring. Observa el ajuste de escala automático. El clúster escala verticalmente mediante la adición de una instancia más.

      Ajuste de escala automático en clúster

    4. Ve a la página Grupos de instancias en Cloud Console.

      Ir a la página Grupos de instancias

    5. Haz clic en el grupo de instancias administrado deeplearning-instance-group.

    6. Haz clic en la pestaña Supervisión (Monitoring).

      Pestaña Supervisión (Monitoring).

      En este punto, tu lógica de ajuste de escala automático debería intentar girar la mayor cantidad de instancias posible para reducir la carga, sin lograrlo.

      Y eso es lo que sucede, como se muestra a continuación:

      Instancias adicionales.

      En este punto, puedes detener la grabación de instancias y observar cómo el sistema se escala hacia abajo.

Configura un balanceador de cargas

Revisemos lo que tienes hasta ahora:

  • Un modelo entrenado, optimizado con TensorRT5 (INT8)
  • Un grupo de instancias administrado. Estas instancias tienen habilitado el ajuste de escala automático según el uso de GPU habilitado

Ahora puedes crear un balanceador de cargas frente a las instancias.

  1. Crea verificaciones de estado. Las verificaciones de estado se usan para determinar si un host en particular en nuestro backend puede entregar el tráfico.

    export HEALTH_CHECK_NAME="http-basic-check"
    
    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
        --request-path /v1/models/default \
        --port 8888
    
  2. Crea un servicio de backend que incluya un grupo de instancias y una verificación de estado.

    1. Crea la verificación de estado.

      export HEALTH_CHECK_NAME="http-basic-check"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
          --protocol HTTP \
          --health-checks $HEALTH_CHECK_NAME \
          --global
      
    2. Agrega el grupo de instancias al nuevo servicio de backend.

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      export WEB_BACKED_SERVICE_NAME="tensorflow-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
      
  3. Configura la URL de reenvío. El balanceador de cargas necesita saber qué URL se puede reenviar a los servicios de backend.

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
        --default-service $WEB_BACKED_SERVICE_NAME
    
  4. Crea el balanceador de cargas.

    export WEB_MAP_NAME="map-all"
    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
        --url-map $WEB_MAP_NAME
    
  5. Agrega una dirección IP externa al balanceador de cargas.

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
        --ip-version=IPV4 \
        --global
    
  6. Encuentra la IP que está asignada.

    gcloud compute addresses list
    
  7. Configura la regla de reenvío que le dice a GCP que reenvíe todas las solicitudes desde la IP pública al balanceador de cargas.

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

    Después de crear las reglas de reenvío globales, la configuración puede tardar varios minutos en propagarse.

Habilita firewall

  1. Comprueba si tienes reglas de firewall que permitan conexiones de fuentes externas a tus instancias de VM.

    gcloud compute firewall-rules list
    
  2. Si no tienes reglas de firewall que permitan estas conexiones, debes crearlas. Para crear reglas de firewall, ejecuta los siguientes comandos:

    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
    

Ejecuta una inferencia

  1. Puedes usar la siguiente secuencia de comandos Python para convertir imágenes en un formato que se pueda subir al servidor.

    from PIL import Image
    import numpy as np
    import json
    import codecs
    <br>
    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))
    
  2. Ejecuta la inferencia.

    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json
    

Realiza una limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

  1. Borra las reglas de reenvío.

    gcloud compute forwarding-rules delete $FORWARDING_RULE --global
    
  2. Borra la dirección IPV4.

    gcloud compute addresses delete $IP4_NAME --global
    
  3. Borra el balanceador de cargas.

    gcloud compute target-http-proxies delete $LB_NAME
    
  4. Borra la URL de reenvío.

    gcloud compute url-maps delete $WEB_MAP_NAME
    
  5. Borra el servicio de backend.

    gcloud compute backend-services delete $WEB_BACKED_SERVICE_NAME --global
    
  6. Borra las verificaciones de estado.

    gcloud compute health-checks delete $HEALTH_CHECK_NAME
    
  7. Borra el grupo de instancias administrado.

    gcloud compute instance-groups managed delete $INSTANCE_GROUP_NAME --region us-central1
    
  8. Borra la plantilla de instancias.

    gcloud beta compute --project=$PROJECT_NAME instance-templates delete $INSTANCE_TEMPLATE_NAME
    
  9. Borra las reglas de firewall.

    gcloud compute firewall-rules delete www-firewall-80
    gcloud compute firewall-rules delete www-firewall-8888