Jack Pan

Phase 2:eval 集**绝不**能见过预标注

· 约 4 分钟阅读

eval 集是 HITL 管线里唯一需要在每轮迭代之间保持干净的东西。这件事做错,所有其他指标——分段器 F1、关键点像素误差、动作分类准确率——都是假的。这篇说「干净」在这里到底是啥意思、怎么维持。

偏差陷阱

Phase 1 产出预标注。标注员校验。如果你直接拿 10% 校验过的 episode 当 eval 集,那些 eval 标签里装着:

  • 模型标对的帧 → 标注员接受预标注 → eval 标签 = 模型预测。
  • 模型标错且显眼的帧 → 标注员修了 → eval 标签 = 修后的,但只针对标注员注意到的那批错。
  • 模型标错且不显眼的帧 → 标注员可能接受了 → eval 标签 = 错的模型预测。

eval 集里每一帧都跟模型预测相关。在这个集上算 F1,测的是「跟『从模型输出开始改的标注员』之间的一致性」,不是「跟真值的一致性」。模型微调;新模型跟 eval 标签更一致(理所应当——它跟旧模型同族);F1 上去了;所有人开心;真实世界数据上的模型没动过。

这是多数 HITL 项目搞砸的那一个决定。指标告诉你闭环在 work,其实没有。

「干净」到底要满足什么

eval 集要满足三条:

  1. 标签是在没见过任何模型预测的情况下产生的。 标注员从零标。没有预填、没有「接受/拒绝」UI 模式。
  2. episode 是在任何模型碰过它之前选的。 别从「好标的」候选里采 eval episode。在可用池子里随机、早早定下、冻起来。
  3. eval 集小到合理、大到能检测变化。 每个 task 类型 ~100 帧是合理起点。低于 ~30 啥都测不出;高于 ~500,你花在 eval 上的标注员时间就是从训练数据里挤出来的。

干净 eval 集 = 每轮用同一个集、用同样方式标。集里的 episode 在微调时禁用——它们永远不进任何训练 slice。每次重训用同一份标签,把不同模型版本拿到同一个靶子前对比。

第一次怎么建

第一次跑 Phase 1 之前:

  1. 每个 task 选 ~10 个 episode。随机选,不是「有意思」的 episode。
  2. 每个发给两个标注员(或者一个标注员 + 二人复核)。
  3. 让他们在空白 UI 上标——没有模型预标注、LS 任务 JSON 里没有 predictions 字段。
  4. 分歧 > 5px(关键点)或 > 5 帧(段边界)人工裁决。
  5. 把结果 pin 住、算 SHA、当成带版本号的产物管理。

这事很烦——从零标比验证预标注慢 3-5 倍。第一天就把预算编进去。后面你没时间补。

该盯的几个数字

三个值得长期跟踪的指标:

  1. 每个模型版本在 eval 集上的 F1 / mAP / 像素误差。 真正衡量进展的数字。只画这个
  2. eval 集大小 + 最后修改时间。 如果一年没复核了,eval 集可能已经老化到分布不再代表性。
  3. 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 集,从来不用扩展