Use TensorFlow Serving with Kubernetes

导语:
    本文是 tensorflow 手册翻译系列的第六篇。
    本篇描述了如何使用在 Docker 容器中运行的 TensorFlow Serving 组件为TensorFlow ResNet 模型提供服务以及如何使用 Kubernetes 部署服务集群。

目录

  • Part 1: 安装
    • 下载 ResNet 保存模型
  • Part 2: 在 Docker 中进行运行
    • 为部署提交镜像
    • 启动服务
    • 查询服务
  • Part 3: 在 kubernetes 中进行部署
    • 云服务项目登录
    • 创建容器集群
    • 上传 Docker 镜像
    • 创建 Kubernetes 的部署和服务
    • 查询模型

本教程展示了如何使用在Docker容器中运行的TensorFlow Serving组件为TensorFlow ResNet模型提供服务以及如何使用Kubernetes部署服务集群。

要了解有关TensorFlow Serving的更多信息,我们推荐TensorFlow Serving基本教程和TensorFlow Serving高级教程。

要了解有关TensorFlow ResNet模型的更多信息,建议阅读TensorFlow中的ResNet。

第1部分进行环境设置 第2部分展示了如何运行本地Docker服务映像 第3部分展示了如何在Kubernetes中进行部署。

第1部分:设置 在开始之前,请先安装Docker。

下载ResNet SavedModel 如果我们已有一个本地模型目录,请清除它:

rm -rf /tmp/resnet

深度残差网络(简称ResNets)提供了身份映射的突破性思想,以便能够训练非常深的卷积神经网络。 对于我们的示例,我们将为ImageNet数据集下载ResNet的TensorFlow SavedModel。

mkdir /tmp/resnet
curl -s http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NHWC_jpg.tar.gz | \
tar --strip-components=2 -C /tmp/resnet -xvz

我们可以验证是否具有SavedModel:

$ ls /tmp/resnet/*
saved_model.pb  variables

第2部分:在Docker中运行 提交映像以进行部署 现在,我们要获取一个服务映像,并将所有更改提交到新映像$ USER / resnet_serving中,以进行Kubernetes部署。

首先,我们将服务图片作为守护程序运行:

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

现在,让我们停止投放基本容器

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: 1538687457
  }
  signature_name: "serving_default"
}

有用!服务器成功分类了猫图像!

第3部分:在Kubernetes中部署 在本节中,我们使用第0部分中构建的容器映像在Google Cloud Platform中使用Kubernetes部署服务集群。

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

接下来,我们将图像推送到注册表,

gcloud docker -- push gcr.io/tensorflow-serving/resnet

创建Kubernetes部署和服务 该部署包含由Kubernetes部署控制的3个resnet_inference服务器副本。 Kubernetes服务与外部负载均衡器在外部公开副本。

我们使用示例Kubernetes配置resnet_k8s.yaml创建它们。

kubectl create -f tensorflow_serving/example/resnet_k8s.yaml

输出:

deployment "resnet-deployment" created
service "resnet-service" created

要查看部署和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入口旁边列出。

查询模型 现在,我们可以从本地主机在其外部地址查询服务。

$ 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模型作为服务!

PREVIOUSCreating a new kind of servable
NEXTBuilding Standard TensorFlow ModelServer