吴恩达神经网络与深度学习 Week-3 学习记录

文章目录
  1. 1. 什么是神经网络
  2. 2. 神经网络表示
  3. 3. 计算神经网络的输出
  4. 4. 多个例子中的向量化
  5. 5. 向量化实现的解释
  6. 6. 激活函数
  7. 7. 为什么需要非线性激活函数
  8. 8. 激活函数的导数
  9. 9. 神经网络的梯度下降
  10. 10. 随机初始化

开始浅层神经网络的学习。

什么是神经网络

可以把很多sigmoid函数堆叠起来构成一个神经网络。在下图所示神经网络中的这堆节点计算对应着Logistic Regression中的计算过程。

在下面的描述中会使用到以下这些符号:
x:表示输入特征。
参数W和b的上标(比如 W[1])表示神经网络中节点相关的量,比如层数,[2]则表示是神经网络的另一层。
同时,(1),也就是圆括号,是用来表示训练样本的,x(1)表示第一个训练样本。

在逻辑回归中只用计算一次sigmoid,但是在神经网络中需要做多次计算,反复计算z和a,最后计算损失函数(Loss Function)。
同时,在逻辑回归中有反向传播来计算导数da,dz等,在神经网络中同样也有这样的反向计算,如下图所示:

神经网络表示

下图所示的神经网络由输入层,隐藏层和输出层构成,输入层是输入的训练集,y_hat是根据训练集输出的结果。

我们可以看到x和y_hat的值,但是看不到中间隐藏层神经元上的值。
之前使用向量x表示输入特征,输入特征的数值还有另外一种表示方式a\^[0]=x([0]是上标),同时,这个a也表示“激活”的意思,它意味着网络中不同层的值会传递给后面的层。

同理,隐藏层也会产生一些“激活”,因此,将其记作 a\^[1],其中的四个神经元就分别对应着a\^[1]_1,a\^[1]_2等,其中,a\^[1]是一个四维向量。最终,输出层会产生某个数值a\^[2],是个实数,所以 y_hat=a\^[2]。

这和逻辑回归类似,但是在逻辑回归中则不需要上标来明确指出这些之来自哪一层。

最后,我们需要知道,隐藏层,以及最后的输入层是带有参数的。这里的隐藏层有两个相关的参数W和b,使用上标[1]来表示这些参数是和第一层这个隐藏层有关的。W是一个4x3的矩阵,b是一个4x1的向量。

最后输出层的W和b上标为2,W\^[2]的大小是1x4,b\^[2]的大小是1x1。

计算神经网络的输出

本节以单个训练样本计算神经网络的预测为例。
当前神经元中包含两个计算步骤:
1.计算出z的值;
2.计算sigmoid函数。

从单个神经元到神经网络,只是将单个神经元中的计算重复多次。
以上图左部的神经网络为例,首先计算最上面的神经元:

其中,上述的标号[1]都和第一隐层有关的向量,因为这是隐层的第一个节点,所有才有一个下标1。

现在来看第二层的计算:

完整的计算图以及向量化图示如下:

一层中的四个节点[z^[1]_1,z^[1]_2,z^[1]_3,z^[1]_4]堆叠起来用z^[1]来表示,W^\1]还有b^[1]也是类似的。最后a^[1]=sigmoid(z^[1])也就是表示将sigmoid计算作用到每个z上。

矩阵运算与推导细节如下,很容易能看懂,不再赘述计算过程。

总结:对于逻辑回归,为了计算输出或者说预测,需要计算z=w.Tx+b和y_hat=a=sigmoid(z),当你有一个神经网络,你需要在代码中实现的是上图右边的等式部分,可以把这看作是一个向量化的计算过程。

多个例子中的向量化

本节主要介绍如何将不同训练样本向量化,如何将不同的训练样本堆叠起来放入矩阵的各列。
首先回顾一下上节的内容,计算式子如下:

将一个样本转换为m个样本之后最后的输出过程变化如下:

圆括号里的值表示训练样本,比如a^2表示第i个训练样本。
通过代码实现时,使用循环从1-m实现上述四个方程的计算:

但是,正如之前提到的一样,通过循环计算耗时量巨大,所有仍然需要将上述过程向量化。
简单来说,首先把m个x的样本堆叠为一个计算矩阵,后续的计算步骤则和之前类似,如下图所示:

其中,竖排紫色的点表示隐藏单元对第i个训练样本的激活函数,横向矩阵A则会扫过不同的训练样本来进行计算(横向表示输入的样本,竖向对应不同的输入特征)。

向量化实现的解释

具体的向量化实现解释可以看下面这张图:

为了方便计算,认为b=0,消去b。

激活函数


假如需要搭建一个神经网络,可以选择的是,选择隐层里用那一个激活函数,还有神经网络的输出单元用什么激活函数。

在之前的课程里,a的值总是通过sigmoid(z)来得到,然而,tanh函数(双曲正切函数):

从实际上来说,tanh函数实际上是sigmoid的平移版。
在运算中,将sigmoid换成tanh,效果要更好,因为tanh输出介于-1到1之间,激活函数的平均值就更接近0。
其中,sigmoid函数和tanh函数都由一个缺点,就是如果z非常大或非常小,那么导数的梯度,或者说这个函数的斜率可能就很小。所以,当z很大或很小的时候,函数的斜率很接近0,这样会拖慢梯度下降算法。

由于这些原因,机器学习中有一个工具,修正线性单元(ReLU):

只要z为正,导数就是1,当z为负时,斜率为0。如果实际使用这个函数,z刚好为0时,导数是没有定义的。

选择激活函数的经验法则:
如果输出值是0和1(即二元分类),那么sigmoid函数很适合作为输出层的激活函数,然后其他所有单元都用ReLU,所谓的线性修正函数现在已经变成激活函数的默认选择了。
如果不确定隐藏层使用什么激活函数,就用ReLU。
正如上文中提到的,ReLU有一个缺点,z为负时导数值为0,但是ReLU还有另外一个版本,叫做带泄露的ReLU,当z为负时,函数不再为0。

为什么需要非线性激活函数

如果使用线性激活函数,神经网络只是把输入线性组合再输出。

假如只使用线性函数或没有激活函数,无论神经网络由多少层,神经网络在做的只是计算线性激活函数,如果以这样的方法,不如直接去掉隐藏层。
因此,如果在隐藏层中使用线性激活函数,输出层使用sigmoid,那么这个神经网络和没有任何隐藏层的标准逻辑回归时一样的。

激活函数的导数

当对神经网络使用反向传播的时候,需要计算激活函数的斜率或者导数。
这节的内容很简单,sigmoid已经推导过很多次了,tanh的求导也很容易。
sigmoid函数求导

tanh函数求导

ReLU函数求导

神经网络的梯度下降

在浅层神经网络(这里指仅包含一个输入层,一个隐藏层还有一个输出层的神经网络)中包含的参数有:W[1],b[1],W[2],b[2]。

给出另外一组参数值的定义:
nx=n[0],n[1],n[2]
n[0]:表示有多少输入特征;
n[1]:表示隐藏单元数目;
n[2]:表示输出单元数目。

在之前的栗子中只介绍过n[2]等于1的情况,矩阵W[1]的维度就是(n[1],n[0]),b[1]的维度是(n[1],1),就是一个列向量,W[2]的维度就是(n[2],n[1])。

神经网络中前向传播和反向传播的推导过程

随机初始化

在逻辑回归中可以将权重初始化为0,但是如果将神经网络的各参数数组全部初始化为0,再使用梯度下降算法,那会完全无效。

如果全部初始化为0,那么隐藏层和输出层中的权重将完全一样。
解决办法:使用随机初始化。


注:这里有一个问题,为什么要使用0.01,为什么不用100或者1000之类的数字?

实际上,习惯将矩阵初始化为非常非常小的随机值,因为,如果使用的是tanh或者sigmoid激活函数,或者在输出层有一个sigmoid函数,如果权重太大,当计算激活函数值时,要记住z[1]=W[1]x+b,然后a[1]是应用于z[1]的激活函数,如果W过大,那么z也就会很大。或者这些z值会很大或者很小,所以在这种情况下,结果最后可能落在tanh或sigmoid函数的平缓部分,梯度的斜率非常小,意味着梯度下降法会非常慢,学习就会很慢。

注:当计算只有一层的神经网络时,0.01会是个不错的选择,但是如果神经网络过大,则需要试试0.01以外的常数。