4、量化精度测试:INT8/FP16量化、校准数据集构建、精度损失评估指标
量化,说白了就是用更少的比特数去表示模型的参数和激活值。你想想看,一个FP32的模型,动辄几百兆,放到嵌入式设备上,内存先炸了。我最早做量化的时候,心里也打鼓——这精度能保住吗?后来踩了无数坑,才摸清楚这里面的门道。
这一章,我们就来聊聊量化精度测试。我会把INT8/FP16量化、校准数据集怎么构建、以及精度损失怎么评估,掰开揉碎了讲清楚。
4.1 INT8与FP16量化:两种主流方案
量化方案有很多,但嵌入式设备上最常用的就是INT8和FP16。为什么?因为硬件支持好,工具链成熟。
4.1.1 FP16量化
FP16,也叫半精度浮点。它用16位来表示一个数,相比FP32,内存和带宽直接砍半。精度损失呢?其实很小。我在项目中测试过,大部分模型FP16推理,精度损失在0.1%以内,肉眼根本看不出来。
FP16量化的好处是——几乎不需要校准。你直接把模型权重从FP32转成FP16,然后跑推理就行了。硬件如果支持FP16计算,速度提升也很明显。
4.1.2 INT8量化
INT8就复杂多了。它用8位整数来表示一个数,动态范围只有256个值。相比FP32的40亿个值,这简直是降维打击。所以,INT8量化必须做校准。
INT8量化的核心是——找到合适的缩放因子(scale)和零点(zero point)。说白了,就是把FP32的数值范围映射到INT8的0~255(或-128~127)上。
映射方式有两种:
- 对称量化: 零点固定为0,只计算scale。适合权重分布对称的情况。
- 非对称量化: 零点可以偏移,适合激活值分布不对称的情况(比如ReLU后的输出全是非负数)。
我建议你,权重用对称量化,激活值用非对称量化。这是业界主流做法,我在多个项目里验证过,效果最稳。
4.2 校准数据集构建:关键中的关键
INT8量化需要校准数据集,用来统计每一层激活值的分布范围。校准数据集的质量,直接决定量化精度。
校准数据集怎么构建?我总结了几条原则:
- 代表性: 校准数据必须来自真实应用场景。比如你做人脸识别,校准集里就不能全是风景图。
- 多样性: 覆盖各种光照、角度、背景。我见过有人只用100张图做校准,结果模型在暗光下精度暴跌。
- 数量适中: 一般500~2000张就够了。太多反而过拟合,太少统计不准。
- 避免重复: 校准集和验证集不能有重叠。否则你测出来的精度是假的。
校准数据集的大小,我一般这样选:
| 模型复杂度 | 校准集数量 | 说明 |
|---|---|---|
| 轻量模型(MobileNet等) | 500~1000张 | 层数少,统计量少 |
| 中等模型(ResNet50等) | 1000~2000张 | 需要更多数据覆盖各层分布 |
| 大模型(YOLOv5等) | 2000~5000张 | 层数多,激活值分布复杂 |
核心要点: 校准数据集不是越大越好。关键是“代表性”。我见过一个项目,用了10000张图做校准,结果精度还不如2000张的——因为那10000张图里有一半是重复的。
4.3 精度损失评估指标:余弦相似度、Top-1/Top-5
量化完了,怎么知道精度损失了多少?三个指标最常用:余弦相似度、Top-1准确率、Top-5准确率。
4.3.1 余弦相似度
余弦相似度衡量的是——量化前后,模型输出的特征向量在方向上的相似程度。取值范围是-1到1,越接近1越好。
计算公式很简单:
cosine_similarity = (A · B) / (||A|| * ||B||)
其中A是FP32模型的输出,B是量化模型的输出。
我一般要求余弦相似度在0.99以上。如果低于0.95,说明量化精度损失严重,需要重新做校准或调整量化参数。
4.3.2 Top-1准确率
Top-1就是模型预测的最可能类别,跟真实标签是否一致。这是最直观的指标。
量化后Top-1下降多少算正常?我一般这样判断:
- FP16量化: 下降不超过0.1%
- INT8量化(分类模型): 下降不超过1%
- INT8量化(检测模型): 下降不超过2%
当然,这只是经验值。具体要看你的模型和任务。我做过一个OCR模型,INT8量化后Top-1只掉了0.3%,但另一个语义分割模型掉了3%。
4.3.3 Top-5准确率
Top-5是模型预测的前5个类别中,是否包含真实标签。这个指标在分类任务中很常用,尤其是类别数很多的时候(比如ImageNet有1000类)。
Top-5对量化精度的容忍度更高。一般来说,INT8量化后Top-5下降不超过0.5%就算合格。
为什么会这样?因为Top-5给了模型更多“容错空间”。即使量化让某个类别的置信度降低了,只要它还在前5名里,就算正确。
4.4 实战:量化精度测试流程
好了,理论讲完了。我们来看看实际怎么做。我一般按这个流程走:
- 准备校准集: 从训练集中随机抽取1000张图,确保覆盖各类场景。
- 运行校准: 用工具(比如TensorRT的INT8校准器)统计每层激活值的分布。
- 导出量化模型: 生成INT8或FP16的模型文件。
- 跑验证集: 用验证集(至少5000张)分别跑FP32模型和量化模型。
- 计算指标: 算余弦相似度、Top-1、Top-5。
- 对比分析: 如果精度损失超标,检查校准集质量或调整量化参数。
这里有一个代码片段,展示如何计算余弦相似度:
import numpy as np
def cosine_similarity(fp32_output, quant_output):
"""
计算两个模型输出的余弦相似度
fp32_output: FP32模型的输出,shape为(N, C)
quant_output: 量化模型的输出,shape为(N, C)
"""
# 归一化
fp32_norm = fp32_output / np.linalg.norm(fp32_output, axis=1, keepdims=True)
quant_norm = quant_output / np.linalg.norm(quant_output, axis=1, keepdims=True)
# 计算余弦相似度
cos_sim = np.sum(fp32_norm * quant_norm, axis=1)
# 返回平均值
return np.mean(cos_sim)
# 示例用法
fp32_out = np.random.randn(100, 10) # 100个样本,10个类别
quant_out = fp32_out * 0.98 + 0.02 * np.random.randn(100, 10) # 模拟量化误差
sim = cosine_similarity(fp32_out, quant_out)
print(f"余弦相似度: {sim:.4f}")
4.5 避坑指南
最后,分享几个我踩过的坑:
- 校准集和验证集混用: 我曾经犯过这个错,校准集和验证集有30%重叠,结果量化精度测出来虚高。后来重新构建了独立的验证集,才发现真实精度掉了1.5%。
- 忽略预处理差异: 量化模型的预处理必须和FP32模型完全一致。包括归一化参数、图像尺寸、通道顺序。差一点都不行。
- 只看Top-1不看余弦相似度: Top-1只能反映最终分类结果,但余弦相似度能反映特征空间的整体偏移。我建议两个都看,互相印证。
- 校准集数量太少: 我见过有人只用50张图做校准,结果量化后模型在某个类别上精度直接归零。后来增加到500张,问题就解决了。
嗯,量化精度测试就聊到这里。下一章我们会讲推理性能测试,包括延迟、吞吐量、内存占用这些指标。到时候见。