LoginSignup
13
12

More than 3 years have passed since last update.

機械学習モデルの予測値を返すAPIをDockerで作ってみた

Last updated at Posted at 2019-11-03

はじめに

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イメージに入って、ライブラリがインポートできるか確認。
確かにpython3lightgbmのライブラリも使えることを確認。

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ページから予測を投げて、帰ってきた値を表示するようなものを作ってみたい。

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12