3700万パラメータの GPT モデルを Azure Container Apps で動かす

フルマネージドのサーバレスコンテナサービスである **Azure Container Apps** で、Transformersの言語モデルを動かしてみました。

https://azure.microsoft.com/ja-jp/products/container-apps/

なお本稿は以前Google Cloud Runを使って書いた記事のAzure版です。Cloud Runに似たサービスであるAzure Container Appsで、同様のことをしてみました。

https://qiita.com/suzuki_sh/items/0f0ecfce8f5984afeeab#fn-gpt-medium-pr

## 環境
- Docker version 20.10.17, build dea9396
- Docker Compose version v2.6.1
- Azure CLI 2.40.0

2022年10月15日時点の情報に基づいています。

## ローカルでアプリケーションの構築
[Cloud Runの時](https://qiita.com/suzuki_sh/items/0f0ecfce8f5984afeeab#%E5%AE%9F%E8%A3%85)と同様に、適当なPromptを入れたらGPTで続きを書いてくれるアプリケーションを構築します。モデルには3700万パラメータの言語モデルである[rinna/japanese-gpt2-xsmall](https://huggingface.co/rinna/japanese-gpt2-xsmall)を使います。

実際に使ったソースコードは下記になります。

https://github.com/s2terminal/gpt-container

これはCloud Run用に開発したものとソースコードは全く同一のままで、一行も書き換えていません。Cloud Run特有の設定が少しだけ入っていますが、そのままにしておいてもAzure Container Appsで動作します。

cloneしたら`$ docker compose up`して localhost:8000 にアクセスし、正常に動作することを確認しておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50391/54a140cb-2542-c816-f94b-59157b6fd0b2.png)

適当なpromptを入れると、無事に続きが出力されます。

## Azure Container Appsへのデプロイ
Azure Container Appsへデプロイしてみます。

### コンテナレジストリ
今回は、Docker Hub のプライベートリポジトリに予めイメージを登録しておいて、Azure Container Appsにデプロイしてみます。

Azureには **Azure Container Registry** があります。

https://azure.microsoft.com/ja-jp/products/container-registry/

これを使うとよりシンプルにデプロイできますが、[価格](https://azure.microsoft.com/ja-jp/pricing/details/container-registry/)が1日24円～とちょっと趣味で使うには高額な印象です。
今回は別のレジストリとして[Docker Hub](https://hub.docker.com/)を利用します。パスワード認証でpullできるコンテナレジストリであればおそらく何でも使えると思います。

先程のアプリケーションをDocker Hubのプライベートリポジトリにビルドして上げておきます。

### Azureへのデプロイ
Azure CLIを使って構築していきます。Azure CLIが使えて`$ az login`しているならどこでもいいですが、今回は[Azureポータル](https://portal.azure.com/)のCloud Shellを使います。

だいたい下記の手順に沿ってデプロイします。

https://learn.microsoft.com/ja-jp/azure/container-apps/get-started-existing-container-image?tabs=bash&pivots=container-apps-private-registry

まずは変数を登録しておきます。

```bash
LOCATION="japaneast"
RESOURCE_GROUP="sample-gpt-container"
CONTAINERAPPS_ENVIRONMENT="sample-gpt-container-environment"
CONTAINERAPPS_NAME="sample-gpt-container-app"
CONTAINER_IMAGE_NAME=registry.hub.docker.com/s2terminal/gpt-container
REGISTRY_SERVER=registry.hub.docker.com
REGISTRY_USERNAME=<REGISTRY_USERNAME>
REGISTRY_PASSWORD=<REGISTRY_PASSWORD>
```

- `LOCATION` は日本なら`japaneast`（`japanwest`はまだContainer Appsが非対応）
- `RESOURCE_GROUP`, `CONTAINERAPPS_ENVIRONMENT`, `CONTAINERAPPS_NAME`は好きな名前をつける
- `CONTAINER_IMAGE_NAME`, `REGISTRY_SERVER`は登録してあるコンテナレジストリに応じて変更

まずAzureのリソースグループを構築します。

```bash
$ az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION
```

Azure Container Apps 環境を構築します。

```bash
$ az containerapp env create \
  --name $CONTAINERAPPS_ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION
```

Azure Container Apps を構築します。

```bash
$ az containerapp create \
  --name $CONTAINERAPPS_NAME \
  --resource-group $RESOURCE_GROUP \
  --image $CONTAINER_IMAGE_NAME \
  --environment $CONTAINERAPPS_ENVIRONMENT \
  --registry-server $REGISTRY_SERVER \
  --registry-username $REGISTRY_USERNAME \
  --registry-password $REGISTRY_PASSWORD \
  --ingress external \
  --target-port 8000 \
  --min-replicas 0 \
  --max-replicas 1 \
  --env-vars PORT=8000
```

[今回構築したアプリケーション](https://github.com/s2terminal/gpt-container)はGoogle Cloud Run用に`PORT`環境変数を受け取ったポートを受け付ける設定になっていますので、ここでは`--env-vars PORT=8000`で設定しています。

無事に構築完了すると、`latestRevisionFqdn`に構築されたアプリケーションにアクセスできるドメインが出力されます。Azureポータルの「コンテナーアプリ」→「概要」→「アプリケーションURL」からも確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50391/a4f7e1b5-cbb2-bf18-b56b-9232b1445f8b.png)

URLにブラウザでアクセスし、適当な入力をして続きが出力されたら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50391/279a47d0-bbc5-0e3f-02ca-8e9964331f28.png)

簡単ですね。

「コンテナーアプリ」→「メトリック」から、起動中のアプリの様子を確認できます。「Replica Count」と「Requests」を表示してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50391/4f44b886-dfc3-a53e-d394-a4fe55c929f7.png)

アクセスをしなくなってから数分後、レプリカ数がゼロになっているのが確認できました。[Azure Container Appsはレプリカ数がゼロにスケールインすると利用料金が発生しなくなります](https://learn.microsoft.com/ja-jp/azure/container-apps/billing#no-replicas-are-running)。そうでなくても無料枠があるので、趣味で触る程度なら非常に低価格で利用できると思います。

### Azure Container Appsのスペック
今回Azure Container Appsにメモリ・CPUを指定せずにデプロイしましたが、デフォルトで 0.5コア/1GiB になっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50391/48134e14-0768-ce57-f893-5431417010ed.png)

Azure Container Appsのメモリは現時点で最大4.0Giです。[特定のCPU/メモリの組み合わせ](https://learn.microsoft.com/ja-jp/azure/container-apps/containers)である必要があります。今回は[rinna/japanese\-gpt2\-xsmall](https://huggingface.co/rinna/japanese-gpt2-xsmall)という比較的小さめなモデルを使いましたが、より大きなモデルを動かすにはちょっと心細いスペックです。
[Google Cloud Runでは最大32GiBまで使える](https://cloud.google.com/run/docs/configuring/memory-limits#max)ので、これはAzureの今後のアップデートに期待です。

## まとめ
GPTの言語モデルをAzure Container Appsにデプロイできました。サーバレスプラットフォームで動かせるのが、当たり前になりつつあります。今後もう少しスペックが上げられたり、GPUが割り当てられるようになれば、十分使えるようになると思います。

## 参考
- [クイック スタート: Azure CLI を使用して既存のコンテナー イメージをデプロイする \| Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/container-apps/get-started-existing-container-image?tabs=bash&pivots=container-apps-private-registry)
- [az containerapp \| Microsoft Learn](https://learn.microsoft.com/ja-jp/cli/azure/containerapp?view=azure-cli-latest#az-containerapp-create)