Chainerで作った機械学習モデルを使ってWebアプリで判定させるデモを作る記事、後編はWebアプリを作ります。
前回記事:ChainerとFlaskで作る機械学習デモアプリ 前編 モデルの作成と保存
Webアプリの構成
ChainerのトレーニングのためのスクリプトをPythonで書いているので、WebアプリもPythonで構築してみます。
コーディングは最小限にして作りたいのでPythonのWebフレームワークであるFlaskを使います。
Welcome | Flask (A Python Microframework)
PythonのWebフレームワークはDjangoなども有名ですが、Flaskはシンプルさと軽量がウリです。今回はお手軽に作りたいのでFlaskを選びました。
Webアプリは画像ファイル(png)をアップロードすると、サーバ側でChainerのモデルを読み込んで、何の文字かを判定、その結果をWeb上に表示するようにします。
Flask環境の構築
以下の記事を参考にFlask環境を構築します。
https://qiita.com/qoAop/items/96a586337fa9f8983e48
アプリの構築
ディレクトリ、ファイル構成は以下のようになります。
1 2 3 4 5 6 7 8 |
├── lcd2.model … 前編の記事で作成したモデル ├── predict.py … メインのスクリプト。ファイルのアップロードと画像判定を行う ├── static … アップロードしたファイルの配置先 │ ├── 20171005132515.png … ここにアップロードしたファイルが保存される │ ├── 20171005134015.png │ └── 20171005134045.png ├── templates … htmlテンプレートの保存先 ├── index.html |
predict.pyの内容です。
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 |
from flask import Flask, render_template, request, redirect, url_for import numpy as np from PIL import Image from chainer import datasets, iterators, optimizers, serializers import chainer import chainer.functions as F import chainer.links as L from chainer import training from chainer.training import extensions from datetime import datetime # Network definition class MLP(chainer.Chain): def __init__(self, n_units, n_out): super(MLP, self).__init__() with self.init_scope(): # the size of the inputs to each layer will be inferred self.l1 = L.Linear(None, n_units) # n_in -> n_units self.l2 = L.Linear(None, n_units) # n_units -> n_units self.l3 = L.Linear(None, n_out) # n_units -> n_out def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) return self.l3(h2) app = Flask(__name__) @app.route('/', methods = ['GET', 'POST']) def upload_file(): if request.method == 'GET': return render_template('index.html') if request.method == 'POST': # アプロードされたファイルを保存する f = request.files['file'] filepath = "./static/" + datetime.now().strftime("%Y%m%d%H%M%S") + ".png" f.save(filepath) # モデルを使って判定する model = L.Classifier(MLP(1000, 10)) serializers.load_npz('lcd2.model', model) image = Image.open(filepath).convert('L') image = np.asarray(image).astype(np.float32) / 255 image = image.reshape((1, -1)) x = chainer.Variable(image) y = model.predictor(x) # predict = np.argmax(y.data) return render_template('index.html', filepath = filepath , predict = predict ) if __name__ == '__main__': app.run(host="0.0.0.0", port=int("5000"),debug=True) |
index.htmlの内容です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<html> <body> {% if predict %} <IMG SRC="{{filepath}} " BORDER="1"> predict:{{predict}} <BR> <HR> {% endif %} ファイルを選択して送信してください<BR> <form action = "./" method = "POST" enctype = "multipart/form-data"> <input type = "file" name = "file" /> <input type = "submit"/> </form> </body> </html> |
アプリの起動と動作確認
スクリプトを作成、配置したらWebサーバを起動させます。
1 |
sudo python predict.py |
サーバにアクセス(今回は5000番ポートで起動しています)するとトップ画面が表示されます。
試しに手書き文字をアップしてみます。ファイルは28×28ピクセルのPNG画像のみ対応しています。
アップロードすると判定結果が返ってきます。ちゃんと正解しています。
まとめ
機械学習関連の案件ではまず事前の検証を行うことが多いです。
検証レベルだとLinuxのCUI上とかで作ることが多いですが、デモしたりする際にはWebアプリ化するなどしてGUIにした方が分かりやすく、CUIに慣れない人でも触ることができ、より理解度が深まることが期待できます。
今回はWebフレームワークFlaskを使うことでアップロードからWeb上での判定表示までを簡単に構築できることがお分かりいただけたかと思います。PoCやデモ等でFlaskをぜひ使ってみてください!