今天我们要讲的是如何构建卷积神经网络的卷积层,下面来看个例子。
上节课,我们已经讲了如何通过两个过滤器卷积处理一个三维图像,并输出两个不同的4×4矩阵。假设使用第一个过滤器进行卷积,得到第一个4×4矩阵。使用第二个过滤器进行卷积得到另外一个4×4矩阵。
最终各自形成一个卷积神经网络层,然后增加偏差,它是一个实数,通过Python的广播机制给这16个元素都加上同一偏差。然后应用非线性函数,为了说明,它是一个非线性激活函数ReLU,输出结果是一个4×4矩阵。
对于第二个4×4矩阵,我们加上不同的偏差,它也是一个实数,16个数字都加上同一个实数,然后应用非线性函数,也就是一个非线性激活函数ReLU,最终得到另一个4×4矩阵。然后重复我们之前的步骤,把这两个矩阵堆叠起来,最终得到一个4×4×2的矩阵。我们通过计算,从6×6×3的输入推导出一个4×4×2矩阵,它是卷积神经网络的一层,把它映射到标准神经网络中四个卷积层中的某一层或者一个非卷积神经网络中。
注意前向传播中一个操作就是z^([1])=W^([1]) a^([0])+b^([1]),其中a^([0])=x,执行非线性函数得到a^([1]),即a^([1])=g(z^([1]))。这里的输入是a^[0] ,也就是x,这些过滤器用变量W^([1])表示。在卷积过程中,我们对这27个数进行操作,其实是27×2,因为我们用了两个过滤器,我们取这些数做乘法。实际执行了一个线性函数,得到一个4×4的矩阵。卷积操作的输出结果是一个4×4的矩阵,它的作用类似于W^([1]) a^([0]),也就是这两个4×4矩阵的输出结果,然后加上偏差。
这一部分(图中蓝色边框标记的部分)就是应用激活函数ReLU之前的值,它的作用类似于z^([1]),最后应用非线性函数,得到的这个4×4×2矩阵,成为神经网络的下一层,也就是激活层。
这就是a^([0])到a^([1])的演变过程,首先执行线性函数,然后所有元素相乘做卷积,具体做法是运用线性函数再加上偏差,然后应用激活函数ReLU。这样就通过神经网络的一层把一个6×6×3的维度a^([0])演化为一个4×4×2维度的a^([1]),这就是卷积神经网络的一层。
示例中我们有两个过滤器,也就是有两个特征,因此我们才最终得到一个4×4×2的输出。但如果我们用了10个过滤器,而不是2个,我们最后会得到一个4×4×10维度的输出图像,因为我们选取了其中10个特征映射,而不仅仅是2个,将它们堆叠在一起,形成一个4×4×10的输出图像,也就是a^[1] 。
为了加深理解,我们来做一个练习。假设你有10个过滤器,而不是2个,神经网络的一层是3×3×3,那么,这一层有多少个参数呢?我们来计算一下,每一层都是一个3×3×3的矩阵,因此每个过滤器有27个参数,也就是27个数。然后加上一个偏差,用参数b表示,现在参数增加到28个。上一页幻灯片里我画了2个过滤器,而现在我们有10个,加在一起是28×10,也就是280个参数。
请注意一点,不论输入图片有多大,1000×1000也好,5000×5000也好,参数始终都是280个。用这10个过滤器来提取特征,如垂直边缘,水平边缘和其它特征。即使这些图片很大,参数却很少,这就是卷积神经网络的一个特征,叫作“避免过拟合”。你已经知道到如何提取10个特征,可以应用到大图片中,而参数数量固定不变,此例中只有28个,相对较少。
最后我们总结一下用于描述卷积神经网络中的一层(以l层为例),也就是卷积层的各种标记。
这一层是卷积层,
用f^([l])表示过滤器大小,我们说过过滤器大小为f×f,上标[l]表示l层中过滤器大小为f×f。通常情况下,上标[l]用来标记l层。
用p^([l])来标记padding的数量,padding数量也可指定为一个valid卷积,即无padding。或是same卷积,即选定padding,如此一来,输出和输入图片的高度和宽度就相同了。
用s^([l])标记步幅。
这一层的输入会是某个维度的数据,表示为n×n×n_c,n_c某层上的颜色通道数。
我们要稍作修改,增加上标[l-1],即n^[l-1] ×n^[l-1] ×n_c^[l-1] ,因为它是上一层的激活值。
此例中,所用图片的高度和宽度都一样,但它们也有可能不同,
所以分别用上下标H和W来标记,即n_H^[l-1] ×n_W^[l-1] ×n_c^[l-1] 。那么在第l层,图片大小为n_H^[l-1] ×n_W^[l-1] ×n_c^[l-1] ,l层的输入就是上一层的输出,因此上标要用[l-1]。神经网络这一层中会有输出,它本身会输出图像。其大小为n_H^([l])×n_W^([l])×n_c^([l]),这就是输出图像的大小。
前面我们提到过,这个公式给出了输出图片的大小,至少给出了高度和宽度,
⌊(n+2p-f)/s+1⌋(注意:((n+2p-f)/s+1)直接用这个运算结果,也可以向下取整)。
在这个新表达式中,l层输出图像的高度,即n_H^([l])=⌊(n_H^[l-1] +2p^([l])-f^([l]))/s^([l]) +1⌋,同样我们可以计算出图像的宽度,用W替换参数H,即n_W^([l])=⌊(n_W^[l-1] +2p^([l])-f^([l]))/s^([l]) +1⌋,公式一样,只要变化高度和宽度的参数我们便能计算输出图像的高度或宽度。这就是由n_H^[l-1] 推导n_H^([l])以及n_W^[l-1] 推导n_W^([l])的过程。
那么通道数量又是什么?这些数字从哪儿来的?
我们来看一下。输出图像也具有深度,通过上一个示例,我们知道它等于该层中过滤器的数量,如果有2个过滤器,输出图像就是4×4×2,它是二维的,如果有10个过滤器,输出图像就是4×4×10。输出图像中的通道数量就是神经网络中这一层所使用的过滤器的数量。如何确定过滤器的大小呢?我们知道卷积一个6×6×3的图片需要一个3×3×3的过滤器,因此过滤器中通道的数量必须与输入中通道的数量一致。因此,输出通道数量就是输入通道数量,所以过滤器维度等于f^([l])×f^([l])×n_c^[l-1] 。
应用偏差和非线性函数之后,这一层的输出等于它的激活值a^([l]),也就是这个维度(输出维度)。a^([l])是一个三维体,即n_H^([l])×n_W^([l])×n_c^([l])。当你执行批量梯度下降或小批量梯度下降时,如果有m个例子,就是有m个激活值的集合,那么输出A^([l])=m×n_H^([l])×n_W^([l])×n_c^([l])。如果采用批量梯度下降,变量的排列顺序如下,首先是索引和训练示例,然后是其它三个变量。
该如何确定权重参数,即参数W呢?过滤器的维度已知,为f^([l])×f^([l])×n_c^([l-1]),这只是一个过滤器的维度,有多少个过滤器,这(n_c^([l]))是过滤器的数量,权重也就是所有过滤器的集合再乘以过滤器的总数量,即f^([l])×f^([l])×n_c^([l-1])×n_c^([l]),损失数量L就是l层中过滤器的个数。
最后我们看看偏差参数,每个过滤器都有一个偏差参数,它是一个实数。偏差包含了这些变量,它是该维度上的一个向量。后续课程中我们会看到,为了方便,偏差在代码中表示为一个1×1×1×n_c^([l])的四维向量或四维张量。
卷积有很多种标记方法,这是我们最常用的卷积符号。大家在线搜索或查看开源代码时,关于高度,宽度和通道的顺序并没有完全统一的标准卷积,所以在查看GitHub上的源代码或阅读一些开源实现的时候,你会发现有些作者会采用把通道放在首位的编码标准,有时所有变量都采用这种标准。实际上在某些架构中,当检索这些图片时,会有一个变量或参数来标识计算通道数量和通道损失数量的先后顺序。只要保持一致,这两种卷积标准都可用。很遗憾,这只是一部分标记法,因为深度学习文献并未对标记达成一致,但课上我会采用这种卷积标识法,按高度,宽度和通道损失数量的顺序依次计算。
这节课我想讲的重点是,卷积神经网络的某一卷积层的工作原理,以及如何计算某一卷积层的激活函数,并映射到下一层的激活值。
了解了卷积神经网络中某一卷积层的工作原理,我们就可以把它们堆叠起来形成一个深度卷积神经网络,下一个笔记讲解。