【深度学习】③--神经网络细节与训练注意点

1. 权重的初始化

1.1 fine-tuning

神经网络的训练的有两种方式,第一种是自己从头到尾训练一遍;第二种是使用别人训练好的模型,然后根据自己的实际需求做改动与调整。后者我们叫做fine-tuning.

在model zoo有大量训练好的模型(不知道的可以百度一下model zoo)

fine-tuning相当于站在巨人的肩膀上,使用别人已经训练好了的优秀的模型去实现自己的需求。一般分为以下两种调整方式: 1.只修改FC(全连接层),比如原来的模型是1000个类别,而你实际上只需要分2个类别,那么你就可以调整FC的神经元个数与权重。并且设置前面所有没有改动的层的学习率为0,然后加大FC层的学习率。

2.包括了调整卷基层,激励层,池化层的神经元个数,或者减少或增加层级的数量。并且调低前面所有没有改动的层的学习率,然后加大后面层的学习率。这种方式的收敛更快和好。

1.2 随机数很小数初始化权重

在做逻辑回归时我们一般都将权重初始化为0,但是,在做神经网络的时候,权重如果很小或等于0,就会出现问题了。

假设权重为0,那么每个节点上的z = wx + b 这个线性函数运算结果都几乎为z = b。然后无论接下来使用什么类型的激励函数,这个函数的值y = g(z)在每个节点上都是相同的。也就是说BP的前向运算的时候得到的结果的是一样的,那么在反向传播时作用在每个权重的更新都是一致的,这绝必不是我们想要的。还记得上一个笔记中提到过,每个神经元会各自去负责一类特征(比如颜色,纹理等),只有在这个特征出现的时候,我们才希望对应的那个神经元被激活了。所以,正常情况下,每个神经元的输出应该是各不相同的。

下面做了一个实验,搭了一个10层的神经网络,并且设置w的初始值是一个很小很小的数,目的是想看看将w初始化成非常小的随机数会对神经网络的运作产生什么不好的影响?

下图10个蓝色的柱状图表示的是在过了激活函数后的每层神经元的输出结果的柱状图。每个柱状图是该层的所有神经元输出结果的一个分布图。蓝色的线形图是10层神经网络每层神经元输出结果的均值。旁边红色的线形图是每层的方差。

分析上图。当计算第一层的时候,均值很小,约为-0.000117,方差比较大约等于0.2,柱状图也显示,第一层的神经元的输出也是分布比较分散的,表示各个神经元的输出各异。

再看第二层。均值一下子上升到了-0.000001,而方差骤降到了0.04,从分布图看该层的神经元输出变得很集中,几乎都分布在一个很狭窄的范围内。也就是说,在第二层的时候,不同神经元的输出趋于一致了,他们的活力降低了。

接着看下面几层,均值小幅上升,方差继续下降,神经元的输出结果越来越一样,到第10层的时候方差已经为0 ,就是说所有神经元的输出都完全相等了。(哭脸)

上面这个实验我们可以得出一个结论:当权重的初始值非常小的时候,对于浅层的神经网络还勉强能够胜任,但是对于深层的神经网络就丧失了活力,这就是上个笔记中提到的“梯度弥散”现象。出现了“梯度弥散”,激励函数就从此挂掉,整个模型的训练也付之东流了。(再哭脸)

1.3 随机数较大数初始化权重

既然权重的初始化不能是很小的数,那么将权重设成比较大的数是否可以呢?

再来做一个实验,此时将权重设置为1。我们来看下面的结果图,仍然是均值,方差,和每层输出的柱状分布图。

看均值和方差的分布到也正常,但是,看到柱状分布图的是心里那个一惊,每层的输出分布呈现一个凹形,数据被分布在了0或者1的两边。这种极端的现象来自于偏大的权重使得z = wx + b的z值变得很大或者很小,而z值越大或越小,g(z)激励函数的输出就越接近于1或者-1,所以呈现了两个极端化的现象。(这里我们使用的激励函数是tanh)

1.4 哈维尔xavier初始化

现在我们知道权重的初始值设置得太大或者太小都不适合。

于是Xavier在2010年发表论文提出了一种解决办法。z值是由于上级指向它的节点Xi 乘以对应的权重的总和。也就是说,影响z值大小的有两个因素:输入层节点的个数,权重值。为了平衡这两个因素,我们认为当输入节点很多的时候,相应的初始权重应当小一点;当节点比较的时候,初始权重应当相应增大。

所以,我们仍然从个高斯分布中得到一个随机的权重值,然后将这个权重值除以输入的节点个数的开根号,得到的新的值为权重的初始值。我们采用这个新的方法去又做了个实验,结果如下:

第一个柱状图是输入的高斯分布图。从第2个到第11个柱状图是10层神经网络的输出,可以发现,他们分布并没有之前那样集中了,并且方差线性图中可见方差下降也没有之前那么快速了。说明这个方法产生了一定的效果。

1.5 哈维尔初始化与ReLU

前面的实验我们都是使用tanh激励函数,但是之前也说过,tanh存在梯度弥散的问题,在神经网络中更常用的是ReLU。现在我们使用ReLU激励函数来做实验。下图是实验结果。

柱状分布图与我们之前看的有所不同,再来回顾一样ReLU激励函数的函数图,它是一个由y=x,和 y = 0 两条射线组成的,当x < 0 时,y = 0. 所以柱状图的分布值也是 >= 0 。

那么问题来了,方差图上显示,方差仍然随着神经网络层次的深入变得越来越小,在10层处已经接近于0了,这表示,该层各个神经元的输出值非常相近,出现了梯度弥散。

哭是没有用的,问题是要解决的。于是2015年的时候有人发论文提出了解决方案。 在想想ReLU这个激励函数的图形,当数据进来的时候,如果小于0,那么这些数据就会被拦下不再前进了,所以每次经过这个激励函数,总有一部分数据因为小于0被拦截,所以剩下的数据就一层一层地越来越少,数据少了,对应的方差也就越来越小了。

为了解决这个问题,可以将之前输入节点n的开根号,还成n/2的开根号,表示每一此过激励函数都会被斩掉一半的输出,也就是下层激励函数的输入,既然节点数被斩掉了一半,那么自然权重应该相对应地增加了。

根据新的方法,输出了以下结果:

从图中可见,均值和方差都随机波动,不再连续减小或上升,处于正常状态。另外,柱状分布图从第1层到第2层都的区别也不大了。

所以,真是棒棒的!

1.6 batch normalization

虽然如此,但是ReLU仍然非常脆弱。在15年的时候google的同学发表论文提出了一个新的方案——batch normalization。

如果激励函数的输入是满足高斯分布的,激励函数的输出也就可以避免上述过程中的这些问题了。(因为输入的变化的幅度保持在一个范围之内) 但事实上输入的x的分布有时并无章可循,所以我们要人为地将激励函数的输入的分布转换为高斯分布。 (注意,这里的输入是激励函数的输入,也就是全链接FC后的输出,也就是线性函数z = wx +b 之后的z.)

那么如何对输入做一个高斯变化呢?变化的公式如下,其实就是标准正太分布的一个转化。原来的输入值减去均值再除以标准差,最后得到的结果就服从了均值为0,方差为1 的标准正态分布了。

但是呢,强行地转化可能会存在问题,因为我们之前说过每一个神经元都有自己的特性关注着独有的特征,如果强制地高斯分布的转换,就会使他们丧失这种特性了。所以在通过上述公式转化之后,再加上下面这一步。这是一个线性的转换,将高斯分布的值乘以一个数再加上一个数,产生了一个新的值y。这个y值就是输入激活函数的值。

γ和β这两个系数是可以被学习的。这样的转化使得之前因为强行转换而丧失的特性可以被还原回来。

batch normalization 的优点 自从有了batch normalization,大家都开始大规模地训练神经网络了。 1.梯度传递更为顺畅,也就是说计算更方便了 2.学习率设高一点也没有关系。如果使用哈维尔初始化方法,就算运用n/2的开根号,学习率太大的时候,也会存在在层次比较深的时候出现loss的低空震荡。 3.对于初始值的依赖减少了。 4.可以看作是一种正则化,对dropout的需求减少了

batch normalization要注意的地方 1.如果层次深,那么所有激励函数前使用BN会加长时间30% 2.是否需要加batch normalization需要视情况而定

2. 正则化与dropout

2.1 正则化

之前我们提到过过拟合的问题,神经网络想秀一秀自己对训练数据的拟合程度与精确程度,结果秀过了。我们的目的并不是得到一个模型去和训练数据完全拟合,而是需要这个模型能够对所有数据都有一个良好地拟合。对训练数据过于精确地拟合反而对其他数据就不那么精确了。就像量身定制的衣服只适合于一个人,而通用的S,M,L码对大部分人都是可以适合的。

为了避免过拟合,我们可以使用正则化。正则化的目的是不让模型过于拟合也不是它偏移。正则化的类型有但不限于以下几种: 1.L1正则化,即在损失函数上加上λ|w|,如此噪声就会因为得不到权重而被抑制。这叫做“阶段效应”。 2.L2正则化,即在损失函数上加上λw^2,也就是λ||w||2,这回产生“缩减效应” 3.L1+L2 4.最大范数约束。

但其实在神经网络中很少用正则化的方式去避免过拟合,原因如下: 1.神经网络中的权重w非常多,对每个权重都去加上λ|w|,会使计算变复杂。 2.在正则化中产生了一个超参数λ,是需要人为却设定的,它的大小会影响模型的训练。

2.2 dropout

dropout是2014年的一篇论文中提出的。它的原理是不一次性开启所有学习单元。如下图: 左图中的是全链接的神经网络,会非常精确地去训练与预测,右图却中关闭了一些神经元。也就是说别让你的神经元去记忆所有东东,要有一些泛化能力。也可以理解为,不要让你的神经网络去听信一家之言,对不同的模型做一个融合。(因为每个batch过来关闭掉的节点是不同的)

3. 训练检查与监控

3.1 在小数据集上“过拟合”

在真正训练模型前我们需要做这样一步: 在所有输入数据集中取出一小部分数据,比如500张图片,将这些小数传入关闭了正则化的神经网络。如果神经网络的神经元够多,层次够深,它是可以完全记忆住每一张图片的,也就是误差为0。我们需要去保证对于小数据集,这个神经网络是能够实现“过拟合”的,因为这可以证明这个神经网络的实现是正确的。

3.2 加入小强度的正则化

在确保了神经网络在小数据集上的过拟合,接下来就加入正则化,但强度不要太大,去观察输出的损失loss是否在下降.如果逐渐下降则该神经网络通过检验。

下面那是python代码和输出结果。

使用一些开源的工具可以很方便地去画图,左图是监控的loss图,横坐标是迭代次数,纵坐标是损失值。因为我们是将所有数据分成许多batch去分批训练的,所以一次迭代每个batch都会有一个损失值,画在坐标上就会形成一条垂直的小段线,经过100次的迭代,我们发现总体而言这条粗壮的损失线是波动下降的,它之所以是波动的,是因为每个batch的数据训练难度不同,在迭代第50次的时候,可能有些数据集难度特别大所以损失比迭代第30次的时候要高。但是总体来说,损失是下降的。

右上图的四条线分别代表了不同的学习率的损失的变化。学习率就是在SGD求梯度时下山的步长。如果学习率很高步长很大,一下子就跨到另一座山上了,损失就增大了。如果学习率稍微下降一点但还是偏高的话,损失一开始会下降地很快,但下降到一定维度就下降地非常非常缓慢甚至不变了。如果学习率很低步长很小,那么在下山的过程中走得会非常慢,所以损失的确会下降,但是下降地很慢,要非常多次迭代后才能降到最低点,这个就极度消耗了计算机的资源和训练的事件了。一个好的学习率,应该是像红线一样,逐渐快速下降,并短迭代内到达最低点。

3.3 对比训练集与验证集上的准确率

第三个监控与检查的方向是对比训练集与验证集的准确率

最好的状态是,训练集与验证集随着迭代次数的上升都往较高的准确率走,且两者准确率相差不大。像下图的红线与绿线,训练集的准确率比验证集的稍微高了一点,其实就出现了一点点的过拟合了。

如果验证集的准确率出现了蓝色线样,就说明出现了严重的过拟合。神经网络对于训练集能够很好的拟合并且准确率很高,但是在验证集上却准确率很低。此时就要重新训练模型。

4. 最优化与参数更新

4.1 SGD 与学习率

只要学习率很小,就能保证loss一直减小,但是收敛会非常慢

动量更新Momentum update 这是受物理学启发的优化方法,加快了收敛速度。这个方法加入了一步分加速度:

v可以初始化为0,mu可以设置为0.9左右值。

Nesterov Momentum 另一种优化的方法是基于凸优化理论,它的收敛更好。 当我们下山中每向下走一步,走完之后的位置其实已经变化了,所以应该用心的位置去做求导,如下公式

学习率衰减 除了使用以上两种方式外,我们还可以让学习率去自己衰减。随着迭代次数上升,学习率应该也随之下降。

1.步伐衰减 比如每20轮完整训练周期,就下降20%的学习率

2.指数衰减 随着t的上升,a会逐渐下降

3.1/t衰减

5. 深层网络与ResNet

ResNet是微软亚洲研究院提出的,获得了ILSVRC2015年的冠军,比之前风靡的VGG还要深8倍,全称为Deeo Residual Learning network.

当神经网络的层次很深,残差传回来的信号就会越来越弱。为了解决这个问题,能不能造一条桥直接将input送到后面那些层次。文字好难解释,来看下图,x是input,weight layer就是卷积计算层,rele是激励层。x首先输给了卷基层,然后经过激励层用给了卷基层,在进入下一个激励层之前,我们将卷基层里出来的数f(x)加上一个由最开始的输入层过来的x,加和的数再作为输入传入下一个激励层。x保留了原始的信号,使其避免了在传递过程中信号越来越弱的问题。

左图画出了不同层次的ResNet的损失图,实线是验证集,虚线是训练集,可以看出层次越深的话损失就越低了。 但是一个有趣的事情是,当层次继续上升,到了1202层的时候,它的损失反而比110层的要大了。

下面是ResNet的python代码,可能有点看不清,想要的童鞋可以直接问我要。

原文发布于微信公众号 - Spark学习技巧(bigdatatip)

原文发表时间:2018-02-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏TensorFlow从0到N

TensorFlow从1到2 - 4 - 深入拆解CNN架构

本篇将拆开CNN架构,一探究竟。 ? 基于空间映射的架构 全连接网络架构存在一个“硬”伤:网络中各层神经元的一维排布方式,丢弃了图像的空间结构信息。 以MN...

4547
来自专栏和蔼的张星的图像处理专栏

6. RCNN--Fast-RCNN--Faster-RCNN技术演进

分类已经学习过了四大网络(AlexNet,VGG,InceptionNer,ResNet),对于一个分类问题,数据量足够的话,根据分类复杂性搭建不同深度的卷积神...

1533
来自专栏红色石头的机器学习之路

台湾大学林轩田机器学习基石课程学习笔记10 -- Logistic Regression

上一节课,我们介绍了Linear Regression线性回归,以及用平方错误来寻找最佳的权重向量w,获得最好的线性预测。本节课将介绍Logistic Regr...

2360
来自专栏人工智能

神经网络与反向传播算法

1、前言 先简单的说下神经网络吧。 简单来说就是模拟大脑的神经元。 前端会有一大批数据输入,例如,前端输入了一张图像的所有像素点。 中间层会有成千上万个网络数据...

1976
来自专栏AI研习社

从编程实现角度学习 Faster R-CNN(附极简实现)

Faster R-CNN 的极简实现: github: simple-faster-rcnn-pytorch(http://t.cn/RHCDoPv ) 本文插...

9905
来自专栏WD学习记录

机器学习 学习笔记(21)深度学习中的正则化

在机器学习中,许多策略被显式的设计来减少测试误差(可能会以增大训练误差为代价)。这些策略统称为正则化。

3072
来自专栏大数据挖掘DT机器学习

python使用AI实现识别暹罗与英短

先来上两张图看看那种猫是暹罗?那种猫是英短? 第一张暹罗 ? 第二张英短 ? 你以后是不是可以识别了暹罗和英短了?大概能,好像又不能。这是因为素材太少了,我们...

38911
来自专栏人工智能LeadAI

TensorFlow从1到2 | 第四章: 拆解CNN架构

上一篇 《TensorFlow从1到2 | 第三章: 深度学习革命的开端:卷积神经网络》 快速回顾了CNN的前世今生。 本篇将拆开CNN架构,一探究竟。 ? 基...

3627
来自专栏程序生活

机器学习(三)使用Python和R语言从头开始理解和编写神经网络介绍目录神经网络背后的直观知识多层感知器及其基础知识什么是激活函数?前向传播,反向传播和训练次数(epochs)多层感知器全批量梯度下降

本篇文章是原文的翻译过来的,自己在学习和阅读之后觉得文章非常不错,文章结构清晰,由浅入深、从理论到代码实现,最终将神经网络的概念和工作流程呈现出来。自己将其翻译...

4727
来自专栏尾尾部落

可能是最全的数据标准化教程(附python代码)

数据标准化(归一化)处理是数据挖掘的一项基础工作,不同评价指标往往具有不同的量纲和量纲单位,当各指标间的水平相差很大时,如果直接用原始指标值进行分析,就会突出数...

1733

扫码关注云+社区