使用 TensorRT5 和 NVIDIA T4 GPU 运行 TensorFlow 推理工作负载


本教程介绍了如何使用在 Compute Engine 上运行的 NVIDIA TensorRT5 GPU 对大规模工作负载运行深度学习推理。

在开始之前,需要了解以下基本内容:

  • 深度学习推理是机器学习过程中的一个阶段,该阶段使用经过训练的模型来识别、处理和分类结果。
  • NVIDIA TensorRT 是一个经过优化的平台,用于运行深度学习工作负载。
  • GPU 用于加快数据密集型工作负载(如机器学习和数据处理)的运行速度。Compute Engine 上提供多种 NVIDIA GPU。本教程使用 T4 GPU,因为 T4 GPU 是专为深度学习推理工作负载设计的。

目标

本教程包含以下过程:

  • 使用预先训练的图表准备模型。
  • 使用不同的优化模式来测试模型的推理速度。
  • 将自定义模型转换为 TensorRT。
  • 设置一个多地区集群,其配置如下:
    • Deep Learning VM Image 为基础构建而成。这些映像预安装了 TensorFlow、TensorFlow Serving 和 TensorRT5。
    • 启用了自动扩缩功能。本教程中的自动扩缩功能基于 GPU 利用率。
    • 启用了负载平衡。
    • 启用了防火墙。
  • 在多地区集群中运行推理工作负载。

教程设置的架构简要概览。

费用

按照本教程操作的费用因教程部分而异。

您可以使用价格计算器计算费用。

如需估算准备模型并以不同的优化速度测试推理速度的费用,请使用以下规范:

  • 1 个虚拟机实例:n1-standard-8(vCPU:8 个,RAM 30GB)
  • 1 个 NVIDIA T4 GPU

如需估算设置多可用区集群的费用,请使用以下规范:

  • 2 个虚拟机实例:n1-standard-16(16 个 vCPU,60 GB RAM)
  • 每个虚拟机实例有 4 个 GPU NVIDIA T4
  • 每个虚拟机实例有 100 GB SSD
  • 1 条转发规则

准备工作

项目设置

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 Compute Engine and Cloud Machine Learning API。

    启用 API

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

    Go to project selector

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 Compute Engine and Cloud Machine Learning API。

    启用 API

工具设置

如需在本教程中使用 Google Cloud CLI,请执行以下操作:

  1. 安装或更新到 Google Cloud CLI 的最新版本。
  2. (可选)设置默认区域和地区

准备模型

本部分介绍了如何创建用于运行模型的虚拟机 (VM) 实例,此外还介绍了如何从 TensorFlow 官方模型目录下载模型。

  1. 创建虚拟机实例。 本教程是使用 tf-ent-2-10-cu113 创建的。如需了解最新的映像版本,请参阅 Deep Learning VM Image 文档中的选择操作系统

    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    export ZONE="us-central1-b"
    export INSTANCE_NAME="model-prep"
    gcloud compute instances create $INSTANCE_NAME \
       --zone=$ZONE \
       --image-family=$IMAGE_FAMILY \
       --machine-type=n1-standard-8 \
       --image-project=deeplearning-platform-release \
       --maintenance-policy=TERMINATE \
       --accelerator="type=nvidia-tesla-t4,count=1" \
       --metadata="install-nvidia-driver=True"
    
  2. 选择模型。本教程使用 ResNet 模型。此 ResNet 模型根据 TensorFlow 中的 ImageNet 数据集进行训练。

    要将 ResNet 模型下载到虚拟机实例,请运行以下命令:

    wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb

    将 ResNet 模型的位置保存在 $WORKDIR 变量中。 将 MODEL_LOCATION 替换为包含所下载模型的工作目录。

    export WORKDIR=MODEL_LOCATION

运行推理速度测试

本部分包括以下过程:

  • 设置 ResNet 模型。
  • 以不同的优化模式运行推理测试。
  • 查看推理测试的结果。

测试过程概述

TensorRT 可以提高推理工作负载的执行速度,但量化过程的提升最为显著。

模型量化是您用来降低模型权重精确率的过程。例如,如果模型的初始权重是 FP32,您可以将精确率降低到 FP16、INT8 甚至是 INT4。在模型的速度(权重精确率)与准确率之间正确取舍权衡非常重要。幸运的是,TensorFlow 包含的功能就能实现这样的权衡,可测量准确性与速度,或测量其他指标,如吞吐量、延迟时间、节点转换率和总训练时间。

过程

  1. 设置 ResNet 模型。如需设置模型,请运行以下命令:

    git clone https://github.com/tensorflow/models.git
    cd models
    git checkout f0e10716160cd048618ccdd4b6e18336223a172f
    touch research/__init__.py
    touch research/tensorrt/__init__.py
    cp research/tensorrt/labellist.json .
    cp research/tensorrt/image.jpg ..
    
  2. 运行测试。此命令需要一些时间才能完成。

    python -m research.tensorrt.tensorrt \
       --frozen_graph=$WORKDIR/resnetv2_imagenet_frozen_graph.pb \
       --image_file=$WORKDIR/image.jpg \
       --native --fp32 --fp16 --int8 \
       --output_dir=$WORKDIR
    

    其中:

    • $WORKDIR 是下载 ResNet 模型的目录。
    • --native 参数是要测试的不同量化模式。
  3. 查看结果。测试完成后,您可以比较每种优化模式的推理结果。

    Predictions:
    Precision:  native [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty',     u'lakeside, lakeshore', u'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus']
    Precision:  FP32 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  FP16 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  INT8 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'grey         whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', u'lakeside, lakeshore']
    

    如需查看完整结果,请运行以下命令:

    cat $WORKDIR/log.txt

    性能结果。

    从结果中,您可以看到 FP32 和 FP16 是相同的。这表示如果您能够熟练运用 TensorRT,便可以立即开始使用 FP16。INT8 显示的结果稍微逊色。

    此外,您还可以看到使用 TensorRT5 运行模型会显示以下结果:

    • 使用 FP32 优化可将吞吐量提高 40%:从 314 fps 提高到 440 fps。同时,延迟时间缩短约 30%,从 0.40 毫秒变成 0.28 毫秒。
    • 使用 FP16 优化而非原生 TensorFlow 图,可将速度提升 214%:从 314 fps 提升到 988 fps。同时,延迟时间缩短至 0.12 毫秒,几乎降低至四分之一。
    • 使用 INT8,您可以观察到速度提升 385%(从 314 fps 提升到 1524 fps),而延迟时间缩短为 0.08 毫秒。

将自定义模型转换为 TensorRT

您可以使用 INT8 模型进行此转换。

  1. 下载模型。如需将自定义模型转换为 TensorRT 图,您需要一个已保存的模型。若要获取已保存的 INT8 ResNet 模型,请运行以下命令:

    wget http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NCHW.tar.gz
    tar -xzvf resnet_v2_fp32_savedmodel_NCHW.tar.gz
  2. 使用 TFTools 将模型转换为 TensorRT 图。如需使用 TFTools 转换模型,请运行以下命令:

    git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
    cd ml-on-gcp/dlvm/tools
    python ./convert_to_rt.py \
       --input_model_dir=$WORKDIR/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
       --output_model_dir=$WORKDIR/resnet_v2_int8_NCHW/00001 \
       --batch_size=128 \
       --precision_mode="INT8"
    

    现在,$WORKDIR/resnet_v2_int8_NCHW/00001 目录中有一个 INT8 模型。

    为了确保一切设置都正确,请尝试运行推理测试。

    tensorflow_model_server --model_base_path=$WORKDIR/resnet_v2_int8_NCHW/ --rest_api_port=8888
  3. 将模型上传到 Cloud Storage。必须执行此步骤,模型才能用在下一部分设置的多地区集群中。如需上传模型,请完成以下步骤:

    1. 归档模型。

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
    2. 上传归档。 将 GCS_PATH 替换为 Cloud Storage 存储桶的路径。

      export GCS_PATH=GCS_PATH
      gsutil cp model.tar.gz $GCS_PATH
      

      如果需要,您可以通过以下网址从 Cloud Storage 获取 INT8 冻结图:

      gs://cloud-samples-data/dlvm/t4/model.tar.gz

设置一个多地区集群

创建集群

现在,您已在 Cloud Storage 平台上创建了一个模型,可以创建一个集群了。

  1. 创建实例模板。实例模板是用于创建新实例的资源。请参阅实例模板。 将 YOUR_PROJECT_NAME 替换为您的项目 ID。

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    export PROJECT_NAME=YOUR_PROJECT_NAME
    
    gcloud beta compute --project=$PROJECT_NAME instance-templates create $INSTANCE_TEMPLATE_NAME \
         --machine-type=n1-standard-16 \
         --maintenance-policy=TERMINATE \
         --accelerator=type=nvidia-tesla-t4,count=4 \
         --min-cpu-platform=Intel\ Skylake \
         --tags=http-server,https-server \
         --image-family=$IMAGE_FAMILY \
         --image-project=deeplearning-platform-release \
         --boot-disk-size=100GB \
         --boot-disk-type=pd-ssd \
         --boot-disk-device-name=$INSTANCE_TEMPLATE_NAME \
         --metadata startup-script-url=gs://cloud-samples-data/dlvm/t4/start_agent_and_inf_server_4.sh
    
    • 此实例模板包含由元数据参数指定的启动脚本。
      • 对使用此模板的每个实例进行创建时,运行此启动脚本。
      • 此启动脚本会执行以下步骤:
        • 安装监控代理,以监控实例上的 GPU 使用情况。
        • 下载模型。
        • 启动推理服务。
      • 在启动脚本中,tf_serve.py 包含推理逻辑。此示例包含一个基于 TFServe 软件包创建的非常小的 Python 文件。
      • 要查看启动脚本,请参阅 startup_inf_script.sh
  2. 创建一个托管实例组 (MIG)。必须有此托管实例组才能在特定地区中设置多个运行中实例。这些实例是根据上一步生成的实例模板创建的。

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \
       --template $INSTANCE_TEMPLATE_NAME \
       --base-instance-name deeplearning-instances \
       --size 2 \
       --zones us-central1-a,us-central1-b
    
    • 您可以在支持 T4 GPU 的任何适用地区中创建此实例。请确保您在该地区中具有可用的 GPU 配额
    • 创建实例需要一些时间。您可以通过运行以下命令来查看进度:

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1

      实例创建

    • 创建托管实例组后,您应该会看到类似以下内容的输出:

      正在运行的实例。

  3. 确认 Google Cloud Monitoring 页面上有一些指标。

    1. 在 Google Cloud Console 中,转到 Monitoring 页面。

      前往 Monitoring

    2. 如果导航窗格中显示 Metrics Explorer,请点击 Metrics Explorer。否则,请选择 Resources,然后选择 Metrics Explorer

    3. 搜索 gpu_utilization

      Monitoring 启动。

    4. 如果有数据进入,您应该会看到如下内容:

      Monitoring 运行。

启用自动扩缩功能

  1. 为托管实例组启用自动扩缩功能。

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    
    gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \
       --custom-metric-utilization metric=custom.googleapis.com/gpu_utilization,utilization-target-type=GAUGE,utilization-target=85 \
       --max-num-replicas 4 \
       --cool-down-period 360 \
       --region us-central1
    

    custom.googleapis.com/gpu_utilization 是指标的完整路径。该示例指定级别 85,这意味着只要 GPU 利用率达到 85,平台就会在我们的组中创建一个新实例。

  2. 测试自动扩缩功能。要测试自动扩缩功能,您需要执行以下步骤:

    1. 通过 SSH 连接到实例。请参阅连接到实例
    2. 使用 gpu-burn 工具向 GPU 添加负载,让 GPU 利用率达到 100% 并保持 600 秒:

      git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
      cd ml-on-gcp/third_party/gpu-burn
      git checkout c0b072aa09c360c17a065368294159a6cef59ddf
      make
      ./gpu_burn 600 > /dev/null &
      
    3. 查看 Cloud Monitoring 页面。观察自动扩缩功能。集群通过添加另一个实例来纵向扩容。

      自动扩缩集群

    4. 在 Google Cloud Console 中,转到实例组页面。

      转到“实例组”

    5. 点击 deeplearning-instance-group 管理的实例组。

    6. 点击监控标签。

      此时,您的自动扩缩逻辑应该会尝试启动尽可能多的实例以减少负载,但运气不佳:

      其他实例。

      此时,您可以停止对实例进行满负载测试,并观察系统如何缩减。

设置负载平衡器

回顾一下,到目前为止您拥有:

  • 一个经过训练的模型,已使用 TensorRT5 (INT8) 进行优化
  • 一组托管实例。这些实例已根据 GPU 利用率启用自动扩缩

现在,您可以创建在实例前的负载平衡器。

  1. 创建健康检查。健康检查用于确定后端的特定主机是否可以处理流量。

    export HEALTH_CHECK_NAME="http-basic-check"
    
    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
       --request-path /v1/models/default \
       --port 8888
    
  2. 创建包含实例组和健康检查的后端服务。

    1. 创建健康检查。

      export HEALTH_CHECK_NAME="http-basic-check"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
         --protocol HTTP \
         --health-checks $HEALTH_CHECK_NAME \
         --global
      
    2. 将实例组添加到新的后端服务。

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services add-backend $WEB_BACKED_SERVICE_NAME \
         --balancing-mode UTILIZATION \
         --max-utilization 0.8 \
         --capacity-scaler 1 \
         --instance-group $INSTANCE_GROUP_NAME \
         --instance-group-region us-central1 \
         --global
      
  3. 设置转发网址。负载平衡器需要知道哪个网址可以转发到后端服务。

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
       --default-service $WEB_BACKED_SERVICE_NAME
    
  4. 创建负载平衡器。

    export WEB_MAP_NAME="map-all"
    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
       --url-map $WEB_MAP_NAME
    
  5. 将外部 IP 地址添加到负载均衡器。

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
       --ip-version=IPV4 \
       --network-tier=PREMIUM \
       --global
    
  6. 找到分配的 IP 地址。

    gcloud compute addresses list
  7. 设置转发规则,告知 Google Cloud 将所有请求从公共 IP 地址转发到负载均衡器。

    export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}')
    export LB_NAME="tf-lb"
    export FORWARDING_RULE="lb-fwd-rule"
    
    gcloud compute forwarding-rules create $FORWARDING_RULE \
       --address $IP \
       --global \
       --load-balancing-scheme=EXTERNAL \
       --network-tier=PREMIUM \
       --target-http-proxy $LB_NAME \
       --ports 80
    

    创建全局转发规则后,可能需要几分钟来传播配置。

启用防火墙

  1. 检查您是否设有允许从外部源连接到虚拟机实例的防火墙规则。

    gcloud compute firewall-rules list
  2. 如果您没有允许这些连接的防火墙规则,则必须予以创建。如需创建防火墙规则,请运行以下命令:

    gcloud compute firewall-rules create www-firewall-80 \
       --target-tags http-server --allow tcp:80
    
    gcloud compute firewall-rules create www-firewall-8888 \
       --target-tags http-server --allow tcp:8888
    

运行推理

  1. 您可以使用以下 Python 脚本将图片转换为可以上传到服务器的格式。

    from PIL import Image
    import numpy as np
    import json
    import codecs
    
    img = Image.open("image.jpg").resize((240, 240)) img_array=np.array(img) result = { "instances":[img_array.tolist()] } file_path="/tmp/out.json" print(json.dump(result, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4))
  2. 运行推理。

    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

  1. 删除转发规则。

    gcloud compute forwarding-rules delete $FORWARDING_RULE --global
  2. 删除 IPV4 地址。

    gcloud compute addresses delete $IP4_NAME --global
  3. 删除负载平衡器。

    gcloud compute target-http-proxies delete $LB_NAME
  4. 删除转发网址。

    gcloud compute url-maps delete $WEB_MAP_NAME
  5. 删除后端服务。

    gcloud compute backend-services delete $WEB_BACKED_SERVICE_NAME --global
  6. 删除健康检查。

    gcloud compute health-checks delete $HEALTH_CHECK_NAME
  7. 删除托管实例组。

    gcloud compute instance-groups managed delete $INSTANCE_GROUP_NAME --region us-central1
  8. 删除实例模板。

    gcloud beta compute --project=$PROJECT_NAME instance-templates delete $INSTANCE_TEMPLATE_NAME
  9. 删除防火墙规则。

    gcloud compute firewall-rules delete www-firewall-80
    gcloud compute firewall-rules delete www-firewall-8888