一、批量归一化(Batch Normalization)
基本思想:希望激活函数在我们想要的高斯范围内保持激活状态。
1、为什么要用批量归一化
对深层神经网络来说,随着网络训练的进行,前一层参数的调整使得后一层输入数据的分布发生变化,这种变化可能导致这个输入数据的分布又变得不太好了。所以即使最开始的输入数据input已做标准化,训练中模型参数的更新依然很容易导致后面层输入数据分布的变化,只要网络的前面几层发生微小的改变,那么后面几层就会被累积放大下去。最终造成靠近输出层的输出结果的剧烈变化。
这种计算数值的不稳定性通常令我们难以训练出有效的深度模型。如果训练过程中,训练数据的分布一直在发生变化,那么将不仅会增大训练的复杂度,影响网络的训练速度而且增加了过拟合的风险。
因而在模型训练时,在应用激活函数之前,应先对一个层的输出进行归一化,将所有批数据强制在统一的数据分布下,然后再将其输入到下一层,使整个神经网络在各层的中间输出的数值更稳定。从而使深层神经网络更容易收敛而且降低模型过拟合的风险。
总结:深层神经网络在做非线性变换前的激活输入值,随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,整体分布逐渐往非线性函数的取值区间的上下限两端靠近,这会导致反向传播时低层神经网络的梯度消失,BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,使得激活输入值落在非线性函数对输入比较敏感的线性区域,其对应的导数远离导数饱和区 ,这样输入的小变化就会导致损失函数较大的变化,避免梯度消失问题产生,学习收敛速度快,能大大加快训练速度。
2、批量归一化的具体过程
批量归一化BN层通常是夹在全连接层/卷积层和激活函数中间的。
对于全连接层,设我们当前的批处理数据中有N个训练样本,也就是N行;每一个样本有D维,也就是D列。那之后就是对每一维(即每一列),计算所有样本的经验均值和方差,然后用下面那个式子对每个样本x的第D维进行归一化处理。
对于卷积层,我们希望每一个activation map的归一化处理都是一样的,因此对于每个activation map,都会算一个均值和标准差,然后对样本中所有的该activation map进行归一化。这块有点没懂???
3、批量归一化中的放缩和平移
批量归一化会完全避免激活函数中的饱和现象,但有的时候适当的饱和也是ok的,因此可以对批量归一化的结果进行一定的放缩和平移,来控制激活函数饱和度的高低,即通过引入参数γ和β来实现这个功能。
因而在批量归一化BN层中,也有两个需要学习的参数,就是γ和β。
4、批量归一化总结
(1)可提升网络中梯度流的质量,避免大规模出现梯度消失的现象;
(2)可增大学习率;
(3)可降低网络对初始化权值的依赖;
(4)起到一种类似于正则化的效果,即每一个样本在每一层的输出结果不仅仅与自己有关,还取决于这个batch中所有的样本的输出值(因为要用它们的平均值和方差来做归一化),这样输出结果就是不确定的,相当于在x中加入了一些抖动;
(5)在测试时,不需要重新计算batch的均值和方差,直接用训练时的均值和方差做归一化即可。
批量归一化参考博客:https://blog.csdn.net/yasin0/article/details/93379629
二、监督学习过程 babysitting the learning process
这部分主要讨论如何监视训练过程并在训练中调整超参数的值以获得更好的结果。
步骤:
1、数据预处理
2、选择网络结构
3、检查损失函数的正确性:初始时的loss是可计算的(详见笔记二),可以用网络中算出来的损失函数的值来检查一下网络是否正确。同时算完之后,可以再加上正则化一项,看看损失函数的值有没有变大。
4、开始训练第一步,只选取非常少的训练数据,同时去掉正则化,看看损失函数能不能降到0。
5、确定学习率learning rate。这个时候加上正则项,并用所有训练数据作为输入,看看loss能不能一点一点随着epoch降下来。通常学习率设在1e-3到1e-5之间。
(1)loss不降:学习率设得太小了
(2)loss变成NAN:学习率设得太大了
(3)loss发生了突变(可能是往小里的突变):也是学习率太大,因为步长大了可能导致W和loss的变化很快。
(4)如果loss一开始不变,之后突然开始变化,说明初始化做得不好。
三、超参数优化
交叉验证:
1、第一阶段:只跑几个epoch来确定超参数的大致范围
2、第二阶段:longer running time, finer research
3、一个tip:如果loss变成了初始loss的三倍以上,证明这个超参不能用,直接结束训练。
4、另一个tip:超参数的采样通常采样对数采样,而不是在一个区间里均匀采样。