3、校准数据集:校准数据集的作用、如何构建校准数据集、数据量多少合适
说到PTQ,很多人第一反应是“找个数据集跑一遍就完事了”。
嗯,我以前也这么想。直到有一次,我用ImageNet的验证集做校准,结果量化后的模型在某个特定场景下直接崩了——输出全是NaN。
排查了半天,才发现是校准数据里缺少了那种“极端分布”的样本。
所以今天咱们好好聊聊校准数据集。
说白了,它就是量化过程中用来“摸清模型脾气”的那一小批数据。
3.1 校准数据集到底在干什么?
你想想看,模型原本是用FP32算的,权重和激活值都是高精度浮点数。
现在要把它压缩到INT8,相当于把一张高清照片压缩成低分辨率版本。
问题是——压缩的时候,哪些细节可以丢?哪些必须保留?
校准数据集就是用来回答这个问题的。
它通过前向传播,统计每一层的激活值分布。然后根据这个分布,决定量化参数(scale和zero_point)。
我习惯把校准过程比作“给模型做体检”——数据就是体检样本,样本选得对不对,直接决定体检结果准不准。
- 统计激活值的动态范围(min/max)
- 确定量化截断阈值(尤其是KL散度法)
- 减少量化带来的精度损失
3.2 如何构建校准数据集?
构建校准数据集,不是随便拿一堆数据往里灌就行的。
我见过有人直接用训练集的前1000张图片做校准,结果量化后精度掉了5个点。
为什么?因为训练集的前1000张可能全是同一类物体,分布太偏了。
这里我给出几条实战经验:
3.2.1 数据来源
- 首选验证集:验证集本身就是用来评估的,分布和真实场景最接近
- 次选训练集子集:如果验证集太小,可以从训练集中随机采样
- 千万别用测试集:测试集是留到最后评估用的,用了就相当于“作弊”
3.2.2 采样策略
我个人习惯用分层采样。
什么意思呢?就是保证每个类别、每种光照条件、每种角度都有样本。
举个例子,如果你做的是人脸检测模型,校准数据里不能全是正面照,侧脸、低头、戴眼镜的都得有。
3.2.3 数据预处理
校准数据的前处理要和训练时保持一致。
我记得有一次,训练时用了均值归一化,但校准数据忘了减均值——结果量化后的模型输出全是错的。
嗯,这种低级错误,犯过一次就记住了。
# 校准数据预处理示例(PyTorch风格)
from torchvision import transforms
calib_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
3.3 数据量多少合适?
这是被问得最多的问题。
“到底要用多少张图片做校准?”
我的回答是:够用就行,不是越多越好。
为什么?因为校准过程本质上是统计分布。样本太少,统计不准;样本太多,计算开销大,而且边际收益递减。
3.3.1 经验值参考
| 任务类型 | 推荐校准数据量 | 说明 |
|---|---|---|
| 图像分类(如ResNet) | 500~2000张 | 每类至少10~20张 |
| 目标检测(如YOLO) | 1000~3000张 | 需要覆盖不同尺寸、遮挡情况 |
| 语义分割(如DeepLab) | 500~1000张 | 场景多样性比数量更重要 |
| NLP(如BERT) | 1000~5000条 | 覆盖不同句式、长度 |
3.3.2 如何判断数据量是否足够?
我有个简单粗暴的方法:画校准曲线。
用不同数量的校准数据(比如100、500、1000、2000)分别做量化,然后看精度变化。
如果精度不再明显提升,说明数据量已经够了。
# 伪代码:校准数据量实验
for num_samples in [100, 500, 1000, 2000]:
calib_data = sample_from_dataset(num_samples)
quantized_model = quantize(model, calib_data)
accuracy = evaluate(quantized_model)
print(f"样本数: {num_samples}, 精度: {accuracy:.4f}")
3.4 校准数据集的核心逻辑
说了这么多,咱们用一张图来总结校准数据集的核心逻辑:
从这张图可以看得很清楚:
校准数据集不是终点,而是起点。它经过前向传播,统计出激活值的分布规律,最终决定了量化参数的好坏。
好了,关于校准数据集就聊这么多。
下一章咱们会深入讲量化参数的计算方法,包括对称量化、非对称量化、KL散度这些概念。
嗯,到时候见。
公众号:蓝海资料掘金营,微信deep3321