1. 深层神经网络(Deep L-layer Neural network)
什么是深度神经网络呢?
首先,我们之前已经学习了Logistic回归、单隐层神经网络,图1中还给出了一个双隐层神经网络和五隐层的神经网络。
Logistic回归是最简单的一种神经网络,是一个浅层模型,而图1中的最后一个神经网络的模型深度要比Logistic回归深得多。浅层或深层是一个相对的程度概念。
一个神经网络的层数为除去输入层以外的其他所有层数,包含一个隐层的神经网络称为双隐层神经网络。按照这个思路,Logistic回归从技术层面上说,它是一个单层神经网络。但前几年在人工智能或机器学习社区中,大家发觉有些函数只有非常深层的神经网络能够学习,而浅一些的模型通常无法学习。
处理任何具体问题的时候都会很难预先准确的判断需要多深的神经网络,因此,先试试Logistic回归的效果,然后再依次增加隐藏层的个数,最后在保留交叉验证数据或开发集上进行评估的做法是比较合理的。隐藏层的个数可以看做是一个可以自由选择数值大小的超参数。
图2为一个四层神经网络,它包含3个隐藏层。每个隐藏层的隐藏单元个数为5、5、3,有一个输出单元。我们以这个神经网络为参照,介绍下用来描述深度神经网络的符号:
- L表示神经网络的层数,图2中的神经网络L=4;
- n[l]表示l层上的节点(单元)数量,输入层标记为第0层,则图2中的神经网络各层节点数可表示为:n[1]=5,n[2]=5,n[3]=3,n[4]=n[L]=1,输入层表示为n[0]=nx=3;
- a[l]表示l层中的激活函数,a[l]=g[l](z[l]);
- w[l]表示在a[l]中计算z[l]值的权重;
- b[l]也是在a[l]方程中使用。
输入特征用x表示,但同时,x也是第0层的激活函数,因此,a0=x。最后一层的激活函数a[L]=y帽,也就是说a[L]等于这个神经网络的预测结果y帽。
2. 深层网络中的前向传播(Forward Propagation in a Deep Network)
本节课中主要讲解了如何在深度网络中灵活应用正向和反向传播。跟以前一样,我们先来看看对其中一个训练样本x该怎么应用正向传播,然后再介绍对整个训练集应用正向传播的向量化过程。本节课我们以四层神经网络(图3)为例,对深层网络的前向传播进行详细讲解。
给定一个输入特征x,计算第一层的激活单元:
- 首先需要计算z[1]:
其中,w[1]和b[1]是会影响到第一层激活单元的参数,输入特征x也可表示为a[0],因为输入特征向量x也是第0层的激活函数。
- 然后计算第一层的激活函数,激活函数g取决于它所在的层数:
当第一层的激活函数计算好了之后,第二层的该如何计算呢?与第一层激活函数计算过程相同,首先需要计算z[2],就是第二层的权重矩阵w[2]乘以第一层的输出值a[1],再加上第二层的偏置向量b[2]。然后计算a[2],它为作用于z[2]的激活函数。符号化第二层的两个公式为:
第三层以此类推,不再赘述。
第四层也就是输出层的计算公式为:
第四层的输出a[4]即为想要估算的y帽的值。
从上述第一层到第四层的推导过程可以总结出一个激活函数计算的通用公式:
刚刚我们已经推导了一遍一个训练样本的计算过程,那么接下来我们再来看一下,怎样用向量化的方法训练整个训练集。
我们将所有样本的每一步计算过程的矩阵进行向量化,即可得到下列计算公式:
对上述公式进行抽象化,得到下述深层网络各层针对所有训练样本计算的通用公式:
其中A[0]=X,即为所有训练集样本的输入特征向量。
我们可以看到深层网络的正向传播过程每层的激活函数计算过程都十分类似,但目前并没有太好的办法能够在不显示调用for循环的情况下,对所有层的激活函数进行计算。因此,在正向传播过程中,计算每一层的激活函数,显示调用for循环来执行是可以接受的。
此外,上述推导过程看起来可能是似曾相识,原因是这个推导过程与单隐层的神经网络计算步骤是相似的,区别在于深层网络需要多重复几遍这个过程。
事实上,我们在实现深度神经网络的过程中,想增加得到没有bug的程序的概率的其中一个方法就是非常仔细、系统化的去思考矩阵的维数。Andrew传授了一个比较好的做法就是:在检查代码的时候,拿出一张纸来,边检查代码,边仔细思考每一步操作的矩阵的维数, 具体做法将在下一节课中讲解。
3. 核对矩阵的维数(Getting your matrix dimensions right)
本节课以五层神经网络(图4)为例,对实现神经网络算法过程中的矩阵维数的核对过程进行详细说明。
图4中的各层神经元个数分别为:
做这种运算时,一般要检查的公式是:在实现第l层中矩阵的时候,矩阵w[l]的维度必须是(n[l],n[l-1]),向量b[l]的维度必须是(n[l],1)。
反向传播的dw[l]的维度应与w[l]的维度相同,同样的db[l]的维度与b[l]的相同。
接下来要检查的是z[l]、x和a[l]的维度。根据上一节中的a[l]计算公式可知,a[l]与z[l]的维度相同。
按照一贯做法,上面分析了一个训练样本各个矩阵的维度,下面我们来看一下向量化实现过程中,这些矩阵维度的变化情况。
即使实现过程已经向量化了,w[l]、b[l]、dw[l]和db[l]的维度都不会变化,多样本的向量化与单样本计算是一致的。但Z、A以及X的维度会在向量化后发生变化,下面我们来分析一下发生变化的原因:
首先,根据之前的分析,我们已知单个样本的z[l]计算公式为:
其中,z[l]的维度为(n[l],1),w[l]的维度为(n[l],n[l-1]),a[l-1]的维度为(n[l-1],1),b[l]的维度为(n[l],1)。
而向量化后,Z[l]的计算公式为:
Z[l]代表的是zl水平堆叠形成的矩阵,具体表示为:
从上述公式可以看出,Z[l]的维度不再是(n[l],1),维度变成(n[l],m),其中,m是训练集的大小,即训练集中样本的个数。
同样的,A[l-1]是将m个样本的al-1水平堆叠在一起形成,因此它的维度变成(n[l-1],m)。
这里有一点需要注意,由于W[l]与A[l-1]的乘积得出的矩阵维度为(n[l],m),根据线性代数矩阵加法的规则,另一个加数b[l]的维度也应该是(n[l],m)。但我们刚刚说b[l]的维度单样本与多样本向量化后没有区别,这是为什么呢?
这主要还是依赖于Python的广播技术,它可以将(n[l],1)维向量自动扩展复制成一个(n[l],m)的矩阵。
在代码实现深度神经网络的算法过程中,确保所有矩阵维度前后一致,能够帮助我们排除一些可能的bug来源。
4. 为什么使用深层表示(Why deep representations?)
我们都知道,深度神经网络能解决好多问题,其实并不需要很大的神经网络,但是得有深度,或者说需要有很多隐藏层。为什么会有这样的需求呢?下面通过几个例子直观的理解下为什么深度神经网络会很好用。
首先,深度网络究竟在计算什么呢?我们通过人脸识别(人脸检测)系统为例来看一下。在人脸识别系统中,当输入一张人脸照片时(照片在计算机中存储为RGB各自对应的矩阵,即输入特征向量),深度神经网络的第一层可以看作是一个特征探测器(或者边缘探测器),假设第一层的隐藏单元共有24个,接下来看一下,这些隐藏单元是怎么针对图6中的人脸进行计算的。
图7中的每个小方格代表一个隐藏单元,不同的隐藏单元会去寻找图片的不同边缘位置。专门用来做图像识别的卷积神经网络将在后面的课程中讲解,到那时会详细解释为什么一个隐藏单元是用一个小方格表示的,这里先不作解释。
可以先把神经网络的第一层当作看图找照片的各个边缘,然后将这些组成边缘的像素放到一起,形成第一层的输出,即第二层的输入。第二层将不同的边缘像素进行组合,形成面部的不同部分,比如可能有一个神经元专门负责找眼睛的部分,另一个神经元在找鼻子的部分。通过把许多边缘结合在一起,就可以开始检测人脸的不同部分。
第三层将第二层输出的人脸的不同部分组合在一起,就可以识别或探测出不同的人脸。
总结下,在人脸识别过程中,可以直观的将神经网络的前几层看作是探测简单特征的函数,如边缘。然后在之后的几层中将前几层识别出的特征进行组合,以便神经网络的层次越深,能够学习的函数越复杂。图7-图9的更深层含义将在卷积神经网络的学习过程中做更深入的介绍。
还有一个技术性的细节需要理解的是:边缘探测器其实相对来说都是针对照片中非常小块的面积,参照图6中的一个小方格。而面部识别则会针对更大一些的区域,参照图9。但核心思想是:在做人脸识别时,一般都会从较小的细节入手,比如边缘,然后再一步步将上一步的特征进行组合来识别更复杂的部位,如一只眼睛或一个鼻子;再将眼睛和鼻子组装到一起,形成更复杂的部分。
这种从简单到复杂的金字塔状表示法或组织方法也可以应用在图像或人脸识别以外的其他数据上。比如要建立一个语音识别系统的时候,需要解决的就是如何识别一个音频片段中的语义。那么,神经网络需要依次学习以下内容:
第一步: 学习检测比较低层次的音频波形的一些特征,比如音调是变高了还是变低了、分辨白噪音、咝咝的声音、音调等。
第二步: 将上一步学习的音频波形组合在一起,就可以去探测声音的基本单元,在语言学中称为音位(phonemes)。
第三步: 在具备基本声音单元学习能力后,将这些音位进行组合就能够识别出音频中的单词。
第四步: 将这些单词进行组合就能够识别出短语或句子。
所以,有多个隐藏层的深度神经网络可以在前几层学习一些比较低层次的简单特征,然后在后面几层中,将这些简单特征组合起来去检测更复杂的东西。