使用 Triton 服务 Torch-TensorRT 模型¶
在讨论机器学习基础设施时,优化和部署是密切相关的。一旦完成网络级优化以获得最佳性能,下一步就是部署它。
然而,服务这个优化的模型也带来自身的一系列考虑因素和挑战,例如:构建支持并发模型执行的基础设施,支持基于 HTTP 或 gRPC 的客户端等等。
Triton 推理服务器 解决了上述问题以及更多问题。 让我们逐步讨论使用 Torch-TensorRT 优化模型、在 Triton 推理服务器上部署模型以及构建客户端来查询模型的过程。
步骤 1:使用 Torch-TensorRT 优化您的模型¶
大多数 Torch-TensorRT 用户都会熟悉此步骤。 为了演示目的,我们将使用 Torchhub 中的 ResNet50 模型。
我们将在 //examples/triton
目录中工作,该目录包含本教程中使用的脚本。
首先拉取 NGC PyTorch Docker 容器。 您可能需要创建一个帐户并从此处获取 API 密钥。 注册并使用您的密钥登录(注册后按照此处的说明进行操作)。
# YY.MM is the yy:mm for the publishing tag for NVIDIA's Pytorch
# container; eg. 24.08
# NOTE: Use the publishing tag for both the PyTorch container and the Triton Containers
docker run -it --gpus all -v ${PWD}:/scratch_space nvcr.io/nvidia/pytorch:YY.MM-py3
cd /scratch_space
使用容器,我们可以将模型导出到 Triton 模型存储库中的正确目录中。 此导出脚本使用 Dynamo 前端进行 Torch-TensorRT,以将 PyTorch 模型编译为 TensorRT。 然后,我们使用 TorchScript 作为 Triton 支持的序列化格式来保存模型。
import torch
import torch_tensorrt as torchtrt
import torchvision
import torch
import torch_tensorrt
torch.hub._validate_not_a_forked_repo=lambda a,b,c: True
# load model
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet50', pretrained=True).eval().to("cuda")
# Compile with Torch TensorRT;
trt_model = torch_tensorrt.compile(model,
inputs= [torch_tensorrt.Input((1, 3, 224, 224))],
enabled_precisions= {torch_tensorrt.dtype.f16}
)
ts_trt_model = torch.jit.trace(trt_model, torch.rand(1, 3, 224, 224).to("cuda"))
# Save the model
torch.jit.save(ts_trt_model, "/triton_example/model_repository/resnet50/1/model.pt")
您可以使用以下命令运行脚本(从 //examples/triton
开始)
docker run --gpus all -it --rm -v ${PWD}:/triton_example nvcr.io/nvidia/pytorch:YY.MM-py3 python /triton_example/export.py
这会将 ResNet 模型的序列化 TorchScript 版本保存在模型存储库中正确的目录中。
步骤 2:设置 Triton 推理服务器¶
如果您是 Triton 推理服务器的新手并想了解更多信息,我们强烈建议您查看我们的 Github 仓库。
要使用 Triton,我们需要创建一个模型存储库。 模型存储库顾名思义,是推理服务器托管的模型的存储库。 虽然 Triton 可以服务于来自多个存储库的模型,但在本示例中,我们将讨论最简单的模型存储库形式。
此存储库的结构应如下所示
model_repository
|
+-- resnet50
|
+-- config.pbtxt
+-- 1
|
+-- model.pt
Triton 需要两个文件来服务模型:模型本身和一个模型配置文件,该文件通常以 config.pbtxt
形式提供。 对于我们在步骤 1 中准备的模型,可以使用以下配置
name: "resnet50"
backend: "pytorch"
max_batch_size : 0
input [
{
name: "x"
data_type: TYPE_FP32
dims: [ 1, 3, 224, 224 ]
}
]
output [
{
name: "output0"
data_type: TYPE_FP32
dims: [1, 1000]
}
]
config.pbtxt
文件用于描述确切的模型配置,其中包含输入和输出层的名称和形状、数据类型、调度和批处理详细信息等详细信息。 如果您是 Triton 的新手,我们强烈建议您查看 我们文档的这一部分 以了解更多详细信息。
设置模型存储库后,我们可以继续使用下面的 docker 命令启动 Triton 服务器。 有关容器的拉取标签,请参阅此页面。
# Make sure that the TensorRT version in the Triton container
# and TensorRT version in the environment used to optimize the model
# are the same. Roughly, like publishing tags should have the same TensorRT version
docker run --gpus all --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 -v ${PWD}:/triton_example nvcr.io/nvidia/tritonserver:YY.MM-py3 tritonserver --model-repository=/triton_example/model_repository
这应该启动一个 Triton 推理服务器。 下一步,构建一个简单的 http 客户端来查询服务器。
步骤 3:构建 Triton 客户端来查询服务器¶
在继续之前,请确保手头有示例图像。 如果您没有,请下载示例图像以测试推理。 在本节中,我们将介绍一个非常基本的客户端。 有关各种更完善的示例,请参阅 Triton 客户端存储库
wget -O img1.jpg "https://www.hakaimagazine.com/wp-content/uploads/header-gulf-birds.jpg"
然后,我们需要安装依赖项以构建 python 客户端。 这些依赖项会因客户端而异。 有关 Triton 支持的所有语言的完整列表,请参阅 Triton 的客户端存储库。
pip install torchvision
pip install attrdict
pip install nvidia-pyindex
pip install tritonclient[all]
让我们跳到客户端。 首先,我们编写一个小的预处理函数来调整大小并规范化查询图像。
import numpy as np
from torchvision import transforms
from PIL import Image
import tritonclient.http as httpclient
from tritonclient.utils import triton_to_np_dtype
# preprocessing function
def rn50_preprocess(img_path="/triton_example/img1.jpg"):
img = Image.open(img_path)
preprocess = transforms.Compose(
[
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
]
)
return preprocess(img).unsqueeze(0).numpy()
transformed_img = rn50_preprocess()
构建客户端需要三个基本点。 首先,我们建立与 Triton 推理服务器的连接。
# Setting up client
client = httpclient.InferenceServerClient(url="localhost:8000")
其次,我们指定模型的输入层和输出层的名称。 这可以在导出期间获得,并且应该已在您的 config.pbtxt
中指定
inputs = httpclient.InferInput("x", transformed_img.shape, datatype="FP32")
inputs.set_data_from_numpy(transformed_img, binary_data=True)
outputs = httpclient.InferRequestedOutput("output0", binary_data=True, class_count=1000)
最后,我们向 Triton 推理服务器发送推理请求。
# Querying the server
results = client.infer(model_name="resnet50", inputs=[inputs], outputs=[outputs])
inference_output = results.as_numpy('output0')
print(inference_output[:5])
输出应如下所示
[b'12.468750:90' b'11.523438:92' b'9.664062:14' b'8.429688:136'
b'8.234375:11']
此处的输出格式为 <confidence_score>:<classification_index>
。 要了解如何将这些映射到标签名称等,请参阅 Triton 推理服务器的文档。
您可以尝试使用此客户端快速使用
# Remember to use the same publishing tag for all steps (e.g. 24.08)
docker run -it --net=host -v ${PWD}:/triton_example nvcr.io/nvidia/tritonserver:YY.MM-py3-sdk bash -c "pip install torchvision && python /triton_example/client.py"