はじめに
前回ローカル環境に Phoenix と Bumblebee による AI REST API を実装しました
今回はこれを Docker コンテナで動かします
実装の全量はこちら
実行ファイルの作成
前回作成した Phoenix プロジェクト api ディレクトリー内に serve というファイル名で Phoenix を起動するシェルを作成します
#!/bin/bash
mix phx.server
この serve
というファイル名も SageMaker の仕様に沿っています
実行できるように権限を付けておきます
chmod +x serve
chmod
がパーミッション(権限)変更コマンドで、 +x
指定で誰でも実行できるようにしています
serving.ex の変更
コンテナで実行する場合、コンテナ内のストレージに保存したファイルはビルド毎に破棄されてしまいます
Bumblebee でダウンロードするモデルのキャッシュディレクトリーはコンテナの外にしておいた方が便利です
lib/api_web/serving.ex をキャッシュディレクトリーを指定するように変更します
...
@resnet_id "microsoft/resnet-50"
+ @cache_dir "/opt/ml/model"
def start_link(_opts) do
{:ok, model} =
- Bumblebee.load_model({:hf, @resnet_id})
+ Bumblebee.load_model({:hf, @resnet_id, cache_dir: @cache_dir})
{:ok, featurizer} =
- Bumblebee.load_featurizer({:hf, @resnet_id})
+ Bumblebee.load_featurizer({:hf, @resnet_id, cache_dir: @cache_dir})
...
依存モジュールとビルド結果の削除
api ディレクトリー配下でローカル実行時に作成されたディレクトリーを削除します
ローカルとコンテナ内では OS が違うため、そのまま同じものを使いまわせないためです
rm -rf _build
rm -rf deps
Docker ファイルの作成
api の親ディレクトリーに Dockerfile を作成します
FROM elixir:1.14.2
RUN mix local.hex --force \
&& mix local.rebar --force
COPY ./api /app
WORKDIR /app
RUN mix deps.get
RUN mix compile.phoenix
RUN chmod +x /app/serve
ENV PATH="/app:${PATH}"
EXPOSE 8080
CMD ["serve"]
-
Elixir 1.14.2 のコンテナをベースにしています
-
api ディレクトリー配下の Phoenix プロジェクトを動かすようにしています
-
コンテナ内でも serve に実行権限を追加しています
-
SageMaker では
serve
がコンテナ起動時に実行されるため、 PATH に/app
を追加してserve
だけで実行できるようにします -
ポート番号 8080 を外部に公開します
docker-compose.yml の作成
Dockerfile と同じディレクトリーに docker-compose.yml を作成します
---
version: '3.2'
services:
web:
container_name: phoenix
build: .
ports:
- '8080:8080'
command: serve
environment:
- MIX_ENV=dev
volumes:
- ./tmp:/tmp
- ./models:/opt/ml/model
-
コンテナ内の 8080 を localhost の 8080 に紐づけています
-
コンテナ起動時には serve を実行するようにしています
-
環境変数 MIX_ENV に dev を指定しています
-
ローカルの ./tmp をコンテナ内の /tmp にマウントします
Bumblebee は /tmp にまずモデルファイルをダウンロードするため、ここはキャッシュディレクトリーと同じファイルシステムである必要があります
./tmp がなければ作成しておいてください
-
ローカルの ./models をコンテナ内の /opt/ml/model にマウントします
ここが Bumblebee のキャッシュディレクトリーになります
./models がなければ作成しておいてください
コンテナの起動
コンテナを起動し、しばらくすると Phoenix が起動します
$ docker-compose up --build
...
Attaching to phoenix
phoenix | Compiling 11 files (.ex)
phoenix | Generated api app
phoenix | [info] TfrtCpuClient created.
phoenix | [info] Running ApiWeb.Endpoint with cowboy 2.9.0 at 0.0.0.0:8080 (http)
phoenix | [info] Access ApiWeb.Endpoint at http://localhost:8080
動作確認
別のターミナルを開きます
まず ping を確認します
$ curl http://localhost:8080/ping
{}%
空の JSON が返ってきます
次に推論を確認します
@sample.jpg
の部分は手元の JPEG ファイルのパスに変えてください
jq をインストールしている場合は jq にパイプすると見やすいです
$ curl -XPOST http://localhost:8080/invocations \
--data-binary @sample.jpg \
--header "Content-Type:image/jpeg" | jq
{
"predictions": [
{
"label": "notebook, notebook computer",
"score": 0.6154251098632812
},
{
"label": "laptop, laptop computer",
"score": 0.11529479920864105
},
{
"label": "bow tie, bow-tie, bowtie",
"score": 0.03906528279185295
},
{
"label": "projector",
"score": 0.0267447829246521
},
{
"label": "dining table, board",
"score": 0.024912187829613686
}
]
}
まとめ
SageMaker で推論実行できるコンテナの条件が揃いました
- serve で Web サーバーを起動する
- ポート番号 は 8080
- /ping で常に正常応答する
- /invocations で推論を実行する
次回、このコンテナを SageMaker にデプロイし、 AI のマイクロサービスとして動作させます