本教學課程說明如何使用在 Docker 容器中執行的 TensorFlow Serving 元件,以提供 TensorFlow ResNet 模型,以及如何使用 Kubernetes 部署 Serving 叢集。
如要進一步瞭解 TensorFlow Serving,建議您參閱TensorFlow Serving 基本教學課程和TensorFlow Serving 進階教學課程。
如要進一步瞭解 TensorFlow ResNet 模型,建議您閱讀TensorFlow 中的 ResNet。
第 1 部分:設定
開始之前,請先安裝 Docker。
下載 ResNet SavedModel
讓我們清除本機模型目錄,以防先前已有目錄
rm -rf /tmp/resnet
深度殘差網路 (簡稱 ResNet) 提供了身分對應的突破性概念,以便訓練非常深度的卷積神經網路。在我們的範例中,我們將下載適用於 ImageNet 資料集的 ResNet TensorFlow SavedModel。
# 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/
我們可以驗證是否已安裝 SavedModel
$ ls /tmp/resnet/*
saved_model.pb variables
第 2 部分:在 Docker 中執行
提交映像檔以進行部署
現在我們要取得 Serving 映像檔,並提交所有變更至新的映像檔 $USER/resnet_serving
,以進行 Kubernetes 部署。
首先,我們以精靈模式執行 Serving 映像檔
docker run -d --name serving_base tensorflow/serving
接下來,我們將 ResNet 模型資料複製到容器的模型資料夾
docker cp /tmp/resnet serving_base:/models/resnet
最後,我們提交容器以提供 ResNet 模型
docker commit --change "ENV MODEL_NAME resnet" serving_base \
$USER/resnet_serving
現在讓我們停止 Serving 基礎容器
docker kill serving_base
docker rm serving_base
啟動伺服器
現在讓我們啟動搭載 ResNet 模型的容器,使其準備好提供服務,並公開 gRPC 埠 8500
docker run -p 8500:8500 -t $USER/resnet_serving &
查詢伺服器
對於用戶端,我們需要複製 TensorFlow Serving GitHub 存放區
git clone https://github.com/tensorflow/serving
cd serving
使用 resnet_client_grpc.py 查詢伺服器。用戶端會下載圖片,並透過 gRPC 傳送以分類為 ImageNet 類別。
tools/run_in_docker.sh python tensorflow_serving/example/resnet_client_grpc.py
這應該會產生如下輸出
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"
}
成功了!伺服器成功分類了貓咪圖片!
第 3 部分:在 Kubernetes 中部署
在本節中,我們將使用第 0 部分中建構的容器映像檔,透過 Kubernetes 在 Google Cloud Platform 中部署 Serving 叢集。
GCloud 專案登入
在這裡,我們假設您已建立並登入名為 tensorflow-serving
的 gcloud 專案。
gcloud auth login --project tensorflow-serving
建立容器叢集
首先,我們建立 Google Kubernetes Engine 叢集以進行服務部署。
$ gcloud container clusters create resnet-serving-cluster --num-nodes 5
應該會輸出類似如下的內容
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
設定 gcloud 容器指令的預設叢集,並將叢集憑證傳遞至 kubectl。
gcloud config set container/cluster resnet-serving-cluster
gcloud container clusters get-credentials resnet-serving-cluster
應該會產生
Fetching cluster endpoint and auth data.
kubeconfig entry generated for resnet-serving-cluster.
上傳 Docker 映像檔
現在讓我們將映像檔推送至 Google Container Registry,以便我們可以在 Google Cloud Platform 上執行。
首先,我們使用 Container Registry 格式和專案名稱標記 $USER/resnet_serving
映像檔,
docker tag $USER/resnet_serving gcr.io/tensorflow-serving/resnet
接下來,我們設定 Docker 以使用 gcloud 作為憑證輔助程式
gcloud auth configure-docker
接下來,我們將映像檔推送至 Registry,
docker push gcr.io/tensorflow-serving/resnet
建立 Kubernetes Deployment 和 Service
部署包含 3 個 resnet_inference
伺服器副本,由 Kubernetes Deployment 控制。這些副本透過 Kubernetes Service 以及 外部負載平衡器 從外部公開。
我們使用範例 Kubernetes 設定 resnet_k8s.yaml 建立它們。
kubectl create -f tensorflow_serving/example/resnet_k8s.yaml
輸出
deployment "resnet-deployment" created
service "resnet-service" created
如要查看 Deployment 和 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
如要查看服務狀態
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
resnet-service 10.239.240.227 104.155.184.157 8500/TCP 1m
可能需要一段時間才能讓所有項目都啟動並執行。
$ 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
服務外部 IP 位址會列在 LoadBalancer Ingress 旁邊。
查詢模型
我們現在可以從本機主機查詢位於外部位址的服務。
$ 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"
}
您已成功在 Kubernetes 中部署 ResNet 模型 Serving 作為服務!