吴恩达(单层神经网络构建)
本周将会学习如何构建一个单层次的神经网络。上周学习了logistic回归,下面将它和上面的神经网络模型连接起来。在logistic回归当中,首先会输入特征向量x和参数w、b,然后计算z=wTx+b,然后计算预测值y^=a=sigmoid(z),最后计算损失值L。神经网络就是这个样子,可以将很多的激活单元重合组成一个神经网络。那么就可以将求z的一步作为神经网络的第一层,求a的一步当作是神经网络的第二
1、神经网络概览

本周将会学习如何构建一个单层次的神经网络。上周学习了logistic回归,下面将它和上面的神经网络模型连接起来。

在logistic回归当中,首先会输入特征向量x和参数w、b,然后计算z=wTx+b,然后计算预测值y^=a=sigmoid(z),最后计算损失值L。神经网络就是这个样子,可以将很多的激活单元重合组成一个神经网络。

那么就可以将求z的一步作为神经网络的第一层,求a的一步当作是神经网络的第二层。这里需要做一个新的符号约定,也就是[i]。在神经网络的第一层中有x,w[1],b[1],z[1]、a[1],表示的是神经网络第一层级相关的变量。那么在神经网络的第二层中有a[2],表示神经网络第二层级的相关变量。这里使用[i]的目的是为了区分(i),(i)代表的是单个样本训练集,而[i]代表神经网络的对应的层级。

和logistic回归类似,选择另一个线性函数计算出z[2],进而求出a[2],a[2]是整个神经网络的输出,在神经网络当中就是这样需要不断的计算a、z,最后计算出损失值L。与logistic的反向传播一样,求da、dw、dz,神经网络中也有反向传播,例如求dw[2]、db[2]、da[1]等等。
2、神经网络表示
之前我们已经看过许多有关神经网络的图形,那么这节将会探讨这些图形具体表示着什么,换句话说就是我们所画的神经网络到底表示着什么,这里会以单个隐藏层的神经网络为例。

上图是一个单隐藏层的神经网络,首先是竖排的输入特征x1、x2、x3,这里叫做输入层,然后中间的节点叫做隐藏层,最后只有一个节点的叫做输出层。在对一个神经网络使用监督学习训练时,在训练集中我们可以看到输入特征x,以及输出目标y,但是隐藏层的那些节点的值是看不到的。那么隐藏层的含义就是,在训练集中对于这些中间节点的值是不知道的,训练集中可以看到输入输出值,但是看不到中间节点的值。

在神经网络中,输入特征不在用x表示,而是用a[0]表示,这里的a有着激活的意思,激活表示不同层级的值回传给后面的层级,输入层将值传给隐藏层,那么输入层的激活值就用a[0]来表示(这也验证了神经网络是由大量的激活单元堆积形成的)。隐藏层也有着自己的激活值,记为a[1],其中每个节点表示为a[1]_1~a[1]_4,其中每个a[1]_i都为4维的列向量,因为隐藏层的节点数为4。最后输出层记为a[2]是一个实数,用来代表y^,它与logistic回归类似,只不过logistic回归不涉及[i],因为logistic回归不涉及到层级,只有一个输出层,而神经网络涉及到层级需要[]。最后我们将这样的神经网络叫做双层神经网络,没有将输入层计入其中,因为输入层是第0层,概念上应该是三层神经网络,但是很多论文里面都称之为双层神经网络。注意隐藏层和输出层都是带参数的。隐藏层里面的参数w[1]和b[1]的维度分别是4x3和4x1,4代表着隐藏层的节点数,3代表输入的特征变量数。输出层里面也有w[2]和b[2],其中w是1x4的,b是1x1的,其中1代表输出层的节点数,4代表输入特征的个数。
值得注意的是所谓的双层神经网络,就是只有一个隐藏层的神经网咯。
3、计算神经网络输出(针对单样本)
单个隐藏层的神经网络已经熟知了。本节是探讨神经网络的输出到底是怎样计算的,简单描述就是将类似于logistic回归那样的计算重复很多次。

上图左侧是logistic回归,其中的大圆圈代表着两步计算,分别是z和a。那么神经网络就是反复的进行logistic回归这种计算。首先看到单隐藏层的神经网络的第一个隐藏单元,有点类似于logistic回归,也是将这样一个小圆圈划分为两部分,求z1[1]=w1[1]Tx+b1[1],a1[1]=sigmoid(z1[1]),其中的下标代表着隐藏单元的顺序,上标代表着层级顺序。类似第二个隐藏单元也是划分为两部分,求z2[1]=w2[1]Tx+b2[1],a2[1]=sigmoid(z2[1])。第二张图是分别四个隐藏单元对应的计算。

如果用for循环来进行上述等式的计算那就太慢了,因此要将上图的8个等式向量化。首先向量化z的计算。将z1[1]~z4[1]竖直排列形成一个1x4的列向量,记为Z[1]。然后将w1[1]T~w4[1]T也竖直排列形成一个4x3的矩阵(w1[1]本来是4x3的,那么w1[1]T就是3x4的。然后将其记为一个1x3的行向量),记为W[1]。然后将x1、x2、x3也竖直排列形成一个1x3的列向量,记为X。然后将b1[1]~b4[1][1]T也竖直排列形成一个4x1的列向量,记为b[1]。最后使得W[1]与X相乘再加上b[1],这就等于Z[1],也就是四个等式的向量化表示。在这个向量化过程当中也可以学的一些规律,在做向量化时就把一个层级的节点的参数都竖直排列形成矩阵或者向量,最后进行相应的运算即可。那么a1[1]~a4[1]也可以竖直排列形成一个4x1的列向量,记为a[1]等于sigmoid(Z[1])。也就是说没有下表的就不代表这某个具体的节点了,而是这个层级相关变量的矩阵或者向量。

在计算过程中我们刚刚讲了x有另一种表示形式,也就是a[0],也就是说在最终的向量化表示当中可以将X=(x1、x2、x3)T矩阵用a[0]代替。也就是Z[1]=W[1]a[0]+b[1],Z[2]=W[1]a[1]+b[2],a[2]=sigmoid(Z[2])。注意隐藏层的最终输出是a[1],所以他作为输出层的输入,代替了x的位置。注意各个向量和矩阵的维度,再上图都有表示。输出层中的参数Z[2]和a[2]就相当于logistic回归当中的Z、a,只不过没有了上标。
总结来说,一个单隐藏层的神经网络中的隐藏层相当于4个logistic回归运算,输出层相当于一个logistic回归运算。并且在之前我们已经学过如果将logistic回归运算的代码向量化。
4、计算神经网络输出(针对多样本)
上述计算神经网络的输出,只是针对了一个输入样本。本节要介绍的是训练集的全部样本同时输入,并且经过神经网络之后同时获得输出结果。

针对于一个样本时,神经网络的隐藏层计算和输出层计算,可以看作是

这四个式子,前两个式子代表着隐藏层四个节点的计算,每个节点都是一个logistic回归单元,后两个式子代表着输出层一个节点的运算,相当于一个logistic回归单元。那么在一个训练集中有多个样本:x(1)~x(m),对于每个样本x(i)都需要求出其对应的输出y^(i),也就是计算在神经网络中的输出a[2](i),其中[2]代表着单隐藏层神经网络的输出层(双层神经网络对应的结果输出上标肯定是[2]),(i)代表着针对于哪个样本。那么a1[1](1)在单隐藏层的神经网络中是指隐藏层第一个节点针对于第一个样本的计算。上图中的代码是不用向量化计算多个样本神经网络输出的例子,用for循环遍历每个样本,并计算每个样本在隐藏层中两个式子的运算和在输出层中两个式子的运算。

将刚刚的for循环进行向量化。首先针对于输入变量进行向量化,使m个样本的输入变量x(1)~x(m)横向排列组成nxm的矩阵X。然后是对四个式子进行向量化。首先使m个样本在隐藏层的线性运算Z[1](1)~Z[1](m)(其中的Z[1](i)又是隐藏层每个节点zj[1](i)组成的)横向排列组成4xm的矩阵Z[1]。然后使m个样本在隐藏层的激活变量A[1](1)~A[1](m)(其中的A[1](i)又是隐藏层每个节点aj[1](i)组成的)横向排列组成4xm的矩阵A[1]。然后是使m个样本在输出层的线性运算Z[2](1)~Z[2](m)(其中的Z[2](i)就是一个实数)横向排列组成1xm的矩阵Z[2]。最后使m个样本在输出层的激活变量A[2](1)~A[2](m)(其中的A[2](i)又是一个实数)横向排列组成1xm的矩阵A[2]。其中Z[1]、Z[2]、A[1]、A[2]这些矩阵,横向扫描是针对于不用的样本,竖向扫描是针对于不同的输入变量或者是隐藏层不同的节点,比如Z[1]横向扫描是隐藏层中固定的某个节点对于所有样本的线性运算,竖向扫描是隐藏层中的每个节点对于固定样本的线性计算。
Z[1]是由Z[1](i)组成的,Z[1](i)由Zj[1](i)组成的。
5、向量化实现神经网络的前向传播
在前一章节的多样本向量化中我们知道了如何将一些量堆叠起来实现向量化,本章节将介绍神经网络前向传播的向量化过程。

根据上张图手动算算神经网络前向传播的内容。首先这里为了简便计算给定只有三个样本,Z[1](1)=W[1]X(1)+b[1],Z[1](2)=W[1]X(2)+b[1],Z[1](3)=W[1]X(3)+b[1](之前写的是W[1](i),但是针对于每个样本隐藏层的参数W都是一样的,所以就都记为W[1]),为了在简便推导,去掉b[1]。然后是W[1](4x3的矩阵)分别去乘X(1)、X(2)、X(3)就等于Z[1](1)、Z[1](2)、Z[1](3)(相乘的结果是4x1的列向量)。使得X=(X(1),X(2),X(3))T,Z[1]=(Z[1](1),Z[1](2),Z[1](3))T,那么Z[1]=W[1]X。最后让Z[1]=W[1]X直接加上b[1]即可,因为b[1]是4x1的列向量,与Z[1]的行数相同,可以直接利用python'广播进行处理。这是前向传播的第一个运算,后面的三个公式的向量化表示可以依次类推。
原来的Z[1](2)=W[1]X(2)+b[1]是针对于单个样本的计算,Z[1]=W[1]X+b[1]是针对于整个训练集的计算。

回顾一下本节视频。首先上图左上角是我们的双层神经网络。右上角是该神经网络针对于全部样本的前向传播且为向量化的过程。然后对这个for循环进行了向量化,使得输入变量X=(X(1),……,X(m)),X的维度为nxm;使得A[1]=(A[1](1)……A[1](m)),其中的A[1](1)又由(A1[1](1)……A4[1](m))组成,其余的Z[1]、Z[2]、A[2]也是这样堆叠的表示方法。然后用Z[1]=W[1]X+b[1]、A[1]=sigmoid(Z[1])、Z[2]=W[2]A[1]+b[2]、A[2]=sigmoid(Z[2])表示整个训练集上神经网络前向传播的向量化过程。注意X可以用A[0]表示,则Z[1]=W[1]A[0]+b[1]。
6、激活函数
上一章节展示了不同样本向量化的神经网络,但是到目前为止我们使用的激活函数都是sigmoid函数,但是它并不是最好的选择,本章节将展示更多的激活函数,sigmoid只是其中一种。

在构建一个神经网络的时候,我们可以自主选择隐藏层和输出层的激活函数。在这之前我们一直使用的是sigmoid函数,但事实上还有其他的激活函数效果比sigmoid函数好得多。在单隐藏层神经网络中,我们只有再求a[1]和a[2]的时候才需要激活函数,现在将sigmoid函数记为g函数,g函数可以是非线性的函数。sigmoid函数的图如右上角,区间为0-1,表达式为1/(i+e-z),其中有一个函数tanh(双曲面正切函数)它的效果总是比sigmoid好,它的图像如图,区间是-1~1,表达式为(ez-e-z)/(ez+e-z),该激活函数效果好一点的原因就是其输出位于-1~1,使得激活函数的输出平均值更接近于0。事实上tanh是由sigmoid平移伸缩后变来的,变形之后经过了(0,0)点,区间变为-1~1。结果表明隐藏层上使用tanh函数效果比sigmoid函数好,因为其激活函数的输出均值更接近于0,而不是0.5。在训练一个算法模型时,如果用tanh代替sigmoid中心化数据,会使数据均值更接近于0,而不是0.5,这使得下一层更好处理。
值得注意的是在隐藏层中我们几乎不在使用sigmoid函数,因为tanh函数在任何场景都比sigmoid函数优越一点。但是有一个例外,就是在输出层的时候,如果输出是一个二分类问题,也就是说输出不是0就是1时,我们更希望输出的值位于0-1,而不是-1~1,因此在输出是二分类问题的时候我们更希望用sigmoid函数。因此这个单隐藏神经网络在隐藏层和输出层用了不同的激活函数,由为了进行区分,我们使用上标g[1]、g[2]来表示不同层级的激活函数。
但是sigmoid和tanh都有一个缺点就是当z很大或则很小的时候函数的斜率会为0,这会拖慢梯度下降算法的速度。机器学习当中有一个经常使用激活函数,Relu(线性修正单元),它的图如上图所示,其表达为a=max(0,z),只要z为正其函数的斜率就为1,z为负函数的斜率就为0,当z=0是,函数的斜率是没有定义的,但是在实际编程中,z=0.000000的概率是很小的,还有就是可以指定z=0时,函数的斜率为多少,尽管Relu是不可微的函数。
选择激活函数的经验法则有当你的输出层是0或者1,也就是一个二分类问题的时候,使用sigmoid函数作为输出层的函数,另外的层级使用Relu函数作为激活函数,这一般是默认的,但是还是会有少数人选择tanh函数。Relu函数有一个缺点就是z为负的时候,其梯度值为0,但是在实际问题中不用担心,因为在很多的神经单元里面都可以令z>0,另外Relu还有一个版本叫做泄露的Relu,它在z为负的之后有一个较为平缓的斜率,它的效果好一点,但是它的使用率并不高。Relu和泄露的Relu的优点就是在很大的z空间中,都使得函数的斜率离0很远。在训练你的神经网络的时候选择Relu函数,真的会快很多,比tanh和sigmoid函数都快,就是因为它的函数的斜率不会为0,你会说z为负的时候,函数的斜率为0,但是在很多的神经单元中我们都可以令z>0.

上述是刚刚介绍的一个激活函数,来总结一下他们的优缺点。首先是sigmoid函数,出了输出层是二分类问题的情况下,其他情况坚决不要使用,因为tanh在任何场合都比sigmoid更加的优越,还有就是为了减少z过大过小造成函数斜率为0的情况,引入了现在默认的激活函数Relu,但是你想试试的化也可以使用一下泄露的Relu,其表达式是a=max(0.001z,z),0.001是自己设定的,可以自己调节。
7、为什么会需要非线性的激活函数
在上一节当中我们对于构建神经网络时选择怎样的激活函数有了一个概念。但是深度学习有一个特点,就是在构建神经网络的时候,我们经常都要面临一些选择,如隐藏层神经元的个数、激活函数,如何初始化权重等等。没有准则规定选择怎样的参数才最适合你的问题,所以吴恩达老师介绍了一些比较冷门和热门的选择,来帮助我们做出选择,另外我们自己也可以在自己训练集上尝试不同的选择看哪个效果更好。本节将谈及为什么要使用非线性激活函数,如果你想要你的神经网络计算更多更有趣的神经网络就必须使用非线性激活函数。

首先回顾一下神经网络的前向传播过程为Z[1]=W[1]a[0]+b[1]、a[1]=g[1](Z[1])、Z[2]=W[2]a[1]+b[2]、a[2]=g[2](Z[2])。现在我们去掉g,或者是令g(z)=z,这样的函数叫做线性函数,或者恒等激活函数,因为他们直接将输入进行了输出。如果将a[1]=Z[1],a[2]=Z[2],那么最后的输出结果y^只不过是输入特征x的线性组合。现在a[1]=Z[1]=W[1]a[0]+b[1]、a[2]=Z[2]=W[2]a[1]+b[2]=W[2](W[1]a[0]+b[1])+b[2]=(W[2]W[1])a[0]+(W[2]b[1]+b[2]),其中a[0]为x,令a[2]=W’X+b’,则最终的输出a[2]就是输入特征x的线性组合。如果你在你的深度学习神经网络中使用激活函数,无非就是将输入特征进行线性组合后进行输出。所以不管你的深度学习的神经网络有多少的隐藏层,只要你采用的是线性函数,那么这个神经网络只会进行线性函数的计算,和去掉隐藏层是一样的,就比如你的神经网络隐藏层都采用线性函数,输出层采用sigmoid函数,那么其复杂度是和没有任何隐藏层的logistic回归一样的。
这里就是想要证明线性隐层是没有用的,因为线性函数的组合仍然是线性函数。如果你想要计算一个有趣的函数就要使用非线性的激活函数,否则做再多的隐藏层都没有用。
另外,只有一种情况会使用线性函数,也就是你的输出层是一个回归问题的时候,例如房屋预测价格的问题,训练集里面的真实预测值都是实数(不是0、1),那么最后的预测值y^也应该是一个实数,这时候输出层使用线性函数也可以,但是隐藏层不要用线性函数,最好的Relu、tanh、泄露Relu的这些激活函数。所以使用线性函数(输出层是个回归问题)和sigmoid激活函数(输出层是个二分类问题)的地方只有输出层。
8、激活函数的导数
本节将探讨神经网络的梯度下降算法的基础——激活函数的导数。在前面我们是学习了神经网络前向传播的向量化过程,以及激活函数的选择过程,现在要进入到神经网络的反向传播过程,反向传播过程就必须计算激活函数的导数。接下来将介绍各种激活函数如何计算其导数。

首先看到对于sigmoid激活函数的导数。指定一个z,它在sigmoid函数图像上对应着一点,这一点的导数也就是斜率就等于上图绿色三角形的高比宽,这个斜率也就是sigmoid激活函数g(x)在z点的导数,记为dg(z)/dz=[1/(1+e-z)]’=e-z/(1+e-z)2=1/(1+e-z)[1+1/(1+e-z)]=g(z)(1+g(z))。当z=10的时候,g(z)≈1,那么dg(z)/dz=0,当z=-10,g(z)≈0,那么dg(z)/dz=0,则说明了当z很大或者很小的时候,sigmoid激活函数的导数(斜率)都为0。当z=0,g(z)=1/2,则dg(z)/dz=1/4。这说明这个导数是正确的,这里又有了新的符号约定,记dg(z)/dz为g’(z),记g(z)为a,故g’(z)=a(a+1)。

其次再看看在任何情况下都优于sigmoid函数的tanh函数。记g(z)=tanh(z)=(ez-e-z)/(ez+e-z),那么g(z)的导数记为dg(z)/dz=[(ez-e-z)/(ez+e-z)]’=1-[(ez-e-z)/(ez+e-z)]2=1-g(z)2。当z=10的时候,g(z)=1,dg(z)/dz=0,当z=-10的时候,g(z)=-1,dg(z)/dz=0,说明tanh和sigmoid一样,z很大或者很小的时候,其导数都为0。当z=0时,g(z)=0,dg(z)/dz=1。新的符号约定,记dg(z)/dz为g’(z),记g(z)为a,故g’(z)=1-a2。

接下来看到Relu函数和带泄露的Relu函数。首先将g(z)=Relu(z)=max(0,z),那么当z>0时,g’(z)=1;当z<0时,g’(z)=0;当z=0时,g’(z)是没有定义的。但是在实际情况中可以编写一段代码,当z=0时,g’(z)=0或者g’(z)=1,这都没有关系,因为实际情况中z=0.0000000000……的概率很小。其次将g(z)=泄露Relu(z)=max(0.01z,z),那么当z>0时,g’(z)=1;当z<0时,g’(z)=0.01;当z=0时,g’(z)是没有定义的。但是在实际情况中可以编写一段代码,当z=0时,g’(z)=0.01或者g’(z)=1,这都没有关系,因为实际情况中z=0.0000000000……的概率很小。
9、神经网络的梯度下降算法
本节将会探讨一个单隐藏层的神经网络反向传播的梯度下降算法的具体实现过程,并且提供梯度下降算法所需要的几个准确的方程。

首先看到单隐藏层的神经网络的参数有W[1]、W[2]、b[1]、b[2]。这里指定新的符号表示n[0]表示输入层的输入特征数量,n[1]表示隐藏层的隐藏单元数量,n[2]表示输出层的输出单元数量,现在我们只看到过n[2]=1的神经网络,也就是只看到过输出层的输出单元数量为1的神经网络,那么W[1]维度就可以定义为(n[1],n[0])、W[2]维度就可以定义为(n[2],n[1])、b[1]维度就可以定义为(n[1],1)、b[2]维度就可以定义为(n[2],1)。然后假如我们的问题是一个二分类问题,那么就会有一个成本函数J(W[1],W[2],b[1],b[2])=1/m∑L(y^(i),y(i)),其中的y^(i)就是a[2](i),且损失函数和二分类问题完全一样。要想训练参数,就必须要使用梯度下降算法,训练神经网络非常重要的一步就是初始化参数,不一定都要初始化为0。那么在初始化了参数之后,每一个梯度下降循环都将计算i=1~i=m的预测值y^(i),然后梯度下降算法会计算导数dW[1]=dJ/dW[1]、dW[2]=dJ/dW[2]、db[1]=dJ/db[1]、db[2][1]=dJ/db[2],然后进行参数更新W[1]=W[1]-αdW[1],b[1]=b[1]-αdb[1]……。这只是梯度下降算法的一次迭代,还需要重复这个步骤很多次,知道参数收敛。在这个步骤当中最重要的就是求导数,下面吴恩达老师给定了一些公式帮助我们求解导数。

如上图左侧是神经网络前向传播的过程,假设这是一个二分类问题,则A[2]=sigmoid(Z[2])。右侧是单隐藏层神经网络的反向传播过程。dZ[2]=A[2]-Y(这里的Z、A、Y都是针对于整个样本的,Y=(y(1)……y(m)))。dW[2]=I/mdZ[2]A[1]T。db[2]=1/m np.sum(dZ[2],axis=1,keepdims=Ture),其中axis=1,代表横向求和,keepdisms=Ture开关是为了防止python输出秩为1的矩阵,从而保证输出的db[2]的维度是(n[2],1),但是n[2]的话,db[2]就是一个实数,而不是一个矩阵,所以keepdims=Ture在这里没有多大的意义。dZ[1]=W[2]TdZ[2]*g[1]‘(Z[1]),其中g[1]‘(Z[1])是对于每个元素求导,结果为(n[1],m)的矩阵,W[2]TdZ[2]也是(n[1],m)的矩阵,其中的*是按元素相乘(np.dot是矩阵乘法)。dW[1]=I/mdZ[1]A[0]T=I/mdZ[1]XT。db[1]=1/m np.sum(dZ[2],axis=1,keepdims=Ture),这里db[1]的维度为(n[1],1),不在是一个实数,所以不想最后的输出结果是秩为1的奇怪矩阵(n[1],),那么就必须加kppedims=Ture或者是使用reshape重塑结构,输出想要形状的db[1]。
10、随机初始化
在训练神经网络时初始化参数非常重要(随机初始化)。logistc回归中通常初始化为0,但是神经网络不能将所有的数组都初始化为0,这样梯度下降算法将会无效。

为什么在神经网络中不能把参数初始化为0?首先看到上图的一个单隐藏层的神经网络,其中n[0]=2,表示输入特征有两个,n[1]=2,表示隐藏单元有两个,n[2]=1,表示输出单元有一个,故W[1]的维度为(2,2),b[1]的维度为(2,1)。现在初始化参数W[1]的四个元素都为0,b[1]的两个元素都为0,其实将b[1]初始化0没有问题,但是将W[1]初始化为0就有问题了。问题在于W[1]初始化为0,那么对于每个输入特征的计算Z1[1]=W[1]x1+b[1]=Z2[1]=W[1]x2+b[1],a1[1]=a2[1],那么每次隐藏层的两个单元都在做着一样的计算,每个隐藏单元的初始化也是一样的。进行反向传播的时候,也是dZ1[1]=dZ2[1]。假设输出层的维度为(1,2)权重参数W[2]也初始化为0,那么这个神经网络的两个隐藏单元是完全一样的,也就是完全做着同样的计算。事实证明每次梯度下降迭代,两个隐藏单元都做着同样的计算,就如上图dw的每一行都是一样的,进行更新迭代W[1]=W[1]-αdW[1]之后,W[1]仍然是两行完全一样的矩阵,所以如果你选择在神经网络中初始化参数为0,不管你训练多长时间,有多少隐藏层和神经元,都没有意义。如果你选择一个更大一点的神经网络,比如如上图的3个特征输入和多个隐藏单元,但是你还是初始化参数为0的话,每个隐藏层单元仍做着一样的计算,根本没有一点用处,我们需要不同的神经元做不同的计算进而更新参数,这一问题的解决办法就是随机初始化。

这里会讲述什么叫做随机初始化。首先还是和上一张图一样的单隐藏层神经网络,将W[1]=np.random.randn((2,2))*0.01,其中使用np.random.randn((2,2))可以将W[1]初始化为(2,2)的高斯分布随机变量,还可以乘上一个比较小的数,如0.01,就可以将W[1]初始化为比较小的随机变量。然后是b[1]=np.zeros((2,1)),可以将b[1]初始化为0,因为只要W[1]随机初始化了,隐藏层单元就会做不一样的计算了。相同W[1]=np.random.randn((1,2))*0.01,b[1]=np.zeros((1,1))。
那么0.01这个常数怎么来的,为什么必须是一个比较小的数,而不能是100,1000?因为对于权重矩阵,我们通常喜欢将它初始化为较小的随机变量,因为Z[1]=W[1]X+b[1],A[1]=g[1](Z[1]),如果激活函数选用的是sigmoid函数或者是tanh函数,那么W[1]很大则Z[1]会很大,Z很大时sigmoid函数或者是tanh函数的斜率就会趋近于0,那么就会导致梯度下降算法速度减慢。所以说如果一开始就采用100这样的数字就会导致sigmoid函数或者是tanh函数饱和,进而导致学习速度减慢,但是如果你的神经网络没有sigmoid函数或者是tanh函数,那么设置数字较大是没有太大问题的,但总体来说0.01函数比较合理的。
但是肯定有比0.01还好的数字,但是对于但隐藏层的神经网络来说够用了,如果是大一点的神经网络可能就要尝试一下别的数字了,但是总之这个常数都是比较小的。
更多推荐
所有评论(0)