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

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

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

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

目标

本教程包含以下过程:

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

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

费用

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

准备模型并以不同的优化速度测试推理速度的估价约为每天 $22.34。此费用根据以下规格估算:

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

设置多地区集群的估价约为每天 $154.38。此费用根据以下规格估算:

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

这些费用是使用价格计算器估算的。

准备工作

项目设置

Compute Engine and Cloud Machine Learning ml.googleapis.com,compute_component
  1. 登录您的 Google 帐号。

    如果您还没有 Google 帐号,请注册新帐号

  2. 在 GCP Console 的项目选择器页面上,选择或创建 GCP 项目。

    转到项目选择器页面

  3. 确保您的 Google Cloud Platform 项目已启用结算功能。 了解如何确认您的项目已启用结算功能

工具设置

要在本教程中使用 gcloud 命令行工具,请执行以下操作:

  1. 安装或更新为 gcloud 命令行工具的最新版本。
  2. (可选)设置默认区域和地区

准备模型

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

  1. 创建虚拟机实例。

    export IMAGE_FAMILY="tf-1-12-cu100"
        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 变量中。

    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. 上传归档。

      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. 创建实例模板。实例模板是用于创建新实例的资源。请参阅实例模板

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
        export IMAGE_FAMILY="tf-1-12-cu100"
        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 Stackdriver 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. 查看 Stackdriver Monitoring 页面。观察自动扩缩功能。集群通过添加另一个实例来纵向扩容。

      集群自动扩缩。

    4. 转到 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 \
            --global
        
  6. 找到分配的 IP 地址。

    gcloud compute addresses list
        
  7. 设置转发规则,告知 GCP 将所有请求从公共 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 \
            --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
        <br>
        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 Platform 帐号产生费用,请执行以下操作:

  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