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、宽、高。我刚开始做项目时,有次忘了归一化,直接拿像素坐标往里塞,结果模型训练出来完全乱套。后来排查了半天才发现是标注格式的问题。
xmin, ymin, xmax, ymax 直接当成中心点和宽高用了。正确的转换公式是:x_center = (xmin + xmax) / 2 / image_widthy_center = (ymin + ymax) / 2 / image_heightwidth = (xmax - xmin) / image_widthheight = (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 参数来做分层抽样。
3.3 数据增强基础
数据增强,说白了就是给模型制造「困难」。你想想看,如果训练数据全是正着拍的猫,那模型遇到侧着躺的猫就懵了。所以我们要主动给数据加点「料」。
YOLO 官方推荐的数据增强策略,我整理成了下面这张图:
我个人最常用的是 Mosaic 增强。它把四张图拼成一张,模型一次就能看到四个不同场景。YOLOv5 之后的版本默认就开了这个。但要注意,Mosaic 在训练后期最好关掉,不然模型会过度依赖这种拼接特征。
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
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 | 目标边界模糊,难以收敛 |
最后说一句,数据增强的参数一定要跟你的实际场景匹配。比如你做的是夜间监控,那亮度调整就应该往暗的方向偏;如果是无人机航拍,旋转角度可以设大一点。没有万能参数,多试几次就知道了。