教程|如何使用 Kubernetes 輕鬆部署深度學習模型

選自 Medium

機器之心編譯

參與:Geek AI、路

本文介紹瞭如何使用 Python、Keras、Flask 和 Docker 在 Kubernetes 上部署深度學習模型。

教程|如何使用 Kubernetes 轻松部署深度学习模型

這簡直太容易了,連你的老闆都能做到!

本文展示瞭如何用 Keras 構建深度學習模型的簡單示例,將其作為一個用 Flask 實現的 REST API,並使用 Docker 和 Kubernetes 進行部署。本文給出的並不是一個魯棒性很好的能夠用於生產的示例,它只是為那些聽說過 Kubernetes 但沒有動手嘗試過的人編寫的快速上手指南。

為此,我在這個過程的每個步驟中都使用了 Google Cloud。這樣做的原因很簡單——我並不想在我的 Windows 10 家用筆記本上安裝 Docker 和 Kubernetes。而谷歌雲能很好地支持這二者的工作。此外,你可以準確地按照我接下來所使用的規範流程進行操作,這可以幫助你更容易地復現我的步驟。而且,你也不用擔心實踐這篇文章的成本。谷歌為新賬戶提供了幾百美金的免費額度,而實現本文示例所需的費用只不過是九牛一毛。

為什麼要將 Kubernetes 用於機器學習和數據科學?

Kubernetes 及其從屬的流行概念「雲原生」(cloud-native)正席捲全球。別擔心——你有所懷疑是對的。我們都見證過鋪天蓋地的「人工智能」、「大數據」、「雲計算」等術語的技術泡沫。Kubernetes 是否也會發生相同的情況,還有待觀察。

但是,如今許多對數據科學一知半解的人會誤導我們,所以我對轉而使用 Kubernetes 的原因並不感興趣也不理解。我的動機很簡單,我希望部署、擴展、管理一個能夠提供預測能力的 REST API。在下文中,你會看到 Kubernetes 會使這一切非常容易。

讓我們開始吧!

大綱

1. 使用 Google Cloud 創建你的環境。

2. 使用 Keras、Flask 和 Docker 提供深度學習模型接口。

3. 使用 Kubernetes 部署上述模型。

4. 享受你所掌握的新知識吧!

步驟 1:使用 Google Cloud 創建你的環境

我在谷歌計算引擎上使用一個小型虛擬機來構建、部署、docker 化深度學習模型。你並不一定非要這麼做。我曾試過在我的 Windows 10 筆記本上安裝最新版本的 Docker CE(Community Edition),但是失敗了。因此我決定直接使用免費的 Google Cloud 額度,這比弄清如何安裝 Docker 能更好地利用我的時間。你可以選擇是否要這樣做。

教程|如何使用 Kubernetes 轻松部署深度学习模型

要想啟動一臺 Google Cloud 虛擬機,你可以打開屏幕左側的工具欄。選擇 Compute Engine。接著,選擇「Create Instance」。如下圖所示,我已經擁有了一個正在工作的虛擬機實例。

教程|如何使用 Kubernetes 轻松部署深度学习模型

下一步,你需要選擇你想要使用的計算規模。默認的(最便宜的)機器設置也可以很好地工作,但是考慮到我們最多隻需要使用這個虛擬機大約 1 小時,我選擇了內存為 15GB 的 4vCPU 配置。

教程|如何使用 Kubernetes 轻松部署深度学习模型

接下來,我將選擇要使用的操作系統和磁盤空間。選擇「Boot Disk」來編輯默認值。這裡我選擇了 Centos 7 作為操作系統,並將磁盤的大小從 10GB 增加到了 100GB。實際上,並不一定要像我一樣選擇 Centos 操作系統。但是,我建議將磁盤大小增加到 10GB 以上,因為我們創建的每個 Docker 容器的大小都大約為 1GB。

教程|如何使用 Kubernetes 轻松部署深度学习模型

創建虛擬機的最後一步是設置防火牆允許使用 HTTP/S。誠然,我並不知道是否需要這個步驟。在部署 Kubernetes 之前,我將展示如何編輯防火牆設置以在虛擬機上測試我們的 API。因此,僅僅查看這些對話框是不夠的,我們還有更多的工作要做。以前我並沒有查看這些對話框,現在我重新試試按照這個教程去做。

教程|如何使用 Kubernetes 轻松部署深度学习模型

我並不確定是否需要此步驟。

現在單擊「Creat」按鈕。很好,困難的部分基本上已經完成了。

教程|如何使用 Kubernetes 轻松部署深度学习模型

步驟 2:使用 Keras 構建深度學習模型

現在,讓我們使用 SSH 連接到虛擬機,並開始構建模型。最簡單的方法是單擊下圖所示的虛擬機旁邊的 SSH 圖標。這個操作會在你的瀏覽器中打開一個終端。

教程|如何使用 Kubernetes 轻松部署深度学习模型

1. 卸載已有的 Docker 版本

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

請注意,如果你使用的操作系統不是 Centos 7,指令可能不同。

2. 安裝最新版 Docker

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager — add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce

3. 啟動 Docker 並運行測試腳本

sudo systemctl start docker
sudo docker run hello-world

如果你看到下圖所示的返回結果,你就完成了 Docker 的部署。

Hello from Docker!
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 寫的腳本。Adrian 寫了一篇很棒的教程,關於如何利用 Keras 構建深度學習模型並使用 Flask 部署它。教程參見:https://blog.keras.io/building-a-simple-keras-deep-learning-rest-api.html

我們需要對 Adrian 的腳本進行兩處關鍵的修改,才能使其運行。如果你不關心 Docker 和 TensorFlow 的技術細節,請跳過下面兩段。

我們要修改的第一個地方與 Docker 有關。在本地運行應用程序時,默認的 flask behavior 會在本地主機(127.0.0...)上提供應用程序服務。在 Docker 容器內運行時,這可能會產生一些問題。解決的方法很簡單。當調用 app.run 時,使用 app.run(host='0.0.0.0') 將 URL 設置為 0.0.0.0。這樣,我們的應用就可以在本地主機和外部 IP 上同時使用了。

下一個問題涉及 TensorFlow。當我運行 Adrian 的原始腳本時,我無法成功調用模型。於是,我閱讀了下面這個 Github issue(https://github.com/tensorflow/tensorflow/issues/14356),並對代碼進行了修改。

global graph
graph = tf.get_default_graph
...
with graph.as_default:
preds = model.predict(image)

說實話,我也不知道為什麼這樣做就行得通。但它確實做到了。所以就這樣運行吧。

首先,創建一個名為 keras-app 的新文件夾,並將當前的路徑移動到該文件夾中。

mkdir keras-app
cd keras-app

現在我們創建一個名為 app.py 的文件。你可以自己選擇要使用的編輯器。我在這裡選用 vim,輸入下面的指令創建並打開 app.py:

vim app.py

打開文件後,敲擊鍵盤上的「i」鍵,進入插入模式。現在你可以把下面的代碼粘貼進去:

# USAGE
# Start the server:
# python app.py
# Submit a request via cURL:
# curl -X POST -F [email protected] 'http://localhost:5000/predict'

# import the necessary packages
from keras.applications import ResNet50
from keras.preprocessing.image import img_to_array
from keras.applications import imagenet_utils
from PIL import Image
import numpy as np
import flask
import io
import tensorflow as tf

# initialize our Flask application and the Keras model
app = flask.Flask(__name__)
model = None

def load_model:
# load the pre-trained Keras model (here we are using a model
# pre-trained on ImageNet and provided by Keras, but you can
# substitute in your own networks just as easily)
global model
model = ResNet50(weights="imagenet")
global graph
graph = tf.get_default_graph

def prepare_image(image, target):
# if the image mode is not RGB, convert it
if image.mode != "RGB":
image = image.convert("RGB")

# resize the input image and preprocess it
image = image.resize(target)
image = img_to_array(image)
image = np.expand_dims(image, axis=0)

image = imagenet_utils.preprocess_input(image)

# return the processed image
return image

@app.route("/predict", methods=["POST"])
def predict:
# initialize the data dictionary that will be returned from the
# view
data = {"success": False}

# ensure an image was properly uploaded to our endpoint
if flask.request.method == "POST":
if flask.request.files.get("image"):
# read the image in PIL format
image = flask.request.files["image"].read
image = Image.open(io.BytesIO(image))

# preprocess the image and prepare it for classification
image = prepare_image(image, target=(224, 224))

# classify the input image and then initialize the list
# of predictions to return to the client
with graph.as_default:
preds = model.predict(image)
results = imagenet_utils.decode_predictions(preds)
data["predictions"] =

# loop over the results and add them to the list of
# returned predictions
for (imagenetID, label, prob) in results[0]:
r = {"label": label, "probability": float(prob)}
data["predictions"].append(r)

# indicate that the request was a success
data["success"] = True

# return the data dictionary as a JSON response
return flask.jsonify(data)

# if this is the main thread of execution first load the model and
# then start the server
if __name__ == "__main__":
print(("* Loading Keras model and Flask starting server..."
"please wait until server has fully started"))
load_model
app.run(host='0.0.0.0')

當你複製以上代碼後,敲擊「Esc」鍵退出插入模式。

然後輸入 :x,保存並關閉文件。

5. 創建一個 requirements.txt 文件

現在回到正題。我們將在 Docker 容器中運行這段代碼。為了做到這一點,我們首先要創建一個 requirements.txt 文件。這個文件將包含代碼需要運行的程序包(如 keras、flask 等)。這樣一來,無論我們將 Docker 容器裝載在哪裡,底層的服務器都能夠安裝代碼所需的依賴。

keras
tensorflow
flask
gevent
pillow
requests

6. 創建 Dockerfile

很好!現在讓我們創建 Dockerfile。這是 Docker 將要讀取的文件,用它來構建和運行我們的項目。

FROM python:3.6
WORKDIR /app
COPY requirements.txt /app
RUN pip install -r ./requirements.txt
COPY app.py /app
CMD ["python", "app.py"]~

現在,我們正引導 Docker 下載一個 Python 3 的基礎鏡像。然後,要求 Docker 使用 Python 程序包管理器 pip 安裝 requirements.txt 文件中詳細指定的包。

接著,我們讓 Docker 通過 python app.py 指令運行我們的腳本。

7. 創建 Docker 容器

目前一切進展順利,現在讓我們構建並測試我們的應用程序。

為了構建我們的 Docker 容器,我們需要運行如下指令:

sudo docker build -t keras-app:latest .

該指令將引導 Docker 為我們當前工作空間的文件夾 keras-app 中的代碼構建一個容器。

這個指令需要一到兩分鐘才能運行完成。在此過程中,Docker 會下載一個 python 3.6 的鏡像並且安裝 requirements.txt 中列出的包。

8. 運行 Docker 容器

現在,讓我們運行 Docker 容器來測試我們的應用程序。

 
sudo docker run -d -p 5000:5000 keras-app

注:通過上面的指令中的數字 5000:5000,我們告訴 Docker 讓端口 5000 處於外部可用狀態,並把我們的本地應用程序指向該端口(它也在端口 5000 上本地運行)。

你可以通過運行 sudo docker ps -a 查看 Docker 容器的狀態。你應該看到如下圖所示的結果:

[gustafcavanaugh@instance-3 ~]$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
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 的 repo 中,他提供了一個示例圖片,我們在這裡也將使用它。

教程|如何使用 Kubernetes 轻松部署深度学习模型

在終端中運行:

curl -X POST -F [email protected] 'http://localhost:5000/predict'

確保你當前的文件夾中有狗狗的圖片「dog.jpg」(或提供正確的文件路徑),你會看到下面的運行結果:

{"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 部署其服務、用 Docker 將其封裝了起來。至此,我們已經完成了困難的部分。現在讓我們用 Kubernetes 部署該容器。

步驟 3:用 Kubernetes 部署我們的模型

1. 創建一個 Docker Hub 賬戶(如果你沒有的話)

我們要做的第一件事是將模型上傳到 Docker Hub 上。如果你還沒有 Docker 賬戶,請創建一個,別擔心,這是免費的。我們這樣做的原因是,我們不會將容器物理移動到 Kubernetes 集群上,而是引導 Kubernetes 在集中託管服務器(即 Docker Hub)上安裝我們的容器。

2. 登錄 Docker Hub 賬戶

創建好 Docker Hub 賬戶後,你可以通過 sudo docker login 指令從命令行登錄。你需要提供用戶名、密碼,就像你登錄網站一樣。

如果你看到下面的信息:

Login Succeeded

那麼你就成功登錄了。現在讓我們進行下一步。

3. 對容器命名

在上傳容器之前,我們需要為容器打標籤。你可以將此步驟看做為容器命名。

首先,運行 sudo docker images,並定位 keras-app 容器的鏡像 id。

輸出應該如下所示:

REPOSITORY TAG IMAGE ID CREATED SIZE keras-app latest ddb507b8a017 About an hour ago 1.61GB

現在,我們可以為 keras-app 打標籤了。請務必遵循我的格式,並將鏡像 id 和 docker hub id 的值替換為你自己指定的值。

#Format
sudo docker tag /
#My Exact Command - Make Sure To Use Your Inputs
sudo docker tag ddb507b8a017 gcav66/keras-app

4. 將容器 push 到 Docker Hub 上

現在可以 push 我們的容器了。在 shell 中運行以下行:

#Format
sudo docker push /
#My exact command
sudo docker push gcav66/keras-app

現在,如果你返回到 Docker Hub 網站,你就可以看到你的 keras-app repo 了。很好,接下來,我們將進入最後一步。

5. 創建一個 Kubernetes 集群

在 Google Cloud 的主頁上選擇 Kubernetes Engine:

教程|如何使用 Kubernetes 轻松部署深度学习模型
教程|如何使用 Kubernetes 轻松部署深度学习模型

接下來,我們將自定義該集群中節點的規模。我選擇了內存為 15GB、4vCPU 的配置。你可以在更小的集群上進行嘗試。請記住,默認設置包含 3 個節點,所以整個集群會擁有 3 倍於你所選擇的資源(即,在本例中為 45GB 內存)。我在這裡偷個懶,選擇了更大的規模,這樣我們的 Kubernetes 集群不會運行太長時間。

教程|如何使用 Kubernetes 轻松部署深度学习模型

接著,只需點擊 Creat。等上一兩分鐘,你的集群就能運轉了。

現在讓我們連接到集群。點擊 Run in Cloud Shell,就可以為 Kubernetes 集群提供控制檯。請注意,這是虛擬機中的一個單獨 shell 環境,你在這裡可以創建並測試 Docker 容器。我們可以在虛擬機上安裝 Kubernetes,谷歌的 Kubernetes 服務會自動為我們完成這個步驟。

教程|如何使用 Kubernetes 轻松部署深度学习模型

現在,在 Kubernetes 上運行我們的 docker 容器。請注意,鏡像標籤僅指向我們在 Docker Hub 上託管的 docker 鏡像。此外,我們通過——port 指定我們想在端口 5000 上運行應用。

kubectl run keras-app --image=gcav66/keras-app --port 5000 


在 Kubernetes 中,容器都在 pod(容器集合)中運行。我們可以輸入 kubectl get pods 來驗證我們的 pod 是否正在運行。如果你看到下面的結果,你就完成了配置。

gustafcavanaugh@cloudshell:~ (basic-web-app-test)$ kubectl get pods
NAME READY STATUS RESTARTS AGE
keras-app-79568b5f57-5qxqk 1/1 Running 0 1m

此時,我們的 pod 正在運行,我們需要將我們的 pod 暴露給 80 端口從而與外界相連。這意味著任何訪問我們部署的 IP 地址的人都可以訪問我們的 API。這也意味著我們不必在 URL 後面指定一個麻煩的端口號(與 :5000 說再見!)。

kubectl expose deployment keras-app --type=LoadBalancer --port 80 --target-port 5000

就要完成了!現在,運行 kubectl get service 來確定我們的部署(以及我們調用 API 所需的 URL)的狀態。同樣地,如果命令的輸出結果和下圖所示的結果類似,你就完成了這一步!

gustafcavanaugh@cloudshell:~ (basic-web-app-test)$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
keras-app LoadBalancer 10.11.250.71 35.225.226.94 80:30271/TCP 4m
kubernetes ClusterIP 10.11.240.1 443/TCP 18m

現在是關鍵時刻了!請獲取 keras 應用程序的 cluster-ip。打開本地終端(或者存有狗狗照片的地方),運行 curl -X POST -F [email protected] 'http:///predict' 指令調用 API。

享受你的實驗結果吧!

如下所示,API 正確地為該圖返回了「小獵犬」的標籤。

$ curl -X POST -F [email protected] 'http://35.225.226.94/predict'
{"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}

步驟 4:封裝

在本教程中,我們使用 Keras 和 Flask 實現了一個深度學習模型,並將其部署為 REST API。然後我們把這個應用程序放在 Docker 容器中,將該容器上傳至 Docker Hub,並且使用 Kubernetes 對其進行部署。

只需要兩個指令,Kubernetes 就部署好了我們的應用程序並向外部提供服務。你應該為此而感到自豪。

現在,我們可以對這個項目做出很多改進。首先,我們應該將運行 flask 應用程序的 python web 服務器從本地 python 服務器替換為 gunicorn 這樣的生產級服務器。我們還應該探索 Kubernetes 的擴展和管理特性,這是本文中幾乎沒有涉及到的。最後,我們可以嘗試從頭開始創建一個 kuberenetes 環境。

教程|如何使用 Kubernetes 輕鬆部署深度學習模型

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

✄------------------------------------------------

加入機器之心(全職記者 / 實習生):[email protected]

投稿或尋求報道:content@jiqizhixin.com

廣告 & 商務合作:[email protected]


分享到:


相關文章: