TorchServe を使用して GKE でスケーラブルな LLM を提供する

このチュートリアルでは、TorchServe フレームワークを使用して、スケーラブルな ML モデルを Google Kubernetes Engine(GKE)クラスタにデプロイして提供する方法について説明します。ユーザー リクエストに基づいて予測を生成する事前トレーニング済みの PyTorch モデルを提供します。モデルをデプロイすると、アプリケーションが予測リクエストの送信に使用する予測 URL を取得できるようになります。この方法では、モデルとウェブ アプリケーションを個別にスケーリングできます。ML ワークロードとアプリケーションを Autopilot にデプロイすると、GKE はワークロードを実行するために基盤となる適切なマシンタイプとサイズを選択します。

このチュートリアルは、GKE Autopilot を使用してノードの構成、スケーリング、アップグレードにおける管理オーバーヘッドを削減することに関心がある、機械学習(ML)のエンジニア、プラットフォーム管理者および運用担当者、データスペシャリスト、AI スペシャリストを対象としています。 Google Cloud のコンテンツで使用されている一般的なロールとタスクの例の詳細については、一般的な GKE ユーザーのロールとタスクをご覧ください。

このページを読む前に、GKE Autopilot モードについて理解しておいてください。

チュートリアルのアプリケーションについて

このアプリケーションは、Fast Dash フレームワークを使用して作成された小さな Python ウェブ アプリケーションです。このアプリケーションを使用して、予測リクエストを T5 モデルに送信します。このアプリケーションは、ユーザーのテキスト入力と言語ペアをキャプチャし、その情報をモデルに送信します。このモデルはテキストを翻訳してアプリケーションに結果を返し、その結果をユーザーに表示します。Fast Dash の詳細については、Fast Dash のドキュメントをご覧ください。

環境を準備する

サンプル リポジトリのクローンを作成し、チュートリアル ディレクトリを開きます。

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/ai-ml/t5-model-serving

クラスタを作成する

次のコマンドを実行します。

gcloud container clusters create-auto ml-cluster \
    --release-channel=RELEASE_CHANNEL \
    --cluster-version=CLUSTER_VERSION \
    --location=us-central1

次のように置き換えます。

  • RELEASE_CHANNEL: クラスタのリリース チャンネル。rapidregularstable のいずれかにする必要があります。L4 GPU を使用するため、GKE バージョン 1.28.3-gke.1203000 以降のチャンネルを選択します。特定のチャンネルで利用可能なバージョンを確認するには、リリース チャンネルのデフォルト バージョンと利用可能なバージョンを表示するをご覧ください。
  • CLUSTER_VERSION: 使用する GKE のバージョン。1.28.3-gke.1203000 以降にする必要があります。

オペレーションが完了するまでに数分かかります。

Artifact Registry リポジトリを作成する

  1. クラスタと同じリージョンに、Docker 形式で新しい Artifact Registry 標準リポジトリを作成します。

    gcloud artifacts repositories create models \
        --repository-format=docker \
        --location=us-central1 \
        --description="Repo for T5 serving image"
    
  2. リポジトリ名を確認します。

    gcloud artifacts repositories describe models \
        --location=us-central1
    

    出力は次のようになります。

    Encryption: Google-managed key
    Repository Size: 0.000MB
    createTime: '2023-06-14T15:48:35.267196Z'
    description: Repo for T5 serving image
    format: DOCKER
    mode: STANDARD_REPOSITORY
    name: projects/PROJECT_ID/locations/us-central1/repositories/models
    updateTime: '2023-06-14T15:48:35.267196Z'
    

モデルをパッケージ化する

このセクションでは、Cloud Build を使用してモデルとサービング フレームワークを単一のコンテナ イメージにパッケージ化し、生成されたイメージを Artifact Registry リポジトリに push します。

  1. コンテナ イメージの Dockerfile を確認します。

    # Copyright 2023 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     https://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    ARG BASE_IMAGE=pytorch/torchserve:0.12.0-cpu
    
    FROM alpine/git
    
    ARG MODEL_NAME=t5-small
    ARG MODEL_REPO=https://huggingface.co/${MODEL_NAME}
    ENV MODEL_NAME=${MODEL_NAME}
    ENV MODEL_VERSION=${MODEL_VERSION}
    
    RUN git clone "${MODEL_REPO}" /model
    
    FROM ${BASE_IMAGE}
    
    ARG MODEL_NAME=t5-small
    ARG MODEL_VERSION=1.0
    ENV MODEL_NAME=${MODEL_NAME}
    ENV MODEL_VERSION=${MODEL_VERSION}
    
    COPY --from=0 /model/. /home/model-server/
    COPY handler.py \
         model.py \
         requirements.txt \
         setup_config.json /home/model-server/
    
    RUN  torch-model-archiver \
         --model-name="${MODEL_NAME}" \
         --version="${MODEL_VERSION}" \
         --model-file="model.py" \
         --serialized-file="pytorch_model.bin" \
         --handler="handler.py" \
         --extra-files="config.json,spiece.model,tokenizer.json,setup_config.json" \
         --runtime="python" \
         --export-path="model-store" \
         --requirements-file="requirements.txt"
    
    FROM ${BASE_IMAGE}
    
    ENV PATH /home/model-server/.local/bin:$PATH
    ENV TS_CONFIG_FILE /home/model-server/config.properties
    # CPU inference will throw a warning cuda warning (not error)
    # Could not load dynamic library 'libnvinfer_plugin.so.7'
    # This is expected behaviour. see: https://stackoverflow.com/a/61137388
    ENV TF_CPP_MIN_LOG_LEVEL 2
    
    COPY --from=1 /home/model-server/model-store/ /home/model-server/model-store
    COPY config.properties /home/model-server/
    

    この Dockerfile では、次の複数のステージのビルドプロセスを定義します。

    1. Hugging Face リポジトリからモデル アーティファクトをダウンロードします。
    2. PyTorch Serving Archive ツールを使用してモデルをパッケージ化します。これにより、推論サーバーがモデルを読み込むために使用するモデル アーカイブ(.mar)ファイルが作成されます。
    3. PyTorch Serve を使用して最終的なイメージをビルドします。
  2. Cloud Build を使用してイメージをビルドして push します。

    gcloud builds submit model/ \
        --region=us-central1 \
        --config=model/cloudbuild.yaml \
        --substitutions=_LOCATION=us-central1,_MACHINE=gpu,_MODEL_NAME=t5-small,_MODEL_VERSION=1.0
    

    ビルドプロセスの完了には数分かかります。モデルサイズが t5-small よりも大きい場合、ビルドプロセスに著しく時間がかかる可能性があります。

  3. イメージがリポジトリにあることを確認します。

    gcloud artifacts docker images list us-central1-docker.pkg.dev/PROJECT_ID/models
    

    PROJECT_ID は、実際の Google CloudPROJECT_ID に置き換えます。

    出力は次のようになります。

    IMAGE                                                     DIGEST         CREATE_TIME          UPDATE_TIME
    us-central1-docker.pkg.dev/PROJECT_ID/models/t5-small     sha256:0cd...  2023-06-14T12:06:38  2023-06-14T12:06:38
    

パッケージ化されたモデルを GKE にデプロイする

このチュートリアルでは、Kubernetes Deployment を使用してイメージをデプロイします。Deployment は、クラスタ内のノードに分散された Pod の複数のレプリカを実行できる Kubernetes API オブジェクトです。

環境に合わせてサンプル リポジトリの Kubernetes マニフェストを変更します。

  1. 推論ワークロードのマニフェストを確認します。

    # Copyright 2023 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     https://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: t5-inference
      labels:
        model: t5
        version: v1.0
        machine: gpu
    spec:
      replicas: 1
      selector:
        matchLabels:
          model: t5
          version: v1.0
          machine: gpu
      template:
        metadata:
          labels:
            model: t5
            version: v1.0
            machine: gpu
        spec:
          nodeSelector:
            cloud.google.com/gke-accelerator: nvidia-l4
          securityContext:
            fsGroup: 1000
            runAsUser: 1000
            runAsGroup: 1000
          containers:
            - name: inference
              image: us-central1-docker.pkg.dev/PROJECT_ID/models/t5-small:1.0-gpu
              imagePullPolicy: IfNotPresent
              args: ["torchserve", "--start", "--foreground"]
              resources:
                limits:
                  nvidia.com/gpu: "1"
                  cpu: "3000m"
                  memory: 16Gi
                  ephemeral-storage: 10Gi
                requests:
                  nvidia.com/gpu: "1"
                  cpu: "3000m"
                  memory: 16Gi
                  ephemeral-storage: 10Gi
              ports:
                - containerPort: 8080
                  name: http
                - containerPort: 8081
                  name: management
                - containerPort: 8082
                  name: metrics
              readinessProbe:
                httpGet:
                  path: /ping
                  port: http
                initialDelaySeconds: 120
                failureThreshold: 10
              livenessProbe:
                httpGet:
                  path: /models/t5-small
                  port: management
                initialDelaySeconds: 150
                periodSeconds: 5
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: t5-inference
      labels:
        model: t5
        version: v1.0
        machine: gpu
    spec:
      type: ClusterIP
      selector:
        model: t5
        version: v1.0
        machine: gpu
      ports:
        - port: 8080
          name: http
          targetPort: http
        - port: 8081
          name: management
          targetPort: management
        - port: 8082
          name: metrics
          targetPort: metrics
    

  2. PROJECT_ID は、実際の Google CloudPROJECT_ID に置き換えます。

    sed -i "s/PROJECT_ID/PROJECT_ID/g" "kubernetes/serving-gpu.yaml"
    

    これにより、Deployment 仕様のコンテナ イメージのパスが、Artifact Registry の T5 モデルイメージのパスと一致するようになります。

  3. Kubernetes リソースを作成します。

    kubectl create -f kubernetes/serving-gpu.yaml
    

モデルが正常にデプロイされたことを確認するには、次の操作を行います。

  1. Deployment と Service のステータスを取得します。

    kubectl get -f kubernetes/serving-gpu.yaml
    

    次のような準備完了の Pod が出力に表示されるまで待ちます。イメージのサイズによっては、最初のイメージの pull に数分かかることがあります。

    NAME                            READY   UP-TO-DATE    AVAILABLE   AGE
    deployment.apps/t5-inference    1/1     1             0           66s
    
    NAME                    TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)                       AGE
    service/t5-inference    ClusterIP   10.48.131.86    <none>        8080/TCP,8081/TCP,8082/TCP    66s
    
  2. t5-inference Service のローカルポートを開きます。

    kubectl port-forward svc/t5-inference 8080
    
  3. 新しいターミナル ウィンドウを開き、テスト リクエストを Service に送信します。

    curl -v -X POST -H 'Content-Type: application/json' -d '{"text": "this is a test sentence", "from": "en", "to": "fr"}' "http://localhost:8080/predictions/t5-small/1.0"
    

    テスト リクエストが失敗し、Pod 接続が閉じた場合は、ログを確認します。

    kubectl logs deployments/t5-inference
    

    出力が次のような場合、TorchServe は一部のモデル依存関係のインストールに失敗しています。

    org.pytorch.serve.archive.model.ModelException: Custom pip package installation failed for t5-small
    

    この問題を解決するには、Deployment を再起動します。

    kubectl rollout restart deployment t5-inference
    

    Deployment コントローラが新しい Pod を作成します。上記の手順を繰り返して、新しい Pod でポートを開きます。

ウェブ アプリケーションを使用して、デプロイされたモデルにアクセスする

Fast Dash ウェブ アプリケーションでデプロイされたモデルにアクセスするには、次の操作を行います。

  1. Fast Dash ウェブ アプリケーションを、Artifact Registry のコンテナ イメージとしてビルドして push します。

    gcloud builds submit client-app/ \
        --region=us-central1 \
        --config=client-app/cloudbuild.yaml
    
  2. テキスト エディタで kubernetes/application.yaml を開き、image: フィールドの PROJECT_ID をプロジェクト ID に置き換えます。あるいは、次のコマンドを実行します。

    sed -i "s/PROJECT_ID/PROJECT_ID/g" "kubernetes/application.yaml"
    
  3. Kubernetes リソースを作成します。

    kubectl create -f kubernetes/application.yaml
    

    Deployment と Service が完全にプロビジョニングされるまでに時間がかかることがあります。

  4. ステータスを確認するには、次のコマンドを実行します。

    kubectl get -f kubernetes/application.yaml
    

    次のような準備完了の Pod が出力に表示されるまで待ちます。

    NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/fastdash   1/1     1            0           1m
    
    NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    service/fastdash   NodePort   203.0.113.12    <none>        8050/TCP         1m
    
  5. ウェブ アプリケーションは実行されていますが、外部 IP アドレスで公開されていません。ウェブ アプリケーションにアクセスするには、ローカルポートを開きます。

    kubectl port-forward service/fastdash 8050
    
  6. ブラウザでウェブ インターフェースを開きます。

    • ローカルシェルを使用している場合は、ブラウザを開いて http://127.0.0.1:8050 に移動します。
    • Cloud Shell を使用している場合は、[ウェブでプレビュー]、[ポートを変更] の順にクリックします。ポート 8050 を指定します。
  7. T5 モデルにリクエストを送信するには、ウェブ インターフェースの [TEXT]、[FROM LANG]、[TO LANG] の各フィールドに値を指定して、[送信] をクリックします。使用可能な言語の一覧については、T5 のドキュメントをご覧ください。

モデルの自動スケーリングを有効にする

このセクションでは、Google Cloud Managed Service for Prometheus の指標に基づいてモデルの自動スケーリングを有効にする方法について説明します。手順は次のとおりです。

  1. カスタム指標の Stackdriver アダプタをインストールする
  2. PodMonitoring と HorizontalPodAutoscaling 構成を適用する

Google Cloud Managed Service for Prometheus は、バージョン 1.25 以降を実行している Autopilot クラスタではデフォルトで有効になっています。

カスタム指標の Stackdriver アダプタをインストールする

このアダプタを使用すると、クラスタで Prometheus の指標を使用して Kubernetes の自動スケーリングに関する決定を行うことができます。

  1. アダプタをデプロイします。

    kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
    
  2. アダプタが使用する IAM サービス アカウントを作成します。

    gcloud iam service-accounts create monitoring-viewer
    
  3. IAM サービス アカウントに、プロジェクトに対する monitoring.viewer ロールと iam.workloadIdentityUser ロールを付与します。

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:monitoring-viewer@PROJECT_ID.iam.gserviceaccount.com" \
        --role roles/monitoring.viewer
    gcloud iam service-accounts add-iam-policy-binding monitoring-viewer@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.workloadIdentityUser \
        --member "serviceAccount:PROJECT_ID.svc.id.goog[custom-metrics/custom-metrics-stackdriver-adapter]"
    

    PROJECT_ID は、実際の Google CloudPROJECT_ID に置き換えます。

  4. アダプタの Kubernetes ServiceAccount にアノテーションを付けて、IAM サービス アカウントの権限を借用できるようにします。

    kubectl annotate serviceaccount custom-metrics-stackdriver-adapter \
        --namespace custom-metrics \
        iam.gke.io/gcp-service-account=monitoring-viewer@PROJECT_ID.iam.gserviceaccount.com
    
  5. アダプタを再起動して変更を反映します。

    kubectl rollout restart deployment custom-metrics-stackdriver-adapter \
        --namespace=custom-metrics
    

PodMonitoring と HorizontalPodAutoscaling 構成を適用する

PodMonitoring は、特定の Namespace で指標の取り込みとターゲットのスクレイピングを可能にする Google Cloud Managed Service for Prometheus カスタム リソースです。

  1. TorchServe Deployment と同じ Namespace に PodMonitoring リソースをデプロイします。

    kubectl apply -f kubernetes/pod-monitoring.yaml
    
  2. HorizontalPodAutoscaler マニフェストを確認します。

    # Copyright 2023 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     https://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: t5-inference
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: t5-inference
      minReplicas: 1
      maxReplicas: 5
      metrics:
      - type: Pods
        pods:
          metric:
            name: prometheus.googleapis.com|ts_queue_latency_microseconds|counter
          target:
            type: AverageValue
            averageValue: "30000"
    

    HorizontalPodAutoscaler は、リクエスト キューの累積期間に基づいて T5 モデルの Pod 数をスケーリングします。自動スケーリングは、キューの累積継続時間をマイクロ秒単位で示す ts_queue_latency_microseconds 指標に基づいています。

  3. HorizontalPodAutoscaler を作成します。

    kubectl apply -f kubernetes/hpa.yaml
    

負荷生成ツールを使用して自動スケーリングを確認する

自動スケーリングの構成をテストするには、サービスを提供するアプリケーションの負荷を生成します。このチュートリアルでは、Locust 負荷生成ツールを使用して、モデルの予測エンドポイントにリクエストを送信します。

  1. 負荷生成ツールを作成します。

    kubectl apply -f kubernetes/loadgenerator.yaml
    

    負荷生成ツール Pod の準備が整うまで待ちます。

  2. 負荷生成ツールのウェブ インターフェースをローカルで公開します。

    kubectl port-forward svc/loadgenerator 8080
    

    エラー メッセージが表示された場合は、Pod の実行中にもう一度お試しください。

  3. ブラウザで、負荷生成ツールのウェブ インターフェースを開きます。

    • ローカルシェルを使用している場合は、ブラウザを開いて http://127.0.0.1:8080 に移動します。
    • Cloud Shell を使用している場合は、[ウェブでプレビュー]、[ポートを変更] の順にクリックします。ポート 8080 を入力します。
  4. [グラフ] タブをクリックして、パフォーマンスの推移を確認します。

  5. 新しいターミナル ウィンドウを開き、HorizontalPodAutoscaler のレプリカ数を確認します。

    kubectl get hpa -w
    

    レプリカの数は、負荷が増加すると増加します。スケールアップに 10 分ほどかかる場合があります。新しいレプリカが開始されると、Locust チャートで成功したリクエストの数が増加します。

    NAME           REFERENCE                 TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
    t5-inference   Deployment/t5-inference   71352001470m/7M   1         5        1           2m11s
    

推奨事項

  • サービングに使用するのと同じバージョンのベース Docker イメージでモデルをビルドします。
  • モデルに特別なパッケージ依存関係がある場合、または依存関係のサイズが大きい場合は、ベース Docker イメージのカスタム バージョンを作成します。
  • モデルの依存関係パッケージのツリー バージョンを監視します。パッケージの依存関係が互いのバージョンをサポートしていることを確認します。たとえば、Panda バージョン 2.0.3 は NumPy バージョン 1.20.3 以降をサポートしています。
  • GPU ノードでは GPU 負荷の高いモデルを実行し、CPU ノードでは CPU 負荷の高いモデルを実行します。これにより、モデル サービングの安定性が向上し、ノードリソースを効率的に消費できます。

モデルのパフォーマンスをモニタリングする

モデルのパフォーマンスをモニタリングするには、Cloud Monitoring で TorchServe ダッシュボードの統合を使用します。このダッシュボードでは、トークンのスループット、リクエスト レイテンシ、エラー率などの重要なパフォーマンス指標を確認できます。

TorchServe ダッシュボードを使用するには、GKE クラスタで Google Cloud Managed Service for Prometheus を有効にする必要があります。これにより、TorchServe から指標が収集されるようになります。TorchServe はデフォルトで Prometheus 形式の指標を公開します。追加のエクスポータをインストールする必要はありません。

こうして、TorchServe ダッシュボードを開いて指標を確認できます。Google Cloud Managed Service for Prometheus を使用してモデルから指標を収集する方法については、Cloud Monitoring のドキュメントの中の TorchServe のオブザーバビリティ ガイダンスをご覧ください。