Initialization & Regularization & Gradient Checking-3

版权为吴恩达老师所有,参考Koala_Tree的博客,部分根据自己实践添加

使用google翻译,部分手工翻译

你可能需要的参考资料https://pan.baidu.com/s/1D2lzBvUQ3gF4RzenBeob2w

第3部分:梯度检查

首先导入您需要的库

import numpy as np 
from testCases import *
from gc_utils import sigmoid,relu,dictionary_to_vector,vector_to_dictionary,gradients_to_vector

1.梯度检查如何工作?

向传播计算梯度\frac{\partial J}{\partial \theta },其中θ表示模型的参数。J是使用前向传播的和您的损失函数计算。

因为前向传播相对容易实现,所以你确信你做对了,所以你几乎100%确定你是在计算成本J正确。因此,您可以使用您的代码来计算J验证计算\frac{\partial J}{\partial \theta }的代码

让我们回顾一下导数(或梯度)的定义: 

如果你不熟悉\lim_{\varepsilon \rightarrow 0}符号,这只是一种说法”当ε 真的很小。“

我们知道以下内容:

  • \frac{\partial J}{\partial \theta }是你想要确保正确计算的东西。
  • 你可以计算(J+\theta ) 和 (J-\theta )(在这种情况下θ是一个实数),因为你对J的实施充满信心是正确的。

让我们使用等式和很小的值ε说服你的CEO你的计算代码 \frac{\partial J}{\partial \theta }是正确的!

2.一维梯度检查

考虑一维线性函数J(\theta )=\theta x。该模型仅包含单个实值参数θ,并采取x作为输入。

您将实现要计算的代码 J.(.) 及其导数\frac{\partial J}{\partial \theta }。然后,您将使用梯度检查来确保J的导数计算是正确的。

还在路上,稍等... 

                                图1 : 1D线性模型

上图显示了关键的计算步骤:首先从x开始,然后计算函数J(x)(“前向传播”)。然后计算导数\frac{\partial J}{\partial \theta }(“向后传播”)。

练习:为这个简单的函数实现“向前传播”和“向后传播”。即,分别在两个函数中计算J(.)(“前向传播”)及其相对于θ的导数(“向后传播”)。

def forward_propagation(x,theta):
    J=theta*x

    return J
x, theta = 2, 4
J = forward_propagation(x, theta)
print ("J = " + str(J))

练习:现在,实现图1的后向传播步骤(微分计算)。即,计算对于\thetaJ(\theta )=\theta x导数。无需你去做微积分,你应该得到dtheta=\frac{\partial J}{\partial \theta }=x

def backward_propagation(x,theta):
    dtheta=x

    return dtheta
x,theta=2,4
dtheta=backward_propagation(x,theta)
print("dtheta = "+str(dtheta))

练习:显示backward_propagation()函数正确计算梯度\frac{\partial J}{\partial \theta },让我们实现梯度检查。

说明
- 首先使用上面的公式和ε计算“gradapprox”。下面是要遵循的步骤:
\theta ^{+}=\theta +\varepsilon

\theta ^{-}=\theta -\varepsilon

J^{+}=J(\theta ^{+})

J^{-}=J(\theta ^{-})
gradapprox=\frac{J^{+}-J^{-}}{2\varepsilon }
- 然后使用向后传播计算梯度,并将结果存储在变量“grad”中
- 最后,使用以下公式计算“gradapprox”和“grad”之间的相对差异:

difference= \frac{||grad-gradapprox||_{2}}{||grad||_{2}+||gradapprox||_{2}}
您将需要3个步骤来计算此公式:
-1'.使用np.linalg.norm(...)
- 2'. 计算分子和分母。您需要两次调用np.linalg.norm(...)。
- 3'.将它们相除。
- 如果这个差异很小(比如小于10^{-7}),你可以非常自信你已经正确计算了你的梯度。否则,梯度计算中可能存在错误。

def gradient_check(x,theta,epsilon=1e-7):
    thetaplus=theta+epsilon
    thetaminus=theta-epsilon
    J_plus=forward_propagation(x,thetaplus)
    J_minus=forward_propagation(x,thetaminus)
    gradapprox=(J_plus-J_minus)/(2*epsilon)

    grad=backward_propagation(x,theta)

    numerator=np.linalg.norm(grad-gradapprox)
    denominator=np.linalg.norm(grad)+np.linalg.norm(gradapprox)
    difference=numerator/denominator

    if difference<1e-7:
        print("The gradient is correct!")
    else:
        print("The gradient is wrong!")

    return difference
x,theta=2,4
difference=gradient_check(x,theta)
print("difference = "+str(difference))

恭喜,差异小于110^{-7}。因此,您可以高度确信已正确计算了梯度backward_propagation()

现在,在更一般的情况下,您的成本函数J有一个以上的1D输入。当你训练神经网络时,θ实际上由多个矩阵W^{[l]}和偏差b^{[l]}组成!了解如何使用更高维度的输入进行梯度检查非常重要。我们开始做吧!

3.N维梯度检查

下图描述了检测模型的前向和后向传播。

还在路上,稍等...

                                  图2 :深度神经网络
LINEAR - > RELU - > LINEAR - > RELU - > LINEAR - > SIGMOID

我们来看看你的前向传播和后向传播的实现。

def forward_propagation_n(X,Y,parameters):
    m=X.shape[1]
    W1=parameters["W1"]
    b1=parameters["b1"]
    W2=parameters["W2"]
    b2=parameters["b2"]
    W3=parameters["W3"]
    b3=parameters["b3"]

    Z1=np.dot(W1,X)+b1
    A1=relu(Z1)
    Z2=np.dot(W2,A1)+b2
    A2=relu(Z2)
    Z3=np.dot(W3,A2)+b3
    A3=relu(Z3)
    
    logprobs=np.multiply(-np.log(A3),Y)+np.multiply(-np.log(1-A3),1-Y)
    cost=1.0/m*np.sum(logprobs)

    cache=(Z1,A1,W1,b1,Z2,A2,W2,b2,Z3,A3,W3,b3)

    return cost,cache

现在,运行向后传播。

def backward_propagation_n(X,Y,cache):
    m=X.shape[1]
    (Z1,A1,W1,b1,Z2,A2,W2,b2,Z3,A3,W3,b3)=cache

    dZ3=A3-Y
    dW3=1.0/m*np.dot(dZ3,A2.T)
    db3=1.0/m*np.sum(dZ3,axis=1,keepdims=True)

    dA2=np.dot(W3.T,dZ3)
    dZ2=np.multiply(dA2,np.int64(A2>0))
    dW2=1.0/m*np.dot(dZ2,A1.T)
    db2=1.0/m*np.sum(dZ2,axis=1,keepdims=True)

    dA1=np.dot(W2.T,dZ2)
    dZ1=np.multiply(dA1,np.int64(A1>0))
    dW1=1.0/m*np.dot(dZ1,X.T)
    db1=1.0/m*np.sum(dZ1,axis=1,keepdims=True)

    gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,
    "dA2": dA2, "dZ2": dZ2, "dW2": dW2, "db2": db2,
    "dA1": dA1, "dZ1": dZ1, "dW1": dW1, "db1": db1}

    return gradients

您在检测测试集上获得了一些结果,但您并不是100%确定您的模型。没有人是完美的!让我们实现梯度检查以验证您的渐变是否正确。

梯度检查如何工作?

您想要将“gradapprox”与通过反向传播计算的梯度进行比较。公式仍然是:

但是,θ不再是标量了。这是一个名为“参数”的字典。我们为您实现了一个函数“dictionary_to_vector() ”。它将“参数”字典转换为称为“值”的向量,通过将所有参数(W1,b1,W2,b2,W3,b3)重新变形为向量并将它们连接而获得。

反函数是“ vector_to_dictionary”,它输出“参数”字典。

还在路上,稍等...

                          图2 : dictionary_to_vector()和vector_to_dictionary()
您将需要在gradient_check_n()中使用这些函数

我们还使用gradients_to_vector()将“gradients”字典转换为矢量“grad”。你不必担心这一点。

练习:实现gradient_check_n()。

说明:这是伪代码,可以帮助您实现渐变检查。

对于num_parameters中的每个i:
- 要计算J_plus[i]
1.设置\theta ^{+}np.copy(parameters_values) 
2.设置\theta ^{+}_{i}到 \theta_{i}^{+} +\varepsilon
3.使用forward_propagation_n(x, y, vector_to_dictionary(\theta ^{+} ))计算J^{+}_{i}
- 计算J_minus[i]:用\theta ^{-}做同样的事情

- 计算gradapprox[i]=\frac{J_{i}^{+}-J_{i}^{-}}{2\varepsilon }

因此,您得到一个向量gradapprox,其中gradapprox [i]是相对于梯度的近似值parameter_values[i]。您现在可以将此gradapprox向量与来自反向传播的梯度向量进行比较。就像1D案例一样,计算: 

difference= \frac{||grad-gradapprox||_{2}}{||grad||_{2}+||gradapprox||_{2}}

def gradient_check_n(parameters,gradients,X,Y,epsilon=1e-7):
    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):
        thetaplus=np.copy(parameters_values)
        thetaplus[i][0]=thetaplus[i][0]+epsilon
        J_plus[i],_=forward_propagation_n(X,Y,vector_to_dictionary(thetaplus))

        thetaminus=np.copy(parameters_values)
        thetaminus[i][0]=thetaminus[i][0]-epsilon
        J_minus[i],_=forward_propagation_n(X,Y,vector_to_dictionary(thetaminus))

        gradapprox[i]=(J_plus[i]-J_minus[i])/(2.0*epsilon)

    numerator=np.linalg.norm(grad-gradapprox)
    denominator=np.linalg.norm(grad)+np.linalg.norm(gradapprox)
    difference=numerator/denominator

    if difference>1e-7:
        print("There is a mistake in the backward propagation! difference = "+str(difference))
    else:
        print ("Your backward propagation works perfectly fine! difference = "+str(difference))

    return difference
X, Y, parameters = gradient_check_n_test_case()

cost, cache = forward_propagation_n(X, Y, parameters)
gradients = backward_propagation_n(X, Y, cache)
difference = gradient_check_n(parameters, gradients, X, Y)

你能得到梯度检查来宣告你的梯度计算是否正确?

注意 
- 渐变检查很慢!用∂逼近梯度\frac{\partial J}{\partial \theta }\approx \frac{J(\theta +\varepsilon )-\theta -\varepsilon}{2\varepsilon }计算成本很高。因此,我们不会在训练期间的每次迭代中运行梯度检查。只需几次检查渐变是否正确。 
- 至少在我们当前的情况下,渐变检查不适用于dropout。您通常会在没有dropout的情况下运行渐变检查算法,以确保您的backprop是正确的,然后添加dropout。

恭喜,您可以确信您的欺诈检测深度学习模型正常运行!你甚至可以用它来说服你的CEO。:)

你应该从中记住
- 梯度检查验证了来自反向传播的梯度与梯度的数值近似(使用前向传播计算)之间的接近程度。
- 梯度检查很慢,因此我们不会在每次训练迭代中运行它。您通常只运行它以确保您的代码是正确的,然后将其关闭并使用backprop进行实际的学习过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值