1.9 归一化输入方法
假设一个数据集只有两个输入特征,并且数据集的散点图如下:
归一化输入需要两个步骤:
(1)零均值化
移动训练集直到它完成零均值化,效果如下:
(2)归一化方差
注意到图中的方差要比的方差大得多,我们要做的是给赋值:
这里的意思是指平方,之所以这么写,是因为都是向量,这里:
它的每个特征都有方差;并且注意到前面已经做了0均值化,方差原本的定义是,但均值已经归零,所以就是方差了;
接下来要将所有数都除以,图像将变得比较均衡,此时的方差都等于1:
提示:
如果你用它来调整训练数据,那么也应该用相同的来归一化测试集,你不希望训练集和测试集的归一化有所不同,均值和方差本来就是模型的参数之一,所以更换输入并不需要改变它们,无论的值是什么,终归是要用它们按,两个式子去计算,所以你要用同样的方法按这四个式子去调整测试集,不能再训练集和测试集上分别预估;我们希望不论是训练数据还是测试数据都是通过相同的定义的相同数据转换,其中是由训练集数据计算得到的;
为什么我们想要归一化输入特征?
如果使用非归一化的输入特征,代价函数将会变得细长狭窄,假设都是一维的:
而如果特征值在不同的范围,例如的取值范围是1~1000,是0~1,结果是参数的范围或比率将会非常不同,导致代价函数像狭长的碗;如果你能画出部分参数的轮廓,它会是一个狭长的函数:
而归一化以后成本函数平均起来更对称:
说到底,如果在狭长的成本函数上运行梯度下降法,你将被迫选择一个很小的学习率,如图中位置梯度下降法可能需要很多迭代过程,但如果成本函数是一个更圆的球形轮廓,那么不论从哪个位置开始,梯度下降法都能更加直接地找到最小值,可以使用较大的学习率即较大的梯度下降步长;
当然是一个高维向量,用二维图不能很好描绘,也许代价函数是高度非线性非凸的,但总的来说,代价函数更圆一些就会更容易优化,前提是特征都要在相似范围内;例如,,这些是相似范围,但这样不是相似范围,对优化算法相当不利
总结:
零均值化、归一化为标准方差(即1)、确保特征都在相似范围内,通常就可以帮助学习算法运行得更快;
1.10 梯度消失和梯度爆炸
训练神经网络有时导数或梯度会变得非常大或非常小,指数级的,加大了训练难度;
假设我们在训练一个很深的神经网络,为了简化假设每层都只有两个单元,并设:
一个深度神经网络的一般很大,从而会使激活函数值逐层呈指数级爆炸增长,最终很大;
此时,会使激活函数值逐层呈指数级减小到接近于0,最终很小;
直观理解就是只要比单位矩阵大一些,深度神经网络的激活函数就将爆炸性增长;只要比单位矩阵小一些,深度神经网络的激活函数就将指数级递减到0;
不仅仅是激活函数值,而且对和层数相关的导数也是呈指数增长或递减;
当前的深度神经网络能达到150层以上,在这种深度神经网络中如果作为的激活函数或梯度函数以指数级上升或下降,它们的值会变得极大,导致训练难度上升,尤其是梯度和层数相差指数级时,梯度下降法的步长会变得很小,梯度下降法将花费很多时间来学习;
1.11 神经网络的权重初始化
这是一个解决梯度爆炸和消失并不完整和系统的方法,从一个例子看起:
例1:单个神经单元权重初始化
先忽略参数,为了防止过大或者过小,当越大时,希望的是能够越小,因为是由项相加而得的,越大时,自然希望每一项能够小一些,也就是希望能够小一些;比较合理的方法是设置:
而对于多层神经网络,对于第层而言有个输入,也可以设置为:
这里的应该指的就是的维度即,而指令在这是指生成一个指定维度的矩阵,矩阵中的元素是从标准正态分布(均值为0,标准差为1)中随机抽取的,而指的是第层的单元数,指对括号中的数开根号,所以结果就是将一个矩阵和一个数相乘,数乘进矩阵会影响矩阵的每一个元素;
而如果使用的是ReLu激活函数,那么方差设置为会更好:
这其实叫“He/MSRA 初始化”的正态分布初始化:
所以如果激活函数的输入特征被零均值化、归一化方差,也会调整到相似范围,这样虽然没有彻底解决,但也确实减少了梯度下降和爆炸的问题,它通过给权重矩阵设置了合理的值,不能比大很多,也不能比小很多,所以梯度并没有消失或爆炸得太快;
其他变体函数:
对于使用激活函数的情况,初始化为以下两种更好,叫“Xavier初始化”:
这些公式只是给出一个起点,一个初始化权重矩阵的默认值,如果你愿意调整,实际上可以把方差参数当作一个超参数进行调整,也许是在中加入一个乘数参数作为超参数,但实际上这个超参数一般不知首先想调优的超参数,并不如其他超参数那么重要。
1.12 梯度的数值逼近
在实施backprop时有一个测试叫梯度检验,它的作用是保证backprop能够正常实施,有时你写下这些方程式,但无法100%确定执行backprop的所有细节都是正确的;为了逐渐实现梯度检验,首先说说如何对计算梯度做数值逼近,下一节再讨论如何在back prop中执行梯度检验;
这是一个和微积分有关的有趣例子,假设我们要求一条曲线在处的导数,导数在微积分里的直观意义是什么呢?是切线斜率。但还有另一种理解方式,那就是如图所示,处的导数严格意义讲就差不多等于时小绿三角的斜边的斜率,也差不多等于大绿三角斜边的斜率,注意三角形除了直角边顶点外的顶点都在曲线上,对应着;而绿三角形斜边的斜率就等于三角形的高宽比;
技术上,大绿三角形在利用高宽比计算导数时比小绿三角更加准确,大概是因为大三角考虑了左下方的小三角,得到了一个双边公差,这比小绿三角的双边公差更加精准;
我们可以验证一下,假设,,则大三角形的高宽比是:
小三角形的高宽比是3.0301,实际上处的导数为3,所以用大三角计算出来的误差更小;
准确的数学定义中:
如果直接让,那么得到的误差将是;而如果采用单边误差,让,那么得到的逼近误差将是,会比大得多;
1.13 梯度检验
梯度检验帮忙节省了很多时间,也帮忙发现了很多backprop中的bug;
如何利用它来调试或检验backprop实施是否正确呢?
神经网络中有这些参数,为了执行梯度检验,首先要做的是:
把所有参数转换为一个巨大的向量
实际中就是将每一个矩阵转换为向量然后所有(包括)的向量进行连接运算,变成一个巨型向量;于是成本函数就是:
然后得到和有同样顺序的,一样将他们整合成一个巨型向量,它和有同样的维度;
那么与成本函数的梯度有什么关系?
不论维度是多少,总能展开成,为了实施梯度检验,所要做的就是循环执行以下代码:
实际上,应该会逼近;这个for loop要求对每个都执行这个运算,最终将所有按顺序排列组成,和具有相同维度;
如何衡量两个向量之间是否彼此接近?
一般做以下运算来检查和的接近程度:
注意这里是欧式距离,即这个向量的所有元素的平方求和再开根号,类似于,分母则是用向量长度做归一化,只是用于预防这些向量过大或者过小;这里的等是沿用了前面设定的,误差合理的值应该是,也就是要比更高阶更小的无穷小量;
检查bug时应该仔细查看是否有某个的和大不相同,如果有利用它去追踪一些求导的计算是否正确,调试,直到式子降到比如;
在实施神经网络中经常要执行foreprop和backprop,然后可能发现这个梯度检验有一个较大的值,合理怀疑有bug存在,调试,调试……debug,debug……直到一段时间后得到一个很小的梯度检验值,就可以自信地说神经网络正确地执行了。
1.14 关于梯度检验实现的注记
(1)不要在训练中使用梯度检验,它只用于调试;
计算所有值的是一个非常漫长的过程,为了实施梯度下降,你必须使用backprop来计算并使用backprop来计算导数,只有调试时才会计算,完成后,你会关闭梯度检验,梯度下降的每一个迭代过程都不会执行梯度检验,因为实在太慢了;
(2)如果算法的梯度检验失败,要检查所有项,检查每一项试图找出bug;
即如果和相去甚远,应该检查不同的值看看是哪个导致了这样;比如你发现和里,某些层中,的值相差很大,但的各项却非常接近,记住的每项和的每一项是一一对应的,这是你可能会发现在计算的导数时存在bug;同理,也有可能bug会出现在中,虽然未必能精确帮你定位bug的位置,但它确实可以帮你估计需要在哪些地方追踪bug;
(3)在实施梯度检验时,如果使用正则化一定要加注意正则项;
(4)梯度检验不能和dropout一起使用;
因为每次迭代过程中dropout都会随机消除隐层单元的不同子集,难以计算dropout在梯度下降上的成本函数;dropout可以作为优化成本函数的一个方法,但成本函数被定义为对所有指数极大的节点子集求和,如果使用dropout,在迭代过程中这些节点都有可能被随机消除,很难计算成本函数,仅仅是对成本函数做抽样;所以很难用梯度检验来双重检验dropout的计算;
因此一般在进行梯度检验时不使用dropout或要使用也要将设为1以后再打开dropout,希望它实施正确;在梯度检验完成以后再打开dropout;
(5)(很少出现)在随机初始化过程中运行梯度检验,再训练网络,反复训练后再重新进行梯度检验;
现实中几乎不会出现这种情况,就是当都接近于0时,可能在随机初始化过程后不久时间内,梯度下降的实施是正确的,但是在运行梯度下降时变得更大,当变得越来越大时梯度下降变得越来越不准确;
如果出现这种情况,你需要做的是考虑在随机初始化后立即进行梯度检验。随后,在训练过程中可以定期或不定期地再次进行梯度检验,以确保梯度下降的持续正确性。