数据增强在卷积神经网络中的应用
2017-09-25 19:31
323 查看
这一篇博客主要讨论在用卷积神经网络进行图像识别或者目标检测时的数据增强手段,并讨论其作用。
首先整理两篇比较有代表性的论文里的数据增强,再说说我自己工作中使用的数据增强,最后讨论这些数据增强的意义(我个人的理解)。
个人觉得,如果你的网络设置的没什么问题,代码也没写错,但是跑出来的效果不尽如人意,比如你希望有80%的准确率,但实际只有70%,那你就应该试一试数据增强,这绝对比你调模型的参数或者结构要有效得多。
而且在实际中,打标数据是很珍贵的,数量可能根本没有达到能够让你训练出一个满足要求的神经网络。这时候数据增强就会显得特别重要。
首先介绍的是2012年令深度学习大放异彩的alexnet中的数据增强,alexnet在2012年的imagenet大赛中获得了冠军,首次把深度学习使用到了图片分类领域,并取得极大成功。
alexnet的输入是一张224x224x3的图片,imagenet的原始图片大小是256x256x3的,作者做了如下数据增强:
训练:原来的图片是256x256,现在依次裁剪出224x224的图片,这样横向有256-224次移动,竖着也有这么多,再加上左右的翻转镜像,相当于把数据集扩大了(256-224)x(256-224)x2=2048倍。
预测:选择一张图片的四个角的224x224加上中间的224x224(加上左右镜像的)一共10张图片的平均值做结果。
这样的数据增强主要是对图片做了裁剪,造成的效果是本来可能是一个完整的人在图片中,现在就剩半个人了,但这样却让模型知道了,这样的半个人他也是人,增强了模型的能力,所谓见多识广。
再来看看vgg中的数据增强,背景和alexnet是一样的,也是imagenet比赛,但比alexnet稍微复杂点:
训练:同样是图片扩大再截取的做法,作者提出了两种方案,一种是把所有图片扩大到统一的尺寸,然后用224x224x3去截取,一种是让每张图片随机在一个范围内扩大,然后再用224x224x3去截取。
最终作者用了一轮预训练加正式训练,
预训练时把图片同一扩大到384x384x3,并且学习率都设置为0.001,训练过程保持不变。
正式训练时以预训练的结果为初始值,把图片在(256~512)之间随机扩大,截取后再训练。
预测:记训练时图片的尺寸为S(比如上面的预训练时,S=384),预测时的尺寸为Q。在预测时把图片固定到Q尺寸,Q和S不一定要相等,然后先在Q尺寸上做卷积,到全连接层时做划窗,得到很多结果做平均,再将不同Q的结果做平均。
对每个S使用多个Q对提升准确率是有用的。
对于使用固定的S训练的模型,测试时使用的Q不能和S相差太多,作者使用了三个Q的值,分别是S-32,S,S+32。
对于使用随机S训练的模型,测试时的Q相对来说可以比固定S时有更多的选择,作者选择的三个Q值分别为S的最小值,S,和S的最大值。
纵观上面两种数据增强的方式,基本都是对图片进行各种各样的裁剪,使得网络在训练时能够见到更多的“不一样的图片”,这样为什么可以增强模型的性能?
假设这样一个场景,测试图片是一只猫躲在窗帘后,只露出了一只尾巴,如果我们的训练集中都是完整的猫图片,那么模型对这个只露出尾巴的图片将毫无办法。再假设我们在数据增强时的各种裁剪,刚好裁到了一只猫的尾巴。
当然,这只是感性的理解。
下面再说说我自己工作中做过的数据增强。
首先说一个这样的需求,请看下面几张图片,有几张是中文字,还有几张是数字,当时需要训练一个神经网络来区分一张图片中是文字还是数字,是个二分类问题。
![](https://img-blog.csdn.net/20170925200220055?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925200304809?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925200351806?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925200405878?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
对于大多数玩神经网络的来说,这个问题太简单了,但有两点问题:
每张图片的大小不一样,有的长有的短,有的高有的矮
我们仅有的打标数据都是我们自己手动打的,正样本和负样本加起来才83张
对第一个问题,我采用了一个比较笨的方法(当时接触神经网络时间还不长,没有过多其他的想法):
首先看了下所有图片的最高高度,然后在这个值的基础上再上下增大一些像素,增大的像素是从每张图片的最上面(或最下面)的五行像素里随机选择的一行,保持文字在图片中间,最终定的高度是70
统一了高度后,对宽度也做了统一,也统一到70,以70的宽度在原始图片上滑框,35个像素点划一次,这样一个宽度为200的图片,就可以划出6张70x70的图片
基于70x70的图片大小训练了一个二分类的网络,在测试时对原始图片做同样的操作,比如裁剪出5张70x70的图片,那么如果有3张都预测为文字,那么就认为这张图片是文字。
裁剪后的图片差不多是下面这样:
![](https://img-blog.csdn.net/20170925201517377?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925201614015?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925201723706?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170925201930715?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这样训练集从83张变成几千张了,于是我训练了一个简单的三层卷积加两层全连接的卷积神经网络,但在测试集上的准确率只有88%左右,由于这一个判断是否是数字的模型只是一个工程中的一步,所以如果这一步的准确率只有88%的话,那这个工程最终的准确率只会更低。
对这样的情况,我决定采取数据增强,仔细思考这个问题,现实中这种打印的字体可能会出现深浅不一,缺墨,或者有一块都是墨,拖墨,扫描时摆的不正等,总之真实的打印机打印出来的字会出现各种情况。
所以我对数据做了下面几种处理:
手工设计了一道公式,使得每张图片从左到右,从右到左,从上到下,从下到上呈现出墨色逐渐变淡的效果
把本来位于中间的字上移或下移
对图片进行裁剪,保留一行文字的一部分
对图片进行随机的旋转
对图片中的文字部分随机添加背景色的空白条,模拟打印时出现一行一行的缺墨情况
对上面几种处理方式做随机组合
经过上面这几种处理后的图片大概是下面这个样子的:
![](https://img-blog.csdn.net/20170926100612186?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926100630867?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926100700437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926100719712?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926100812634?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIy<br/>b228<br/>NA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926100939364?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926101006672?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
上面这些图片的辨认难度相比于没有处理的图片有了很大的提高,经过这样的组合处理后,我的数据集扩大到了几十万,这样训练出来的模型准确率上升到了96%,提升效果很明显。
再说一个我在做目标检测时做的数据增强。
还是上面的文字识别例子,上面的长条形数据是从一张完整的发票上扣下来的,这里使用的就是目标检测的技术,从一张发票中识别出有文字的区域,再扣出这部分区域。
我们遇到了同样的问题,只有40张打标数据,每张发票的大小是2000x3000,我们使用的SSD模型接受的输入是300x300,如果就按照300x300去从这2000x3000张上面去扣也就只有40x6x10=2400张图片。
不过显然可以有重叠的用300x300的去划,这样就会瞬间多出很多图片,虽然图片中的字可能是一样的,但位置还是有细微的变动的。
接着我们又把裁剪下来的300x300的图片随机缩放后再用300x300的去截取,这样图片中的字体大小变化了,位置也变化了,也可以算新的样本。
同时还使用的500x500,300x500,500x300等等不同尺寸的框去2000x3000的大图上框,框完了再resize到300x300。
经过这些步骤,我们的数据集扩大了很多,最终训练出来的模型效果已经可以接受,比如下面这样的(敏感信息做了覆盖):
![](https://img-blog.csdn.net/20170926112021738?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926112102104?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926112137332?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170926112156893?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVveWFuZzIyNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
以上两个例子都是我在实际工作中遇到的数据不足时的处理方案。
方法都比较简单粗暴,但都取得了不错的效果(相比调整模型结构,参数效果要好得多)。
个人觉得,在以往传统算法建模时我们要花费很大的时间去设计特征,做很多特征,而在深度学习阶段我们需要花很大的时间去做数据增强这么一件事:
深度学习参数多,模型复杂,本来就需要大量的数据才能达到比较好的效果,而现实中有标注的数据往往是很珍贵的,所以要利用好当前数据很有必要做数据增强
神经网络模型的拟合能力很强,即使是看着像噪音的数据喂给它,往往也能提升模型的性能,鲁棒性强
是噪音还是提升性能的数据?在使用传统机器学习算法时我们要小心的处理异常值,如果要预测的目标中异常值太多会对模型的性能造成很大的影响。而在深度学习中,像我们上面那样做数据增强,其实是给数据带来了不小的噪音的,但模型的能力却变强了,我个人的理解现实世界就是有各种噪音的,传统算法去除噪音再建模本身就是一个理想化的做法,和真实世界并不相符,但必须这么做,因为那些算法就是建立在“符合高斯分布”这样的假设下的,而深度学习可以更好的对噪音进行处理,关注噪音数据中的关键部分,这样模型的能力相比没见过噪音的就上升了。
以上就是我对数据增强的看法,也许有部分是不对的,但应该还算有参考意义吧。
首先整理两篇比较有代表性的论文里的数据增强,再说说我自己工作中使用的数据增强,最后讨论这些数据增强的意义(我个人的理解)。
个人觉得,如果你的网络设置的没什么问题,代码也没写错,但是跑出来的效果不尽如人意,比如你希望有80%的准确率,但实际只有70%,那你就应该试一试数据增强,这绝对比你调模型的参数或者结构要有效得多。
而且在实际中,打标数据是很珍贵的,数量可能根本没有达到能够让你训练出一个满足要求的神经网络。这时候数据增强就会显得特别重要。
首先介绍的是2012年令深度学习大放异彩的alexnet中的数据增强,alexnet在2012年的imagenet大赛中获得了冠军,首次把深度学习使用到了图片分类领域,并取得极大成功。
alexnet的输入是一张224x224x3的图片,imagenet的原始图片大小是256x256x3的,作者做了如下数据增强:
训练:原来的图片是256x256,现在依次裁剪出224x224的图片,这样横向有256-224次移动,竖着也有这么多,再加上左右的翻转镜像,相当于把数据集扩大了(256-224)x(256-224)x2=2048倍。
预测:选择一张图片的四个角的224x224加上中间的224x224(加上左右镜像的)一共10张图片的平均值做结果。
这样的数据增强主要是对图片做了裁剪,造成的效果是本来可能是一个完整的人在图片中,现在就剩半个人了,但这样却让模型知道了,这样的半个人他也是人,增强了模型的能力,所谓见多识广。
再来看看vgg中的数据增强,背景和alexnet是一样的,也是imagenet比赛,但比alexnet稍微复杂点:
训练:同样是图片扩大再截取的做法,作者提出了两种方案,一种是把所有图片扩大到统一的尺寸,然后用224x224x3去截取,一种是让每张图片随机在一个范围内扩大,然后再用224x224x3去截取。
最终作者用了一轮预训练加正式训练,
预训练时把图片同一扩大到384x384x3,并且学习率都设置为0.001,训练过程保持不变。
正式训练时以预训练的结果为初始值,把图片在(256~512)之间随机扩大,截取后再训练。
预测:记训练时图片的尺寸为S(比如上面的预训练时,S=384),预测时的尺寸为Q。在预测时把图片固定到Q尺寸,Q和S不一定要相等,然后先在Q尺寸上做卷积,到全连接层时做划窗,得到很多结果做平均,再将不同Q的结果做平均。
对每个S使用多个Q对提升准确率是有用的。
对于使用固定的S训练的模型,测试时使用的Q不能和S相差太多,作者使用了三个Q的值,分别是S-32,S,S+32。
对于使用随机S训练的模型,测试时的Q相对来说可以比固定S时有更多的选择,作者选择的三个Q值分别为S的最小值,S,和S的最大值。
纵观上面两种数据增强的方式,基本都是对图片进行各种各样的裁剪,使得网络在训练时能够见到更多的“不一样的图片”,这样为什么可以增强模型的性能?
假设这样一个场景,测试图片是一只猫躲在窗帘后,只露出了一只尾巴,如果我们的训练集中都是完整的猫图片,那么模型对这个只露出尾巴的图片将毫无办法。再假设我们在数据增强时的各种裁剪,刚好裁到了一只猫的尾巴。
当然,这只是感性的理解。
下面再说说我自己工作中做过的数据增强。
首先说一个这样的需求,请看下面几张图片,有几张是中文字,还有几张是数字,当时需要训练一个神经网络来区分一张图片中是文字还是数字,是个二分类问题。
对于大多数玩神经网络的来说,这个问题太简单了,但有两点问题:
每张图片的大小不一样,有的长有的短,有的高有的矮
我们仅有的打标数据都是我们自己手动打的,正样本和负样本加起来才83张
对第一个问题,我采用了一个比较笨的方法(当时接触神经网络时间还不长,没有过多其他的想法):
首先看了下所有图片的最高高度,然后在这个值的基础上再上下增大一些像素,增大的像素是从每张图片的最上面(或最下面)的五行像素里随机选择的一行,保持文字在图片中间,最终定的高度是70
统一了高度后,对宽度也做了统一,也统一到70,以70的宽度在原始图片上滑框,35个像素点划一次,这样一个宽度为200的图片,就可以划出6张70x70的图片
基于70x70的图片大小训练了一个二分类的网络,在测试时对原始图片做同样的操作,比如裁剪出5张70x70的图片,那么如果有3张都预测为文字,那么就认为这张图片是文字。
裁剪后的图片差不多是下面这样:
这样训练集从83张变成几千张了,于是我训练了一个简单的三层卷积加两层全连接的卷积神经网络,但在测试集上的准确率只有88%左右,由于这一个判断是否是数字的模型只是一个工程中的一步,所以如果这一步的准确率只有88%的话,那这个工程最终的准确率只会更低。
对这样的情况,我决定采取数据增强,仔细思考这个问题,现实中这种打印的字体可能会出现深浅不一,缺墨,或者有一块都是墨,拖墨,扫描时摆的不正等,总之真实的打印机打印出来的字会出现各种情况。
所以我对数据做了下面几种处理:
手工设计了一道公式,使得每张图片从左到右,从右到左,从上到下,从下到上呈现出墨色逐渐变淡的效果
把本来位于中间的字上移或下移
对图片进行裁剪,保留一行文字的一部分
对图片进行随机的旋转
对图片中的文字部分随机添加背景色的空白条,模拟打印时出现一行一行的缺墨情况
对上面几种处理方式做随机组合
经过上面这几种处理后的图片大概是下面这个样子的:
上面这些图片的辨认难度相比于没有处理的图片有了很大的提高,经过这样的组合处理后,我的数据集扩大到了几十万,这样训练出来的模型准确率上升到了96%,提升效果很明显。
再说一个我在做目标检测时做的数据增强。
还是上面的文字识别例子,上面的长条形数据是从一张完整的发票上扣下来的,这里使用的就是目标检测的技术,从一张发票中识别出有文字的区域,再扣出这部分区域。
我们遇到了同样的问题,只有40张打标数据,每张发票的大小是2000x3000,我们使用的SSD模型接受的输入是300x300,如果就按照300x300去从这2000x3000张上面去扣也就只有40x6x10=2400张图片。
不过显然可以有重叠的用300x300的去划,这样就会瞬间多出很多图片,虽然图片中的字可能是一样的,但位置还是有细微的变动的。
接着我们又把裁剪下来的300x300的图片随机缩放后再用300x300的去截取,这样图片中的字体大小变化了,位置也变化了,也可以算新的样本。
同时还使用的500x500,300x500,500x300等等不同尺寸的框去2000x3000的大图上框,框完了再resize到300x300。
经过这些步骤,我们的数据集扩大了很多,最终训练出来的模型效果已经可以接受,比如下面这样的(敏感信息做了覆盖):
以上两个例子都是我在实际工作中遇到的数据不足时的处理方案。
方法都比较简单粗暴,但都取得了不错的效果(相比调整模型结构,参数效果要好得多)。
个人觉得,在以往传统算法建模时我们要花费很大的时间去设计特征,做很多特征,而在深度学习阶段我们需要花很大的时间去做数据增强这么一件事:
深度学习参数多,模型复杂,本来就需要大量的数据才能达到比较好的效果,而现实中有标注的数据往往是很珍贵的,所以要利用好当前数据很有必要做数据增强
神经网络模型的拟合能力很强,即使是看着像噪音的数据喂给它,往往也能提升模型的性能,鲁棒性强
是噪音还是提升性能的数据?在使用传统机器学习算法时我们要小心的处理异常值,如果要预测的目标中异常值太多会对模型的性能造成很大的影响。而在深度学习中,像我们上面那样做数据增强,其实是给数据带来了不小的噪音的,但模型的能力却变强了,我个人的理解现实世界就是有各种噪音的,传统算法去除噪音再建模本身就是一个理想化的做法,和真实世界并不相符,但必须这么做,因为那些算法就是建立在“符合高斯分布”这样的假设下的,而深度学习可以更好的对噪音进行处理,关注噪音数据中的关键部分,这样模型的能力相比没见过噪音的就上升了。
以上就是我对数据增强的看法,也许有部分是不对的,但应该还算有参考意义吧。
相关文章推荐
- 卷积神经网络简单的应用(一):目的与数据
- 重新想象 Windows 8.1 Store Apps (80) - 控件增强: WebView 之基本应用, POST 数据, 与 JavaScript 交互
- 4用于cifar10的卷积神经网络-4.4/4.5cifar10数据集读取和数据增强扩充(上/下)
- 【技术直通车】在现实增强应用Layar中显示ArcGIS数据(Ⅱ)
- 【技术直通车】在现实增强应用Layar中显示ArcGIS数据(Ⅰ)
- JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
- 重新想象 Windows 8.1 Store Apps (80) - 控件增强: WebView 之基本应用, POST 数据, 与 JavaScript 交互
- 社区开放任务指南-3102-应用透明的SQLite数据安全性增强
- JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
- SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性
- 最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用22
- 《海量日志数据分析与应用》之社交数据分析:好友推荐
- keychain 多应用共享数据
- 阿里RAP+fiddler实现app原生应用的cgi数据mock----- (一)RAP+fiddler工具主流程部署调试
- 通过java增强for循环for each遍历Map中的数据
- 【研究】使用满意度与用户体验调查数据,揭示HR应用用户体验三大发现——HR应用趋势洞察解读系列(三)
- 增强现实技术(AR)及扩展应用
- 数据挖掘技术在商业银行CRM中的应用理论与模型研究
- 第6章 对表单和数据表格应用样式
- FullCalendar日历插件应用之数据展现(一)