数据增强之Mosaic (Mixup,Cutout,CutMix)

1、简介和比较

Mosaic数据增强方法是YOLOV4论文中提出来的,主要思想是将四张图片进行随机裁剪,再拼接到一张图上作为训练数据。这样做的好处是丰富了图片的背景,并且四张图片拼接在一起变相地提高了batch_size,在进行batch normalization的时候也会计算四张图片,所以对本身batch_size不是很依赖,单块GPU就可以训练YOLOV4。

https://github.com/Tianxiaomo/pytorch-YOLOv4​github.com/Tianxiaomo/pytorch-YOLOv4

另外几种常见的数据增强的比较

  • Mixup:将随机的两张样本按比例混合,分类的结果按比例分配;
  • Cutout:随机的将样本中的部分区域cut掉,并且填充0像素值,分类的结果不变;
  • CutMix:就是将一部分区域cut掉但不填充0像素而是随机填充训练集中的其他数据的区域像素值,分类结果按一定的比例分配

区别
上述三种数据增强的区别:

  1. cutout和cutmix就是填充区域像素值的区别;
  2. mixup和cutmix是混合两种样本方式上的区别:
  3. mixup是将两张图按比例进行插值来混合样本,cutmix是采用cut部分区域再补丁的形式去混合图像,不会有图像混合后不自然的情形。

优点

  1. 在训练过程中不会出现非信息像素,从而能够提高训练效率;
  2. 保留了regional dropout的优势,能够关注目标的non-discriminative parts;
  3. 通过要求模型从局部视图识别对象,对cut区域中添加其他样本的信息,能够进一步增强模型的定位能力;
  4. 不会有图像混合后不自然的情形,能够提升模型分类的表现;
  5. 训练和推理代价保持不变。

2、Mosaic实现方法及细节

Yolov4的mosaic数据增强参考了CutMix数据增强方式, 是CutMix数据增强方法的改进版。Mosaic数据增强利用了四张图片,对四张图片进行拼接,每一张图片都有其对应的框,将四张图片拼接之后就获得一张新的图片,同时也获得这张图片对应的框,然后我们将这样一张新的图片传入到神经网络当中去学习,相当于一下子传入四张图片进行学习了。论文中说这极大丰富了检测物体的背景!且在标准化BN计算的时候一下子会计算四张图片的数据!如下图所示:

这里以对Voc2007数据集进行随机数据增强为例进行讲解,大致分为四步:

Step.1: 从Voc数据集中每次随机读取四张图片

Step.2 : 分别对四张图片进行翻转(对原始图片进行左右的翻转)、缩放(对原始图片进行大小的缩放)、色域变化(对原始图片的明亮度、饱和度、色调进行改变)等操作

操作完成之后然后再将原始图片按照 第一张图片摆放在左上,第二张图片摆放在左下,第三张图片摆放在右下,第四张图片摆放在右上四个方向位置摆好。

Step.3 : 进行图片的组合和框的组合

完成四张图片的摆放之后,我们利用矩阵的方式将四张图片它固定的区域截取下来,然后将它们拼接起来,拼接成一 张新的图片,新的图片上含有框框等一系列的内容。

如上图可以看到将四张图片进行拼接的时候有很明显的边缘,横线和竖线就是分割的线,这个分割线是由我们人为事先预先设定好了的,在代码中由min_offset_x和min_offset_y去选取分割的线。

拼接完成之后得到的新的一张图片,我们可以看到拼接的图片的左上角的图相对于原图来说是少了的,因为拼接的时候被它右边的图覆盖掉了,拼接的时候很有可能也会把另外的图中的框给覆盖掉,这些问题都会在最后的对框进行处理:当图片的框(或者图片本身)超出两张图片之间的边缘(也就是我们设置的分割线)的时候,我们就需要把这个超出分割线的部分框或者图片的部分)处理掉,进行边缘处理。

3、源码解读

https://github.com/Tianxiaomo/pytorch-YOLOv4/blob/master/dataset.py​github.com/Tianxiaomo/pytorch-YOLOv4/blob/master/dataset.py

图1

部分代码:300

oh, ow, oc = img.shape    # img为读取的图片数据      
# self.cfg.jitter为cfg文件中的参数,默认给的是0.2                                              
dh, dw, dc = np.array(np.array([oh, ow, oc]) * self.cfg.jitter, dtype=np.int)  
# 首先生成一些随机偏移的坐标,分别代表左右上下                                    
pleft = random.randint(-dw, dw)   
pright = random.randint(-dw, dw)  
ptop = random.randint(-dh, dh)    
pbot = random.randint(-dh, dh) 
# 裁剪部分的长和宽
swidth = ow - pleft - pright
sheight = oh - ptop - pbot     

整个Mosaic过程如图一所示,图一展示的是pleft,pright,ptop,pbot都大于0时的情况,首先在原图上找到以(pleft,pright)为左上角,swidth,sheight为宽和长的矩形,然后取这个矩形和原图的交集(也就是深绿色的部分)。

注意:图1中(2)这里不是直接取的交集出来,而是先创建一个宽为swidth,长为sheight的矩形,再将矩形赋值为原图RGB三个通道的均值,然后再将上面说的交集部分根据计算的坐标放在这个矩形上面,只不过图一是基于pleft,pright,ptop,pbot都大于0时的情况,所以正好放在(0, 0)坐标上。具体可以参考一以下代码。

部分代码:112

# new_src_rect也就是上面说的交集的坐标(x1, y1, x2, y2)
 new_src_rect = rect_intersection(src_rect, img_rect)                                                                                                                        
 dst_rect = [max(0, -pleft), max(0, -ptop), max(0, -pleft) + new_src_rect[2] - new_src_rect[0], 
             max(0, -ptop) + new_src_rect[3] - new_src_rect[1]]  
                                            
cropped = np.zeros([sheight, swidth, 3])                                   
cropped[:, :, ] = np.mean(img, axis=(0, 1))                                
# 这里就是将交集部分放在矩形上                                                      
cropped[dst_rect[1]:dst_rect[3], dst_rect[0]:dst_rect[2]] = \              
    img[new_src_rect[1]:new_src_rect[3], new_src_rect[0]:new_src_rect[2]]  

然后对图片进行resize,resize为网络输入所需要的分辨率,默认情况下就是608x608大小。然后根据计算的左上坐标,以及随机得到的宽CutX,长Cuty,裁剪一部分区域作为一张新图的左上部分。图1中(4)红框表示裁剪的区域,注意:图1中(4)左上角的(0, 0)坐标是因为pleft,pright大于0,根据计算所得。计算裁剪坐标的过程可参照以下代码。

部分代码:279
# 根据网络的输入大小随机计算的cut_x、cut_y,min_offset为预设参数,默认为0.2
# cfg.w,cfg.h为网络的输入大小,默认为608
if use_mixup == 3:
 min_offset = 0.2
 cut_x = random.randint(int(self.cfg.w * min_offset), int(self.cfg.w * (1 - min_offset)))
 cut_y = random.randint(int(self.cfg.h * min_offset), int(self.cfg.h * (1 - min_offset)))
# 裁剪坐标的计算过程                                                                                 
left_shift = int(min(cut_x, max(0, (-int(pleft) * self.cfg.w / swidth))))                         
top_shift = int(min(cut_y, max(0, (-int(ptop) * self.cfg.h / sheight))))                          
                                                                                                  
right_shift = int(min((self.cfg.w - cut_x), max(0, (-int(pright) * self.cfg.w / swidth))))        
bot_shift = int(min(self.cfg.h - cut_y, max(0, (-int(pbot) * self.cfg.h / sheight))))               
# 这里的ai参数为图一中的(3), out_img初始化的新图
# 该函数的功能就是图1中(3)到(5)的过程,分别将裁剪的图片粘贴到新图的左上,右上,左下,右下
# 循环4次,每循环一次粘贴一次,每次根据给的参数i粘贴到哪个部分                                       
out_img, out_bbox = blend_truth_mosaic(out_img, ai, truth.copy(), self.cfg.w, self.cfg.h, cut_x,  
                                       cut_y, i, left_shift, right_shift, top_shift, bot_shift)   

以下是blend_truth_mosaic函数细节:

213
def blend_truth_mosaic(out_img, img, bboxes, w, h, cut_x, cut_y, i_mixup,                                        
                       left_shift, right_shift, top_shift, bot_shift):                                           
    left_shift = min(left_shift, w - cut_x)                                                                      
    top_shift = min(top_shift, h - cut_y)                                                                        
    right_shift = min(right_shift, cut_x)                                                                        
    bot_shift = min(bot_shift, cut_y)                                                                            
                                                                                                                 
    if i_mixup == 0:                                                                                             
        bboxes = filter_truth(bboxes, left_shift, top_shift, cut_x, cut_y, 0, 0)                                 
        out_img[:cut_y, :cut_x] = img[top_shift:top_shift + cut_y, left_shift:left_shift + cut_x]                
    if i_mixup == 1:                                                                                             
        bboxes = filter_truth(bboxes, cut_x - right_shift, top_shift, w - cut_x, cut_y, cut_x, 0)                
        out_img[:cut_y, cut_x:] = img[top_shift:top_shift + cut_y, cut_x - right_shift:w - right_shift]          
    if i_mixup == 2:                                                                                             
        bboxes = filter_truth(bboxes, left_shift, cut_y - bot_shift, cut_x, h - cut_y, 0, cut_y)                 
        out_img[cut_y:, :cut_x] = img[cut_y - bot_shift:h - bot_shift, left_shift:left_shift + cut_x]            
    if i_mixup == 3:                                                                                             
        bboxes = filter_truth(bboxes, cut_x - right_shift, cut_y - bot_shift, w - cut_x, h - cut_y, cut_x, cut_y)
        out_img[cut_y:, cut_x:] = img[cut_y - bot_shift:h - bot_shift, cut_x - right_shift:w - right_shift]      
                                                                                                                 
    return out_img, bboxes                                                                                       

最后说明一下对于标签框的处理,图1中可以看到,当进行裁剪的时候,如果裁剪了样本当中的标签框的部分区域,则将其舍弃,保留裁剪之后还完整的标签框。

下图为pleft,pright,ptop,pbot都小于0的裁剪情况:

YOLOV4-Mosaic数据增强详解_Q1u1NG的博客-CSDN博客_mosaic数据增强

YoloV4当中的Mosaic数据增强方法(附代码讲解)_哆啦A梦爱学习的博客-CSDN博客_mosaic数据增强代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值