手元のGPU環境で作成したTensorFlowモデルを、クラウド環境上で動作させたいということは良くあると思います。実際、いま私もそのようなお仕事をしているのですが・・・。
クラウド上で動作させるといっても、方法はいろいろあります。Amazon SageMakerのようなマネージドなクラウドを使用してデプロイすればWeb API化まで簡単に行うことができますし、一方でAmazon EC2のようなIaaSを用いて自分ですべて環境構築するという方法もあります。ちなみに、モデルをGPU環境で作って、それをEC2のようなCPUのみの環境で動作させるということも、もちろん可能です。(ちょっとワーニングが出ますけど。)
構成
EC2環境でTensorFlowモデルをデプロイする方法として、以下の2つが考えられます。
- TensorFlow Servingを使用する
- TensorFlowでモデルを動かし予測処理を行い、Flaskアプリを作ってWeb API化する
前者のTensorFlow Servingは、拙著「使ってわかったAWSのAI」で簡単な使い方を説明しました。きちんと使えば、前処理などの処理もパイプライン的に行えるので良さそうです。
ただ、今回は後者の方法を用いることにしました。
Nginx → uWSGI → Flask → TensorFlow
こんな構成です。
環境構築
まず、Amazon Linux 2環境のEC2インスタンスを準備します。インスタンスタイプはひとまずt2.mediumを選択しました。同時処理数などにもよりますが、この程度の性能の環境でも推論処理は問題なく動作します。
手元の環境がPython 3.8だったので、Amazon Linux 2環境も同様のバージョンにします。
どうやら、バージョンを合わせないとh5ファイル(TensorFlowモデルを保存したファイル形式)の読み込みでエラーになるようです。
sudo amazon-linux2-extras install epel
sudo amazon-linux2-extras install nginx1
sudo amazon-linux2-extras install python3.8
sudo yum install python38-devel
sudo yum groupinstall "Development Tools"
yum install pcre pcre-devel
Python3.8のpip
を使用可能にします。
sudo pip3.8 install --upgrade pip
sudo ln -s /usr/local/bin/pip3.8 /usr/bin/pip3.8
requirements.txt
を下記のようにします。
uwsgi
Flask
tensorflow==2.5.0
# 以下は必要に応じて
awscli
boto3
boto
pycryptodome
あとは、このrequirements.txt
を用いてPythonパッケージをインストールします。
sudo pip3.8 install -r requirements.txt
Flaskアプリの構築
/home/ec2-user/app/app.py
というファイルを作成し、下記の内容にします。
モデルを保存したh5ファイルは、/home/ec2-user/app/models/model.h5
に保存しました。
label_mapやpreprocessのあたりは、作成したモデルやトレーニング時の設定に合わせます。
#!flask/bin/python
import json
from flask import Flask, Response, request
import base64
import io
import os
import numpy as np
import tensorflow as tf
from datetime import datetime as dt
app = Flask(__name__)
image_dir = '.'
now = dt.now()
model = tf.keras.models.load_model(os.path.join('models', 'model.h5'))
label_map = {'label0': 0, 'label1': 1, 'label2': 2}
@app.route('/predict', methods=['POST'])
def predict():
json_data = request.get_json()
image_base64 = json_data['image']
image_file = os.path.join(image_dir, '%s.JPG' % now.strftime('%Y%m%d%H%M%S'))
with open(image_file, 'wb') as f:
f.write(base64.b64decode(image_base64))
img = tf.keras.preprocessing.image.load_img(
image_path, target_size=(224, 224), color_mode='rgb')
x = tf.keras.preprocessing.image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = tf.keras.applications.inception_resnet_v2.preprocess_input(x)
preds = model.predict(x)
result = None
for pred, value in label_map.items():
if value == np.argmax(preds):
result = pred
print('Predicted class is:', pred,
'With a confidence score of: ', np.max(preds))
return Response(json.dumps({'result': result}), mimetype='application/json', status=200)
if __name__ == '__main__':
app.run()
uWSGI
/home/ec2-user/app/app.ini
というファイルを作成し、下記の内容にします。
ログの保存場所として、/home/ec2-user/logs
というフォルダを作成しておきます。
[uwsgi]
module = app
callable = app
die-on-term = true
chdir = /home/ec2-user/app
processes = 1
master = false
vacuum = true
socket = /run/uwsgi.sock
chmod-socket = 666
logto = /home/ec2-user/logs/uwsgi.log
uWSGIを起動するため、/etc/systemd/system/uwsgi.service
を作成し、下記の内容にします。
[Unit]
Description = uWSGI
After = syslog.target
[Service]
ExecStart = /usr/local/bin/uwsgi --ini /home/ec2-user/app/app.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
あとは、下記のとおり起動します。
sudo systemctl enable uwsgi
sudo systemctl start uwsgi
Nginx
Nginxを導入している場合、/etc/nginx/conf.d/flask.conf
のようなファイルを作成し、下記のようにuWSGIへのリバースプロキシを設定します。
server {
server_name abc.vivinko.com; # 例
location / {
include uwsgi_params;
uwsgi_pass unix:///run/uwsgi.sock;
}
}
OpenCV
OpenCVを使用する場合は、下記のようにインストールするか、上記のrequirements.txt
に書いてまとめてインストールします。
sudo pip3 install opencv-python
import cv2
でImportError: libGL.so.1: cannot open shared object file: No such file or directory
というエラーが出る場合は、下記のパッケージをインストールします。
sudo yum install mesa-libGL.x86_64
参考サイト
- https://qiita.com/meriam_dev/items/2fe225cd46bbae3a0dc2