通用数据增强方法(Data Augmentation)

通用数据增强方法(Data Augmentation)

1、前言

  机器学习尤其是深度学习中,为了防止模型过拟合,数据增强也是一种非常有效的方法,好多牛逼的模型除了网络结构精妙意外,在数据(比较吃数据的有监督深度学习)上也做了不可忽视的工作,才有state of the art的效果。来看一张图:

通用数据增强方法(Data Augmentation)_第1张图片

C10和C100是没有经过数据增强的训练效果,C10+和C100+则是经过数据增强的效果,提升非常明显……,这个是分类的错误率。在目标检测领域,好的算法都采用了精妙的数据增强,如YOLOv2&v3、SSD、Faster-RCNN和MASK-RCNN等。

2、数据增强

2.1 随机裁切(random crop)

   随机裁切几乎是所有深度学习框架训练都具有的数据增强方法,在很多有名的深度学习网络(VGG,AlexNet,GoogleNet,ResNet……)的训练中,对输入256*256的图像,通常会以224或227的窗口随机获得子图像作为训练,而在测试时则是以图像中心的子块(Patch)。最终使用则直接将图像resize到训练时用的crop size大小。实现也是比较简单,在红色区域内随机取点作为滑窗左上角顶点。

通用数据增强方法(Data Augmentation)_第2张图片

Python实现:

import numpy.random as npr

def randomCrop(img,size_h,size_w):

    rows,cols=img.shape[:2]

    left_h=npr.randint(0,rows-size_h)

    left_w=npr.randint(0,cols-size_w)

    crop_img=img[left_h:left_h+size_h,left_w:left_w+size_w]

    return crop_img

2.2 翻转(左右上下)

   左右翻转也叫做水平翻转或镜像(mirror),将图像的左右部分以图像垂直中轴线为中心进行镜像对换。假设原图像高度为h,宽度为w,原图像某一像素点P(x0,y0), 经过水平镜像变换后为P(w-1-x0,y0),矩阵表示:

Python代码(左右镜像):

#水平翻转
def  horizontalFlip(img):
    size = img.shape  # 获得图像的形状
    iLR = img.copy()  # 获得一个和原始图像相同的图像,注意这里要使用深度复制
    h = size[0]
    w = size[1]
    for i in range(h):  # 元素循环
        for j in range(w):
            iLR[i, w - 1 - j] = img[i, j]
    return iLR

#垂直翻转
def verticalFlip(img):
    size = img.shape  # 获得图像的形状
    iLR = img.copy()  # 获得一个和原始图像相同的图像,注意这里要使用深度复制
    h = size[0]
    w = size[1]
    for i in range(h):  # 元素循环
        for j in range(w):
            iLR[ h- 1 - i,j] = img[i, j]
    return iLR

2.3 颜色抖动(color jitter)

  颜色抖动是指对图像的曝光度(exposure)、饱和度(saturation)和色调(hue)进行随机变化形成不同光照及颜色下的图片,达到数据增强的目的,尽可能使得模型能够使用不同光照条件小的情形,提高模型泛化能力。

  YOLOv2-v3的目标检测就用到了这一数据增强方法,YOLO在训练的每一Batch中对训练数据进行在线数据增强(包括颜色抖动) ,实现上首先将图像变换到HSV颜色空间,然后对图像在HSV颜色空间中随机的改变图像的曝光度、饱和度和色调,然后再将变换后的图像转到RGB空间。具体实现代码可以参考YOLO源码(image.c),

void random_distort_image(image im, float hue, float saturation, float exposure)

{

    float dhue = rand_uniform_strong(-hue, hue);

    float dsat = rand_scale(saturation);

    float dexp = rand_scale(exposure);

    distort_image(im, dhue, dsat, dexp);

}

void distort_image(image im, float hue, float sat, float val)

{

    rgb_to_hsv(im);

    scale_image_channel(im, 1, sat);//改变S通道,该通道的像素值乘上随机sat值

    scale_image_channel(im, 2, val);//改变V通道,该通道的像素值乘上随机val值

    int i;

    for(i = 0; i < im.w*im.h; ++i){

        im.data[i] = im.data[i] + hue;//改变H通道,该通道像素值加随机hue值

        if (im.data[i] > 1) im.data[i] -= 1;

        if (im.data[i] < 0) im.data[i] += 1;

    }

    hsv_to_rgb(im);

    constrain_image(im);

}

对于部分任务也可以借鉴该方法,对样本进行离线或者在线的数据增强。

2.4 噪声(高斯噪声)

一般对图像加入高斯噪声可以使得图像变得模糊,从而模拟模糊情况。Python实现

from skimage import util
def gaussNoise(img):

    noise_img=util.random_noise(img,mode='gaussian')

    result=util.img_as_ubyte(noise_img)

    return result

2.5 旋转

图像旋转一般是以图像中心为旋转中心进行随机旋转(一般有一个正负角度约束),而。Python实现

from skimage.transform import rotate
def img_rotate(img,angle):

    return rotate(img,angle)
rotate_limit=(-30, 30)

theta = np.pi / 180 * np.random.uniform(rotate_limit[0], rotate_limit[1]) #逆

img_rot = img_rotate(img, theta)
#opencv实现
def cv_rotate(img,center,angle,scale):

    rows,cols=img.shape[:2]

    M = cv2.getRotationMatrix2D(center, angle, scale)

    dst = cv2.warpAffine(img, M, (cols, rows))

    return dst

2.6 平移

   1)图像沿着X轴或Y轴的平移有以下四种情况:

def move_right(img,dis):

    size = img.shape  # 获得图像的形状

    iLR = img.copy()  # 获得一个和原始图像相同的图像,注意这里要使用深度复制

    h = size[0]

    w = size[1]

    for i in range(h):

        for j in range(w):

            if j-dis>0:

                iLR[i,j]=img[i,j-dis]

            else:

                iLR[i, j] =0

    return iLR



def move_left(img,dis):

    size = img.shape  # 获得图像的形状

    iLR = img.copy()  # 获得一个和原始图像相同的图像,注意这里要使用深度复制

    h = size[0]

    w = size[1]

    for i in range(h):

        for j in range(w):

            if j+dis0:

                iLR[i,j]=img[i-dis,j]

            else:

                iLR[i, j] =0

    return iLR

2)图像沿着任意向量平移

参考:https://blog.csdn.net/sty945/article/details/79387054

def translate(image, x, y): #3

    M = np.float32([[1, 0, x], [0, 1, y]]) #4  //X轴移动x, Y中移动y

    shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0])) #5

    return shifted #6

2.7 缩放

   全卷积网络对于尺度没有严格要求,如目标检测算法yolov2-v3在训练过程中会对样本进行随机尺度变换(每隔10步变换一次),实现多尺度训练,进而跨尺度特征融合。同时也使得模型对于不同尺度的图像有更强的适应性。

from skimage.transform import rescale
def image_resize(img,scale):

    result=rescale(img,scale)

    return result

2.8 PCA jitter

PCA jitter是实际上对RGB颜色空间添加扰动,从而达到对RGB颜色添加噪声的目的,具体为对RGB空间做PCA,然后对主成分做一个(0, 0.1)的高斯扰动。最早使用是在2012年的AlexNet,从论文实验中可以看出,PCA jitter对于分类的性能提升比较显著。

def PCA_Jittering (img):

    img = np.asanyarray(img, dtype='float32')

    img = img / 255.0

    img_size = img.size // 3  # 转换为单通道

    img1 = img.reshape(img_size, 3)

    img1 = np.transpose(img1)  # 转置

    img_cov = np.cov([img1[0], img1[1], img1[2]])  # 协方差矩阵

    lamda, p = np.linalg.eig(img_cov)  # 得到上述协方差矩阵的特征向量和特征值


    # p是协方差矩阵的特征向量

    p = np.transpose(p)  # 转置回去



    # 生成高斯随机数********可以修改

    alpha1 = random.gauss(0, 1)

    alpha2 = random.gauss(0, 1)

    alpha3 = random.gauss(0, 1)


    # lamda是协方差矩阵的特征值

    v = np.transpose((alpha1 * lamda[0], alpha2 * lamda[1], alpha3 * lamda[2]))  # 转置


    # 得到主成分

    add_num = np.dot(p, v)


    # 在原图像的基础上加上主成分

    img2 = np.array([img[:, :, 0] + add_num[0], img[:, :, 1] + add_num[1], img[:, :, 2] + add_num[2]])


    # 现在是BGR,要转成RBG再进行保存

    img2 = np.swapaxes(img2, 0, 2)

    img2 = np.swapaxes(img2, 0, 1)

    return img2

 

 

你可能感兴趣的:(深度学习)