参考来源–感兴趣请戳我戳我
<https://medium.com/nanonets/how-to-use-deep-learning-when-you-have-limited-data-part-2-data-augmentation-c26971dc8ced>
.
author是Bharath Raj <https://thatbrguy.github.io/>。
以下是翻译内容,有部分删减,感兴趣的可以读原文,该blog仅供学习。笔耕不易,互相交流。


<>can my “state-of-the-art” neural network perform well with the meagre
amount of data I have?

Yes.我们的优化目的,是当参数沿着正确的方向调整时,模型的loss可以达到最低。

<>How do I get more data, if I don’t have “more data”?

因此,为了获得更多数据,我们只需要对现有数据集进行微小改动。轻微更改,例如翻转或翻译或轮换。无论如何,我们的神经网络会认为这些是不同的图像。



卷积神经网络CNN,对放置在不同方向的对象,也能进行稳健的分类,即具有不变性的属性。更具体地,CNN对于平移,不同视角,尺度大小或光照等(或上述的组合)可以是不变的。

这基本上是数据增加的前提。在实际场景中,我们可能会在一组有限的条件下获取图像数据集。但是,我们的目标应用可能存在于各种条件下,例如不同的方向,位置,比例,亮度等。我们通过使用额外的合成对数据进行修改,并训练我们的神经网络来解释这些情况。

<>Can augmentation help even if I have lots of data?

是。它有助于增加数据集中的相关数据量。这与神经网络学习的方式有关。
Your neural network is only as good as the data you feed it.

<>Where do we augment data in our ML pipeline?


答案似乎很明显;我们在将数据提供给模型之前进行扩充吗?是的,但你有两个选择。一种选择是事先执行所有必要的转换,从根本上增加数据集的大小。另一种选择是在将小批量送到机器学习模型之前,在小批量上执行这些转换。

第一个选项称为离线扩充。对于相对较小的数据集,此方法是首选,因为您最终会将数据集的大小增加一个等于您执行的转换次数的因子(例如,通过翻转我的所有图像,我会增加数据集的大小系数为2)。

第二个选项称为在线增强,或即时增强。对于较大的数据集,此方法是首选,因为您无法承受大小的爆炸式增长。相反,您将对要提供给模型的迷你批次执行转换。一些机器学习框架支持在线增强,可以在GPU上加速。

<>Popular Augmentation Techniques


在本节中,我们将介绍一些常用但基本但功能强大的增强技术。在我们探索这些技术之前,为简单起见,让我们做一个假设。假设是,我们不需要考虑图像边界之外的东西。我们将使用以下技术,以便我们的假设是有效的。如果我们使用一种技术迫使我们猜出图像边界之外的东西,会发生什么?在这种情况下,我们需要插入一些信息。在我们介绍了增强类型之后,我们将详细讨论这个问题。对于这些技术中的每一种,我们还指定了数据集大小增加的因子(也称为数据增强因子)。

<>1、Flip

给你个图像自己体会!!!

# NumPy.'img' = A single image. flip_1 = np.fliplr(img) # TensorFlow. 'x' = A
placeholder for an image. shape = [height, width, channels] x = tf.placeholder(
dtype= tf.float32, shape = shape) flip_2 = tf.image.flip_up_down(x) flip_3 = tf.
image.flip_left_right(x) flip_4 = tf.image.random_flip_up_down(x) flip_5 = tf.
image.random_flip_left_right(x)
<>2、Rotation


关于此操作需要注意的一件事是旋转后图像尺寸可能无法保留。如果您的图像是正方形,则以直角旋转它将保留图像大小。如果它是一个矩形,旋转180度将保持大小。以更精细的角度旋转图像也会改变最终的图像尺寸。我们将在下一节中看到我们如何处理这个问题。以下是以直角旋转的方形图像的示例。

您可以使用您喜欢的包中的任何以下命令执行旋转。数据增强因子= 2到4倍
# Placeholders: 'x' = A single image, 'y' = A batch of images # 'k' denotes
the number of 90 degree anticlockwise rotations shape = [height, width, channels
] x = tf.placeholder(dtype = tf.float32, shape = shape) rot_90 = tf.image.rot90(
img, k=1) rot_180 = tf.image.rot90(img, k=2) # To rotate in any angle. In the
example below, 'angles' is in radians shape = [batch, height, width, 3] y = tf.
placeholder(dtype = tf.float32, shape = shape) rot_tf_180 = tf.contrib.image.
rotate(y, angles=3.1415) # Scikit-Image. 'angle' = Degrees. 'img' = Input Image
# For details about 'mode', checkout the interpolation section below. rot =
skimage.transform.rotate(img, angle=45, mode='reflect')
<>3、Scale


图像可以向外或向内缩放。向外缩放时,最终图像尺寸将大于原始图像尺寸。大多数图像框架从新图像中剪切出一个部分,其大小等于原始图像。我们将在下一节中处理向内缩放,因为它会缩小图像大小,迫使我们对超出边界的内容做出假设。以下是缩放的示例或图像。

您可以使用scikit-image使用以下命令执行缩放。数据增强因子=任意。
# Scikit Image. 'img' = Input Image, 'scale' = Scale factor # For details
about 'mode', checkout the interpolation section below. scale_out = skimage.
transform.rescale(img, scale=2.0, mode='constant') scale_in = skimage.transform.
rescale(img, scale=0.5, mode='constant') # Don't forget to crop the images back
to the original size (for # scale_out)
<>4、Crop

与缩放不同,我们只是从原始图像中随机抽样一个部分。
然后,我们将此部分的大小调整为原始图像大小。
这种方法通常称为随机裁剪。
以下是随机裁剪的示例。
仔细观察,您会发现此方法与缩放之间的区别。

您可以使用以下任何TensorFlow命令执行随机裁剪。数据增强因子=任意。
# TensorFlow. 'x' = A placeholder for an image. original_size = [height, width,
channels] x = tf.placeholder(dtype = tf.float32, shape = original_size) # Use
the following commands to perform random crops crop_size = [new_height,
new_width, channels] seed = np.random.randint(1234) x = tf.random_crop(x, size =
crop_size, seed = seed) output = tf.images.resize_images(x, size =
original_size)
<>5、Translation


翻译只涉及沿X或Y方向(或两者)移动图像。在下面的示例中,我们假设图像在其边界之外具有黑色背景,并且被适当地翻译。这种增强方法非常有用,因为大多数对象几乎可以位于图像的任何位置。这迫使你的卷积神经网络无处不在。

您可以使用以下命令在TensorFlow中执行转换。
数据增强因子=任意
# pad_left, pad_right, pad_top, pad_bottom denote the pixel # displacement.
Set one of them to the desired value and rest to 0 shape = [batch, height, width
, channels] x = tf.placeholder(dtype = tf.float32, shape = shape) # We use two
functions to get our desired augmentation x = tf.image.pad_to_bounding_box(x,
pad_top, pad_left, height + pad_bottom + pad_top, width + pad_right + pad_left)
output= tf.image.crop_to_bounding_box(x, pad_bottom, pad_right, height, width)
<>6、Gaussion Noise


当您的神经网络试图学习可能无用的高频特征(大量出现的模式)时,通常会发生过度拟合。具有零均值的高斯噪声基本上在所有频率中具有数据点,从而有效地扭曲高频特征。这也意味着较低频率的组件(通常是您的预期数据)也会失真,但您的神经网络可以学会超越它。添加适量的噪音可以增强学习能力。一个色调较低的版本是盐和胡椒噪音,它表现为随机的黑白像素在图像中传播。这类似于通过向图像添加高斯噪声而产生的效果,但可能具有较低的信息失真水平。

您可以在TensorFlow上使用以下命令为图像添加高斯噪声。数据增强因子= 2x。
#TensorFlow. 'x' = A placeholder for an image. shape = [height, width, channels
] x = tf.placeholder(dtype = tf.float32, shape = shape) # Adding Gaussian noise
noise= tf.random_normal(shape=tf.shape(x), mean=0.0, stddev=1.0, dtype=tf.
float32) output = tf.add(x, noise)
<>Advanced Augmentation Techniques高级增强技术


现实世界中,原始数据仍然可以存在于上述简单方法无法解释的各种条件下。例如,识别照片中景观(山水)。景观可以是任何东西:冰苔原,草原,森林等。听起来像一个非常直接的分类任务吧?除了一件事,你是对的。我们忽略了影响表演的照片中的一个重要特征
- 拍摄照片的季节。
如果我们的神经网络不了解某些景观可以在各种条件下(雪,潮湿,明亮等)存在的事实,它可能会将冰冻的湖岸错误地标记为冰川或将湿地标记为沼泽。
缓解这种情况的一种方法是添加更多图片,以便我们考虑所有季节性变化。但这是一项艰巨的任务。扩展我们的数据增强概念,想象一下人工生成不同季节的效果有多酷?

<>GAN来拯救你


在没有加入细节的情况下,条件GAN可以将图像从一个域转换为图像到另一个域。如果你认为这听起来太模糊,No;这就是这个神经网络的强大功能!以下是用于将夏季风景照片转换为冬季风景的条件GAN的示例。

Changing seasons using a CycleGAN (Source)
<https://junyanz.github.io/CycleGAN/>

上述方法是稳健的,但计算密集。更便宜的替代品将被称为神经风格转移。它抓取一个图像(又称“风格”)的纹理/氛围/外观,并将其与另一个图像的内容混合。使用这种强大的技术,我们产生类似于条件GAN的效果(事实上,这种方法是在cGAN发明之前引入的!)。
这种方法的唯一缺点是,输出看起来更具艺术性而非现实性。但是,有一些进步,如下面显示的深度照片风格转移,有令人印象深刻的结果。

深度照片风格转移。请注意我们如何在数据集上生成我们想要的效果。(来源
<https://blog.csdn.net/u010801994/article/details/https://arxiv.org/abs/1703.07511>

我们没有深入探索这些技术,因为我们并不关心它们的内在工作。我们可以使用现有的训练模型,以及转移学习的魔力,将其用于增强。

<>A brief note on interpolation关于插值的简要说明


如果您想要翻译不具有黑色背景的图像,该怎么办?如果你想向内扩展怎么办?或者以更精细的角度旋转?在我们执行这些转换后,我们需要保留原始图像大小。由于我们的图像没有关于其边界之外的任何信息,我们需要做出一些假设。通常,假设图像边界之外的空间在每个点都是常数0。因此,当您进行这些转换时,会得到一个未定义图像的黑色区域。

从左侧开始,图像逆时针旋转45度,图像向右旋转,图像向内缩放。
**但这是正确的假设吗?**在现实世界的情况下,大多数不是。图像处理和ML框架有一些标准方法,您可以使用它们来决定如何填充未知空间。它们的定义如下。

从左边开始,我们有constant, edge, reflect, symmetric and wrap模式。

<>1、Constant

最简单的插值方法是用一些常数值填充未知区域。这可能不适用于自然图像,但可以用于在单色背景下拍摄的图像。

<>2、Edge

在边界之后扩展图像的边缘值。此方法适用于温和的translations。

<>3、Relect

图像像素值沿图像边界反射。此方法适用于包含树木,山脉等的连续或自然背景。

<>4、Symmetric对称

该方法类似于反射,除了在反射边界处制作边缘像素的副本的事实。通常,反射和对称可以互换使用,但在处理非常小的图像或图案时会出现差异。

<>5、Wrap

图像只是重复超出其边界,就好像它正在平铺一样。这种方法并不像其他方法那样普遍使用,因为它对很多场景都没有意义。
除此之外,您可以设计自己的方法来处理未定义的空间,但通常这些方法对大多数分类问题都可以。

<>So, if I use ALL of these techniques, my ML algorithm would be robust right?

如果你以正确的方式使用它,那么是的!你问的正确方法是什么?好吧,有时并非所有的增强技术都对数据集有意义。再考虑我们的汽车示例。以下是一些修改图像的方法。

第一幅图像(左起)是原始图像,第二张图像是水平翻转,第三张图像旋转180度,最后一张图像旋转90度(顺时针)。
当然,它们是同一辆车的照片,但您的目标应用可能永远不会看到以这些方向呈现的汽车。

例如,如果您只是想在路上对随机汽车进行分类,那么只有第二张图像才能在数据集上进行分类。但是,如果你拥有一家处理车祸的保险公司,并且你想要确定倒车,破车的车型,那么第三张图片就有意义了。对于上述两种情况,最后一张图像可能没有意义。
关键是,在使用增强技术时,我们必须确保不增加不相关的数据。

<>Is it really worth the effort?

你可能期待一些结果来激励你走得更远。很公平;我也有这个问题。让我用玩具示例证明增强确实有效。您可以复制此实验以进行验证。
让我们创建两个神经网络,将数据分类为四类中的一类:猫,狮子,老虎或豹子。问题是,一个不会使用数据增加,而另一个则不会。您可以从此处下载数据集link
<https://drive.google.com/drive/folders/1GpIpbqBQ_ak1Z_4yAj7t6YRqDDyyBbAq>。(
ps:需要翻墙,打不开的可留邮箱给我)
如果你已经检查了数据集,你会发现每个类只有50个图像用于训练和测试。显然,我们不能对其中一个分类器使用扩充。为了使赔率更公平,我们使用 Transfer
Learning
<https://medium.com/nanonets/nanonets-how-to-use-deep-learning-when-you-have-limited-data-f68c0b512cab>
为模型提供了更少的数据量。

对于没有增强的那个,让我们使用VGG19网络。我在这里写了一个TensorFlow实现
<https://github.com/thatbrguy/VGG19-Transfer-Learn>,它基于here
<https://github.com/machrisaa/tensorflow-vgg>
这个实现。一旦你克隆了我的仓库,就可以从这里(同上data)获取数据集,并从这里获取vgg19.npy
<https://mega.nz/#!xZ8glS6J!MAnE91ND_WyfZ_8mvkuSa2YcA7q-1ehfSm-Q1fxOvvs>
(用于转移学习)。您现在可以运行模型来验证性能。
我同意,编写额外的数据扩充代码确实是一种努力。所以,为了建立我们的第二个模型,我转向Nanonets
<https://nanonets.com/?utm_source=Medium&utm_campaign=data%20augmentation/>
。他们在内部使用转移学习和数据扩充,以使用最少的数据提供最佳结果。您需要做的就是在他们的网站
<https://blog.csdn.net/u010801994/article/details/81914716>
上传数据,并等待它们在他们的服务器上训练(通常大约30分钟)。你知道什么,它对我们的比较实验来说是完美的。
完成培训后,您可以请求调用其API来计算测试准确度。查看我的仓库以获取示例代码段(不要忘记在代码段中插入您的模型ID)。
Results VGG19 (No Augmentation)- 76% Test Accuracy (Highest) Nanonets (With
Augmentation) - 94.5% Test Accuracy
令人印象深刻的不是它。事实上,大多数模型在更多数据的情况下表现良好。所以为了提供一个具体的证明,我已经提到了下表。它显示了Cifar
10(C10)和Cifar 100(C100)数据集上流行神经网络的错误率。C10 +和C100 +列是数据增加的错误率。

原作者电子邮件(bharathrajn98@gmail.com)。