Ce didacticiel montre comment utiliser les composants TensorFlow Serving exécutés dans des conteneurs Docker pour servir le modèle TensorFlow ResNet et comment déployer le cluster de service avec Kubernetes.
Pour en savoir plus sur TensorFlow Serving, nous vous recommandons le didacticiel de base TensorFlow Serving et le didacticiel avancé TensorFlow Serving .
Pour en savoir plus sur le modèle TensorFlow ResNet, nous vous recommandons de lire ResNet dans TensorFlow .
- La première partie obtient la configuration de votre environnement
- La partie 2 montre comment exécuter l'image de diffusion Docker locale
- La partie 3 montre comment déployer dans Kubernetes.
Partie 1 : Configuration
Avant de commencer, installez d'abord Docker .
Téléchargez le modèle sauvegardé ResNet
Effacons notre répertoire de modèles locaux au cas où nous en aurions déjà un :
rm -rf /tmp/resnet
Les réseaux résiduels profonds, ou ResNets en abrégé, ont fourni l'idée révolutionnaire des mappages d'identité afin de permettre la formation de réseaux neuronaux convolutifs très profonds. Pour notre exemple, nous allons télécharger un TensorFlow SavedModel de ResNet pour l'ensemble de données ImageNet.
# Download Resnet model from TF Hub
wget https://tfhub.dev/tensorflow/resnet_50/classification/1?tf-hub-format=compressed -o resnet.tar.gz
# Extract SavedModel into a versioned subfolder ‘123’
mkdir -p /tmp/resnet/123
tar xvfz resnet.tar.gz -C /tmp/resnet/123/
Nous pouvons vérifier que nous avons le SavedModel :
$ ls /tmp/resnet/*
saved_model.pb variables
Partie 2 : Exécuter dans Docker
Valider l’image pour le déploiement
Nous voulons maintenant prendre une image de diffusion et valider toutes les modifications dans une nouvelle image $USER/resnet_serving
pour le déploiement de Kubernetes.
Nous exécutons d’abord une image de service en tant que démon :
docker run -d --name serving_base tensorflow/serving
Ensuite, nous copions les données du modèle ResNet dans le dossier modèle du conteneur :
docker cp /tmp/resnet serving_base:/models/resnet
Enfin, nous engageons le conteneur à servir le modèle ResNet :
docker commit --change "ENV MODEL_NAME resnet" serving_base \
$USER/resnet_serving
Arrêtons maintenant le récipient de base de service
docker kill serving_base
docker rm serving_base
Démarrer le serveur
Démarrons maintenant le conteneur avec le modèle ResNet pour qu'il soit prêt à être servi, en exposant le port gRPC 8500 :
docker run -p 8500:8500 -t $USER/resnet_serving &
Interroger le serveur
Pour le client, nous devrons cloner le dépôt TensorFlow Serving GitHub :
git clone https://github.com/tensorflow/serving
cd serving
Interrogez le serveur avec resnet_client_grpc.py . Le client télécharge une image et l'envoie via gRPC pour être classée dans les catégories ImageNet .
tools/run_in_docker.sh python tensorflow_serving/example/resnet_client_grpc.py
Cela devrait donner un résultat comme :
outputs {
key: "classes"
value {
dtype: DT_INT64
tensor_shape {
dim {
size: 1
}
}
int64_val: 286
}
}
outputs {
key: "probabilities"
value {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1001
}
}
float_val: 2.41628322328e-06
float_val: 1.90121829746e-06
float_val: 2.72477100225e-05
float_val: 4.42638565801e-07
float_val: 8.98362372936e-07
float_val: 6.84421956976e-06
float_val: 1.66555237229e-05
...
float_val: 1.59407863976e-06
float_val: 1.2315689446e-06
float_val: 1.17812135159e-06
float_val: 1.46365800902e-05
float_val: 5.81210713335e-07
float_val: 6.59980651108e-05
float_val: 0.00129527016543
}
}
model_spec {
name: "resnet"
version {
value: 123
}
signature_name: "serving_default"
}
Ça marche! Le serveur a réussi à classer une image de chat !
Partie 3 : Déployer dans Kubernetes
Dans cette section, nous utilisons l'image de conteneur créée dans la partie 0 pour déployer un cluster de service avec Kubernetes dans Google Cloud Platform .
Connexion au projet GCloud
Ici, nous supposons que vous avez créé et connecté un projet gcloud nommé tensorflow-serving
.
gcloud auth login --project tensorflow-serving
Créer un cluster de conteneurs
Nous créons d’abord un cluster Google Kubernetes Engine pour le déploiement du service.
$ gcloud container clusters create resnet-serving-cluster --num-nodes 5
Ce qui devrait produire quelque chose comme :
Creating cluster resnet-serving-cluster...done.
Created [https://container.googleapis.com/v1/projects/tensorflow-serving/zones/us-central1-f/clusters/resnet-serving-cluster].
kubeconfig entry generated for resnet-serving-cluster.
NAME ZONE MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
resnet-serving-cluster us-central1-f 1.1.8 104.197.163.119 n1-standard-1 1.1.8 5 RUNNING
Définissez le cluster par défaut pour la commande gcloud conteneur et transmettez les informations d'identification du cluster à kubectl .
gcloud config set container/cluster resnet-serving-cluster
gcloud container clusters get-credentials resnet-serving-cluster
ce qui devrait donner lieu à :
Fetching cluster endpoint and auth data.
kubeconfig entry generated for resnet-serving-cluster.
Téléchargez l'image Docker
Transférons maintenant notre image vers Google Container Registry afin de pouvoir l'exécuter sur Google Cloud Platform.
Nous marquons d'abord l'image $USER/resnet_serving
en utilisant le format Container Registry et le nom de notre projet,
docker tag $USER/resnet_serving gcr.io/tensorflow-serving/resnet
Ensuite, nous configurons Docker pour utiliser gcloud comme assistant d'identification :
gcloud auth configure-docker
Ensuite, nous transférons l'image vers le registre,
docker push gcr.io/tensorflow-serving/resnet
Créer un déploiement et un service Kubernetes
Le déploiement se compose de 3 répliques du serveur resnet_inference
contrôlées par un déploiement Kubernetes . Les réplicas sont exposés en externe par un service Kubernetes avec un équilibreur de charge externe .
Nous les créons en utilisant l'exemple de configuration Kubernetes resnet_k8s.yaml .
kubectl create -f tensorflow_serving/example/resnet_k8s.yaml
Avec sortie :
deployment "resnet-deployment" created
service "resnet-service" created
Pour afficher l'état du déploiement et des pods :
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
resnet-deployment 3 3 3 3 5s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
resnet-deployment-bbcbc 1/1 Running 0 10s
resnet-deployment-cj6l2 1/1 Running 0 10s
resnet-deployment-t1uep 1/1 Running 0 10s
Pour afficher l'état du service :
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
resnet-service 10.239.240.227 104.155.184.157 8500/TCP 1m
Cela peut prendre un certain temps pour que tout soit opérationnel.
$ kubectl describe service resnet-service
Name: resnet-service
Namespace: default
Labels: run=resnet-service
Selector: run=resnet-service
Type: LoadBalancer
IP: 10.239.240.227
LoadBalancer Ingress: 104.155.184.157
Port: <unset> 8500/TCP
NodePort: <unset> 30334/TCP
Endpoints: <none>
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
1m 1m 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
L'adresse IP externe du service est répertoriée à côté de LoadBalancer Ingress.
Interroger le modèle
Nous pouvons désormais interroger le service à son adresse externe auprès de notre hôte local.
$ tools/run_in_docker.sh python \
tensorflow_serving/example/resnet_client_grpc.py \
--server=104.155.184.157:8500
outputs {
key: "classes"
value {
dtype: DT_INT64
tensor_shape {
dim {
size: 1
}
}
int64_val: 286
}
}
outputs {
key: "probabilities"
value {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1001
}
}
float_val: 2.41628322328e-06
float_val: 1.90121829746e-06
float_val: 2.72477100225e-05
float_val: 4.42638565801e-07
float_val: 8.98362372936e-07
float_val: 6.84421956976e-06
float_val: 1.66555237229e-05
...
float_val: 1.59407863976e-06
float_val: 1.2315689446e-06
float_val: 1.17812135159e-06
float_val: 1.46365800902e-05
float_val: 5.81210713335e-07
float_val: 6.59980651108e-05
float_val: 0.00129527016543
}
}
model_spec {
name: "resnet"
version {
value: 1538687457
}
signature_name: "serving_default"
}
Vous avez déployé avec succès le modèle ResNet servant de service dans Kubernetes !