在 Jupyterhub 上用十分鐘建立 Server 來跑模型
Build an AI App — 0: use Ngrok and Flask to build a server for ai model
想要用 web service 來展示你的 model 的時後,只有 Jupyterhub 怎麼辦呢? 不想租 AWS、GCE,想用自己的本機的跑 server 的時候,又要怎麼辦呢? 用這次要介紹的 ngrok 就可以讓你輕鬆地在任何機器上建立讓別人可以連線的 server。
— 環境架設 —
首先,需要一個有裝 flask、你需要的套件 (e.g. Tensorflow, Pytorch) 和 GPU 的 hub 就可以囉!
首先從 Ngrok 的官網 下載需要的作業系統的 zip file (在這裡我是下載 32-bits Linux 的檔案),解壓縮和認證後就可以直接使用它啦!
$ unzip /path/to/ngrok.zip
$ ./ngrok authtoken <your Ngrok id>
最簡單的使用方法就是執行以下指令:
$ ./ngrok http 80
這樣就可以建立一個 HTTP 的連線到 80 這個 port,用紅筐內的網址連到你的 server 了。只可惜要升級帳號才能有固定的 ip,所以比較適合拿來開發或demo用。
— 建立 Flask Server —
Flask 是一個非常容易使用的 web server 框架,所以就用他來建立範例 server吧。首先,建立一個 hello world server 來測試 Ngrok 是首有成功連到server。創建一個新檔 app/main.py,在裡面寫:
from flask import Flask, request, send_fileapp = Flask(__name__)@app.route("/")
def hello():
return "Hello World!"
在 Terminal 執行:
export FLASK_APP=app/main.py
python -m flask run
Flask 預設的 port 是 5000,所以執行 Ngrok的時候就得要 bind 到 5000。
$ ./ngrok http 5000
打開瀏覽器前往 “http://xxxx.ngrok:5000/”,有出現 “Hello World!” 就是成功了!
— 建立 API —
接著就可以來寫 API 啦!不過在開始前,先看一下範例 server 所使用的 model 的使用方法吧!這是一個 image transfer 的 model,需要 input 一張圖片和你要 transfer 過去的風格。
def transform(image, style):
...
return output_image
首先,先建立一個 API
用 @app.route(URL, methods) 建立一個 api,因為要傳圖片到 server,所以 method 要選 POST。 另外,為了讓使用者決定要要轉到哪種風格,用角括號加入在網址加入 style 變數 :
@app.route('/sync_transform/<style>', methods=['POST'])
def sync_transform(style):
如果使用者 post 到 “sync_transform/style1”,那麼 sync_transform 函式就會收到 “style1” 字串作為 input。
然後要從 request 夾帶的檔案得到 Image 物件。
- 先檢查使用者是否有夾帶檔案,沒有檔案則回傳 error_message 和 status_code。
if 'file' not in request.files:
return 'No file part', 500
2. 再檢查有沒有檔名,因為如果傳來的是空的 file part 過來,會沒有檔名。
file = request.files['file']
if file.filename == '':
return 'No selected file', 500
3. 用 pillow 將檔案轉成 Image 物件。
image = Image.open(file.stream).convert("RGB")
記得要先 import pillow 這個 package:
from PIL import Image
接下來就是可以執行 model 了,這個範例 model 會回傳一個 Pillow Image 物件:
image = sync_transform(image, style)
最後,回傳前必須轉成 file bytes:
# 轉成指定副檔名的 bytes,要產生jpg的話,format要給 jpeg
image_bytes = io.BytesIO()
image.save(image_bytes, format='JPEG')# 把讀取位置調回最開始
image_bytes.seek(0)
用 Flask 的 send_file 回傳到 client 端:
return send_file(image_bytes, attachment_filename='result.jpg', mimetype='image/jpg')
完整 function 如下:
— 執行 —
分別在不同分頁 執行 Ngrok 和 Flask server 就可以接收 requests 了。
— Request 測試 —
最後用 request 套件來測試 Server 是否有成功。建立一個 test.py:
執行完後,test_recieved_from_jupyter.jpg 可以正常顯示就代表成功了!
— 完整程式碼 —
https://github.com/leafinity/cartoon_server/tree/jupyter-sync-server
— 參考資料 —
[2] Install both python 3.6 and 3.7