はじめに
Yellowbrickで精度を確認しつつ作った機械学習モデル1を予測APIサーバのような形で活用してみたいと思い、Dockerで作ってみた。
Flaskについてはこちら2、Dockerについてはこちら3を参考にして、APIサーバーから応答が返ってくるところまでを目標にする。
環境
環境は以下の通り。
$sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.6
BuildVersion: 17G8037
Dockerのインストールについては4を参考にした。
ログが結構長かったので、一部省略。
$docker version
Client: Docker Engine - Community
Version: 19.03.4
API version: 1.40
Go version: go1.12.10
(省略)
Server: Docker Engine - Community
Engine:
Version: 19.03.4
API version: 1.40 (minimum version 1.12)
(省略)
構築
Dockerイメージの作成
まずDockerイメージをDockerfileから作成する。
エディタで以下の内容が記載されたファイルを作成する。
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install python3 python3-pip -y
RUN pip3 install flask
RUN pip3 install scikit-learn
RUN pip3 install numpy
RUN pip3 install scipy
RUN pip3 install lightgbm
RUN pip3 install joblib
RUN pip3 install pandas
dockerコマンドでイメージを作成する。
docker build . -t myflask/mlapi:1.0
しばらくすると、以下のメッセージが表示されて構築完了。
Successfully built 4a82ed953436
Successfully tagged myflask/mlapi:1.0
dockerイメージが作られていることをdocker images
コマンドで確認。
$docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myflask/mlapi 1.0 4a82ed953436 7 minutes ago 782MB
ubuntu latest 775349758637 2 days ago 64.2MB
試しにdockerイメージに入って、ライブラリがインポートできるか確認。
確かにpython3
もlightgbm
のライブラリも使えることを確認。
root@117483d4b9ed:/# python3
Python 3.6.8 (default, Oct 7 2019, 12:59:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lightgbm
>>> exit()
APIサーバ用プログラム作成
dockerイメージから抜けて、ローカル環境でAPIサーバ用のプログラムを作成する。
機械学習モデルを作った際にjoblib
でモデルを保存した1ので、同じくjoblib
を使ってモデルをロードしている。
こちら2の記事を参考にしているが、データの項目量が違うので受け取り部分について工夫した。
一度、features
の中身をpandasのDataFrameに渡して予測するようにしている。
from joblib import load
import flask
import numpy as np
import pandas as pd
import lightgbm as lgb
# initialize our Flask application and pre-trained model
app = flask.Flask(__name__)
model = None
def load_model():
global model
model = load("./lightgbm.joblib")
@app.route("/predict", methods=["POST"])
def predict():
response = {
"success": False,
"Content-Type": "application/json"
}
if flask.request.method == "POST":
if flask.request.get_json().get("feature"):
# read feature from json and convert to dataframe
features = flask.request.get_json().get("feature")
df_X = pd.DataFrame.from_dict(features)
# predict
response["prediction"] = model.predict(df_X).tolist()
# indicate that the request was a success
response["success"] = True
# return the data dictionary as a JSON response
return flask.jsonify(response)
if __name__ == "__main__":
load_model()
print("Server is running ...")
app.run(host='0.0.0.0', port=5000)
APIサーバ起動
ローカル環境にディレクトリを作って、上のプログラムと、機械学習モデルを格納しておく。
mkdir vol
mv lightgbm.joblib ./vol/
mv api.py ./vol/
dockerコマンドで上で作ったvolディレクトリをdockerイメージにmountして、起動する。
$docker run -it --rm -p 5000:5000 -v $(pwd)/vol:/home myflask/mlapi:1.0 /bin/bash
home以下にあるapi.pyを実行すると、APIサーバが起動する。
root@5d1e3cf74246:/# cd home/
root@5d1e3cf74246:/home# python3 api.py
Server is running ...
* Serving Flask app "api" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
応答の確認
上でIPアドレス0.0.0.0、ポート5000にサーバを設定しているので、ここにcurl
コマンドで予測するためのデータを渡してみる。
学習データはYellowbrickのload_bikeshareを使っているので、項目を揃えてfeaturesの中に詰めてサーバに渡している。そのままpandasのDataFrameに変換できるように、データの要素をリストにした。
$curl http://0.0.0.0:5000/predict -X POST -H 'Content-Type:application/json' -d '{"feature":{"season":[1], "year":[0], "month":[1], "hour":[0], "holiday":[0], "weekday":[6], "workingday":[0], "weather":[1], "temp":[0.24], "feelslike":[0.3], "humidity":[0.8], "windspeed":[0.0]}}'
上記コマンドを打つと、下のように応答が帰ってきた。やったー。
{"Content-Type":"application/json","prediction":[34.67747315059312],"success":true}
さいごに
REST APIとか、サーバとか詳しくなくてもDockerやFlaskを使うことで簡単に構築できた。
今度Webページから予測を投げて、帰ってきた値を表示するようなものを作ってみたい。