【2017CS231n】第六讲:训练神经网络(上)
一.**函数
输入与权重W作用后,输入到非线性的**函数。**函数有以下几类:
1.1 Sigmoid
当输入元素输入到sigmoid函数中,数据会被压缩在[0,1]的范围。当有一个非常大的输入,那么函数的输出结果将非常接近于1。当输入是一个绝对值很大的负数,那么输出接近于0。
Sigmoid函数存在以下三个问题:
1.Sigmoid饱和导致梯度流失
当我们的输入值特别大时,这时函数的输出就会接近sigmod的正饱和区,所以输出就会变成常数。这时游梯度就是0。
图中举的例子当x=-10时,sigmod接近负饱和区域,x=0时,会得到一个合理的梯度,进行较好的反向传播,x=10时,梯度为0。
2.Sigmoid是非零中心输出函数
当输入全为正时,乘以权重w,然后输入到**函数中,本地梯度df/dw=x,如果所有输入x都为正,那么局部梯度都是正或负。
w的梯度为dL/df乘以df/dw,这意味着w的梯度,当他们全为正或负时,w总是朝着一个方向移动。在进行w的参数更新时,可以用一个数去更新所有的值,或者增加或者减小。这对于w的更新来说十分低效。
下面举一个例子来说明:
在这个例子中我们假设w是二维的。用全为正数或负数的值去迭代。
蓝色的是梯度的更新方向。我们假设w的最佳值是红色的向量。我们从某一个方向开始更新,但是我们不能从w的这个方向直接优化。因为我们的梯度方向要么为正要么为负,所以w迭代的方向是曲折前进的。
所以一般情况下我们使用的x均值为0。这样x有正有负,则w的更新就不会是一个方向,在更新时就会高效些。
3.Sigmoid函数是指数函数,计算代价较高。
1.2 tanh函数
这个挺简单的,大家看下下面的讲义。
1.3 ReLU
1.4 dead ReLU
导致dead ReLU的原因:
w的初始值设置的不好,导致部分输入x与w作用后不能**ReLU函数。梯度传回来它不会更新也不会被**。
大部分的ReLU网络都有这个问题,大概10%到20%的会挂掉。
在实际中人们会用较小的偏置项来初始化ReLU,增加他们在初始化时被**的可能。但是这个方法不常用,大部分都把偏置项设为0。
1.5 几种ReLU的变种:
1. Leaky ReLU和P ReLU
Leaky ReLU有一个系数0.01,所以不会有饱和的问题。P ReLU采用一个系数a,这个a不用硬编码去写定它,把它当做一个可以学习的参数。
2. EReLU
在负半轴没有斜率,这建立了一种负饱和机制,有利于鲁棒性的提升。但是这种观点现在还有争议。
1.6 最大输出神经元
两组权值w1和w2分别跟x作用,取较大的值。
缺点:会使参数翻倍2*w。
1.7 实际中使用的**函数
用ReLU呗,不要用sigmoid。
二.数据预处理
对原始数据进行零均值化和归一化。
在图像领域我们一般只做零均值化,不做归一化和其他复杂的预处理。
对图像来说我们就是做零均值化的预处理。
在数据集中计算一个均值图像,对所有要传入网络的数据都减去这个均值图像。在一些网络中我们也通过减去单通道的均值代替减去均值图像。
例子中的图像是32*32*3。图像宽度和高度是32,另外的3代表图像是3通道图像(RGB)。我们得到的单通道均值分别是R均值,G均值,B均值。均值是从所有数据中计算得到的。
零均值化并没有解决sigmoid遇到的问题,零均值只会在第一层网络中解决sigmod的饱和问题,但是在后续的网络中会有很多非零均值问题,所以问题会在后面的网络中迅速恶化。
三.网络权值初始化
在网络中我们需要初始化w权值,再用梯度下降来更新。3.1 w=0
当w=0时,所有的神经元对输入的数据都做同样的事情,他们得到相同的输出和相同的梯度,w将以相同的方式更新。
而我们希望神经元学习到不同的东西。
3.2 w=随机数
当我们用小的随机数做初始值,例如对高斯分布做抽样。这样解决了参数对称问题。在小的网络中这种方式可以,但是在大的网络中会有问题。
当我们采用很小的随机数,每层网络的输出会迅速变小,并接近于0,梯度也迅速变小。
当我们取很大的随机数,采用tanh**函数,会饱和。梯度将接近于0,权值得不到更新。
3.3 Xvaier初始化
要求输入方差等于输出方差,根据这个我们能得到这个初始化的公式。
四.批量归一化
批量归一化的目的:在我们想要的高斯范围保持**状态。
我们想要正确地**单位高斯函数,我们可以取目前批量处理的均值,然后用均值和方差来进行归一化。
我们在训练开始时才设置这个值,以便每一层都有很好的单位高斯分布。
批量归一化做的是将输入数据转化为单位高斯数据(将原始数据平移和缩放)。
当输入数据是符合高斯分布时,批量归一化并不会使高斯数据损失,因为只是对数据进行平移和缩放,使数据在一个便于操作的区域。
减去均值再除以标准差就是高斯化。
假设当前的批处理有N个训练样本,假设每批是D维的,对每个维度计算均值和方差。每个特征元素通过批量处理进行计算。
通常在全连接层和卷积层之后插入的BN。
我们通过每个与神经元**函数相连的输入来进行缩放。
我们可以用相同的方法连接卷积层,唯一的区别是我们在卷积层的情况下,我们不仅想要归一化所有的特征维度的独立训练实例,而且在我们的**映射图,包括我们的训练实例,我们想要归一化跨特征维度和空间位置的所有特性。之所以这么做是我们想要服卷积的性质,我们希望附近的位置能以同样的方式进行归一化。
我们并不清楚是否要在每个全连接层之后进行批量归一化操作,也不清楚是否确实想要给这些tanh非线性函数输入一单位高斯数据。这里只是要把输入数据限制在非线性函数的线性区域,我们只是想避免出现饱和。
批量归一化就是在进行归一化之后,需要进行额外的缩放操作。我们先做了归一化,然后用常亮γ进行缩放,再用另一个因子β进行平移。网络可以学习缩放因子γ使它等于方差,学习β使它等于均值。γ和β是通过学习得到的因子。
批量归一化思想:我们提供输入,计算小批量均值(对每个输入的小批量都做这个操作),然后计算方差,通过均值和方差进行归一化,还有额外的缩放和平移因子,从而改进了整个网络的梯度流。批量归一化会使网络更具鲁棒性。
批量归一化也可以看做是正则化的一种方式:每层的**值和输出,都源于输入x以及批中被采样的其他样本,因为你将通过这一批样本的经验化均值对输入数据进行归一化,所以它不再对给定的训练样本提供确定的值,而是将输入放入批中。因为不再是确定的值,就像在x中加入一些抖动,实现正则化效果。
训练时计算和使用的均值和方差在测试时不用重新计算。
五.监督训练过程
在训练过程中如何调整参数获得好的训练效果。
首先进行数据预处理。
第二步选择好的网络结构。
再三检查一下我们的损失函数是否合理。
例子中我们有一个归一化指数函数分类器,损失函数是负对数10分类,损失函数是1/10去负对数,大概2.3。
接下来启动正则项,发现损失上升了(不启动正则项损失就是输入数据的损失)。
下面开始正式训练,拿出所有的训练数据,加入一个小的正则化项。确定最优的学习率。
设置学习率1e-6,损失基本不变,因为学习率设置的太小了。此时梯度更新也很小。
当学习率很大1e6时,出现NaN。意味着学习率很高。
通常我们的学习率范围在[1e-3,1e-5]之间。
六.优化超参数
在训练集上训练,在验证集上验证。
选择相当分散的数值,经过几个epochs的训练,发现哪些参数有效。有了一个参数区间,然后更精确地搜索。
如上面的例子所示,在一些区间用10的幂次进行采样更好。
也可以进行网格采样。
观察损失函数的曲线。学习率是一个很重要的参数。
观察学习率/损失曲线时发现在刚开始很平滑,但是在某一个时间节点突然陡峭下降可能是学习率初始值没有设好。
如果训练精度和验证精度之间有很大的差距,这就说明很可能过拟合了。这时可以增加正则项权重。如果训练精度和验证精度差距不大说明没有过拟合,这时可以增加模型容量,可以提高精度。