Pythonの強力な顔認識モデルをHerokuにデプロイしてモバイルアプリから呼び出せるようにしました。
第一回はPython側のコードとHerokuへのデプロイまで、第二回ではFlutterでそのデプロイした処理を呼び出す部分を紹介したいと思います。
第二回のFlutterでの呼び出し部は以下の記事を参照ください。
Pythonの顔認識モデルをHerokuにデプロイしてFlutterから利用②
この記事の投稿者について
Twitterで顔認識を活用したアプリ開発についてつぶやいています。
https://twitter.com/studiothere2
noteにアプリ開発の日記を連載しています。
https://note.com/there2
顔認識モデル
利用ライブラリ
Python face_recognitionを利用しています。
https://github.com/ageitgey/face_recognition
ドキュメントが非常に充実しており、とても簡単に利用できます。
ベンチマークで99.38%の精度ということで、人間と同等以上のパフォーマンスが期待できます。
その他利用ライブラリ
あまり深く考えていませんが、Herokuでよく利用されていて軽量そうなものを選びました。
- Web開発フレームワーク:Flask
- HTTPサーバー:Gunicorn
Pythonソースコード解説
必要最小限のシンプルなものですが、骨子がわかるかと思います。
import face_recognition
from flask import Flask, jsonify, request, redirect
app = Flask(__name__)
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
まずは必要なライブラリのインポートと定数の宣言です。
appの変数名はGunicornの起動時にも利用します。
@app.route('/')
def hello_world():
return 'hello'
rootで呼ばれた時に、単純にhelloだけを表示します。
これはサーバーが生きているかどうかの確認に便利です。
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
画像ファイルが送られてきたときに、そのファイルの拡張子がpng, jpg, jpeg, gifのいずれかであることを確認します。
これら以外の場合はface recognitionの処理対象外としています。
@app.route('/embedding', methods=['GET', 'POST'])
def get_embedding():
# Check if a valid image file was uploaded
if request.method == 'POST':
if 'file' not in request.files:
print("file not in request.files")
return redirect(request.url)
file = request.files['file']
if file.filename == '':
print("file name is blank")
return redirect(request.url)
メインの顔認識処理部です。
/embedding
で呼び出します。
POSTでinput typeがfileでファイル名に上記のpng, jpg, jpeg, gifのいずれかの場合のみ処理します。
それ以外の場合はリダイレクトで呼び出し元に戻します。その場合、response code
が302
となります。
if file and allowed_file(file.filename):
print("file found")
# The image file seems valid! Detect faces and return the result.
img = face_recognition.load_image_file(file)
emb = face_recognition.face_encodings(img)[0]
return jsonify(emb.tolist())
正しいファイル形式でPOSTされてきた場合、face_recognitionにファイルを読み込ませて、それを使って128次元のFloatのEmbeddingを取得します。
このEmbeddingを使うと、他の顔との類似度を算出する事ができます。
この部分は別途モバイルアプリ側で実装しますので、Python側ではEmbeddingした顔の特徴量情報のみを返します。
face_recognitionの戻り値はNumpyの配列なので、tolist()
を呼び出してPythonの配列にする必要があります。
それをJson化したものを戻します。
# If no valid image file was uploaded, show the file upload form:
return '''
<!doctype html>
<title>upload</title>
<h1>Please select image and upload</h1>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''
GETで呼ばれた場合は、ファイルアップロード用のHTMLを出力し、直接ファイルアップロードできるようにしています。
if __name__ == "__main__":
app.run(host='0.0.0.0')
メイン処理で、Flaskを起動します。hostを0.0.0.0
としておくことで、Herokuのデプロイ先でのURLで利用できるようにします。
動作確認
pip install -r requirements.txt
必要なライブラリはrequirements.txt
にまとめていますので、上記のコマンドでまとめてインストールできます。
なおこのrequirements.txt
はHerokuにデプロイする際も必要となります。
バージョンによってはcmake
, dlib
, face_recognition
の順にインストールしないとHerokuでうまくデプロイできないという情報があったので、以下のようにrequirements.txt
に記載しておきました。
boost==0.1
cmake
boost-py
dlib
face_recognition_models
face-recognition
Flask==1.1.2
gunicorn==20.0.4
gunicornを使ってローカルで起動してみます。
gunicorn run:app --log-file -
うまく起動したら以下のように表示されると思います。
$ gunicorn run:app --log-file -
[2020-05-15 09:02:24 +0900] [11143] [INFO] Starting gunicorn 20.0.4
[2020-05-15 09:02:24 +0900] [11143] [INFO] Listening at: http://127.0.0.1:8000 (11143)
[2020-05-15 09:02:24 +0900] [11143] [INFO] Using worker: sync
[2020-05-15 09:02:24 +0900] [11146] [INFO] Booting worker with pid: 11146
ブラウザでhttp://127.0.0.1:8000
を開いてみましょう。
hello
と表示されたら成功です。
続いて、http://127.0.0.1:8000/embedding
にアクセスすると以下のようにファイル選択のHTMLが表示されると思います。
人の顔画像のファイルをアップロードしてみてください。
次のように128個のFloatの配列が表示されたら成功です。
これがアップロードした画像の特徴量となるEmbeddingの中身です。
クラウド環境
Herokuの利用
WEBサービスのデプロイする先としてHerokuを選択しました。
Pythonで利用できること、デプロイが簡単でスケールしやすい事、利用料がリーズナブルだと感じた事からHerokuを選択しました。
試しの利用なら無料で利用できます。
対抗としてFirebaseのCloud Functionも考えましたが、今回のモデルは読み込みにある程度負担がかかりますので都度起動されるCloud Functionより常時起動しているVM型の方が良いと思いました。
Herokuも無料版だと30分利用がないとインスタンスが落ちてしまって呼び出し時に起動が走るようですが、有料版にすればインスタンスが落ちなくなります。
必要に応じて有料版に移行すればよいでしょう。
Herokuへのデプロイ
デプロイ作業は難しくありません。
Herokuへユーザ登録して以下のセットアップ手順に沿っていけばよいでしょう。
https://devcenter.heroku.com/articles/getting-started-with-python
Herokuのコマンドラインツールをインストールします。
sudo snap install heroku --classic
Herokuへログインします。
ブラウザが立ち上がって、ブラウザからログインできます。
heroku login
Herokuにアプリを登録します。
適当な名前でアプリが登録され、Herokuのダッシュボードで確認できるようになります。
heroku create
Procfileを作成します。
このファイルは、Herokuにどのようにサーバを起動すれば良いかを教えるファイルです。
以下のようにWEBとしてgunicornを起動するように指示を書いておきます。
web: gunicorn run:app --log-file -
以上で準備完了です。あとはgitコマンドでherokuのリポジトリにプッシュすればデプロイされます。
※事前にgitコミットを済ませておく必要があります。
git push heroku master
これでHerokuにデプロイされて、URLが表示されますので、そのURLにアクセスして動作する事を確認してみてください。
なお、初回のデプロイにはかなり時間がかかります。特にdlibがC++で書かれたライブラリでコンパイルが必要なため、インストール完了までかなり待たされました。
30分ぐらいかかったかもしれません。
エラー終了するのでなければ気軽に待ちましょう。
次回はFlutterからこのWEBサービスを呼び出す部分を紹介したいと思います。