专栏感知模型算子量化与反量化

模型算子量化与反量化

kotei左文亮2024-11-22
242
0

什么是模型参数量化与反量化?其实量化和反量化并不是什么新知识,我们在对图像做预处理时就用到了量化和反量化。回想一下,我们通常会将一张 uint8 类型、数值范围在 0~255 的图片归一成 float32 类型、数值范围在 0.0~1.0 的张量,这个过程就是反量化。类似地,我们经常将网络输出的范围在 0.0~1.0 之间的张量调整成数值为 0~255、uint8 类型的图片数据,这个过程就是量化。所以量化本质上只是对数值范围的重新调整。

网络模型参数量化是一种减少模型大小和提高推理速度的技术,通过降低模型参数的精度(例如,从32位浮点数减少到8位整数)来实现。

 

参数量化有三个好处:1,减少内存消耗;2,减少推理时间,因为数据类型更简单计算更快;3,减少能源消耗,因为推理一帧,计算量变少了,推理更快了,能源消耗降低了。

反量化操作是为了让量化后的神经元输出与量化前的输出变化不大,不然整型变换后相乘的参数值会与原本的浮点值差很多,对于后面的神经元来说输入相当于就变了,模型准确率自然大打折扣,所以激活值需要经过反量化,从而使得后面的神经元察觉不到输入发生变化,对于整个神经网络来说,输入什么就输出什么,仿佛没有量化操作参与,精度自然能保持。

 

在量化方法中,非对称量化和对称量化是两种常见的量化策略,它们各有特点和应用场景。白话说就是对称量化时0点对齐。

非对称量化不要求量化后的值中零点对应于原始值中的零。这意味着量化操作可以有一个任意的零点,这个零点被映射到量化范围内的某个整数值上。因此,非对称量化使用三个参数(量化最小值、量化最大值和零点)来定义从原始数值到量化数值的映射关系。缺点是执行量化和反量化操作可能需要更多的计算
对称量化要求量化后的值中零点必须对应于原始值中的零,这意味着量化操作的零点固定不变。因此,对称量化通常使用两个参数(量化的最小值和最大值)来定义量化的范围,而这个范围是以零为中心对称的。缺点是很少有参数矩阵是很对称的,无法像非对称量化那样精确地表示数据范围,导致量化误差增加

总结对称量化和非对称量化的优点缺点

对称量化的优点:

没有偏移量,可以降低计算量

分布在正负半轴的权值数值均可被充分利用,具有更高的利用率;

对于深度学习模型,可以使用int8类型的乘法指令进行计算,加快运算速度;

能够有效的缓解权值分布在不同范围内的问题。

对称量化的缺点:

对于数据分布在0点附近的情况,量化的位数可能不够;

数据分布的范围过于分散,如果缺乏优秀的统计方法和规律,会导致量化效果不佳。

非对称量化的优点:

通过偏移量可以保证量化数据分布在非负数范围内,可以使得分辨率更高;

适合数据分布范围比较集中的情况。

非对称量化的缺点:

对于偏移量的计算需要额外的存储空间,增加了内存占用;

偏移量计算需要加减运算,会增加运算的复杂度;

对于深度学习模型,要使用int8类型的乘法指令进行计算,需要进行额外的偏置操作,增加了运算量。

 

 

其中地平线的工具链PTQ里hb_model_modifier工具的输出内容有可供候选的可删除节点(即模型中的位于输入输出位置的所有Transpose、Quantize、Dequantize、DequantizeFilter、Cast、Reshape、Softmax节点)。

其中Quantize节点用于将模型float类型的输入数据量化至int8类型,其计算公式如下:

qx = clamp(round(x / scale) + zero_point, -128, 127)

  • round(x) 实现浮点数的四舍五入。
  • clamp(x) 函数实现将数据钳位在-128~127之间的整数数值。
  • scale 为量化比例因子。
  • zero_point 为非对称量化零点偏移值,对称量化时 zero_point = 0 。

 

C++的参考实现如下:

static inline float32_t _round(float32_t const input) {

std::fesetround(FE_TONEAREST);

float32_t const result{std::nearbyintf(input)};

return result;

}

static inline int8_t int_quantize(float32_t value, float32_t const scale) {

value = _round(value / scale);

value = std::min(std::max(value, -128.0f), 127.0f);

return static_cast(value);

}

Dequantize节点则用于将模型int8或int32类型的输出数据反量化回float或double类型,其计算公式如下:

deqx = (x - zero_point) * scale

C++的参考实现如下:

static_castfloat>(value) * scale

目前地平线的BPU只支持对称量化。

感知
技术深度解析
评论0
0/1000