3. 数据集准备:标注格式详解与数据增强基础

数据集准备,说白了就是给模型喂饭。饭好不好,直接决定模型能不能长大。我见过太多人花大把时间调参数,结果数据集一塌糊涂——标注格式不对、样本分布失衡、增强策略乱用。嗯,今天咱们就把这块彻底捋清楚。

3.1 YOLO 标注格式详解

YOLO 用的是自己的 txt 标注格式,跟 COCO 的 json、VOC 的 xml 都不一样。你想想看,一个 txt 文件就能搞定一张图的所有标注信息,多轻量。

每张图片对应一个同名的 .txt 文件。比如 image_001.jpg 的标注文件就是 image_001.txt。文件里每一行代表一个目标,格式长这样:

<class_id> <x_center> <y_center> <width> <height>

注意,这里的坐标都是 归一化 的。什么意思?就是除以图片的宽和高,让值落在 0~1 之间。举个例子:

0 0.531250 0.685185 0.234375 0.314815
1 0.125000 0.250000 0.150000 0.200000

第一列 0 是类别 ID,后面四个是归一化后的中心点 x、中心点 y、宽、高。我刚开始做项目时,有次忘了归一化,直接拿像素坐标往里塞,结果模型训练出来完全乱套。后来排查了半天才发现是标注格式的问题。

⚠️ 避坑指南:我曾经在转换 VOC 数据集时,把 xmin, ymin, xmax, ymax 直接当成中心点和宽高用了。正确的转换公式是:
x_center = (xmin + xmax) / 2 / image_width
y_center = (ymin + ymax) / 2 / image_height
width = (xmax - xmin) / image_width
height = (ymax - ymin) / image_height

3.2 数据集划分策略

数据准备好了,接下来怎么分?我个人习惯按 训练集 70%、验证集 20%、测试集 10% 来切。但这不是死规矩,得看你的数据量。

数据量 训练集 验证集 测试集 说明
< 1000 张 80% 10% 10% 数据少,验证集和测试集不能太大
1000 ~ 10000 张 70% 20% 10% 标准划分,比较稳妥
> 10000 张 60% 20% 20% 数据充足,可以多留点做测试

划分时有个关键点:保证各类别在三个集合中的比例一致。比如你的数据里猫占 60%、狗占 40%,那训练集、验证集、测试集里也应该是这个比例。我建议用 sklearn.model_selection.train_test_split 的 stratify 参数来做分层抽样。

💡 我的经验:划分完成后,一定要检查一下验证集和测试集里有没有跟训练集高度相似的图片。比如同一场景的连续帧,如果都放进去了,那验证结果会虚高。我一般会手动抽检 50 张,确保没有数据泄露。

3.3 数据增强基础

数据增强,说白了就是给模型制造「困难」。你想想看,如果训练数据全是正着拍的猫,那模型遇到侧着躺的猫就懵了。所以我们要主动给数据加点「料」。

YOLO 官方推荐的数据增强策略,我整理成了下面这张图:

YOLO 数据增强策略体系 原始图像 几何变换 随机翻转(左右/上下) 随机旋转(±30°) 随机缩放(0.5~1.5倍) 随机裁剪 + 填充 色彩变换 亮度调整(±0.5) 对比度调整(±0.5) 饱和度调整(±0.5) 色相偏移(±0.1) 高级增强 Mosaic(四图拼接) MixUp(两张混合) CutOut(随机遮挡) 随机噪声(高斯/椒盐) 💡 建议:训练初期使用基础增强,后期逐步加入高级增强 Mosaic 和 MixUp 对小目标检测效果提升明显

我个人最常用的是 Mosaic 增强。它把四张图拼成一张,模型一次就能看到四个不同场景。YOLOv5 之后的版本默认就开了这个。但要注意,Mosaic 在训练后期最好关掉,不然模型会过度依赖这种拼接特征。

🔧 实操建议:在 YOLOv8 的配置文件中,数据增强参数都在 augment 部分。我一般这样设置:
hsv_h: 0.015(色相偏移)
hsv_s: 0.7(饱和度偏移)
hsv_v: 0.4(亮度偏移)
degrees: 10.0(旋转角度)
translate: 0.1(平移比例)
scale: 0.5(缩放比例)
mosaic: 1.0(Mosaic 概率)

3.4 标注格式转换实战

实际项目中,你拿到的数据大概率不是 YOLO 格式。我遇到过从客户那拿来的 COCO 格式数据,还有自己用 LabelImg 标出来的 VOC 格式。怎么转?

这里给一个 Python 转换脚本的核心逻辑:

def voc_to_yolo(xml_file, class_names):
    tree = ET.parse(xml_file)
    root = tree.getroot()
    
    # 获取图片尺寸
    size = root.find('size')
    img_w = int(size.find('width').text)
    img_h = int(size.find('height').text)
    
    yolo_lines = []
    for obj in root.findall('object'):
        class_name = obj.find('name').text
        class_id = class_names.index(class_name)
        
        # 读取 VOC 的 bbox
        bbox = obj.find('bndbox')
        xmin = int(bbox.find('xmin').text)
        ymin = int(bbox.find('ymin').text)
        xmax = int(bbox.find('xmax').text)
        ymax = int(bbox.find('ymax').text)
        
        # 转换为 YOLO 格式
        x_center = (xmin + xmax) / 2 / img_w
        y_center = (ymin + ymax) / 2 / img_h
        width = (xmax - xmin) / img_w
        height = (ymax - ymin) / img_h
        
        yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
    
    return yolo_lines
⚠️ 注意:转换时一定要检查坐标有没有越界。我曾经遇到过标注框的 xmin 比 xmax 还大的情况,这种脏数据会直接让训练崩溃。建议在转换脚本里加一个校验:
assert xmin < xmax and ymin < ymax, "Invalid bbox coordinates"

3.5 数据增强的「度」

数据增强不是越多越好。我见过有人把亮度调到 ±0.9,结果图片都变成全白或全黑了,模型根本学不到东西。这里给一个我总结的「安全区间」:

增强类型 安全范围 过度增强的后果
亮度 ±0.3 ~ ±0.5 特征丢失,模型无法识别
旋转 ±10° ~ ±30° 目标变形严重,标注框偏移
缩放 0.5 ~ 1.5 倍 小目标消失或大目标截断
Mosaic 概率 0.5 ~ 1.0 模型过拟合拼接特征
MixUp 概率 0.1 ~ 0.3 目标边界模糊,难以收敛

最后说一句,数据增强的参数一定要跟你的实际场景匹配。比如你做的是夜间监控,那亮度调整就应该往暗的方向偏;如果是无人机航拍,旋转角度可以设大一点。没有万能参数,多试几次就知道了。