快速入门指南#

本 TensorRT 快速入门指南是希望试用 TensorRT SDK 的开发人员的起点;具体来说,它演示了如何快速构建一个应用程序,以在 TensorRT 引擎上运行推理。

简介#

NVIDIA TensorRT 是一个 SDK,用于优化训练过的深度学习模型,以实现高性能推理。TensorRT 包含一个深度学习推理优化器和一个用于执行的运行时。

在您使用您选择的框架训练了深度学习模型之后,TensorRT 使您能够以更高的吞吐量和更低的延迟运行它。

Typical Deep Learning Development Cycle Using TensorRT

本节介绍 TensorRT 中可用的基本安装、转换和运行时选项,以及它们最适用的场景。

以下是每个章节的快速摘要

Installing TensorRT - 我们提供了多种简单的 TensorRT 安装方法。

The TensorRT Ecosystem - 我们描述了一个简单的流程图,展示不同类型的转换和部署工作流程,并讨论它们的优点和缺点。

Example Deployment Using ONNX - 本章 بررسی(检查,examine)转换和部署模型的基本步骤。它介绍了本指南其余部分中使用的概念,并引导您完成为优化推理执行而必须做出的决策。

ONNX Conversion and Deployment - 我们提供了来自 PyTorch 的 ONNX 导出的广泛概述,以及指向提供更多详细信息的 Jupyter Notebook 的指针。

Using the TensorRT Runtime API - 本节提供了关于使用 TensorRT C++ 和 Python API 进行图像语义分割的教程。

对于允许您快速部署模型的更高级别应用程序,请参阅 NVIDIA Triton Inference Server 快速入门

安装 TensorRT#

有几种 TensorRT 的安装方法。本节介绍使用以下方式的最常见选项:

  • 容器,

  • Debian 文件,或

  • 独立的 pip wheel 文件。

有关安装 TensorRT 的其他方法,请参阅安装指南

对于已经熟悉 TensorRT 并希望快速运行其应用程序、正在使用 NVIDIA CUDA 容器或希望设置自动化的高级用户,请按照网络存储库安装说明进行操作(请参阅使用 NVIDIA 机器学习网络存储库进行 Debian 安装)。

容器安装#

本节介绍 NVIDIA 定期发布和维护的定制虚拟机镜像 (VMI)。NVIDIA NGC 认证的公有云平台用户可以通过浏览 NGC 网站 并识别可用于在其 VMI 上运行的可用 NGC 容器和标签来访问特定的设置说明。

在每个主要的云提供商上,NVIDIA 都发布了定制的 GPU 优化 VMI,并定期更新操作系统和驱动程序。这些 VMI 针对最新一代 NVIDIA GPU 的性能进行了优化。使用这些 VMI 在具有 B200、H100、A100、L40S 或 T4 GPU 的云托管虚拟机实例上部署 NGC 托管的容器、模型和资源,可确保深度学习、机器学习和 HPC 工作负载的最佳性能。

要在公有云上部署 TensorRT 容器,请按照与您的 NGC 认证的公有云平台 相关的步骤进行操作。

Debian 安装#

请参阅 Debian 安装 说明。

Python 包索引安装#

请参阅 Python 包索引安装 说明。

TensorRT 生态系统#

TensorRT 是一个大型且灵活的项目。它可以处理各种转换和部署工作流程,哪种工作流程最适合您将取决于您的具体用例和问题设置。

TensorRT 提供了多种部署选项,但所有工作流程都涉及将您的模型转换为优化的表示形式,TensorRT 将其称为引擎。为您的模型构建 TensorRT 工作流程包括选择正确的部署选项和用于引擎创建的正确参数组合。

基本 TensorRT 工作流程#

您必须遵循五个基本步骤来转换和部署您的模型

  1. 导出模型

  2. 选择精度

  3. 转换模型

  4. 部署模型

在完整的端到端工作流程的上下文中理解这些步骤是最容易的:在Example Deployment Using ONNX 中,我们将介绍一个简单的框架无关的部署工作流程,以使用 ONNX 转换和 TensorRT 的独立运行时将训练好的 ResNet-50 模型转换为 TensorRT 并进行部署。

转换和部署选项#

TensorRT 生态系统分为两个部分

  1. 您可以遵循各种路径将其模型转换为优化的 TensorRT 引擎。

  2. 用户在部署其优化的 TensorRT 引擎时可以使用 TensorRT 定位的各种运行时。

转换#

使用 TensorRT 转换模型有四个主要选项

  1. 使用 Torch-TensorRT

  2. .onnx 文件自动 ONNX 转换

  3. 使用基于 GUI 的工具 Nsight Deep Learning Designer

  4. 使用 TensorRT API 手动构建网络(在 C++ 或 Python 中)

PyTorch 集成 (Torch-TensorRT) 提供了模型转换和用于转换 PyTorch 模型的高级运行时 API。在 TensorRT 不支持特定运算符的情况下,它可以回退到 PyTorch 实现。有关支持的运算符的更多信息,请参阅 ONNX Operator Support

用于自动模型转换和部署的更高效选项是使用 ONNX 进行转换。ONNX 是一种框架无关的选项,适用于 TensorFlow、PyTorch 和更多框架中的模型。TensorRT 支持使用 TensorRT API 或 trtexec 从 ONNX 文件进行自动转换,我们将在本节中使用 trtexec。ONNX 转换是全有或全无的,这意味着模型中的所有操作都必须受 TensorRT 支持(或者您必须为不支持的操作提供自定义插件)。ONNX 转换生成一个单一的 TensorRT 引擎,与 Torch-TensorRT 相比,开销更小。

除了 trtexec 之外,Nsight Deep Learning Designer 还可以将 ONNX 文件转换为 TensorRT 引擎。基于 GUI 的工具提供模型可视化和编辑、推理性能分析以及轻松将 ONNX 模型转换为 TensorRT 引擎。Nsight Deep Learning Designer 会根据需要自动下载 TensorRT 位(包括 CUDA 和 cuBlas),而无需单独安装 TensorRT。

您可以使用 TensorRT 网络定义 API 手动构建 TensorRT 引擎,以获得最佳性能和自定义性。这涉及在 TensorRT 中逐个操作地构建与目标模型相同的网络,仅使用 TensorRT 操作。创建 TensorRT 网络后,您将仅从框架中导出模型的权重,并将它们加载到 TensorRT 网络中。对于这种方法,有关使用 TensorRT 的网络定义 API 构建模型的更多信息可以在这里找到:

部署#

使用 TensorRT 部署模型有三种选项

  1. 在 PyTorch 中部署

  2. 使用独立的 TensorRT 运行时 API

  3. 使用 NVIDIA Triton 推理服务器

您对部署的选择将决定转换模型所需的步骤。

当使用 Torch-TensorRT 时,最常见的部署选项是简单地在 PyTorch 中部署。Torch-TensorRT 转换会生成一个 PyTorch 图,其中插入了 TensorRT 操作。您可以像使用 Python 运行任何其他 PyTorch 模型一样运行 Torch-TensorRT 模型。

TensorRT 运行时 API 允许最低的开销和最细粒度的控制。但是,TensorRT 本身不支持的运算符必须作为插件实现(预先编写的插件库可在 GitHub: TensorRT plugin 上找到)。使用运行时 API 进行部署的最常见路径是使用框架的 ONNX 导出,我们将在下一节中介绍。

最后,NVIDIA Triton 推理服务器是开源推理服务软件,使团队能够从任何框架(TensorFlow、TensorRT、PyTorch、ONNX Runtime 或自定义框架)、从本地存储或 Google Cloud Platform 或 AWS S3 在任何基于 GPU 或 CPU 的基础设施(云、数据中心或边缘)上部署训练好的 AI 模型。它是一个灵活的项目,具有几个独特的功能,例如异构模型的并发模型执行和同一模型的多个副本(多个模型副本可以进一步减少延迟)、负载平衡和模型分析。如果您必须通过 HTTP 提供模型服务(例如在云推理解决方案中),这是一个不错的选择。您可以找到 NVIDIA Triton 推理服务器主页文档

选择正确的工作流程#

选择如何转换和部署模型时,两个最重要的因素是

  1. 您选择的框架

  2. 您首选的 TensorRT 运行时目标

有关可用运行时选项的更多信息,请参阅本指南中包含的关于 Understanding TensorRT Runtimes 的 Jupyter Notebook。

使用 ONNX 的示例部署#

ONNX 是一种框架无关的模型格式,可以从大多数主要框架(包括 TensorFlow 和 PyTorch)导出。TensorRT 提供了一个库,用于通过 ONNX-TRT 解析器 将 ONNX 直接转换为 TensorRT 引擎。

本节将介绍将来自 ONNX 模型动物园的预训练 ResNet-50 模型转换为 TensorRT 引擎的五个步骤。从视觉上看,这是我们将遵循的过程

在您了解 TensorRT 工作流程的基本步骤之后,您可以深入研究更深入的 Jupyter Notebook(请参阅以下主题),以了解如何使用 Torch-TensorRT 或 ONNX 使用 TensorRT。使用 PyTorch 框架,您可以按照入门 Jupyter Notebook Running this Guide 进行操作,其中更详细地介绍了这些工作流程步骤。

导出模型#

TensorRT 转换的主要自动路径需要不同的模型格式才能成功转换模型:ONNX 路径要求模型以 ONNX 格式保存。

在此示例中,我们使用 ONNX,因此我们需要一个 ONNX 模型。我们将使用 ResNet-50,这是一个可用于各种目的的基本骨干视觉模型。我们将使用 ONNX 模型动物园中包含的预训练 ResNet-50 ONNX 模型执行分类。

使用 wget 从 ONNX 模型动物园下载预训练的 ResNet-50 模型并解压它。

wget https://download.onnxruntime.ai/onnx/models/resnet50.tar.gz
tar xzf resnet50.tar.gz

这会将预训练的 ResNet-50 .onnx 文件解压到路径 resnet50/model.onnx

Exporting To ONNX From PyTorch 中,您可以看到我们如何导出将在此相同部署工作流程中使用的 ONNX 模型。

选择精度#

推理通常比训练需要更低的数值精度。在一定程度上,较低的精度可以为您提供更快的计算速度和更低的内存消耗,而不会牺牲任何有意义的准确性。TensorRT 支持 FP32、FP16、FP8、BF16、FP8、INT64、INT32、INT8 和 INT4 精度。

TensorRT 有两种类型的系统

  1. 弱类型允许 TensorRT 的优化器自由地降低精度以提高性能。

  2. 强类型要求 TensorRT 根据输入类型静态推断网络中每个张量的类型,然后严格遵守这些类型。如果您在导出之前已经降低了精度并希望 TensorRT 符合要求,这将非常有用。

有关更多信息,请参阅Strong Typing vs Weak Typing

本节演示了弱类型网络的使用。

FP32 是大多数框架的默认训练精度,因此我们将从此处开始使用它进行推理。

import numpy as np
PRECISION = np.float32

我们设置 TensorRT 引擎在运行时应使用的精度,我们将在下一节中进行设置。

转换模型#

ONNX 转换路径是自动 TensorRT 转换的最通用和性能最高的路径之一。它适用于 TensorFlow、PyTorch 和许多其他框架。

有几个工具可以帮助您将模型从 ONNX 转换为 TensorRT 引擎。一种常见的方法是使用 trtexec - 一个包含在 TensorRT 中的命令行工具,它可以执行多种操作,包括将 ONNX 模型转换为 TensorRT 引擎并对其进行分析。

我们可以按如下方式运行此转换

trtexec --onnx=resnet50/model.onnx --saveEngine=resnet_engine_intro.engine

这会将我们的 resnet50/model.onnx 转换为名为 resnet_engine_intro.engine 的 TensorRT 引擎。

注意

  • 要告诉 trtexec 在哪里找到我们的 ONNX 模型,请运行以下命令

    --onnx=resnet50/model.onnx
    
  • 要告诉 trtexec 在哪里保存我们优化的 TensorRT 引擎,请运行以下命令

    --saveEngine=resnet_engine_intro.engine
    

对于喜欢基于 GUI 工具的简易性的开发人员,Nsight Deep Learning Designer 使您能够轻松地将 ONNX 模型转换为 TensorRT 引擎文件。trtexec 的大多数命令行参数在 Nsight Deep Learning Designer 的 GUI 上也可用。

部署模型#

成功创建 TensorRT 引擎后,我们必须决定如何使用 TensorRT 运行它。

有两种类型的 TensorRT 运行时:具有 C++ 和 Python 绑定的独立运行时以及与 PyTorch 的原生集成。本节将使用一个简化的包装器 (ONNXClassifierWrapper),它调用独立运行时。我们将生成一批随机化的“虚拟”数据,并使用我们的 ONNXClassifierWrapper 对该批次运行推理。有关 TensorRT 运行时的更多信息,请参阅 Understanding TensorRT Runtimes Jupyter Notebook。

  1. 设置 ONNXClassifierWrapper(使用我们在选择精度中确定的精度)。

    from onnx_helper import ONNXClassifierWrapper
    trt_model = ONNXClassifierWrapper("resnet_engine.trt", target_dtype = PRECISION)
    
  2. 生成虚拟批次。

    input_shape = (1, 3, 224, 224)
    dummy_input_batch = np.zeros(input_shape , dtype = PRECISION)
    
  3. 将一批数据馈送到我们的引擎并获取我们的预测。

    predictions = trt_model.predict(dummy_input_batch)
    

请注意,包装器在运行第一批次时加载并初始化引擎,因此此批次通常需要一段时间。有关批处理的更多信息,请参阅Batching 部分。

有关 TensorRT API 的更多信息,请参阅 NVIDIA TensorRT API 文档。有关 ONNXClassifierWrapper 的更多信息,请参阅 GitHub 上 onnx_helper.py 的实现。

ONNX 转换和部署#

ONNX 交换格式提供了一种从许多框架(包括 PyTorch、TensorFlow 和 TensorFlow 2)导出模型以与 TensorRT 运行时一起使用的方法。使用 ONNX 导入模型要求模型中的运算符受 ONNX 支持,并且您需要提供 TensorRT 不支持的任何运算符的插件实现。(TensorRT 的插件库可以在 GitHub: plugin 上找到)。

使用 ONNX 导出#

可以使用 PyTorch export 从 PyTorch 模型轻松生成 ONNX 模型。

Using PyTorch with TensorRT through the ONNX notebook 展示了如何从 PyTorch ResNet-50 模型生成 ONNX 模型,使用 trtexec 将这些 ONNX 模型转换为 TensorRT 引擎,以及在推理时使用 TensorRT 运行时将输入馈送到 TensorRT 引擎。

从 PyTorch 导出到 ONNX#

将 PyTorch 模型转换为 TensorRT 的一种方法是将 PyTorch 模型导出到 ONNX,然后将其转换为 TensorRT 引擎。有关更多详细信息,请参阅 Using PyTorch with TensorRT through ONNX。该 Notebook 将引导您完成此路径,从以下导出步骤开始

  1. torchvision 导入 ResNet-50 模型。这将加载一个带有预训练权重的 ResNet-50 副本。

    import torchvision.models as models
    
    resnet50 = models.resnet50(pretrained=True, progress=False).eval()
    )
    
  2. 从 PyTorch 保存 ONNX 文件。

    注意

    我们需要一批数据才能从 PyTorch 保存我们的 ONNX 文件。我们将使用虚拟批次。

    import torch
    
    BATCH_SIZE = 32
    dummy_input=torch.randn(BATCH_SIZE, 3, 224, 224)
    
  3. 保存 ONNX 文件。

    import torch.onnx
    torch.onnx.export(resnet50, dummy_input, "resnet50_pytorch.onnx", verbose=False)
    )
    

将 ONNX 转换为 TensorRT 引擎#

将 ONNX 文件转换为 TensorRT 引擎有三种主要方法

  1. 使用 trtexec

  2. 使用 TensorRT API

  3. 使用 Nsight Deep Learning Designer GUI

在本节中,我们将重点介绍使用 trtexec。要使用 trtexec 将上述 ONNX 模型之一转换为 TensorRT 引擎,我们可以按如下方式运行此转换

trtexec --onnx=resnet50_pytorch.onnx --saveEngine=resnet_engine_pytorch.trt

这会将我们的 resnet50_onnx_model.onnx 转换为名为 resnet_engine.trt 的 TensorRT 引擎。

将 TensorRT 引擎部署到 Python 运行时 API#

有几种运行时可用于 TensorRT 的目标。当性能很重要时,TensorRT API 是运行 ONNX 模型的好方法。以下部分将使用 TensorRT 运行时 API 在 C++ 和 Python 中部署更复杂的 ONNX 模型。

在 Notebook Using PyTorch through ONNX 中,您可以看到如何在 Jupyter 中使用 Python 运行时 API 部署上述模型。另一个简单的选项是使用 ONNXClassifierWrapper,如Deploy the Model 中所示。

使用 TensorRT 运行时 API#

模型转换和部署的最有效且可自定义的选项之一是 TensorRT API,它具有 C++ 和 Python 绑定。

TensorRT 包括一个具有 C++ 和 Python 绑定的独立运行时。它通常比 Torch-TRT 集成更高效且更可自定义,并且在 PyTorch 中运行。C++ API 的开销较低,但 Python API 与 Python 数据加载器和 NumPy 和 SciPy 等库配合良好,并且更易于用于原型设计、调试和测试。

以下教程说明了如何使用 TensorRT C++ 和 Python API 对图像进行语义分割。对于此任务,使用了具有 ResNet-101 骨干的全卷积模型。该模型接受任意大小的图像并生成每像素预测。

本教程包含以下步骤

  1. 设置:启动测试容器并从导出到 ONNX 并使用 trtexec 转换的 PyTorch 模型生成 TensorRT 引擎。

  2. C++ 运行时 API:使用引擎和 TensorRT 的 C++ API 运行推理。

  3. Python 运行时 API:使用引擎和 TensorRT 的 Python API 运行推理。

设置测试容器并构建 TensorRT 引擎#

  1. TensorRT 开源软件存储库 下载此快速入门教程的源代码。

    $ git clone https://github.com/NVIDIA/TensorRT.git
    $ cd TensorRT/quickstart
    
  2. 将预训练的 FCN-ResNet-101 模型转换为 ONNX。

    在这里,我们使用教程中包含的导出脚本来生成 ONNX 模型并将其保存到 fcn-resnet101.onnx。有关 ONNX 转换的详细信息,请参阅ONNX Conversion and Deployment。该脚本还生成了一个大小为 1282x1026 的测试图像,并将其保存到 input.ppm

    Test Image, Size 1282x1026
    1. 启动 NVIDIA PyTorch 容器以运行导出脚本。

      $ docker run --rm -it --gpus all -p 8888:8888 -v `pwd`:/workspace -w /workspace/SemanticSegmentation nvcr.io/nvidia/pytorch:20.12-py3 bash
      
    2. 运行导出脚本以将预训练模型转换为 ONNX。

      $ python3 export.py
      

    注意

    FCN-ResNet-101 有一个维度为 [batch, 3, height, width] 的输入和一个维度为 [batch, 21, height, weight] 的输出,其中包含与 21 个类别标签的预测相对应的未归一化概率。将模型导出到 ONNX 时,我们在输出端附加一个 argmax 层,以生成最高概率的每像素类别标签。

  3. 使用 trtexec 工具从 ONNX 构建 TensorRT 引擎。

    trtexec 可以从 ONNX 模型生成 TensorRT 引擎,然后可以使用 TensorRT 运行时 API 部署该引擎。它利用 TensorRT ONNX 解析器 将 ONNX 模型加载到 TensorRT 网络图中,并利用TensorRT Builder API 生成优化的引擎。

    构建引擎可能很耗时,通常离线执行。

    trtexec --onnx=fcn-resnet101.onnx --saveEngine=fcn-resnet101.engine --optShapes=input:1x3x1026x1282
    

    成功执行应生成一个引擎文件,以及在命令输出中类似于 Successful 的内容。

    trtexec 可以使用 Commonly Used Command-line Flags 中描述的配置选项构建 TensorRT 引擎。

在 C++ 中运行引擎#

在测试容器中编译并运行 C++ 分割教程。

$ make
$ ./bin/segmentation_tutorial

以下步骤展示了如何使用Deserializing A Plan 进行推理。

  1. 从文件反序列化 TensorRT 引擎。文件内容被读取到缓冲区并在内存中反序列化。

    std::vector<char> engineData(fsize);
    engineFile.read(engineData.data(), fsize);
    
    std::unique_ptr<nvinfer1::IRuntime> mRuntime{nvinfer1::createInferRuntime(sample::gLogger.getTRTLogger())};
    
    std::unique_ptr<nvinfer1::ICudaEngine> mEngine(runtime->deserializeCudaEngine(engineData.data(), fsize));
    
  2. TensorRT 执行上下文封装了执行状态,例如用于在推理期间保持中间激活张量的持久设备内存。

    由于分割模型是在启用动态形状的情况下构建的,因此必须为推理执行指定输入的形状。可以查询网络输出形状以确定输出缓冲区的相应维度。

    char const* input_name = "input";
    assert(mEngine->getTensorDataType(input_name) == nvinfer1::DataType::kFLOAT);
    auto input_dims = nvinfer1::Dims4{1, /* channels */ 3, height, width};
    context->setInputShape(input_name, input_dims);
    auto input_size = util::getMemorySize(input_dims, sizeof(float));
    char const* output_name = "output";
    assert(mEngine->getTensorDataType(output_name) == nvinfer1::DataType::kINT64);
    auto output_dims = context->getTensorShape(output_name);
    auto output_size = util::getMemorySize(output_dims, sizeof(int64_t));
    
  3. 为了准备推理,为所有输入和输出分配 CUDA 设备内存,处理图像数据并将其复制到输入内存中,并生成引擎绑定的列表。

    对于语义分割,输入图像数据通过拟合到 [0, 1] 范围内进行处理,并使用均值 [0.485, 0.456, 0.406] 和标准差 [0.229, 0.224, 0.225] 进行归一化。有关 torchvision 模型 GitHub: models 的输入预处理要求,请参阅 GitHub: models。此操作由实用程序类 RGBImageReader 抽象化。

    void* input_mem{nullptr};
    cudaMalloc(&input_mem, input_size);
    void* output_mem{nullptr};
    cudaMalloc(&output_mem, output_size);
    const std::vector<float> mean{0.485f, 0.456f, 0.406f};
    const std::vector<float> stddev{0.229f, 0.224f, 0.225f};
    auto input_image{util::RGBImageReader(input_filename, input_dims, mean, stddev)};
    input_image.read();
    cudaStream_t stream;
    auto input_buffer = input_image.process();
    cudaMemcpyAsync(input_mem, input_buffer.get(), input_size, cudaMemcpyHostToDevice, stream);
    
  4. 推理执行使用上下文的 executeV2enqueueV3 方法启动。执行后,我们将结果复制到主机缓冲区并释放所有设备内存分配。

    context->setTensorAddress(input_name, input_mem);
    context->setTensorAddress(output_name, output_mem);
    bool status = context->enqueueV3(stream);
    auto output_buffer = std::unique_ptr<int64_t>{new int64_t[output_size]};
    cudaMemcpyAsync(output_buffer.get(), output_mem, output_size, cudaMemcpyDeviceToHost, stream);
    cudaStreamSynchronize(stream);
    
    cudaFree(input_mem);
    cudaFree(output_mem);
    
  5. 每像素类别预测的伪彩色图被写入 output.ppm 以可视化结果。实用程序类 ArgmaxImageWriter 抽象化了这一点。

    const int num_classes{21};
    const std::vector<int> palette{
            (0x1 << 25) - 1, (0x1 << 15) - 1, (0x1 << 21) - 1};
    auto output_image{util::ArgmaxImageWriter(output_filename, output_dims, palette, num_classes)};
    int64_t* output_ptr = output_buffer.get();
    std::vector<int32_t> output_buffer_casted(output_size);
    for (size_t i = 0; i < output_size; ++i) {
        output_buffer_casted[i] = static_cast<int32_t>(output_ptr[i]);
    }
    output_image.process(output_buffer_casted.get());
    output_image.write();
    

    对于测试图像,预期输出如下

    Test Image, Size 1282x1026

在 Python 中运行引擎#

  1. 安装所需的 Python 包。

    $ pip install pycuda
    
  2. 启动 Jupyter 并使用提供的令牌使用 http://<host-ip-address>:8888 浏览器登录。

    $ jupyter notebook --port=8888 --no-browser --ip=0.0.0.0 --allow-root
    
  3. 打开 tutorial-runtime.ipynb notebook 并按照其步骤操作。

TensorRT Python 运行时 API 直接映射到Running An Engine In C++ 中描述的 C++ API。