Questo tutorial mostra come utilizzare i componenti TensorFlow Serving in esecuzione nei contenitori Docker per servire il modello TensorFlow ResNet e come distribuire il cluster di servizio con Kubernetes.
Per ulteriori informazioni su TensorFlow Serving, consigliamo il tutorial di base di TensorFlow Serving e il tutorial avanzato di TensorFlow Serving .
Per saperne di più sul modello TensorFlow ResNet, ti consigliamo di leggere ResNet in TensorFlow .
- La parte 1 fornisce la configurazione dell'ambiente
- La parte 2 mostra come eseguire l'immagine di servizio Docker locale
- La parte 3 mostra come eseguire la distribuzione in Kubernetes.
Parte 1: installazione
Prima di iniziare, installa Docker .
Scarica il modello salvato ResNet
Cancellamo la directory dei nostri modelli locali nel caso ne avessimo già una:
rm -rf /tmp/resnet
Le reti residue profonde, o ResNet in breve, hanno fornito l'idea rivoluzionaria delle mappature di identità per consentire l'addestramento di reti neurali convoluzionali molto profonde. Per il nostro esempio, scaricheremo un TensorFlow SavedModel di ResNet per il set di dati 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/
Possiamo verificare di avere il SavedModel:
$ ls /tmp/resnet/*
saved_model.pb variables
Parte 2: esecuzione in Docker
Commetti l'immagine per la distribuzione
Ora vogliamo prendere un'immagine di servizio ed eseguire il commit di tutte le modifiche in una nuova immagine $USER/resnet_serving
per la distribuzione Kubernetes.
Per prima cosa eseguiamo un'immagine di servizio come demone:
docker run -d --name serving_base tensorflow/serving
Successivamente, copiamo i dati del modello ResNet nella cartella del modello del contenitore:
docker cp /tmp/resnet serving_base:/models/resnet
Infine impegniamo il contenitore a servire il modello ResNet:
docker commit --change "ENV MODEL_NAME resnet" serving_base \
$USER/resnet_serving
Ora fermiamo il contenitore base di servizio
docker kill serving_base
docker rm serving_base
Avviare il server
Ora avviamo il contenitore con il modello ResNet in modo che sia pronto per essere servito, esponendo la porta gRPC 8500:
docker run -p 8500:8500 -t $USER/resnet_serving &
Interroga il server
Per il client, dovremo clonare il repository GitHub di TensorFlow Serving:
git clone https://github.com/tensorflow/serving
cd serving
Interroga il server con resnet_client_grpc.py . Il client scarica un'immagine e la invia tramite gRPC per la classificazione in categorie ImageNet .
tools/run_in_docker.sh python tensorflow_serving/example/resnet_client_grpc.py
Ciò dovrebbe comportare un output come:
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"
}
Funziona! Il server classifica con successo l'immagine di un gatto!
Parte 3: distribuzione in Kubernetes
In questa sezione utilizziamo l'immagine del contenitore creata nella Parte 0 per distribuire un cluster di servizio con Kubernetes in Google Cloud Platform .
Accesso al progetto GCloud
Qui presupponiamo che tu abbia creato e effettuato l'accesso a un progetto gcloud denominato tensorflow-serving
.
gcloud auth login --project tensorflow-serving
Crea un cluster di contenitori
Per prima cosa creiamo un cluster Google Kubernetes Engine per la distribuzione del servizio.
$ gcloud container clusters create resnet-serving-cluster --num-nodes 5
Che dovrebbe produrre qualcosa come:
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
Imposta il cluster predefinito per il comando del contenitore gcloud e passa le credenziali del cluster a kubectl .
gcloud config set container/cluster resnet-serving-cluster
gcloud container clusters get-credentials resnet-serving-cluster
che dovrebbe risultare in:
Fetching cluster endpoint and auth data.
kubeconfig entry generated for resnet-serving-cluster.
Carica l'immagine Docker
Ora eseguiamo il push della nostra immagine su Google Container Registry in modo da poterla eseguire su Google Cloud Platform.
Per prima cosa tagghiamo l'immagine $USER/resnet_serving
utilizzando il formato Container Registry e il nome del nostro progetto,
docker tag $USER/resnet_serving gcr.io/tensorflow-serving/resnet
Successivamente, configuriamo Docker per utilizzare gcloud come assistente per le credenziali:
gcloud auth configure-docker
Successivamente inseriamo l'immagine nel registro,
docker push gcr.io/tensorflow-serving/resnet
Crea distribuzione e servizio Kubernetes
La distribuzione è composta da 3 repliche del server resnet_inference
controllato da una distribuzione Kubernetes . Le repliche vengono esposte esternamente da un servizio Kubernetes insieme a un sistema di bilanciamento del carico esterno .
Li creiamo utilizzando l'esempio di configurazione Kubernetes resnet_k8s.yaml .
kubectl create -f tensorflow_serving/example/resnet_k8s.yaml
Con uscita:
deployment "resnet-deployment" created
service "resnet-service" created
Per visualizzare lo stato della distribuzione e dei pod:
$ 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
Per visualizzare lo stato del servizio:
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
resnet-service 10.239.240.227 104.155.184.157 8500/TCP 1m
Potrebbe volerci un po' di tempo prima che tutto sia attivo e funzionante.
$ 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'indirizzo IP esterno del servizio è elencato accanto a LoadBalancer Ingress.
Interroga il modello
Ora possiamo interrogare il servizio al suo indirizzo esterno dal nostro host locale.
$ 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"
}
Hai distribuito con successo il modello ResNet che funge da servizio in Kubernetes!