Ultralytics YOLO27: 加入候补名单。
Get Started
构建高性能 YOLO 数据集·训练与迭代·课程 8/10
课程初级

判断数据集是否已准备就绪

通过八项通过/未通过检查来决定是否启动首次训练,自动化其中脚本可以验证的三项,并了解每项检查失败时该如何修复。

每个项目都会迎来团队想要开始训练的时刻。有时数据集已准备就绪;有时它仍存在划分泄漏或标注不足的类别,白白耗费一周 GPU 时间,得到一个不值得信任的指标。对每项检查给出“是”“否”或“有记录的例外”这三种结果,共八项检查,可以让决策客观,而不是凭感觉做决定。

学习成果

按照八项就绪检查为数据集评分,让脚本验证其中三项可计数的检查,并给出是否启动训练的决定或按优先级排列的修复清单。

快速通道
如果你已经熟悉相关内容,以下是简要版。
  1. 完成全部八项检查并评分:是、否或有记录的例外。

  2. 让 readiness.py 对数据量、泄漏、划分覆盖率和背景图像占比进行评分。

  3. 在数据层面修复所有未通过项,而不是靠超参数解决。

  4. 只有在记录下已知缺口的预期影响后,才带着这个缺口交付。

实践操作

八项检查#

#检查项通过标准未通过时,返回
1明确的目标目标、任务、类别和验收测试均已记录并达成一致从业务目标开始
2已定义的类别每个类别都有定义,并明确指出一个不属于该类别的相似对象目标和标注指南
3有代表性的图像每种规格场景都达到配额,且图像主要来自实际生产场景收集高质量、有代表性的数据
4足够的数据量每个类别 ≥ 1,500 张图像且 ≥ 10,000 个实例,或有记录的例外规格和数据收集
5一致的标注已编写指南、完成校准轮次,标注一致率 ≥ 90%标注最佳实践
6已完成质量控制审计脚本无异常、可疑项已复核、质量控制记录已完成数据集质量控制
7干净的数据划分按组划分、每个组只出现在一个划分中、每个划分都包含所有类别正确划分数据集
8背景图像0–10% 的图像是标注为空的画面规格和数据收集

这份清单逐项检查了数据收集和标注指南中涵盖的同一组决策;在这里,这些决策汇总为一个是否启动训练的判断。

自动化可计数的检查#

第 4、7 和 8 项检查都是算术问题,因此脚本每次都能以相同方式评分。以下脚本读取练习集和上一课中由 group_split.py 写出的划分列表:

from collections import Counter
from pathlib import Path

root = Path("datasets/practice")  # images/, labels/, and the train/val/test.txt lists from group_split.py
splits = {s: [Path(p).stem for p in (root / f"{s}.txt").read_text().split()] for s in ("train", "val", "test")}

def classes(stem):
    label = root / "labels" / f"{stem}.txt"
    return [int(r.split()[0]) for r in label.read_text().splitlines() if r.strip()] if label.exists() else []

stems = [s for split in splits.values() for s in split]
instances = Counter(c for s in stems for c in classes(s))
images = Counter(c for s in stems for c in set(classes(s)))
background = sum(not classes(s) for s in stems) / len(stems)
groups = {split: {s.rsplit("_", 1)[0] for s in names} for split, names in splits.items()}
per_split = {split: {c for s in names for c in classes(s)} for split, names in splits.items()}
shared = (groups["train"] & groups["val"]) | (groups["train"] & groups["test"]) | (groups["val"] & groups["test"])
weakest = min(instances, key=lambda c: (images[c], instances[c]))

checks = {
    "4 volume": (images[weakest] >= 1500 and instances[weakest] >= 10_000,
                 f"weakest class {weakest}: {images[weakest]} images, {instances[weakest]} instances"),
    "7 no shared groups": (not shared, f"{len(shared)} groups appear in more than one split"),
    "7 every class in every split": (all(per_split[s] == set(instances) for s in splits),
                                     ", ".join(f"{s} misses {len(set(instances) - per_split[s])}" for s in splits)),
    "8 background 0-10%": (background <= 0.10, f"{background:.1%} background images"),
}
for name, (ok, detail) in checks.items():
    print(f"{'PASS' if ok else 'FAIL'}  {name:<29} {detail}")
FAIL  4 volume                      weakest class 30: 1 images, 1 instances
PASS  7 no shared groups            0 groups appear in more than one split
FAIL  7 every class in every split  train misses 5, val misses 36, test misses 41
PASS  8 background 0-10%            1.6% background images

按组划分修复了泄漏问题,但练习集离就绪还差得很远:其中最弱的类别(30,skis)只有一个已标注实例,而且验证集无法评估一半的类别。对于 128 张演示图像,这就是预期的结论;这项检查的目的正是在一周的训练开始前给出这样的结论。

脚本干净不代表检查清单也完整

脚本只能覆盖可计数的项目。检查项 1、2、3、5 和 6 需要人工完成:明确一致的目标、书面定义、规范覆盖范围、测得的一致性分数以及质检备注。请手动评分,并为每项提供一行证据。

做出决定:开始训练、带着缺口交付,还是先修复#

检查未通过时,人们很容易选择下一步做点别的,而不是修复数据:

诱人的捷径行不通的原因
“试试更大的模型。”更大的模型同样会如实学到标签噪声。
“调整学习率。”任何优化器设置都无法补上缺失的类别或场景。
“增加训练轮数。”在覆盖面狭窄的数据上增加训练轮数,只会让过拟合更快发生。
“增加数据增强。”数据增强无法创造数据中从未包含的场景。

三种看似就绪但仍未通过的情况#

模式未通过的检查具体表现解决方法
数据量大但缺乏变化35,000 张图像,只有一台相机,没有边缘案例训练前从更多相机、地点和时段收集数据
变化丰富但缺乏一致性5标注人员对边界框范围和遮挡情况意见不一完善指南、进行校准,并重新标注受影响的样本
隐蔽的数据泄漏7对视频帧按图像随机划分按视频片段、摄像头或日期重新划分;预计验证集 mAP 会下降,因为这一下降反映了真实情况

带着已知缺口上线#

通常,正确的做法是在所有检查都通过之前,先推出一个范围明确的首版模型:可以是试点、原型,或仅覆盖部分摄像头的 v1。模型投入生产后,比在黑暗中反复打磨数据集更快地暴露实际问题。如果你带着缺口上线,请记录以下三点:

  • 哪项检查未通过。
  • 预期影响,例如“没有夜间数据;预计天黑后召回率会降低”。
  • 在 v1 运行期间弥补缺口的数据采集计划。
没有影响说明的例外,只是跳过了检查

“数量:例外”对接手的人毫无帮助。“数量:pallet,共 700 个实例,预计拥挤货位中的托盘召回率会较低;计划在六月前再标注 2,000 个”才是受控风险。每项例外都必须说明它对验收测试的预期影响。

每次重新训练前都重新运行检查#

模型质量随时间变化:新标注数据到来时质量保持稳定,随后在预期衰退点之后开始下降,因此需要考虑现在是否重新训练,还是继续等待

适用于 v1 的数据集并不一定自动适用于 v3。新增类别、新数据源和新标注人员都可能导致原本通过的检查失败;与此同时,生产数据会持续漂移,而新标签也在不断累积。每次重新训练前都重新运行 readiness.py 并重新评估人工检查项;这只需几分钟,但跳过这一步可能导致你在有问题的数据集上训练一周。

试试看

在划分后的数据集(或练习集)上运行 readiness.py,然后手动评估五项人工检查,每项都用一行证据说明结果。按每项失败检查对验收测试造成的风险大小排序。交付物:一份包含八行、带评分的检查清单,并附上通过与否的决定或按优先级排序的修复列表,保存在 QC 记录旁边。

完成条件
满足以下所有条件,即表示你已完成本课程。
  • 八项检查都有评分和一行证据;其中三项可计数的检查结果来自脚本。

  • 每个例外都说明其对验收测试的预期影响,以及弥补缺口的计划。

  • 决定(训练、记录缺口后上线,或先修复)已与检查清单一并记录。

显示解答

练习集的评分检查清单:

#检查项评分证据
1目标明确是第 1 课中的 objective.md 和 acceptance_test.py
2类别已定义否COCO 的 80 个类别名称没有书面定义,也没有说明哪些相似类别应排除
3图像具有代表性否coverage.py:cam2–cam4 未达到配额
4数据量充足否readiness.py:最弱类别只有 1 张图像
5标签一致否校准轮次的一致率为 47%
6QC 已完成部分完成已运行审计;000000000438.jpg 中的疑似问题仍未解决
7划分干净否没有共享组,但验证集缺少 71 个类别中的 36 个
8背景图像是1.6%

决定:先修复。按对验收测试的风险排序:(1) 将类别列表缩减到目标所需类别,一次性减少第 2、4 和 7 项检查的工作量;(2) 为这些类别采集更多数据组;(3) 完成指南中关于远处人物的规则并重新标注。演示集未通过这项检查,这是应该的。

接下来做什么

检查清单通过后,下一课会运行基线微调,并将结果转化为下一项数据集修复任务。

登录以保存学习进度