Phase 2:eval 集**绝不**能见过预标注
· 约 4 分钟阅读
eval 集是 HITL 管线里唯一需要在每轮迭代之间保持干净的东西。这件事做错,所有其他指标——分段器 F1、关键点像素误差、动作分类准确率——都是假的。这篇说「干净」在这里到底是啥意思、怎么维持。
偏差陷阱
Phase 1 产出预标注。标注员校验。如果你直接拿 10% 校验过的 episode 当 eval 集,那些 eval 标签里装着:
- 模型标对的帧 → 标注员接受预标注 → eval 标签 = 模型预测。
- 模型标错且显眼的帧 → 标注员修了 → eval 标签 = 修后的,但只针对标注员注意到的那批错。
- 模型标错且不显眼的帧 → 标注员可能接受了 → eval 标签 = 错的模型预测。
eval 集里每一帧都跟模型预测相关。在这个集上算 F1,测的是「跟『从模型输出开始改的标注员』之间的一致性」,不是「跟真值的一致性」。模型微调;新模型跟 eval 标签更一致(理所应当——它跟旧模型同族);F1 上去了;所有人开心;真实世界数据上的模型没动过。
这是多数 HITL 项目搞砸的那一个决定。指标告诉你闭环在 work,其实没有。
「干净」到底要满足什么
eval 集要满足三条:
- 标签是在没见过任何模型预测的情况下产生的。 标注员从零标。没有预填、没有「接受/拒绝」UI 模式。
- episode 是在任何模型碰过它之前选的。 别从「好标的」候选里采 eval episode。在可用池子里随机、早早定下、冻起来。
- eval 集小到合理、大到能检测变化。 每个 task 类型 ~100 帧是合理起点。低于 ~30 啥都测不出;高于 ~500,你花在 eval 上的标注员时间就是从训练数据里挤出来的。
干净 eval 集 = 每轮用同一个集、用同样方式标。集里的 episode 在微调时禁用——它们永远不进任何训练 slice。每次重训用同一份标签,把不同模型版本拿到同一个靶子前对比。
第一次怎么建
第一次跑 Phase 1 之前:
- 每个 task 选 ~10 个 episode。随机选,不是「有意思」的 episode。
- 每个发给两个标注员(或者一个标注员 + 二人复核)。
- 让他们在空白 UI 上标——没有模型预标注、LS 任务 JSON 里没有
predictions字段。 - 分歧 > 5px(关键点)或 > 5 帧(段边界)人工裁决。
- 把结果 pin 住、算 SHA、当成带版本号的产物管理。
这事很烦——从零标比验证预标注慢 3-5 倍。第一天就把预算编进去。后面你没时间补。
该盯的几个数字
三个值得长期跟踪的指标:
- 每个模型版本在 eval 集上的 F1 / mAP / 像素误差。 真正衡量进展的数字。只画这个。
- eval 集大小 + 最后修改时间。 如果一年没复核了,eval 集可能已经老化到分布不再代表性。
- eval ↔ train 数据泄漏。 跑一个 SHA 检查,确保任何 eval episode 都没出现在任何训练 slice 里。一行 CI 断言。
第 3 条总有一天会救你。第一天就装上。
什么时候刷新 eval 集
两个正当理由:
- 数据分布漂了。 新摄像机、新 task、新环境。旧 eval 集已经没代表性。建一个新的干净 eval 集,旧的归档存历史。
- eval 饱和。 模型在 eval 上 99%,改进跟噪声分不开。把 eval 集做难——往边界 case 重采样、或者加新 task 类型。
两种情况下规则一样:建新的、不要扩展老的。跨 eval 集变化比较模型版本 = 在比较不同的测量。
总结
- 模型预测做种子的 eval 标签对模型有偏。F1 涨了真实表现没涨。
- 干净 eval = 从零标、模型碰之前选好的、冻起来、每轮重复用。
- 第一天建。每帧贵 3-5 倍,每分钟都值得。
- CI 断言守住 eval ↔ train 泄漏。
- 用替换刷新 eval 集,从来不用扩展。