学习目标
使用Numpy实现梯度检验,理解其原理。
笔记
1.理解梯度检验
导数(梯度)的定义:
∂
J
∂
θ
=
lim
ε
→
0
J
(
θ
+
ε
)
−
J
(
θ
−
ε
)
2
ε
\frac{\partial J}{\partial \theta} = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}
∂θ∂J=ε→0lim2εJ(θ+ε)−J(θ−ε)
梯度检验:取一个很小的值,记作
ε
\varepsilon
ε,代入
J
(
θ
+
ε
)
−
J
(
θ
−
ε
)
2
ε
\frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}
2εJ(θ+ε)−J(θ−ε)计算得到gradapprox,如果gradapprox和梯度grad差异很小(低于一个阈值,一般取
1
0
−
7
10^{-7}
10−7),则说明之前求导得到的梯度是正确的。
2.实现梯度检验
2.1 一维梯度检验
- 创建一个变量 θ + \theta^{+} θ+, θ + = θ + ε \theta^{+} = \theta + \varepsilon θ+=θ+ε;
- 创建一个变量 θ − \theta^{-} θ−, θ − = θ − ε \theta^{-} = \theta - \varepsilon θ−=θ−ε;
- 创建一个变量 J + J^{+} J+, J + = J ( θ + ) J^{+} = J(\theta^{+}) J+=J(θ+);
- 创建一个变量 J − J^{-} J−, J − = J ( θ − ) J^{-} = J(\theta^{-}) J−=J(θ−);
- 创建一个变量 g r a d a p p r o x gradapprox gradapprox, g r a d a p p r o x = J + − J − 2 ε gradapprox = \frac{J^{+} - J^{-}}{2 \varepsilon} gradapprox=2εJ+−J−;
- 计算 g r a d grad grad, g r a d = J ( θ ) grad = J(\theta) grad=J(θ);
- 计算 d i f f e r e n c e difference difference, d i f f e r e n c e = ∣ ∣ g r a d − g r a d a p p r o x ∣ ∣ 2 ∣ ∣ g r a d ∣ ∣ 2 + ∣ ∣ g r a d a p p r o x ∣ ∣ 2 difference = \frac {\mid\mid grad - gradapprox \mid\mid_2}{\mid\mid grad \mid\mid_2 + \mid\mid gradapprox \mid\mid_2} difference=∣∣grad∣∣2+∣∣gradapprox∣∣2∣∣grad−gradapprox∣∣2
- 如果 d i f f e r e n c e < 1 0 − 7 difference<10^{-7} difference<10−7,说明梯度计算正确。
其中, d i f f e r e n c e difference difference的计算用python表示是:
numerator = np.linalg.norm(grad - gradapprox)
denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox)
difference = numerator / denominator
2.2 N维梯度检验
N维梯度检验与一维梯度检验不同的是此处的
θ
\theta
θ不再是标量,而是一个字典(图中parameters),整体的计算思路一致。图中说明了在进行N维梯度检验时要用到的两个函数dictionary_to_vector() 和 vector_to_dictionary() 的用途。
N维梯度检验(gradient_check_n)的python代码如下:
def gradient_check_n(parameters, gradients, X, Y, epsilon=1e-7, print_msg=False):
# 创建变量
parameters_values, _ = dictionary_to_vector(parameters)
grad = gradients_to_vector(gradients)
num_parameters = parameters_values.shape[0]
J_plus = np.zeros((num_parameters, 1))
J_minus = np.zeros((num_parameters, 1))
gradapprox = np.zeros((num_parameters, 1))
for i in range(num_parameters):
theta_plus = np.copy(parameters_values)
theta_plus[i] = theta_plus[i][0] + epsilon
J_plus[i], _ = forward_propagation_n(X, Y, vector_to_dictionary(theta_plus))
theta_minus = np.copy(parameters_values)
theta_minus[i] = theta_minus[i][0] - epsilon
J_minus[i], _ = forward_propagation_n(X, Y, vector_to_dictionary(theta_minus))
gradapprox[i] = (J_plus[i] - J_minus[i]) / (2*epsilon)
numerator = np.linalg.norm(grad - gradapprox)
denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox)
difference = numerator / denominator
return difference
学习时间
2022.6.27
总结
-
梯度检验可验证反向传播的梯度与梯度近似值之间的接近度(使用正向传播进行计算);
-
梯度检验很慢,用 ∂ J ∂ θ ≈ J ( θ + ε ) − J ( θ − ε ) 2 ε \frac{\partial J}{\partial \theta} \approx \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon} ∂θ∂J≈2εJ(θ+ε)−J(θ−ε)逼近梯度很耗费资源,通常只需检查几次梯度是否正确。
-
梯度检验不适用于dropout。先运行不带dropout的梯度检验算法以确保后向传播正确,然后添加dropout。
需要注意的地方
- 梯度检验时将参数W,b当作自变量而不是x;
- 未完待续。