部署可扩缩的 TensorFlow 推理系统

Last reviewed 2023-11-02 UTC

本文档介绍如何部署可扩缩的 TensorFlow 推理系统中所述的参考架构。

本系列文章面向熟悉 Google Kubernetes Engine 和机器学习 (ML) 框架(包括 TensorFlow 和 NVIDIA TensorRT)的开发者。

完成本部署后,请参阅衡量和优化 TensorFlow 推理系统的性能

架构

下图展示了推理系统的架构。

推理系统的架构。

Cloud Load Balancing 将请求流量发送到最近的 GKE 集群。集群中的每个节点包含一个 Pod。在每个 Pod 中,Triton 推理服务器提供推理服务(以服务 ResNet-50 模型),而 NVIDIA T4 GPU 可提高性能。集群上的监控服务器会收集有关 GPU 利用率和内存用量的指标数据。

如需了解详情,请参阅可扩缩的 TensorFlow 推理系统

目标

  • 下载 ResNet-50 预训练模型,并使用 TensorFlow 与 TensorRT (TF-TRT) 的集成来应用优化
  • 从 NVIDIA Triton 推理服务器提供 ResNet-50 模型
  • 使用 PrometheusGrafana 为 Titon 构建监控系统
  • 使用 Locust 构建负载测试工具

费用

除了 NVIDIA T4 GPU 之外,在此部署中,您还可以使用 Google Cloud 的以下收费组件:

如需根据您的预计使用量来估算费用,请使用价格计算器

完成此部署后,请勿删除您创建的资源。测量和调整部署时,您需要这些资源。

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the GKE API.

    Enable the API

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the GKE API.

    Enable the API

使用 TF-TRT 构建优化模型

在本部分,您将创建一个工作环境并优化预训练模型。

预训练模型使用 gs://cloud-tpu-test-datasets/fake_imagenet/ 中的虚构数据集。Cloud Storage 位置 gs://solutions-public-assets/tftrt-tutorial/resnet/export/1584366419/ 中还有一个预训练模型的副本。

创建工作环境

在您的工作环境中,您可以使用 Deep Learning VM Image 创建 Compute Engine 实例。您将在此实例上使用 TensorRT 优化和量化 ResNet-50 模型。

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  2. 部署名为 working-vm 的实例:

    gcloud config set project PROJECT_ID
    gcloud config set compute/zone us-west1-b
    gcloud compute instances create working-vm \
        --scopes cloud-platform \
        --image-family common-cu113 \
        --image-project deeplearning-platform-release \
        --machine-type n1-standard-8 \
        --min-cpu-platform="Intel Skylake" \
        --accelerator=type=nvidia-tesla-t4,count=1 \
        --boot-disk-size=200GB \
        --maintenance-policy=TERMINATE \
        --metadata="install-nvidia-driver=True"
    

    PROJECT_ID 替换为您之前创建的 Google Cloud 项目的 ID。

    此命令使用 NVIDIA T4 启动 Compute Engine 实例。首次启动时,它会自动安装与 TensorRT 5.1.5 兼容的 NVIDIA GPU 驱动程序。

采用不同优化方式创建模型文件

在本部分中,您可以使用 TF-TRT 将以下优化应用于原始 ResNet-50 模型:

  • 图优化
  • 使用图优化转换为 FP16
  • 使用 INT8 通过图优化进行量化

如需详细了解这些优化,请参阅性能优化

  1. 在 Google Cloud 控制台中,转到 Compute Engine > 虚拟机实例

    转到“虚拟机实例”

    您会看到您之前创建的 working-vm 实例。

  2. 如需打开实例的终端控制台,请点击 SSH

    您可以使用此终端运行本文档中的其余命令。

  3. 在终端中,克隆所需的代码库并更改当前目录:

    cd $HOME
    git clone https://github.com/GoogleCloudPlatform/gke-tensorflow-inference-system-tutorial
    cd gke-tensorflow-inference-system-tutorial/server
    
  4. 将预训练的 ResNet-50 模型下载到本地目录:

    mkdir -p models/resnet/original/00001
    gcloud storage cp gs://solutions-public-assets/tftrt-tutorial/resnet/export/1584366419/* models/resnet/original/00001 --recursive
    
  5. 构建一个包含 TF-TRT 优化工具的容器映像:

    docker build ./ -t trt-optimizer
    docker image list
    

    最后一个命令会显示一个代码库表。

  6. 在表中,找到 tft-optimizer 代码库的行,复制映像 ID。

  7. 将优化(图优化、转换为 FP16 和使用 INT8 量化)应用于原始模型:

    export IMAGE_ID=IMAGE_ID
    
    nvidia-docker run --rm \
        -v `pwd`/models/:/workspace/models ${IMAGE_ID} \
        --input-model-dir='models/resnet/original/00001' \
        --output-dir='models/resnet' \
        --precision-mode='FP32' \
        --batch-size=64
    
    nvidia-docker run --rm \
        -v `pwd`/models/:/workspace/models ${IMAGE_ID} \
        --input-model-dir='models/resnet/original/00001' \
        --output-dir='models/resnet' \
        --precision-mode='FP16' \
        --batch-size=64
    
    nvidia-docker run --rm \
        -v `pwd`/models/:/workspace/models ${IMAGE_ID} \
        --input-model-dir='models/resnet/original/00001' \
        --output-dir='models/resnet' \
        --precision-mode='INT8' \
        --batch-size=64 \
        --calib-image-dir='gs://cloud-tpu-test-datasets/fake_imagenet/' \
        --calibration-epochs=10
    

    IMAGE_ID 替换为您在上一步复制的 tft-optimizer 的映像 ID。

    --calib-image-dir 选项指定用于预训练模型的训练数据的位置。相同的训练数据用于 INT8 量化的校准。校准过程可能需要大约 5 分钟。

    命令运行完毕后,最后一个输出行类似于以下内容,其中优化的模型保存在 ./models/resnet 中:

    INFO:tensorflow:SavedModel written to: models/resnet/INT8/00001/saved_model.pb
    

    目录结构类似于以下内容:

    models
    └── resnet
        ├── FP16
        │   └── 00001
        │       ├── saved_model.pb
        │       └── variables
        ├── FP32
        │   └── 00001
        │       ├── saved_model.pb
        │       └── variables
        ├── INT8
        │   └── 00001
        │       ├── saved_model.pb
        │       └── variables
        └── original
            └── 00001
                ├── saved_model.pb
                └── variables
                    ├── variables.data-00000-of-00001
                    └── variables.index
    

下表总结了目录和优化之间的关系。

目录 优化
FP16 除图优化外,转换为 FP16
FP32 图优化
INT8 除图优化外,使用 INT8 进行量化
original 原始模型(未经 TF-TRT 优化)

部署推理服务器

在本部分中,您将部署具有五个模型的 Triton 服务器。首先,将您在上一部分中创建的模型二进制文件上传到 Cloud Storage。然后创建一个 GKE 集群并在该集群上部署 Triton 服务器。

上传模型二进制文件

  • 在 SSH 终端中,将模型二进制文件和 config.pbtxt 配置文件上传到存储桶:

    export PROJECT_ID=PROJECT_ID
    export BUCKET_NAME=${PROJECT_ID}-models
    
    mkdir -p original/1/model/
    cp -r models/resnet/original/00001/* original/1/model/
    cp original/config.pbtxt original/1/model/
    cp original/imagenet1k_labels.txt original/1/model/
    
    mkdir -p tftrt_fp32/1/model/
    cp -r models/resnet/FP32/00001/* tftrt_fp32/1/model/
    cp tftrt_fp32/config.pbtxt tftrt_fp32/1/model/
    cp tftrt_fp32/imagenet1k_labels.txt tftrt_fp32/1/model/
    
    mkdir -p tftrt_fp16/1/model/
    cp -r models/resnet/FP16/00001/* tftrt_fp16/1/model/
    cp tftrt_fp16/config.pbtxt tftrt_fp16/1/model/
    cp tftrt_fp16/imagenet1k_labels.txt tftrt_fp16/1/model/
    
    mkdir -p tftrt_int8/1/model/
    cp -r models/resnet/INT8/00001/* tftrt_int8/1/model/
    cp tftrt_int8/config.pbtxt tftrt_int8/1/model/
    cp tftrt_int8/imagenet1k_labels.txt tftrt_int8/1/model/
    
    mkdir -p tftrt_int8_bs16_count4/1/model/
    cp -r models/resnet/INT8/00001/* tftrt_int8_bs16_count4/1/model/
    cp tftrt_int8_bs16_count4/config.pbtxt tftrt_int8_bs16_count4/1/model/
    cp tftrt_int8_bs16_count4/imagenet1k_labels.txt tftrt_int8_bs16_count4/1/model/
    
    gcloud storage buckets create gs://${BUCKET_NAME}
    gcloud storage cp original tftrt_fp32 tftrt_fp16 tftrt_int8 tftrt_int8_bs16_count4 \
        gs://${BUCKET_NAME}/resnet/ --recursive
    

    PROJECT_ID 替换为您之前创建的 Google Cloud 项目的 ID。

    config.pbtxt 文件中指定以下调节参数:

    • 模型名称
    • 输入张量名称和输出张量名称
    • 为每个模型分配 GPU
    • 实例组的批次大小和数量

    例如,original/1/model/config.pbtxt 文件包含以下内容:

    name: "original"
    platform: "tensorflow_savedmodel"
    max_batch_size: 64
    input {
        name: "input"
        data_type: TYPE_FP32
        format: FORMAT_NHWC
        dims: [ 224, 224, 3 ]
    }
    output {
        name: "probabilities"
        data_type: TYPE_FP32
        dims: 1000
        label_filename: "imagenet1k_labels.txt"
    }
    default_model_filename: "model"
    instance_group [
      {
        count: 1
        kind: KIND_GPU
      }
    ]
    dynamic_batching {
      preferred_batch_size: [ 64 ]
      max_queue_delay_microseconds: 20000
    }
    

如需详细了解批次大小和实例组的数量,请参阅性能优化

下表汇总了您在本部分部署的五个模型。

模型名称 优化
original 原始模型(未经 TF-TRT 优化)
tftrt_fp32 图优化
(批次大小=64,实例组=1)
tftrt_fp16 除图优化外,转换为 FP16
(批次大小=64,实例组=1)
tftrt_int8 除图优化外,使用 INT8 进行量化
(批次大小=64,实例组=1)
tftrt_int8_bs16_count4 除图优化外,使用 INT8 进行量化
(批次大小=16,实例组=4)

使用 Titon 部署推理服务器

  1. 在 SSH 终端中,安装和配置身份验证软件包,该软件包用于管理 GKE 集群:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    sudo apt-get install google-cloud-sdk-gke-gcloud-auth-plugin
    
  2. 创建 GKE 集群和具有使用 NVIDIA T4 GPU 的计算节点的 GPU 节点池:

    gcloud auth login
    gcloud config set compute/zone us-west1-b
    gcloud container clusters create tensorrt-cluster \
        --num-nodes=20
    gcloud container node-pools create t4-gpu-pool \
        --num-nodes=1 \
        --machine-type=n1-standard-8 \
        --cluster=tensorrt-cluster \
        --accelerator type=nvidia-tesla-t4,count=1
    

    --num-nodes 标志为 GKE 集群指定 20 个实例,为 GPU 节点池 t4-gpu-pool 指定一个实例。

    GPU 节点池包含一个带有 NVIDIA T4 GPU 的 n1-standard-8 实例。GPU 实例数量应大于或等于推理服务器 pod 的数量,因为在同一实例上多个 pod 不能共用 NVIDIA T4 GPU。

  3. 显示集群信息:

    gcloud container clusters list
    

    输出类似于以下内容:

    NAME              LOCATION    MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION    NUM_NODES  STATUS
    tensorrt-cluster  us-west1-b  1.14.10-gke.17  XX.XX.XX.XX    n1-standard-1  1.14.10-gke.17  21         RUNNING
    
  4. 显示节点池信息:

    gcloud container node-pools list --cluster tensorrt-cluster
    

    输出类似于以下内容:

    NAME          MACHINE_TYPE   DISK_SIZE_GB  NODE_VERSION
    default-pool  n1-standard-1  100           1.14.10-gke.17
    t4-pool       n1-standard-8  100           1.14.10-gke.17
    
  5. 启用 daemonSet 工作负载:

    gcloud container clusters get-credentials tensorrt-cluster
    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/nvidia-driver-installer/cos/daemonset-preloaded.yaml
    

    此命令会在 GPU 节点池中的节点上加载 NVIDIA GPU 驱动程序。当您向 GPU 节点池添加新节点时,它也会自动加载驱动程序。

  6. 在集群上部署推理服务器:

    sed -i.bak "s/YOUR-BUCKET-NAME/${PROJECT_ID}-models/" trtis_deploy.yaml
    kubectl create -f trtis_service.yaml
    kubectl create -f trtis_deploy.yaml
    
  7. 等待几分钟,直到服务可用。

  8. 获取 Triton 的 clusterIP 地址,并将其存储在环境变量中:

    export TRITON_IP=$(kubectl get svc inference-server \
      -o "jsonpath={.spec['clusterIP']}")
    echo ${TRITON_IP}
    

此时,推理服务器提供您在采用不同优化方式创建模型文件部分中创建的四个 ResNet-50 模型。客户端可以指定在发送推理请求时要使用的模型。

使用 Prometheus 和 Grafana 部署监控服务器

  1. 在 SSH 终端中,在集群上部署 Prometheus 服务器:

    sed -i.bak "s/CLUSTER-IP/${TRITON_IP}/" prometheus-configmap.yml
    kubectl create namespace monitoring
    kubectl apply -f prometheus-service.yml -n monitoring
    kubectl create -f clusterRole.yml
    kubectl create -f prometheus-configmap.yml -n monitoring
    kubectl create -f prometheus-deployment.yml -n monitoring
    
  2. 获取 Prometheus 服务的端点网址。

    ip_port=$(kubectl get svc prometheus-service \
      -o "jsonpath={.spec['clusterIP']}:{.spec['ports'][0]['port']}" -n monitoring)
    echo "http://${ip_port}"
    

    记下 Prometheus 端点网址,因为稍后您将使用它来配置 Grafana。

  3. 在集群上部署 Grafana 服务器:

    kubectl create -f grafana-service.yml -n monitoring
    kubectl create -f grafana-deployment.yml -n monitoring
    
  4. 等待几分钟,直到所有服务可用。

  5. 获取 Grafana 服务的端点网址。

    ip_port=$(kubectl get svc grafana-service \
      -o "jsonpath={.status['loadBalancer']['ingress'][0]['ip']}:{.spec['ports'][0]['port']}" -n monitoring)
    echo "http://${ip_port}"
    

    记下 Grafana 端点网址,以便在下一步使用。

  6. 在网络浏览器中,前往您在上一步记下的 Grafana 网址。

  7. 使用默认用户 ID 和密码(adminadmin)登录。出现提示时,更改默认密码。

  8. 点击添加您的首个数据源,然后在时序数据库列表中选择 Prometheus

  9. 设置标签页的网址字段中,输入您之前记下的 Prometheus 端点网址。

  10. 点击保存并测试,然后返回主屏幕。

  11. nv_gpu_utilization 添加监控指标:

    1. 点击创建您的第一个信息中心,然后点击添加可视化图表
    2. 进入数据源列表,选择 Prometheus
    3. 前往查询标签页,找到指标字段,输入 nv_gpu_utilization

    4. 前往面板选项部分,找到标题字段,输入 GPU Utilization,然后点击应用

      该页面会显示 GPU 利用率面板。

  12. nv_gpu_memory_used_bytes 添加监控指标:

    1. 点击添加,然后选择可视化图表
    2. 前往查询标签页,找到指标字段,输入 nv_gpu_memory_used_bytes

    3. 前往面板选项部分,找到标题字段,输入 GPU Memory Used,然后点击保存

  13. 如需添加信息中心,请前往保存信息中心面板,点击保存

    您会看到 GPU 利用率和 GPU 内存用量图表。

部署负载测试工具

在本部分中,您将在 GKE 上部署 Locust 负载测试工具,并生成工作负载来衡量推理服务器的性能。

  1. 在 SSH 终端中,构建一个包含 Triton 客户端库的 Docker 映像,并将其上传到 Container Registry:

    cd ../client
    git clone https://github.com/triton-inference-server/server
    cd server
    git checkout r19.05
    sed -i.bak "s/bootstrap.pypa.io\/get-pip.py/bootstrap.pypa.io\/pip\/2.7\/get-pip.py/" Dockerfile.client
    docker build -t tritonserver_client -f Dockerfile.client .
    gcloud auth configure-docker
    docker tag tritonserver_client \
        gcr.io/${PROJECT_ID}/tritonserver_client
    docker push gcr.io/${PROJECT_ID}/tritonserver_client
    

    构建过程可能需要大约 5 分钟。该过程完成后,SSH 终端中会显示命令提示符。

  2. 构建流程完成后,构建 Docker 映像以生成测试工作负载,并将其上传到 Container Registry:

    cd ..
    sed -i.bak "s/YOUR-PROJECT-ID/${PROJECT_ID}/" Dockerfile
    docker build -t locust_tester -f Dockerfile .
    docker tag locust_tester gcr.io/${PROJECT_ID}/locust_tester
    docker push gcr.io/${PROJECT_ID}/locust_tester
    

    请勿更改或替换命令中的 YOUR-PROJECT-ID

    此映像根据您在上一步中创建的映像构建而成。

  3. 部署 Locust 文件 service_master.yamldeployment_master.yaml

    sed -i.bak "s/YOUR-PROJECT-ID/${PROJECT_ID}/" deployment_master.yaml
    sed -i.bak "s/CLUSTER-IP-TRTIS/${TRITON_IP}/" deployment_master.yaml
    
    kubectl create namespace locust
    kubectl create configmap locust-config --from-literal model=original --from-literal saddr=${TRITON_IP} --from-literal rps=10 -n locust
    
    kubectl apply -f service_master.yaml -n locust
    kubectl apply -f deployment_master.yaml -n locust
    

    configmap 资源用于指定客户端将推断请求发送到的机器学习模型。

  4. 等待几分钟,直到服务可用。

  5. 获取 locust-master 客户端的 clusterIP 地址,并将该地址存储在环境变量中:

    export LOCUST_MASTER_IP=$(kubectl get svc locust-master -n locust \
        -o "jsonpath={.spec['clusterIP']}")
    echo ${LOCUST_MASTER_IP}
    
  6. 部署 Locust 客户端:

    sed -i.bak "s/YOUR-PROJECT-ID/${PROJECT_ID}/" deployment_slave.yaml
    sed -i.bak "s/CLUSTER-IP-LOCUST-MASTER/${LOCUST_MASTER_IP}/" deployment_slave.yaml
    kubectl apply -f deployment_slave.yaml -n locust
    

    这些命令会部署 10 个 Locust 客户端 Pod,供您生成测试工作负载。如果您无法使用当前数量的客户端生成足够的请求,可以使用以下命令更改 Pod 数量:

    kubectl scale deployment/locust-slave --replicas=20 -n locust
    

    如果默认集群没有足够的容量来增加副本的数量,我们建议您增加 GKE 集群中的节点数量。

  7. 复制 Locust 控制台的网址,并在网络浏览器中打开以下网址:

    export LOCUST_IP=$(kubectl get svc locust-master -n locust \
         -o "jsonpath={.status.loadBalancer.ingress[0].ip}")
    echo "http://${LOCUST_IP}:8089"
    

    Locust 控制台随即打开,您可以从中生成测试工作负载。

检查正在运行的 Pod

如需确保组件成功部署,请检查 Pod 是否正在运行。

  1. 在 SSH 终端中,检查推理服务器 Pod:

    kubectl get pods
    

    输出类似于以下内容:

    NAME                                READY   STATUS    RESTARTS   AGE
    inference-server-67786cddb4-qrw6r   1/1     Running   0          83m
    

    如果您没有获得预期输出,请确保已完成使用 Triton 部署推理服务器中的步骤。

  2. 检查 Locust Pod:

    kubectl get pods -n locust
    

    输出类似于以下内容:

    NAME                                READY   STATUS    RESTARTS   AGE
    locust-master-75f6f6d4bc-ttllr      1/1     Running   0          10m
    locust-slave-76ddb664d9-8275p       1/1     Running   0          2m36s
    locust-slave-76ddb664d9-f45ww       1/1     Running   0          2m36s
    locust-slave-76ddb664d9-q95z9       1/1     Running   0          2m36s
    

    如果您没有获得预期的输出,请确保已完成部署负载测试工具中的步骤。

  3. 检查监控 Pod:

    kubectl get pods -n monitoring
    

    输出类似于以下内容:

    NAME                                     READY   STATUS    RESTARTS   AGE
    grafana-deployment-644bbcb84-k6t7v       1/1     Running   0          79m
    prometheus-deployment-544b9b9f98-hl7q8   1/1     Running   0          81m
    

    如果您未看到预期输出,请确保已完成使用 Prometheus 和 Grafana 部署监控服务器中的步骤。

在本教程系列的下一部分中,您将使用此推理服务器系统了解各种优化如何提高性能以及如何解读这些优化。 如需了解后续步骤,请参阅衡量和优化 TensorFlow 推理系统的性能

后续步骤