094、YOLOv8改进实战:Copy-Paste增强在目标检测中的应用与YOLOv8代码实现

发布时间:2026/7/29 15:21:35
094、YOLOv8改进实战:Copy-Paste增强在目标检测中的应用与YOLOv8代码实现 094、YOLOv8改进实战Copy-Paste增强在目标检测中的应用与YOLOv8代码实现上个月调一个密集小目标场景的模型mAP卡在0.52死活上不去。试了Mosaic、MixUp、CutMix效果都一般。后来翻到一篇2020年的论文Copy-Paste增强抱着试试看的心态改了一版mAP直接跳到0.61。今天把这个坑填上聊聊Copy-Paste在YOLOv8里的落地实现。为什么Mosaic搞不定密集小目标Mosaic把四张图拼在一起确实增加了小目标数量但有个致命问题——小目标在拼接后变得更小了。原本32x32的物体缩放到原图1/4区域后变成16x16特征图上的响应几乎消失。Copy-Paste的思路完全不同直接把目标对象复制粘贴到其他图片上目标尺寸不变只是换个背景。这个思路在工业场景特别实用。比如检测生产线上的螺丝正常样本里螺丝分布稀疏Copy-Paste可以制造出密集场景模型被迫学会区分重叠目标。Copy-Paste的核心逻辑简单说就是三步从源图抠出目标随机选个位置贴到目标图处理遮挡关系。但落地时有两个关键点容易翻车。第一个坑是标签处理。粘贴后目标框坐标变了需要重新计算。如果粘贴位置和原有目标重叠要不要保留我的做法是保留所有目标让模型自己去学遮挡情况。实验证明保留遮挡目标比删除效果好3-4个点。第二个坑是粘贴比例。贴太多会破坏背景分布模型学会有目标的地方背景就奇怪。我控制在每张图最多贴3个目标超过这个数效果反而下降。YOLOv8代码实现先看数据加载部分。YOLOv8的Dataset类在ultralytics/data/dataset.py里我们需要在load_mosaic方法后面加一个分支。defload_copy_paste(self,index):# 这里踩过坑直接修改原图会导致后续epoch数据重复# 正确做法是每次随机选择源图和目标图ifrandom.random()self.copy_paste_prob:# 控制概率我设0.5returnself.load_image(index)# 随机选一张源图别选同一张src_idxrandom.choice([iforiinrange(len(self.im_files))ifi!index])src_img,src_hypself.load_image(src_idx)# 获取源图的目标框和类别src_labelsself.labels[src_idx].copy()iflen(src_labels)0:returnself.load_image(index)# 源图没目标就跳过# 随机选一个目标来粘贴obj_idxrandom.randint(0,len(src_labels)-1)obj_boxsrc_labels[obj_idx][1:5]# xywh格式obj_clssrc_labels[obj_idx][0]# 抠出目标区域这里别用cv2.resize会改变目标尺寸x1,y1,x2,y2self.xywh2xyxy(obj_box)obj_patchsrc_img[int(y1):int(y2),int(x1):int(x2)].copy()# 随机生成粘贴位置保证目标完全在图像内h,wsrc_img.shape[:2]paste_xrandom.randint(0,w-(x2-x1))paste_yrandom.randint(0,h-(y2-y1))# 粘贴操作这里用alpha blending效果更好# 简单做法直接覆盖但边缘会有锯齿target_imgself.load_image(index)[0]target_img[paste_y:paste_yobj_patch.shape[0],paste_x:paste_xobj_patch.shape[1]]obj_patch# 更新标签添加新目标框new_box[obj_cls,(paste_xpaste_xobj_patch.shape[1])/2/w,# cx(paste_ypaste_yobj_patch.shape[0])/2/h,# cyobj_patch.shape[1]/w,# wobj_patch.shape[0]/h]# hself.labels[index]np.vstack([self.labels[index],new_box])returntarget_img这个实现有个问题——每次都要加载两张图训练速度会下降。我的优化方案是预加载一批图到缓存随机选源图时从缓存里取。训练配置在YOLOv8的配置文件中添加参数# copy_paste增强参数copy_paste:0.5# 应用概率copy_paste_max_objects:3# 每张图最多贴几个copy_paste_scale_range:[0.5,1.5]# 目标缩放范围别太大注意copy_paste_scale_range这个参数。我一开始没加缩放模型对固定尺寸目标过拟合。加上0.5到1.5的随机缩放后泛化能力明显提升。踩过的坑第一个坑是类别不平衡。如果源图里某个类别特别多粘贴后这个类别的样本会爆炸。我加了类别采样权重让每个类别被选中的概率均衡。第二个坑是背景污染。粘贴的目标边缘有原背景的像素导致模型学到目标周围有特定颜色。解决方案是用高斯模糊处理边缘或者用泊松融合。第三个坑是标签格式。YOLOv8的标签是归一化的粘贴后要重新计算归一化坐标。我在这里debug了半小时因为忘记把像素坐标转成归一化坐标。效果对比在VisDrone数据集上不加Copy-Paste的mAP是0.52加了之后0.61。提升主要来自小目标类别比如行人从0.38涨到0.49自行车从0.41涨到0.53。但注意这个增强对中大目标效果不明显甚至可能下降。因为中大目标本身特征丰富粘贴后反而引入噪声。我建议只在密集小目标场景使用。个人经验Copy-Paste不是万能药。如果你的数据集目标分布均匀MosaicMixUp的组合就够了。但遇到以下情况Copy-Paste值得一试目标尺寸小于32x32、同类目标经常重叠、背景单一但目标密集。另外训练轮数要适当增加。Copy-Paste增加了数据复杂度我通常把epoch从300调到400让模型充分学习粘贴后的分布。最后提醒一点验证集不要用Copy-Paste。我见过有人把增强用在验证集上结果mAP虚高上线后直接翻车。