故障排除#

以下章节帮助解答关于典型用例的最常见问题。

如需更多帮助,请咨询您的支持工程师或在 NVIDIA 开发者论坛上发布您的问题以获得故障排除支持。

常见问题解答#

本节旨在帮助排除故障并解答我们最常被问到的问题。

问:如何为多个批次大小创建优化的引擎?

答:虽然 TensorRT 允许针对给定批次大小优化的引擎以任何较小的大小运行,但对于那些较小尺寸的性能可能无法得到最佳优化。要针对多个批次大小进行优化,请在分配给 OptProfilerSelector::kOPT 的维度上创建优化配置文件。

问:校准表在不同的 TensorRT 版本之间是否可移植?

答:否。内部实现不断优化,并且可能在版本之间发生变化。因此,不能保证校准表与不同版本的 TensorRT 二进制兼容。当使用新版本的 TensorRT 时,应用程序必须构建新的 INT8 校准表。

问:引擎在不同的 TensorRT 版本之间是否可移植?

答:默认情况下,否。有关配置引擎以实现向前兼容性的说明,请参阅 版本兼容性 部分。

问:如何选择最佳工作区大小?

答:一些 TensorRT 算法需要在 GPU 上额外的workspace。方法 IBuilderConfig::setMemoryPoolLimit() 控制可以分配的最大 workspace 量,并阻止构建器考虑需要更多 workspace 的算法。在运行时,空间在创建 IExecutionContext 时自动分配。即使在 IBuilderConfig::setMemoryPoolLimit() 中设置的量要高得多,分配的量也不会超过所需的量。因此,应用程序应允许 TensorRT 构建器尽可能多的 workspace;在运行时,TensorRT 分配的 workspace 不会超过此值,通常更少。如果设备内存需要在引擎构建期间用于其他目的,则 workspace 大小可能需要限制为小于完整的设备内存大小。

问:如何在多个 GPU 上使用 TensorRT?

答:每个 ICudaEngine 对象在实例化时(由构建器或在反序列化时)绑定到特定的 GPU。要选择 GPU,请在使用构建器或反序列化引擎之前使用 cudaSetDevice()。每个 IExecutionContext 都绑定到与其创建引擎相同的 GPU。当调用 execute()enqueue() 时,请通过在必要时调用 cudaSetDevice() 来确保线程与正确的设备关联。

问:如何从库文件中获取 TensorRT 的版本?

答:符号表有一个名为 tensorrt_version_#_#_#_# 的符号,其中包含 TensorRT 版本号。在 Linux 上读取此符号的一种可能方法是使用 nm 命令,如下例所示

$ nm -D libnvinfer.so.* | grep tensorrt_version
00000000abcd1234 B tensorrt_version_#_#_#_#
问:如果我的网络产生错误的答案,我该怎么办?

答:您的网络可能会生成不正确答案的原因有多种。以下是一些可以帮助诊断问题的故障排除方法

  • 从日志流中打开 VERBOSE 级别的消息,并检查 TensorRT 报告的内容。

  • 检查您的输入预处理是否完全生成网络所需的输入格式。

  • 如果您正在使用降低的精度,请在 FP32 中运行网络。如果它产生正确的结果,则较低的精度可能对网络的动态范围不足。

  • 尝试将网络中的中间张量标记为输出,并验证它们是否符合您的期望。

注意

将张量标记为输出可能会抑制优化,因此,可能会更改结果。

您可以使用 NVIDIA Polygraphy 来帮助您进行调试和诊断。

问:如何在 TensorRT 中实现批归一化?

答:可以使用 TensorRT 中的 IElementWiseLayer 序列来实现批归一化。更具体地说

adjustedScale = scale / sqrt(variance + epsilon)
batchNorm = (input + bias - (adjustedScale * mean)) * adjustedScale
问:为什么我的网络在使用 DLA 时比不使用 DLA 时运行得更慢?

答:DLA 旨在最大限度地提高能源效率。根据 DLA 支持的功能和 GPU 支持的功能,任何一种实现都可能更高效。您选择的实现取决于您的延迟或吞吐量要求和功率预算。由于所有 DLA 引擎都独立于 GPU 且彼此独立,您也可以同时使用这两种实现来进一步提高网络的吞吐量。

问:TensorRT 是否支持 INT4 量化或 INT16 量化?

答:TensorRT 支持用于 GEMM 仅权重量化的 INT4 量化。TensorRT 不支持 INT16 量化。

问:TensorRT 何时会在 UFF 解析器中支持我的网络所需的层 XYZ?

答:UFF 已弃用。我们建议用户将其工作流程切换到 ONNX。TensorRT ONNX 解析器是一个开源项目。

问:我可以使用多个 TensorRT 构建器在不同的目标上进行编译吗?

答:TensorRT 假定用于构建设备的设备的所有资源都可用于优化目的。并发使用多个 TensorRT 构建器(例如,多个 trtexec 实例)在不同的目标(DLA0、DLA1 和 GPU)上进行编译可能会过度订阅系统资源,从而导致未定义的行为(意味着,低效的计划、构建器故障或系统不稳定)。

在使用带有 -saveEngine 参数的 trtexec 时,建议分别针对不同的目标(DLA 和 GPU)进行编译并保存其计划文件。然后可以将此类计划文件重用于加载(使用带有 --loadEngine 参数的 trtexec)并在各自的目标(DLA0、DLA1 和 GPU)上提交多个推理作业。这种两步过程减轻了构建阶段系统资源的过度订阅,同时还允许计划文件的执行在不受构建器干扰的情况下进行。

问:哪些层由 Tensor Cores 加速?

答:大多数数学密集型操作将通过 tensor core 加速 - 卷积、反卷积、全连接和矩阵乘法。在某些情况下,特别是对于小通道计数或小组大小,另一种实现可能更快,并且会被选择而不是 tensor core 实现。

问:为什么观察到重格式化层,即使没有“没有实现遵守无重格式化规则”的警告消息?

答:无重格式化网络 I/O 并不意味着重格式化层不会插入到整个网络中。只有输入和输出网络张量可以配置为不需要重格式化层;换句话说,TensorRT 可以为内部张量插入重格式化层以提高性能。

了解错误消息#

如果在执行期间发生错误,TensorRT 会报告一条错误消息,旨在帮助调试问题。以下各节讨论开发人员可能会遇到的一些常见错误消息。

ONNX 解析器错误消息

下表捕获了常见的 ONNX 解析器错误消息。有关特定的 ONNX 节点支持信息,请参阅 运算符支持文档

常见 ONNX 解析器错误消息#

错误消息

描述

<X> 必须 初始化器!

这些错误消息表示 ONNX 节点输入张量预计在 TensorRT 中是初始化器。可能的修复方法是使用 TensorRT 的 Polygraphy 工具对模型运行常量折叠:polygraphy surgeon sanitize model.onnx --fold-constants --output model_folded.onnx

!inputs.at(X).is_weights()

getPluginCreator() 无法 找到 插件 <operator name> 版本 1

这是一个错误,说明 ONNX 解析器没有为特定运算符定义导入函数,并且在加载的运算符注册表中未找到相应的插件。

TensorRT Core Library 错误消息

下表捕获了常见的 TensorRT core library 错误消息。

常见 TensorRT Core Library 错误消息#

错误消息

描述

安装错误

CUDA 初始化 失败,错误代码为 <code>。 请检查 CUDA 安装: https://docs.nvda.net.cn/cuda/cuda-installation-guide-linux/index.html。

如果 CUDA 或 NVIDIA 驱动程序安装损坏,则可能会发生此错误。有关在您的操作系统上安装 CUDA 和 NVIDIA 驱动程序的说明,请参阅 URL。

构建器错误

内部 错误: 无法 找到 节点 <name> 的任何实现。 尝试使用 IBuilderConfig::setMemoryPoolLimit() 增加 工作区大小。

发生此错误是因为网络中给定的节点没有可以在给定工作区大小下运行的层实现。这通常是因为工作区大小不足,但也可能表明存在错误。如果增加建议的工作区大小没有帮助,请报告错误(请参阅 报告 TensorRT 问题)。

<layer-name>: (内核|偏置)权重具有非零计数但为空值 <layer-name>: (内核|偏置)权重具有零计数但为非空值

当传递给构建器的 Weights 数据结构中的值和计数字段之间存在不匹配时,会发生此错误。如果计数为 0,则值字段必须包含空指针;否则,计数必须为非零,并且值必须包含非空指针。

构建器是在与当前设备不同的设备上创建的。 | 如果您创建一个以一个 GPU 为目标的 IBuilder,调用 cudaSetDevice() 以另一个 GPU 为目标,然后尝试使用 IBuilder 创建引擎,则可能会发生此错误。
确保您仅在使用用于创建 IBuilder 的 GPU 为目标时使用 IBuilder

您可能会遇到错误消息,指示张量维度与给定层的语义不匹配。仔细阅读 NvInfer.h 上关于每个层的使用以及层张量输入和输出的预期维度的文档。

INT8 校准错误

张量 <X> 均匀为零。

当张量的数据分布均匀为零时,会发生此警告,应将其视为错误。在网络中,在以下情况下,输出张量分布可能均匀为零:- 所有值为零的常数张量;不是错误。- 所有负输入的激活 (ReLU) 输出:不是错误。- 由于上一层中的计算错误,数据分布被强制为全零;此处发出警告。[1] - 用户未提供任何校准图像;此处发出警告。[1]

无法 找到 张量 <X> 的比例因子。

此错误表明校准失败,未检测到比例因子。这可能是由于缺少 INT8 校准器或网络层的自定义比例因子不足。

引擎兼容性错误

引擎计划文件与此版本的 TensorRT 不兼容,期望 (格式|库)版本 <X> 但得到 <Y>;请重新构建。

如果您正在运行 TensorRT,但使用的引擎 PLAN 文件与当前版本的 TensorRT 不兼容,则可能会发生此错误。确保在生成和运行引擎时使用相同的 TensorRT 版本。

引擎计划文件是在不兼容的设备上生成的,期望计算能力 <X> 但得到计算能力 <Y>;请重新构建。

如果您在计算能力与用于运行引擎的设备不同的设备上构建引擎,则可能会发生此错误。

不建议跨不同型号的设备使用引擎计划文件,并且可能会影响性能甚至导致错误。

如果您在具有相同计算能力但与引擎运行设备不完全相同的设备上构建引擎,则可能会发生此警告。正如警告所示,强烈建议在生成引擎和部署引擎时使用相同型号的设备,以避免兼容性问题。

内存不足错误

在初始化(张量|层): <name> GPU 内存期间,GPU 内存分配失败。

如果 GPU 内存不足以实例化 TensorRT 引擎,则可能会发生这些错误消息。验证 GPU 是否有足够的内存来容纳所需的层权重和激活张量。

在反序列化权重期间分配失败。

GPU 不满足运行此引擎的最低内存要求…

FP16 错误

网络需要原生 FP16,但平台没有原生 FP16。

如果您尝试在不支持 FP16 算法的 GPU 上反序列化使用 FP16 算法的引擎,则可能会发生此错误消息。您必须在不使用 FP16 精度推理的情况下重建引擎,或者将您的 GPU 升级到支持 FP16 精度推理的型号。

插件错误

自定义层 <name> 返回非零初始化。

如果插件层的 initialize() 方法返回非零值,则可能会发生此错误。请参阅该层的实现以进一步调试此错误。有关更多信息,请参阅 NVIDIA TensorRT 运算符参考

代码分析工具#

编译器 Sanitizers#

Google sanitizers 是一组 代码分析工具

dlopen 和 Address Sanitizer 的问题#

sanitizers 存在一个已知问题,此处有文档记录。当在 sanitizer 下对 TensorRT 使用 dlopen 时,除非采用以下两种解决方案之一,否则将报告内存泄漏

  1. 在 sanitizer 下运行时,不要调用 dlclose

  2. 在 sanitizer 下运行时,将标志 RTLD_NODELETE 传递给 dlopen

dlopen 和 Thread Sanitizer 的问题#

当从多个线程使用 dlopen 时,线程 sanitizer 可能会列出错误。要抑制此警告,请创建一个名为 tsan.supp 的文件,并将以下内容添加到该文件

race::dlopen

在线程 sanitizer 下运行应用程序时,请使用以下命令设置环境变量

export TSAN_OPTIONS=”suppressions=tsan.supp”

CUDA 和 Address Sanitizer 的问题#

address sanitizer 在 CUDA 应用程序中存在一个已知问题,此处有文档记录。为了在 address sanitizer 下成功运行 CUDA 库(例如 TensorRT),请将选项 protect_shadow_gap=0 添加到 ASAN_OPTIONS 环境变量。

CUDA 11.4 中的一个已知错误可能会在 address sanitizer 中触发不匹配的分配和释放错误。要禁用这些错误,请将 alloc_dealloc_mismatch=0 添加到 ASAN_OPTIONS

Undefined Behavior Sanitizer 的问题#

UndefinedBehaviorSanitizer (UBSan) 使用 -fvisibility=hidden 选项报告误报,如 此处有文档记录。添加 -fno-sanitize=vptr 选项以避免 UBSan 报告此类误报。

Valgrind#

Valgrind 是一个动态分析工具框架,可以自动检测应用程序中的内存管理和线程错误。

某些版本的 Valgrind 和 glibc 受 bug 的影响,当使用 dlopen 时,会导致报告虚假的内存泄漏,这会在 Valgrind 的 memcheck 工具下运行 TensorRT 应用程序时产生虚假错误。要解决此问题,请按照 此处文档将以下内容添加到 Valgrind 抑制文件中

{
    Memory leak errors with dlopen
    Memcheck:Leak
    match-leak-kinds: definite
    ...
    fun:*dlopen*
    ...
}

CUDA 11.4 中的一个已知错误可能会在 Valgrind 中触发不匹配的分配和释放错误。要禁用这些错误,请将选项 --show-mismatched-frees=no 添加到 Valgrind 命令行。

Compute Sanitizer#

当在 compute-sanitizer 下运行 TensorRT 应用程序时,由于缺少函数,cuGetProcAddress 可能会失败,错误代码为 500。可以使用 --report-api-errors no 选项忽略或抑制此错误。这是由于 CUDA 向后兼容性检查函数在 CUDA 工具包/驱动程序组合上是否可用。这些函数在 CUDA 的后期版本中引入,但在当前平台上不可用。

了解日志中打印的格式#

在 TensorRT 的日志中,格式打印为类型,后跟步幅和向量化信息。例如

Half(60,1:8,12,3)

其中

  • Half 表示元素类型为 DataType::kHALF,即 16 位浮点数

  • :8 表示格式每个向量打包八个元素,并且向量化沿第二个轴进行。

其余数字是以向量为单位的步幅。对于此张量,坐标 (n,c,h,w) 到地址的映射是

((half*)base_address) + (60*n + 1*floor(c/8) + 12*h + 3*w) * 8 + (c mod 8)

1: 是 NHWC 格式的常见格式。例如,这是 NCHW 格式的另一个示例

Int8(105,15:4,3,1)

INT8 表示元素类型为 DataType::kINT8:4 表示向量大小为 4。对于此张量,坐标 (n,c,h,w) 到地址的映射是

(int8_t*)base_address + (105*n + 15*floor(c/4) + 3*h + w) * 4 + (c mod 4)

标量格式的向量大小为 1。为简洁起见,打印省略了 :1

通常,坐标到地址的映射具有以下形式

(type*)base_address + (vec_coordinate · strides) * vec_size + vec_mod

其中

  • 点表示内积

  • 步幅是打印的步幅,即以向量为单位的步幅

  • vec_size 是每个向量的元素数

  • vec_coordinate 是原始坐标,其中沿向量化轴的坐标除以 vec_size

  • vec_mod 是沿向量化轴的原始坐标模 vec_size

报告 TensorRT 问题#

如果您在使用 TensorRT 时遇到问题,请检查 常见问题解答了解错误消息 部分,以查找类似的失败模式。例如,许多引擎构建失败可以通过使用以下命令使用 Polygraphy 对 ONNX 模型进行清理和常量折叠来解决

polygraphy surgeon sanitize model.onnx --fold-constants --output model_folded.onnx

此外,强烈建议您在提交问题之前先尝试我们最新的 TensorRT 版本(如果您尚未这样做),因为该问题可能已在最新版本中修复。

TensorRT 问题报告渠道#

如果 常见问题解答了解错误消息 部分都无法帮助您,您可以通过 NVIDIA 开发者论坛TensorRT GitHub Issue 页面报告问题。这些渠道会持续监控,以便为您遇到的问题提供反馈。

以下是在 NVIDIA 开发者论坛上报告问题的步骤

  1. 注册 NVIDIA 开发者网站

  2. 登录到开发者网站。

  3. 单击右上角的您的姓名。

  4. 单击我的帐户 > 我的 Bug,然后选择提交新 Bug

  5. 填写 bug 报告页面。描述清楚并提供重现问题的步骤。

  6. 单击提交 Bug

报告问题时,请提供设置详细信息并包括以下信息

  • 环境信息

    • 操作系统或 Linux 发行版和版本

    • GPU 类型

    • NVIDIA 驱动程序版本

    • CUDA 版本

    • cuDNN 版本

    • Python 版本(如果使用 Python)。

    • TensorFlow、PyTorch 和 ONNX 版本(如果使用了其中任何一个)。

    • TensorRT 版本

    • NGC TensorRT 容器版本(如果使用了 TensorRT 容器)。

    • Jetson(如果使用),包括操作系统和硬件版本

  • 问题的详细描述。

  • 重现问题的步骤

    • ONNX 文件(如果使用了 ONNX)。

    • 触发问题的最小命令或脚本

    • 通过在 ILogger 中启用 kVERBOSE 来获取详细日志

根据问题的类型,提供下面列出的更多信息可以加快响应和调试过程。

报告功能问题#

报告功能问题时,例如链接器错误、段错误、引擎构建失败、推理失败等,请提供重现问题的脚本和命令以及详细的环境描述。拥有更多详细信息有助于我们更快地调试功能问题。

由于 TensorRT 引擎特定于特定的 TensorRT 版本和特定的 GPU 类型,请勿在一个环境中构建引擎,然后在另一个具有不同 GPU 或依赖软件堆栈(例如 TensorRT 版本、CUDA 版本、cuDNN 版本等)的环境中使用它来运行。此外,通过检查环境变量 LD_LIBRARY_PATH(或 Windows 上的 %PATH%),确保应用程序链接到正确的 TensorRT 和 cuDNN 共享对象文件。

报告精度问题#

报告精度问题时,请提供用于计算精度指标的脚本和命令。描述预期的精度水平,并分享使用 ONNX-Runtime 等其他框架获得预期结果的步骤。

Polygraphy 工具可以调试精度问题并产生最小的失败案例。有关说明,请参阅 关于调试 TensorRT 精度问题 的文档。拥有显示精度问题的 Polygraphy 命令或最小的失败案例可以加快我们调试您的精度问题所需的时间。

请注意,即使在 FP32 精度下,TensorRT 和 PyTorch、TensorFlow 或 ONNX-Runtime 等其他框架之间期望获得按位相同的结果是不切实际的,因为浮点数计算的顺序可能会导致输出值略有不同。实际上,小的数值差异不应显着影响应用程序的精度指标,例如对象检测网络的 mAP 分数或翻译网络的 BLEU 分数。如果您看到 TensorRT 和 PyTorch、TensorFlow 或 ONNX-Runtime 等其他框架之间的精度指标显着下降,则可能是真正的 TensorRT 错误。

如果您在启用 FP16/BF16 精度时在 TensorRT 引擎输出中看到 NaN 或无限值,则可能是网络中的中间层输出在 FP16/BF16 中溢出。一些有助于缓解这种情况的方法包括

  • 确保网络权重和输入被限制在合理的窄范围内(例如 [-1, 1] 而不是 [-100, 100])。这可能需要更改网络并重新训练。

    • 考虑通过缩放或裁剪输入到受限范围来预处理输入,然后再将其传递给网络以进行推理。

  • 为容易溢出的各个层(例如 Reduce 和 Element-Wise Power ops)覆盖精度为 FP32。

Polygraphy 可以通过使用降低的精度来帮助您诊断常见问题。有关更多信息,请参阅 Polygraphy 的 使用降低的精度 操作指南。

关于精度问题的可能解决方案,请参阅 提高模型精度 部分以及 使用量化类型 部分,以获取有关使用 INT8/FP8 精度 的说明。

报告性能问题#

如果您要报告性能问题,请使用以下命令分享完整的 trtexec 日志

trtexec --onnx=<onnx_file> <precision_and_shape_flags> --verbose --profilingVerbosity=detailed --dumpLayerInfo --dumpProfile --separateProfileRun --useCudaGraph --noDataTransfers --useSpinWait --duration=60

详细日志有助于我们识别性能问题。如果可能,也请使用以下命令分享 Nsight Systems 性能分析文件

trtexec --onnx=<onnx_file> <precision_and_shape_flags> --verbose --profilingVerbosity=detailed --dumpLayerInfo --saveEngine=<engine_path>
nsys profile --cuda-graph-trace=node -o <output_profile> trtexec --loadEngine=<engine_path> <precision_and_shape_flags> --useCudaGraph --noDataTransfers --useSpinWait --warmUp=0 --duration=0 --iterations=20

有关使用 trtexec 工具和这些标志含义的更多说明,请参阅 trtexec 部分。

如果您不使用 trtexec 来测量性能,请提供您用于测量性能的脚本和命令。将您的脚本的性能测量结果与 trtexec 工具的测量结果进行比较。如果两个数字不同,则您的脚本在性能测量方法上可能存在一些问题。

有关影响性能的一些环境因素,请参阅 性能测量的硬件/软件环境 部分。

脚注