深度学习笔记(三)卷积神经网络对照CAFFE
1. 结构概诉
常规神经网络回顾:神经网络的输入是一个向量,然后在一系列的隐含层中对它做变换(卷积+激活函数)。每个隐含层都是由若干的神经元组成,每个神经元都与前一层中的所有神经元连接。但是在一个隐含层中,神经元相互独立不进行任何连接。最后的全连接层被称为 ”输出层“,在分类问题中,它输出的值被看作是不同类别的评分值。
与常规神经网络不同,卷积神经网络的各层中的神经元是3维排列的:宽度 $W$、高度$H$和深度$D$(这里的深度是指激活数据体的第三个维度,而不是整个网络的深度,整个网络的深度指的是网络的层数)。举个例子,CIFAR-10中的图像是作为卷积神经网络的输入,该数据体的维度是32x32x3(宽度,高度和深度)。我们将看到,层中的神经元将只与前一层中一小块区域连接,而不是采取全连接方式。对于用来分类CIFAR-10中的图像的卷积网络,其最后的输出层的维度是1x1x10,因为在卷积神经网络结构的最后部分将会把全尺寸的图像压缩为包含分类评分的一个向量,向量是在深度方向排列的。下面是例子:
左边是一个3层的常规神经网络。右边是一个卷积神经网络,图中网络将它的神经元都排列成3个维度(宽、高和深度)。卷积神经网络的每一层都将3D的输入数据变化为神经元3D的激活数据并输出。在这个例子中,红色的输入层装的是图像,所以它的宽度和高度就是图像的宽度和高度,它的深度是3(代表了红、绿、蓝3种颜色通道)。
一个用于分类的卷积神经网络的结构可以是[输入层-卷积层-激励层-池化层-全连接层-损失计算层]的组合。
2. 数据层Data
layer { name: "data" type: "Data" top: "data" top: "label" transform_param { scale: 0.00390625 # 归一化 #mean_file: "imagenet_mean.binaryproto" # 均值文件 #crop_size: 224 # 裁剪尺寸 mean_value: 104 #三个通道的均值 mean_value: 117 mean_value: 123 mirror: true # 是否随机镜像 } data_param { source: "C:/caffe-master/data/test/train_leveldb" # 数据路径 batch_size: 60 backend: LEVELDB # 数据类型 } }
数据层主要涉及数据层的一些预处理操作。
3. 卷积层Convolution
layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 64 kernel_size: 3 # 卷积核大小 pad: 1 # 零填充 stride: 1 weight_filler { type: "xavier" # 权重初始化方式 } bias_filler { type: "constant" # 偏置初始化方式 } } }
卷积层的参数是由一些可学习的滤波器集合构成的。每个滤波器在空间上(宽度和高度)都比较小,但深度和输入数据一致。举例来说,卷积神经网络的第一层的一个典型滤波器的尺寸可以是 $5*5*3$ (宽高都是5像素,深度是3是因为图像应为颜色通道,所以有3的深度)。在前向传播的时候,让每个滤波器都在输入数据的宽度和高度上滑动,然后计算整个滤波器和输入数据任一处的内积(更精确地说是卷积)。当滤波器沿着输入数据的宽度和高度滑过后,会生成一个2维激活图(activation map),激活图给出了数据在每个空间位置处滤波器的反应。直观地来说,网络会让滤波器学习到当它看到某些类型的视觉特征时就激活,具体的视觉特征可能是某些方位上的边界,或者某些颜色的斑点,,甚至可以是网络更高层上的蜂巢状或者车轮状图案。
在每个卷积层上,我们会有一整个集合的滤波器(比如12个),每个都会生成一个不同的二维激活图。将这些激活映射在深度方向上层叠起来就生成了输出数据。
局部连接
与常规神经网络一样,输入层的神经元需要和隐含层的神经元连接。但是这里不是将每一个输入神经元都与每一个隐含神经元连接,而是仅仅在一个图像的局部区域创建连接。该连接的空间大小叫做神经元的局部感知域(receptive field),它的尺寸是一个超参数(其实就是滤波器的空间尺寸)。
在深度方向上,这个连接的大小总是和输入量的深度相等。
例:假设输入数据体尺寸为[32x32x3](比如CIFAR-10的RGB图像),如果感知域(或滤波器尺寸)是5x5,该局部感知域的5x5个神经元与一个隐藏层的同一个神经元连接,每个连接上有一个权重参数,那么共5x5x3=75个权重(还要加一个偏差参数)。如果将局部感知域沿着从左往右,从上往下的顺序滑动,就会得对应隐藏层中不同的神经元。注意这个连接在深度维度上的大小必须为3,和输入数据体的深度一致。
空间排列
接下来我们将讨论输出数据体中神经元的数量,以及他们的排列方式。存在3个超参数控制着输出数据体的尺寸:深度(depth),步长(stride)和零填充(zero-padding)。
- 输出数据体的深度和它使用的滤波器的数量一致,而每个滤波器在输入数据中寻找一些不同的东西。举例来说,如果第一个卷积层的输入是原始图像,那么在深度维度上的不同神经元将可能被不同方向的边界,或者是颜色斑点激活。我们将这些沿着深度方向排列、感知域大小相同的神经元集合称为深度列(depth column)。
- 其次,在滑动滤波器的时候,必须指定步长。当步长为1,滤波器每次移动1个像素。
- 有时候将输入数据体用 0 在边缘处进行填充是很必要的,这个零填充(zero-padding)的尺寸是一个超参数。零填充有一个良好性质,可以控制输出数据体的空间尺寸(最常用的是用来保持输入数据体在空间上的尺寸,这样输入和输出的宽高都相等)。
输出数据体在空间上的尺寸可以通过输入数据体尺寸 $W$,卷积层中神经元的感知域尺寸 $F$,步长 $S$ 和零填充的数量 $P$ 的函数来计算:
$\frac{W-F+2P}{S}+1$
在设计网络的时候,我们要合理的配置输出数据体的尺寸(使上式结果为整数),使用零填充和遵守其他一些设计策略将会有效解决这个问题。
真实案例:Krizhevsky构架赢得了2012年的ImageNet挑战,其输入图像的尺寸是[227x227x3]。在第一个卷积层,神经元使用的感受野尺寸,步长,不使用零填充。因为(227-11)/4+1=55,卷积层的深度,则卷积层的输出数据体尺寸为[55x55x96]。55x55x96个神经元中,每个都和输入数据体中一个尺寸为[11x11x3]的区域全连接。在深度列上的96个神经元都是与输入数据体中同一个[11x11x3]区域连接,但是权重不同。
注意:在caffe中我们发现上面的除法在卷积时除不尽,按往小取整;池化时除不尽,按往大取整。例如:
输入:100(batch_size) 3(三通道) 128*128 卷积: convolution_param { num_output: 128 pad: 3 kernel_size: 7 stride: 2 输出:100 128 64 64 池化: pool: MAX kernel_size: 3 stride: 2 输出:100 128 32 32
权重共享
我们在卷积神经网络中通过使用参数共享来控制参数的数量。就用上面的例子,在第一个卷积层就有55x55x96=290,400个神经元,每个有11x11x3=364个参数和1个偏差。将这些合起来就是290400x364=105,705,600个参数。单单第一层就有这么多参数,显然这个数目是非常大的。
作一个合理的假设:如果一个特征在计算某个空间位置 $(x,y)$ 的时候有用,那么它在计算另一个不同位置 $(x_2,y_2)$ 的时候也有用。基于这个假设,可以显著地减少参数的数量。换而言之,就是将深度维度上一个单独的二维切片看作深度切片(depth slice)。比如一个尺寸为55 x55 x96的数据体就有96个切片,每个尺寸为55 x55。在每个深度切片上都使用同样的权重和偏差,这样上式中就只有96个不同的权重集了,共96 x(11 x11 x3)个权重和96个偏差。
注意,如果在一个深度切片中的所有权重都使用同一个权重向量,那么卷积层的前向传播在每个深度切片中可以看做是在计算神经元权重和输入数据体的卷积(这就是“卷积层”名字由来)。这也是为什么总是将这些权重集合称为滤波器(filter)(或卷积核(kernel)),因为它们和输入进行了卷积。
小结
我们总结一下卷积层的性质:
输入数据体的尺寸为$W_1\times{H_1}\times{D_1}$
4个超参数:滤波器的数量$K$, 滤波器的空间尺寸$F$, 步长$S$,零填充数量$P$
输出数据体的尺寸为$W_2\times{H_2}\times{D_2}$, 其中:
$W_2=\frac{W_1-F+2P}{S}+1$ $D_2=K$
(宽度和高度的计算方法相同)
由于参数共享,每个滤波器包含$F\times{F}\times{D_1}$个权重,卷积层一共有$F\times{F}\times{D_1}\times{K}$个权重和$K$个偏置。
在输出数据体中,第$d$个深度切片(空间尺寸是$W_2\times{H_2}$),是用第$d$个滤波器和输入数据体进行有效卷积运算的结果(使用步长$S$),最后再加上第$d$个偏置。
4. 激励层
layer { name: "relu1" type: "ReLU" bottom: "conv1" top: "conv1" }
常见的激励层有 ReLU,SIGMOID,TANH函数。
5. 池化层Pooling
layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } }
池化层通常紧随卷积层之后使用,其作用是简化卷积层的输出。例如,池化层中的每一个神经元可能将前一层的一个2X2区域内的神经元求和。而另一个经常使用的max-pooling,该池化单元简单地将一个2X2的输入域中的最大激励输出,除此还可以使用L-2范式池化(L2-norm pooling)。
池化层在输入数据体的每个深度切片上,独立地对其进行空间上的降采样。左边:本例中,输入数据体尺寸为[224*224*64]被降采样成了[112x112x64], 采样的滤波器尺寸是2,步长为2,而深度不变。右边:最常用的降采样操作是取最大值,也就是最大池化,这里步长为2,每个取最大值操作是从4个数字中选取(即2x2的方块区域中)。
6. 全连接层InnerProduct
layer {
name: "ip1"
type: "InnerProduct"
bottom: " pool1"
top: " ip1"
inner_product_param {
num_output: 136
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
在全连接层中,神经元对于前一层中所有激活数据是全部连接的,这和常规神经网络中一样,它们的计算可以先用矩阵乘法,再加上偏差。
全连接层和卷积层之间唯一的不同就是卷积层中神经元只与输入数据中的一个局部区域连接,并且在卷积列中的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的。
7. 损失计算层
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip1"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer{
name: "loss"
type: "EuclideanLoss"
bottom: "ip1"
bottom: "label"
top: "loss"
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip1"
bottom: "label"
top: "loss"
}
常用的损失计算层有SOFTMAX_LOSS,EUCLIDEAN_LOSS,HINGE_LOSS,ACCURACY正确率。
8. 其他层
除此之外常用的还有CONCAT结合层,常用的数据格式是LEVELDB 和LMDB。
批量归一化层:caffe官方将BN层拆成两个层来实验,一个是https://github.com/BVLC/caffe/blob/master/include/caffe/layers/batch_norm_layer.hpp,
另外一个是https://github.com/BVLC/caffe/blob/master/include/caffe/layers/scale_layer.hpp。
其具体使用方法可以参考:https://github.com/KaimingHe/deep-residual-networks/blob/master/prototxt/ResNet-50-deploy.prototxt 中的BatchNorm与Scale。
9. 卷积神经网络结构
卷积神经网络通常是由三种层构成:卷积层,池化层和全连接层(FC)。ReLU激活函数层也应该算是一层,它逐元素地进行激活函数操作。
层的排列规律:卷积神经网络最常见的形式就是将一些卷积层和ReLU层放在一起,其后紧跟池化层,然后重复如此直到图像在空间上被缩小到一个足够小的尺寸,在某个地方过渡成全连接层也较为常见。最后的全连接层得到输出,比如分类评分等。最常见的卷积神经网络结构如下:
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中* 指的是重复次数,POOL?指的是一个可选的汇聚层。其中N >=0,通常N<=3,M>=0,K>=0,通常K<3。
最新进展:传统的将层按照线性进行排列的方法已经受到了挑战,挑战来自谷歌的Inception结构和微软亚洲研究院的残差网络(Residual Net)结构。这两个网络(下文案例学习小节中有细节)的特征更加复杂,连接结构也不同。
10. 案列学习
- LeNet:最著名的就是被应用在识别数字和邮政编码等的LeNet结构了。
- AlexNet:这个网络的结构和LeNet非常类似,但是更深更大,并且使用了层叠的卷积层来获取特征(之前通常是只用一个卷积层并且在其后马上跟着一个汇聚层)。
- GoogLeNet:它主要的贡献就是实现了一个奠基模块,它能够显著地减少网络中参数的数量(AlexNet中有60M,该网络中只有4M)。还有,这个论文中没有使用卷积神经网络顶部使用全连接层,而是使用了一个平均汇聚,把大量不是很重要的参数都去除掉了。GooLeNet还有几种改进的版本,最新的一个是Inception-v4。
- VGGNet:它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了16个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是3x3的卷积和2x2的汇聚。他们的预训练模型是可以在网络上获得并在Caffe中使用的。VGGNet不好的一点是它耗费更多计算资源,并且使用了更多的参数,导致更多的内存占用(140M)。其中绝大多数的参数都是来自于第一个全连接层。后来发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。
- ResNet:残差网络(Residual Network)是ILSVRC2015的胜利者,由何恺明等实现。它使用了特殊的跳跃链接,大量使用了批量归一化(batch normalization)。这个结构同样在最后没有使用全连接层。读者可以查看何恺明的的演讲(视频,PPT),以及一些使用Torch重现网络的实验。ResNet当前最好的卷积神经网络模型(2016年五月)。何开明等最近的工作是对原始结构做一些优化,可以看论文Identity Mappings in Deep Residual Networks,2016年3月发表。