歡迎光臨
每天分享高質量文章

用Python/Keras/Flask/Docker在Kubernetes上部署深度學習模型

簡單到老闆也可以親自部署

 

這篇博文演示瞭如何透過Docker和Kubernetes,用Keras部署深度學習模型,並且透過Flask提供REST API服務。
這個模型並不是強壯到可供生產的模型,而是給Kubernetes新手一個嘗試的機會。我在Google Cloud上部署了這個模型,而且工作的很好。另外使用者可以用同樣的步驟重現以上功能。如果使用者擔心成本,Google提供了大量免費機會,這個演示基本沒有花錢。
為什麼用Kubernetes來做機器學習和資料科學

 

Kubernetes以及Cloud Native,正在席捲整個世界,我們已經感受到了。我們正處在一個由AI/Big Data/Cloud驅動的技術風暴中心,Kubernetes也正在加入這個中心。
但是如果從資料科學角度看並沒有使用Kubernetes的特殊原因。但是從部署,擴充套件和管理REST API方面來看,Kubernetes正在實現簡易化的特性。
步驟預覽:
  1. 在Google Cloud上建立使用者

  2. 使用Keras/Flask/Docker搭建一個REST API的機器學習模型服務

  3. 用Kubernetes部署上述模型

  4. enjoy it

 

步驟一:在Google Cloud上建立使用者
我在Google Compute Engine上建立了一個對外提供服務的容器化深度學習模型,當然Google平臺並不是必須的,只要能夠安裝Docker,隨便選擇平臺樣式。 
進入Google雲平臺,點選左側螢幕選擇Compute Engine,啟動Google Cloud VM。然後選擇“Create Instance”,可以看到已經執行的實體。 
下一步選擇計算資源。預設設定就足夠,因為只是演示,我選擇了4vCPUs和15G記憶體。 
選擇作業系統和磁碟大小。我選擇了CentOS 7,100G硬碟。建議磁碟大於10G,因為每個Docker容器有1G大小。
 
最後一步是配置允許HTTP/S工作的防火牆策略。建議選擇全部透明,以便減少麻煩。 
選擇“Create”,一切進展順利。 
步驟二:用Keras建立深度學習模型
SSH登入到虛機開始建立模型。最簡單方式就是點選虛機下方的SSH圖示,會在瀏覽器中開啟一個終端。
 
1、刪除預裝Docker
  1. sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
2、安裝最新Docker版本
  1. sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  2. sudo yum-config-manager add-repo https://download.docker.com/linux/centos/docker-ce.repo
  3. sudo yum install docker-ce
3、啟動容器執行測試指令碼
  1. sudo systemctl start docker
  2. sudo docker run hello-world
以下是正確輸出:
  1. Hello from Docker!
  2. This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.    (amd64) 3. The Docker daemon created a new container from that image which runs the    executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it    to your terminal
4、建立深度學習模型
這裡會借用Adrian Rosebrock的一個指令碼,他提供了使用Keras的深度學習模型並透過Flask提供服務的教程,可以從這裡[1]訪問。
這個模型可以直接執行。但是我修改了兩個配置資訊:
首先,改變了容器配置,預設flask使用127.0.0….作為預設服務地址,這會在容器內部執行時出現問題。我將它修改成0.0.0.0,這樣就可以實現對外和對內都可以工作的IP地址。
第二是關於Tensorflow的配置,可以從GitHub中找到這個問題描述[2]。
  1. global graph
  2. graph = tf.get_default_graph()
  3. ...
  4. with graph.as_default():
  5.    preds = model.predict(image)
執行指令碼,首先建立專用目錄:
  1. mkdir keras-app
  2. cd keras-app
建立app.py檔案: vim app.py
  1. # USAGE
  2. # Start the server:
  3. #   python app.py
  4. # Submit a request via cURL:
  5. #   curl -X POST -F image=@dog.jpg 'http://localhost:5000/predict'
  6. # import the necessary packages
  7. from keras.applications import ResNet50
  8. from keras.preprocessing.image import img_to_array
  9. from keras.applications import imagenet_utils
  10. from PIL import Image
  11. import numpy as np
  12. import flask
  13. import io
  14. import tensorflow as tf
  15. # initialize our Flask application and the Keras model
  16. app = flask.Flask(__name__)
  17. model = None
  18. def load_model():
  19.    # load the pre-trained Keras model (here we are using a model
  20.    # pre-trained on ImageNet and provided by Keras, but you can
  21.    # substitute in your own networks just as easily)
  22.    global model
  23.    model = ResNet50(weights="imagenet")
  24.    global graph
  25.    graph = tf.get_default_graph()
  26. def prepare_image(image, target):
  27.    # if the image mode is not RGB, convert it
  28.    if image.mode != "RGB":
  29.        image = image.convert("RGB")
  30.    # resize the input image and preprocess it
  31.    image = image.resize(target)
  32.    image = img_to_array(image)
  33.    image = np.expand_dims(image, axis=0)
  34.    image = imagenet_utils.preprocess_input(image)
  35.    # return the processed image
  36.    return image
  37. @app.route("/predict", methods=["POST"])
  38. def predict():
  39.    # initialize the data dictionary that will be returned from the
  40.    # view
  41.    data = {"success": False}
  42.    # ensure an image was properly uploaded to our endpoint
  43.    if flask.request.method == "POST":
  44.        if flask.request.files.get("image"):
  45.            # read the image in PIL format
  46.            image = flask.request.files["image"].read()
  47.            image = Image.open(io.BytesIO(image))
  48.            # preprocess the image and prepare it for classification
  49.            image = prepare_image(image, target=(224, 224))
  50.            # classify the input image and then initialize the list
  51.            # of predictions to return to the client
  52.            with graph.as_default():
  53.                preds = model.predict(image)
  54.                results = imagenet_utils.decode_predictions(preds)
  55.                data["predictions"] = []
  56.                # loop over the results and add them to the list of
  57.                # returned predictions
  58.                for (imagenetID, label, prob) in results[0]:
  59.                    r = {"label": label, "probability": float(prob)}
  60.                    data["predictions"].append(r)
  61.                # indicate that the request was a success
  62.                data["success"] = True
  63.    # return the data dictionary as a JSON response
  64.    return flask.jsonify(data)
  65. # if this is the main thread of execution first load the model and
  66. # then start the server
  67. if __name__ == "__main__":
  68.    print(("* Loading Keras model and Flask starting server..."
  69.        "please wait until server has fully started"))
  70.    load_model()
  71.    app.run(host='0.0.0.0')
5、建立requirements.txt檔案
為了在容器內執行程式碼,需要建立requirements.txt檔案,其中包括需要執行的包,例如keras、flask、一起其它相關包。這樣無論在哪裡執行程式碼,依賴包都保持一致。
  1. keras
  2. tensorflow
  3. flask
  4. gevent
  5. pillow
  6. requests
6、建立Dockerfile
  1. FROM python:3.6
  2. WORKDIR /app
  3. COPY requirements.txt /app
  4. RUN pip install -r ./requirements.txt
  5. COPY app.py /app
  6. CMD ["python", "app.py"]~
首先讓容器自行下載Python 3安裝image,然後讓Python呼叫pip安裝requirements.txt中的依賴包,最後執行python app.py。 
7、建立容器
  1. sudo docker build -t keras-app:latest .
在keras-app目錄下建立容器,後臺開始安裝Python 3 image等在步驟6中定義的操作。
8、執行容器
  1. sudo docker run -d -p 5000:5000 keras-app
用 sudo docker ps-a檢查容器狀態,應該看到如下輸出:
  1. [gustafcavanaugh@instance-3 ~]$ sudo docker ps -a
  2. CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS                    NAMES
  3. d82f65802166        keras-app           "python app.py"     About an hour ago   Up About an hour          0.0.0.0:5000->5000/tcp   nervous_northcutt
9、測試模型
現在可以測試此模型。用狗的照片作為輸入,可以傳回狗的品種。在Adrian的示例中都有該圖片,我們也使用它們,並儲存自工作目錄下,命名為dog.jpg。 
執行命令:
  1. curl -X POST -F image=@dog.jpg 'http://localhost:5000/predict'
應該得到如下輸出:
  1. {"predictions":[{"label":"beagle","probability":0.987775444984436},{"label":"pot","probability":0.0020967808086425066},{"label":"Cardigan","probability":0.001351703773252666},{"label":"Walker_hound","probability":0.0012711131712421775},{"label":"Brittany_spaniel","probability":0.0010085132671520114}],"success":true}
可以看到此模型成功將狗歸類為比格犬。下一步,我們用Kubernetes部署容器模型。
第三步:用Kubernetes部署模型
1、建立Docker Hub賬號
第一步需要在Docker hub上傳模型,以便使用Kubernetes集中管理。
2、登入到Docker Hub
sudo docker login, 登入到Docker Hub,應該看到如下輸出:
  1. Login Succeeded
3、給容器打標簽
給模型容器命名,上傳前先給它打標簽。
sudo docker images,應該得到容器的id,輸出如下:
  1. REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE keras-app           latest              ddb507b8a017        About an hour ago   1.61GB

 

打標簽命令如下:
  1. #Format
  2. sudo docker tag <your image id> <your docker hub id>/<app name>
  3. #My Exact Command - Make Sure To Use Your Inputs
  4. sudo docker tag ddb507b8a017 gcav66/keras-app
4、將模型容器上傳到Docker Hub
執行命令如下:
  1. #Format
  2. sudo docker push <your docker hub name>/<app-name>
  3. #My exact command
  4. sudo docker push gcav66/keras-app
5、建立Kubernetes叢集
在Google Cloud Home介面,選擇Kubernetes Engine。 
建立新叢集: 
選擇叢集內節點資源,因為要啟動三個節點(每個節點4vCPU和15G記憶體),至少需要12vCPU和45G記憶體。 
連線叢集,Google’s Kubernetes自動會在VM上安裝Kubernetes。 
在Kubernetes中執行容器:
  1. kubectl run keras-app --image=gcav66/keras-app --port 5000
確認是否Pod正確執行 kubectlgetpods,輸出如下:
  1. gustafcavanaugh@cloudshell:~ (basic-web-app-test)$ kubectl get pods
  2. NAME                         READY     STATUS    RESTARTS   AGE
  3. keras-app-79568b5f57-5qxqk   1/1       Running   0          1m
為了安全起見,將服務埠暴露與80埠:
  1. kubectl expose deployment keras-app --type=LoadBalancer --port 80 --target-port 5000
確認服務正常啟動: kubectlgetservice,正常輸出如下:
  1. gustafcavanaugh@cloudshell:~ (basic-web-app-test)$ kubectl get service
  2. NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
  3. keras-app    LoadBalancer   10.11.250.71   35.225.226.94   80:30271/TCP   4m
  4. kubernetes   ClusterIP      10.11.240.1              443/TCP        18m
提取cluster-IP,並將其合併於服務提交命令: curl-X POST-F image=@dog.jpg’http:///predict’,得到正常輸入如下:
  1. $ curl -X POST -F image=@dog.jpg 'http://35.225.226.94/predict'
  2. {"predictions":[{"label":"beagle","probability":0.987775444984436},{"label":"pot","probability":0.0020967808086425066},{"label":"Cardigan","probability":0.001351703773252666},{"label":"Walker_hound","probability":0.0012711131712421775},{"label":"Brittany_spaniel","probability":0.0010085132671520114}],"success":true}
第四步:總結
本文提供了一個使用Keras和Flask提供REST API服務的深度學習模型,並把它整合到容器內部,上傳到Docker Hub,並用Kubernetes部署,非常容易地實現了對外提供服務和訪問。
現在,我們可以對這個專案進行很多改進。對於初學者,可以改變本地Python服務到更加強壯的gunicorn;可以橫向擴充套件Kubernetes,實現服務擴容;也可以從頭搭建一套Kubernetes環境。
相關連結:

  1. https://blog.keras.io/building-a-simple-keras-deep-learning-rest-api.html

  2. https://github.com/tensorflow/tensorflow/issues/14356

原文連結:https://medium.com/analytics-vidhya/deploy-your-first-deep-learning-model-on-kubernetes-with-python-keras-flask-and-docker-575dc07d9e76

 

Kubernetes應用實戰培訓

Kubernetes應用實戰培訓將於2018年11月9日在北京開課,3天時間帶你係統學習Kubernetes本次培訓包括:容器特性、映象、網路;Docker特性、架構、元件、概念、Runtime;Docker安全;Docker實踐;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用物件、設計原則;Kubernetes的實踐、執行時、網路、外掛已經落地經驗;微服務架構、DevOps等,點選下方圖片檢視詳情。

    贊(0)

    分享創造快樂