השתמש ב- 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

רשתות שיוריות עמוקות, או בקיצור ResNets, סיפקו את רעיון פריצת הדרך של מיפוי זהויות על מנת לאפשר אימון של רשתות עצביות קונבולוציוניות עמוקות מאוד. לדוגמה שלנו, נוריד 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.

ראשית אנו מריצים תמונת הגשה בתור דמון:

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: 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.

העלה את תמונת Docker

כעת נדחוף את התמונה שלנו ל- 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

לאחר מכן אנו דוחפים את התמונה לרישום,

docker push gcr.io/tensorflow-serving/resnet

צור פריסה ושירות של Kubernetes

הפריסה מורכבת מ-3 העתקים של שרת resnet_inference הנשלט על ידי פריסת Kubernetes . ההעתקים נחשפים חיצונית על ידי שירות Kubernetes יחד עם מאזן עומסים חיצוני .

אנו יוצרים אותם באמצעות הדוגמה של 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!