使用 Polygraphy 系统化调试 TensorRT 精度问题:从定位误差来源到最小失败用例的完整指南 使用 Polygraphy 系统化调试 TensorRT 精度问题从定位误差来源到最小失败用例的完整指南【免费下载链接】TensorRTNVIDIA® TensorRT™ is an SDK for high-performance deep learning inference on NVIDIA GPUs. This repository contains the open source components of TensorRT.项目地址: https://gitcode.com/GitHub_Trending/tens/TensorRT本指南基于 NVIDIA TensorRT 开源仓库中 Polygraphy 调试精度指南面向在大规模神经网络上遇到 TensorRT 推理精度问题的开发者。它提供了一套扁平化决策流程通过逐步缩小问题范围真实输入 → 间歇性判定 → 逐层对比 → 子图提取 → 模型自动缩减最终将难以定位的精度问题收敛为一个最小失败用例minimal failing case为后续深入代码或上报 Bug 提供清晰起点。读完本文你将掌握polygraphy run、debug build、debug reduce、surgeon、inspect等子工具的完整调用链与关键参数具备独立排查精度问题的实战能力。调试精度问题的总体策略TensorRT 精度问题尤其是大型网络中的精度问题之所以难以调试是因为错误可能在网络中逐层累积与放大早期层的小偏差经过后续层的非线性激活、归一化、池化等操作后可能被急剧放大导致最终输出与参考实现差异巨大而真正的根因却隐藏在网络的深处。本文档给出的核心思路是化整为零与其面对整个网络束手无策不如系统地缩小问题规模、锁定失败来源。原文将这一过程组织成一个扁平化流程图——每一步都是一个二选一的分支判断根据你的实际情况选择对应的下一步。完整流程如下净化 ONNX 模型可选 ↓ 真实输入数据是否有影响 ├─ 是 → 模型对输入数据敏感可能没有 Bug └─ 否 → 问题是否间歇性 ├─ 是 → debug build 定位可疑 tactictactic 选择 └─ 否 → 能否逐层对比 ├─ 是失败可复现→ 提取失败子图 │ ├─ 子图也失败 → 得到最小失败用例 │ └─ 子图正常 → 转向模型缩减 └─ 否标记输出后精度反而恢复/无法运行→ debug reduce 缩减 ONNX 模型 ├─ 缩减模型仍失败 → 得到最小失败用例 └─ 缩减模型不失败/以不同方式失败 → 检查 --check 与 --fail-regex 后重试前置建议如果你使用的是 ONNX 模型建议先尝试净化sanitize模型在某些情况下这本身就能直接解决问题例如常量折叠消除了冗余节点或修复了 shape 运算引入的精度差异。第一步真实输入数据是否造成差异某些模型对输入数据非常敏感。例如真实输入可能比随机生成的输入获得更好的精度——这不一定代表 TensorRT 有 Bug而可能只是模型本身的数值特性。因此调试的第一步是用真实输入数据替换随机生成的数据观察精度是否改善。Polygraphy 提供了多种提供真实输入数据的方式详见run示例 05使用自定义输入数据对比主要包括两种数据加载脚本data loader script编写一个定义了load_data()函数的 Python 脚本Polygraphy 在每次运行时调用它生成输入。适合输入数据量大、避免写盘浪费的场景polygraphy run dynamic_identity.onnx --trt --onnxrt \ --trt-min-shapes X:[1,2,28,28] --trt-opt-shapes X:[1,2,28,28] --trt-max-shapes X:[1,2,28,28] \ --data-loader-script data_loader.pyJSON 输入文件用--load-inputs custom_inputs.json加载预生成的输入。可移植性好且能保证结果可复现polygraphy run dynamic_identity.onnx --trt --onnxrt \ --trt-min-shapes X:[1,2,28,28] --trt-opt-shapes X:[1,2,28,28] --trt-max-shapes X:[1,2,28,28] \ --load-inputs custom_inputs.json注意对于动态形状模型务必确认 TensorRT 优化 profile 覆盖了自定义输入数据的形状如上面示例中min opt max均为[1,2,28,28]。分支判断使用真实输入数据后精度可接受→ 大概率没有 Bug只是模型对输入数据敏感调试到此结束。仍然存在精度问题→ 继续下一步判断问题是否间歇性。第二步问题是否间歇性——用debug build定位可疑 Tactic在开始逐层分析之前先回答一个问题问题是否在多次构建引擎之间间歇出现如果重建引擎后精度问题有时会消失→ 问题具有间歇性进入调试间歇性精度问题小节。如果每次构建引擎都出现精度问题→ 问题稳定可复现直接跳转逐层对比小节。为什么会出现间歇性失败TensorRT 的引擎构建过程是非确定性的构建器依赖 timing 来选择每个算子层的实现策略tactic而每次构建时选择的 tactic 可能不同。当其中某个 tactic 本身存在数值 Bug 时就可能表现为时好时坏flaky/intermittent的精度失败。使用debug build自动化定位可疑 tacticPolygraphy 提供了debug build子工具来帮助你找到这类问题 tactic。其思路是反复构建引擎并保存每次的 tactic replay 文件拿到一组已知好和已知坏的 tactic 后对比找出差异进而定位可疑的失败源头。完整流程源自debug示例 01① 用 ONNX-Runtime 生成 golden 输出作为基准polygraphy run identity.onnx --onnxrt \ --save-outputs golden.json② 用debug build反复构建 TensorRT 引擎与 golden 输出对比并保存每次的 tactic replaypolygraphy debug build identity.onnx --fp16 --save-tactics replay.json \ --artifacts-dir replays --artifacts replay.json --until10 \ --check polygraphy run polygraphy_debug.engine --trt --load-outputs golden.json逐项解读这条命令polygraphy_debug.engine中间产物与其它debug子工具一样debug build每轮迭代会生成一个中间产物默认是当前目录下的./polygraphy_debug.engine一个 TensorRT 引擎。提示debug build支持其它工具如convert、run的全部 TensorRT 构建器配置选项。--check判定命令debug build通过执行--check指定的命令来判断每轮引擎是好还是坏。此处用polygraphy run将引擎输出与 golden 值对比。提示省略--check即可进入交互模式适合初学者。--until终止条件debug build没有自动终止条件必须显式给出。它可以是迭代次数如--until10也可以是字符串good或bad——后者表示找到第一个通过或失败的迭代后即停止。--save-tactics--artifacts--artifacts-dir--save-tactics replay.json让每轮迭代保存 tactic replay 文件--artifacts replay.json让debug build管理这些文件并自动将其分类到good和bad两个子目录下位于--artifacts-dir指定的主目录中。③ 用inspect diff-tactics对比好/坏 tacticpolygraphy inspect diff-tactics --dir replays正常输出类似如果bad目录为空工具会如实报告无法确定可疑 tactic此时若你的模型确实间歇失败说明失败机制可能超出了 tactic replay 的覆盖范围应上报 TensorRT issue[I] Loaded 2 good tactic replays. [I] Loaded 0 bad tactic replays. [I] Could not determine potentially bad tactics. Try generating more tactic replay files?版本注意事项原文重要提示上述基于IAlgorithmSelector的 approach 在较新版本 TensorRT 中已不能可靠工作——TensorRT 10.8 起IAlgorithmSelector接口被弃用部分 tactic 选择不再暴露给该接口因此无法保证确定性构建。对 TensorRT 8.7 及更新版本推荐改用 tactic timing cachePolygraphy 的--save-timing-cache与--load-timing-cache来保证确定性但 timing cache 文件是不透明的无法用inspect diff-tactics解释其内容。分支判断找到了失败 tactic→ 你已经有了最小失败用例跳转文末得到最小失败用例。没找到→ 失败可能并非间歇性进入逐层对比。第三步能否逐层对比——定位第一个出错的层如果精度问题是稳定可复现的最好的下一步就是弄清楚是哪一层导致了失败。Polygraphy 提供了一种机制把网络中的所有张量都标记为输出从而可以逐层比较。但必须注意标记额外输出可能扰动 TensorRT 的优化过程改变 timing、层融合选择与格式约束从而掩盖真实失败。因此需要先确认标记所有输出后精度问题是否仍然存在。逐层对比的操作源自run示例 01框架对比非常直接——用--trt-outputs mark all和--onnx-outputs mark all让两个框架都输出所有中间张量polygraphy run dynamic_identity.onnx --trt --onnxrt \ --trt-outputs mark all \ --onnx-outputs mark all补充几个有用的配套参数--fail-fast在输出出现第一个不匹配后立即退出便于快速定位第一个出错张量。容差控制逐层对比时默认的--atol/--rtol通常按 FP32 精度设定使用--fp16等降精度构建时应适当放宽例如--atol 0.001 --rtol 0.001 --check-error-stat median--check-error-stat可选elemwise默认、mean、median、max分别表示逐元素、均值、中位数、最大绝对/相对误差比较。如果模型有动态输入形状用--input-shapes X:[1,2,4,4]显式指定避免 Polygraphy 默认将动态维覆盖为 1 并给出警告。关于比较逻辑的原理解读Polygraphy 先逐元素计算absdiff out0 - out1与reldiff absdiff / abs(out1)当同一索引满足absdiff[i] atol 且 reldiff[i] rtol时判定失败。elemwise比max更宽松——若不同索引分别超了绝对/相对误差max会失败而elemwise可能通过。分支判断标记其它输出后失败依然复现→ 进入提取失败子图。标记其它输出后精度反而变好或根本无法运行→ 逐层对比这条路走不通进入缩减失败的 ONNX 模型。第四步提取失败子图Extracting A Failing Subgraph既然逐层对比可行就可以从对比日志中确定第一个引入误差的层。一旦锁定问题层就可以把它从模型中提取出来单独研究。① 用inspect model弄清目标层的输入/输出张量名、形状与数据类型查看 TensorRT 网络polygraphy inspect model identity.onnx \ --show layers --display-astrt查看 ONNX 模型polygraphy inspect model identity.onnx --show layers两者输出都包含网络输入/输出张量的dtype与shape列表以及每个层/节点的张量流向--show layers attrs weights可进一步显示层属性与权重。② 用surgeon extract提取只包含问题层的子图源自surgeon示例 01子图隔离当不知道张量形状与数据类型时可用auto让 Polygraphy 自动推断——输入必须同时给出形状和类型两个auto输出只需类型一个autopolygraphy surgeon extract model.onnx \ --inputs x1:auto:auto \ --outputs add_out:auto \ -o subgraph.onnx如果已知形状和类型也可以直接写明例如polygraphy surgeon extract model.onnx \ --inputs x1:[1,3,224,224]:float32 \ --outputs add_out:float32 \ -o subgraph.onnx关于auto的机制Polygraphy 会优先依赖 ONNX shape 推断确定中间张量若推断失败则用 ONNX-Runtime 以合成输入数据跑一次推理来获取形状可通过--model-inputs控制输入形状。注意后一种情况会让子图输入变为固定形状如需恢复动态形状可对子图再次extract并指定含动态维的形状例如--inputs identity_out_0:[-1,-1]:auto。提取后用polygraphy inspect model subgraph.onnx --show layers确认子图结构正确。分支判断子图也失败→ 得到最小失败用例。子图正常→ 说明问题依赖于更大的上下文例如上游张量数值触发了溢出转入模型缩减流程。第五步自动缩减失败的 ONNX 模型debug reduce当逐层对比无法定位失败源头时可以采用暴力缩减法迭代地生成越来越小的子图直到找到仍然失败的最小模型。debug reduce子工具将此过程自动化。工作流程与关键命令完整操作序列源自debug示例 02缩减失败的 ONNX 模型① 前置处理冻结输入形状并折叠 shape 运算对动态形状模型或含 shape 运算的模型尤其必要polygraphy surgeon sanitize model.onnx -o folded.onnx --fold-constants \ --override-input-shapes x0:[1,3,224,224] x1:[1,3,224,224]surgeon sanitize还支持--fold-size-threshold控制常量折叠的最大字节数避免Tile、ConstantOfShape等节点折叠出巨大常量导致模型膨胀。② 预生成全网络逐层 golden 值并保存输入polygraphy run folded.onnx --onnxrt \ --save-inputs inputs.json \ --onnx-outputs mark all --save-outputs layerwise_golden.json③ 用data to-input把输入与逐层输出合并为一个逐层输入文件供后续子图作为张量输入使用polygraphy data to-input inputs.json layerwise_golden.json -o layerwise_inputs.json④ 用debug reduce以bisect模式缩减polygraphy debug reduce folded.onnx -o initial_reduced.onnx --modebisect --load-inputs layerwise_inputs.json \ --check polygraphy run polygraphy_debug.onnx --trt \ --load-inputs layerwise_inputs.json --load-outputs layerwise_golden.json⑤ 用linear模式进一步细化bisect得到的模型未必最小polygraphy debug reduce initial_reduced.onnx -o final_reduced.onnx --modelinear --load-inputs layerwise_inputs.json \ --check polygraphy run polygraphy_debug.onnx --trt \ --load-inputs layerwise_inputs.json --load-outputs layerwise_golden.json关键参数与原理--mode缩减策略详见debug reduce使用指南bisect复杂度为O(log N)linear为O(N)但可能得到更小的模型推荐策略是先bisect后linear。--check判定命令每轮迭代生成中间产物polygraphy_debug.onnx可用--iter-artifact修改路径由--check判定好坏。省略--check进入交互模式。为什么必须提供--load-inputs若不提供polygraphy run会为子图张量重新随机生成输入这些值与生成 golden 数据时张量的实际取值不符对比将失去意义。对于含多路并行分支的模型如两条分支汇合到Sumdebug reduce需要把其中一条分支折叠为常量才能继续缩减因此必须提供输入数据否则会收到如下警告并可能产生假阴性[W] This model includes multiple branches/paths. In order to continue reducing, one branch needs to be folded away. Please ensure that you have provided a data loader argument to debug reduce if your --check command is using a non-default data loader. Not doing so may result in false negatives!动态形状模型的处理优先用surgeon sanitize --override-input-shapes冻结输入形状并--fold-constants折叠 shape 运算或给debug reduce传--model-input-shapes借助 shape 推断shape 推断失败时可加--force-fallback-shape-inference改为跑推理获取形状也可用--no-reduce-inputs保持原模型输入不变、只从尾部移除层。保留中间产物--artifacts polygraphy_debug.onnx可让每轮子图自动分类到good/bad目录文件名含迭代号便于缩减异常退出时仍有现场也便于人工对比不同子图寻找规律。额外产出最小通过模型--min-good path让debug reduce同时保存最接近最小失败模型的最小通过模型两者对比常能揭示失败根因的更多线索。精度误差调试的容差与 golden 值策略针对精度类失败debug reduce使用指南 专门强调两点容差选择中间层可能存在较大误差却并不影响最终输出精度假阳性同时容差又必须低到能抓住真实错误。好的起点是把容差设为接近全模型观察到的误差水平。两种 golden 值生成方式一次性预生成所有层的 golden 值必须保证每个子图的输入来自 golden 值否则对比无意义即上面命令中--load-inputs的用途。每轮子图单独生成 golden 值手动工作量更少但无法精确复现子图在原图上下文中的行为——例如原模型中某中间层发生溢出导致的错误重新生成输入可能无法复现。分支判断缩减后的模型仍然失败→ 得到最小失败用例。缩减后不再失败或以不同方式失败→ 检查缩减选项后重试。第六步检查--check与--fail-regex如果缩减后的模型不再失败或以不同方式失败先确认你的--check命令是否正确。特别地建议使用--fail-regex来确保缩减过程只针对精度失败本身、忽略其它无关失败。这里需要理解debug系列子工具的失败判定机制详见debug子工具使用指南debug子工具按非零退出码判定一次迭代为失败。但有时--check命令本身不会以非零码退出例如polygraphy inspect model总是成功此时可以用--fail-regex指定正则表达式只要--check命令的stdout/stderr输出中匹配到任一正则即判定为失败。例如示例文档用模型中包含Mul节点来模拟失败polygraphy inspect model的--show layers输出中包含Op: Mul文本从而体验缩减流程polygraphy debug reduce folded.onnx -o initial_reduced.onnx --modebisect \ --fail-regex Op: Mul \ --check polygraphy inspect model polygraphy_debug.onnx --show layers验证缩减结果应只剩Mul节点polygraphy inspect model final_reduced.onnx --show layers检查完--check与--fail-regex后回到缩减失败的 ONNX 模型步骤重新缩减。收尾你得到了一个最小失败用例走到这里你已经成功把一个难以捉摸的 TensorRT 精度问题收敛为最小失败用例minimal failing case——无论它是某个可疑 tactic、某个单独失败的子图还是缩减到极致的 ONNX 模型。后续调试将显著轻松如果你是TensorRT 开发者接下来可以基于该最小用例深入代码结合 Polygraphy 测试用例 中的对比逻辑复现并定位实现缺陷如果你不是TensorRT 开发者请带着最小失败用例、复现命令与相关日志上报 Bug这将极大帮助维护者快速定位问题。进一步阅读Polygraphy 精度调试指南本文原始出处debug子工具使用指南交互模式与失败判定机制debug reduce使用指南容差、golden 值、缩减模式示例调试间歇性 Tactic 问题 与 缩减失败的 ONNX 模型示例框架对比与逐层输出对比、自定义输入数据示例子图隔离surgeon extract、常量折叠surgeon sanitize示例检查 TensorRT 网络、检查 ONNX 模型【免费下载链接】TensorRTNVIDIA® TensorRT™ is an SDK for high-performance deep learning inference on NVIDIA GPUs. This repository contains the open source components of TensorRT.项目地址: https://gitcode.com/GitHub_Trending/tens/TensorRT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考