Exécuter des charges de travail d'inférence TensorFlow avec des GPU TensorRT5 et NVIDIA T4

Ce tutoriel explique comment exécuter des inférences de deep learning sur des charges de travail à grande échelle à l'aide de GPU NVIDIA TensorRT5 s'exécutant sur Compute Engine.

Avant de commencer, voici quelques notions de base à assimiler :

  • L'inférence de deep learning est l'étape du processus de machine learning lors de laquelle un modèle entraîné est utilisé afin de reconnaître, de traiter et de classer des résultats.
  • NVIDIA TensorRT est une plate-forme optimisée pour l'exécution de charges de travail de deep learning.
  • Les GPU permettent d'accélérer les charges de travail qui consomment beaucoup de données, telles que le machine learning et le traitement des données. Une large gamme de GPU NVIDIA est disponible sur Compute Engine. Ce tutoriel utilise des GPU T4, car ils sont spécialement conçus pour les charges de travail d'inférence de deep learning.

Objectifs

Ce tutoriel décrit comment effectuer les opérations suivantes :

  • Préparer un modèle à l'aide d'un graphe pré-entraîné
  • Tester la vitesse d'inférence sur un modèle en utilisant différents modes d'optimisation
  • Convertir un modèle personnalisé en graphe TensorRT
  • Définir un cluster multizone configuré de la manière suivante :
    • Le cluster est basé sur des images de VM de deep learning Google. Les services TensorFlow, TensorFlow Serving et TensorRT5 sont pré-installés sur ces images.
    • L'autoscaling est activé sur le cluster. L'autoscaling de ce tutoriel est basé sur l'utilisation du GPU.
    • L'équilibrage de charge est activé sur le cluster.
    • Le pare-feu est activé sur le cluster.
  • Exécuter une charge de travail d'inférence dans un cluster multizone

Présentation de l'architecture de haut niveau pour la configuration du tutoriel

Coûts

Le coût de ce tutoriel varie d'une section à l'autre.

Les frais de préparation du modèle et de test des vitesses d'inférence avec différents modes d'optimisation sont estimés à 22,34 USD par jour. Ce tarif est basé sur les spécifications suivantes :

  • 1 instance de VM : n1-standard-8 (8 processeurs virtuels, 30 Go de RAM)
  • 1 GPU NVIDIA Tesla T4

Les frais de configuration de votre cluster multizone sont estimés à 154,38 USD par jour. Ce tarif est basé sur les spécifications suivantes :

  • 2 instances de VM : n1-standard-16 (16 processeurs virtuels, 60 Go de RAM)
  • 4 GPU NVIDIA Tesla T4 par instance de VM
  • 100 Go de stockage SSD par instance de VM
  • 1 règle de transfert

Ces frais ont été estimés à l'aide du simulateur de coût.

Avant de commencer

Configuration du projet

  1. Connectez-vous à votre compte Google.

    Si vous n'en possédez pas déjà un, vous devez en créer un.

  2. Sélectionnez ou créez un projet Google Cloud Platform.

    Accéder à la page "Gérer les ressources"

  3. Assurez-vous que la facturation est activée pour votre projet Google Cloud Platform.

    Découvrir comment activer la facturation

  4. Activez Compute Engine et Cloud Machine Learning les API requises.

    Activer les API.

Configuration des outils

Pour utiliser l'outil de ligne de commande gcloud dans ce tutoriel, procédez comme suit :

  1. Installez la dernière version de l'outil de ligne de commande gcloud ou appliquez la mise à jour correspondante.
  2. (Facultatif) Définissez une région et une zone par défaut.

Préparer le modèle

Cette section décrit comment créer une instance de machine virtuelle (VM) permettant d'exécuter le modèle. Elle explique également comment télécharger un modèle à partir du catalogue de modèles officiels de Tensorflow.

  1. Créez l'instance 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. Sélectionnez un modèle. Ce tutoriel utilise le modèle ResNet, qui a été entraîné à l'aide de l'ensemble de données ImageNet disponible dans TensorFlow.

    Pour télécharger le modèle ResNet sur votre instance de VM, exécutez la commande suivante :

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

    Enregistrez l'emplacement du modèle ResNet dans la variable $WORKDIR.

    export WORKDIR=[MODEL_LOCATION]
    

Tester la vitesse d'inférence

Cette section décrit comment effectuer les opérations suivantes :

  • Configurer le modèle ResNet
  • Exécuter des tests d'inférence avec différents modes d'optimisation
  • Examiner les résultats des tests d'inférence

Présentation du processus de test

TensorRT peut accroître la vitesse des charges de travail d'inférence, mais l'amélioration la plus importante provient du processus de quantification.

La quantification de modèle est un processus permettant de réduire la précision des pondérations d'un modèle. Par exemple, si la pondération initiale d'un modèle correspond à FP32, vous pouvez réduire la précision à FP16, INT8 ou même INT4. Il est important de choisir le bon compromis entre la vitesse (précision des pondérations) et la justesse d'un modèle. Heureusement, TensorFlow inclut des fonctionnalités qui permettent d'effectuer cette démarche. Vous pouvez alors mesurer la justesse par rapport à la vitesse ou à d'autres métriques telles que le débit, la latence, les taux de conversion de nœud et la durée totale de l'entraînement.

Procédure

  1. Configurez le modèle ResNet. Pour ce faire, exécutez les commandes suivantes :

    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. Exécutez le test. Cette opération peut prendre un certain temps.

    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
    

    Où :

    • $WORKDIR est le répertoire dans lequel vous avez téléchargé le modèle ResNet.
    • Les arguments --native correspondent aux différents modes de quantification à tester.
  3. Examinez les résultats. Une fois le test terminé, vous pouvez comparer les résultats d'inférence pour chaque mode d'optimisation.

    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']
    

    Pour afficher les résultats complets, exécutez la commande suivante :

    cat $WORKDIR/log.txt
    

    Résultats

    D'après les résultats, vous pouvez constater que les modes FP32 et FP16 sont identiques. Si vous êtes à l'aise avec TensorRT, vous pouvez donc directement commencer à utiliser FP16. Les résultats du mode INT8 sont légèrement moins bons.

    En outre, vous pouvez constater que l'exécution du modèle avec TensorRT5 donne les résultats suivants :

    • L'optimisation FP32 augmente le débit de 40 % (passage de 314 à 440 IPS). Elle réduit également la latence d'environ 30 % (0,28 ms au lieu de 0,40 ms).
    • Par rapport au graphe natif de TensorFlow, l'optimisation FP16 augmente la vitesse de 214 % (passage de 314 à 988 IPS). La latence tombe également à 0,12 ms, soit presque trois fois moins que le graphe natif.
    • Avec INT8, vous pouvez observer une accélération de 385 %, avec un débit passant de 314 à 1 524 IPS et une latence chutant à 0,08 ms.

Convertir un modèle personnalisé en graphe TensorRT

Pour effectuer cette conversion, vous pouvez utiliser un modèle INT8.

  1. Téléchargez le modèle. Pour convertir un modèle personnalisé en graphe TensorRT, vous avez besoin d'un modèle enregistré. Exécutez la commande suivante pour obtenir un modèle ResNet INT8 enregistré :

    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. Convertissez le modèle en graphe TensorRT à l'aide de TFTools. Pour ce faire, exécutez la commande suivante :

    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"
    

    Vous disposez maintenant d'un modèle INT8 dans votre répertoire $WORKDIR/resnet_v2_int8_NCHW/00001.

    Pour vous assurer que tout est bien configuré, essayez d'exécuter un test d'inférence.

    tensorflow_model_server --model_base_path=$WORKDIR/resnet_v2_int8_NCHW/ --rest_api_port=8888
    
  3. Importez le modèle dans Cloud Storage. Cette étape est nécessaire pour que le modèle puisse être utilisé à partir du cluster multizone, configuré dans la section suivante. Pour importer le modèle, procédez comme suit :

    1. Créez une archive du modèle.

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
      
    2. Importez l'archive.

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

      Si nécessaire, vous pouvez obtenir un graphe INT8 figé dans Google Cloud Storage à l'adresse suivante :

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

Configurer un cluster multizone

Créer le cluster

Maintenant que vous disposez d'un modèle sur la plate-forme Cloud Storage, vous pouvez créer un cluster.

  1. Créez un modèle d'instance. Un modèle d'instance est une ressource utile qui permet de créer des instances. Consultez la page Modèles d'instances pour en savoir plus.

    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
    
    • Ce modèle d'instance inclut un script de démarrage spécifié par le paramètre "metadata".
      • Exécutez ce script de démarrage lors de la création de l'instance sur chaque instance utilisant ce modèle.
      • Le script de démarrage exécute les tâches suivantes :
        • Il installe un agent chargé de surveiller l'utilisation du GPU sur l'instance.
        • Il télécharge le modèle.
        • Il démarre le service d'inférence
      • Dans le script de démarrage, le fichier tf_serve.py contient la logique d'inférence. Cet exemple inclut un petit fichier Python basé sur le package TFServe.
      • Pour afficher le script de démarrage, accédez à la page startup_inf_script.sh.
  2. Créez un groupe d'instances géré (MIG, Managed Instance Group). Ce groupe permet de configurer plusieurs instances en cours d'exécution dans des zones spécifiques. Les instances sont créées en fonction du modèle d'instance généré à l'étape précédente.

    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
    
    • Vous pouvez créer cette instance dans n'importe quelle zone disponible compatible avec les GPU T4. Assurez-vous de disposer d'un quota de GPU suffisant dans la zone.
    • La création de l'instance prend un certain temps. Vous pouvez suivre la progression de cette étape en exécutant la commande suivante :

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

      Capture d'écran de la création d'instance

    • Une fois le groupe d'instances géré créé, un résultat semblable aux lignes suivantes doit s'afficher :

      Capture d'écran de l'instance en cours d'exécution

  3. Vérifiez que les métriques sont disponibles sur la page Stackdriver Monitoring de Google Cloud Platform.

    1. Depuis la console Google Cloud Platform, accédez à la page Explorateur de métriques :

      Accéder à l'explorateur de métriques

    2. Recherchez gpu_utilization.

      Interface au lancement de Stackdriver Monitoring

    3. Si des données sont enregistrées, vous devriez voir un écran similaire à ceci :

      Interface de Stackdriver Monitoring en cours d'exécution

Activer l'autoscaling

  1. Activez l'autoscaling sur le groupe d'instances géré.

    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 correspond au chemin d'accès complet à notre métrique. L'exemple spécifie le niveau 85, ce qui signifie que chaque fois que l'utilisation du GPU atteint 85 %, la plate-forme crée une instance dans notre groupe.

  2. Testez l'autoscaling. Pour ce faire, effectuez les étapes suivantes :

    1. Connectez-vous en SSH à l'instance. Consultez la page Se connecter à des instances pour en savoir plus.
    2. À l'aide de l'outil gpu-burn, faites grimper le taux d'utilisation du GPU à 100 % et maintenez-le à ce niveau pendant 600 secondes :

      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. Accédez à la page Stackdriver. Observez l'autoscaling. Le cluster ajoute une instance supplémentaire.

      Capture d'écran de l'autoscaling

    4. Accédez à la page "Groupes d'instances" dans la console GCP.

      Accéder à la page "Groupes d'instances"

    5. Cliquez sur le groupe d'instances géré deeplearning-instance-group.

    6. Cliquez sur l'onglet "Monitoring" (Surveillance).

      Onglet

      À ce stade, votre logique d'autoscaling devrait essayer de démarrer un maximum d'instances pour réduire la charge, sans succès.

      Et c'est exactement ce qui se passe :

      Instances supplémentaires

      Vous pouvez désormais arrêter de surmener les instances et observer comment le système réduit leur nombre.

Configurer un équilibreur de charge

Passons en revue les ressources à votre disposition :

  • Un modèle entraîné, optimisé avec TensorRT5 (INT8)
  • Un groupe d'instances géré (l'autoscaling est activé sur ces instances, dont le nombre dépend de l'utilisation du GPU)

Vous pouvez maintenant créer un équilibreur de charge devant les instances.

  1. Créez des vérifications d'état. Elles permettent de déterminer si un hôte spécifique sur notre backend peut diffuser le trafic.

    export HEALTH_CHECK_NAME="http-basic-check"
    
    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
        --request-path /v1/models/default \
        --port 8888
    
  2. Créez un backend comprenant un groupe d'instances et une vérification d'état.

    1. Créez la vérification d'état.

      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. Ajoutez le groupe d'instances au nouveau service 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. Configurez l'URL de transfert. L'équilibreur de charge doit savoir quelle URL peut être transférée aux services 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. Créez l'équilibreur de charge.

    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. Ajoutez une adresse IP externe à l'équilibreur de charge.

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
        --ip-version=IPV4 \
        --global
    
  6. Recherchez l'adresse IP attribuée.

    gcloud compute addresses list
    
  7. Configurez la règle de transfert qui indique à GCP de transférer toutes les requêtes provenant de l'adresse IP publique à l'équilibreur de charge.

    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
    

    Une fois les règles de transfert globales créées, la propagation de votre configuration peut prendre plusieurs minutes.

Activer le pare-feu

  1. Vérifiez que vous disposez de règles de pare-feu autorisant les connexions provenant de sources externes à vos instances de VM.

    gcloud compute firewall-rules list
    
  2. Si vous ne possédez pas de règles de pare-feu autorisant ces connexions, vous devez les créer. Pour ce faire, exécutez les commandes suivantes :

    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
    

Exécuter une inférence

  1. Vous pouvez exploiter le script Python suivant pour convertir des images dans un format pouvant être importé sur le serveur.

    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. Exécutez l'inférence.

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

Nettoyer

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud Platform :

  1. Supprimez les règles de transfert.

    gcloud compute forwarding-rules delete $FORWARDING_RULE --global
    
  2. Supprimez l'adresse IPV4.

    gcloud compute addresses delete $IP4_NAME --global
    
  3. Supprimez l'équilibreur de charge.

    gcloud compute target-http-proxies delete $LB_NAME
    
  4. Supprimez l'URL de transfert.

    gcloud compute url-maps delete $WEB_MAP_NAME
    
  5. Supprimez le service de backend.

    gcloud compute backend-services delete $WEB_BACKED_SERVICE_NAME --global
    
  6. Supprimez les vérifications d'état.

    gcloud compute health-checks delete $HEALTH_CHECK_NAME
    
  7. Supprimez le groupe d'instances géré.

    gcloud compute instance-groups managed delete $INSTANCE_GROUP_NAME --region us-central1
    
  8. Supprimez le modèle d'instance.

    gcloud beta compute --project=$PROJECT_NAME instance-templates delete $INSTANCE_TEMPLATE_NAME
    
  9. Supprimez les règles de pare-feu.

    gcloud compute firewall-rules delete www-firewall-80
    gcloud compute firewall-rules delete www-firewall-8888
    
Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Documentation Compute Engine