Comment déployer un modèle de détection d'objet avec le service TensorFlow

Les modèles de détection d'objets sont parmi les modèles d'apprentissage en profondeur les plus sophistiqués. Ils sont capables de localiser et de classer des objets en temps réel dans des images et des vidéos. Mais à quoi sert un modèle s’il ne peut pas être utilisé pour la production?

Grâce aux gars formidables de TensorFlow, TensorFlow est capable de servir nos modèles en production. Il existe de très bons articles sur TensorFlow qui vous permettent de démarrer comme celui-ci et celui-ci.

Cet article portera sur la façon dont nous pouvons servir des modèles de détection d’objet spécifiquement avec TF Serving. Il est motivé par l’absence d’une bonne ressource en ligne qui explique comment créer des modèles de détection d’objets prêts pour la production et des environnements de service TF utilisant Docker. Nous verrons également comment servir le modèle et créer un script côté client pour y accéder. Notre architecture ressemblera à ceci:

Dans l’esprit de ne pas réinventer la roue, j’ai pris l’aide des ressources disponibles dans l’API de détection d’objets pour ce tutoriel. Je suppose que vous avez cloné l'API de détection d'objet de TensorFlow - mais si ce n'est pas le cas, procédez comme suit:

# Clone tensorlfow modèles repo
https://github.com/tensorflow/models.git
cd models / research / object_detection

1. Créer un modèle prêt à la production pour la gestion en transit

En supposant que vous ayez formé votre modèle de détection d'objet à l'aide de TensorFlow, les quatre fichiers suivants seront enregistrés sur votre disque:

Fichiers modèles formés enregistrés sur le disque

Ces fichiers peuvent être utilisés directement pour l'inférence. Ou nous pouvons utiliser le script freeze_graph.py pour convertir le modèle en un graphe figé comprenant l’architecture du modèle et les pondérations dans un fichier. Ceci est utile à des fins de test sur votre machine locale, mais ne convient pas à un environnement de production.

Pour créer des modèles prêts à être utilisés, nous allons ajuster le fichier exporter.py disponible sur l’API Github de détection d’objets. Le script d'origine disponible sur le référentiel n'enregistre pas les variables requises pour la diffusion. Utilisez le script exporter.py suivant au lieu de l’original TensorFlow.

Les modifications suivantes ont été apportées à l'exportateur ci-dessus.py:

  1. Passez à la méthode _write_saved_model. Cela est nécessaire, car le script python d'origine n'enregistre pas les variables requises pour servir le modèle. Maintenant, au lieu d’utiliser frozen_graph_def, nous utilisons lerefrained_checkpoint_peut avoir les poids du modèle en tant que variables. (crédits pour ce numéro de Github)

2. Modifiez la fonction d’appel de frozen_graph_def en entraîne_prefix_Checkpoint en procédant comme suit:

3. Mettez en commentaire le code qui enregistre les fichiers sur le disque non requis pendant le service:

Vous êtes maintenant tous prêts à créer votre modèle pouvant être utilisé pour servir. Le code suivant peut vous aider à atteindre cet objectif:

Voici une explication de ce code:

  1. Chaque modèle de détection d'objet a une configuration qui doit être transmise à export_model.py. Cela consiste en des informations concernant l'architecture du modèle. Pour plus d'informations, consultez ce lien.
  2. La méthode get_configs_from_pipeline_file crée un dictionnaire à partir du fichier de configuration et la méthode create_pipeline_proto_from_configs crée un objet tampon proto à partir de ce dictionnaire.
  3. input_checkpoint est le chemin d'accès à model.ckpt du modèle formé.
  4. model_version_id est un entier pour la version actuelle du modèle. Ceci est requis par TF-servant pour la gestion des versions de modèles.
  5. object_detection.exporter enregistrera le modèle au format suivant:
Modèle prêt à être utilisé par TF-Serving

1 / est la version du modèle, saved_model.pb. Il contient l'architecture du modèle et le répertoire des variables a les poids pour le modèle. Ce modèle est prêt à être servi.

2. Créez un environnement de service TF à l'aide de Docker.

À propos de Docker

Docker est un outil logiciel qui vous permet de regrouper des logiciels en unités standardisées pour le développement, l'expédition et le déploiement. L'image de conteneur Docker est un package léger, autonome et exécutable d'un logiciel qui inclut tout le nécessaire pour l'exécuter: code, exécution, outils système, bibliothèques système et paramètres.

En bref, Docker nous permet d’isoler votre application et ses dépendances dans un package autonome pouvant être utilisé n’importe où et à tout moment sans avoir à vous soucier de l’installation de code et des dépendances du système.

Notre motivation pour utiliser docker pour le service TensorFlow est que nous pouvons expédier notre conteneur pour fonctionner sur le cloud et adapter facilement notre service sans avoir à installer de nouvelles dépendances.

La documentation officielle du serveur TensorFlow explique comment le construire à partir des sources. C’est bien, mais moi (et beaucoup de membres de la communauté) avons eu du mal à le compiler dans le conteneur de docker. Nous allons donc passer en revue les étapes une par une ici.

  1. Construisez le conteneur en utilisant l'image officielle du menu fixe

En supposant que vous ayez cloné le référentiel officiel TensorFlow comme décrit dans la dernière partie, vous pouvez créer l'image du menu fixe en procédant comme suit:

# Déplacer vers le répertoire des fichiers du menu fixe
cd ./serving/tensorflow_serving/tools/docker/
# Construire l'image (CPU)
construction de docker --pull -t $ USER / tensorflow-servant-devel-cpu -f Dockerfile.devel.
ou
# Construire l'image (GPU)
construction de docker --pull -t $ USER / tensorflow-servant-devel-gpu -f Dockerfile.devel-gpu.

Avant de démarrer le conteneur de menu fixe, augmentez la mémoire (jusqu'à 10-12 Go) et le nombre de CPU (de 4 à 6) disponibles pour le conteneur dans la section Préférences de l'application fixe. La création du serveur TensorFlow est un processus exigeant en mémoire et les paramètres par défaut risquent de ne pas fonctionner. Une fois cela fait, vous pouvez démarrer le conteneur comme ceci:

[POUR CPU]
docker run -it -p 9000: 9000 $ USER / tensorflow-servant-devel-cpu / bin / bash
ou
[POUR GPU]
docker run -it -p 9000: 9000 $ USER / tensorflow-servant-devel-gpu / bin / bash

Dans le conteneur, procédez comme suit:

[POUR CPU]
# Cloner le TensorFlow servant le dépôt Github dans le conteneur
git clone --recurse-submodules https://github.com/tensorflow/serving
cd servant / tensorflow
# Configurer TensorFlow
./configurer
cd ..
# Construire TensorFlow servant
bazel build -c opt --copt = -msse4.1 --copt = -msse4.2 tensorflow_serving / ...
ou
[POUR GPU]
# TensorFlow servant le repo Github est déjà présent dans le conteneur # donc pas besoin de cloner à nouveau
# Configurez TensorFlow avec CUDA en acceptant (-y) -
# with_CUDA_support flag
cd servant / tensorflow
./configurer
# Construire TensorFlow au service de CUDA
bazel build -c opt --copt = -msse4.1 --copt = -msse4.2 --copt = -mavx --copt = -mavx2 --copt = -mfma --copt = -O3 --copt = / usr / local / cuda tensorflow_serving / ...

Le processus de construction peut prendre jusqu'à une heure en fonction du système hôte et de la configuration du menu fixe. Une fois la construction terminée sans erreur, vous pouvez tester si le serveur de modèles est en cours d'exécution:

bazel-bin / tensorflow_serving / model_servers / tensorflow_model_server

La sortie devrait ressembler à ceci:

Drapeaux:
--port = 8500 int32 port sur lequel écouter
--enable_batching = false bool active le traitement par lots
--batching_parameters_file = "" chaîne Si non vide, lit un BatchingParameters protobuf ascii à partir du nom de fichier fourni et utilise les valeurs contenues à la place des valeurs par défaut.
--model_config_file = "" chaîne Si ce n'est pas vide, lit un modèle ModelServerConfig ascii à partir du nom de fichier fourni et sert les modèles de ce fichier. Ce fichier de configuration peut être utilisé pour spécifier plusieurs modèles à servir et d’autres paramètres avancés, y compris une stratégie de version autre que celle par défaut. (Si utilisé, - nom_modèle, - chemin_model_base sont ignorés.)
--model_name = "default" nom de chaîne du modèle (ignoré si l'indicateur --model_config_file est défini
--model_base_path = "" chemin de la chaîne à exporter (ignoré si l'indicateur --model_config_file est défini, sinon requis)
--file_system_poll_wait_seconds = 1 intervalle int32 en secondes entre chaque interrogation du système de fichiers pour la nouvelle version du modèle
--tensorflow_session_parallelism = 0 int64 Nombre de threads à utiliser pour l'exécution d'une session Tensorflow. Configuré automatiquement par défaut. Notez que cette option est ignorée si --platform_config_file n'est pas vide.
--platform_config_file = "" string S'il n'est pas vide, lisez un prototypage ascii PlatformConfigMap à partir du nom de fichier fourni et utilisez cette configuration de plateforme à la place de la plateforme Tensorflow. (Si utilisé, --enable_batching est ignoré.)

Votre environnement de service est maintenant prêt à être utilisé. Quittez le conteneur et validez les modifications qu'il contient dans une image. Vous pouvez faire ça comme ça:

  • Appuyez sur [Cltr-p] + [Cltr-q] pour quitter le conteneur
  • Trouvez l'ID du conteneur:
# Trouver l'ID du conteneur
docker ps
NOM DES PORTS DE STATUT CRÉÉS PAR UN COMMAND D'IMAGE D'IDENTIFIANT
  • Valider les modifications:
# Valider les modifications
[POUR CPU]
docker commit $ {CONTAINER ID} $ USER / tensorflow-servant-devel-cpu
ou
[POUR GPU]
docker commit $ {CONTAINER ID} $ USER / tensorflow-servant-devel-gpu
  • Entrez à nouveau le conteneur:
docker exec -it $ {CONTAINER ID} / bin / bash

Remarque: pour que le conteneur de service TensorFlow puisse accéder aux GPU de votre système hôte, vous devez installer nvidia-docker sur votre système et exécuter le conteneur de la manière suivante:

nvidia-docker docker run -it -p 9000: 9000 $ USER / tensorflow-servant-devel-gpu / bin / bash

Vous pouvez ensuite vérifier votre utilisation du processeur graphique à l'intérieur du conteneur à l'aide de la commande nvidia-smi cmd.

Images Docker prédéfinies

Comme je l’ai vu sur un certain nombre de problèmes liés à Github (voir ressources), les utilisateurs sont incapables de compiler TensorFlow servant sur docker. J'ai donc des images de menu fixe prédéfinies pour la prise en charge du processeur et du processeur graphique.

Vous pouvez les trouver sur ma page Docker Hub ou vous pouvez afficher les images comme suit:

[POUR CPU]
docker pull gauravkaila / tf_serving_cpu
ou
[POUR GPU]
docker pull gauravkaila / tf_serving_gpu

3. Création d'un client pour demander au serveur de modèles s'exécutant dans le conteneur Docker d'inférence sur une image de test

Introduction rapide à gRPC (Google Remote Procedure Call) et aux tampons de protocole

gRPC (appel de procédure distant de Google) est le protocole RPC enveloppé par HTTP2 de Google. Cela permet à un client fonctionnant sur un ordinateur d'accéder à un ordinateur distant, via le réseau informatique, et d'appeler une «fonction» sur cet ordinateur distant comme si la fonction était locale par rapport au client.

TensorFlow servant utilise ce protocole pour servir des modèles d'inférence. Selon la documentation officielle,

Dans gRPC, une application client peut appeler directement des méthodes sur une application serveur sur une machine différente, comme s'il s'agissait d'un objet local, ce qui facilite la création d'applications et de services distribués.
architecture de gRPC

Ici, le serveur gRPC est notre conteneur docker qui exécute le service de service TensorFlow, et notre client est en python qui demande ce service par inférence. Cet article décrit le fonctionnement de RPC de manière très structurée.

Le gRPC utilise des tampons de protocole pour sérialiser des données structurées ainsi que pour définir les paramètres et renvoyer les réponses pour les méthodes appelables. Il est neutre sur le plan linguistique et sur la plate-forme. Il possède un langage structuré qui compile ensuite le code de sérialisation de transport dans la langue choisie pour l'inclure dans votre projet. Il transmet les données au format binaire, qui est plus petit et plus rapide que les bons vieux JSON et XML.

Créer le client

Une demande de service TensorFlow peut être de trois types:

  1. Classification: Utilise l'API RPC de classification qui accepte un tenseur d'entrée (par exemple, une image) et génère une classe et un score.
  2. Prédiction et régression: utilise l'API RPC de prédiction qui accepte un tenseur d'entrée (par exemple, une image) et génère plusieurs tenseurs tels que (pour la détection d'objet) des bounding_boxes, des classes, des scores, etc.

Comme le problème à résoudre ici est un problème de prédiction, nous utiliserons l'API RPC de prédiction. Pour cela, nous avons besoin du prédicteur protobuf disponible sur le github servant TensorFlow, et nous devons les convertir en notre code spécifique à la langue (c.-à-d. Python).

Vous pouvez le faire vous-même ou utiliser le moyen le plus simple et télécharger les fichiers python à partir de ce dépôt github. Nous allons utiliser cet objet protobuf pour créer une demande de prédiction dans notre client.

Modèle d'un client RPC de prévision

Le stub est un morceau de code utilisé pour convertir les paramètres lors d'un appel de procédure distante (RPC). Le client et le serveur étant assis dans des espaces adresse différents, le paramètre envoyé par le client au serveur (et inversement) doit être converti pour que l'ordinateur serveur distant perçoive le RPC comme un appel de fonction local. Le stub utilisé ici est le code généré à partir du protobuf prévu tel que décrit ci-dessus.

Lancement du service de service TensorFlow

Comme décrit dans la partie précédente, notre service de service TensorFlow s'exécutera dans un conteneur de menus fixes avec des ports ouverts au monde extérieur. En supposant que l'image de menu fixe est disponible, le conteneur peut être démarré comme suit:

$ docker run -it -d -P --name tf_serving_cpu -p 3000: 3000 gauravkaila / tf_serving_cpu

Ici, le port 3000 est ouvert sur le monde et le client peut accéder au service de gestion TensorFlow via ce port. Exportez le répertoire de modèles créé dans la première partie dans un dossier du conteneur:

$ docker cp / chemin / vers / modèle tf_serving_cpu: / chemin / vers / destination

Pour exécuter le service, ouvrez le conteneur et démarrez:

# Déplacer vers le répertoire / serveur
$ cd servant /
# Démarrer le service
$ bazel-bin / tensorflow_serving / model_servers / tensorflow_model_server
--port = 3000
--model_name = obj_det
--model_base_path = / chemin / vers / dest &> obj_det &

Assurez-vous que l'indicateur nom_modèle a le même nom que celui spécifié dans le client. La sortie est enregistrée dans obj_det. Si tout s'est bien passé, vous pourrez voir le résultat suivant lorsque vous tapez:

$ tail -f obj_det
tensorflow_serving / model_servers / main.cc: 288] Exécution de ModelServer à 0.0.0.0:3000…

Le modèle est en cours de préparation et est prêt à être utilisé par notre client.

Visualiser les cadres de sélection sur des images de test

Le but d'un modèle de détection d'objet est de visualiser les boîtes englobantes des objets localisés sur l'image. Afin de visualiser l'image finale avec les cadres de sélection, nous allons utiliser le fichier visualization_utils.py de l'API de détection d'objet TensorFlow.

Nous pouvons accéder aux sorties individuelles du résultat comme ceci:

boxes = result.outputs ['detection_boxes']. float_val
classes = resultat.outputs ["classes_de_reconnaissance"]. float_val
scores = result.outputs ['detection_scores']. float_val

Ceci retourne des objets protobuf qui peuvent être introduits dans le fichier visualization_utils.py:

image_vis = vis_util.visualize_boxes_and_labels_on_image_array (
    {input_image},
    np.reshape (cases, [100,4]),
    np.squeeze (classes) .astype (np.int32),
    np.squeeze (scores),
    category_index,
    use_normalized_coordinates = True,
    épaisseur_ligne = 8)

Le script client final ressemblera à ceci:

Sortie finale

En envoyant une image test d’une horloge, notre sortie finale devrait ressembler à ceci. Remarque: le modèle utilisé ici est un RCNN plus rapide, pré-formé sur un jeu de données COCO pour lequel le numéro de classe 85 correspond à une horloge.

les sorties {
clé: "boîtes de détection"
valeur {
dtype: DT_FLOAT
tensor_shape {
dim {
taille: 1
}
dim {
taille: 300
}
dim {
taille: 4
}
}
float_val: 0.24750074744224548
float_val: 0.17159424722194672
float_val: 0.9083144068717957
float_val: 0.797699511051178
les sorties {
clé: "classes de détection"
valeur {
dtype: DT_FLOAT
tensor_shape {
dim {
taille: 1
}
dim {
taille: 300
}
}
float_val: 85.0
les sorties {
clé: "détection_scores"
valeur {
dtype: DT_FLOAT
tensor_shape {
dim {
taille: 1
}
dim {
taille: 300
}
}
float_val: 0.9963208436965942

Qu'avons-nous réalisé

Nous avons commencé par un cas d'utilisation de détection d'objet pour démontrer la puissance du service TensorFlow. Nous avons exporté notre modèle formé vers un format attendu par le serveur TensorFlow, avons compilé le service TF à l'aide de Docker et avons créé un script client pouvant demander au serveur de modèles d'inférence.

Que réserve l'avenir

  1. En utilisant ce cas d'utilisation comme modèle, nous pouvons utiliser TensorFlow servant d'autres modèles de prévision et de classification.
  2. Nous pouvons utiliser la version GPU de TensorFlow pour obtenir une inférence plus rapide.
  3. Nous pouvons faire évoluer notre service en déployant plusieurs conteneurs docker exécutant le service de service TF.
  4. Vous pouvez entrer des images en lot au lieu d'envoyer une image par demande.

Ressources

  1. API de détection d'objet TensorFlow
  2. Ce blog génial sur TF-Serving

Problèmes Github:

  • https://github.com/tensorflow/serving/issues/542
  • https://github.com/tensorflow/serving/issues/590
  • https://github.com/tensorflow/serving/issues/410
  • https://github.com/tensorflow/serving/issues/672
  • https://github.com/tensorflow/serving/issues/659

À propos de l'auteur: Gaurav est un ingénieur en apprentissage automatique au Dock, le premier centre de recherche et d’innovation d’Accenture à Dublin, en Irlande. Ses intérêts incluent la construction de systèmes évolutifs d’apprentissage en profondeur pour les applications de vision par ordinateur. Trouvez plus sur gauravkaila.com