1. 从一次模型推理的“诡异”精度损失说起
最近在把一个训练好的PyTorch模型部署到NVIDIA GPU上做推理加速,用上了TensorRT。流程走得很顺,模型转换、构建引擎、执行推理,一气呵成。然而,当我兴冲冲地对比原始PyTorch模型和TensorRT引擎的输出时,心凉了半截——某些关键输出张量的数值差异超出了可接受的范围,虽然没到完全错误的地步,但精度损失已经影响了业务逻辑的判断。更让人头疼的是,整个过程没有任何报错,日志一片祥和,仿佛在说:“看,我跑得多快。” 问题出在哪?是模型转换时某个算子不支持导致的精度妥协?是层融合(Layer Fusion)时引入了细微的数值误差?还是我的输入数据预处理在某个环节和转换时对不上?
这种“静默失败”是模型部署中最让人沮丧的情况之一。TensorRT作为一个高性能的推理优化器,其内部进行了大量图优化、精度校准和内核选择,这个过程像一个黑盒。当出现精度或性能问题时,传统的打印日志、断点调试方法几乎失效。你需要一个“X光机”,能够透视TensorRT的整个工作流程,从模型导入、图优化、到引擎构建和推理执行,进行逐层、逐张量的比对和验证。这就是NVIDIA官方推出的模型调试与验证工具——polygraphy的核心价值所在。它不是什么新潮的框架,而是一个专为TensorRT生态打造的“外科手术刀”,能精准地定位模型转换和推理过程中的问题。今天,我们就来彻底搞懂它,让你下次再遇到TensorRT的“玄学”问题时,能有的放矢,快速排雷。
2. polygraphy是什么?为什么它是TensorRT调试的“瑞士军刀”
在深入使用之前,我们得先弄清楚polygraphy的定位。它不是一个独立的推理运行时,而是一个Python工具包和命令行工具集。你可以把它理解为TensorRT(以及ONNX Runtime等其他推理后端)的“高级调试插件”和“自动化测试框架”。它的设计目标非常明确:简化、自动化和深化模型在部署流程中的验证与调试工作。
为什么在已经有TensorRT的trtexec等工具的情况下,还需要polygraphy?因为trtexec更侧重于性能基准测试和引擎生成,而在模型行为正确性验证方面不够细致。polygraphy填补了这个空白,它提供了以下几个不可替代的核心能力:
2.1 多后端交叉验证(Sanity Check)这是polygraphy的基石功能。它允许你将同一个模型,用不同的后端(如PyTorch、ONNX Runtime、TensorFlow)和TensorRT进行推理,并逐层、逐输出地比较结果。这能第一时间告诉你,是TensorRT转换本身引入了误差,还是你的原始模型在其他后端上就有问题。它支持从多种格式加载模型(如.onnx,.pt,.trt引擎文件),并自动处理不同框架间的输入/输出张量名称映射和数据搬运。
2.2 逐层精度分析(Layer-wise Precision Analysis)当整体输出出现偏差时,你需要知道是哪个算子或哪一层开始“跑偏”的。polygraphy可以运行模型,并导出每一层(或每个算子)的输入和输出张量。你可以将这些中间结果与参考后端(如ONNX Runtime)的对应结果进行比对,从而将问题范围从整个网络缩小到某个具体的层或算子组合。这对于定位因TensorRT不支持的算子、或特定精度(FP16/INT8)下数值不稳定导致的问题至关重要。
2.3 自动化故障排查工作流polygraphy提供了一系列命令行工具,可以将复杂的调试流程脚本化。例如,一个典型的排查路径是:
- 用
polygraphy run快速验证模型在不同后端下的输出一致性。 - 如果失败,用
polygraphy debug工具自动进行二分法搜索,定位是哪个图优化(如某个融合规则)或哪个层导致了错误。 - 使用
polygraphy inspect检查模型结构、TensorRT引擎的计划(plan)、或者各层的精度信息。 这些工具通过命令行参数组合,能构建出强大的自动化测试流水线。
2.4 对INT8量化调试的强力支持INT8量化是TensorRT提升性能的利器,但也是调试的难点。polygraphy可以协助你验证校准(Calibration)过程,对比量化前后各层的数值分布,帮助诊断是因校准数据不具代表性导致的精度骤降,还是模型中存在对量化敏感的结构(如某些激活函数)。
简单来说,如果你满足于“模型能跑起来,速度还挺快”,那么可能用不到polygraphy。但如果你追求的是“模型必须跑得又快又准,并且我知道为什么快、为什么准”,那么polygraphy是你工具箱里的必备品。它把模型部署中的“黑盒”调试,变成了可观测、可分析、可复现的“白盒”操作。
3. 手把手搭建你的polygraphy调试环境
工欲善其事,必先利其器。polygraphy的安装不算复杂,但需要注意一些版本匹配问题,否则很容易掉进坑里。
3.1 基础环境准备首先,确保你的基础环境已经就绪:
- CUDA和cuDNN:这是TensorRT的基石。请根据你打算使用的TensorRT版本,查阅NVIDIA官方文档,安装对应版本的CUDA和cuDNN。版本不匹配是绝大多数问题的根源。
- TensorRT:从NVIDIA官网下载并安装TensorRT。建议使用.tar.gz包安装,便于管理库路径。安装后,务必将TensorRT的
lib目录添加到LD_LIBRARY_PATH环境变量中。export LD_LIBRARY_PATH=/path/to/your/TensorRT-8.x.x.x/lib:$LD_LIBRARY_PATH
3.2 安装polygraphypolygraphy可以通过Python的pip包管理器安装。强烈建议在虚拟环境(如venv或conda)中进行,以避免污染系统环境或与其他项目产生冲突。
# 创建并激活一个虚拟环境(以conda为例) conda create -n trt_debug python=3.8 conda activate trt_debug # 使用pip安装polygraphy。它会自动安装一些核心依赖。 pip install polygraphy3.3 安装可选的后端polygraphy的核心功能需要与其他推理后端交互。根据你的需求,选择性安装:
- ONNX Runtime:这是最常用的参考后端,强烈建议安装。
pip install onnxruntime-gpu # 如果使用GPU,确保CUDA版本匹配 # 或者 pip install onnxruntime 使用CPU版本 - PyTorch:如果你的原始模型是PyTorch的。
pip install torch torchvision - TensorFlow:如果需要与TF模型对比。
pip install tensorflow
3.4 验证安装安装完成后,运行一个快速命令验证polygraphy是否正常工作,以及TensorRT后端是否可用:
polygraphy run --help这应该会显示polygraphy run工具的帮助信息。更进一步的验证,可以尝试列出可用的计算后端:
polygraphy run --check这个命令会检查当前环境下polygraphy能识别和使用的所有推理后端(如trt,onnxrt,trt-legacy等)。如果TensorRT后端显示为可用,说明环境基本配置正确。
注意:一个常见的“坑”。有时即使TensorRT安装好了,
polygraphy run也可能找不到libnvinfer.so等库。这几乎总是因为LD_LIBRARY_PATH没有正确设置,或者在虚拟环境中未生效。请仔细检查,并确保在激活虚拟环境后,该环境变量已包含TensorRT的库路径。你可以通过echo $LD_LIBRARY_PATH来确认。
4. 核心武器一:polygraphy run—— 模型正确性的第一道防线
polygraphy run是你最常用到的命令。它的核心思想是“对比验证”。让我们通过一个实际场景来学习如何使用它。
4.1 场景:验证ONNX模型转TensorRT后的精度假设你有一个已经导出为ONNX格式的模型model.onnx,并用trtexec生成了一个TensorRT引擎model.engine。现在你想确保这个引擎的输出与原始ONNX模型在ONNX Runtime下的输出是一致的。
一个最基本的验证命令如下:
polygraphy run model.onnx \ --trt --save-engine=model.engine \ --onnxrt \ --atol 1e-3 --rtol 1e-3 \ --verbose让我们拆解这个命令:
model.onnx:输入的模型文件。polygraphy run会根据后续参数,用它来生成TensorRT引擎或直接提供给ONNX Runtime。--trt:指定使用TensorRT后端来运行模型。--save-engine=model.engine:指示TensorRT后端构建引擎,并将其保存到model.engine文件。如果文件已存在,polygraphy默认会直接加载它,而不是重新构建。--onnxrt:指定同时使用ONNX Runtime后端作为参考。--atol 1e-3 --rtol 1e-3:设置绝对公差(absolute tolerance)和相对公差(relative tolerance)。这是判断两个张量是否“相等”的关键。由于浮点数计算存在固有误差,我们很少要求完全相等。atol=1e-3意味着允许绝对误差在0.001以内;rtol=1e-3意味着允许相对误差在0.1%以内。你需要根据模型的数据范围和业务敏感度来调整这两个值。对于分类任务,可能宽松些;对于回归任务,可能需要更严格。--verbose:输出详细信息,包括每个输出张量的具体比较结果。
当执行这个命令时,polygraphy会做以下几件事:
- 加载
model.onnx。 - 使用TensorRT(如果引擎不存在则构建,存在则加载)进行一次推理。
- 使用ONNX Runtime进行一次推理。
- 比较两个后端所有输出张量的值,检查它们是否在设定的容差范围内一致。
- 在终端输出详细的比较报告。
4.2 处理输入数据上面的命令使用了模型的默认输入(通常是全零或随机值)。但在真实场景中,我们需要用真实或代表性的数据来验证。polygraphy提供了灵活的数据加载方式。
方式一:使用NumPy数据文件这是最常用的方法。你可以将输入数据保存为.npz文件(多个数组)或.npy文件(单个数组)。数组的键名(对于.npz)或文件名需要与模型输入的名称对应。
假设模型有一个输入叫input0,你可以:
# 准备数据,例如在Python中 import numpy as np data = np.random.randn(1, 3, 224, 224).astype(np.float32) # 假设是图像输入 np.save(‘input0.npy‘, data) # 运行polygraphy polygraphy run model.onnx \ --trt --onnxrt \ --load-inputs inputs.npz # 如果所有输入在一个npz文件里 # 或者 --load-inputs input0.npy # 如果只有一个输入文件方式二:使用数据加载器脚本对于更复杂的数据预处理(如图像解码、归一化),可以编写一个Python脚本作为数据加载器。
# data_loader.py import numpy as np def load_data(): # 你的数据加载和预处理逻辑 image = load_and_preprocess_image(‘test.jpg‘) return {‘input0‘: image} # 返回一个字典,键为输入名,值为numpy数组然后在命令行中引用:
polygraphy run model.onnx \ --trt --onnxrt \ --load-inputs data_loader.py4.3 理解输出与常见问题运行后,如果验证通过,你会看到类似[I] PASSED的输出。如果失败,输出会详细指出哪个输出张量不匹配,误差有多大。
一个典型的失败信息会告诉你:
Output ‘output_name‘:是哪个输出出了问题。Max Absolute Difference:最大绝对误差。Max Relative Difference:最大相对误差。- 甚至可能打印出误差最大的那个元素在两个后端中的具体值。
遇到失败怎么办?
- 检查容差:首先确认你设置的
--atol和--rtol是否合理。对于FP32模型,1e-5是常见的严格标准;对于FP16,1e-3可能更现实。 - 检查输入:确保两个后端接收到完全相同的输入数据。使用
--save-inputs参数可以将polygraphy使用的输入数据保存下来,方便你检查。 - 检查模型:如果误差巨大,可能是模型转换时某个算子不被TensorRT支持,被替换或拆分了。这时就需要用到更强大的
polygraphy debug工具进行深度定位。
5. 核心武器二:polygraphy debug—— 定位问题层的“二分法”利器
当polygraphy run告诉你输出不一致,且排除了输入和容差问题后,真正的挑战才开始:到底是模型的哪一部分导致了差异?手动逐层检查对于一个成百上千层的网络来说是不现实的。polygraphy debug工具自动化了这个过程,它采用了一种类似“二分查找”的策略,系统地、自动化地定位问题源。
5.1debug工具的工作原理想象一下,你的模型是一个长长的操作序列(A->B->C->...->Z)。debug工具的目标是找到第一个产生错误输出的操作。它的算法大致如下:
- 它首先在序列的中间点(比如操作M)将模型“切开”。它运行原始参考模型(如ONNX Runtime)到M点,保存中间输出。
- 然后,它构建两个TensorRT子模型:一个从起点到M点,另一个从M点到终点。它用第一步保存的中间输出作为第二个子模型的输入。
- 分别验证这两个TensorRT子模型与参考模型对应部分输出是否一致。
- 根据验证结果,问题必然出现在其中一个子模型中。于是,它就在有问题的那个子模型区间内,再次进行“切开”和验证。
- 重复这个过程,直到将问题范围缩小到单个或少数几个操作。
这个过程完全自动化,你只需要告诉它模型和参考后端。
5.2 使用debug进行自动化根因分析继续使用之前的model.onnx,假设我们已经知道TensorRT输出不对。我们可以启动调试会话:
polygraphy debug reduce model.onnx \ --check polygraphy run polygraphy_debug.engine \ --onnxrt \ --atol 1e-3 \ --rtol 1e-3 \ --artifacts-dir ./debug_artifacts \ --show-output这个命令看起来复杂,我们来分解一下:
polygraphy debug reduce:这是调试命令,reduce模式用于自动缩小问题范围。model.onnx:待调试的模型。--check:这是核心参数,它指定了用于判断“是否通过”的命令。这里我们嵌套了一个polygraphy run命令。polygraphy_debug.engine是一个占位符,debug工具在每次迭代中会生成一个临时的TensorRT引擎文件并替换这个名字。--onnxrt --atol 1e-3 --rtol 1e-3定义了判断标准:用ONNX Runtime作为参考,容差为1e-3。
--artifacts-dir:指定一个目录来保存调试过程中生成的所有中间文件(如每次迭代的子模型、引擎、日志等)。这对于事后分析非常重要。--show-output:实时显示调试过程的输出。
运行这个命令后,你会看到终端里开始滚动日志,debug工具在自动地进行“切开-验证-判断-再切开”的循环。最终,它会输出一个结论,例如:
[I] The problem was isolated to 2 nodes: [I] Node: ‘/conv1/Conv‘ (Op: Conv) [I] Node: ‘/relu1/Relu‘ (Op: Relu)这告诉你,问题很可能出在名为/conv1/Conv的卷积层和其后的/relu1/Relu激活层这个组合上。
5.3 分析调试产物在--artifacts-dir指定的目录里,你会找到一系列文件,其中最重要的是:
reduced.onnx:这是debug工具最终找到的、能复现问题的最小化模型。这个模型只包含导致问题的那些层,极大简化了你的分析对象。- 迭代文件夹(
iter_0000/,iter_0001/...):里面保存了每一次“切开”后生成的子模型和对应的引擎。你可以用Netron可视化这些.onnx文件,直观地看到debug工具是如何一步步缩小范围的。
拿到reduced.onnx后,你就可以集中火力分析这几层:检查卷积的参数(如步长、填充、分组)、检查输入/输出的维度、思考在FP16精度下Relu是否可能引入异常等。相比于面对原始的巨大模型,现在的问题已经变得非常具体和可管理。
6. 核心武器三:polygraphy inspect—— 模型与引擎的“体检报告”
如果说run和debug是动态调试工具,那么inspect就是一个静态分析工具。它用于查看模型或引擎的内部信息,帮助你理解TensorRT到底对你的模型做了什么。
6.1 检查TensorRT引擎计划(Plan)TensorRT引擎文件(.engine或.plan)是一个黑盒二进制文件。inspect可以将其解构,展示出引擎的执行计划。
polygraphy inspect model engine model.engine这个命令会输出大量信息,包括:
- 引擎基本信息:如名称、TensorRT版本、计算能力(compute capability)。
- 绑定信息(Bindings):列出所有的输入和输出张量,包括它们的名称、数据类型、形状(如果引擎是动态形状的,会显示优化范围)。
- 层信息(Layers):这是最关键的部分。它列出了引擎中所有的层(或更准确地说,是“操作”或“内核”)。你会看到:
- 层的名称和类型(如Convolution, Activation, Pooling)。
- 该层的精度(如float32, float16, int8)。
- 该层使用的具体算法(例如,对于卷积,会显示其使用的
cudnnConvolutionFwdAlgo_t)。 - 该层的输入和输出张量。
通过查看层信息,你可以确认:
- 层融合:看看TensorRT是否将
Conv + Bias + Relu融合成了一个单一的内核。 - 精度设置:哪些层运行在FP16或INT8下,哪些保持在FP32。
- 动态形状:对于每个绑定,其最小、最优、最大形状分别是多少。
6.2 检查模型结构你也可以用inspect来查看ONNX模型的结构,这比用Netron在命令行中快速浏览更便捷。
polygraphy inspect model model.onnx --mode basic--mode参数可以控制输出信息的详细程度,basic模式会显示图的基本信息、输入输出以及节点列表。
6.3 对比两个模型inspect还能对比两个模型,找出它们结构上的差异。
polygraphy inspect diff model_a.onnx model_b.onnx这在以下场景非常有用:
- 对比原始ONNX模型和经过某些预处理(如onnx-simplifier简化后)的模型。
- 对比TensorRT构建引擎前后,模型图发生的变化(虽然更常用的是对比ONNX和Engine的差异,但
inspectdiff主要针对模型结构)。
7. 实战演练:一个完整的TensorRT精度调试案例
让我们虚构一个完整的场景,串联使用上述工具。
7.1 问题描述我们有一个用于图像超分辨率的PyTorch模型SRNet,已导出为srnet.onnx。使用TensorRT(FP16模式)转换并生成引擎srnet_fp16.engine后,推理速度提升显著,但生成的部分图像存在明显的局部色块和伪影。
7.2 第一步:基础验证首先,用polygraphy run进行快速验证,使用一张测试图片。
# 假设我们有一个数据加载脚本 prepare_input.py polygraphy run srnet.onnx \ --trt --save-engine=srnet_fp16.engine \ --onnxrt \ --load-inputs prepare_input.py \ --atol 1e-2 --rtol 1e-2 \ # 图像任务容差可以稍大 --verbose输出显示,output_pixel张量的最大相对误差达到了0.5,远超容差,验证失败。
7.3 第二步:定位问题区间启动debug工具,自动化查找问题层。
polygraphy debug reduce srnet.onnx \ --check “polygraphy run polygraphy_debug.engine --onnxrt --load-inputs prepare_input.py --atol 1e-2“ \ --artifacts-dir ./debug_srnet \ --show-output经过约10次迭代,工具输出结论:问题被隔离到包含‘/upconv1/Conv‘,‘/pixelshuffle1/DepthToSpace‘,‘/final_act/Tanh‘这三个连续节点的一个小子图中。
7.4 第三步:静态分析与假设
- 用Netron打开
debug_srnet/iter_final/reduced.onnx,观察这个最小子图。它由一个转置卷积(ConvTranspose,可能用于上采样)、一个PixelShuffle(深度到空间重排)和一个Tanh激活函数组成。 - 用
polygraphy inspect查看引擎中对应层的精度:
发现polygraphy inspect model engine srnet_fp16.engine --mode layers | grep -A5 -B5 “upconv1\|pixelshuffle1\|final_act“/upconv1/Conv和/final_act/Tanh在引擎中被标记为float16精度。
7.5 第四步:提出假设与验证Tanh激活函数在输入值较大时,其梯度会变得非常小。在FP16精度下,数值表示范围(~5.96e-8 ~ 65504)远小于FP32,且精度更低。有可能在FP16下,上采样层(upconv1)输出的数值范围偶尔会超出FP16下Tanh函数稳定计算的区间,或者由于精度损失导致梯度计算出现异常,从而在图像上表现为色块。
验证方法:强制有问题的层使用FP32精度。 我们可以修改TensorRT的builder配置,通过设置逐层精度覆盖(layer precision override)来实现。但这需要写代码。一个更快捷的验证方式是:直接构建一个全FP32的引擎来对比。
# 使用trtexec快速构建一个FP32引擎 trtexec --onnx=srnet.onnx --saveEngine=srnet_fp32.engine --fp32 # 再次用polygraphy run比较 FP32 TRT 和 ONNXRuntime polygraphy run srnet.onnx \ --trt --load-engine=srnet_fp32.engine \ --onnxrt \ --load-inputs prepare_input.py \ --atol 1e-4 --rtol 1e-4如果这次误差回到正常范围,并且生成的图像伪影消失,那么就证实了我们的假设:网络末端的Tanh激活函数对FP16精度敏感。
7.6 第五步:解决方案既然找到了根本原因,解决方案就明确了:
- 精度覆盖:在构建引擎时,通过TensorRT的Python API或
trtexec的--layerPrecisions参数,强制将/final_act/Tanh层及其输入层保持在FP32精度。 - 修改模型:考虑将最后的Tanh激活替换为对低精度更友好的函数(如Sigmoid的缩放版),或者在Tanh前加入一个小的归一化层,约束输入范围。
- 调整训练:如果在训练时就考虑到部署,可以在训练中模拟FP16精度(使用AMP自动混合精度),让模型提前适应。
通过这个案例,你可以看到polygraphy如何将一起“玄学”的图像伪影问题,通过run->debug->inspect的工具链,转化为一个具体的、可验证的、可解决的技术问题(特定层在FP16下的数值不稳定)。这正是高效模型调试的核心。
8. 进阶技巧与避坑指南
掌握了基本工具链后,一些进阶技巧和常见陷阱能让你事半功倍。
8.1 善用--val-range参数进行压力测试polygraphy run的--val-range参数可以自动生成输入数据,用于测试模型在不同数值范围内的行为。这对于检查模型在边界情况下的鲁棒性非常有用。
# 测试输入值在[-1, 1]范围内时模型的行为 polygraphy run model.onnx --trt --onnxrt --val-range input0:[-1,1] # 测试输入值在[0, 255]范围内时模型的行为(模拟图像像素值) polygraphy run model.onnx --trt --onnxrt --val-range input0:[0,255]如果模型在某个数值范围内误差突然增大,可能提示了模型中存在数值敏感的操作(如除法、指数运算)。
8.2 处理动态形状模型对于支持动态形状的模型,你需要为每个输入指定一个“优化配置文件”(Optimization Profile)。在polygraphy run中,可以使用--trt-min-shapes,--trt-opt-shapes,--trt-max-shapes参数来指定。
polygraphy run dynamic_model.onnx \ --trt \ --onnxrt \ --trt-min-shapes input0:[1,3,224,224] \ --trt-opt-shapes input0:[4,3,224,224] \ --trt-max-shapes input0:[8,3,224,224] \ --input-shapes input0:[4,3,224,224] # 本次推理使用的具体形状确保ONNX Runtime后端也使用相同的输入形状进行对比。
8.3debug工具的高级模式除了reduce模式,debug还有bisect等模式,适用于不同场景。reduce是通用且强大的,但有时bisect在特定情况下可能更快。查阅官方文档了解不同模式的区别。
8.4 性能分析与run工具polygraphy run也可以用于简单的性能对比。使用--warm-up和--iterations参数。
polygraphy run model.onnx --trt --iterations=100 --warm-up=10 --duration=0这会让TensorRT推理100次,并忽略前10次预热的结果,然后输出平均延迟。你可以对比--trt和--onnxrt后的性能数据。但请注意,对于严格的性能基准测试,更专业的工具(如Nsight Systems)仍是首选。
8.5 常见“坑”与解决思路
- 错误:
TensorRT was not found on the system...- 原因:
LD_LIBRARY_PATH未正确设置,或者虚拟环境未继承该变量。 - 解决:在激活虚拟环境后,显式设置
LD_LIBRARY_PATH。或在虚拟环境的activate脚本中设置。
- 原因:
- 错误:
INVALID_ARGUMENT: ... getPluginCreator could not find plugin ...- 原因:模型使用了自定义插件(Plugin),但运行环境没有加载对应的插件库。
- 解决:使用
--plugins参数指定插件库文件(.so文件)。polygraphy run model.onnx --trt --plugins /path/to/libmyplugin.so
debug过程卡住或异常缓慢- 原因:模型很大,或者
debug的某些迭代步骤中,生成的子模型触发了TensorRT的某些耗时优化或错误。 - 解决:尝试使用
--minimal参数,让debug工具生成更精简的中间模型。或者,先尝试用--mode子命令进行一些初步分析。
- 原因:模型很大,或者
- INT8量化模型验证失败
- 原因:INT8精度下误差通常更大。校准数据集不具代表性是主因。
- 解决:
- 确保
polygraphy run时使用的验证数据不在校准数据集中。 - 使用
--load-inputs提供更具代表性的验证数据。 - 适当放宽
--atol和--rtol。 - 使用
polygraphy inspect检查各层是否真的以INT8运行,有时TensorRT会出于精度考虑将某些层回退到FP16/FP32。
- 确保
polygraphy的强大之处在于它将一系列繁琐、容易出错的调试任务封装成了简单的命令行操作。从快速的正确性检查,到自动化的根因定位,再到深度的引擎分析,它覆盖了TensorRT模型调试生命周期的关键环节。掌握它,并不能让你避免所有问题,但能确保当问题出现时,你有一套科学、高效的方法来应对,而不是盲目地猜测和试错。下次当你TensorRT模型输出不对劲时,别急着怀疑人生,先让polygraphy帮你照一照。