022、数据增强改进(一):Mosaic、MixUp、CutMix原理与组合策略
上周在部署YOLOv11到边缘设备时遇到个头疼的问题:模型在测试集上mAP挺漂亮,一到真实场景就漏检小目标。查了一轮发现,训练数据里小目标样本太少,模型没见过“世面”。这让我重新审视数据增强——不是简单旋转翻转就能解决的,得用点“猛药”。
一、Mosaic:把四张图拼成一张的“全景训练”
Mosaic说穿了就是数据穷人的福音。你只有640x640的输入尺寸,但想让模型学会看大场景?直接把四张训练图随机裁剪拼接成一张,相当于让模型一次看四个样本。
def mosaic_augmentation(images, labels, size=640):
# 初始化输出画布
output_img = np.full((size, size, 3), 114, dtype=np.uint8)
output_labels = []
# 随机选中心点
cx, cy = random.randint(size//4, 3*size//4), random.randint(size//4, 3*size//4)
for i in range(4):
img, lbl = images[i], labels[i]
h, w = img.shape[:2]
# 确定当前图片在画布中的位置
if i == 0: # 左上
x1a, y1a, x2a, y2a = 0, 0, cx, cy
x1b, y1b, x2b, y2b = w-cx, h-cy, w, h # 从原图右下角裁剪
elif i == 1: # 右上
x1a, y1a, x2a, y2a = cx, 0, size, cy
x1b, y1b, x2b, y2b = 0, h-cy, w-cx, h
# ... 其他两个象限类似
# 贴图到画布
output_img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]
# 调整标注框坐标(这里容易出错!)
for label in lbl:
x, y, w_box, h_box = label[1:]
# 坐标转换要分两步:先裁剪偏移,再平移到新位置
new_x = (x * w - x1b) / (x2b - x1b) * (x2a - x1a) + x1a
new_y = (y * h - y1b) / (y2b - y1b) * (y2a - y1a) + y1a
# 记得归一化到0-1
new_x /= size
new_y /= size
output_labels.append([label[0], new_x, new_y, w_box, h_box])
return output_img, output_labels
关键点:坐标转换是Mosaic最容易翻车的地方。我建议先画个坐标系在纸上推演一遍,别直接抄代码。另外,四张图拼接后可能出现大量小目标,正负样本比例会变,可以适当调整anchor匹配阈值。
二、MixUp:两张图线性混合的“柔和增强”
MixUp的思路很数学——把两张图按比例α混合,标签也按同样比例混合。这强迫模型学习更平滑的决策边界。
def mixup(img1, labels1, img2, labels2, alpha=0.5):
# alpha从Beta分布采样,别固定死
lam = np.random.beta(alpha, alpha) if alpha > 0 else 0.5
# 混合图像(注意数据类型转换)
mixed_img = (img1.astype(np.float32) * lam +
img2.astype(np.float32) * (1 - lam)).astype(np.uint8)
# 混合标签(YOLO格式需要特殊处理)
mixed_labels = []
for label in labels1:
mixed_labels.append([label[0], label[1], label[2], label[3], label[4], lam]) # 最后加个权重
for label in labels2:
mixed_labels.append([label[0], label[1], label[2], label[3], label[4], 1-lam])
return mixed_img, mixed_labels
坑点:直接混合两张图的边界框会破坏YOLO的标签格式。我的做法是保留所有框但增加一个混合权重,计算loss时按权重加权。也有团队直接复制所有框不做混合,但这样会让模型困惑——一个位置对应两个物体?
三、CutMix:挖掉一块补上另一张的“局部移植”
CutMix更激进:随机挖掉一张图的部分区域,用另一张图的对应区域补上。标签按面积比例混合。
def cutmix(img1, labels1, img2, labels2, beta=1.0):
h, w = img1.shape[:2]
# 随机生成裁剪区域
lam = np.random.beta(beta, beta)
cut_ratio = np.sqrt(1 - lam) # 保持面积比例
cut_w = int(w * cut_ratio)
cut_h = int(h * cut_ratio)
cx = np.random.randint(w)
cy = np.random.randint(h)
x1 = max(0, cx - cut_w // 2)
y1 = max(0, cy - cut_h // 2)
x2 = min(w, cx + cut_w // 2)
y2 = min(h, cy + cut_h // 2)
# 执行“移植手术”
mixed_img = img1.copy()
mixed_img[y1:y2, x1:x2] = img2[y1:y2, x1:x2]
# 计算实际混合比例(可能因为边界裁剪而改变)
actual_lam = 1 - ((x2 - x1) * (y2 - y1) / (w * h))
# 合并标签并调整框的位置
mixed_labels = []
for label in labels1:
# 检查框是否在裁剪区域内
x_center, y_center = label[1] * w, label[2] * h
if not (x1 <= x_center <= x2 and y1 <= y_center <= y2):
mixed_labels.append(label) # 保留完整框
for label in labels2:
# 只保留在裁剪区域内的框
x_center, y_center = label[1] * w, label[2] * h
if x1 <= x_center <= x2 and y1 <= y_center <= y2:
# 坐标要转换到新图像的位置
new_label = label.copy()
new_label[1] = (x_center - x1) / w # 注意这里!x1是偏移量
new_label[2] = (y_center - y1) / h
mixed_labels.append(new_label)
return mixed_img, mixed_labels, actual_lam
经验:CutMix后标签处理要格外小心。原图的框如果被切到,应该直接丢弃(因为不完整了);补丁图的框只有完全在裁剪区内才保留。这个逻辑和实际业务场景强相关——如果你的目标经常被遮挡,可以适当放宽保留条件。
四、组合策略:不是越多越好
实际项目中我试过三种组合方式:
方案A:顺序流水线
Mosaic → 常规增强(旋转、色彩抖动)→ 随机选MixUp或CutMix
适合数据量中等、场景复杂的项目
方案B:概率抽样
每张图以0.3概率走Mosaic,0.3概率走MixUp,0.3概率走CutMix,0.1概率原图
适合追求模型鲁棒性的场景
方案C:分阶段策略
- 前50轮:Mosaic + MixUp(强增强)
- 中间30轮:只做CutMix(中等增强)
- 最后20轮:只做基础增强(弱增强)
适合小目标检测任务,前期丰富上下文,后期稳定收敛
我在交通监控项目里用方案C,小目标漏检率降了7%。关键发现是:Mosaic虽然好,但训练后期要逐渐关闭,否则模型会过度依赖“拼图”上下文,反而影响泛化。
五、部署时的注意事项
-
推理时别增强:这是新手常犯的错误,训练时用了Mosaic,部署时也拼四张图输入——完全错误!增强只在训练阶段。
-
标签格式兼容:自己写增强代码时,先统一转换成绝对坐标计算,最后再归一化。中间用相对坐标很容易累积误差。
-
内存瓶颈:Mosaic一次加载四张图,如果原图很大(比如1920x1080),批量稍大就OOM。建议在dataloader里做降采样预处理。
-
验证集处理:验证集绝对不要用这些增强!否则指标会虚高。有些框架默认对验证集做随机增强,一定要关掉。
最后给个实用建议:别盲目堆叠增强方法。先分析你的数据缺什么——缺小目标就加强Mosaic,缺遮挡场景就加强CutMix,缺类别平衡就加强MixUp。每次只改一个变量,在验证集上观察mAP变化,特别是看各类别的AP是否均衡提升。好的增强策略应该让“短板类别”受益最大。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)