TensorRT INT8 校准器指南:Polygraphy Calibrator 的配置参数与源码实现解析
【免费下载链接】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
Polygraphy 的polygraphy.backend.trt.Calibrator为 TensorRT 的 INT8 量化校准提供了一套简洁、可复用的封装:只需提供一个数据加载器,即可自动为 TensorRT 网络生成动态范围(dynamic range)并构建 INT8 引擎。本文以仓库中的 calibrator.rst 文档所对应的 calibrator.py 源码为主线,系统讲解 Calibrator 的每个参数、底层执行流程,以及与CreateConfig、DataLoader的配合方式,帮助读者在 TensorRT INT8 部署中快速落地。
Calibrator 是什么:从 RST 文档到工厂函数
tools/Polygraphy/docs/backend/trt/calibrator.rst是一份 Sphinx autodoc 风格文档,正文通过automodule:: polygraphy.backend.trt.calibrator指令直接展开该模块的全部公开 API。因此,这份文档的技术主体就是 calibrator.py 中由@mod.export()导出的Calibrator(...)工厂函数。
在 TensorRT 中,INT8 推理需要为网络中的每个张量确定数值范围(dynamic range),而校准器(calibrator)的作用就是喂入有代表性的数据,让 TensorRT 依据这些数据的实际分布统计出合适的缩放因子。Polygraphy 的Calibrator工厂接收一个数据加载器,动态生成一个继承自 TensorRT 原生校准器基类(默认为trt.IInt8EntropyCalibrator2)的实例,把“喂数据”这件事完全托管给 Python 端的数据加载器。
参数详解:工厂函数的完整签名
Calibrator的完整签名如下(源码见 calibrator.py):
Calibrator( data_loader, cache=None, BaseClass=None, batch_size=None, quantile=None, regression_cutoff=None, algo=None, )各参数的作用与默认值如下表所示:
| 参数 | 类型 | 默认值 | 作用与约束 |
|---|---|---|---|
data_loader | Sequence[OrderedDict[str, Union[numpy.ndarray, DeviceView, torch.Tensor, int]]] | 必填 | 可迭代对象或生成器,每次 yield 一个“输入名 → 输入数据”的映射(feed_dict)。支持 NumPy 数组、PolygraphyDeviceView、PyTorch 张量或 GPU 指针(int)。校准批次数由数据加载器供给的条目数决定 |
cache | str或 file-like | 不保存 | 校准缓存(calibration cache)的保存/加载路径或文件对象。下次构建引擎时可直接复用,跳过重新校准 |
BaseClass | type | trt.IInt8EntropyCalibrator2 | 要继承的 TensorRT 校准器基类。可选IInt8EntropyCalibrator、IInt8EntropyCalibrator2、IInt8MinMaxCalibrator、IInt8LegacyCalibrator等 |
batch_size | int | 1 | 已弃用。数据加载器每批提供的数据条数,仅用于get_batch_size()返回值 |
quantile | float | 0.5 | 仅对trt.IInt8LegacyCalibrator生效,指定分位数 |
regression_cutoff | float | 0.5 | 仅对trt.IInt8LegacyCalibrator生效,指定回归截断值 |
algo | trt.CalibrationAlgoType | MINMAX_CALIBRATION(当BaseClass为IInt8Calibrator时实际为ENTROPY_CALIBRATION_2) | 仅对trt.IInt8Calibrator生效,指定校准算法 |
关于algo参数有一个值得注意的细节:在__init__文档字符串中标注的默认值是trt.CalibrationAlgoType.MINMAX_CALIBRATION,但在 IInt8Calibrator 分支 的get_algorithm()方法中,实际回退值写的是ENTROPY_CALIBRATION_2,即默认继承IInt8EntropyCalibrator2时走的是熵校准路径。quantile与regression_cutoff则由 IInt8LegacyCalibrator 分支 的get_quantile()/get_regression_cutoff()返回,二者默认值均为 0.5。
数据加载器:给校准器“喂数据”的四种姿势
data_loader是唯一必填参数。它可以是任意迭代器或生成器,每次迭代返回一个 feed_dict。源码 calibrator.py 的_get_batch_impl会对每份数据做如下处理:
- 从数据加载器迭代器中取下一批数据,同时累计
self.num_batches; - 若数据加载器已耗尽(
StopIteration),则返回None通知 TensorRT 校准结束;若第一轮就没有任何数据,会触发G_LOGGER.critical报错并提示可能原因(数据加载器本身无数据,或生成器被多次复用而无法回卷); - 若已设置
input_metadata,调用base_util.check_inputs校验数据形状与类型; - 按 TensorRT 传入的输入名顺序,将每份数据转为 GPU 指针:
int(GPU 指针)直接使用,其余类型通过trt_util._get_array_on_gpu搬运到设备端并缓存在self.device_buffers中。
因此,数据既可以是 CPU 上的 NumPy 数组,也可以是已经在 GPU 上的DeviceView、PyTorch 张量或裸指针。官方示例 04_int8_calibration_in_tensorrt/example.py 给出了最朴素的写法:
def calib_data(): for _ in range(4): yield {"x": np.ones(shape=(1, 1, 2, 2), dtype=np.float32)}如果不想手写数据加载器,Polygraphy 内置了 DataLoader,可基于种子与范围自动生成随机输入。其核心参数包括:
seed:随机数种子,默认constants.DEFAULT_SEED;同一索引保证生成同一份数据(__getitem__中使用seed + index);iterations:供给数据的迭代次数,默认 1;input_metadata:输入名到形状/类型的映射,用于确定动态维度的具体形状与数据类型;val_range:数值生成范围,默认(0.0, 1.0);可用字典按输入名分别指定,空字符串""作为默认范围的键;data_loader_backend_module:生成数据的后端模块,支持"numpy"与"torch",默认"numpy"。
注意:内置DataLoader需要依赖input_metadata才能生成数据,而这正是 Calibrator 的set_input_metadata机制要解决的问题。
与 TensorRT API 的对接:输入元数据与类型强制
input_metadata 的传递链
当不清楚模型输入细节时,可以在自定义数据加载器中访问input_metadata属性——Polygraphy 的CreateConfig、EngineFromNetwork等 API 会自动为校准器注入该元数据。底层实现位于 util.py 的 try_setup_polygraphy_calibrator:
- 从
config.int8_calibrator取出校准器,通过is_polygraphy_calibrator标记判断是否为 Polygraphy 校准器(该标记在 calibrator.py 中设置); - 从
config.get_calibration_profile()获取校准 profile,再通过get_input_metadata_from_network(network, calib_profile, force_opt_shapes=True)提取输入元数据; - 调用
calibrator.set_input_metadata(input_metadata)完成注入。
值得注意的是,TensorRT 目前只支持校准 profile 的 OPT 形状,因此元数据强制使用优化形状。若网络没有设置校准 profile,则会输出警告,提示手动调用calibrator.set_input_metadata()。
非 float32 输入的自动覆盖
set_input_metadata(calibrator.py)会遍历输入元数据:TensorRT 要求非索引(index)类校准输入以 float32 提供,因此当某个输入的 dtype 不属于FLOAT32、INT32、INT64、BOOL时,会打印警告并把元数据中的类型覆盖为FLOAT32,同时提示自定义数据加载器务必为该输入返回 float32 张量。这些覆盖后的元数据也会被写入self.data_loader.input_metadata,供内置DataLoader使用。
校准缓存:让第二次构建引擎“免校准”
cache参数使校准结果可复用。相关方法在 calibrator.py:
read_calibration_cache():TensorRT 在构建时调用。若cache未设置或文件为空返回None;读取失败会记录错误并回退为重新校准。每次reset()会把self.cache_contents置回None,确保重新校准时会再次检查缓存;write_calibration_cache(cache):TensorRT 校准完成后调用。内容以cache.tobytes()形式保存在内存中,并在cache非空时通过util.save_file写入磁盘;写入失败仅记录错误,不影响引擎构建。
利用缓存后,同样的网络第二次构建可以直接跳过校准过程,显著缩短 CI 或反复构建场景下的构建时间。官方示例 04_int8_calibration_in_tensorrt/example.py 即传入cache="identity-calib.cache"。
完整实战:构建 INT8 引擎的端到端流程
将校准器接入引擎构建的完整示例同样来自 04_int8_calibration_in_tensorrt/example.py:
from polygraphy.backend.trt import Calibrator, CreateConfig, EngineFromNetwork, NetworkFromOnnxPath, TrtRunner calibrator = Calibrator(data_loader=calib_data(), cache="identity-calib.cache") build_engine = EngineFromNetwork( NetworkFromOnnxPath("identity.onnx"), config=CreateConfig(int8=True, calibrator=calibrator), ) with G_LOGGER.verbosity(G_LOGGER.VERBOSE), TrtRunner(build_engine) as runner: outputs = runner.infer({"x": np.ones(shape=(1, 1, 2, 2), dtype=np.float32)})关键点在于CreateConfig(int8=True, calibrator=calibrator):仅仅提供校准器还不够,必须同时开启 INT8 模式。在 config.py 中可以看到约束逻辑:
- 提供了校准器但未开启 int8 模式时,会输出警告“A calibrator was provided to
CreateConfig, but int8 mode was not enabled”; - 使用
USE_TENSORRT_RTX=1(RTX 校准模式)时不支持自定义校准器,会直接critical报错; - 构建时把
config.int8_calibrator设为该校准器; - 若网络没有显式精度且未提供校准器,会报错提示需要设置 dynamic range 或提供校准器才能使用 int8 模式。
如果不想与 Polygraphy 的 loader 体系绑定,也可以在原生 TensorRT 代码中直接使用:config.int8_calibrator = calibrator同样成立,因为该对象本身就是一个合法的 TensorRT 校准器实例。
生命周期管理:reset、free 与上下文管理器
校准器实例还提供了几个与生命周期相关的方法(calibrator.py):
reset():清空之前校准缓存的 dynamic range,并尝试回卷数据加载器(self.data_loader_iter = iter(self.data_loader))。注意生成器无法回卷——若同一校准器需要复用于多个网络,数据加载器必须是可重复迭代的(如 list);free():释放device_buffers中缓存的所有 GPU 缓冲;__enter__/__exit__:支持with上下文管理,退出时自动调用free()释放设备内存。
此外,__init__中强制调用BaseClass.__init__(self)有一个值得注意的实现细节:注释明确说明“对于任何 trampoline 类,必须显式初始化父类,否则会莫名 segfault”,这也是 Polygraphy 动态生成校准器子类时保证稳定性的关键一步。
小结
PolygraphyCalibrator的价值在于把 TensorRT 原生校准器的样板代码(get_batch、read_calibration_cache、write_calibration_cache等)压缩为一个工厂函数 + 一个数据加载器:数据侧支持 NumPy、DeviceView、PyTorch 张量与 GPU 指针四种形态,结果侧支持缓存复用,精度侧支持通过BaseClass切换熵校准、MinMax 校准与 Legacy 校准等不同算法。配合CreateConfig(int8=True, calibrator=...)与内置DataLoader,可以在极少量代码内完成 INT8 引擎的校准与构建,是 TensorRT INT8 部署中值得优先采用的方案。
【免费下载链接】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),仅供参考