网易课程DeepLearning.ai 吴恩达深度学习课程笔记:第三周④:神经网络的梯度下降、随机初始化

神经网络的梯度下降(Gradient descent for neural networks)

在这个视频中,我会给你实现反向传播或者说梯度下降算法的方程组,在下一个视频我们会介绍为什么这几个特定的方程是针对你的神经网络实现梯度下降的正确方程。

你的单隐层神经网络会有W[1]b[1]W[2]b[2] 这些参数,还有个nx 表示输入特征的个数,n[1] 表示隐藏单元个数,n[2] 表示输出单元个数。

在我们的例子中,我们只介绍过的这种情况,那么参数:

矩阵W[1] 的维度就是(n[1],n[0] ),b[1] 就是n[1] 维向量,可以写成(n[1],1) ,就是一个的列向量。 矩阵W[2] 的维度就是(n[2],n[1] ),b[2] 的维度就是(n[2],1) 维度。

你还有一个神经网络的成本函数,假设你在做二分类任务,那么你的成本函数等于:

Cost function:

公式: J(W[1],b[1],W[2],b[2])=1mi=1mL(y,y)  

loss function和之前做logistic回归完全一样。

训练参数需要做梯度下降,在训练神经网络的时候,随机初始化参数很重要,而不是初始化成全零。当你参数初始化成某些值后,每次梯度下降都会循环计算以下预测值:

正向传播方程如下(之前讲过):

 forward propagation

反向传播方程如下:

back propagation

公式3.35:

 

上述是反向传播的步骤,注:这些都是针对所有样本进行过向量化,Y1×m 的矩阵;这里np.sum是pythonnumpy命令,axis=1表示水平相加求和,keepdims是防止python输出那些古怪的秩数(n,) ,加上这个确保阵矩阵db[2] 这个向量输出的维度为(n,1) 这样标准的形式。

目前为止,我们计算的都和Logistic回归十分相似,但当你开始计算反向传播时,你需要计算,是隐藏层函数的导数,输出在使用sigmoid函数进行二元分类。这里是进行逐个元素乘积,因为W[2]Tdz[2](z[1]) 这两个都为(n[1],m) 矩阵;

还有一种防止python输出奇怪的秩数,需要显式地调用reshape把np.sum输出结果写成矩阵形式。

以上就是正向传播的4个方程和反向传播的6个方程,这里我是直接给出的,在下个视频中,我会讲如何导出反向传播的这6个式子的。如果你要实现这些算法,你必须正确执行正向和反向传播运算,你必须能计算所有需要的导数,用梯度下降来学习神经网络的参数;你也可以许多成功的深度学习从业者一样直接实现这个算法,不去了解其中的知识。

随机初始化(Random+Initialization)

当你训练神经网络时,权重随机初始化是很重要的。对于逻辑回归,把权重初始化为0当然也是可以的。但是对于一个神经网络,如果你把权重或者参数都初始化为0,那么梯度下降将不会起作用。

让我们看看这是为什么。有两个输入特征,n[0]=2 ,2个隐藏层单元n[1] 就等于2。 因此与一个隐藏层相关的矩阵,或者说W[1] 是2*2的矩阵,假设把它初始化为0的2*2矩阵,b[1] 也等于 [0 0]T ,把偏置项b 初始化为0是合理的,但是把w 初始化为0就有问题了。 那这个问题如果按照这样初始化的话,你总是会发现a1[1]  和 a2[1] 相等,这个激活单元和这个激活单元就会一样。因为两个隐含单元计算同样的函数,当你做反向传播计算时,这会导致dz1[1]  和 dz2[1] 也会一样,对称这些隐含单元会初始化得一样,这样输出的权值也会一模一样,由此W[2] 等于[0 0]

图3.11.1 但是如果你这样初始化这个神经网络,那么这两个隐含单元就会完全一样,因此他们完全对称,也就意味着计算同样的函数,并且肯定的是最终经过每次训练的迭代,这两个隐含单元仍然是同一个函数,令人困惑。dW 会是一个这样的矩阵,每一行有同样的值因此我们做权重更新把权重W[1]W[1]-adW 每次迭代后的W[1] ,第一行等于第二行。

由此可以推导,如果你把权重都初始化为0,那么由于隐含单元开始计算同一个函数,所有的隐含单元就会对输出单元有同样的影响。一次迭代后同样的表达式结果仍然是相同的,即隐含单元仍是对称的。通过推导,两次、三次、无论多少次迭代,不管你训练网络多长时间,隐含单元仍然计算的是同样的函数。因此这种情况下超过1个隐含单元也没什么意义,因为他们计算同样的东西。当然更大的网络,比如你有3个特征,还有相当多的隐含单元。

如果你要初始化成0,由于所有的隐含单元都是对称的,无论你运行梯度下降多久,他们一直计算同样的函数。这没有任何帮助,因为你想要两个不同的隐含单元计算不同的函数,这个问题的解决方法就是随机初始化参数。你应该这么做:把W[1] 设为np.random.randn(2,2)(生成高斯分布),通常再乘上一个小的数,比如0.01,这样把它初始化为很小的随机数。然后b 没有这个对称的问题(叫做symmetry breaking problem),所以可以把 b  初始化为0,因为只要随机初始化W 你就有不同的隐含单元计算不同的东西,因此不会有symmetry breaking问题了。相似的,对于W[2] 你可以随机初始化,b[2] 可以初始化为0。

W1=np.random.randn2,2 * 0.01 ,

b[1]=np.zeros((2,1))  

W[2]=np.random.randn(2,2) * 0.01 , b[2]=0

你也许会疑惑,这个常数从哪里来,为什么是0.01,而不是100或者1000。我们通常倾向于初始化为很小的随机数。因为如果你用tanh或者sigmoid激活函数,或者说只在输出层有一个Sigmoid,如果(数值)波动太大,当你计算激活值时z[1]=W[1]x+b[1] , a[1]=σ(z[1])=g[1](z[1]) 如果W 很大,z 就会很大。z 的一些值a 就会很大或者很小,因此这种情况下你很可能停在tanh/sigmoid函数的平坦的地方(见图3.8.2),这些地方梯度很小也就意味着梯度下降会很慢,因此学习也就很慢。

回顾一下:如果w 很大,那么你很可能最终停在(甚至在训练刚刚开始的时候)z 很大的值,这会造成tanh/Sigmoid激活函数饱和在龟速的学习上,如果你没有sigmoid/tanh激活函数在你整个的神经网络里,就不成问题。但如果你做二分类并且你的输出单元是Sigmoid函数,那么你不会想让初始参数太大,因此这就是为什么乘上0.01或者其他一些小数是合理的尝试。对于w[2] 一样,就是np.random.randn((1,2)),我猜会是乘以0.01。

事实上有时有比0.01更好的常数,当你训练一个只有一层隐藏层的网络时(这是相对浅的神经网络,没有太多的隐藏层),设为0.01可能也可以。但当你训练一个非常非常深的神经网络,你可能会选择一个不同于的常数而不是0.01。下一节课我们会讨论怎么并且何时去选择一个不同于0.01的常数,但是无论如何它通常都会是个相对小的数。

好了,这就是这周的视频。你现在已经知道如何建立一个一层的神经网络了,初始化参数,用前向传播预测,还有计算导数,结合反向传播用在梯度下降中。

猜你喜欢

转载自blog.csdn.net/qq_36552489/article/details/93780788