这些情况我们都经历过。你精通机器学习的相关概念,并能将其应用于机器学习模型。打开浏览器搜索相关数据,很可能会找到一系列数据以及上百幅相关照片。
你会想起大部分流行的数据集拥有数以千计的图片(甚至更多)。你也会想起有人曾说过拥有大规模的数据集对性能至关重要。你会感到失望,非常想知道:在有限的数据量下,顶级神经网络能不能很好地工作?
回答是肯定的,但在见证奇迹之前,我们需要思考一些基本问题。
为什么需要大量的数据
常用的神经网络的参数数量。
当你训练一个机器学习模型时,你实际做工作的是调参,以便将特定的输入(一副图像)映像到输出(标签)。我们优化的目标是使模型的损失最小化, 以正确的方式调节优化参数即可实现这一目标。
成功的神经网络拥有数以百万计的参数!
自然,如果你有大量参数,就需要提供你的机器学习模型同比例的实例,以获得优秀的性能。你需要的参数数量与需要执行的任务复杂性也成比例。
在没有大量数据情况下,如何获取更多数据?
其实,你并不需要添加大量的图像到你的数据集,为什么? 因为,神经网络从一开始就不是智能的,例如,缺乏训练的神经网络会认为下面这3个网球是不同的、独立的图像。
完全一样的网球,神经网络的解释却不同。
所以,为了获得更多数据,我们仅需要对已有的数据集做微小的调整。比如翻转、平移或旋转。神经网络会认为这些数据是不同的。
运动中的数据增强
一个卷积神经网络有一个称作不变性的性质,即使卷积神经网络被放在不同方向上,它也能进行对象分类。更具体的说,卷积神经网络对平移、视角、尺寸或照度(或以上组合)保持不变性。
这就是数据增强的本质前提。在现实世界中,我们可能会有一组在有限的条件下拍摄的图像 。但是,我们的目标应用可能是在多变的环境中,例如,不同的方向、位置、比例、亮度等。我们通过使用经综合修改过的数据来训练神经网络,以应对这些情形。
即使拥有大量数据,再增强数据也是有帮助的吗?
当然。这会有助于增加数据集中相关数据的数量。 这与神经网络的学习方法相关,让我通过一个例子来说明。
假设数据集中的两个类。左边的代表品牌A(福特),右边的代表品牌B(雪佛兰)。
假设完成了训练,并且输入上面的图像,即品牌A。但是你的神经网络输出认为它是品牌B的汽车!使用先进的神经网络不是应该有95%的正确率吗?我不是夸大其词,类似的事情在过去也发生过。
福特汽车(品牌A),但面向右侧。
为什么会发生这种现象?因为这是大多数机器学习算法就是这么工作的。它会寻找区分一个类和另一个类的最明显特征。在这个例子中 ,这个特征就是所有品牌A的汽车朝向左边,所有品牌B的汽车朝向右边。
神经网络的好坏取决于输入的数据。
我们如何预防这种现象发生? 我们需要减少数据集中不相关特征的数量。对上面的汽车类型分类器来说,一个最简单的解决办法就是为数据集中的每种类别都添加朝向不同方向的汽车照片。更好的办法是,你只需要将现有的数据集中的照片水平翻转,使汽车朝向另一侧。现在,用新的数据集训练神经网络,你就会得到你想要的结果。
通过增强数据集,可以防止神经网络学习到不相关的模式,根本上提升整体性能。
准备开始
在我们深入研究各种增强技术之前,我们必须先考虑一个问题。
在机器学习过程中的什么位置进行数据增强?
答案相当明显:在向模型输入数据之前增强数据集,对吗?是的,但你有两个选项,一个是预先进行所有必要的变换,从根本上增加数据集的规模。另外一个是小批量执行变换,仅仅在输入机器学习模型之前。
- 第一项被称为离线增强。这个方法常被用于相对较小的数据集。因为你最终会通过一个与执行的转换数量相等的因子来增加数据集的大小(例如,通过翻转所有图像,数据集数量会增加2倍)。
- 第二个选项称为在线增强,或称为动态增强。主要应用于规模较大的数据集,因为你无法负担数据量爆炸性增长。反而,你可以通过对即将输入模型的小批量数据的执行相应的变化。很多机器学习架构已经支持在线增强,并可以利用GPU进行加速。
常用的增强技术
在这一节,我们将介绍一些基础但功能强大的增强技术,这些技术目前被广泛应用。在我们讲述这些技术之前,为简单起见,让我们做一个假设,即我们不需要关心图片边界之外的东西。如果使用下面的技术,我们的假设将是有效的。
如果使用的技术关注图像边界之外的区域,将会发生什么呢?在这种情况下,我们需要插入一些信息。在讨论完数据增强的类型后我们在详细讨论这一问题。
我们为每个技术都定义了一个增强因子,用以增强数据集(也成为数据增强因子)。
1. 翻转
你可以水平或垂直翻转图像。一些架构并不支持垂直翻转图像。但,垂直翻转等价于将图片旋转180再水平翻转。下面就是图像翻转的例子。
从左侧开始分别是:原始图像,水平翻转图像,垂直翻转图像。
可以通过执行下面的命令完成图像翻转。
2. 旋转
关于这个操作,需要注意的一个关键问题是,在旋转之后,图像维度可能不会被保留。如果是正方型图像,旋转90度之后图像的尺寸会被保存。如果图像是长方形,旋转180度之后图像尺寸也会保存。 但用更小的角度旋转图像,将会改变最终图像的尺寸。在下面的章节中我们将会看到如何解决这个问题。下面是方形图像旋转90度的例子。
当我们从左到右移动时,图像相对于前一个图像顺时针旋转90度。
你可以执行下面的任一命令完成图像旋转。 数据增强因子 = 2 到 4x
3. 缩放
图像可以被放大或缩小。放大时,放大后的图像尺寸会大于原始尺寸。大多数图像处理架构会按照原始尺寸对放大后的图像进行裁切。我们将在下一章节讨论图像缩小,因为图像缩小会减小图像尺寸,这使我们不得不对图像边界之外的东西做出假设。下面是图像缩放的例子。
从左边开始分别为:原始图像,图像向外缩放10%,图像向外缩放20%。
通过下面的命令执行图像缩放。数据增强因子=任意。
4. 裁剪
与缩放不同,我们随机从原始图像中采样一部分。然后将这部分图像调整为原始图像大小。这个方法更流行的叫法是随机裁剪。下面是随机裁剪的例子。如果你靠近了看,你会注意到裁剪和缩放两种技术之间的区别。
从左侧开始分别为:原始图像,从左上角裁剪出一个正方形部分,然后从右下角裁剪出一个正方形部分。剪裁的部分被调整为原始图像大小。
通过下面的TensorFlow命令你可以执行随机裁剪。 数据增强因子=任意。
5. 平移
平移是将图像沿X或Y方向(或者同时沿2个方向)移动。在下面的例子中, 我们假设在图像边界之外是黑色的背景,也同步被移动。这一数据增强方法非常有用,因为大多数对象有可能分布在图像的任何地方。这迫使你的卷积神经网络需要看到所有地方。
从左侧开始分别为:原始图像,图像翻转到右侧,图像向上翻转。
在TensorFlow中,可以通过如下命令完成图像平移。数据增强因子=任意。
6. 高斯噪声
过拟合(Overfitting)经常会发生在神经网络试图学习高频特征(即非常频繁出现的无意义模式)的时候,而学习这些高频特征对模型提升没什么帮助。
那么如何处理这些高频特征呢?一种方法是采用具有零均值特性的高斯噪声,它实质上在所有频率上都能产生数据点,可以有效的使高频特征失真,减弱其对模型的影响。
但这也意味着低频的成分(通常是你关心的特征)同时也会受到影响,但是神经网络能够通过学习来忽略那些影响。事实证明,通过添加适量的噪声能够有效提升神经网络的学习能力。
一个“弱化”的版本是椒盐噪声,它以随机的白色和黑色像素点呈现并铺满整个图片。这种方式对图像产生的作用和添加高斯噪声产生的作用是一样的,只是效果相对较弱。
从左侧开始分别为:原始图像,增加了高斯噪声的图像,添加了椒盐噪声的图像。
在 TensorFlow 中,你可以使用以下的代码给图片添加高斯噪声。数据增强因子(Data Augmentation Factor)= 2x。
高级增强技术
现实世界中,自然状态下的数据,存在于各种各样的状况之中, 不能用上述简单的方法来处理。例如, 进行照片中的景观识别的任务。景观可以是任何自然中的东西:冰冻寒带草原、草原、森林等等。听起来像是个很直接的分类任务对吧?基本没问题,除了一件事外。我们忽略了照片中的一个关键特征, 而这个特征将会影响到模型的表现——照片拍摄的季节。
如果我们的神经网络不明白某些景观可以存在于各种条件下(雪、潮湿、明亮等), 它可能会错误地将冰冻的湖畔标记为冰川或者把沼泽标记为湿地。
缓解这种情况的一种方法是添加更多的图片,这样我们就可以解释所有季节性变化。但这是一项艰巨的任务。扩展我们的数据增强概念,想象一下,人为地产生不同季节的效果会有多酷?
条件型生成对抗网络,了解一下
并不用深入了解繁杂的细节,条件型生成对抗网络就能将一张图片从一个领域转换到另一个领域中去。假如你觉得这听上去太模棱两可了,它本身并不是这样;事实上这是一种强大的神经网络 ! 下面是一个应用条件型生成对抗网络(Conditional GANs)将夏日风光的图片转换为冬季风景的例子。
用CycleGAN 改变季节
(Github: https://junyanz.github.io/CycleGAN/)
上述方法是鲁棒的(Robust), 但是属于计算密集型,需要耗费大量的计算性能。一个更廉价的选择是所谓的神经风格迁移(Neural Style Transfer)。它抓住了一个图像的纹理/气氛/外观 (又名, "风格"), 并将其与其他内容混合在一起。使用这种强大的技术, 我们产生的效果类似于我们的条件型生成对抗网络所产生的效果(事实上, 这个方法是在 cGANs 发明之前就被提出来了!)。
这种方法唯一的缺点在于输出结果看起来太有艺术感了,以至于显得不那么真实。但是,在譬如深度学习的图像风格转换方面还是具有独特的优势,至少它的输出结果给人留下了深刻印象。
深度照片风格转移。
注意如何在数据集上产生我们想要的效果。
(来源:https://arxiv.org/abs/1703.07511)
由于我们并不关注其内部的工作原理,所以我们没有深入探索这些技术。事实上,我们可以使用现有训练好的模型再加上一点迁移学习的“神奇力量”来进行数据增强。
插值简介
如果想平移一个没有黑色背景的图像时候该怎么办?向内部缩放呢?旋转一个特定的角度?在完成这些变换之后,我们需要保持原始图像的大小。由于我们的图像没有包含其边界之外的区域的任何信息,我们得做一些假设。一般来说,我们会假定图像边界之外的部分的每一个像素点的值都是常数 0 (RGB值为 0 表示黑色)。这样,在对图像进行变换之后,在图像没有覆盖的地方会得到一块黑色的区域。
从左侧开始分别为:逆时针旋转45度的图像,右侧翻转的图像和向内缩放的图像。
但是,那个假设是不是就一定正确呢?在现实世界中,大多数情况下那个假设是不适用的。图像处理和机器学习框架提供的一些标准的处理方式,你可以决定如何填充未知的空间。
从左侧开始分别为:常数,边缘,反射,对称和包裹模式。
它们的定义如下:
1. 常量填充
最简单的插值方法是用某个常量值填充未知区域。这可能不适用于自然图像, 但可以用于在单色背景下拍摄的图像。
2. 边缘扩展
将图像边缘的值扩展到边界以外。这个方法可用于轻微的平移的图像。
3. 反射
图像像素值沿图像边界进行反射。这种方法对于包含树木、山脉等的连续或自然背景是有用的。
4. 对称
此方法类似于反射,除了在反射边界上进行边缘像素拷贝。通常,反射和对称可以交替使用,但在处理非常小的图像或图案时,差异将是可见的。
5. 包裹
在超出图像边界的部分重复填充图像,仿佛在进行图像平铺。这种方法不像其他的那样普遍使用, 因为它对很多场景都没有意义。
除此之外,你还可以设计自己的方法来处理未定义的空间, 但通常以上这些方法对大多数分类问题都有很好的效果。
使用了这些所有的技术,能保证机器学习算法的鲁棒性吗?
如果你用的是正确的方法,那这个问题的答案是 Yes ! 什么?你问正确方法是什么?嗯,有时不是所有的增强技术都对数据集有意义。再考虑一下我们的汽车例子。下面是可以修改图像的一些方法。
第一个图像(从左边开始)是原始图像,第二个图像是水平翻转的,第三个图像旋转了180度,最后一个图像旋转了90度(顺时针)。
当然, 他们是同一辆车的照片, 但你的目标应用可能永远不会看到在这些方向的汽车。
例如,如果你要分类在路上的随机车辆,只有第二个图像对数据集来说是有意义的。但是,如果你拥有一家处理车祸的保险公司,而你也想识别车祸中颠倒的、撞坏的车, 那么第三张图片是有意义的。最后一个图像可能对上述两种情况都没有意义。
关键是, 在使用增强技术的同时,我们必须确保不增加无关的数据.。
这样做真的值得吗?
你也许正期待着能有一些结果来。有道理,我也做了这一点。让我先通过一个小示例来证明数据增强的确能够产生作用。不信的话,你可以复现这个实验来验证。
让我们创建两个神经网络, 将数据分类到四类中的一个: 猫、狮子、豹或者老虎。区别在于,一个不会使用数据增强,而另一个将使用数据增强。可以从此链接下载数据集。
如果你查看了数据集,你会发现里面训练集和测试集中每一类都只有50张图片。很明显,我们不能对特定的一个分类器使用增强技术。公平起见,我们使用迁移学习让模型能够应对数据稀缺问题。
数据库里的四个分类
对于没有进行数据增强的神经网络,我们将使用 VGG19 网络结构。在参考这个 VGG19 实现的基础上,我用TensorFlow实现了我们的第一个神经网络。一旦你克隆了我的 Github Repo, 你就可以从这里 得到数据集以及从这里 下载 VGG19. npy (用于迁移学习) 。完成上述工作后,就可以运行模型来验证性能了。
不过, 为数据增强编写额外的代码确实是费时费力的工作。所以, 构建我们的第二个模型过程中,我使用了 Nanonets。它内部实现了转移学习和数据扩充,可以用最少的数据量提供最佳的结果。所有你需要做的只是上传的数据到他们的网站,并等待他们的服务器训练完毕就可以了(通常约30分钟)。你要知道,这对我们进行对比实验多么完美。
完成训练后,你可以对其 API 请求调用来计算测试的准确性。你可以在GitHub repo中找到对应的示例代码片段 (不要忘记在代码段中插入模型的 ID)。
对比结果令人印象深刻不是吗?事实上,大多数模型在更多的数据上可以表现更良好。为了提供一个具体的证明,可仔细看看下面这张表。它显示了 Cifar 10 (C10) 和 Cifar 100 (C100) 数据集上常用的神经网络的错误率。C10+ 和 C100+ 列是进行数据增强后的错误率。
Cifar 10 和 Cifar 100 数据集上的表现