选自imaddabbura
机器之心编译,禁止二次转载
参与:刘天赐、路
本文介绍了如何使用梯度检验方法确认反向传播代码是否准确。
在《Coding Neural Network - Forward Propagation and Backpropagation》一文中,我们借助 numpy 实现了前向传播和反向传播算法。但从头开始实现反向传播很容易遇到 bug 或者报错。因此,在训练数据上运行神经网络之前,必须检验反向传播的实现是否正确。不过首先,我们先复习一下反向传播的概念:从最后的节点开始,沿着拓扑排序的反方向遍历所有节点,计算每个边的尾节点相对于损失函数的导数。换言之,计算损失函数对所有参数的导数:∂J/∂θ,其中θ表示模型中的参数。
我们通过计算数值梯度并比较数值梯度和根据反向传播求出的梯度(解析梯度)间的差异,来测试我们的实现代码。这里有两种数值梯度的计算方法:
右边形式:
(1) [J(θ+ϵ)−J(θ)]/ϵ
双边形式(见图 2):
(2) [J(θ+ϵ)−J(θ−ϵ)]/2ϵ
图 2:双边数值梯度
逼近导数的双边形式比右边形式更接近真实值。我们以 f(x)=x^2 为例,在 x=3 处计算导数。
可以看到,解析梯度和双边数值梯度之间的差值几乎为零;而和右边形式的数值梯度之间的差值为 0.01。因此在下文中,我们使用双边形式计算数值梯度。
另外,我们使用下式对数值梯度和解析梯度间的差值进行标准化。
(3)
如果差值≤10^−7,可以认为反向传播的实现代码没有问题;否则,就需要回去检查代码,因为一定有什么地方出错了。
以下是完成梯度检验的步骤:
1. 随机从训练集中抽取一些样本,用来计算数值梯度和解析梯度(不要使用所有训练样本,因为梯度检验运行会很慢)。
2. 初始化参数。
3. 计算前向传播和交叉熵损失。
4. 利用写好的反向传播的实现代码计算梯度(解析梯度)。
5. 计算双边形式的数值梯度。
6. 计算数值梯度和解析解梯度的差值。
这里,我们使用《Coding Neural Network - Forward Propagation and Backpropagation》中所写的函数来实现参数初始化、前向传播、反向传播以及交叉熵损失的计算。
导入数据。
编写 helper 函数,帮助实现参数和梯度词典(gradients dictionary)到向量的相互转换。
最后,编写梯度检验函数,利用此函数计算解析梯度和数值梯度之间的差值,并借此判断反向传播的实现代码是否正确。我们随机抽取 1 个样本来计算差值:
结论
以下是一些关键点:
双边形式的数值梯度在逼近解析梯度时效果比单边形式的数值梯度更好。
由于梯度检验的运行很慢,因此:
进行梯度检验时,只使用一个或少数样本;
在确认反向传播的实现代码无误后,训练神经网络时记得取消梯度检验函数的调用。
如果使用了 drop-out 策略,(直接进行)梯度检验会失效。可以在进行梯度检验时,将 keep-prob 设置为 1,训练神经网络时,再进行修改。
通常采用 e=10e-7 作为检查解析梯度和数值梯度间差值的基准。如果差值小于 10e-7,则反向传播的实现代码没有问题。
幸运的是,在诸如 TensorFlow、PyTorch 等深度学习框架中,我们几乎不需要自己实现反向传播,因为这些框架已经帮我们计算好梯度了;但是,在成为一个深度学习工作者之前,动手实现这些算法是很好的练习,可以帮助我们理解其中的原理。
源代码地址:https://github.com/ImadDabbura/blog-posts/blob/master/notebooks/Coding-Neural-Network-Gradient-Checking.ipynb
领取专属 10元无门槛券
私享最新 技术干货