NVIDIA NIMを使用して、アリババクラウドACKでLLM推論を加速

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/use-nvidia-nim-to-accelerate-llm-inference-in-alibaba-cloud-ack_601823?spm=a2c65.11461433.0.0.4ee35355vU3MBl)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

大規模言語モデル(LLM)は、近年急速に発展し、様々な業界のニーズに応えるために新たなシナリオを生み出す熱いトピックです。オープンソースモデルの継続的な強化に伴い、ますます多くの企業がそれらを本番環境にデプロイし、AIモデルを既存のインフラストラクチャと接続して、システムのレイテンシーとスループットを最適化し、監視とセキュリティを向上させています。しかし、この一連のモデル推論サービスを本番環境でデプロイすることは複雑であり、時間のかかる作業です。その過程を簡素化し、企業が生成型AIモデルのデプロイを加速するために、本記事では[NVIDIA NIM](https://www.nvidia.com/en-us/ai/#referrer=ai-subdomain)（高性能AIモデルの安全かつ信頼性の高いデプロイメントを目的としたマイクロサービスのセット、使いやすい事前構築されたコンテナ化ツールのセット）と[アリババクラウドコンテナサービスfor Kubernetes（ACK）](https://www.alibabacloud.com/help/en/ack)などの製品を組み合わせます。記事が提供する一連の即戦力のある操作ガイドを使用することで、高性能で可観測的、柔軟で弾性的なLLMモデル推論サービスを迅速に構築できます。ACKのクラウドネイティブAIスイートACKは、世界で最初のサービスの1つとしてCertified Kubernetes Conformance Programに参加しており、高度なコンテナ化アプリケーション管理サービスを提供し、企業向けのコンテナ化アプリケーションのライフサイクル管理をサポートしています。ACKを使用することで、クラウド上でコンテナ化アプリケーションを簡単に効率的に実行・管理できます。[クラウドネイティブAIスイート](https://www.alibabacloud.com/help/en/ack/cloud-native-ai-suite/)は、ACKによって提供されるクラウドネイティブAI技術と製品の解決策であり、クラウドネイティブアーキテクチャと技術を活用して、ACK内でAI支援の生産システムを迅速に開発することを支援します。また、AIまたは機械学習アプリケーションやシステムに対してフルスタックの最適化も提供しています。クラウドネイティブAIスイートは、Kubeflowコミュニティのオープンソースプロジェクトであるコマンドラインツール[Arena](https://github.com/kubeflow/arena)を提供し、深層学習の主要なプロダクションタスク（データ管理、モデルトレーニング、モデル評価、推論サービスのデプロイなど）を簡素化し効率的に管理しながら、Kubernetesの概念の複雑さを軽減します。Arenaを使用することで、分散トレーニングタスクを迅速に提出し、タスクのライフサイクルを管理できます。さらに、クラウドネイティブAIスイートは、例えばGPUカードの利用量向上のためにbinpackアルゴリズムを使用してGPUカードを割り当てるなど、分布式シナリオ向けに最適化されたスケジューリングポリシーも提供しています。カスタムタスク優先度管理とテナントの弾性的なリソースクォータ制御もサポートしており、ユーザーのリソース割り当てを確保しながら、クラスター全体のリソース利用効率を向上させるためのリソース共有も可能です。概要本記事では、クラウドネイティブAIスイートを使用してオープンソース推論サービスフレームワーク[KServe](https://github.com/kserve/kserve)を統合し、ACKクラスターでNVIDIA NIMを迅速にデプロイする方法を説明します。PrometheusのマネージドサービスとGrafanaのマネージドサービスを使用して、リアルタイムで推論サービスの状態を監視するダッシュボードを迅速に構築できます。NVIDIA NIMが提供するnum_requests_waitingなどのさまざまなモニタリングメトリックを使用して、キュー待ちのリクエスト数に基づいて推論サービスの弾性スケーリングポリシーを構成できます。トラフィックの急増が、推論サービスで処理される必要があるリクエストを待機リストに入れる場合、新しいインスタンスが自動的にスケールアウトされ、ピークトラフィックに対応することができます。全体的なソリューションのアーキテクチャは以下の通りです：
![1](https://yqintl.alicdn.com/20624c353670be2f16a9db6caa8d1a70304e3fc2.jpeg)ACK上のNVIDIA NIM本記事では、ACKクラスターにNVIDIA NIMをデプロイする手順を紹介します。手順は以下の通りです：1. GPU搭載のACKクラスターを作成し、クラウドネイティブAIスイート、ack-kserve、その他のコンポーネントをインストールします。2. Arenaを使用してKServe推論サービスを提出し、NVIDIA NIMコンテナを使用してllama3 8Bモデルをデプロイします。3. 推論サービスのモニタリングを設定し、リアルタイムで推論サービスの状態を監視できます。4. キュー待ちのリクエスト数に基づいて、モデルサービスインスタンスのスケールを自動で柔軟に調整するための弾性スケーリングポリシーを構成します。手順1. [NVIDIA NIMのドキュメント](https://docs.nvidia.com/nim/large-language-models/latest/getting-started.html#generate-an-api-key)を参照して、[NVIDIA NGC](https://catalog.ngc.nvidia.com/?filters=&orderBy=weightPopularDESC&query=&page=&pageSize=)のAPIキーを生成し、この記事で使用する[Llama3-8b-instruct](https://build.nvidia.com/meta/llama3-8b)などのモデルイメージへのアクセス権を申請します。Llama Modelの[カスタム商用オープンソースライセンス契約](https://ai.meta.com/resources/models-and-libraries/llama-downloads/nim-deploy)を読み、遵守してください。2. NGCプライベートリポジトリからNIMイメージをプルするために、imagePullSecretを作成します。```export NGC_API_KEY=<your-ngc-api-key>kubectl create secret docker-registry ngc-secret \    --docker-server=nvcr.io\    --docker-username='$oauthtoken'\    --docker-password=${NGC_API_KEY}```3. コンテナ内でNGCプライベートリポジトリにアクセスするために、nvidia-nim-secretを作成します。詳細は[nim-deployデプロイメントドキュメント](https://github.com/NVIDIA/nim-deploy/blob/main/kserve/README.md)をご覧ください。```kubectl apply -f-<<EOFapiVersion: v1kind: Secretmetadata:  name: nvidia-nim-secretsstringData:  NGC_API_KEY: <your-ngc-api-key>EOF```4. 対象クラスター内にPVとPVCを構成します。その後のモデルファイルは、作成した共有ストレージにダウンロードされます。NASボリュームの使用については、[こちら](https://www.alibabacloud.com/help/en/ack/ack-managed-and-ack-dedicated/user-guide/mount-statically-provisioned-nas-volumes)をご覧ください。PVのパラメーターは以下の通りです：| パラメーター | 説明 || --- | --- || PVタイプ | NAS || 名称 | nim-model || アクセスマード | ReadWriteMany || マウントターゲットのドメイン名 | マウントターゲットを選択するか、カスタムマウントターゲットを入力できます。マウントターゲットのドメイン名の確認方法については、[こちら](https://www.alibabacloud.com/help/en/nas/user-guide/manage-mount-targets#section-sjv-ozt-711)をご覧ください。 || マウントパス | モデルが配置されるパスを指定します（例：/nim-model）。|PVCのパラメーターは以下の通りです：| パラメーター | 説明 || --- | --- || PVCタイプ | NAS || 名称 | nim-model || 分配モード | 既存のボリュームを指定してください。既存のボリュームを選択する際は、ハイパーリンクをクリックし、作成したPVを選択してください。|5. 次のようにコマンドを実行して
```markdown
## ArenaでKServeを使用してモデルをデプロイする

```bash
arena serve kserve \
--name=llama3-8b-instruct \
--image=nvcr.io/nim/meta/llama3-8b-instruct:1.0.0 \
--image-pull-secret=ngc-secret \
--gpus=1 \
--cpu=8 \
--memory=32Gi \
--share-memory=32Gi \
--port=8000 \
--security-context runAsUser=0 \
--annotation=serving.kserve.io/autoscalerClass=external \
--env NIM_CACHE_PATH=/mnt/models \
--env-from-secret NGC_API_KEY=nvidia-nim-secrets \
--enable-prometheus=true \
--metrics-port=8000 \
--data=nim-model:/mnt/models
```

期待される出力:

```
INFO[0004] ジョブ llama3-8b-instruct が正常に提出されました
INFO[0004] ジョブの状態を確認するには、`arena serve get llama3-8b-instruct --type kserve -n default` を実行してください
```

上記の出力は、推論サービスがデプロイされたことを示しています。

6. 推論サービスがデプロイされた後、KServe推論サービスのデプロイ状況を確認するためには、以下のコマンドを実行します:

```bash
arena serve get llama3-8b-instruct
```

期待される出力:

```
名前:       llama3-8b-instruct
ネームスペース:  デフォルト
タイプ:       KServe
バージョン:    1
希望数:    1
利用可能:  1
期間:        24分
アドレス:    http://llama3-8b-instruct-default.example.com
ポート:       :80
GPU:        1
インスタンス:
  名前                                           ステータス   年齢  レディ  リスタート  GPU  ノード
  ----                                           ------   ---  -----  --------  ---  ----
  llama3-8b-instruct-predictor-545445b4bc-97qc5  実行中  24分
    1/1    0         1    ap-southeast-1.172.16.xx.xxx
```

上記の出力は、KServe推論サービスがデプロイされ、モデルへのアクセスアドレスが次のようであることを示しています:

[http://llama3-8b-instruct-default.example.com](http://llama3-8b-instruct-default.example.com/?spm=a2c6h.13046898.publish-article.5.5fa26ffaLKKu5K)

7. 取得したNGINX IngressのIPアドレスを通じて、推論サービスにアクセスすることができます。

```bash
# NGINX IngressのIPアドレスを取得する
NGINX_INGRESS_IP=$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}')

# 推論サービスのHostnameを取得する
SERVICE_HOSTNAME=$(kubectl get inferenceservice llama3-8b-instruct -o jsonpath='{.status.url}' | cut -d "/" -f 3)

# 推論サービスにアクセスするリクエストを送信する
curl -H "Host: $SERVICE_HOSTNAME" -H "Content-Type: application/json" http://$NGINX_INGRESS_IP:80/v1/chat/completions -d '{"model": "meta/llama3-8b-instruct", "messages": [{"role": "user", "content": "昔々"}], "max_tokens": 64, "temperature": 0.7, "top_p": 0.9, "seed": 10}'
```

期待される出力:

```json
{"id":"cmpl-70af7fa8c5ba4fe7b903835e326325ce","object":"chat.completion","created":1721557865,"model":"meta/llama3-8b-instruct","choices":[{"index":0,"message":{"role":"assistant","content":"物語を始めるようなですね！私はそれを聞きたいと思います。\"昔々\"から続きを話しましょう"},"logprobs":null,"finish_reason":"stop","stop_reason":128009}],"usage":{"prompt_tokens":14,"total_tokens":45,"completion_tokens":31}}
```

上記の出力は、NGINX IngressのIPアドレスを通じて推論サービスにアクセスでき、推論結果が返されることを示しています。

### 監視

NVIDIA NIMは、最初のトークン遅延、現在実行中のリクエスト数、要求されたトークン数、生成されたトークン数などの様々なPrometheus監視メトリックを提供します。これらのメトリックを使用して、PrometheusのマネージドサービスとGrafanaのマネージドサービスを使って迅速にGrafanaのダッシュボードを作成し、推論サービスの状態をリアルタイムで観察することができます。

1. ACKクラスターでPrometheusのマネージドサービスを有効にする方法については、[Prometheusサービスの有効化](https://www.alibabacloud.com/help/ja/ack/ack-managed-and-ack-dedicated/user-guide/use-alibaba-cloud-prometheus-service-to-monitor-an-ack-cluster?spm=a2c4g.11186623.0.0.612b63c5QDfm5F#section-o0u-mkk-58y)をご参照ください。

2. Grafanaのワークスペースを作成し、ダッシュボードページにログインします。

3. NVIDIA NIMが提供する[ダッシュボードのサンプル](https://docscontent.nvidia.com/sphinx/0000018f-7ee8-d345-a7bf-ffeadf9c0000/0000018f-7ee7-db2d-a1ff-7ef744750000/nim/large-language-models/latest/_downloads/66e67782ce543dcccec574b1483f0ea0/nim-dashboard-example.json)をインポートします。

4. インポート後のダッシュボードの例:

![ダッシュボード例](https://yqintl.alicdn.com/00a72cd7543d49afc42b41544a7020b8b988ccdb.jpeg)

### 自動スケーリング

KServeを使用してモデルを推論サービスとしてデプロイすると、負荷が動的に変動する状況に対応するために、モデルがデプロイされた推論サービスが必要となります。KServeは、CPU使用率、メモリ使用量、GPU使用率、カスタムパフォーマンスメトリックに基づいて、Horizonal Pod Autoscaler (HPA)技術とスケーリングコントローラーを統合して、モデルのポッドを自動かつ柔軟にスケールします。これによりサービスのパフォーマンスと安定性が確保されます。

#### カスタムメトリックに基づく自動スケーリングポリシーの設定

カスタムメトリックに基づく自動スケーリングは、ACKが提供するHorizonal Pod Autoscalerのメカニズムとack-alibaba-cloud-metrics-adapterコンポーネントに基づいて実装されます。詳細については、[Prometheusサービスのメトリックに基づく水平ポッドのスケーリング](https://www.alibabacloud.com/help/ja/ack/serverless-kubernetes/user-guide/horizontal-pod-scaling-based-on-prometheus-service-metrics-1)をご覧ください。以下は、NVIDIA NIMが提供するnum_requests_waitingメトリックに基づくスケーリングポリシーの設定例です。

1. Prometheusのマネージドサービスとack-alibaba-cloud-metrics-adapterをデプロイする方法については、上記のリンクを参照してください。

2. Helmページで、ack-alibaba-cloud-metrics-adapterのアクション列から更新をクリックし、カスタムフィールドに以下のルールを追加します:

```yaml
- seriesQuery: num_requests_waiting{namespace!="",pod!=""}
  resources:
    overrides:
      namespace: {resource: "namespace"}
      pod: {resource: "pod"}
  metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)
```

3. カスタムメトリックに基づいて自動スケーリングを行う。例えば、待機中のリクエ
```markdown
## スケールターゲット参照の設定

```yaml
scaleTargetRef:
  apiVersion: apps/v1
  kind: Deployment
  name: llama3-8b-instruct-predictor
```

HPAを作成するためのコマンドを実行してください：

```bash
kubectl apply -f hpa.yaml
```

HPAの状態を確認するためのコマンドを実行してください：

```bash
kubectl get hpa llama3-8b-instruct-hpa
```

期待される出力：

```
NAME                     REFERENCE                                 TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
llama3-8b-instruct-hpa   Deployment/llama3-8b-instruct-predictor   0/10      1         3         1          34s
```

5. 次のコマンドを実行して、サービスに対するストレステストを行います。詳細については、[Hey](https://github.com/rakyll/hey)を参照してください。

```bash
hey -z 5m -c 400 -m POST -host $SERVICE_HOSTNAME -H "Content-Type: application/json" -d '{"model": "meta/llama3-8b-instruct", "messages": [{"role": "user", "content": "昔々"}], "max_tokens": 64}' http://$NGINX_INGRESS_IP:80/v1/chat/completions
```

6. ストレステスト中に別のターミナルを開き、次のコマンドを実行してサービスのスケーリング状況を確認してください。

```bash
kubectl describe hpa llama3-8b-instruct-hpa
```

期待される出力には以下のようなイベントが含まれます：

```
Events:
  Type    Reason             Age   From                       Message
  ----    ------             ----  ----                       -------
  Normal  SuccessfulRescale  52s   horizontal-pod-autoscaler  New size: 3; reason: pods metric num_requests_waiting above target
```

上記の出力から、ストレステスト中にポッド数が2に増加したことがわかりますが、約5分後に1に減少しています。つまり、ポッドのスケーリングが可能であることを示しています。

## 要約
本記事では、NVIDIA NIMをアリババクラウドのKubernetesコンテナサービスにデプロイし、PrometheusのマネージドサービスとGrafanaのマネージドサービスを使用して、Grafana上で監視ダッシュボードを迅速に構築しました。これにより、推論サービスの状態をリアルタイムで観測できるようになりました。推論サービスが直面する動的に変化する負荷に対応するために、保留中のリクエスト数に基づくカスタムメトリックに基づく自動スケーリングポリシーを設定しました。これにより、モデルの推論サービスインスタンスは待機中のリクエスト数に応じて動的にスケールアウトできます。上記の方法を使用することで、可観測性があり極めて弾性的な高性能モデルの推論サービスを迅速に構築することができます。