TensorRT量化-FP16和INT8

FP16

  • FP16 :FP32 是指 Full Precise Float 32 ,FP 16 就是 float 16。更省内存空间,更节约推理时间。

  • Half2Mode :tensorRT 的一种执行模式(execution mode ),这种模式下 图片上相邻区域的 tensor 是 以16位 交叉存储的方式 存在的。而且在 batchsize 大于 1的情况下,这种模式的运行速度是最快的。(Half2Mode is an execution mode where internal tensors interleave 16-bits from
    adjacent pairs of images, and is the fastest mode of operation for batch sizes greater
    than one.

    这是计算机组成原理中涉及到存储方式的选择,不是很懂。大概是下图这样的:

    以下分别是 2D和3D情况:
    在这里插入图片描述
    在这里插入图片描述

    参考这个 顺序存储和交叉存储 ,这样做可以提升存储器带宽。更多详细内容参考文末参考资料。

2 具体做法

2.1 配置 builder

TensorRT3.0的官方文档上说,如果只是使用 float 16 的数据精度代替 float-32 , 实际上并不会有多大的性能提升。真正提升性能的是 half2mode ,也就是上述使用了交叉存存储方式的模式。

如何使用half2mode ?

  • 首先 使用float 16 精度的数据 来初始化 network 对象,主要做法就是 在调用NvCaffeParser 工具解析 caffe模型时,使用 DataType::kHALF 参数,如下:

    const IBlobNameToTensor *blobNameToTensor = 
    parser->parse(locateFile(deployFile).c_str(), 
    locateFile(modelFile).c_str(), 			
    *network, 				 
    DataType::kHALF);
    
  • 配置builder 使用 half2mode ,这个很简单,就一个语句就完成了:

    builder->setHalf2Mode(true);
    

int8

定义网络时,注意这个地方传进去的dataType,如果使用FP16 inference 则传进去的是FP16,也就是kHALF;但如果是使用INT8 inference的话,这个地方传进去的是kFLOAT,也就是 FP32,这是因为INT8 需要先用FP32的精度来确定转换系数,TensorRT自己会在内部转换成INT8。

const IBlobNameToTensor* blobNameToTensor =    
parser->parse(locateFile(deployFile).c_str(),  
locateFile(modelFile).c_str(),   
*network,                  
DataType::kFLOAT);

这个看起来就跟使用FP32是一样的流程,INT8 MODE inference的输入和输出都是 FP32的。

配置build使用int8,

//设置int8模式
builder->setInt8Mode(dataType == DataType::kINT8);
//s设置int8标定
builder->setInt8Calibrator(calibrator);
//brief: Build a CUDA engine from a network definition.
//实际过程在buildCudaEngine时完成
engine = builder->buildCudaEngine(*network);

int8标定
官方文档关于量化的叙述:

INT8 calibration provides an alternative to generate per activation tensor the dynamic range. This methods can be categorized as post training technique to generate the appropriate quantization scale. The process of determining these scale factors is called calibration, and requires the application to pass batches of representative input for the network (typically batches from the training set.) Experiments indicate that about 500 images is sufficient for calibrating ImageNet classification networks.

int8量化的调用接口为 IInt8EntropyCalibrator

当build int8 engine时,执行以下步骤:
Builds a 32-bit engine, runs it on the calibration set, and records a histogram for each tensor of the distribution of activation values.
Builds a calibration table from the histograms.
Builds the INT8 engine from the calibration table and the network definition.

  • build一个32位engine,在标定集中运行,记录每一个tensor的激活值分布的直方图
  • 根据直方图创建一个标定表
  • 根据标定表和网络定义生成int8 engine

标定表可以缓存。当多次build同一个网络时,标定表缓存是非常必要的。当第一次build时,生成标定表,之后build时,直接读取标定表,而不用再次标定。

build中配置int8标定
builder->setInt8Calibrator(calibrator);

使用 writeCalibrationCache() and readCalibrationCache() 函数缓存标定表。

参考

TensorRT(4)-Profiling and 16-bit:Inference https://arleyzhang.github.io/articles/fda11be6/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章