实现神经网络的时候,如果不能确定反向传播计算梯度的时候有没有错误,这时候就可以进行梯度检验。简单来说梯度检验的目的就是检查程序反向传播部分有没有Bug。
数学分析
首先来看导数的数学定义:
(1)f′θ)=limε→0f(θ+ε)−f(θ−ε)2ε
f^{\prime} \theta )=\lim_{\varepsilon \to 0}\frac{f(\theta+\varepsilon)-f(\theta-\varepsilon)}{2 \varepsilon} \tag1
f′θ)=ε→0lim2εf(θ+ε)−f(θ−ε)(1)
以 y=θ3y=\theta^3y=θ3 为例。我们可以根据其导函数求得在 θ=1\theta=1θ=1 时的导数值为 f′(θ=1)=3θ2=3f'(\theta=1)=3\theta^2=3f′(θ=1)=3θ2=3。对于式(1),如果我们不考虑求极限,可以得到在 θ=1\theta=1θ=1 时的导数的近似值为(令 ε=0.001\varepsilon=0.001ε=0.001,称下式为双边误差)
(2)f′θ)∣θ=1=f(1.01)−f(0.99)0.02=3.0001
f^{\prime} \theta )|_{\theta=1}=\frac{f(1.01)-f(0.99)}{0.02}=3.0001 \tag2
f′θ)∣θ=1=0.02f(1.01)−f(0.99)=3.0001(2)
可以看到,在计算正确的时候,由导函数计算出来的值应该是和双边误差计算出来的值非常接近的。
具体到神经网络的梯度值。对于一个神经网络,假设它的所有权重和阈值参数为W[1],b[1],W[2],b[2],...,W[L],W[L]\bold{W}^{[1]},\bold{b}^{[1]},\bold{W}^{[2]},\bold{b}^{[2]},...,\bold{W}^{[L]},\bold{W}^{[L]}W[1],b[1],W[2],b[2],...,W[L],W[L],反向传播过程求得的梯度参数为dW[1],db[1],dW[2],db[2],...,dW[L],dW[L]d\bold{W}^{[1]},d\bold{b}^{[1]},d\bold{W}^{[2]},d\bold{b}^{[2]},...,d\bold{W}^{[L]},d\bold{W}^{[L]}dW[1],db[1],dW[2],db[2],...,dW[L],dW[L]。为了检验每一个参数 www 的值,首先将他们所有的值分别转化为向量 θ\thetaθ 和 dθd\thetadθ
(3)θ=[w11[1],w12[1],...,b1[1],b1[2],w11[2],w12[2],...,b1[2],b2[2],...,w11[L],w12[L],...,b1[L],b2[L]...]\theta=[w_{11}^{[1]},w_{12}^{[1]},...,b_1^{[1]}, b_1^{[2]},w_{11}^{[2]},w_{12}^{[2]},...,b_1^{[2]}, b_2^{[2]},...,w_{11}^{[L]},w_{12}^{[L]},...,b_1^{[L]}, b_2^{[L]}...] \tag 3θ=[w11[1],w12[1],...,b1[1],b1[2],w11[2],w12[2],...,b1[2],b2[2],...,w11[L],w12[L],...,b1[L],b2[L]...](3)
(4)dθ=[dw11[1],dw12[1],...,db1[1],db1[2],dw11[2],dw12[2],...,db1[2],db2[2],...,dw11[L],dw12[L],...,db1[L],db2[L]...]d\theta=[dw_{11}^{[1]},dw_{12}^{[1]},...,db_1^{[1]}, db_1^{[2]},dw_{11}^{[2]},dw_{12}^{[2]},...,db_1^{[2]}, db_2^{[2]},...,dw_{11}^{[L]},dw_{12}^{[L]},...,db_1^{[L]},d b_2^{[L]}...] \tag 4dθ=[dw11[1],dw12[1],...,db1[1],db1[2],dw11[2],dw12[2],...,db1[2],db2[2],...,dw11[L],dw12[L],...,db1[L],db2[L]...](4)
这样,对于第 iii 个元素,根据首先计算在当前位置的双边误差
(5)dθapprox[i]=J(θ1,θ2,…θi+ε,…)−J(θ1,θ2,…θi−ε,…)2ε
d \theta_{\mathrm{approx}}[i]=\frac{J\left(\theta_{1}, \theta_{2}, \ldots \theta_{i}+\varepsilon, \ldots\right)-J\left(\theta_{1}, \theta_{2}, \ldots \theta_{i}-\varepsilon, \ldots\right)}{2 \varepsilon} \tag5
dθapprox[i]=2εJ(θ1,θ2,…θi+ε,…)−J(θ1,θ2,…θi−ε,…)(5)
其中 JJJ 表示损失函数值。
由前面的分析可以得到正确计算的情况下 dθapprox[i]d \theta_{\mathrm{approx}}[i]dθapprox[i] 应该是很接近损失函数在θ\thetaθ 处的偏导数 dθi=∂J∂θid \theta_i=\frac{\partial J}{\partial \theta_{i}}dθi=∂θi∂J 的值,这样在计算式(5)得到每一个 θi\theta_iθi 的值之后,得到的 dθapproxd \theta_{\mathrm{approx}}dθapprox 应当是非常接近 dθd\thetadθ 的,我们通过以下式子来计算他们的误差
(6)check_error=∣∣dθapprox−dθ∣∣2∣∣dθapprox∣∣2+∣∣dθ∣∣2check\_error=\frac{||d \theta_{\mathrm{approx}}-d\theta||_2}{||d \theta_{\mathrm{approx}}||_2+||d\theta||_2} \tag6check_error=∣∣dθapprox∣∣2+∣∣dθ∣∣2∣∣dθapprox−dθ∣∣2(6)
其中 ∣∣⋅∣∣2||·||_2∣∣⋅∣∣2 表示向量的欧几里得范数。
一般来说,在 ε=1e−7\varepsilon=1e-7ε=1e−7 时,如果通过式(6)计算得到的结果小于 1e−71e-71e−7表明梯度计算是没有问题的。
注意
- 梯度检验知识一个调试Bug的技巧,因此在训练过程是不使用梯度检验的;
- 梯度检验的时候不要忘记正则化项;
- 不要和dropout同时使用