こんにちは。エンジニアのマクシムです。
今回は「PAIで機械学習アプリを作ってみた」シリーズのPart 3です。Part 1ではOSSとPAI-DSWを連携して機械学習モデルを学習させて、Part 2ではPAI-EASでモデルのデプロイを行いました。Part 3では、EASでのモデルデプロイ時のデバッグ方法をまず紹介して、服画像認識のウェブアプリと推論サービスの連携についてお話しします。ウェブアプリは今回Flaskで作ります。
Part 2はこちらから。
開発プロセスの全体図です:

目次
1. EASの管理機能
アプリの話をする前に、ここで少しEASとアプリを連携させる中で役に立つ管理機能をいくつか紹介します。
デプロイのデバッグ
EASCMDを使ってデプロイする時に、以下のようなエラーが出たりします。この場合、EASのホーム画面ではサービスが「Failed」状態で表示されます。そこで、失敗したサービスをクリックして、メニューの「Service Log」でエラーのログを確認することができます(最新ログは下の方に表示されます)。例えば、下記画像ではOpenCVが必要とするライブラリファイルが存在しないというエラーが出ているので、コンテナのライブラリの再設定などが必要です。
サービスのデバッグ
デプロイが成功したら、アプリを作る前にモデルが正しく動いているかどうかなど確認する必要があります。そのために、API Gatewayを通してVPC内でCURLリクエストを投げられるインターフェイスが用意されています。今回デプロイしたサービスは、予めOpenCVでエンコードされた画像を受け付けるように作ったので、直接このデバッグ機能は試せないですが、入力が数字や文字列などのサービスの場合、下記のBodyフィールドに指定してサービスを試すことが可能です。入力に対して400 Bad Requestが返ってきたり、レスポンス内容のフォーマットが正しいかなど色々確認できます。
サービスのモニタリング
更に、サービスのモニタリングダッシュボードも準備されています。そこに、リクエスト数やレスポンスタイプなどの様々な統計量が記録されているので、サービスのデバッグやテスト時に非常に役に立ちます。
これらの機能をうまく使ってモデルとアプリの連携を行えるので、皆さんもぜひ試してみてくださいね。
2. モデルのリクエスト
それでは、Part 2でデプロイしたサービスのリクエストの送り方から見ていきます。正しくリクエストをするには、二つの注意点があります。一つ目は、URLやリクエストのヘッダーなどの正しい形式を守ることと、二つ目はPart 2で定義したプロセサが対応している画像形式の再現の仕方です。
まず、リクエストに必須なURLとTokenは、前回Part 2でデプロイ時に発行された"Internet Endpoint"と"Token"を使います。Tokenはヘッダーの"Authorization"フィールドとして指定します(下の"test_request.py"を参照)。
次に、入力画像はOpenCVでNumpyアレイとして読み込み、文字列に変換したものをリクエストに渡します。プロセサのapp.pyでは「np_arr = np.fromstring(data, np.uint8)」と「img_np = cv.imdecode(np_arr, cv.IMREAD_COLOR)」で元通りの画像に変換されます。
最終的に、下記のコードにファイルと同じフォルダの服画像名を指定すればリクエスト完成です:
gist51828d8d98fd36fe1d7df9d048995d3b
3. Flaskアプリ
今回はFlaskライブラリを使って基礎的なウェブアプリを作ります。アプリは、ユーザーがアップロードした画像をサーバー上("static/")に保存して、EASのモデルにPOSTリクエストで送り、戻ってきた推論結果を表示する簡単な処理を行ってくれます。ファイルはFlaskの「mnist_app.py」と、ウェブインタフェースの「index.html」のみとなります。
第2章のコードは下記のmnist_app.pyコードに入っているので、"eas_url"と"token"をPart 2のデプロイ(第5章)に出てきたURL(Internet Endpoint)とTokenに変更して使います。
gist9ff00024aa517462b1e3c304dfcbfe2d
スタイル関連の話は本記事のスコープ外なので、CSSファイルは今回書きません。また、FlaskはJinjaというウェブテンプレートエンジンを使っていて、クライアント側の処理をファイル一枚で完結させます。
gist2f1975742b52c6c5acdcd44c4c9a3357
4. ECSの設定
アプリのコードが揃ったので、ECSを設定します。シンガポールリージョンの従量課金インスタンスを適当なスペックで設定したら、グローバルIPアドレスを確認してscpでFlaskアプリをアップロードし、インスタンスにログインします。
$ scp -r flask/ user@your_ECS_IP:/path/to/destination $ ssh user@your_ECS_IP
ECSインスタンスにアクセスしたら、mnist_app.pyのあるフォルダに移動してFlaskアプリのサービングを開始します。今回は動作確認までが目標なので、ネットワークの全IPからの接続を受け付けるように「--host=0.0.0.0」と設定します。
$ cd path/to/flask $ export FLASK_APP=mnist_app.py $ export FLASK_ENV=development $ flask run --host=0.0.0.0
これでECSがサービングしているので、ECSのセキュリティグループを正しく設定していれば、ブラウザで「IPアドレス:5000」にアクセスするとアプリが表示されるはずです。(サービングに使うポートはmnist_app.pyの最後に「5000」と設定しています。)
SBCloudのロゴ付きパーカーを「シャツ」と分類してしまっていますが、そもそもMNIST-fashionデータに「パーカー」のカテゴリーが存在しないので仕方がないです笑。
まとめ
これまでの3回の記事を通して、デモアプリが完成しました。
このように、機械学習アプリというのはデータを扱ったりモデルやアプリを開発したりと、色々な要素が組み合わさっています。それをクラウドという同一環境の中で行うことで、よりスムースにインテグレーションができるようになります。PAIの「DSW」と「EAS」はAIアプリ開発の中で重要な部分を占めています。
ただし、今回作ったデモアプリは、コードのテスト、モデルの精度の向上、サービスのセキュリティやパフォーマンスなどにおいて、まだ色々な課題があるので、皆さんはそれらに注意してイケてる機械学習アプリを作ってみてくださいね。