3、校准数据集:如何构建有效的校准数据集?数据量、数据分布对校准的影响
说到量化校准,很多人第一反应是:“不就是拿点数据跑一遍吗?”
嗯,我以前也这么想。直到有一次,我用了一组全是猫的图片去校准一个图像分类模型,结果模型量化后,看到狗就懵了。那叫一个惨。
说白了,校准数据集就是量化过程的“标尺”。标尺歪了,你量出来的东西能准吗?
3.1 校准数据集到底在干什么?
量化校准的核心目的,是找到每一层激活值的真实分布范围。比如一个层的输出值在 [-3.2, 5.8] 之间,那我们就用这个范围去映射到 INT8 的 [-128, 127]。
但问题是——你不可能跑完整训练集去统计。太慢了,也太贵了。所以我们需要一个“代表”,也就是校准数据集。
核心原则:校准数据集必须能代表模型在真实推理时遇到的数据分布。
我个人的习惯是,先搞清楚模型部署后的应用场景。如果是做自动驾驶的,你拿一堆室内场景图去校准,那肯定不行。你想想看,路上的行人、车辆、交通标志,这些才是关键。
3.2 数据量:到底需要多少张图?
这个问题我经常被问到。答案其实很灵活,但有个经验值:
| 模型类型 | 推荐校准样本数 | 备注 |
|---|---|---|
| 分类模型(如 ResNet) | 100 - 500 张 | 每类至少 5-10 张 |
| 检测模型(如 YOLO) | 200 - 1000 张 | 覆盖不同尺寸、角度 |
| 分割模型(如 UNet) | 100 - 500 张 | 关注边缘和纹理区域 |
| Transformer 模型 | 200 - 1000 条 | 文本长度要多样 |
为什么是这个量?我解释一下。
校准本质上是在做“采样统计”。样本太少,你看到的分布是片面的。比如一个层的输出值范围是 [-10, 10],但你只拿了 10 张图,可能只看到 [-2, 3],那量化后就会严重截断。
但样本太多也没必要。我记得有个项目,同事用了 5000 张图去校准,结果和 300 张的效果几乎一样。白白浪费了时间。
我的经验:从 200 张开始,跑一次校准,看看量化后的精度。如果掉点严重,再逐步增加。一般到 500 张左右就饱和了。
3.3 数据分布:比数量更重要的事
数量只是基础,分布才是灵魂。
什么叫好的分布?我举个例子。
假设你有一个分类模型,有 10 个类别。校准数据集里,类别 A 有 100 张,类别 B 到 J 各只有 1 张。那模型对类别 B 到 J 的激活值分布,基本就是瞎猜的。
我个人建议,校准数据集要满足以下几点:
- 类别平衡:每个类别至少 5-10 个样本。如果类别太多,可以按频率采样,但不要完全忽略少数类。
- 难度覆盖:不要只挑简单的样本。比如分类任务,既要有清晰的正面照,也要有模糊的、遮挡的、光照不好的。我遇到过一个问题,校准集全是高清图,结果部署到低分辨率摄像头时,精度直接掉了 5 个点。
- 场景多样性:如果是检测模型,要覆盖不同背景、不同光照、不同角度。我有个做安防的朋友,校准集里全是白天场景,结果晚上一跑,模型直接“瞎”了。
注意:千万不要用训练集或验证集做校准。这会导致“数据泄露”,你看到的校准精度是虚高的。一旦部署到新数据上,立马现原形。
3.4 如何构建一个有效的校准数据集?
好了,理论说完了,咱们来点实操的。我一般按这个流程走:
- 确定应用场景:模型部署后,会面对什么样的数据?是手机拍照、监控视频、还是医疗影像?
- 从训练集中采样:按类别、场景、难度分层采样。不要随机抽,要“刻意”选。
- 加入少量“边缘案例”:比如极端光照、遮挡、模糊等。这些样本虽然少,但能帮助校准更鲁棒。
- 验证校准效果:用校准后的量化模型,在验证集上跑一次。如果精度掉点超过 1%,说明校准集可能有问题。
这里我分享一个我常用的采样代码片段:
import random
from collections import defaultdict
def build_calibration_set(dataset, samples_per_class=20):
"""
按类别分层采样,构建校准数据集
"""
class_to_indices = defaultdict(list)
for idx, (_, label) in enumerate(dataset):
class_to_indices[label].append(idx)
cal_indices = []
for label, indices in class_to_indices.items():
# 如果该类样本少于目标数,全部取走
if len(indices) <= samples_per_class:
cal_indices.extend(indices)
else:
# 随机采样,保证多样性
cal_indices.extend(random.sample(indices, samples_per_class))
return cal_indices
这段代码很简单,但很实用。它保证了每个类别都有足够的代表,不会出现“偏科”的情况。
3.5 避坑指南:我曾经踩过的坑
做量化校准这么多年,我踩过的坑真不少。挑几个典型的说说:
- 坑一:校准集和验证集混用。 我曾经为了省事,直接用验证集做校准。结果量化后精度看起来很好,一上线就崩了。后来才明白,验证集已经被“污染”了。
- 坑二:只用“好”样本。 我有个项目,校准集全是清晰、标准的图片。结果模型在模糊、低光照场景下,精度掉了 8 个点。后来我加入了 20% 的“坏”样本,问题就解决了。
- 坑三:数据量太少。 有一次我只用了 50 张图做校准,结果量化后的模型在某些层上出现了严重的截断误差。后来增加到 200 张,问题就消失了。
小技巧:如果你不确定校准集够不够好,可以跑一次“校准集分布分析”。把每一层的激活值分布画出来,看看有没有明显的“空洞”或“偏斜”。如果有,说明校准集可能不够全面。
3.6 总结一下
校准数据集,说白了就是量化过程的“眼睛”。眼睛不好使,路就走歪了。
我个人建议,花点时间在构建校准集上,绝对值得。200-500 张图,类别平衡、场景多样、难度覆盖,基本就能搞定大部分模型。
记住一句话:校准集的质量,决定了量化模型的天花板。
好了,这一章就到这里。下一章我们聊聊“量化感知训练”,那是另一个有意思的话题。