はじめに
先日の記事で作ったイコちゃんとペリー分類器ですが、今回は画像ファイルを送れば分類結果が返されるFlaskのAPIを作ってみようと思います。すごく簡単にできそうな記事を見つけたので、そこで紹介されていたコードを使います。
前回のおさらい
前回は、ペリーの画像27枚、イコちゃんの画像20枚を集めKerasでVGG16を使って分類器を作りました。テストデータもペリー9枚、イコちゃん7枚の計16枚と用意し、F1スコアは0.705くらいでした。画像を集めるのが面倒なのと、GPUを持っていないので更なる精度向上はいったん目指しておりません。
Flaskとは
FlaskとはWikipediaによると、「Python用の軽量なウェブアプリケーションフレームワークで、Djangoの次に人気がある。」とあります。学習済みモデルで推論の処理を受けつけ、その結果を返すということにしか関心がないデータサイエンティストとしては、ウェブアプリケーションフレームワークをわざわざ学びたいものではないですが、データサイエンス界隈ではしばしば見かけることから、学ばざるを得ないなと思います。
Flaskには「処理を受け付け、結果を返す」というただそれだけの関心で向き合っていく次第です。
公式ドキュメントはこちら(Welcome to Flask — Flask Documentation (2.0.x))になります。
そういえば以前、「[第3版]Python機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)」という書籍でFlaskを用いたレコメンドAPIを時間制限のある無料のサーバ(PythonAnywhere)で実装したことはありましたが、CSSやHTMLを色々設定して面倒だなという印象がありあまり記憶に残っておりません(笑)。
今回の処理
この記事のソースコードはこの記事、「How to Build A Machine Learning API Using Flask」から使わせていただきました。ローカル環境で機能するAPIをFlaskで作るというものです。
ざっくりとした処理の流れとしては、
学習済みモデルの読み込みをした状態で、
入力された画像を前処理し、
推論を行い、その結果を返すというものです。
ソースコード
さて、学習済みの画像分類モデルで、画像を受け付けて推論し、結果を返すコードは以下の通りとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
import io import string import time import os import flask from flask import Flask, jsonify, request import numpy as np from PIL import Image import keras from keras.applications.vgg16 import VGG16 from tensorflow.keras.optimizers import Adam from keras.layers import Activation, Dense, Dropout, Flatten, Input from keras.models import Model def model_vgg(class_num,height,width): out_num = class_num input_tensor = Input(shape=(height, width, 3)) vgg = VGG16(include_top=False, input_tensor=input_tensor, weights=None) x = vgg.output x = Flatten()(x) x = Dense(2048,activation="relu")(x) x = Dropout(0.5)(x) x = Dense(2048,activation="relu")(x) x = Dropout(0.5)(x) x = Dense(out_num)(x) x = Activation("softmax")(x) model = Model(inputs=vgg.inputs,outputs=x) model.compile(optimizer=Adam(lr=1e-4), loss='categorical_crossentropy', metrics=['accuracy']) return model ## 学習済みモデルの読み込み # paramaters ------------------- WIDTH = 256 HEIGHT = 256 class_num = 2 # modelの呼び出し model = model_vgg(class_num, HEIGHT, WIDTH) # 学習済みの重みのロード model.load_weights("../perry_image/weights2_15.h5") ## 画像の前処理 def prepare_image(img): img = Image.open(io.BytesIO(img)) img = img.resize((WIDTH,HEIGHT)) img = np.array(img) # 画素値0~255を0~1の間に標準化する img = img / 255. return img ## 予測 def predict_result(img): Yp = model.predict(np.array([img]).astype(np.int)) return 1 if Yp[0][1] > 0.29 else 0 ## Flask app = Flask(__name__) # 書き込みがありリソースが更新される可能性のある処理 @app.route('/predict', methods=['POST']) def infer_image(): if 'file' not in request.files: return "Please try again. The Images doesn't exist" file = request.files.get('file') if not file: return img_bytes = file.read() img = prepare_image(img_bytes) return jsonify(prediction=predict_result(img)) # 情報の取得 @app.route('/', methods=['GET']) def index(): return 'Machine Learning Inference' if __name__ == '__main__': app.run(debug=True, host='0.0.0.0') |
こちらのソースコードをapp.pyのファイル名で保存して、
コンソール上で
1 |
python app.py |
と実行すれば、FlaskのAPIサーバが立ち上がります。
今回はローカル環境なので、ブラウザで
http://0.0.0.0:5000/
を表示すればサーバが起動しているのを見れます。
さて、肝心の画像分類ですが、
コンソール上で以下のようにcurlコマンドを叩けばローカルのサーバから推論結果が返ってきます。–formという引数で’file=@”/perry_image/test/ikochan_test_8.jpeg”‘みたいにローカルのファイル名を指定して実行する形となります。
1 2 3 4 5 |
curl --location --request POST 'http://0.0.0.0:5000/predict' --form 'file=@"/perry_image/test/ikochan_test_8.jpeg"' { "prediction": 1 } |
1なので、この画像はイコちゃん判定されました。過去の記事にもあるように、正解率は11/16くらいなので、69%と微妙ですけども。
今回はローカルサーバですが、Webサーバ上で起動すれば、機械学習を用いたツール開発が実現できますね。
なにより、思ったよりも短いコードで実現できてしまうことに驚きました。推論などの処理は基本的にPOSTのところに書く感じです。
今後:本番運用に必要なことについて
仕事で使うとなると、このコードを載せるサーバとかセキュリティ周りをどうするかというのが気になります。処理回数の制限とかIP制限とか認証キーとかどうするのか。
URLが流出するかもしれないし、誰かがDOS攻撃とかしてくる人がいるかもしれないし。
データ分析をするだけのご身分ではこういったことを考えることはないですが、データサイエンティストという職種に求められるスキルが少しずつ広がっていくのは面白いとも思えるので、粛々と向き合っていきたいです。
最近、「Python FlaskによるWebアプリ開発入門 物体検知アプリ&機械学習APIの作り方」という書籍が出ていたので、ポチりました。本番で運用する観点でどういったリスクを潰しておくべきか、この本から学んで実装までいけるといいなと思います。
参考情報
[第3版]Python機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)
How to Build A Machine Learning API Using Flask
GETとPOSTの違いについて