实现神经网络的时候,如果不能确定反向传播计算梯度的时候有没有错误,这时候就可以进行梯度检验。简单来说梯度检验的目的就是检查程序反向传播部分有没有Bug。
数学分析
首先来看导数的数学定义:
(1)
f
′
θ
)
=
lim
ε
→
0
f
(
θ
+
ε
)
−
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
=
θ
3
y=\theta^3
y=θ3 为例。我们可以根据其导函数求得在
θ
=
1
\theta=1
θ=1 时的导数值为
f
′
(
θ
=
1
)
=
3
θ
2
=
3
f'(\theta=1)=3\theta^2=3
f′(θ=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],反向传播过程求得的梯度参数为
d
W
[
1
]
,
d
b
[
1
]
,
d
W
[
2
]
,
d
b
[
2
]
,
.
.
.
,
d
W
[
L
]
,
d
W
[
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]。为了检验每一个参数
w
w
w 的值,首先将他们所有的值分别转化为向量
θ
\theta
θ 和
d
θ
d\theta
dθ
(3)
θ
=
[
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
]
.
.
.
]
\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 θ = [ d w 11 [ 1 ] , d w 12 [ 1 ] , . . . , d b 1 [ 1 ] , d b 1 [ 2 ] , d w 11 [ 2 ] , d w 12 [ 2 ] , . . . , d b 1 [ 2 ] , d b 2 [ 2 ] , . . . , d w 11 [ L ] , d w 12 [ L ] , . . . , d b 1 [ L ] , d b 2 [ 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 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]...](4)
这样,对于第
i
i
i 个元素,根据首先计算在当前位置的双边误差
(5)
d
θ
a
p
p
r
o
x
[
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)
其中
J
J
J 表示损失函数值。
由前面的分析可以得到正确计算的情况下
d
θ
a
p
p
r
o
x
[
i
]
d \theta_{\mathrm{approx}}[i]
dθapprox[i] 应该是很接近损失函数在
θ
\theta
θ 处的偏导数
d
θ
i
=
∂
J
∂
θ
i
d \theta_i=\frac{\partial J}{\partial \theta_{i}}
dθi=∂θi∂J 的值,这样在计算式(5)得到每一个
θ
i
\theta_i
θi 的值之后,得到的
d
θ
a
p
p
r
o
x
d \theta_{\mathrm{approx}}
dθapprox 应当是非常接近
d
θ
d\theta
dθ 的,我们通过以下式子来计算他们的误差
(6)
c
h
e
c
k
_
e
r
r
o
r
=
∣
∣
d
θ
a
p
p
r
o
x
−
d
θ
∣
∣
2
∣
∣
d
θ
a
p
p
r
o
x
∣
∣
2
+
∣
∣
d
θ
∣
∣
2
check\_error=\frac{||d \theta_{\mathrm{approx}}-d\theta||_2}{||d \theta_{\mathrm{approx}}||_2+||d\theta||_2} \tag6
check_error=∣∣dθapprox∣∣2+∣∣dθ∣∣2∣∣dθapprox−dθ∣∣2(6)
其中
∣
∣
⋅
∣
∣
2
||·||_2
∣∣⋅∣∣2 表示向量的欧几里得范数。
一般来说,在
ε
=
1
e
−
7
\varepsilon=1e-7
ε=1e−7 时,如果通过式(6)计算得到的结果小于
1
e
−
7
1e-7
1e−7表明梯度计算是没有问题的。
注意
- 梯度检验知识一个调试Bug的技巧,因此在训练过程是不使用梯度检验的;
- 梯度检验的时候不要忘记正则化项;
- 不要和dropout同时使用