很多人第一次做图像识别,卡在两件事上:一是搞不清训练和测试到底谁管什么,把测试集当训练集反复调,结果上线就崩;二是 epoch 拍脑袋定,要么欠拟合没学够,要么跑飞了过拟合还看不出来。这篇按分工、数据划分、epoch 设置、排查顺序四段讲,给的是判断标准和可执行动作,具体数值到站内模型库与训练页面核对当时的资料。
很多人第一次做图像识别,卡在两件事上:一是搞不清训练和测试到底谁管什么,把测试集当训练集反复调,结果离线指标好看、上线就崩;二是 epoch 拍脑袋定,要么欠拟合没学够,要么跑飞了过拟合自己还看不出来。这篇按分工、数据划分、epoch 设置、排查顺序四段讲,给的是判断标准和可执行动作。
先记住一句话:训练和测试不是二选一,是两个方向相反的活儿。一个要把数据榨干,一个要假装没见过这份数据。搞混了,后面花再多时间调参也是在给自己发假奖状。具体到某个模型、某种任务该参考什么口径,到站内模型库与训练相关页面核对当时的资料,不要照着别人博客里的数字抄。
训练和测试不是二选一,是分工不同
训练阶段的唯一目标是让模型在已有数据上把参数学好,损失降下去;测试阶段的目标正好相反,是判断这套参数换到没见过的数据上还灵不灵。所以训练时可以尽量拟合,测试时必须保持「我没参与过调参」的干净身份。一旦把测试集拿去反复调参,它就已经变成验证集甚至训练集了,这时候指标再漂亮也只说明模型记住了这批数据,不代表真实泛化。
| 阶段 | 核心目标 | 允许做什么 | 最怕什么 |
|---|---|---|---|
| 训练 | 把参数学到位 | 前向、反向、更新权重 | 学得太死,只记住训练样本 |
| 验证 | 帮你做选择 | 选 epoch、选结构、选超参 | 反复选中同一批数据,选择噪声变大 |
| 测试 | 报告真实水平 | 只在最后跑一次出结论 | 被当调参依据用,指标虚高 |
数据怎么分、三类集合各管什么
训练集调参数,验证集做选择,测试集只在最后用一次、出报告用。划分比例没有万能值,样本少的时候,分层抽样比按固定比例切更靠谱:先保证每个类别在三个集合里都出现过,再谈每边放多少。图像任务还有个隐蔽的坑,同一张原图裁出来的图、翻转出来的副本,不能一半在训练侧一半在测试侧,那等于把答案提前泄给模型。
- 先按类别分层,再随机切,避免某一类在测试集里一个样本都没有
- 同一张原图的所有增强副本,必须整组留在同一个集合里
- 划分脚本要固定随机种子,不然每次重跑划分都变,实验没法比
- 切完之后打印一遍各类样本数,数不对就重切,别急着开训
- 如果数据来源分批次(不同设备、不同时间段),按批次留一份测试集更接近真实场景
还有一点常被忽略:验证集和测试集的分布要尽量贴近线上会遇到的数据。如果测试集全是棚拍图、线上全是手机随手拍,那验证指标再稳也说明不了问题。具体到某个数据集该怎么切,站内指南中心有相关整理,可以对着当时的口径核一遍。
epoch 怎么定:先看曲线,再谈次数
别问「跑多少轮够」,要问「这轮之后验证指标还在涨吗」。典型信号是训练损失继续降、验证损失开始抬头,那就已经进过拟合区了。常用做法是先把上限设得偏大,同时挂上早停、保存验证最优权重,让训练自己停下来,而不是人盯着日志拍数字。轮数本身不是目标,泛化才是。
- 早停
- 验证指标连续若干轮不再提升就停,停的轮数要跟样本量匹配,别设得太短就误判
- 最优权重保存
- 只保留验证表现最好的那一版,最后交付用它,而不是用最后一轮的
- 学习率调度
- 后期降学习率常能让曲线再压一段,但调了它,epoch 的合适区间也会跟着变
- 先用偏大的轮数上限试跑把上限设成你预估的明显偏大值,只看曲线走向,别急着下结论
- 看两条损失的开口训练损失继续降、验证损失抬头即过拟合;两条都平、都不降即欠拟合或学习率有问题
- 按信号决定加还是减欠拟合就加轮数或加模型容量;过拟合就减轮数、加增强、加正则
- 记住不适用的场景验证集太小、或和线上分布差太远时,早停挑出的轮数也可能骗你,得另设一批贴近线上的数据复核
小数据集、图像增强用得重的时候,同样轮数下模型能学到的信息更多,这时候可以适当减少轮数;数据量大、增强弱则可以多跑一些。这些都是方向判断,具体数量级到站内模型库和训练相关页面核对当时的资料更稳妥。
训练不收敛或指标虚高的排查顺序
排查有固定顺序:先查数据标注和划分,再查学习率这类超参,最后才怀疑模型结构。顺序反了,你会在结构上折腾很久,结果问题出在几张标错的图上。每次只改一个变量,并留记录,否则最后说不清是哪一步起了作用。
| 现象 | 优先怀疑 | 先做的动作 |
|---|---|---|
| 离线指标高、上线效果差 | 数据泄漏或分布不一致 | 查同一原图副本是否跨集合、查训练与推理预处理是否一致 |
| 损失几乎不降、曲线全程平 | 标签或输入有问题 | 抽查标签是否正确、确认输入归一化做了没有 |
| 损失震荡或直接发散 | 学习率过大 | 先降学习率重跑,再考虑调 batch 与优化器 |
如果验证指标一直不错但总觉得不踏实,可以换个更接近线上分布的小批量数据再验一次,这一步比继续调参更能暴露问题。各家的评测口径和训练资料经常更新,动手前到站内测评与训练相关页面核对当时的口径,别用旧结论套新任务。
下一步把训练、验证、测试三份数据的划分脚本固定下来,再参考站内整理的中转站与工具资料确认环境是否一致,避免预处理两侧不统一导致指标虚高。→常见问题
训练集和测试集能不能是同一批数据?
不行,那样测出来的只是模型对见过的样本还记不记得,不代表它面对新图片能认出来。至少要把一部分数据完全隔离,全程不参与训练和调参,只在上线前验收或出报告时用一次,这样得到的数字才有参考价值。
epoch 是不是设得越多效果越好?
不是。轮数太少模型没学够,轮数太多会开始背训练样本,验证集表现反而变差。实用做法是设一个偏大的上限配合早停,让验证指标不再提升就停,并保留验证表现最好的那一版权重,而不是跑满全程。
验证集准确率很高,上线却不行,先查什么?
按顺序查三件事:一是数据有没有泄漏,比如同一张图的近似副本同时出现在训练和验证里;二是验证集分布和线上是否一致,比如拍摄角度、光照差异很大;三是预处理在训练和推理两侧是否一模一样,尺寸、归一化对不上是最常见的坑。