目标检测中图像增强,mixup 如何操作?

2019 年 2 月 5 日 极市平台

加入极市专业CV交流群,与6000+来自腾讯,华为,百度,北大,清华,中科院等名企名校视觉开发者互动交流!更有机会与李开复老师等大牛群内互动!

同时提供每月大咖直播分享、真实项目需求对接、干货资讯汇总,行业技术交流点击文末“阅读原文”立刻申请入群~


作者信息:同济大学计算机系硕士研究生 费敬敬

来源:知乎

https://www.zhihu.com/question/308572298/answer/585140274


mixup 是目前图像增强的一个小技巧,本文主要探讨了以下问题:

  • 目标检测中图像增强,mixup 是如何操作的?

  • 对于图像的 mixup 很好理解,那对于标签,mixup 是如何操作的?


以下是来自同济大学计算机系的知乎答主费敬敬(Pascal)的回答:


在讲检测之前,我们先看看mixup在图像分类是怎么用的。mixup 源于顶会ICLR的一篇论文 mixup: Beyond Empirical Risk Minimization 

(https://arxiv.org/abs/1710.09412),可以在无额外计算开销的情况下稳定提升1个百分点的图像分类精度。



当前,mixup目前主要是用于图像分类,有两种主流的实现方式,我用的好像是GluonCV版本,参考的是这个版本的代码:

https://github.com/tengshaofeng/ResidualAttentionNetwork-pytorch/blob/master/Residual-Attention-Network/train_mixup.py


  1. 对于输入的一个batch的待测图片images,我们将其和随机抽取的图片进行融合,融合比例为lam,得到混合张量inputs;

  2. 第1步中图片融合的比例lam是[0,1]之间的随机实数,符合beta分布,相加时两张图对应的每个像素值直接相加,即 inputs = lam*images + (1-lam)*images_random;

  3. 将1中得到的混合张量inputs传递给model得到输出张量outpus,随后计算损失函数时,我们针对两个图片的标签分别计算损失函数,然后按照比例lam进行损失函数的加权求和,即loss = lam * criterion(outputs, targets_a) + (1 - lam) * criterion(outputs, targets_b);


我觉得这个过程不是很好讲清楚,我们直接看PyTorch版实现代码,代码很好理解:


for i,(images,target) in enumerate(train_loader):
    # 1.input output
    images = images.cuda(non_blocking=True)
    target = torch.from_numpy(np.array(target)).float().cuda(non_blocking=True)

    # 2.mixup
    alpha=config.alpha
    lam = np.random.beta(alpha,alpha)
    index = torch.randperm(images.size(0)).cuda()
    inputs = lam*images + (1-lam)*images[index,:]
    targets_a, targets_b = target, target[index]
    outputs = model(inputs)
    loss = lam * criterion(outputs, targets_a) + (1 - lam) * criterion(outputs, targets_b)

    # 3.backward
    optimizer.zero_grad()   # reset gradient
    loss.backward()
    optimizer.step()        # update parameters of net


我们通过matplotlib来可视化mixup这个过程,二张图片的mixup结果随着lam的变化而发生渐变


for i in range(1,10):
    lam= i*0.1
    im_mixup = (im1*lam+im2*(1-lam)).astype(np.uint8)
    plt.subplot(3,3,i)
    plt.imshow(im_mixup)
plt.show()





实际代码中的lam由随机数生成器控制,lam符合参数为(alpha,alpha)的beta分布,默认取alpha=1,这里的alpha是一个超参数,比如我遇到的一个情况就是alpha=2效果更好,alpha的值越大,生成的lam偏向0.5的可能性更高。



如上就是图像分类mixup的一个pytorch实现,说完这个我们来看看检测怎么用mixup


对于目标检测的话,如果用上面这种图像mixup融合,损失函数加权相加的方式,我想就不存在标签问题了:图1 和 图2 按照比例lam进行线性融合,然后送入model进行检测分别按标签计算损失函数,然后按照lam加权相加得到最终的损失函数。



实际上,GluonCV中目标检测的mixup实现是这样子的,以下为缩减拼接版本:


class MixupDetection(Dataset):
	# mixup two images
	height = max(img1.shape[0], img2.shape[0])
	width = max(img1.shape[1], img2.shape[1])
	mix_img = mx.nd.zeros(shape=(height, width, 3), dtype='float32')
	mix_img[:img1.shape[0], :img1.shape[1], :] = img1.astype('float32') * lambd
	mix_img[:img2.shape[0], :img2.shape[1], :] += img2.astype('float32') * (1. - lambd)
	mix_img = mix_img.astype('uint8')
	y1 = np.hstack((label1, np.full((label1.shape[0], 1), lambd)))
	y2 = np.hstack((label2, np.full((label2.shape[0], 1), 1. - lambd)))
	mix_label = np.vstack((y1, y2))
	return mix_img, mix_labelfrom gluoncv.data.mixup import MixupDetectiontrain_dataset = MixupDetection(train_dataset)def train(net, train_data, val_data, eval_metric, ctx, args):
        for epoch in range(args.start_epoch, args.epochs):
        mix_ratio = 1.0
        if args.mixup:
            # TODO(zhreshold) only support evenly mixup now, target generator needs to be modified otherwise
            train_data._dataset.set_mixup(np.random.uniform, 0.5, 0.5)
            mix_ratio = 0.5
            if epoch >= args.epochs - args.no_mixup_epochs:
                train_data._dataset.set_mixup(None)
                mix_ratio = 1.0
        for i, batch in enumerate(train_data):
            with autograd.record():
                for data, label, rpn_cls_targets, rpn_box_targets, rpn_box_masks in zip(*batch):
                    # overall losses
                    losses.append(rpn_loss.sum() * mix_ratio + rcnn_loss.sum() * mix_ratio)
                    metric_losses[0].append(rpn_loss1.sum() * mix_ratio)
                    metric_losses[1].append(rpn_loss2.sum() * mix_ratio)
                    metric_losses[2].append(rcnn_loss1.sum() * mix_ratio)
                    metric_losses[3].append(rcnn_loss2.sum() * mix_ratio)
                    add_losses[0].append([[rpn_cls_targets, rpn_cls_targets>=0], [rpn_score]])
                    add_losses[1].append([[rpn_box_targets, rpn_box_masks], [rpn_box]])
                    add_losses[2].append([[cls_targets], [cls_pred]])
                    add_losses[3].append([[box_targets, box_masks], [box_pred]])
                autograd.backward(losses)train_data, val_data = get_dataloader(
    net, train_dataset, val_dataset, args.batch_size, args.num_workers)train(net, train_data, val_data, eval_metric, ctx, args)


我觉得跟我想的是一个意思,但是有些细节还没搞懂,因此没法下个定论。整个代码在图片融合那一块是没啥悬念的,但是标签的融合那一步的额外weights在代码上是怎么被用到的我没搞懂( https://github.com/dmlc/gluon-cv/blob/49be01910a8e8424b017ed3df65c4928fc918c67/gluoncv/data/mixup/detection.py#L74 )。


不管怎样,有几个点是明确的:


  1. 图片的融合是很明确的逐像素相加,融合得到的新图的尺寸是取两张图片的中的最大值,也就是说(600,800)和(900,700)两张图融合得到的新图大小是(900,800),新增的部分取零,这一步的意义是确保新图装得下原先的两张图,且不改变检测框的绝对位置;

  2. 源代码中的todo注释,表明mixup这一块还没更新完,目前代码中所采用的mixup系数是固定的,就是0.5,并没有随机生成,也就是两张图各占一半权重,从更新日期看这个坑好久没有填了。


mixup相关代码地址贴出来了,欢迎大佬们指正我的错误:

  • https://github.com/dmlc/gluon-cv/blob/49be01910a8e8424b017ed3df65c4928fc918c67/gluoncv/data/mixup/detection.py#L65

  • https://github.com/dmlc/gluon-cv/blob/428ee05d7ae4f2955ef00380a1b324b05e6bc80f/scripts/detection/faster_rcnn/train_faster_rcnn.py#L187


文中可视化代码:

https://github.com/pascal1129/CV_Notes/blob/master/codes/mixup.ipynb





*延伸阅读

Anime-InPainting: 基于Edge-Connect的图像修补工具(含大量动漫萌妹子图)

工具|ImagePy:一款基于Python的高扩展性开源图像处理框架


每月大咖直播分享、真实项目需求对接、干货资讯汇总,行业技术交流点击左下角“阅读原文”立刻申请入群~


觉得有用麻烦给个好看啦~  

登录查看更多
30

相关内容

还在修改博士论文?这份《博士论文写作技巧》为你指南
【模型泛化教程】标签平滑与Keras, TensorFlow,和深度学习
专知会员服务
20+阅读 · 2019年12月31日
【GitHub实战】Pytorch实现的小样本逼真的视频到视频转换
专知会员服务
35+阅读 · 2019年12月15日
目标检测中边界框的回归策略
极市平台
17+阅读 · 2019年9月8日
小目标检测相关技巧总结
极市平台
28+阅读 · 2019年8月15日
CVPR2019通用目标检测
极市平台
8+阅读 · 2019年8月6日
最全综述 | 图像目标检测
计算机视觉life
31+阅读 · 2019年6月24日
Kaggle实战目标检测奇淫技巧合集
极市平台
17+阅读 · 2019年6月1日
一种小目标检测中有效的数据增强方法
极市平台
119+阅读 · 2019年3月23日
PyTorch中在反向传播前为什么要手动将梯度清零?
极市平台
39+阅读 · 2019年1月23日
使用Python进行图像增强
AI研习社
17+阅读 · 2018年9月30日
用CNN分100,000类图像
极市平台
17+阅读 · 2018年1月29日
Generating Rationales in Visual Question Answering
Arxiv
5+阅读 · 2020年4月4日
Neural Module Networks for Reasoning over Text
Arxiv
9+阅读 · 2019年12月10日
Arxiv
4+阅读 · 2019年9月26日
Arxiv
3+阅读 · 2019年3月1日
Parsimonious Bayesian deep networks
Arxiv
5+阅读 · 2018年10月17日
Arxiv
4+阅读 · 2018年4月26日
Arxiv
4+阅读 · 2018年3月14日
VIP会员
相关VIP内容
还在修改博士论文?这份《博士论文写作技巧》为你指南
【模型泛化教程】标签平滑与Keras, TensorFlow,和深度学习
专知会员服务
20+阅读 · 2019年12月31日
【GitHub实战】Pytorch实现的小样本逼真的视频到视频转换
专知会员服务
35+阅读 · 2019年12月15日
相关资讯
目标检测中边界框的回归策略
极市平台
17+阅读 · 2019年9月8日
小目标检测相关技巧总结
极市平台
28+阅读 · 2019年8月15日
CVPR2019通用目标检测
极市平台
8+阅读 · 2019年8月6日
最全综述 | 图像目标检测
计算机视觉life
31+阅读 · 2019年6月24日
Kaggle实战目标检测奇淫技巧合集
极市平台
17+阅读 · 2019年6月1日
一种小目标检测中有效的数据增强方法
极市平台
119+阅读 · 2019年3月23日
PyTorch中在反向传播前为什么要手动将梯度清零?
极市平台
39+阅读 · 2019年1月23日
使用Python进行图像增强
AI研习社
17+阅读 · 2018年9月30日
用CNN分100,000类图像
极市平台
17+阅读 · 2018年1月29日
相关论文
Generating Rationales in Visual Question Answering
Arxiv
5+阅读 · 2020年4月4日
Neural Module Networks for Reasoning over Text
Arxiv
9+阅读 · 2019年12月10日
Arxiv
4+阅读 · 2019年9月26日
Arxiv
3+阅读 · 2019年3月1日
Parsimonious Bayesian deep networks
Arxiv
5+阅读 · 2018年10月17日
Arxiv
4+阅读 · 2018年4月26日
Arxiv
4+阅读 · 2018年3月14日
Top
微信扫码咨询专知VIP会员