TensorRT 使用混合精度
五种精度类型
kFLOAT //!< FP32 format.
kHALF //!< FP16 format.
kINT8 //!< INT8 format.
kINT32 //!< INT32 format.
kTF32 //!< TF32 format.
TF32精度
TF32 Tensor Cores 可以使用 FP32 加速网络,通常不会损失准确性。 对于需要高动态范围权重或激活的模型,它比 FP16 更健壮。
在构建引擎时设置环境变量 NVIDIA_TF32_OVERRIDE=0 将禁用 TF32
//如果设备支持TF32精度,则使用TF32精度
if(builder->platformHasTf32())
{
builder->setTf32Mode(true);//不确定是否对,先这么写
builder->setTf32Mode(dataType == DataType::kTF32);//不确定是否对,先这么写
};
//step6:创建config并设置最大batchsize和最大工作空间
IBuilderConfig * config = builder->createBuilderConfig();
//停用TF32指令
config->clearFlag(BuilderFlag::kTF32);
//也可通过设置环境变量禁用TF32
NVIDIA_TF32_OVERRIDE=0
此外可以对特定的网络层指定精度,这个是通用方法
//指定layer层精度是INT8
layer->setPrecision(nvinfer1::DataType::kINT8)
//指定输出层精度是FP32
layer->setOutputType(out_tensor_index, nvinfer1::DataType::kFLOAT)
FP16精度的设置
fp16只需略微修改代码,明显提高速度,基本不影响精度, TensorRT3.0的官方文档上说,如果只是使用 float 16 的数据精度代替 float-32 , 实际上并不会有多大的性能提升。真正提升性能的是 half2mode ,使用16位交叉存存储方式的模式。在 batchsize 大于 1的情况下,这种模式的运行速度是最快的
//如果设备支持FP16精度,则使用FP16精度
if(builder->platformHasFastFp16())
{
builder->setFp16Mode(true);
builder->setFp16Mode(dataType == DataType::kHALF);
};
//step6:创建config并设置最大batchsize和最大工作空间
IBuilderConfig * config = builder->createBuilderConfig();
//设置构建器标志可启用 FP16 精度推理。
config->setFlag(BuilderFlag::kFP16);
//强制使用 FP16 位精度:
config->setFlag(BuilderFlag::kSTRICT_TYPES)//这可能没有最佳性能。 建议仅出于调试目的使用此标志。
INT8精度的设置
精度并没有损失太多,速度提升很大,尤其是当 batch_size 大于1时,提升更明显
TensorRT 的INT8模式只支持计算能力为6.1以上的GPU
注意:parser解析模型的时候传进去的dataType,使用INT8 inference的话,这个地方传进去的是kFLOAT,也就是 FP32,这是因为INT8 需要先用FP32的精度来确定转换系数,TensorRT自己会在内部转换成INT8。这个看起来就跟使用FP32是一样的流程,INT8 MODE inference的输入和输出都是 FP32的。
//如果设备支持INT8精度,则使用INT8精度
if(builder->platformHasFastInt8())
{
builder->setInt8Mode(true);
builder->setInt8Mode(dataType == DataType::kINT8);
builder->setInt8Calibrator(calibrator);//校准器接口
};
//step6:创建config并设置最大batchsize和最大工作空间
IBuilderConfig * config = builder->createBuilderConfig();
//设置构建器标志可启用 INT8 精度推理。
config->setFlag(BuilderFlag::kINT8);
//强制使用INT8位精度:
config->setFlag(BuilderFlag::kSTRICT_TYPES)//这可能没有最佳性能。 建议仅出于调试目的使用此标志。
//配置校准器
config->setInt8Calibrator(calibrator.get());
TensorRT 提供了多种 IInt8Calibrator
校准器变体:
//这是推荐的校准器,是 DLA 所必需的。 默认情况下,校准发生在图层融合之前。 推荐用于基于 CNN 的网络。
IEntropyCalibratorV2
//这个校准器似乎更适合 NLP 任务。 默认情况下,校准发生在图层融合之前。 推荐用于 NVIDIA BERT(谷歌官方实现的优化版本)等网络
IMinMaxCalibrator
//这是传统的熵校准器。这比传统的校准器更简单,并且产生更好的结果。 默认情况下,在层融合之后进行校准。
IEntropyCalibrator
//该校准器与 TensorRT 2.0 EA 兼容。 该校准器需要用户参数化,并在其他校准器产生不良结果时作为备用选项提供。 默认情况下,在层融合之后进行校准。
ILegacyCalibrator
int8量化流程
典型的工作流还是直接使用 GTC2017 PPT 原文说法吧:
-
You will need:
- Model trained in FP32.
- Calibration dataset.
-
TensorRT will:
-
Run inference in FP32 on calibration dataset.
-
Collect required statistics(直方图).
-
Run calibration algorithm → optimal scaling factors.
-
Quantize FP32 weights → INT8.
-
根据直方图和参数生成校准表
CalibrationTable
,根据网络定义和校准表生成int8 engine
-
结论 Conclusion
- 对称的,不饱和的线性量化,会导致精度损失较大;
- weights权值的int8量化使用的是不饱和的方式,对activation激活值使用的是饱和的量化方式
- 通过最小化 (相对熵)KL散度来选择 饱和量化中的 阈值 |T|;
- FP32完全可以降低为INT8推理,精度几乎持平,速度有很大提升。