こんにちは。機械学習エンジニアのマクシムです。
本記事は、Alibaba CloudのPAIを使った機械学習アプリ開発プロセスを紹介するシリーズのPart 2です。前回Part 1に続いて、学習済みのモデルのパッケージングとデプロイを行います。
Part 1はこちらから。
開発プロセスの流れ:

1. 入力画像処理のコード
Part 1でモデルの学習が終わりましたが、そのモデルはMNISTデータを活用していて、28x28の決まった入力フォーマットしか受け付けないので、モデルを使って分類する前に、入力画像を同じフォーマットに変換する必要があります。そのために、画像処理ライブラリのOpenCVを使ってmnist_util.pyというモジュールを予め作っておきます。
gist18464b17db5eb31d2782a5b8b0e0c96b
コードの解説:
- mnist_class_index(): 0〜9の数字の入力に対してMNISTの服カテゴリー名を出力する関数。モデルの出力結果が出た時に呼びます。
- mnist_format(): 入力画像をMNISTフォーマットに変換して2D numpyアレイを返す関数。モデルで画像分類を行う前に呼びます。
mnist_format()の画像変換処理は以下のように行います:
2. デプロイ処理のコード
PAI-EASは機械学習モデルをデプロイするためのサービスです。本来、機械学習モデルを構築する際には、TensorFlowやPyTorch、またはscikit-learnなどの様々なライブラリがあって、学習したモデルの状態を保存して使います。学習済みのモデルを再利用するために、決まった形式に保存することを、シリアライゼーション("serialization")と呼びます。ライブラリや機械学習手法によってフォーマットが色々あります(例:SavedModel、PMML、pickle、.h5、ONNXなど)。
EASではシリアライズ化されたモデルをデプロイする方法が二つあります。一つ目は、一般的なフォーマットのモデルのファイルだけ指定して、残りの処理をEASがカバーしてくれるやり方です。現在TensorFlowのSavedModel、PMMLとCaffeの三つの形式をサポートしています。アリババはこれを「Built-in プロセサ」と呼んでいます(デプロイの詳しいところは第4章で話します)。二つ目は「カスタムプロセサ」といって、任意の形式でモデルを指定して自分でサービングの処理を書くやり方です。(※ 現在カスタムプロセサでモデルをデプロイしたい場合、EASのSubscriptionが必要になるのでご注意ください。)
今回は.h5形式でモデルを保存しているため、カスタムプロセサの処理を書く必要があります。これをアリババのサンプルコード(3.3)をベースに書きます。カスタムプロセサの最低限の構成はシンプルで、allspark.BaseProcessorというアリババ独自のクラスを継承して、initialize()にプロセサ起動時の処理と、process()にリクエストによって送られてくるデータ(分類したい画像など)の処理を指定するだけです。
gist117febcba144655d7df9a15107a49850
コード解説:
initialize(): 起動時にPart 1で保存した.h5ファイル(モデル)を読み込む。モデルファイルのパスについては第3章でもっと詳しく話します。
process(): pre_process()を呼んでリクエストの画像データを前処理し、モデルの分類結果を出して、post_process()で予測結果を正しいフォーマットに変換して結果を返す。
pre_process(): str形式のデータをnumpyアレイに変換し、第1章で書いたモジュールのmnist_util.mnist_format()で入力画像をMNIST形式に変換する。
post_process(): モデルは10次元のベクターを返すので、最大値に当てはまる服カテゴリーの名前をmnist_util.mnist_class_index()で返す。
3. コンテナの準備
ここから少しハンズオンっぽくなっていきます。
全てのファイル(メインファイル、画像処理モジュールとモデルファイル)が揃ったところで、パッケージング段階に入ります。パッケージングとは、モデルや処理ファイルを組み合わせて、適切な環境で正しく動くように一体化させることです。第1章と第2章で定義したPythonファイルはPython 3のOpenCVとTensorFlow2.0をベースに書いているため、ライブラリとファイルの結びつけを慎重に進める必要があります。
EASでは、「モデル+処理ファイル」と共に「Python仮想環境 (conda)」を準備して一緒にパッケージ化してデプロイするか、仮想環境をコンテナに準備した後に「モデル+ファイル」だけパッケージ化して、両方(コンテナイメージとパッケージ)をデプロイ時に指定するやり方があります。仮想環境ファイルはかなり大きく、毎回パッケージに入れると時間がかかってしまうため、今回は後者のコンテナを使ったデプロイを行います。
第3、4、5章で行う作業を図でまとめると以下のようになります。

コンテナイメージを準備する前に、公式ドキュメントに従ってAlibaba CloudのContainer Registryサービスで新しい"eas-demo-image"というPublicレポジトリを設定します。
次に、コンテナを設定します。ここからのステップはローカルPCのターミナルで行います。
まず、アリババからEAS用のベースコンテナイメージをダウンロードします。そして、プロセスを「pai-demo-app」と名付けてイメージを実行して、アクセスします。
$ docker pull registry.cn-shanghai.aliyuncs.com/eas/eas-python-base-image:py3.6-allspark-0.8 $ docker run -itd --name pai-demo-app registry.cn-shanghai.aliyuncs.com/eas/eas-python-base-image:py3.6-allspark-0.8 $ docker exec -it pai-demo-app /bin/bash
コンテナに入ったら、「ENV/」フォルダと「app.py」があります。ENV/はデプロイ時に呼ばれるPythonの仮想環境で、app.pyはイメージにデフォルトで入っているプロセサファイルです。第2章で再定義しているので削除します。
$ rm app.py
下記コマンドでpipをアップグレードし、TensorFlow2.0とOpenCVをインストールします。
$ ./ENV/bin/pip install --upgrade pip $ ./ENV/bin/pip install tensorflow==2.0 opencv-python-headless $ exit
本来、「app.py + mnist_util.py + fashion_mnist_model.h5」ファイルが正しくコンテナのPython環境で動くか確かめますが、ここでは省略します。
コンテナの設定が終わってイメージをAlibaba Cloud上のContainer Registryサービスに保存しておいて、どこからでも使えるようにします。Container Registryでレポジトリ名をクリックすればpushのやり方が記載されています。
$ docker commit -m "Commit message" -a "Commit author" pai-demo-app username/eas-demo-image:latest $ docker login --username=your_user_id@your_domain registry-intl.ap-southeast-1.aliyuncs.com $ docker tag username/eas-demo-image:latest registry-intl.ap-southeast-1.aliyuncs.com/yvm-repos/eas-demo-image:latest $ docker push registry-intl.ap-southeast-1.aliyuncs.com/yvm-repos/eas-demo-image:latest
これで、Container Registryにデモアプリ用のコンテナイメージがアップロードされました!
あとで、イメージのURLをデプロイの時に使います。
4. パッケージング
コンテナの準備ができたので、ファイルのパッケージングを行います。今回、パッケージングはファイルを圧縮するだけの作業になります。 EASは.zipと.tar.gz形式をサポートしていて普段通りに圧縮してもいいのですが、ここではアリババが配っているEASCMDというEAS用のコマンドラインツールを使います(あとでデプロイにも使います)。
まずはダウンロード(Mac版を使います)して、実行可能にします。そして、承認情報を設定してendpointをシンガポールに設定します:
$ wget http://eas-data.oss-cn-shanghai.aliyuncs.com/tools/eascmdmac64 $ chmod +x eascmdmac64 $ ./eascmdmac64 config –i <AccessKeyID> -k <AccessKeySecret> -e pai-eas.ap-southeast-1.aliyuncs.com
EASCMDの設定が終わったら、"processor/"フォルダを作って「app.py」、「mnist_util.py」と「mnist_model.h5」を中にコピーしてから、下記コマンドでパッケージ化され、Alibaba Cloud上(OSS)にアップロードされます。
$ ./eascmdmac64 pysdk pack ./processor
これで、パッケージング完了です!最後に、出来上がったパッケージをOSSにアップロードします。
$ ./eascmdmac64 upload processor.tar.gz
パッケージのURLをデプロイの時に使います。
5. デプロイ
Alibaba Cloudにコンテナイメージとファイルパッケージのアップロードができたので、いよいよデプロイフェーズに移ります。EASでは、リソースをニーズに合わせてデプロイできるようになっています。PAI-EASのプロダクト画面で簡単にデプロイできますが、EASCMDで更に細かく設定することができます。リソースの設定やコンテナイメージ、プロセサパッケージは予めJSONファイルに設定して、EASCMDでデプロイを行います。JSONファイルに指定できる項目はこちらに書いてあります。今回デプロイに使うファイルは以下になります。
gistf7bad067e886032c0c462c5b14e77e82
下記に、デプロイのJSONファイルの項目をいくつか解説します。まずは、デプロイするモデルに関する項目から見ていきます:
項目 | 概要 | 今回のデプロイ |
---|---|---|
name | サービス名(リージョン毎の重複不可) | 「pai_demo_app」と任意の名前をつけます。 |
processor_type | カスタムプロセサを使う場合に指定。使われる言語によって、pythonやcppなどがあります。 | 今回は「python」を使います。 |
processor | Built-inプロセサを使う場合に指定。pmml、tensorflow_gpu、tensorflow_cpu、caffe_gpu、caffe_cpuなどがあります。 | |
processor_entry | プロセサのメインファイルパス | 第2章で定義した「./app.py」ファイルを指定。 |
processor_path | プロセサのパッケージのURL | 第4章のパッケージURLを指定。 |
model_path | PMML、TensorFlowのSavedModelやCaffeのBuilt-inプロセサを使う場合指定します。 | |
data_image | コンテナイメージのURL | 第3章のコンテナイメージURLを指定。 |
更に、metadataフィールドにデプロイサーバーの細かい設定が行えます:
項目 | 概要 | 今回のデプロイ |
---|---|---|
region | リージョンのendpointキーワード(キーワードはこちらから確認できます) | シンガポールでデプロイするので、「ap-southeast-1」を使います。 |
instance | サービスのインスタンス数 | 今回はデモなので1で十分です。 |
workers | 各インスタンスのスレッド数(デフォルト=5) | |
memory | サービングのメモリ(GB単位) | 適当に16GB設定しておきます。 |
resource | カスタムプロセサの場合、EASのリソースグループIDを指定します。Built-inプロセサはデフォルトで大丈夫です。 | この表の下に詳細を書いています。 |
cpu | 各インスタンスのCPU数 | とりあえず1個で動くか確認して、後から変えます。 |
gpu | 各インスタンスのGPU数 |
上記の"resource"において、現時点でEASでのカスタムプロセサによるデプロイはプライベートリソースグループが必要です。Pay-as-you-go(従量課金)だと使えませんので、Subscriptionを購入します。購入したリソースグループのIDはEASのホーム画面からわかります。
上記のapp.jsonをeascmdmac64と同じディレクトリーに保存して、下記コマンドを実行すればデプロイ完了です。
$ ./eascmdmac64 create app.json
まとめ
これで、モデルがデプロイされて、APIリクエストで推論結果を返してくれるサービスができました。次回Part 3では、まずEASの管理機能を少し紹介してから、APIリクエストの送り方とECSでの簡単なウェブアプリのサービングについてお話しします。