第三章 数据集准备:小目标数据集的标注规范与增强策略

说实话,小目标检测的难点,有一半都出在数据上。

模型再强,数据不行,照样白搭。我见过太多同学拿着通用目标检测的数据集直接训小目标,结果mAP惨不忍睹。为什么?因为小目标在图像里就那么几个像素,标注稍微偏一点,IoU就直接掉到0.3以下了。

这一章,咱们就聊聊小目标数据集该怎么准备。从标注规范到增强策略,我把这几年踩过的坑都摊开来讲。

3.1 小目标标注的“毫米级”要求

先问个问题:你觉得小目标的标注框,误差允许多大?

对于大目标,比如一辆汽车占满半个画面,框偏个5个像素,IoU可能还有0.9。但对于小目标,比如一个行人只有30x30像素,框偏5个像素,IoU可能就掉到0.6以下了。

所以,小目标标注的第一条铁律:精度必须控制在2个像素以内

小目标标注核心指标:

  • 标注框边缘误差 ≤ 2像素
  • 遮挡目标必须标注可见部分(不要脑补完整框)
  • 模糊目标:如果人眼都看不清,建议直接丢弃
  • 密集场景:每个实例都必须独立标注,不能漏标

我在做无人机航拍数据集时遇到过一个问题:一群鸟在天空飞,每只鸟只有10x10像素左右。标注员为了省事,直接画一个大框把一群鸟框住。这种数据喂给YOLO,模型根本学不会“一只鸟”是什么概念。后来我强制要求:每个独立实例必须单独标注,哪怕只有5x5像素。

3.2 标注格式与工具选择

YOLO系列最常用的标注格式是txt文件,每行一个目标:

class_id x_center y_center width height

注意:这里的坐标都是归一化到[0,1]的。对于小目标,width和height的值会非常小,比如0.01甚至0.005。这时候浮点数精度就很重要了。

我曾经踩过的坑:

用LabelImg标注小目标时,默认保存的坐标只保留6位小数。对于1920x1080的图像,6位小数对应约0.001的精度,换算成像素就是1-2个像素。看起来够用?但如果你做Mosaic增强或者随机裁剪,坐标经过多次变换后,精度损失会累积。我建议:标注坐标至少保留8位小数

工具方面,我个人推荐:

  • LabelImg:轻量级,适合小规模数据
  • CVAT:支持半自动标注,适合大规模项目
  • Roboflow:在线标注+增强一条龙,适合快速验证

对于小目标,我特别推荐CVAT的“分块标注”功能。把大图切成小块,标注员可以放大到像素级去画框,精度高很多。

3.3 小目标数据增强策略

数据增强是小目标检测的“救命稻草”。但要注意:不是所有增强都适合小目标

举个例子,RandomResizedCrop(随机裁剪缩放)是分类任务的标配,但在小目标检测里,它可能直接把目标裁掉或者缩得更小。我见过一个项目,用了RandomResizedCrop后,小目标的召回率直接掉了15%。

下面是我总结的小目标专属增强策略

增强方法 适用场景 推荐参数 注意事项
Mosaic 通用 4张图拼接 小目标可能被切碎,建议配合Copy-Paste
Copy-Paste 小目标专用 每张图粘贴3-5个小目标 注意背景融合,避免边缘生硬
RandomScale 多尺度训练 0.5~1.5倍 不要缩太小,下限建议0.8
Cutout 遮挡鲁棒性 遮挡区域≤图像面积5% 避免遮挡小目标本身
MixUp 类别平衡 alpha=0.2 小目标混合后可能更难识别

3.4 Copy-Paste:小目标增强的“核武器”

在所有增强方法里,我最想重点聊的是Copy-Paste。说白了,就是把小目标从一张图里抠出来,贴到另一张图上去。

为什么它特别适合小目标?

  • 小目标在原始数据里往往数量不足,Copy-Paste可以直接增加样本量
  • 可以控制粘贴的位置,避免目标重叠
  • 可以调整粘贴目标的尺度,模拟不同距离

我分享一个我在项目中用过的代码片段:

def copy_paste_augmentation(image, labels, paste_objects):
    """
    paste_objects: 从其他图像中提取的小目标列表
    每个元素: (bbox, class_id, image_patch)
    """
    h, w = image.shape[:2]
    for obj in paste_objects:
        patch, bbox, cls_id = obj
        ph, pw = patch.shape[:2]
        
        # 随机选择粘贴位置
        x = random.randint(0, w - pw)
        y = random.randint(0, h - ph)
        
        # 简单的alpha融合
        alpha = 0.7
        image[y:y+ph, x:x+pw] = (1-alpha)*image[y:y+ph, x:x+pw] + alpha*patch
        
        # 添加标注
        x_center = (x + pw/2) / w
        y_center = (y + ph/2) / h
        width = pw / w
        height = ph / h
        labels.append([cls_id, x_center, y_center, width, height])
    
    return image, labels

我的经验:

Copy-Paste时,尽量选择背景相似的场景。比如把天空中的鸟贴到另一张天空图上,效果就很好。如果把鸟贴到草地上,模型可能会学到“鸟在草地上”这种错误关联。我一般会准备一个“背景相似度”的筛选逻辑,低于阈值的就不贴。

3.5 多尺度训练与测试

小目标检测还有一个经典技巧:多尺度训练

YOLO系列支持在训练时动态调整输入尺寸。比如YOLOv8,可以设置一个尺寸范围,每次迭代随机选一个。这样做的好处是:模型能学到不同尺度下的特征表达。

我建议的配置:

  • 基础尺寸:640x640
  • 多尺度范围:0.5~1.5倍(即320x320到960x960)
  • 步长:32的倍数(因为YOLO的下采样倍数是32)

测试时,可以用TTA(Test Time Augmentation)。说白了就是多尺度推理,然后融合结果。我实测过,TTA能让小目标的AP提升2-3个点。代价就是推理时间翻倍,嗯,看你的场景能不能接受。

3.6 数据质量检查清单

最后,我整理了一份数据质量的检查清单。每次准备数据集时,我都会过一遍:

  1. 标注完整性:有没有漏标的小目标?特别是密集场景
  2. 标注精度:随机抽100个框,检查边缘误差是否≤2像素
  3. 类别平衡:小目标类别和大目标类别的数量比是否合理?
  4. 尺度分布:小目标(<32x32像素)占比是否足够?建议至少20%
  5. 遮挡情况:是否有足够的遮挡样本?建议10%-20%
  6. 背景多样性:小目标是否出现在不同背景中?避免过拟合

我曾经犯过的错:

有一次做交通标志检测,小标志(比如限速牌)在训练集里只有200个,大标志(比如广告牌)有2000个。模型训出来,大标志mAP 0.95,小标志只有0.3。后来我做了两件事:一是用Copy-Paste把小标志数量补到2000,二是对小标志类别加了3倍的loss权重。最终小标志的mAP提到了0.78。

数据准备这一步,说白了就是“磨刀不误砍柴工”。我见过太多人急着调模型,结果数据一塌糊涂,调了两个月还不如别人好好准备一周数据的效果。你想想看,是不是这个道理?

下一章,咱们聊聊YOLO模型结构怎么改,才能更好地适配小目标。到时候我会分享一些我在实际项目中用过的魔改方案,保证干货满满。