Polygraphy 实战用 Runner API 在真实数据集上验证 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导读本文基于 TensorRT 开源仓库中 Polygraphy 的官方示例 02_validating_on_a_dataset系统讲解为什么在大规模真实数据集含标签或 golden 值的精度验证场景下应当直接使用 Runner API 而非Comparator并通过TrtRunner的完整可运行代码演示如何逐样本加载数据、执行推理并断言结果。读完本文你将掌握 Polygraphy 的 Runner 统一接口、infer()的缓冲区复用语义以及如何用最少的改动把验证逻辑切换到 ONNX-Runtime 等其他推理后端。为什么Comparator不适合真实数据集验证Polygraphy 提供的Comparator非常适合在多个 runner 之间比较少量推理结果例如快速对比 TensorRT 引擎与 ONNX-Runtime 的输出差异。但从源码看Comparator.run()的设计目标始终是运行并收集、比较结果它接收一组 runners通过data_loader供给输入数据逐次调用runner.infer()并把每次输出封装成IterationResult收集进RunResults见 comparator/comparator.py、comparator/struct.py当迭代次数大于 1 时它会为每次输出执行copy.deepcopy(outputs)见 comparator/comparator.py这在样本数量巨大时会带来显著的内存开销它内置的DataLoader按既定规则如正态分布随机数生成输入data_loader.py 中DataLoader的迭代次数由数据量决定对逐条读取真实样本、逐条与 golden 值比对这种验证范式并不友好。当验证对象是单个 runner、数据集规模大、且每个样本都带有标签或 golden 输出时官方文档给出的结论非常明确直接使用 runner 更合适。需要补充的是Comparator.run()提供了data_loader参数允许用户传入自定义输入数据List[Dict[str, numpy.ndarray]]或生成器因此在小数据集场景下这也是一条可行路径见 comparator/comparator.py 中data_loader与warm_up、use_subprocess、save_inputs_path等参数说明。直接使用 Runner 的两大核心优势1. 输入加载与结果验证完全自由TrtRunner只是一个封装 TensorRT 推理的对象你完全可以自己写for循环从磁盘、数据库或内存逐条取出输入数据用runner.infer()执行推理再用任意你喜欢的指标np.array_equal、MSE、Top-1 等逐条比对 golden 值。数据如何加载、结果如何判定都交由你的代码全权控制。2. Runner 统一接口带来极低切换成本所有 runner 都继承自 backend/base/runner.py 中的BaseRunner对外暴露一致的接口__enter__/__exit__上下文管理器进入时调用activate()完成 GPU/CPU 内存分配等初始化退出时调用deactivate()释放资源见 backend/base/runner.pyinfer(feed_dict, ...)接收一个输入名 - numpy 数组的字典返回输出名 - 数组的字典。因此把验证后端从 TensorRT 换成 ONNX-Runtime只需要把 runner 的构造方式换掉验证循环本身一行都不用改。示例文档甚至指出在本例中切换到 ONNX-Runtime 只需改动 2 行代码这被留作读者的练习。运行示例的完整步骤环境准备确保本机已安装 TensorRTTrtRunner依赖tensorrtPython 包安装其他依赖。示例目录 02_validating_on_a_dataset/requirements.txt 中只有一个依赖numpy执行python3 -m pip install -r requirements.txt示例所需的模型文件 identity.onnx 已随仓库提供无需额外下载。运行示例python3 example.py正常结束时终端会输出Validation succeeded!。逐行拆解 example.pyRunner 验证的完整范式示例主脚本位于 02_validating_on_a_dataset/example.py下面按逻辑分段讲解。1. 模拟真实数据集与 golden 值import numpy as np from polygraphy.backend.trt import EngineFromNetwork, NetworkFromOnnxPath, TrtRunner # Pretend that this is a very large dataset. REAL_DATASET [ np.ones((1, 1, 2, 2), dtypenp.float32), np.zeros((1, 1, 2, 2), dtypenp.float32), np.ones((1, 1, 2, 2), dtypenp.float32), np.zeros((1, 1, 2, 2), dtypenp.float32), ] # Definitely real data # For an identity network, the golden output values are the same as the input values. EXPECTED_OUTPUTS REAL_DATASET这里的 4 个样本用于模拟大规模数据集在实际项目中REAL_DATASET可以是任意数量、任意来源文件、迭代器、数据库游标的真实样本。由于模型是恒等identity网络其 golden 输出与输入完全相同因此EXPECTED_OUTPUTS直接复用REAL_DATASET——这段代码的价值在于演示逐样本取数据、逐样本验结果的骨架替换成真实模型后只需把EXPECTED_OUTPUTS换成真实的标签/golden 序列。2. 延迟构建 TensorRT 引擎build_engine EngineFromNetwork(NetworkFromOnnxPath(identity.onnx))NetworkFromOnnxPath负责从 ONNX 文件解析出网络定义EngineFromNetwork负责在首次被调用时即 runner 激活时完成引擎构建。这种惰性加载模式是 Polygraphy 的惯用写法传给 runner 的是一个可调用对象而非已经建好的引擎。3. 用上下文管理器激活 runner 并逐样本验证with TrtRunner(build_engine) as runner: for data, golden in zip(REAL_DATASET, EXPECTED_OUTPUTS): # NOTE: The runner owns the output buffers and is free to reuse them between infer() calls. # Thus, if you want to store results from multiple inferences, you should use copy.deepcopy(). outputs runner.infer(feed_dict{x: data}) assert np.array_equal(outputs[y], golden) print(Validation succeeded!)要点如下with语句即生命周期管理进入with块时TrtRunner自动完成引擎构建与上下文创建activate_impl中创建 execution context、输入/输出缓冲与 CUDA 流见 backend/trt/runner.py退出时自动释放显存与流资源feed_dict是键值映射x是 identity.onnx 的输入张量名outputs[y]是输出张量名缓冲区复用语义关键陷阱runner 拥有输出缓冲区两次infer()之间可能复用同一块内存。如果需要在循环中把多次推理结果保存下来留待后续分析必须对每次输出执行copy.deepcopy()否则之前保存的数组会被后续推理覆盖逐条断言每个样本推理后立即与 golden 值比对np.array_equal要求完全一致恒等模型 float32 全 1/全 0 输入数值上是精确等价的。4. TrtRunner 构造参数速查TrtRunner的构造函数见 backend/trt/runner.py还提供若干高级参数在大规模验证时值得关注参数默认值说明engine必填TensorRT 引擎、执行上下文或返回二者的可调用对象如EngineFromNetwork(...)name自动生成runner 的人类可读名称前缀用于日志标识optimization_profileNone多 profile 引擎时指定激活的优化 profile 索引默认使用第 0 个 profileallocation_strategystatic显存分配策略static预分配足以覆盖所有 profile 的整块内存profile按当前 profile 的最大 shape 分配runtime按当前输入 shape 动态分配weight_streaming_budgetNone权重流式加载的显存预算字节None 或 -2 表示禁用-1 由 TensorRT 自动决定weight_streaming_percentNone常驻 GPU 的权重百分比None 或 100 表示禁用权重流式加载5. 底层推理链路infer() 发生了什么从源码看TrtRunner.infer()最终落到_infer_impl()见 backend/trt/runner.py其核心流程是遍历引擎所有输入张量把feed_dict中的主机数据拷贝到 GPU_get_array_on_gpu并缓存到device_input_buffers若输入 shape 或地址与上下文当前状态不一致调用set_input_shape/set_tensor_address更新shape 没变化时跳过这是循环验证高效的关键为每个输出张量设置输出分配器然后执行context.execute_async_v3(self.stream.ptr)异步推理从输出分配器读取结果构造输出名 - 数组的OrderedDict返回。理解这一链路有助于解释一个常见现象由于输入数据在首次推理后 shape 往往不再变化循环内的后续推理会跳过 shape 设置步骤因此大批量逐样本验证的开销主要集中在数据拷贝与 kernel 执行本身。扩展到其他 Runner2 行代码切换后端由于统一接口的存在验证循环代码与具体后端解耦。例如把验证后端换成 ONNX-Runtime仅需把第 24 行的 import 和 runner 的构造替换为对应实现如OnnxrtRunner第 42-50 行的验证循环保持原样即可。同样的思路适用于 Polygraphy 支持的任何 runner 实现——这正是验证代码只写一遍的价值所在。小结何时用Comparator小样本、多 runner 的输出对比与精度差异分析何时直接用 Runner单 runner 大规模真实数据集 逐样本 golden 比对官方明确推荐后者核心方法论with Runner(...) as runner:管理生命周期feed_dict输入、字典输出逐条断言必要时copy.deepcopy()保存结果可迁移性所有 runner 接口一致后端切换只影响 runner 构造那一两行代码。完整的可运行示例与模型文件位于 tools/Polygraphy/examples/api/02_validating_on_a_datasetPolygraphy 的 Runner、Comparator 完整 API 可进一步阅读 Polygraphy 文档 及其源码目录 tools/Polygraphy/polygraphy。【免费下载链接】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),仅供参考