3、数据标注:半自动标注工具(LabelImg、CVAT),标注质量检查,处理不平衡数据集
数据标注这件事,说实话,比调模型参数更磨人。
我刚开始做微小机器学习的时候,总觉得标注就是「体力活」,随便标标就行。结果呢?模型训练出来,准确率死活上不去。后来一查,标注框歪了十几个像素,标签还打错了几个。嗯,从那以后我再也不敢小看标注了。
今天咱们聊聊怎么用半自动工具提效,怎么检查标注质量,以及怎么处理那个让人头疼的不平衡数据集。
3.1 半自动标注工具:LabelImg 和 CVAT
纯手工标注,一张图花5分钟,1000张图就是5000分钟。你想想看,这谁受得了?
半自动标注的思路很简单:先用一个预训练模型跑一遍,生成初步标注框,然后人工微调。说白了,就是让机器先干80%的活,人只负责检查和修正。
3.1.1 LabelImg:轻量级首选
LabelImg 是我个人最常用的工具,尤其适合小数据集。它基于 Python + Qt,安装简单,开箱即用。
# 直接 pip 安装
pip install labelImg
# 或者从源码运行
git clone https://github.com/tzutalin/labelImg
cd labelImg
python labelImg.py
使用技巧:
- 快捷键要背熟:W 画框,A/D 切换图片,Ctrl+S 保存。我习惯左手按键盘,右手握鼠标,效率能翻倍。
- 自动保存模式:在 View 菜单里勾选 Auto Save mode,省得忘记保存。
- 预标注插件:LabelImg 支持加载 YOLO 或 TensorFlow 的推理结果作为初始框。我在项目中用过一次,把标注时间从3天压缩到了半天。
3.1.2 CVAT:团队协作利器
CVAT(Computer Vision Annotation Tool)是 Intel 开源的在线标注平台。它支持多人同时标注,还能自动跟踪标注进度。
部署方式(Docker 一键启动):
git clone https://github.com/opencv/cvat
cd cvat
docker-compose up -d
CVAT 的几个亮点:
- 半自动标注:内置了 Deep Learning 模型,比如 Mask R-CNN、YOLO。你点一下「Auto Annotation」,它就能生成一批候选框。
- 标注质量看板:能看到每个人标注了多少张、平均耗时、标注框的 IoU 分布。这个功能我特别喜欢,谁在摸鱼一目了然。
- 导出格式丰富:支持 COCO、Pascal VOC、YOLO、TFRecord 等。不用自己写格式转换脚本。
3.2 标注质量检查:别让垃圾数据毁了模型
「垃圾进,垃圾出」——这句话在机器学习里是铁律。我见过太多人花大量时间调模型,结果发现是标注数据有问题。
标注质量检查,我一般分三步走:
3.2.1 人工抽检
随机抽取 5%-10% 的标注数据,让另一个人重新标注一遍。然后计算两个标注结果的 IoU(交并比)和标签一致性。
我常用的检查指标:
| 指标 | 计算公式 | 合格标准 |
|---|---|---|
| IoU | 交集面积 / 并集面积 | ≥ 0.7 |
| 标签准确率 | 一致标签数 / 总标签数 | ≥ 95% |
| 漏标率 | 漏标物体数 / 总物体数 | ≤ 5% |
3.2.2 自动化检查脚本
写个脚本跑一遍,能发现很多肉眼看不出的问题。比如:
import json
def check_annotation(annotation_file):
with open(annotation_file, 'r') as f:
data = json.load(f)
issues = []
for img in data['images']:
# 检查标注框是否超出图像边界
for ann in img['annotations']:
x, y, w, h = ann['bbox']
if x < 0 or y < 0 or x+w > img['width'] or y+h > img['height']:
issues.append(f"框越界: {img['file_name']}")
# 检查框面积是否过小(可能是误标)
if w * h < 100:
issues.append(f"框太小: {img['file_name']}")
return issues
3.2.3 一致性校验
多人标注时,不同人的标准可能不一样。比如「这个算不算遮挡?」「边界模糊的物体要不要标?」
我的做法是:
- 制定详细的标注规范文档,图文并茂
- 每周开一次标注对齐会,讨论争议案例
- 用 Fleiss' Kappa 系数衡量标注一致性,低于 0.6 就要重新培训
3.3 处理不平衡数据集
不平衡数据集,说白了就是某些类别的样本特别多,某些类别特别少。比如工业缺陷检测中,合格品占了99%,缺陷品只有1%。
这种情况下,模型会「偷懒」——它只要把所有样本都预测为合格品,准确率就有99%。但这不是我们想要的。
3.3.1 数据层面:重采样
最直接的方法就是让各类别样本数量差不多。
过采样(Oversampling):
- 随机复制少数类样本。简单,但容易过拟合。
- SMOTE(合成少数类过采样):在少数类样本之间插值生成新样本。我试过,效果比随机复制好不少。
欠采样(Undersampling):
- 随机删除多数类样本。适合数据量大的情况。
- NearMiss:只保留多数类中离少数类最近的样本。能保留更多决策边界信息。
3.3.2 算法层面:调整损失函数
如果不想动数据,可以改损失函数。
加权交叉熵损失:
import torch.nn as nn
# 计算每个类别的权重(样本数越少,权重越大)
class_weights = [1.0 / count for count in class_counts]
weights = torch.tensor(class_weights)
criterion = nn.CrossEntropyLoss(weight=weights)
Focal Loss:这是我在目标检测中常用的。它让模型更关注难分类的样本,而不是那些已经分对的样本。
class FocalLoss(nn.Module):
def __init__(self, alpha=0.25, gamma=2.0):
super().__init__()
self.alpha = alpha
self.gamma = gamma
def forward(self, pred, target):
ce_loss = F.cross_entropy(pred, target, reduction='none')
pt = torch.exp(-ce_loss)
focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss
return focal_loss.mean()
3.3.3 评估指标:别只看准确率
不平衡数据集上,准确率是骗人的。你应该关注:
- 精确率(Precision):预测为正例的样本中,有多少是真的正例。
- 召回率(Recall):真正的正例中,有多少被找出来了。
- F1-Score:精确率和召回率的调和平均。
- 混淆矩阵:一目了然看到哪些类别被混淆了。
举个例子:
| 指标 | 合格品 | 缺陷品 |
|---|---|---|
| 精确率 | 0.99 | 0.45 |
| 召回率 | 0.98 | 0.60 |
| F1-Score | 0.98 | 0.51 |
你看,缺陷品的 F1 只有 0.51,这才是真正需要优化的地方。
3.4 小结
数据标注这件事,说白了就是「磨刀不误砍柴工」。
用半自动工具提效,用质量检查保底,用重采样或损失函数处理不平衡。这三步走下来,你的数据集质量至少能提升一个档次。
我个人习惯是:标注阶段花 60% 的时间,检查阶段花 30%,处理不平衡花 10%。别嫌检查浪费时间,它省下的调参时间,远比你想象的多。