本文档介绍如何部署可扩缩的 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 模型
- 使用 Prometheus 和 Grafana 为 Titon 构建监控系统
- 使用 Locust 构建负载测试工具
费用
除了 NVIDIA T4 GPU 之外,在此部署中,您还可以使用 Google Cloud 的以下收费组件:
如需根据您的预计使用量来估算费用,请使用价格计算器。
完成此部署后,请勿删除您创建的资源。测量和调整部署时,您需要这些资源。
准备工作
- 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.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the GKE API.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the GKE 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 模型。
In the Google Cloud console, activate Cloud Shell.
部署名为
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 通过图优化进行量化
如需详细了解这些优化,请参阅性能优化。
在 Google Cloud 控制台中,转到 Compute Engine > 虚拟机实例。
您会看到您之前创建的
working-vm
实例。如需打开实例的终端控制台,请点击 SSH。
您可以使用此终端运行本文档中的其余命令。
在终端中,克隆所需的代码库并更改当前目录:
cd $HOME git clone https://github.com/GoogleCloudPlatform/gke-tensorflow-inference-system-tutorial cd gke-tensorflow-inference-system-tutorial/server
将预训练的 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
构建一个包含 TF-TRT 优化工具的容器映像:
docker build ./ -t trt-optimizer docker image list
最后一个命令会显示一个代码库表。
在表中,找到
tft-optimizer
代码库的行,复制映像 ID。将优化(图优化、转换为 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 部署推理服务器
在 SSH 终端中,安装和配置身份验证软件包,该软件包用于管理 GKE 集群:
export USE_GKE_GCLOUD_AUTH_PLUGIN=True sudo apt-get install google-cloud-sdk-gke-gcloud-auth-plugin
创建 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。显示集群信息:
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
显示节点池信息:
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
启用
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 节点池添加新节点时,它也会自动加载驱动程序。
在集群上部署推理服务器:
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
等待几分钟,直到服务可用。
获取 Triton 的
clusterIP
地址,并将其存储在环境变量中:export TRITON_IP=$(kubectl get svc inference-server \ -o "jsonpath={.spec['clusterIP']}") echo ${TRITON_IP}
此时,推理服务器提供您在采用不同优化方式创建模型文件部分中创建的四个 ResNet-50 模型。客户端可以指定在发送推理请求时要使用的模型。
使用 Prometheus 和 Grafana 部署监控服务器
在 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
获取 Prometheus 服务的端点网址。
ip_port=$(kubectl get svc prometheus-service \ -o "jsonpath={.spec['clusterIP']}:{.spec['ports'][0]['port']}" -n monitoring) echo "http://${ip_port}"
记下 Prometheus 端点网址,因为稍后您将使用它来配置 Grafana。
在集群上部署 Grafana 服务器:
kubectl create -f grafana-service.yml -n monitoring kubectl create -f grafana-deployment.yml -n monitoring
等待几分钟,直到所有服务可用。
获取 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 端点网址,以便在下一步使用。
在网络浏览器中,前往您在上一步记下的 Grafana 网址。
使用默认用户 ID 和密码(
admin
和admin
)登录。出现提示时,更改默认密码。点击添加您的首个数据源,然后在时序数据库列表中选择 Prometheus。
在设置标签页的网址字段中,输入您之前记下的 Prometheus 端点网址。
点击保存并测试,然后返回主屏幕。
为
nv_gpu_utilization
添加监控指标:- 点击创建您的第一个信息中心,然后点击添加可视化图表。
- 进入数据源列表,选择 Prometheus。
前往查询标签页,找到指标字段,输入
nv_gpu_utilization
。前往面板选项部分,找到标题字段,输入
GPU Utilization
,然后点击应用。该页面会显示 GPU 利用率面板。
为
nv_gpu_memory_used_bytes
添加监控指标:- 点击添加,然后选择可视化图表。
前往查询标签页,找到指标字段,输入
nv_gpu_memory_used_bytes
。前往面板选项部分,找到标题字段,输入
GPU Memory Used
,然后点击保存。
如需添加信息中心,请前往保存信息中心面板,点击保存。
您会看到 GPU 利用率和 GPU 内存用量图表。
部署负载测试工具
在本部分中,您将在 GKE 上部署 Locust 负载测试工具,并生成工作负载来衡量推理服务器的性能。
在 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 终端中会显示命令提示符。
构建流程完成后,构建 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
。此映像根据您在上一步中创建的映像构建而成。
部署 Locust 文件
service_master.yaml
和deployment_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
资源用于指定客户端将推断请求发送到的机器学习模型。等待几分钟,直到服务可用。
获取
locust-master
客户端的clusterIP
地址,并将该地址存储在环境变量中:export LOCUST_MASTER_IP=$(kubectl get svc locust-master -n locust \ -o "jsonpath={.spec['clusterIP']}") echo ${LOCUST_MASTER_IP}
部署 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 集群中的节点数量。
复制 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 是否正在运行。
在 SSH 终端中,检查推理服务器 Pod:
kubectl get pods
输出类似于以下内容:
NAME READY STATUS RESTARTS AGE inference-server-67786cddb4-qrw6r 1/1 Running 0 83m
如果您没有获得预期输出,请确保已完成使用 Triton 部署推理服务器中的步骤。
检查 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
如果您没有获得预期的输出,请确保已完成部署负载测试工具中的步骤。
检查监控 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 推理系统的性能。
后续步骤
- 详细了解 Google Kubernetes Engine (GKE)。
- 详细了解 Cloud Load Balancing。
- 如需查看更多参考架构、图表和最佳实践,请浏览云架构中心。