4、全连接神经网络




1 对全连接神经网络结构的理解

1.1 单个节点如何工作

在这里插入图片描述
这里以包含一个隐藏层和一个输出层的两层全连接神经网络为例(严格的说输入层并不能算为一层),上图左是它的结构图。将网络中的某个节点放大,得到了上图右。与逻辑回归采用 sigmoid 函数作为激活函数不同的是,适用于神经网络的激活函数有很多,包括但不限于 sigmoid 函数,下面会详解讲解。除了激活函数的差别外,神经网络中单个节点和逻辑回归却具有相同的结构,都是先执行一个线性运算,然后再通过激活函数做一个非线性的运算。

神经网络往往包含很多层,一层中又包含多个节点,这里用上标[i]表示网络中的第 i 层,用下标j表示第 j 个节点。数据集包含多个样本,这里用上标(k)表示第 k 个样本。图中的 z z z 表示网络节点在执行线性运算后的结果, a a a 表示网络节点在执行激活函数(activation function)后的输出。输入层并不执行任何计算,所以它并不能算为一个层,只不过我们习惯上这样叫它。输入层也可以看作第 0 层,则输入的向量 x x x 也可以看作是第 0 层的输出,即 a [ 0 ] = x a^{[0]}=x a[0]=x。对于输入的某个样本的特征向量 x x x ,神经网络的每个节点是如何工作的呢?这里以第 1 层为例,给出了第一层节点的计算过程,如下图右。
在这里插入图片描述

1.2 整个网络如何工作

通过上图我们已经知道了单个节点是如何工作的。那么对于某个样本的特征向量 x x x ,整个神经网络的节点是如何合作并最终输出 y ^ \hat{y} y^ 的呢?由图中的箭头可以知道,神经网络从输入层开始,上一层的输出作为下一层的输入,直到输出最终的结果。我们把第 i 层的所有节点的参数向量 w 转置后按顺序放进矩阵 W [ i ] W^{[i]} W[i] 中,再把第 i 层的所有节点的参数 b 按顺序组合成一个列向量 b b b,那么对于上图第 1 层的运算过程,我们用 z [ 1 ] = W [ 1 ] x + b z^{[1]} = W^{[1]}x+b z[1]=W[1]x+b a [ 1 ] = s i g m o i d ( z [ 1 ] ) a^{[1]}=sigmoid(z^{[1]}) a[1]=sigmoid(z[1]) 这两个式子便能完成上图中相同的工作。只不过我们这里把每一层所有节点的 w,b, a a a,z 分别放在了一起。通过这种向量化的方式,现在我们能更方便地计算每一层节点的输出了。对于输入的某个样本的特征向量 x x x,我们按照同样的方式计算整个神经网络的输出,如下图所示。
在这里插入图片描述
对于包含 m 个样本的样本集,其特征矩阵 X = { x ( 1 ) , x ( 2 ) ⋯ , x ( m ) } . X = \{x(1),x(2) ⋯ , x(m)\} . X={x(1),x(2),x(m)}. 上面是以单个样本 x x x 为单位进行运算,如果要以这种方式完成对整个样本集的预测的话,必须通过大量的 for 循环,下图左给出了通过循环对所有样本进行预测的做法。但是对于庞大的数据集和稍微复杂的网络结构来说,用 for 循环这无疑会花费大量的计算时间。为了使我们的网络模型更加高效,一般使用向量化的计算方式代替 for 循环,下图右展示了通过向量化计算对所有样本进行预测的做法。
在这里插入图片描述

2 激活函数

2.1 激活函数的对比与选择

神经网络往往包含多个层,不同层的激活函数可以不一样。下面是几种常见的激活函数。

1)sigmoid 函数

表达式: s i g m o i d ( z ) = 1 1 + e − z sigmoid(z) = \frac{1}{1 + e^{-z}} sigmoid(z)=1+ez1

函数图像:
在这里插入图片描述
sigmoid 函数的值域为 (0,1)。从图中可以看出,当因变量 z z z 取值为 0 时,sigmoid 曲线的斜率(梯度)最大,计算出来为 0.25。当因变量 z z z 的取值越大或越小时,sidmoid 曲线的斜率(梯度)就越小。当 z z z > 5 或 z z z < -5 时,sigmoid 曲线的斜率(梯度)几乎为零。如此一来,当我们在通过梯度下降算法来更新参数的时候,如果 z z z 的取值过大,那么参数更新的速度就会变得非常缓慢。

所以在神经网络中选择 sigmoid 函数作为激活函数并不是一个很好的选择,但有个例外就是二元分类的输出层。因为二元分类的标签 y y y 要么是 0,要么是 1,所以我们希望输出的 y ^ \hat{y} y^ 能表示当前样本属于某类别的概率,而概率又介于 0 和 1 之间,这恰好和 sigmoid 函数的值域相符。所以在做二元分类的时候,输出层的激活函数可以选择 sigmoid。

2)tanh 函数

表达式: t a n h ( z ) = e z − e − z e z + e − z tanh(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}} tanh(z)=ez+ezezez

函数图像:
在这里插入图片描述
如果选择 tanh 作为隐藏层的激活函数,效果几乎总是比 sigmoid 函数要好,因为 tanh 函数的输出介于 -1 与 1 之间,激活函数的平均值就更接近于 0,而不是 0.5,这让下一层的学习更加方便一点。

和 sigmoid 函数类似,当因变量 z z z 取值为 0 时,tanh 曲线的斜率(梯度)最大,计算出来为 1。当因变量 z z z 的取值越大或越小时,sigmoid 曲线的斜率(梯度)就越小。所以 tanh 也会面临和 sigmiod 函数同样的问题:当 z z z 很大或很小时,tanh 曲线的斜率(梯度)几乎为零,这对于执行梯度下降算法十分不利。

3)ReLU 函数

表达式: R e L U ( z ) = m a x ( 0 , z ) ReLU(z) = max(0,z) ReLU(z)=max(0,z)

函数图像:
在这里插入图片描述
目前在机器学习中最受欢迎的激活函数是 ReLU (Rectified Linear Unit),即修正线性单元。现在 ReLU 已经成为了隐层激活函数的默认选择。如果不确定隐层应该使用哪个激活函数,可以先尝试一下 ReLU。

z z z > 0 时,曲线斜率为 1;当 z z z < 0 时,曲线的斜率为 0;当 z z z = 0 时,曲线不可导,斜率就失去了意义,但在实际编程的时候可以令其为 1 或 0,尽管在数学上这样不正确,但不必担心,因为出现 z z z = 0 的概率非常非常小。ReLu函数的好处在于对于大部分的 z z z,激活函数的斜率(导数)和 0 差很远。所以在隐层中使用 ReLU 激活函数,神经网络的学习速度通常会快很多。ReLU 也有一个缺点,那就是当 z z z 为负数时,ReLU 曲线的斜率为 0,不过这在实践中不会有什么问题,因为有足够多的隐层节点使 z z z 大于 0。

4)Leaky-ReLU 函数

表达式: R e L U ( z ) = m a x ( k z , z )     , k 通 常 为 0.01 ReLU(z) = max(kz,z) \ \ \ ,k通常为0.01 ReLU(z)=max(kz,z)   ,k0.01

函数图像:
在这里插入图片描述
通过前面对 ReLU 的介绍我们知道了 ReLU 函数的缺点:当 z z z 为负数时,ReLU 曲线的导数为 0。而 Leaky-ReLU 则是另一个版本的 ReLU,当当 z z z 为负数时,Leaky-ReLU 曲线的导数不再为 0,而是有一个平缓的斜率。这通常比 ReLU 要好,不过实际中使用的频率却不怎么高。

5)线性激活函数与线性层

到现在为止,我们讨论的都是非线性的激活函数。那么什么时候我们可以使用线性激活函数或者线性的层呢?通常其用处不是很多,当想要处理一些关于压缩的特殊问题时,可以在隐藏层中使用,或者处理回归问题在输出层中使用。除此之外,基本上没有其他地方能用到线性激活函数或者线性的层了。

2.2 为什么要用非线性的激活函数

先来看一看正常情况下,使用非线性激活函数 g ( z ) g(z) g(z) 的神经网络完成正向传播的计算表达式:
在这里插入图片描述
现在,我们去掉激活函数 g [ 1 ] ( z [ 1 ] ) g^{[1]}(z^{[1]}) g[1](z[1]) g [ 2 ] ( z [ 2 ] ) g^{[2]}(z^{[2]}) g[2](z[2]),网络中的两个层就变成了线性层。正向传播的表达式就变成了

z [ 1 ] = W [ 1 ] x + b [ 1 ] z^{[1]}=W^{[1]}x+b^{[1]} z[1]=W[1]x+b[1] z [ 2 ] = W [ 2 ] z [ 1 ] + b [ 2 ] z^{[2]}=W^{[2]}z^{[1]}+b^{[2]} z[2]=W[2]z[1]+b[2]

再把两个式子合并为一个

z [ 2 ] = W [ 2 ] ( W [ 1 ] x + b [ 1 ] ) + b [ 2 ] = ( W [ 2 ] W [ 1 ] ) x + ( W [ 2 ] b [ 1 ] + b [ 2 ] ) z^{[2]} = W^{[2]}(W^{[1]}x+b^{[1]})+b^{[2]} = (W^{[2]}W^{[1]})x+(W^{[2]}b^{[1]}+b^{[2]}) z[2]=W[2](W[1]x+b[1])+b[2]=(W[2]W[1])x+(W[2]b[1]+b[2])

W ′ = W [ 2 ] W [ 1 ] W'=W^{[2]}W^{[1]} W=W[2]W[1] b ′ = W [ 2 ] b [ 1 ] + b [ 2 ] b'=W^{[2]}b^{[1]}+b^{[2]} b=W[2]b[1]+b[2]

z [ 2 ] = W ′ x + b ′ z^{[2]} = W'x+b' z[2]=Wx+b

通过上面的推倒可以看到,对于输入神经网络的线性组合 x x x,在去掉激活函数后,先经过第一个隐层的计算,然后神经网络在输出层最终输出的 z [ 2 ] z^{[2]} z[2] 还是一个线性组合。这样的话还不如把输出层的参数设置为 W ′ W' W b ′ b' b,然后直接去掉隐层。也就是说,无论有多少个线性隐层,最终的输出还是一个线性组合,还不如不要隐层,因为多个线性函数的组合还是一个线性函数。那么要是所有隐层都去掉非线性激活函数,而在输出层保留一个 sigmoid 函数呢?它的效果和没有任何隐层的逻辑回归是一样的。

3 网络参数初始化

3.1 随机初始化

在逻辑回归的问题中,把权重参数初始化为零是可行的。但把神经网络的权重参数全部初始化为零,并使用梯度下降算法将无法获得预期的效果。
在这里插入图片描述
以上面这个简单的神经网络为例。其与隐藏层关联的权重矩阵 W [ 1 ] W^{[1]} W[1] 是一个 2 x 2 的矩阵。现在将这个矩阵的初始值都设为 0,同样我们将偏置矩阵 b [ 1 ] b^{[1]} b[1] 的值也都初始化为 0。 b [ 1 ] b^{[1]} b[1] 的初始值全为 0 不会影响最终结果,但是将权重参数矩阵 W [ 1 ] W^{[1]} W[1] 初始值都设为 0 会引起下面的问题。

无论输入什么样的特征向量 x x x,当进行前向传播的计算时, a 1 [ 1 ] a_1^{[1]} a1[1] a 2 [ 1 ] a_2^{[1]} a2[1] 是相等的,所以他们隐层的两个节点对输出层唯一节点的影响也是相同的。当进行反向传播的计算时,也会导致代价函数对 W 1 [ 1 ] W_1^{[1]} W1[1] W 2 [ 1 ] W_2^{[1]} W2[1] 的偏导不会有差别。所以在更新参数后, W 1 [ 1 ] W_1^{[1]} W1[1] W 2 [ 1 ] W_2^{[1]} W2[1] 还是相等的。这又导致在进入下一次迭代后,依然是重蹈覆辙。

在上面这个例子中,隐藏层中上面的节点和下面的节点是相同的,它们实现的是完全相同的功能。在机器学习中,这种情形被称为是“对称”的。当把神经网络的权重参数全部初始化为 0 后,无论运行梯度下降多长时间,所有的隐藏神经元都将依然是“对称”的。这种情况下,再多的隐层节点也是无用的,因为它们依然提供的是完全相同的功能,这并不能给我们带来任何帮助。 所以我们希望两个不同的隐藏单元能实现不同的功能 ,而进行随机初始化能够解决这个问题。

3.2 初始值的大小

利用python编写神经网络时,通常使用 W[i] =np.random.randn((rows,cols))*0.01 这样的方式来对所有的权重矩阵 W 进行随机初始化并乘上一个非常小的数,比如 0.01。这样操作后,就将权重参数矩阵赋予了非常小的随机初始值。对于 b 来说,b并不会由于初始值为零而产生对称问题,所以使用 b[i]=np.zeros((rows,1)) 这样的方式来对所有的偏置矩阵 b 初始化为零。

现在权重参数矩阵 W 已经完成了随机初始化,不同的隐藏单元会承担不同的计算工作,我们也不会再遇到类似前面说的对称问题了。那么为什么会在初始化 W 的时候使用 0.01 这个常量? 为什么是 0.01 而不把它设置为 100 或 1000?当在网络中用到了 tanh 或sigmoid 激活函数时,如果 W 很大,那么 Z = W T x + b Z=W^Tx+b Z=WTx+b(的绝对值)也相应的会非常大,而此时 A = s i g m o i d ( Z ) A=sigmoid(Z) A=sigmoid(Z) A = t a n h ( Z ) A= tanh(Z) A=tanh(Z) 图像对应的部分的斜率就非常小,这意味着梯度下降会非常缓慢,所以整个学习过程也会变得尤为缓慢。而如果在神经网络中未使用任何sigmoid或者tanh激活函数,这种情况可能不明显。

有时候会有比 0.01 更为合适的数值,当训练一个仅含一个隐藏层的神经网络时,显而易见 0.01 这个数值在类似于这样不含过多隐藏层的浅层神经网络中是非常合适的。但当你要训练一个非常非常复杂的深度神经网络时,可以通过尝试使用不同的数值并观察梯度下降的结果来确定最适合的数值。

4 神经网络的梯度下降算法

4.1 梯度下降大概步骤

神经网络同样可以使用梯度下降算法来更新网络的参数 W 和 b。具体来说就是通过多次迭代,一步一步通过更新神经网络每一层节点的参数来减小神经网络输出的误差,最终误差达到最小时的参数就是我们要寻找的参数。大概步骤为:

在循环中完成:
    1、前向传播:从第一层到输出层,逐层计算网络输出;
    2、计算代价函数;
    3、反向传播:从输出层到第一层,逐层计算各层的梯度 ∂ J ∂ W \frac{\partial{J}}{\partial{W}} WJ ∂ J ∂ b \frac{\partial{J}}{\partial{b}} bJ
    4、更新参数: W = W − ∂ J ∂ W W=W-\frac{\partial{J}}{\partial{W}} W=WWJ , b = b − ∂ J ∂ b b=b-\frac{\partial{J}}{\partial{b}} b=bbJ .

4.2 前向传播与反向传播的计算

假设这里有一个 L L L 层的神经网络,不同的层激活函数可以不一样,我们用 g [ i ] ( Z [ i ] ) g^{[i]}(Z^{[i]}) g[i](Z[i])表示第 i 层的激活函数。则在前向传播中,前一层的输出作为后一层的输入,一层一层的计算直至输出 A [ L ] A^{[L]} A[L],如下图所示。
在这里插入图片描述
假设我们现在还是做一个二分类任务,则输出层的选择 sigmoid 激活函数,即 g [ L ] ( z [ L ] ) = s i g m i o d ( z [ L ] ) g^{[L]}(z^{[L]}) = sigmiod(z^{[L]}) g[L](z[L])=sigmiod(z[L])。然后代价函数我们定义为:

J = − 1 m ∑ i = 1 m ( y [ L ] ( i ) log ⁡ a [ L ] ( i ) + ( 1 − y [ L ] ( i ) ) log ⁡ ( 1 − a [ L ] ( i ) ) ) J = -\frac{1}{m}\sum_{i=1}^{m}(y^{[L](i)}\log{a^{[L](i)}}+(1-y^{[L](i)})\log{(1-a^{[L](i)})}) J=m1i=1m(y[L](i)loga[L](i)+(1y[L](i))log(1a[L](i)))

则在后向传播中,我们通过链式求导法则从后向前一层一层的计算代价函数对 W W W b b b 的偏导 ∂ J ∂ W \frac{\partial{J}}{\partial{W}} WJ ∂ J ∂ b \frac{\partial{J}}{\partial{b}} bJ。下图展示了反向传播的计算过程。(注意:为了书写方便,下图用符号 d d d 表示对代价函数 J J J 某个变量的偏导。比如 d z dz dz 表示 ∂ J ∂ z \frac{\partial{J}}{\partial{z}} zJ)。
在这里插入图片描述

4.3 各个矩阵或向量的尺寸

需要注意的是,向量化计算对参与运算的矩阵或向量的尺寸十分敏感。在运算时,我们需要对各个矩阵或向量的尺寸有十分清楚的了解。假如: x x x 是一个包含 n 个特征值的列向量,且样本集包含 m 个样本,网络的第 i 层有 n [ i ] n^{[i]} n[i] 个节点,则各个矩阵或向量的尺寸为:

X X X n ∗ m n*m nm
Y Y Y 1 ∗ m 1*m 1m
W [ i ] W^{[i]} W[i] n [ i ] ∗ n [ i − 1 ] n^{[i]}*n^{[i-1]} n[i]n[i1]
b [ i ] b^{[i]} b[i] n [ i ] ∗ 1 n^{[i]}*1 n[i]1
Z [ i ] Z^{[i]} Z[i] n [ i ] ∗ m n^{[i]}*m n[i]m
A [ i ] A^{[i]} A[i] n [ i ] ∗ m n^{[i]}*m n[i]m

另外在反向传播中,代价函数对某个矩阵的偏导得到的梯度矩阵与这个矩阵的尺寸是一致的,即:

d W [ i ] dW^{[i]} dW[i] W [ i ] W^{[i]} W[i] 的尺寸一致;
d b [ i ] db^{[i]} db[i] b [ i ] b^{[i]} b[i] 的尺寸一致;
d Z [ i ] dZ^{[i]} dZ[i] Z [ i ] Z^{[i]} Z[i] 的尺寸一致;
d A [ i ] dA^{[i]} dA[i] A [ i ] A^{[i]} A[i] 的尺寸一致。

  • 47
    点赞
  • 321
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值