收藏ShowMeAI查看更多精彩内容
本系列为吴恩达老师《深度学习专项课程(Deep Learning Specialization)》学习与总结整理所得,对应的课程视频可以在这里查看。
在ShowMeAI前一篇文章 神经网络基础 中我们对以下内容进行了介绍:
本篇内容我们将从浅层神经网络入手,逐步拓展到真正的神经网络模型知识学习。
图示为两层神经网络,也可以称作单隐层神经网络(a single hidden layer neural network)。这就是典型的浅层(shallow)神经网络,结构上,从左到右,可以分成三层:
注意:当我们计算网络的层数时,通常不考虑输入层。因此图中隐藏层是第一层,输出层是第二层。
有一些约定俗成的符号表示,如下:
接下来我们开始详细推导神经网络的计算过程。
我们依旧来看看我们熟悉的逻辑回归,我们用其构建两层神经网络。逻辑回归的前向传播计算可以分解成计算$z和
$a的两部分。
如果我们基于逻辑回归构建两层神经网络,前向计算从前往后要做2次计算:
在每层计算中,我们注意对应的上标和下标:
我们将输入层到隐藏层的计算公式列出来:
后续从隐藏层到输出层的计算公式为:
上述每个节点的计算都对应着一次逻辑运算的过程,分别由计算z和a两部分组成。
我们引入向量化思想提升计算效率,将上述表达式转换成矩阵运算的形式,如下所示:
我们这里特别注意一下数据维度:
上面部分提到的是单个样本的神经网络正向传播矩阵运算过程。对于m个训练样本,我们也可以使用向量化矩阵运算的形式来提升计算效率。形式上,它和单个样本的矩阵运算十分相似,比较简单。我们记输入矩阵X的维度为(n_x,m),则有:
上述公式中,Z^{[1]}的维度是(4,m),4是隐藏层神经元的个数;A^{[1]}的维度与Z^{[1]}相同;Z^{[2]}和A^{[2]}的维度均为(1,m)。
我们可以这样理解上述的矩阵:行表示神经元个数,列表示样本数目m。
在神经网络中,隐藏层和输出层都需要激活函数(activation function),前面的例子中我们都默认使用Sigmoid函数\sigma(z)作为激活函数。实际我们有不同的激活函数可以选择,而且它们有各自的优点:
the hyperbolic tangent function,双曲正切函数
优点:函数输出介于(-1,1),激活函数的平均值就更接近0,有类似数据中心化的效果。效果几乎总比Sigmoid函数好(二元分类的输出层我们还是会用Sigmoid,因为我们希望输出的结果介于(0,1))。
缺点:当z趋紧无穷大(或无穷小),导数的梯度(即函数的斜率)就趋紧于0,这使得梯度算法的速度大大减缓。这一点和Sigmoid一样。
the rectified linear unit,修正线性单元
优点:当z > 0时,梯度始终为1,从而提高神经网络基于梯度算法的运算速度,收敛速度远大于Sigmoid和tanh。
缺点:当z < 0时,梯度一直为0,但是实际的运用中,该缺陷的影响不是很大。
带泄漏的ReLU
优点:Leaky ReLU保证在z < 0的时候,梯度仍然不为0。
理论上来说,Leaky ReLU有ReLU的所有优点,但在实际操作中没有证明总是好于ReLU,因此不常用。
总结
在选择激活函数的时候,如果在不知道该选什么的时候就选择ReLU。当然也没有固定答案,要依据实际问题在交叉验证集合中进行验证分析。注意,我们可以在不同层选用不同的激活函数。
使用线性激活函数和不使用激活函数、无论神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,就成了最原始的感知器了。我们以2层神经网络做一个简单推导,如下:
假设所有的激活函数都是线性的,为了更简单一点,我们直接令激活函数g(z)=z,即a=z。那么,浅层神经网络的各层输出为:
我们对上述公式中a^{[2]}展开计算,得:
上述推导后,我们可以发现a^{[2]}仍是输入变量x的线性组合!后续堆叠更多的层次,也可以依次类推,这表明,使用神经网络,如果不使用激活函数或使用线性激活函数,与直接使用线性模型的效果并没有什么两样!因此,隐藏层的激活函数必须要是非线性的。
不过,在部分场景下,比如是回归预测问题而不是分类问题,输出值y为连续值,输出层的激活函数可以使用线性函数。如果输出y恒为正值,则也可以使用ReLU激活函数,这些具体情况具体分析。
我们来看一下不同激活函数的导数,这将在我们反向传播中频繁用到。
下面我们来一起看看,神经网络中的梯度计算。
我们依旧以浅层神经网络为例,它包含的参数为W^{[1]},b^{[1]},W^{[2]},b^{[2]}。
令输入层的特征向量个数n_x=n^{[0]},隐藏层神经元个数为n^{[1]},输出层神经元个数为n^{[2]}=1。则:
上述神经网络的前向传播过程,对应的公式如下图左侧。反向传播过程,我们会进行梯度计算,我们先列出Cost Function对各个参数的梯度,如下图右侧公式。
其中,np.sum
使用到python中的numpy工具库,想了解更多的同学可以查看ShowMeAI的 图解数据分析 系列中的numpy教程,也可以通过ShowMeAI制作的numpy速查手册 快速了解其使用方法)
我们使用上篇内容 神经网络基础 中的计算图方式来推导神经网络反向传播。回忆我们前面提到的逻辑回归,推导前向传播和反向传播的计算图如下图所示:
因为多了隐藏层,神经网络的计算图要比逻辑回归的复杂一些,如下图所示。
综上,对于浅层神经网络(包含一个隐藏层)而言,「单个样本」和「m个训练样本」的反向传播过程分别对应如下的6个表达式(都是向量化矩阵形式):
我们在很多机器学习模型中,会初始化权重为0。但在神经网络模型中,参数权重W是不能全部初始化为零的,它会带来对称性问题(symmetry breaking problem),下面是分析过程。
假设一个浅层神经网络包含两个输入,隐藏层包含两个神经元。
如果权重W^{[1]}和W^{[2]}都初始化为零,这样使得隐藏层第一个神经元的输出等于第二个神经元的输出,即a_1^{[1]}=a_2^{[1]}。容易得到dz_1^{[1]}=dz_2^{[1]},以及dW_1^{[1]}=dW_2^{[1]}。
我们发现:隐藏层两个神经元对应的权重行向量W_1^{[1]}和W_2^{[1]}每次迭代更新都会得到完全相同的结果,W_1^{[1]}始终等于W_2^{[1]},完全对称!这样隐藏层设置多个神经元就没有任何意义了。
当然,因为中间层每次只会有1个偏置项参数b,它可以全部初始化为零,并不会影响神经网络训练效果。
上述提到的权重W全部初始化为零带来的问题就是symmetry breaking problem(对称性)。解决方法也很简单:在初始化的时候,W参数要进行随机初始化,不可以设置为0。而b因为不存在对称性的问题,可以设置为 0。
以 2 个输入,2 个隐藏神经元为例:
W = np.random.rand(2,2)* 0.01
b = np.zeros((2,1))
这里将 W 的值乘以 0.01(或者其他的常数值)的原因是为了使得权重 W 初始化为较小的值,这是因为使用 Sigmoid 函数或者 tanh 函数作为激活函数时:
ReLU 和 Leaky ReLU 作为激活函数时不存在这种问题,因为在大于 0 的时候,梯度均为 1。如果输出层是Sigmoid函数,则对应的权重W最好初始化到比较小的值。