第2章:模型量化基础——什么是量化、量化类型(对称/非对称)、量化精度(INT8/FP16)的选择
各位同学,咱们今天聊聊量化。说实话,我刚入行那会儿,觉得量化就是个「压缩模型」的黑魔法。后来踩了不少坑才明白——量化不是玄学,是数学。
你想想看,一个训练好的模型,参数都是FP32的浮点数。跑在服务器上没问题,但你要把它塞进一个只有几MB内存的嵌入式设备里?那可就难了。量化,说白了就是用更少的比特去表示这些参数。
2.1 什么是量化?
量化就是把连续的浮点数,映射到离散的整数空间。举个例子:
原始值: 0.0, 0.1, 0.2, ..., 1.0
量化后: 0, 1, 2, ..., 255
嗯,就是这么简单粗暴。但这里有个关键问题——精度损失。我在项目中遇到过,一个模型量化后精度掉了5个点,排查了半天才发现是某个层的激活值分布太宽了。
核心公式:
量化值 = round(原始值 / 缩放因子) + 零点偏移
反量化:原始值 ≈ (量化值 - 零点偏移) × 缩放因子
缩放因子和零点偏移,就是量化过程中最重要的两个参数。它们决定了你的映射关系。
2.2 量化类型:对称 vs 非对称
这里我要重点讲一下。很多新手搞不清楚对称量化和非对称量化的区别。我建议你记住一句话:对称量化省计算,非对称量化省精度。
对称量化
对称量化,零点偏移固定为0。也就是说,浮点数的0映射到整数的0。这样做的好处是计算简单,乘法运算时不需要处理偏移量。
// 对称量化示例
scale = max(|min_val|, |max_val|) / 127
quantized_value = round(original_value / scale)
但问题来了——如果你的数据分布不对称,比如ReLU后的激活值全是正数,那对称量化就会浪费一半的表示范围。我曾经在一个语音模型上吃过这个亏,量化后精度直接崩了。
非对称量化
非对称量化允许零点偏移不为0。它能更好地匹配数据的实际分布。
// 非对称量化示例
scale = (max_val - min_val) / 255
zero_point = round(-min_val / scale)
quantized_value = round(original_value / scale) + zero_point
说白了,非对称量化就是「量体裁衣」。你的数据分布什么样,它就怎么映射。代价是计算时多了一个偏移量,硬件实现稍微复杂一点。
我的经验:
权重一般用对称量化,因为权重分布通常接近0对称。激活值建议用非对称量化,尤其是ReLU后的激活值全是正数,非对称量化能多保留一倍精度。
2.3 量化精度:INT8 vs FP16
选INT8还是FP16?这个问题我经常被问到。我的回答是:看你的硬件和精度要求。
| 特性 | INT8 | FP16 |
|---|---|---|
| 存储大小 | 8比特 | 16比特 |
| 表示范围 | -128 ~ 127 | ±65504 |
| 精度损失 | 较大 | 较小 |
| 硬件支持 | 广泛(NPU/TPU) | GPU友好 |
| 推理速度 | 快(整数运算) | 中等 |
INT8的优势在于存储和速度。一个100MB的模型,量化到INT8就变成25MB。而且整数运算在嵌入式设备上比浮点快得多。我做过一个测试,在Cortex-M4上,INT8推理速度是FP32的4倍。
FP16的好处是精度损失小。如果你的模型对精度特别敏感,比如医疗影像或自动驾驶,FP16是更安全的选择。但要注意,很多嵌入式设备不支持FP16硬件加速,跑起来反而比INT8慢。
避坑指南:
我曾经在一个项目里,为了追求极致压缩,把所有层都量化到INT8。结果模型在边缘场景下频繁出错。后来我学乖了——敏感层保留FP16,非敏感层用INT8。这种混合精度量化,既保住了精度,又控制了模型大小。
2.4 如何选择?
嗯,这里我给大家一个实用的决策流程:
- 先看硬件:你的芯片支持什么?不支持就别硬上。
- 再看精度要求:允许掉几个点?如果只能掉1%以内,建议FP16或混合精度。
- 最后看存储限制:Flash只有256KB?那没得选,INT8走起。
我个人习惯是:先用INT8量化跑一遍,看精度损失。如果损失超过2%,再尝试混合精度。如果还不行,才考虑FP16。你想想看,能省则省嘛。
总结一下:
- 量化就是把FP32映射到低比特空间
- 对称量化省计算,非对称量化省精度
- INT8省存储快推理,FP16保精度
- 混合精度往往是性价比最高的方案
好了,这一章就到这里。下一章咱们聊聊量化感知训练(QAT),那才是真正让量化不掉精度的关键。记得动手试试,光看是学不会的。