前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >支招 | 如何用 TensorLayer 做目标检测的数据增强

支招 | 如何用 TensorLayer 做目标检测的数据增强

作者头像
AI研习社
发布2019-09-19 16:02:51
4660
发布2019-09-19 16:02:51
举报
文章被收录于专栏:AI研习社AI研习社

本文作者:@董豪,来自帝国理工学院,现已入驻AI研习社社区。欢迎扫描文末社区名片关注他的个人主页,查看更多动态。

  • Python Can Be Fasttensorlayer.readthedocs.io(https://tensorlayer.readthedocs.io/en/latest/modules/prepro.html#python-can-be-fast)
  • 最新快速数据增强方法tensorlayer.readthedocs.io(https://tensorlayer.readthedocs.io/en/latest/modules/prepro.html#python-can-be-fast)
愿回答的方法已经过时了,请看上面链接的方法。

更多新技术请扫描底部名片关注我的社区主页 (https://www.yanxishe.com/center/myPage/5160264 )或知乎专栏:TensorLayer技术分享。

======== 以下是原回答 ========

数据增强在机器学习中的作用不言而喻。和图片分类的数据增强不同,训练目标检测模型的数据增强在对图像做处理时,还需要对图片中每个目标的坐标做相应的处理。此外,位移、裁剪等操作还有可能使得一些目标在处理后只有一小部分区域保留在原图中,这需要额外的机制来判断是否需要去掉该目标来训练模型。为此TensorLayer 1.7.0发布中,提供了大量关于目标检测任务的数据集下载、目标坐标处理、数据增强的API。最近的几次发布主要面向新的卷积方式(Deformable Convolution, Depthwise ...),优化Subpixel Convolution以及提供新的递归方式(ConvLSTM)等。

首先,我们下载VOC2012数据集并对类别和坐标做预处理。tl.files.load_voc_dataset函数自动下载数据集,其返回的坐标格式和Darknet一样,则[x_c, y_c, w,h],其中x_c和y_c代表一个目标的中心在图片上的位置,w和h代表该目标的宽度和高度,这4个值是其和原图高度和宽度的比例,所以这4个值的范围在0~1之间。

代码语言:javascript
复制
tensorlayer tl


imgs_file_list, _, _, _, classes, _, _,\
    _, objs_info_list, _ = tl.files.load_voc_dataset(dataset="2012")
    

ann_list = []
info objs_info_list:
    ann = tl.prepr
    o.parse_darknet_ann_str_to_list(info)
    c, b = tl.prepro.parse_darknet_ann_list_to_cls_box(ann)
    ann_list.append([c, b])

单张图片处理

我们先对一张图片做处理,以观察tl.prepro工具箱中各个API的效果。这里我们保存2号图片的原图,以供后面做比较。

代码语言:javascript
复制
idx = 2  
image = tl.vis.read_image(imgs_file_list[idx])
tl.vis.draw_boxes_and_labels_to_image(image, ann_list[idx][0], 
     ann_list[idx][1], [], classes, True, save_name='_im_original.png')

原图 Original Image

代码语言:javascript
复制
im_flip, coords = tl.prepro.obj_box_left_right_flip(image, 
     ann_list[idx][1], is_rescale=, is_center=, is_random=)
tl.vis.draw_boxes_and_labels_to_image(im_flip, ann_list[idx][0], 
     coords, [], classes, , save_name='_im_flip.png')

左右翻转 Flip

代码语言:javascript
复制
# 位移
im_shfit, clas, coords = tl.prepro.obj_box_shift(image, ann_list[idx][0], 
         ann_list[idx][1], wrg=0.1, hrg=0.1, 
         is_rescale=True, is_center=True, is_random=False)tl.vis.draw_boxes_and_labels_to_image(im_shfit, clas, coords, [], 
         classes, True, save_name='_im_shift.png')

位移 Shift

代码语言:javascript
复制
im_zoom, clas, coords = tl.prepro.obj_box_zoom(image, ann_list[idx][0], 
         ann_list[idx][1], zoom_range=(1.3, 0.7), 
         is_rescale=, is_center=, is_random=)
tl.vis.draw_boxes_and_labels_to_image(im_zoom, clas, coords, [], 
         classes, , save_name='_im_zoom.png')

高宽缩放 Zoom

从缩放的图片中,我们可以看到一架飞机由于大部分区域被移到图像之外了,只剩下机头的一小部分,所以这个目标被去除了。tl.prepro工具箱中关于目标检测的API往往有thresh_wh和thresh_wh2两个阀值,thresh_wh表示在处理图像之后,若一个目标的宽或高和图片本身宽高的比例小于这个值,则去除该目标;thresh_wh2表示在处理图像之后,若一个目标的宽高或高宽比例小于这个值,则去除该目标。大家可以根据特定开发任务来设置这两个值,作者建议在常规情况下使用默认值。

代码语言:javascript
复制
im_resize, coords = tl.prepro.obj_box_imresize(image, 
        coords=ann_list[idx][1], size=[300, 200], is_rescale=)
tl.vis.draw_boxes_and_labels_to_image(im_resize, ann_list[idx][0], 
        coords, [], classes, , save_name='_im_resize.png')

调整大小

代码语言:javascript
复制
# 裁剪
im_crop, clas, coords = tl.prepro.obj_box_crop(image, ann_list[idx][0], 
         ann_list[idx][1], wrg=200, hrg=200, 
         is_rescale=, is_center=, is_random=)
tl.vis.draw_boxes_and_labels_to_image(im_crop, clas, coords, [], 
         classes, , save_name='_im_crop.png')

裁剪 Crop

多线程处理

实际训练模型时,我们可能会使用多线程方法来对一个batch的图片做随机的数据增强。这时,tl.prepro工具箱的API中is_random全部设为True。

代码语言:javascript
复制
import tensorlayer as tl
import random

batch_size = 64
im_size = [416, 416]   # 输出图的大小
n_data = len(imgs_file_list)
jitter = 0.2
def _data_pre_aug_fn(data):
    im, ann = data
    clas, coords = ann
    ## 随机改变图片亮度、对比度和饱和度
    im = tl.prepro.illumination(im, gamma=(0.5, 1.5), 
             contrast=(0.5, 1.5), saturation=(0.5, 1.5), is_random=True)
    ## 随机左右翻转 
    im, coords = tl.prepro.obj_box_left_right_flip(im, coords, 
             is_rescale=True, is_center=True, is_random=True)
    ## 随机调整大小并裁剪出指定大小的图片,这同时达到了随机缩放的效果
    tmp0 = random.randint(1, int(im_size[0]*jitter))
    tmp1 = random.randint(1, int(im_size[1]*jitter))
    im, coords = tl.prepro.obj_box_imresize(im, coords, 
            [im_size[0]+tmp0, im_size[1]+tmp1], is_rescale=True, 
             interp='bicubic')
    im, clas, coords = tl.prepro.obj_box_crop(im, clas, coords, 
             wrg=im_size[1], hrg=im_size[0], is_rescale=True, 
             is_center=True, is_random=True)
    ## 把数值范围从 [0, 255] 转到 [-1, 1] (可选)
    im = im / 127.5 - 1
    return im, [clas, coords]
    
# 随机读取一个batch的图片及其标记
idexs = tl.utils.get_random_int(min=0, max=n_data-1, number=batch_size)
b_im_path = [imgs_file_list[i] for i in idexs]
b_images = tl.prepro.threading_data(b_im_path, fn=tl.vis.read_image)
b_ann = [ann_list[i] for i in idexs]

# 多线程处理
data = tl.prepro.threading_data([_ for _ in zip(b_images, b_ann)], 
              _data_pre_aug_fn)
b_images2 = [d[0] for d in data]
b_ann = [d[1] for d in data]

# 保存每一组图片以供体会
for i in range(len(b_images)):
    tl.vis.draw_boxes_and_labels_to_image(b_images[i], 
             ann_list[idexs[i]][0], ann_list[idexs[i]][1], [], 
             classes, True, save_name='_bbox_vis_%d_original.png' % i)
    tl.vis.draw_boxes_and_labels_to_image((b_images2[i]+1)*127.5, 
             b_ann[i][0], b_ann[i][1], [], classes, True, 
             save_name='_bbox_vis_%d.png' % i)

最后,我们得到64组处理前和处理后的图片,下面列出2组图片以供参考。

原图

随机处理后

原图

随机处理后

处理逻辑

这就完了吗?大家认真思考一下上面的 _data_pre_aug_fn 函数做数据增强有什么潜在缺点?假设我们的训练图像高宽非常不确定的话,比如有的图是300x1000而有的图是1000x300,上面的函数一上来就把图片resize到一个正方形,会导致很多形状高宽信息丢失!

当我们的数据集存在高宽比例多样性很大时,我们需要另外的机制来解决这个问题。下面的函数中,我们的resize会根据原图高宽来决定,我们把原图最小的那个边resize成最终尺寸对应需要的大小,同时另外一个边以同比例resize(比如,如果原图高比宽小,则把高resize成最终需要的高,同时宽以相同比例resize)。做完这一步之后,我们再对其进行随机左右翻转,缩放等操作,最终裁剪出我们需要的尺寸的图。

代码语言:javascript
复制
def _data_aug_fn(self, data, jitter):
    im, ann = data
    clas, coords = ann
    ## resize到高宽合适的大小
    scale = np.max((self.im_size[1] / float(im.shape[1]), 
            self.im_size[0] / float(im.shape[0])))
    im, coords = tl.prepro.obj_box_imresize(im, coords, 
            [int(im.shape[0]*scale)+2, int(im.shape[1]*scale)+2], 
            is_rescale=True, interp='bicubic')
    ## 几何增强 geometric transformation
    im, coords = tl.prepro.obj_box_left_right_flip(im, 
            coords, is_rescale=True, is_center=True, is_random=True)
    im, clas, coords = tl.prepro.obj_box_shift(im, clas, 
            coords, wrg=0.1, hrg=0.1, is_rescale=True, 
            is_center=True, is_random=True)
    im, clas, coords = tl.prepro.obj_box_zoom(im, clas, 
            coords, zoom_range=(1-jitter, 1+jitter), 
            is_rescale=True, is_center=True, is_random=True)
    im, clas, coords = tl.prepro.obj_box_crop(im, clas, coords, 
            wrg=self.im_size[1], hrg=self.im_size[0], 
            is_rescale=True, is_center=True, is_random=True)
    ## 光度增强 photometric transformation
    im = tl.prepro.illumination(im, gamma=(0.5, 1.5), 
            contrast=(0.5, 1.5), saturation=(0.5, 1.5), is_random=True)
    im = tl.prepro.adjust_hue(im, hout=0.1, is_offset=True, 
            is_clip=True, is_random=True)
    im = tl.prepro.pixel_value_scale(im, 0.1, [0, 255], is_random=True)
    ## 把数值范围从 [0, 255] 转到 [-1, 1] (可选)
    im = im / 127.5 - 1.
    im = np.clip(im, -1., 1.)
    return im, [clas, coords]

原图

随机处理后

原图

随机处理后

原图

随机处理后

处理前

随机处理后

更新

新版本的TensorFlow发布了dataset API,自带threading功能,大家可以到下面链接获取代码。

TensorLayer结合Dataset API生成VOC:

https://github.com/tensorlayer/tensorlayer/blob/master/example/tutorial_tf_dataset_voc.py

结束语

对于产业界的朋友来说,数据增强的逻辑和业务本身是非常相关的,我们需要对不同的数据集写不同的增强代码,合理的增强逻辑往往会在相同的算法上大大提高准确性。各位还可以仔细思考一下crop和shift, zoom之间的先后问题会对图片有什么影响。TensorLayer把每一种增强行为都独立开来,以便大家完全可控地实现自己的增强算法逻辑。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI研习社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 愿回答的方法已经过时了,请看上面链接的方法。
  • 单张图片处理
  • 多线程处理
  • 处理逻辑
  • 更新
  • 结束语
相关产品与服务
图像识别
腾讯云图像识别基于深度学习等人工智能技术,提供车辆,物体及场景等检测和识别服务, 已上线产品子功能包含车辆识别,商品识别,宠物识别,文件封识别等,更多功能接口敬请期待。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档