ใช้ TensorFlow Serving กับ Kubernetes

บทช่วยสอนนี้แสดงวิธีใช้ส่วนประกอบ TensorFlow Serving ที่ทำงานอยู่ในคอนเทนเนอร์ Docker เพื่อให้บริการโมเดล TensorFlow ResNet และวิธีการปรับใช้คลัสเตอร์การให้บริการด้วย Kubernetes

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ TensorFlow Serving เราขอแนะนำ บทช่วยสอนขั้นพื้นฐานของ TensorFlow Serving และ บทช่วยสอนขั้นสูงของ TensorFlow Serving

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับโมเดล TensorFlow ResNet เราขอแนะนำให้อ่าน ResNet ใน TensorFlow

  • ส่วนที่ 1 รับการตั้งค่าสภาพแวดล้อมของคุณ
  • ส่วนที่ 2 แสดงวิธีการเรียกใช้อิมเมจที่ให้บริการ Docker ในเครื่อง
  • ส่วนที่ 3 แสดงวิธีการปรับใช้ใน Kubernetes

ส่วนที่ 1: การตั้งค่า

ก่อนที่จะเริ่มต้น ให้ติดตั้ง Docker ก่อน

ดาวน์โหลด ResNet SavedModel

มาล้างไดเร็กทอรีโมเดลในเครื่องของเราในกรณีที่เรามีอยู่แล้ว:

rm -rf /tmp/resnet

Deep Residual Network หรือเรียกสั้นๆ ว่า ResNets ทำให้เกิดแนวคิดที่ก้าวหน้าในการแมปข้อมูลประจำตัว เพื่อให้สามารถฝึกอบรมโครงข่ายประสาทเทียมแบบ Convolutional ที่ลึกมากได้ สำหรับตัวอย่างของเรา เราจะดาวน์โหลด TensorFlow SavedModel ของ ResNet สำหรับชุดข้อมูล 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/

เราสามารถตรวจสอบได้ว่าเรามี SavedModel:

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

ส่วนที่ 2: การทำงานใน Docker

คอมมิตอิมเมจสำหรับการปรับใช้

ตอนนี้เราต้องการนำอิมเมจที่ให้บริการและ ยอมรับ การเปลี่ยนแปลงทั้งหมดกับอิมเมจใหม่ $USER/resnet_serving สำหรับการปรับใช้ Kubernetes

ขั้นแรกเราเรียกใช้อิมเมจที่ให้บริการเป็น daemon:

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 &

สอบถามเซิร์ฟเวอร์

สำหรับลูกค้า เราจะต้องโคลน repo 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

เข้าสู่ระบบโครงการ GCloud

ที่นี่เราถือว่าคุณได้สร้างและเข้าสู่ระบบโปรเจ็กต์ gcloud ชื่อ tensorflow-serving

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.

อัปโหลดภาพนักเทียบท่า

ตอนนี้เรามาส่งอิมเมจของเราไปที่ Google Container Registry เพื่อให้เราสามารถรันบน Google Cloud Platform ได้

อันดับแรก เราจะแท็กอิมเมจ $USER/resnet_serving โดยใช้รูปแบบ Container Registry และชื่อโปรเจ็กต์ของเรา

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

การปรับใช้ประกอบด้วย 3 เรพลิกาของเซิร์ฟเวอร์ resnet_inference ที่ควบคุมโดย Kubernetes Deployment แบบจำลองจะถูกเปิดเผยภายนอกโดย บริการ Kubernetes พร้อมด้วย External Load Balancer

เราสร้างมันขึ้นมาโดยใช้ตัวอย่าง Kubernetes config resnet_k8s.yaml

kubectl create -f tensorflow_serving/example/resnet_k8s.yaml

ด้วยเอาต์พุต:

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

วิธีดูสถานะของการทำให้ใช้งานได้และพ็อด:

$ 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"
}

คุณปรับใช้โมเดล ResNet ที่ให้บริการเป็นบริการใน Kubernetes สำเร็จแล้ว!