12.2 梯度检查
12.2 梯度检查⚓︎
12.2.1 为何要做梯度检查?⚓︎
神经网络算法使用反向传播计算目标函数关于每个参数的梯度,可以看做解析梯度。由于计算过程中涉及到的参数很多,用代码实现的反向传播计算的梯度很容易出现误差,导致最后迭代得到效果很差的参数值。
为了确认代码中反向传播计算的梯度是否正确,可以采用梯度检验(gradient check)的方法。通过计算数值梯度,得到梯度的近似值,然后和反向传播得到的梯度进行比较,若两者相差很小的话则证明反向传播的代码是正确无误的。
12.2.2 数值微分⚓︎
导数概念回忆⚓︎
其含义就是Python
中可以这样实现:
def numerical_diff(f, x):
h = 1e-5
d = (f(x+h) - f(x))/h
return d
因为计算机的舍入误差的原因,h
不能太小,比如1e-10
,会造成计算结果上的误差,所以我们一般用[1e-4,1e-7]
之间的数值。
但是如果使用上述方法会有一个问题,如图12-4所示。
图12-4 数值微分方法
红色实线为真实的导数切线,蓝色虚线是上述方法的体现,即从
公式2被称为双边逼近方法。
用双边逼近形式会比单边逼近形式的误差小100~10000倍左右,可以用泰勒展开来证明。
泰勒公式⚓︎
泰勒公式是将一个在
其中,
利用泰勒展开公式,令
单边逼近误差⚓︎
如果用单边逼近,把公式4两边除以
公式5已经和公式1的定义非常接近了,只是左侧多出来的第二项,就是逼近的误差,是个
双边逼近误差⚓︎
如果用双边逼近,我们用三阶泰勒展开:
令
再令
公式6减去公式7,有:
两边除以
公式9中,左侧多出来的第二项,就是双边逼近的误差,是个
12.2.3 实例说明⚓︎
公式2就是梯度检查的理论基础。比如一个函数:
我们看一下它在
再看它的数学解析解:
可以看到公式10和公式11的结果一致。当然在实际应用中,一般不可能会完全相等,只要两者的误差小于1e-5
以下,我们就认为是满足精度要求的。
12.2.4 算法实现⚓︎
在神经网络中,我们假设使用多分类的交叉熵函数,则其形式为:
m是样本数,n是分类数。
参数向量化⚓︎
我们需要检查的是关于
向量化的
对于上式中的每一个向量,我们依次使用公式2的方式做检查,于是有对第i个向量值的梯度检查公式:
因为我们是要比较两个向量的对应分量的差别,这个可以用对应分量差的平方和的开方(欧氏距离)来刻画。但是我们不希望得到一个具体的刻画差异的值,而是希望得到一个比率,这也便于我们得到一个标准的梯度检验的要求。
为什么这样说呢?其实我们可以这样想,假设刚开始的迭代,参数的梯度很大,而随着不断迭代直至收敛,参数的梯度逐渐趋近于0,即越来越小,这个过程中,分子(欧氏距离)是跟梯度的值有关的,随着迭代次数的增加,也会减小。那在迭代过程中,我们只利用分子就没有一个固定标准去判断梯度检验的效果,而加上一个分母,将梯度的平方和考虑进去,大值比大值,小值比小值,我们就可以得到一个比率,同样也可以得到一个确定的标准去衡量梯度检验的效果。
算法⚓︎
- 初始化神经网络的所有矩阵参数(可以使用随机初始化或其它非0的初始化方法)
- 把所有层的
都转化成向量,按顺序存放在 中 - 随机设置
值,最好是归一化之后的值,在[0,1]之间 - 做一次前向计算,再紧接着做一次反向计算,得到各参数的梯度
- 把得到的梯度
变化成向量形式,其尺寸应该和第2步中的 相同,且一一对应( 对应 , 对应 ) - 对2中的
向量中的每一个值,做一次双边逼近,得到 - 比较
和 的值,通过计算两个向量之间的欧式距离:
结果判断:
梯度计算肯定出了问题。
可能有问题了,需要检查。
不光滑的激励函数来说时可以接受的,但是如果使用平滑的激励函数如 tanh nonlinearities and softmax,这个结果还是太高了。
可以喝杯茶庆祝下。
另外要注意的是,随着网络深度的增加会使得误差积累,如果用了10层的网络,得到的相对误差为1e-2
那么这个结果也是可以接受的。
12.2.5 注意事项⚓︎
-
首先,不要使用梯度检验去训练,即不要使用梯度检验方法去计算梯度,因为这样做太慢了,在训练过程中,我们还是使用backprop去计算参数梯度,而使用梯度检验去调试,去检验backprop的过程是否准确。
-
其次,如果我们在使用梯度检验过程中发现backprop过程出现了问题,就需要对所有的参数进行计算,以判断造成计算偏差的来源在哪里,它可能是在求解
出现问题,也可能是在求解某一层的 出现问题,梯度检验可以帮助我们确定发生问题的范围,以帮助我们调试。 -
别忘了正则化。如果我们添加了二范数正则化,在使用backprop计算参数梯度时,不要忘记梯度的形式已经发生了变化,要记得加上正则化部分,同理,在进行梯度检验时,也要记得目标函数
的形式已经发生了变化。 -
注意,如果我们使用了drop-out正则化,梯度检验就不可用了。为什么呢?因为我们知道drop-out是按照一定的保留概率随机保留一些节点,因为它的随机性,目标函数
的形式变得非常不明确,这时我们便无法再用梯度检验去检验backprop。如果非要使用drop-out且又想检验backprop,我们可以先将保留概率设为1,即保留全部节点,然后用梯度检验来检验backprop过程,如果没有问题,我们再改变保留概率的值来应用drop-out。 -
最后,介绍一种特别少见的情况。在刚开始初始化W和b时,W和b的值都还很小,这时backprop过程没有问题,但随着迭代过程的进行,
和 的值变得越来越大时,backprop过程可能会出现问题,且可能梯度差距越来越大。要避免这种情况,我们需要多进行几次梯度检验,比如在刚开始初始化权重时进行一次检验,在迭代一段时间之后,再使用梯度检验去验证backprop过程。
代码位置⚓︎
ch12, Level2
思考与练习⚓︎
- 改变任意一行反向传播代码,再运行梯度检查代码,看看结果如何。