文章

卷积神经网络

卷积神经网络

回顾上节

简单回顾上节课的内容,我们讲了神经网络。线性评分函数的运行实例,通过向上堆叠这些线性层,并在层间添加非线性,来实现完整的神经网络。我们发现这有助于解决模式问题,我们通过学习任务所需的中间模板,例如不同类型的车辆,红色的车,黄色的车之类的,把中间特征组合起来得到某一类别的最终的评分函数。

Desktop View 简单回顾:神经网络(来自cs231n)

卷积神经网络与常规神经网络的构想基本一致。不同的是需要训练卷积层,因为卷积层更能保留输入的空间结构。

Desktop View 卷积神经网络(来自cs231n)

通过神经网络的历史,来了解卷积神经网络的诞生。

卷积和池化

关于ConvNets在今天的应用,实际上它有大量的运用。对你们的项目而言,充分发挥你们的想象力,我们乐于看见其他的应用。

今天我们学习卷积神经网络是如何工作的。和神经网络一样,我们先从函数角度了解它的工作原理,不作任何大脑的比喻,然后我们会简单介绍这些连接点。

上节课我们提到全连接层的概念。对全连接层而言,我们要做的就是在这些向量上进行操作。比如我们有一张图片,三维图片(32*32*3大小)。一些是我们之前看过的图片,我们将所有的像素展开就可以得到一个3072维的向量。这个例子我们得到这些权重,把向量和权重矩阵相乘,这里我们用10*3072然后就可以得到激活值。这一层的输出,例子中我们用10行数据与这个3072维的输入进行点积运算,从而我们可以得到一个数字,这个数字也就是该神经元的值。

Desktop View 全连接层(来自cs231n)

在这个例子中,我们将有10个这样的神经元输出。

卷积原理

至于卷积层,它和全连接层的主要差别,在于我们提到的可以保全空间结构。用一张我们之前用过的32*32*3的图片,而不是将它展开成一个长的向量,我们可以保持图片的结构,这个三维输入的结构。接下来我们的权重是一些小的卷积核。

Desktop View 图片输入保留空间结构(来自cs231n)

Desktop View 卷积核的大小(来自cs231n)

例子中是5*5*3的大小,我们将把这个卷积核在整个图像上滑动,计算出每一个空间定位时的点积结果,接下来就是它们工作的具体细节。

首先我们采用的卷积核总是会将输入量扩展至完全,所以它们都是很小一个空间区域,这里是5*5,而不是输入空间全部大小32*32,但它们通常会遍历所有通道,所以采用5*5*3的大小。

然后我们采用这个卷积核,并给定一个空间区域,在这个卷积核和图像块间进行点积运算。我们要做的就是在图像空间区域上覆盖这个卷积核,然后进行点积运算。也就是将卷积核每个位置元素和与之对应图像区域的像素值相乘,这个区域是从图像上取出的,经过运算后会给我们一个点积结果。在这个例子中,我们进行了5*5*3次计算,这是乘法运算的次数,之后我们再加上偏置项,这就是使用卷积核W的基本方法,就是用W的转置乘以X再加上偏置项。

Desktop View 进行点积计算(来自cs231n)

当我们做点积时,是否会把5*5*3这个块转成一个向量。本质上我们就是这么做的,将对应的每个空间位置元素进行相乘然后相加,如果你把在那一点处的卷积核及对应的输入数据块展开成一个向量再进行点积运算,它们的结果是相同的。

Desktop View 不断滑动卷积核(来自cs231n)

如何滑动卷积核并遍历所有空间位置呢?接下来我们讨论的就是,将这个卷积核从左上方的边角处开始,让卷积核遍历输入的所有像素点,在每一个位置我们都进行点积运算,每一次运算都会在输出激活映射中产生一个值,之后我们再继续滑动卷积核,最简单的方式就是一个像素一个像素地滑动,我们持续地进行这样操作,并相应的填满我们的输出激活映射。你可能意识到输出映射的维数和你所想的结果并不符合,我们的输入是32*32,但输出是28*28。我们将会对这个问题用例子来解释这里的维数变化的机制,但首先你需要决定如何滑动卷积核。是否按像素逐个滑动,或者其他滑动方式,比如可以每经过两个输入值进行一次滑动,也就是说一次滑动两个像素点,这是你得到不同尺寸大小的输出,这完全取决于滑移的方式。但是一般而言你会依照栅格形式来进行滑移。

Desktop View 滑动第二个卷积核(来自cs231n)

我们采用了一卷积核,然后将它在图像的整个平面进行滑移,然后输出它的激活映射,它里面的值就是卷积核在每个位置求得的结果。当我们在处理一个卷积层时,我们希望用到多种卷积核,因为每一个卷积核都可以从输入中得到一种特殊的模式或概念,所以我们会有一组卷积核。这里我将要用第二个卷积核,也就是图中绿色的卷积核,它同样也是5*5*3的大小,将它进行滑移,遍历输入层的所有位置,然后我们得到了第二个相同尺寸的绿色的激活映射。

Desktop View 6个卷积核,最终对应6层激活映射(来自cs231n)

我们可以按照同样的方法使用多个卷积核进行计算,如果我们这样做的话,比方说如果我们有6个卷积核,每个尺寸都是5*5*3,这样我们就会得到一个6层的激活映射。总之我们会得到这么一个尺寸大小是28*28*6的输出。

下面简单描述下在卷积神经网络中我们是如何使用这些卷积层的。我们的ConvNet基本上是由多个卷积层组成的一个序列,它们依次堆叠,就像我们之前在神经网络中那样堆叠简单的线性层一样,之后我们将用激活函数对其进行逐一处理,比方说一个ReLU激活函数。我们将得到一些比如ConvReLU的东西,以及一些池化层,之后你会得到一系列的这些层,每一个都会有一个输出,该输出又作为下一个卷积层的输入。

Desktop View 在卷积神经网络中,我们如何使用这些卷积层(来自cs231n)

这些层采用多个卷积核,每一个卷积核会产生一个激活映射,可以观察这些层,然后把它们叠加成一个ConvNet,最后的结果是你完成了对这组卷积核的学习。

Desktop View 卷积层特征可视化(来自cs231n)

前面几层的卷积核一般代表了一些低阶的图像特征,比方说像一些边缘特征,而对于那些中间层,你可以得到一些更加复杂的图像特征,它的内容看起来可能更加丰富,比如边角和斑点等等,而对于那些高阶的特征,你可以获得一些比斑点之类的更加丰富的内容。

我们会在后面的课程中详细讨论如何能够直接观察到这些图像特征,并且尝试去解释你的神经网络。你的神经网络在学习何种特征,但当前最重要的是要明白这些特征大致上代表了什么。当你有了这些堆叠在一起的层时,你要知道它们是一些从简单到复杂的特征序列。

提问时间

提问:增加深度的出发点是什么?

这里针对初始层我有三个卷积核,接着下一层有6个卷积核,这主要是出于一种架构设计层面的考虑。在实际操作中有人发现这种网络结构更加有效,之后我们会举例说明多种卷积神经网络结构之间的差异,还有如何去设计这些结构,以及为什么这些特殊的结构会比其它的更有效一些。但基本的考虑是你可以选择不同的设计方式,针对一个卷积神经网络,你的卷积核尺寸大小,它滑动的步长,你将采用多少个卷积核,在后面会讨论这个。

当我们将卷积核在图像上进行滑移时,它有些像我们对这些边缘或者拐角进行采样而不是其他地方,这是一个很好的点,后面用几张PPT讨论,我们如何尝试并弥补这个问题。

Desktop View 卷积层特征可视化(来自cs231n)

这些我们堆叠在一起的卷积层上,看到了我们如何从更简单的特征开始,然后将它们集成到更复杂的特征上。这实际上和HubelWiesel在实验观察到的是一致的。在早期阶段,我们使用这些简单神经元,然后可以推广到更复杂神经元。所以即使我们没有明确地强制我们的ConvNet模型去学习这些类型的特征,实际上当你给它这种类型的层次结构,并且使用反向传播进行训练,这些类型的卷积核最终也会学到。

提问:在这些可视化的图像中,我们看到了什么?

在这些可视化的图像中,如果我们看Conv1第一个卷积层,这些网格中的每个部分都是一个神经元,所以我们这里可视化的就是这个输入长什么样子,它将特定神经元的激活函数最大化,你会得到什么样的图像能给你最大值,并使神经元拥有最大值。我们做这个的方式基本上是通过从一个特定的神经元激活函数开始反向传播,然后观察输入中的什么触发之后会产生这个神经元的最大值。关于如何创建这些可视化图像,这些我们将会在之后的讲座中更深入讨论。

基本上这个网格中的每个元素都在展示了输入会长什么样子,基本上是最大化了神经元的激活函数,所以从某种意义上来说,神经元在寻找什么。

Desktop View 卷积层特征可视化(来自cs231n)

这是由每个卷积核生成的一些激活函数映射的例子,我们可以把可视化的东西放在最上面,有一整排5*5的过滤器,这基本上是一个经过训练的ConvNet的实际案例,其中每一个都是一个5*5的卷积核的样子,然后我们在一张图像上进行卷积。在这个图像中,我认为这个激活函数看起来像是一个小汽车的一角,像是车灯。这有一个例子,如果我们看第一个图像,这个红色的卷积核就会像卷积核上的红色框一样过滤,我们会看到它正在寻找看起来像是一个定向边缘的模板,所以如果你把这个卷积核滑过图像,它会得到一个较高的值,在这个类型的方向由边缘的地方会有很多白色的值,所以这些激活函数映射的每一个都对应滑动这些卷积核的一个输出,以及这些卷积核产生输出的位置,或者说图像中这种类型的模板更能表示的地方。我们叫这些卷积,是因为这与两个信号的卷积有关,所以很早就有人提出这个基本上就是卷积公式,这对于在信号处理中见过卷积的人来说很明显。当然在实践中,它实际上更像是一个相关性,我们与这个卷积核的翻转形式进行卷积,但这有一些微妙,这些对于课程的目的并不是很重要,但基本上如果你正写出来你正在做什么,那就符合卷积的定义了。但这里只需要一个卷积核在图像空间上滑过,并且计算出每个位置的点积。

Desktop View 卷积层特征可视化(来自cs231n)

卷积神经网络从整体上来看像什么呢?其实就是一个输入图片,让它通过很多层,第一个是卷积层,然后通常是非线性层,所以ReLU其实就是一种非常常用的手段。有了Conv层、ReLU层,接下来我们会用到池化层,这些措施已经大大降低了激活映射的采样尺寸。经过这些处理之后,最终得到卷积层输出,然后我们就可以用我们之前见过的全连接层连接所有的卷积输出,并用其获得一个最终的分值函数。

实例剖析

下面通过几个例子来理解这个过程。

前面说过的这个32*32*3的图像,用5*5*3的卷积核在图像上滑过,看看如何准确地产生这个28*28的激活映射。

Desktop View 卷积示例(来自cs231n)

我们可以假设实际上是用的7*7的输入,有一个3*3的卷积核,接下来用这个卷积核将它套在我们左下角,然后我们来做乘法,做点积,将所有的值乘起来,得到我们的第一个值,接着是激活映射图左上方的值。

Desktop View 卷积示例(来自cs231n)

接下来我们要做的是将卷积核从左向右滑动,从中会得到另一个值,继续这样做就会不断得到新值,最后我们将得到一个5*5的输出。

Desktop View 卷积示例(来自cs231n)

Desktop View 卷积示例(来自cs231n)

基本上,滑动卷积核是在水平方向上的5个空间位置以及垂直方向的5个空间位置。

前面说过有多种选项可选,我事先将其滑过每一个单独的空间位置,每滑一次所经过的区间称其为步幅,在最初我们使用1作为步长,现在我们看用2作为步长结果会怎样?

Desktop View 卷积示例,步长为2(来自cs231n)

刚开始找一个初始位置,每次滑过两个像素,就会得到基于这个位置的进一步的值。

Desktop View 卷积示例,步长为2(来自cs231n)

也就是说,如果我们采用值为2的步幅,我们总共会有3个可以拟合的输出,也就是一个3*3的输出。

Desktop View 卷积示例,步长为2(来自cs231n)

那么步幅采用3,会有什么结果?再滑动一个回合,结果显示它在这里不能拟合了。也就是说,当采用步长3时,和既有图像不能很好地拟合,说明这是行不通的,我们不会这样去做卷积,因为它会导致不对称的输出。

Desktop View 卷积示例,步长为3(来自cs231n)

下面看看如何计算输出尺寸,实际上它能归纳为一个很好的公式。

这里假设输入的维度为N,卷积核大小为F,那么我们在滑动时的步幅以及最终的输出大小,也就是我们输出大小的空间维度,这些将变成(N-F)/步幅,然后加1。假设将卷积核置于最不可能的位置上,然后选取所有在它前面的像素,那么选取步幅时有几个解是可以拟合的,其实就是这个方程的解。

Desktop View 计算输出向量的尺寸(来自cs231n)

像我们之前看到的一样,如果N=7F=3,如果我们想用步幅1,就会得到像我们之前采用的5*5一样的结果,用步幅2也一样,但用步幅3时就行不通了。

相当于采用零填充边界来得到最后我们想要的大小,就像我们前边提到的一个问题,就是在角上我们要做什么,所以实际上我们在用零填充我们的输入图片,所以你现在将能够在实际输入图像的右上角位置放置一个卷积核。

Desktop View 零填充边界(来自cs231n)

问题来了。如果输入是一样的,就是7*7,卷积核大小是3*3,步幅为1,但是现在用1个像素来填充,输出大小会变成怎样?这时N=9,一旦填补了它,就需要将这个填补值应用于公式。这时输出是7*7*(使用的卷积核的数目),因为每个卷积核要在输入的整个深度上做点积,但是之后它将产生一个数字。

在下面这个例子里,每个卷积核将产生一个1*7*7的激活映射图输出,那么深度就是使用的卷积核的数量。

Desktop View 卷积示例(来自cs231n)

提问时间

提问:当我们有一个32*32*3的输入时,这是怎么和前面关联起来的?

我们的输入有个深度,比如展示一个没有深度的2D的例子,这主要是为了简化一下,但在实际中将像前面一样,需要乘以整个深度,这里你的卷积核是一个3*3的空间卷积核,再乘以你的输入深度,在这个例子中就是3*3*3,其他就是一样的了。

提问:零填补是否在角落上增加了一些额外的特征?

我们尽全力来得到一些值,然后做一些就像处理那个图像的范围的事,所以零填补是它的一种方式,我们可以侦测到在这个区域内的模板的某些部分,当然还有其他方式来达成这个目的,你可以尝试复制这里的值或者扩充它们,这样就不用变成零填补了。在实际中这是一个合理的方法,所以在边缘处是有些人为成分,你可以尽最大努力来解决它,处理实际问题时这是很合理的。

提问:如果我们有非方形图片,我们需要会使用横纵不同的步幅吗?

通常这没什么问题,不过实际上通常用同样的步幅,因为我们通常操作方形区域,我们通常就在每个地方用相同的步幅。通常意义上说,它有点像你在看这个图片时的分辨率,所以通常你可能会想匹配你的水平和垂直分辨率,你可以这么做,但人们通常不这么做。

提问:我们为什么要做零填补?

我们做零填补的方式是保持和我们之前的输入大小相同,我们开始用的是7*7,如果让卷积核从左上角开始,将所有东西填入,那么之后我们会得到一个更小的输出,但是我们会想保持全尺寸输出。

如何填充能够基本上保证你想要的输出图像的尺寸,以及在边角区域应用卷积核?

Desktop View 零填充边界(来自cs231n)

在选择上,你的步长、卷积核、卷积核的大小、步长的大小、零填充,通常的卷积核大小有3*35*57*7,这些都是常用的大小。比如3*3,为了保持图像的空间尺寸进行宽度为1的零填充,如果卷积核为5*5,通过数学计算得到零填充的宽度为27*7零填充的宽度则为3

所以进行零填充的目的就是为了保证输入图像的尺寸。

但是如果图像有多个层,你需要处理的图像是多层叠在一起,会发现如果不做零填充,或任何形式的填充,输出图像的尺寸会迅速减小,这不是我们想要的。设想有一个不错的深度网络,你的激活映射迅速缩的非常小,这样是不好的,这会损失一些信息,你只能用很少的值来表示你的原始图像,然而这并不是你想要的。同时每次图像变得更小,关于图像边角的信息也会丢掉更多。

Desktop View 缩小的太快不好(来自cs231n)

关于卷积核的计算

下面是对这些大小的卷积核进行计算的一些例子。

Desktop View 计算输出向量(来自cs231n)

假设我们的输入是332*32的图像,我们使用105*5的卷积核,步长为1,填充宽度为2,输出图像的尺寸有多大?

Desktop View 输出向量尺寸是32(来自cs231n)

在这一层中参数有多少个?记住我们有105*5的卷积核。

Desktop View 参数量是多少?(来自cs231n)

计算时注意,因为输入的大小,还有图像的深度,这里每个卷积核的大小是5*5,但这里还隐含了深度,需要对整个输入进行计算,还有偏差项。

Desktop View 这一层的卷积核参数量:760(来自cs231n)

在实际使用中,每个卷积核有5*5,还要在乘以3(权重),还要再加上偏差项1个参数,每个卷积核有76个参数,一共10个这样的卷积核,所以总共760个参数。

卷积小结

这里总结了卷积层,之后大家可以仔细看看,我们有特定维度的输入,我们有各种选项,比如卷积核的大小,步长的大小,零填充的大小,这些你基本上全部都可以使用。进行到我们之前说的,可以计算输出有多大,总共有多少参数。

Desktop View 总结:卷积层(来自cs231n)

这些常用的设定我们之前讲到过,3*35*5,步长通常为12,根据具体情况选择合适的零填充P。通常来说,比如你希望保持图像的大小,卷积核的个数为K,通常我们使用2的次方数,如3264128512等,这些都是常用的数字。

Desktop View one-by-one卷积(来自cs231n)

另一方面,我们也可以做1*1的卷积,使用1*1的卷积在空间范围做卷积也很有意义。但是在空间区域上并不是真正的5*5,虽然1*1的计算非常琐碎,但我们仍然可以使用这个卷积核在这个深度进行计算。这就是在这个输入深度要在整个深度上进行一个点积。

如果输入的大小是56*56*64,然后用321*1的卷积核进行计算,输出就是56*56*32

这里是一个卷积层在TORCH中的例子,一个深度学习框架。

Desktop View 卷积层在Torch里边的一个示例实现(来自cs231n)

可以进到这些深度学习框架,能看到每一层的定义,这里可以看到每一层中用到的正向计算和反向计算,也可以看到卷积,空间卷积只是它们其中之一。然后需要做的就是所有这些设计的选项,你的输入和输出图像的大小,核的宽度,核的大小,零填充以及这类选项。

看看另一个框架Caffe,会发现它们非常相似。

Desktop View 卷积层在Caffe里边的一个示例实现(来自cs231n)

你会定义网络,在Caffe中定义网络,你可以在配置文件中定义各层的选项,你可以看到卷积层,比如输出的数量、Caffe中卷积核的个数、核的大小和步长等等。

提问:凭着怎样的直观感觉来确定所使用的步长的?

从某种意义上说,这个跟图像分辨率有关,背后的原因通常是当我们使用更大的步长时,我们所获得输出是一个降采样之后的图片,这个降采样之后的图片可以说是一种池化处理,不过又比池化在某些时候更好些。这就是其背后的动因。因为你能获得和降采样处理图片相同的效果,并且这个时候你会缩小在每一层中你所处理的激活映射的尺寸,并且还会在此后影响到你所用到的参数的数目。这是因为比如说在所有卷积层的最后,你加上一些全连接层,现在全连接层会被连接到所有的卷积层的输出值,那么小的步长带给你的是更少的参数,然后基本上可以认为这是在追求一种平衡(参数数量、模型尺寸,还有过拟合之间的平衡)。以上这些就是你在选择步长时所需要考虑的。

CNN架构

卷积神经网络(CNN)由输入层、卷积层、激活函数、池化层、全连接层组成,即INPUT-CONV-RELU-POOL-FC

总的一个结构大致如下,

Desktop View CNN(来自cs231n)

卷积层

用它来进行特征提取,如下:

Desktop View 卷积层(来自cs231n)

输入图像是32*32*33是它的深度(即RGB),卷积层是一个5*5*3filter(感受野),这里注意:感受野的深度必须和输入图像的深度相同。通过一个filter与输入图像的卷积可以得到一个28*28*1的特征图,上图是用了两个filter得到了两个特征图;

我们通常会使用多层卷积层来得到更深层次的特征图。如下:

Desktop View 经过多层卷积得到深层次的特征图(来自cs231n)

Desktop View 多层卷积的过程(来自cs231n)

关于卷积的过程图解如下:

Desktop View 多层卷积的过程细节(来自cs231n)

输入图像和filter的对应位置元素相乘再求和,最后再加上b,得到特征图。如图中所示,filter w0的第一层深度和输入图像的蓝色方框中对应元素相乘再求和得到0,其他两个深度得到20,则有0+2+0+1=3即图中右边特征图的第一个元素3.,卷积过后输入图像的蓝色方框再滑动,stride=2,如下:

Desktop View 以步长为2进行滑动(来自cs231n)

如上图,完成卷积,得到一个3*3*1的特征图;在这里还要注意一点,即zero pad项,即为图像加上一个边界,边界元素均为0(对原输入无影响)。一般有

  • F=3 => zero pad with 1
  • F=5 => zero pad with 2
  • F=7=> zero pad with 3

边界宽度是一个经验值,加上zero pad这一项,是为了使输入图像和卷积后的特征图具有相同的维度,例如,输入为5*5*3,filter为3*3*3,在zero pad1,则加上zero pad后的输入图像为7*7*3,则卷积后的特征图大小为5*5*1(7-3)/1+1),与输入图像一样。

而关于特征图的大小计算方法具体如下,

Desktop View 特征图大小计算公式(来自cs231n)

卷积层还有一个特性,就是权值共享原则。如下图,

Desktop View 权值共享(来自cs231n)

如没有这个原则,则特征图由1032*32*1的特征图组成,即每个特征图上有1024个神经元,每个神经元对应输入图像上一块5*5*3的区域,即一个神经元和输入图像的这块区域有75个连接,即75个权值参数,则共有75*1024*10=768000个权值参数,这是非常复杂的,因此卷积神经网络引入权值共享原则,即一个特征图上每个神经元对应的75个权值参数被每个神经元共享,这样则只需75*10=750个权值参数,而每个特征图的阈值也共享,即需要10个阈值,则总共需要750+10=760个参数。

池化层

对输入的特征图进行压缩,一方面使特征图变小,简化网络计算复杂度;一方面进行特征压缩,提取主要特征。如下,

Desktop View 池化层(来自cs231n)

池化操作一般有两种,一种是Avy Pooling,一种是max Pooling,如下,

Desktop View 最大池化(来自cs231n)

同样地采用一个2*2filtermax pooling是在每一个区域中寻找最大值,这里的stride=2,最终在原特征图中提取主要特征得到右图。而一般的filter2*2,最大取3*3stride2,压缩为原来的1/4

注意:这里的pooling操作是特征图缩小,有可能影响网络的准确度,因此可以通过增加特征图的深度来弥补(这里的深度变为原来的2倍)。

Avy pooling现在不怎么用了,方法是对每一个2*2的区域元素求和,再除以4,得到主要特征。

全连接层

连接所有的特征,将输出值送给分类器(如softmax分类器)。

另外,CNN网络中前几层的卷积层参数量占比小,计算量占比大;而后面的全连接层正好相反,大部分CNN网络都具有这个特点。因此我们在进行计算加速优化时,重点放在卷积层;进行参数优化、权值裁剪时,重点放在全连接层。

视觉之外的卷积神经网络

现在换个角度,从大脑神经元的角度来分析。

卷积层

就像我们之前上一节课分析神经元那样,我们将看到在每一个位置,我们会取一个卷积核与图像的特定部分之间的一个点积,从而得到一个数值结果。

基于同样的想法来取这样一些输入值和权值矩阵W之间的点积,这些卷积核的权值,也就是这些突触的权值,然后得到一个结果值,但它们主要的区别在于,神经元具有局部的连接性,所以我们不关注所输入图片的全部,而是关注图像空间的一个局部区域,就是这样我们很快就会得到这个神经元在图像各个区域所被激发的程度。

现在保留这个空间结构,就可以基于之后各层的激活映射进行推导。

Desktop View 卷积的神经元视角(来自cs231n)

接下来有一些术语。

有一个5*5的卷积核,我们也可以称它为这个神经元的一个5*5的感受野,因为这个感受野基本上讲就是输入区域,就是这个神经元所能接受到的视野,这也是感受野的另一个常见叫法。对于每一个5*5滤波器,我们都将让它们划过整个图像空间,但是这些卷积核都是具有相同的权重,具有相同的参数。

Desktop View 卷积的神经元视角解读(来自cs231n)

正如我们之前所说,我们将会得到的输出将会是这个大小。空间上来说,比如28*28,卷积核的数量就是所谓的深度,比方说一共有5层的卷积核,那么我们从这个三维网格中将会得到一个528*28尺寸的输出。如果你看一下这些卷积核在激活量的某个空间区域内沿着深度方向,这五个神经元,所有这些神经元基本上可以把它理解为所有这些都作用于输入图片的同一片区域,但它们却具有不同的功用,这些不同的卷积核作用于图像的相同区域当中。

Desktop View 卷积的神经元视角解读(来自cs231n)

这里跟我们此前提到过的全连接层做一个比较。之前那个例子我们看一下每一个神经元,在激活区域或者输出中,每一个神经元都连接着平展后的所有输入,所以神经元是与全体输入量都发生关联,而不是像卷积核这样只与图像的一个局部区域发生关联。

Desktop View 拿全连接层的作用效果,和卷积层做比较(来自cs231n)

提问时间

提问:在某一层当中,那些卷积核都是完全对称的吗?对称是指这些卷积核的维度相同,做同样的计算,它们有什么不同的地方吗?

除了它们有相同的参数值外,没什么不同。我们用一个滤波器,有5*5*3个参数值的滤波器,然后我们就以相同的方式滑动卷积核,滑过整个的输入部分,从而得到一张激活映射。

其他层

刚才深入到了很多细节当中,关于这些卷积层构造的细节当中。我们要简要的提及一下其他的各个层。这些层一起构成了整个卷积网络。我们有卷积层,每隔几个卷积层,就会有些池化层夹在中间,还有些非线性层。

Desktop View CNN网络架构(来自cs231n)

池化层

这些池化层所要做的是,要让所生成的表示更小且更容易控制,之前有谈到过这个,为什么我们要让所生成的表示尽量小,这是为了最后有更少的参数,这关系到最后我们得到的参数数量,并且基本上也会关系到给定区域内的不变性问题。关于池化层所要做的事只是在做降低采样率处理吗?对输入的全体也有效吗?比如说,对224*224*64的输入进行空间上的降采样处理,所以最后你得到的是一个112*112的结果,重要的一点是我们不会做在深度方向上的池化处理,而只是做平面上的,所以输入的深度和输出的深度是一样的。

Desktop View 池化层(来自cs231n)

举例来说,最常见的方法是最大池化法。在这个例子当中池化层也有一个卷积核的大小,而且卷积核的大小和我们所要池化处理的区域大小是相同的,在这个例子中如果我们使用2*2的滤波器,并在这里设定步长为2,让这个卷积核滑过整个输入部分,就像我们进行卷积时做的那样,不过我们不进行取数量积的计算,我们只提取其中的最大值,所在图像区域的输入的最大值。

Desktop View 最大池化(来自cs231n)

提问:这是否是通常的做法,就是设定步长,使它们不会互相重叠?

是的,对于池化层来说是这样的。我认为更通常的做法是让它们没有任何重叠,可以这样认为,我们希望进行降采样处理,对于给定的一个区域这样避免重叠的处理和只用一个数值来表示整个区域是有道理的。然后我们就接着看下一个区域,并且继续下去。

提问:为什么最大值池化要好于像均值池化之类的方式?

均值池化不是不能用,但最大值池化通常用的更多,因为它有类似这样的意义:我有一堆神经元的激活值在这,每个值都在一定程度上表示了在这个位置某个神经元的激发程度,或者是某组卷积核的激发程度,你可以把最大值池化看成这组卷积核在图像任意区域的受激程度的表示,所以需要做检测识别之类的任务,最大值池化是更直观的——不管你要从图片里找光线,还是其他类似的信息,不管在区域内什么地方,用一个最显著的最大值来激活它。

提问:不管是池化还是步长滑动都是在降采样,能不能只滑动步长而不池化,或者只池化不滑动步长呢?

实际上在实践中,在一些神经网络结构中,人们已经开始用滑动来代替池化去做降采样。我觉得可以把问题看成比例性的滑动,这么做可能会有稍微更好一些的结果,所以这么想是对的。

讲到池化层了。再说一遍,我们有多种选项,你得到容量为W*H*D的输入,然后设置超参数,选择卷积核的尺寸,或者池化的空间范围以及步长,然后计算输出的容量。公式跟前面一样,在这里仍然适用。把总的长度W减去卷积核尺寸,除以步长再加一。

Desktop View 计算输出的容量(来自cs231n)

有一点需要注意,一般不在池化层做填零,因为池化层只做降采样,这样就不会导致卷积核扫过边缘时有一部分超出了输入的范围,这样池化时就不需要担心这样的问题,所以就直接降采样。 池化层的典型设置是2*2的卷积核加步长2或者3*33,用2*2的池化器。你依然可以用2*2的池化器,也可以用3*3的卷积核。实践中2*2是常用设置。

Desktop View common setting(来自cs231n)

这样我们讲完了这些卷积层,ReLU层讲的和朴素神经网络一样,所以像这样分散池化来实现降采样。

全连接层

然后最后一件事就是,得到一个全连接层,跟我们之前看到的全连接层是一样的。在这里我们把卷积网络最后一层的输出,即一个固定尺寸的矩阵,我们知道它的长宽高,把这样的矩阵直接拉平,这样就获得了一组一维输入,与朴素神经网络相连,得到卷积网络最后的全连接层,即与每一个卷积图输出相连接的权重。现在可以这样理解,我们不再需要保全之前的空间结构了,而是在最后一层把所有内容汇聚在一起,我们想根据这些信息来得到一些结论。这样得到的就是,类似之前看到的那些分值一样的输出了。

Desktop View 全连接层(来自cs231n)

提问:最右边的16个像素点是什么?

就是说这一列怎么理解,比如这个pool,这里我们展示的是每一列都是激活映射的输出,某一层的输出。一开始我们有个车,经过卷积层得到的是每一个滑过输入图像的卷积核的激活映射,把激活映射送进ReLU得到一些这样的值,这么一直走走走,在池化层得到的就是前面ReLU层输出,拿到ReLU层的输出然后池化,这就做了降采样,取出所有卷积核对应位置上的最大值。如果看下这个池化层的输出,比如刚才说的最后那一列,看起来和ReLU层的输出一样,只是做了降采样和取了每个空间位置上的最大值,这就是两者之间细微的差别。

看起来好像仅仅取到了很少量的信息,那怎么根据这个来做区分?可以这么想,每一个池化层输出的值实际上是数据经过了整个网络处理后累积的结果,在最顶层每一个值都表示了上一阶的某个概念,就像之前看过的HubelWiesel,和类似的这些层级卷积核可以在最底层寻找边缘,或者一些简单的结构,经过卷积层你可以看到输出的第一列小图一般是某些特定的激活表征,比如边缘在图像各个位置的体现,越往后得到的是更复杂、更高层的表示。下一个卷积层则会表现出,比如图片中的一些边角区域,所有这些都有含义,输入不再是原始图片,而是之前的输出,比如边缘的表示图,它是在边缘图上进一步计算,来得到更复杂的内容,检测更复杂的任务。这样当你到达最后一个池化层的时候,每个值都代表了一组复合模板的激活情况,这样得到的全连接层把所有的信息聚合在一起得到一组分类的分值,每个值代表复合的复杂概念的受激程度。

提问:池化多少次才足以实现分类?

答案是试了才知道,在实践中这些都是我们的选项,需要稍微直觉上做一下思考。需要池化但也不能池化太多次,不然最后得到的图像的表征值就非常少,这就需要一些平衡。你要考虑大家已经试过的各种各样的配置,你要做交叉检验,尝试不同的池化大小、卷积核的大小、层的数量,来找到最能解决问题的配置。不同的问题,不同的数据对应的最优超参数也是不一样的。

总结

今天讲了卷积神经网络的工作原理,怎么把卷积和池化层堆叠起来,最后怎么与全连接层结合。小尺寸卷积核和更深的网络结构是一个趋势,后面会讲一些这方面的例子,还有一个趋势是完全弃用池化和全连接层,而保留卷积层形成非常深的卷积网络,这些以后会讲。

典型结构是什么样的呢?就像之前说的,卷积ReLU重复N次,每次做一个池化,如此反复,最后来到全连接ReLU层,像之前我们讲的加一层两层或者几层,最后用softmax得到你的类别分数,比如五类十类这样的。所以你把卷积ReLU采样序列和最后几个全连接层堆叠在一起,得到一个很深的卷积网络,不过后面我们会说到一些新的结构,比如ResNetGoogleNet使用了不同的结构,而不是这种套路。

Desktop View 课堂总结(来自cs231n)

本文由作者按照 CC BY 4.0 进行授权

© ManShouyuan. 保留部分权利。

本站总访问量 本站访客数人次

🚩🚩🚩🚩🚩🚩