人工智能/深度学习

基于 NVIDIA 的 PC 的端到端 AI : ONNX Runtime 中的 CUDA 和 TensorRT 执行提供程序

这篇文章是 optimizing end-to-end AI 系列文章的第四篇。 有关更多信息,请参阅以下帖子:

正如在 End-to-End AI for NVIDIA-Based PCs 系列的上一篇文章中所解释的, ONNX Runtime 中有多个执行提供程序( EP ),它们支持针对给定部署场景使用特定于硬件的功能或优化。本文介绍了 CUDA EPTensorRT EP ,它们使用了高度优化的 NVIDIA 推理库和各自的硬件功能,如 Tensor Core 。

除了 NVIDIA 硬件上的最佳性能外,这还允许在多个操作系统甚至数据中心、 PC 和嵌入式( NVIDIA Jetson )硬件上使用相同的 EP 。由于这些 EP 是特定于 NVIDIA 的,因此这是获得 FP8 精度或 NVIDIA Ada Lovelace architecture 中的 transformer 引擎等新硬件功能的最快途径。

CUDA EP 和 TensorRT EP 之间的区别?

您可能会问,为什么 ONNX Runtime 中甚至有两个 NVIDIA EP ?虽然它们都使用相同的后端( CUDA )与 GPU 驱动程序通信,但它们有不同的方式来构建和执行 ONNX 图。

CUDA 步骤

CUDA EP 使用 cuDNN inference library ,其基于神经网络的粒度操作块。这样的构建块可以类似于卷积或融合算子;例如卷积+激活+归一化。

使用融合运算符的好处是减少了全局内存流量,这通常是激活函数等廉价操作的瓶颈。这样的操作块可以通过穷举搜索或根据 GPU 选择内核的启发式来选择。

穷举搜索仅在部署设备上的第一次推断期间进行,因此使得第一次推断比以下推断慢。这导致始终对特定块使用性能最高的实现。

TensorRT 步骤

TensorRT EP 也可熔断此类操作块。同时,它评估整个图形并收集所有可能的路径以执行图形。

通过优化整个图和可能的重新排序操作,优化的潜力更大。然后对评估的可能执行路径进行分析,并选择性能最佳的执行路径,并将其保存为所谓的引擎。

这些引擎不仅表示图形的操作列表,还表示其权重和执行所需的所有信息。对于大型 ONNX 模型,在这样的图形级别上进行优化和分析可能需要几分钟的时间。彻底的 cuDNN 搜索只评估小的网络构建块,使其搜索速度更快。

cuDNN 只评估自己的内核,而 NVIDIA TensorRT 策略跨越包括 cuDNN 在内的多个库。另一个重要因素是 TensorRT 可以为网络内部的中间缓冲区分配的工作空间内存。

当涉及到执行时, TensorRT 通常可以提供更快的执行,因为它保证为整个图而不仅仅是子部分选择最佳执行路径。这显然是以这样高的引擎创建时间为代价的,因此需要考虑一些部署问题。

在 TensorRT 8.5 及更高版本中, cuDNN 和 cuBLAS 内核是可选的添加,以减少 TensorRT 库的部署大小。目前, ONNX Runtime 使用 TensorRT 8.4 ,没有公开的选项来启用或禁用特定库。

Diagram shows that ONNX Runtime is part of deep learning frameworks, along with PyTorch and other apps.
图 1 。 NVIDIA 推理堆栈

部署注意事项

为了部署 CUDA EP ,您只需提供相应的库和 ONNX 文件。为了在设置时间和推理性能之间进行权衡,您可以使用 cudnn_conv_algo_search 属性在启发式和穷举内核搜索之间进行选择。

对于 TensorRT EP ,有更多的考虑因素。不仅要传送 ONNX 文件,而且要传送为该 ONNX 生成的引擎,以省略在用户硬件上构建模型。

由于构建过程需要时间,用户构建不应该在第一次推断时进行,而是应该在应用程序安装期间或在应用程序第一次启动时使用相应的提示进行。

为了缓存生成的引擎以供以后使用,以下设置尤为重要。请注意,这样生成的引擎不仅特定于 ONNX 文件,还特定于 GPU 体系结构(计算能力)。

trt_options.trt_engine_cache_enable = 1;
trt_options.trt_engine_cache_path = "/path/to/cache"

幸运的是,这两个提供程序都基于 CUDA ,并且非常可互换,正如您在本文提供的示例应用程序中看到的那样。稍后可以很容易地更改决定。

示例应用程序

本文提供的示例应用程序可以在 NVIDIA/ProViz-AI-Samples GitHub repo 上找到。它演示了一个具有 AI 超分辨率模型的简单照片处理管道。它没有用户界面。相反,它是处理图像文件夹的命令行专用工具。

除了运行推理之外,它还演示了如何将预处理和后处理集成到这样的管道中。样本中的预处理和后处理很简单,但可以通过其他 CUDA 加速库(如 NPPCV-CUDAOpenCV )轻松扩展。在本例中,它是从 NCHW 到 NHWC 的数据格式转换,作为自定义 CUDA 内核。

该示例的关键方面是使用单独的流将数据复制到 GPU 和从 GPU 复制数据,并进行处理。由于 GPU 能够同时通过 PCI 总线复制数据以进行计算,这将隐藏引入的复制延迟,并使您能够在 GPU 忙时加载下一个图像。

对于连续图像,只有第一个图像具有上载延迟,只有最后一个图像具有下载延迟。其余部分通过管道隐藏(图 2 )。我们为应用程序添加了 NVTX 范围,以便于性能分析。

当前,如果未事先编译 feature branch ,则 ONNX Runtime 无法显示 CUDA 工作的异步执行。示例中的 README 解释了如何使用自定义二进制文件而不是预编译的二进制文件。

Nsight provides a timeline view of the CUDA kernels as blue boxes that are executed for inference. It also enables correlating the issued CPU command for that with the respective execution on GPU. The same is true for other API commands and PCI traffic. Above that, you see the sampled GPU metric which especially with AI helps you confirm that Tensor Cores are used.
图 2 :应用程序管道的 Nsight 系统视图

在图 2 中,第二次 PCI 上传和第一次 PCI 下载隐藏在 CUDA 内核执行之后(蓝色)。这样,两个推论之间就没有差距了。此外,您可以在 CPU 部分看到用两个 NVTX 范围标注的 CPU 占用的时间有多少,从而为其他工作释放了资源。

以下是需要强调的其他几个设置决策:

  • CUDA 图
  • TensorRT 工作空间大小
  • NHWC 格式
  • FP16 和 FP8

CUDA 图

CUDA 图减少了网络内所有内核的 CPU 启动开销。虽然第一次发布有捕获 CUDA 图的开销,但所有以下推论都从中受益。

性能增益的大小在很大程度上取决于所使用的网络。对于正在处理多帧的视频处理工作负载,值得尝试 CUDA 图。

虽然在两个 EP 上通常都可以使用 CUDA 图,但它仅在 CUDA 到enable_cuda_graph上作为本地会话创建参数公开。

TensorRT 工作空间大小

TensorRT 工作空间大小是一个经常不清楚的参数,但却是 TensorRT 的一个重要参数。由于 TensorRT 可以重新排列图形中的操作以进行优化,因此可能需要更多内存来存储中间结果。

该值由工作空间大小控制,告诉引擎构建器除了引擎重量和输入之外, TensorRT 还可以分配多少字节。用这个参数进行实验并用推理大小来权衡速度是有意义的。

类似的参数可用于 CUDA EP cudnn_conv_use_max_workspace but serves a ,含义略有不同,因为这仅涉及卷积张量上的中间缓冲区或填充,而不是新的中间缓冲。

NHWC 格式

NHWC 格式的输入非常适合 NVIDIA 上的 Tensor Core GPU 。由于 ONNX 仅支持 NCHW 格式,因此必须使用技巧启用 NHWC 作为输入张量。将输入维度设置为 NHWC ,并在 CUDA 或 TensorRT EP 删除的输入之后插入 Transpose 操作(图 3 )。

After the network input is configured as NHWC we add a transpose layer to write the whole ONNX file as NCHW as it does not support NHWC.
图 3 。添加 Transpose 层

在图 3 中,将 NHWC 的 Transpose 层添加到 NCHW 可以将 NHWC 张量作为输入,尽管 ONNX 仅支持 NCHW 。

FP16 和 FP8

FP16 和 FP8 等操作精度对于 GPU 上的最佳性能尤为重要。在 TensorRT EP 中,必须在会话创建期间使用以下属性显式启用它们:

OrtTensorRTProviderOptions trt_options{};
trt_options.trt_fp16_enable = 1;
trt_options.trt_int8_enable = 1;

有关详细信息,请参见 ONNX Runtime Performance Tuning

结论

阅读本文后,您应该了解如何使用 NVIDIA 后端通过 ONNX Runtime 高效部署 ONNX 模型。这篇文章为如何围绕这一点构建最佳管道提供了指导。

虽然示例没有显示 TensorRT 的实际部署,但它可以保存生成的引擎以供以后使用。如图所示,您可以模板化整个管道以快速交换 TensorRT 和 CUDA EP 。

如果您对这些主题有任何进一步的问题,请访问 NVIDIA 开发者论坛或加入 NVIDIA Developer Discord 。对于示例代码中的错误或问题,请在 NVIDIA/ProViz-AI-Samples 上提交 GitHub 问题。

要阅读本系列的第一篇文章,请参阅 End-to-End AI for NVIDIA-Based PCs: An Introduction to Optimization

有关更多信息和访问 NVIDIA 技术,请参阅 NVIDIA AI for Accelerating Creative Applications

 

标签