OpenPPL / ppq

PPL Quantization Tool (PPQ) is a powerful offline neural network quantization tool.
Apache License 2.0
1.56k stars 236 forks source link

调度部分算子至FP32时,生成engine失败 #530

Open zhjw0927 opened 11 months ago

zhjw0927 commented 11 months ago

大佬:

我使用PPQ量化模型时,根据逐层误差的提示将误差较大的层调度至非量化平台上,生成了动态范围文件。 在构建Engine时,使用setDynamicRange API去加载动态范围,和使用layer->setPrecision(nvinfer1::DataType::kHALF) 将调度至非量化平台上的算子设置成FP16精度。 结果显示 Internal Error (Assertion nbPTQScales == nbChannels failed.)。

下图中左侧三个Conv被调度至了非量化平台上(PPQ阶段),和使用TensorRT API设置为FP16精度(Engine阶段)。我尝试理解上述报错的原因,第一可能是因为左侧三个Conv为FP16精度,所以其输入和输出都为FP16精度,最右侧Conv为INT8精度,其输入和输出都为INT8精度,四个Conv的输出存在两种类型,所以在Concat算子内发生错误;第二可能是因为四个Conv在进行横向融合时,因为精度不同所以发生了错误,但这种情况下,TensorRT在融图时,不会先考虑参与融合的算子的精度吗?图融合 和 INT8量化在构建Engine时是哪一个先被执行呀?

麻烦大佬帮忙指导下。

Screenshot from 2023-12-27 09-41-56

下图中的Conv算子在PPQ阶段被调度至了非量化平台上,在生成Engine时被API显式设置FP16 层精度。Sigmoid和Mul算子是量化状态。在构建Engine时,Conv的输入和输出都是FP16精度,该输出在输入到Sigmoid和Mul算子前会被转化成INT8精度,执行INT8计算。 麻烦大佬帮忙指导下,我的理解有没有错误。

Screenshot from 2023-12-27 09-49-08

感谢。

ZhangZhiPku commented 11 months ago

由于你调用了 layer->setPrecision(nvinfer1::DataType::kHALF) 这个函数,这种显示的调用将在图融合发生之前对图进行修改,因此你的精度调整逻辑优于图融合会首先发生。TRT的错误 Internal Error (Assertion nbPTQScales == nbChannels failed.),与 TRT自身的逻辑有关,我不能提供更进一步的信息帮助你debug。 但当你存在一个concat上面接了多个不同的算子的时候,你最好将所有输入算子统一调度,否则会导致推理框架难以处理。 当你的conv-sigmoid-mul结构只调度了conv到浮点时,你的理解是正确的,sigmoid与mul仍将以int8精度执行。

zhjw0927 commented 11 months ago

感谢大佬指导。

我查阅官方文档时,发现TRT说明隐式量化时,仅针对性能进行优化,对在哪里使用INT的控制非常微弱,即使显示设置某一层的精度,也会在图融合阶段丢失其必须被执行INT的信息。上述TRT的报错,感觉像是PTQ仅提供了最右侧卷积激活值的scale与四个卷积融合后的激活值尺度不对齐。好吧,我也不清楚,尝试去理解黑盒。。。

我再问下conv-sigmoid-mul 这个结构,假设Sigmoid层被调度到了浮点,其余两个是量化状态。我观察到PPQ生成的量化范围JSON文件中没有Conv层输出到Sigmoid层那一条支路的scale,那么Conv层输出INT8在进入Sigmoid层之前是怎样转化到FLOAT的呢? 不是很理解一个INT算子后连接FLOAT算子,PPQ未提供INT算子输出的scale,中间过程数据类型的转换是如何进行的。

还请大佬再次指导下,谢谢。