ページの先頭です

ページ内を移動するためのリンク
本文へ (c)

ここから本文です。

GPUプラットフォームにおけるAIモデルの開発と推論 - AIモデル開発と推論サービスの実現

ライター:奈良 昌紀
通信事業者のデータセンターにおいてネットワーク・サーバー運用を経験した後、ネットワンシステムズに入社。帯域制御やWAN高速化製品担当を経て、2008年から仮想化関連製品を担当。現在は主にクラウド、仮想インフラの管理、自動化、ネットワーク仮想化を担当。

目次

はじめに

こちらのBlog記事ではコンテナ環境でGPUを活用するためのNVIDIA AI Enterprise + VMware vSphere® with VMware Tanzu® をご紹介しました。今回は2回の記事に分けて、この環境を利用して自然言語処理モデルであるBERTをチューニングし、開発したAIモデルをTriton Inference ServerによりKubernetes上でコンテナとして実行し、Kubernetesのオートスケール機能によってスケールアウト・スケールインを実現する方法をご紹介します。

  • BERT (Bidirectional Encoder Representations from Transformers)

BERTはGoogleが開発した深層学習を利用した自然言語処理モデルの1つです。翻訳、文書分類、質問応答等の自然言語処理タスクに対してBERTの学習は大量データによる「事前学習」と少量データによる「ファインチューニング」の2段階でモデルの開発を行います。NVIDIAはNGCを通じて事前学習済みのBERTモデルを公開しており、NVIDIAが公開するBERTはGoogleの公式実装をNVIDIAのGPUに最適化しています。

  • SQuAD (The Stanford Question Answering Dataset)

SQuAD(The Stanford Question Answering Dataset)はスタンフォード大学が作った質問応答データセットです。Wikipedia 英語版の記事とその記事内容に対する質問、その回答のテキストのセットで構成されており、500以上の記事と100,000以上の質問と回答のペアが含まれています。 SQuADによりBERTの事前学習モデルをファインチューニングすることで、質疑応答タスク向けのモデルを作成することが可能です。

  • NVIDIA Triton Inference Server™

NVIDIA Triton Inference ServerTensorFlowTensorRTPyTorchOpenVINORAPIDS FILLightGBMONNX Runtime等のメジャーなフレームワークをデプロイすることが可能です。また、C++やPythonで独自の処理を実装し、同様にデプロイすることも可能です。これらのフレームワークで生成したモデルを変換することなくGPUやCPUサーバーにデプロイすることが可能です。データサイエンティストは、フレームワークやネットワークを自由に選択することができ、開発者とIT運用者はこれらのネットワークによって訓練されたモデルを簡単にサポートすることが可能です。

開発環境の構築とモデル開発

仮想マシンの作成

vSphere with TanzuではSupervisor ClusterVM Serviceを利用して、Tanzu Kubernetes Cluster 環境に加え、単体の仮想マシンをデプロイすることが可能です。今回は機械学習モデルを開発する環境として Ubuntuベースの仮想マシンを作成します。モデルの開発に利用するコンテナイメージは各種ライブラリが含まれているため、比較的大容量となります。コンテナイメージが格納されるデータ領域(/var/lib/docker)と、モデルを格納するホームディレクトリ領域(/home)に対してPersistent Volume Claimを作成して仮想マシンに接続して、ディスク容量を増やし、データを永続化します。

apiVersion: vmoperator.vmware.com/v1alpha1
kind: VirtualMachine
metadata:
  name: gpu-vm1
  labels:
    app: gpu-vm1
spec:
  imageName: ubuntu-20-1633387172196
  className: a30-mig-24g
  powerState: poweredOn
  storageClass: unity-k8s
  vmMetadata:
    configMapName: vm1-cm
    transport: OvfEnv
  networkInterfaces:
  - networkType: nsx-t
  volumes:
  - name: gpu-vm1-pvc1
    persistentVolumeClaim:
      claimName: gpu-vm1-pvc1
  - name: gpu-vm1-pvc2
    persistentVolumeClaim:
      claimName: gpu-vm1-pvc2

.spec.classNameとして指定しているa30-mig-24gはNVIDIA A30のGPUメモリー24GBを共有モードとして「マルチインスタンスGPU共有」(MIG)でvGPUを構成します。

仮想マシンのスペック(.spec.vmMetadata)としてcloud-configのデータを含むConfigMapを指定することで仮想マシンをカスタマイズすることが可能です。ConfigMap内ではユーザーの作成や、接続されたPersistent Volume Claimのマウントポイント等を設定します。作成した仮想マシンのSSHJupyter Notebookに対して外部から接続できるよう、VirtualMachinesServiceLoadBalancerとして作成します。

apiVersion: vmoperator.vmware.com/v1alpha1
kind: VirtualMachineService
metadata:
  name: gpu-vm1-svc
spec:
  selector:
    app: gpu-vm1
  type: LoadBalancer
  ports:
  - name: jupyter
    port: 8888
    protocol: TCP
    targetPort: 8888
  - name: ssh
    port: 22
    protocol: TCP
    targetPort: 22

VM上のコンテナでvGPUを利用してモデル開発を行うため、仮想マシンにはNVIDIAドライバー、NVIDIA Container Toolkit、Dockerをインストールします。

BERTモデルのファインチューニング

NVIDIAが公開しているDeepLearningExamplesリポジトリを利用して、VM上でTensorflowコンテナを実行し、Jupyter Notebook経由でBERTモデルのファインチューニングを行います。DeepLearningExamplesリポジトリには、モデル開発で利用するための各種スクリプトとNotebook

NGCで公開されているコンテナイメージ(tensorflow-2-0:22.02-tf1-nvaie-2.0-py3)をベースとして、モデル作成用のコンテナイメージをビルドし、launch.shによってコンテナを起動します。launch.shスクリプトの実行により、VMのカレントディレクトリ(DeepLearningExamples/TensorFlow/LanguageModeling/BERT/)が/workspace/bert/resultsとしてマウントされます。

git clone https://github.com/NVIDIA/DeepLearningExamples.git
cd DeepLearningExamples/TensorFlow/LanguageModeling/BERT/
docker build . --rm -t bert --build-arg FROM_IMAGE_NAME=nvcr.io/nvaie/tensorflow-2-0:22.02-tf1-nvaie-2.0-py3
bash scripts/docker/launch.sh

コンテナ内でファインチューニングに利用するSQuaD 1.1データセットをダウンロードします。

python3 /workspace/bert/data/bertPrep.py --action download --dataset squad

コンテナ内でJupyter Notebookを起動します。

jupyter notebook --ip=0.0.0.0 --allow-root

Jupyter Notebookの起動が成功すると、GUIにアクセスするためのTokenが表示されます。ブラウザでVMの8888番ポートにアクセスし、生成されたTokenを利用してJupyter Notebookにログインし、notebooksフォルダ内のbert_squad_tf_finetuning.ipynbを開き、「BERT Question Answering Fine-Tuning with Mixed Precision」を実行します。

このNotebookではNVIDIAが公開しているBERTのTensorFlow事前学習モデルをNGCからダウンロードし、SQuAD v1.1データセットによってファインチューニングしてモデルを再生成します。

BERTモデルのエクスポート

実行中のnotebookをshutdownして、作成したファインチューニングしたモデルをrun_squad.pyスクリプトでコンテナ内の/workspace/bert/tritionディレクトリにTritonで読み込める形式としてエクスポートします。

python run_squad.py --vocab_file=/workspace/bert/data/download/finetuned_large_model_SQUAD1.1/vocab.txt --bert_config_file=/workspace/bert/data/download/finetuned_large_model_SQUAD1.1/bert_config.json --init_checkpoint=/workspace/bert/data/download/finetuned_large_model_SQUAD1.1/model.ckpt --max_seq_length=384 --doc_stride=128 --predict_batch_size=8 --output_dir=/workspace/bert/triton --export_triton=True --amp --use_xla

指定したディレクトリ(/workspace/bert/triton)triton_models/bertディレクトリが作成され、配下にTriton向けのモデルが格納されます。

$ tree triton
triton 
└── triton_models
    └── bert
        ├── 1
        │   └── model.savedmodel
        │       ├── saved_model.pb
        │       └── variables
        │           ├── variables.data-00000-of-00001
        │           └── variables.index
        └── config.pbtxt

推論環境の構築

Tanzu Kubernetes Clusterのデプロイ

今回は推論サーバーをKubernetes上でコンテナとして実行するため、vGPUノードで構成されるTanzu Kubernetes Clusterを作成します。vGPUを持つノードプールと持たないノードプールで構成されるクラスターを作成します。vGPUを持つノードプールは仮想マシンクラスとして、NVIDIA A100のGPUメモリー10GBを共有モードとして「時間の共有」(Time Sharing)でvGPUを構成します。

2022年6月現在、MIGで構成されるvGPU環境の利用において、DCGM ExporterはUtilizationに関するメトリックを出力することができない等の制約があります。後述のHPAによるオートスケールを実現するには、Time SharingによるvGPUで構成されるTanzu Kubernetes Clusterを作成する必要があります。

GPU Operatorのインストール

作成したTanzu Kubernetes Cluster上でDCGM Exporterを利用することによりNVIDIA GPUの各種メトリックを取得することが可能になります。こちらのBlog記事で紹介した方法でNVIAEGPU OperatorをインストールするとDCGM Exporterもインストールされます。

$ helm install gpu-operator nvaie/gpu-operator-2-0 -n gpu-operator

インストールを確認します。gpu-operator-2-0-v1.10.1がインストールされていることが確認できます。

$ helm list -n gpu-operator
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                           APP VERSION
gpu-operator    gpu-operator    1               2022-06-22 13:50:33.30332478 +0900 JST  deployed        gpu-operator-2-0-v1.10.1        v1.10.1

dcgm-exporterはDaemonSetとしてデプロイされ、vGPUを持つノード上でのみ起動します。

$ kubectl get daemonset -n gpu-operator -l app=nvidia-dcgm-exporter
NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                              AGE
nvidia-dcgm-exporter   4         4         4       4            4           nvidia.com/gpu.deploy.dcgm-exporter=true   26m
$ kubectl get pod -n gpu-operator -owide -l app=nvidia-dcgm-exporter
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE                                                        NOMINATED NODE   READINESS GATES
nvidia-dcgm-exporter-52cqg   1/1     Running   0          25m   172.20.24.103   a100-vgpu-cluster-a100-ts-10g-pool-9fwjz-678dc589fc-j48xx   <none>           <none>
nvidia-dcgm-exporter-hz88n   1/1     Running   0          23m   172.20.25.20    a100-vgpu-cluster-a100-ts-10g-pool-9fwjz-678dc589fc-6d4kz   <none>           <none>
nvidia-dcgm-exporter-q6ms7   1/1     Running   0          23m   172.20.22.161   a100-vgpu-cluster-a100-ts-10g-pool-9fwjz-678dc589fc-xvzth   <none>           <none>
nvidia-dcgm-exporter-qxng9   1/1     Running   0          25m   172.20.26.132   a100-vgpu-cluster-a100-ts-10g-pool-9fwjz-678dc589fc-qvzgs   <none>           <none>

モデルの配置

Triton Inference ServerをKubernetes上にデプロイする場合、NFS共有にTritonモデルリポジトリを配置し、Triton Inference ServerをDeploymentリソースとして実行します。Deploymentリソースとして定義することにより、KubernetesのHorizontal Pod Autoscaler (HPA)によりレプリカ数を制御し、Triton推論サーバーのオートスケールが可能になります。今回はTritonモデルリポジトリとして利用するNFS共有をvSAN File Serviceによって構成します。

作成したファイル共有を学習環境のVMにマウントし、作成したBERTモデルをコピーします。

$ sudo mkdir /models
$ sudo mount -t nfs gpu1.tanzu.techlab.netone.co.jp:/datastore /models
$ sudo cp -r DeepLearningExamples/TensorFlow/LanguageModeling/BERT/triton/triton_models/bert /models/
$ tree /models
/models
└── bert
    ├── 1
    │   └── model.savedmodel
    │       ├── saved_model.pb
    │       └── variables
    │           ├── variables.data-00000-of-00001
    │           └── variables.index
    └── config.pbtxt
4 directories, 4 files

上記ファイル共有をKubernetes上で利用できるよう、PersistentVolumeとPersistent Volume Claimを作成します。

$ kubectl get pv,pvc
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                   STORAGECLASS   REASON   AGE
nfs-pv   500Gi      RWX            Retain           Bound    triton-server/nfs-pvc                           45s                         
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   500Gi      RWX                           30s

Triton Inference Serverの起動

Triton Inference Serverを実行するためのDeploymentマニフェストを作成します。Deploymentではモデルを配置したPVCVolumeとして/modelsにマウントし、Pod内のTriton Inference Serverから参照します。尚、Triton Inference Servertritonserver-2-0:22.02-nvaie-2.0-py3としてNGCで公開されているイメージを利用していますが、vSphere with Tanzu環境のレジストリ(Harbor)に再配置し、コンテナイメージのダンロード時間を短縮しています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bert-qa
  labels:
    app: triton-server
spec:
  selector:
    matchLabels:
      app: triton-server
  replicas: 1
  template:
    metadata:
      labels:
        app: triton-server
    spec:
      imagePullSecrets:
      - name: nvaie-demo-default-image-pull-secret
      volumes:
      - name: model-repo
        persistentVolumeClaim:
          claimName: nfs-pvc
      containers:
      - name: serving
        image: 10.44.187.8/nvaie-demo/tritonserver-2-0:22.02-nvaie-2.0-py3
        ports:
        - name: grpc
          containerPort: 8001
        - name: http
          containerPort: 8000
        - name: metrics
          containerPort: 8002
        volumeMounts:
        - name: model-repo
          mountPath: "/models"
        resources:
          limits:
            nvidia.com/gpu: 1
        command: ["tritonserver", "--model-store=/models"]
      volumes:
      - name: model-repo
        persistentVolumeClaim:
          claimName: nfs-pvc

ClusterIPによりTriton Inference Serverにアクセスできるよう、Serviceリソースを作成します。TCP8000はREST API、TCP8001はgRPC、TCP8002はメトリックを提供します。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: triton-server
  name: bert-qa
spec:
  ports:
  - name: port-1
    port: 8001
    protocol: TCP
    targetPort: 8001
  - name: port-2
    port: 8000
    protocol: TCP
    targetPort: 8000
  - name: port-3
    port: 8002
    protocol: TCP
    targetPort: 8002
  selector:
    app: triton-server
  type: LoadBalancer

上記マニフェストによりTriton Inference Serverをデプロイすると、以下のようにPodとServiceが作成されます。

$ kubectl get pod,svc
NAME                           READY   STATUS    RESTARTS   AGE
pod/bert-qa-74dbc5fcbc-7zsh9   1/1     Running   0          22s
NAME              TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                        AGE
service/bert-qa   LoadBalancer   10.96.131.35   10.44.187.5   8001:31971/TCP,8000:32370/TCP,8002:31714/TCP   22s

Podのログを確認すると、PVC上のファインチューニングしたBERTモデルをロードしてTriton Inference Serverが起動していることが確認できます。

I0624 03:58:41.201744 1 server.cc:592]
+-------+---------+--------+
| Model | Version | Status |
+-------+---------+--------+
| bert  | 1       | READY  |
+-------+---------+--------+
I0624 03:58:41.238073 1 metrics.cc:623] Collecting metrics for GPU 0: GRID A100D-10C

EXTERNAL-IP経由でTriton Inference ServerのREST APIでBERTモデルにアクセスすると応答が確認できます。

$ curl 10.44.187.5:80008000/v2/models/bert/ready
HTTP/1.1 200 OK
Content-Length: 0
Content-Type: text/plain

以上で、作成したBERTモデルをTriton Inference Serverでホストすることができました。

次回はKubernetes上にデプロイしたTriton Inference ServerをHorizontal Pod Autoscalingによりオートスケールする方法を説明します。

※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。

RECOMMEND