1. 全连接神经网络的问题
图像识别问题本质上就是分类问题,比如我们要区分猫和狗,那么我们就需要构建一个模型,将照片丢进去后,模型能输出猫或者狗的概率有多大。在做图像识别时首要的就是要提取图片的特征,那么如何提取图片的特征呢?前面讲到了前向全连接网络,我们可以尝试用前向全连接网络提取。假设图片的像素是100*100,如果如片是彩色的,每个像素都有RGB三种颜色的数值。因此,一张图片是有一个三维向量构成的,一维是长100,一维是宽100,还有一维是R、G、B 3个通道(channels)。把这个三维向量拉直作为一个一维向量,长度就是100*100*3。
假设全连接网络的输入层有100个神经元,那么输入层的权值参数
w
w
w(Weight)的个数就等于
100
∗
100
∗
3
∗
100
=
3
×
1
0
6
100*100*3*100=3\times 10^6
100∗100∗3∗100=3×106这个参数量是巨大的,参数数目越多导致模型就越复杂,就更容易产生过拟合问题。另外参数量太大,也会导致计算量巨大。
采用前向全连接网络提取图片特征是不可取的,那么如何更加有效率地提取图片特征呢?前面提到了设计一个网络的架构,需要分析网络应用领域的专门知识,在这里我们就需要分析图片的特性。
2. 利用“感受野”看图片的局部
我们在区分一张图片时,我们观察的往往是图片的局部的、最重要的特征。 比如图片上是一只鸟,我们可能通过嘴巴、眼睛、爪子等就可以判断出是一只鸟了。因此,输入层的每一个神经元没有必要看图片的全局,只需要看一个局部就行了。
根据这个特性,我们就可以对网络进行简化了。一个神经元不看图片的全局,而是看图片的一个局部,我们将这个局部称为神经元的感受野(receptive field),比如下图所示的神经元感受野是3*3*3的,表示宽度、长度、通道数都是3。不同神经元的感受野可以存在重叠区域甚至是完全相同的,这个在于个人的设计,但是有一个常用的设计做法。
这个常用的设计做法如下图所示。所有神经元的感受野大小是一样的,且感受野包含图片的所有通道,比如下图所设计的感受野大小为3*3*3。这些感受野的排布方式如下:左上角的感受野向右滑动2个像素(当然也可以滑动1个像素,滑动的步长(stride) 时自定义的),形成一个新的感受野,这样两个感受野就有1个像素的宽度重叠,然后新的感受野再向右滑动2个像素,又形成了一个新的感受野,这样反复滑动并形成新的感受野,直到滑到图片的最右端,这时候感受野可能超出了图片的区域,对超出部分采取的策略是填0,称为“padding"。在完成了第一行滑行后,感受野在往下滑两个像素,然后重复上述过程,然后再下滑直到感受野到达图片低端,这样所有的感受野就可以覆盖整张图片了。比如图中图片的像素是6*6*3的,感受野大小为3*3*3,滑动步长为2,那么总共就会有9个感受野。假设每一个感受野有一个神经元进行观测,那么就会有9个神经元,每个神经元的参数是9个权值加1个偏置,那么就总共有90参数。
3. 神经元的参数共享
在两张不同的图片上,同一个特征区域可能处于不同位置。 比如鸟嘴的局部特征区域在下面这两张图上就处在不同的位置上。那么如何才能让两个不同的神经元在看到这两个不同的感受野时,能产生一致的特征值呢?
一个较好的办法就是参数共享,即这两个神经元的参数设置成一样的,如下图所示两个不同感受野的神经元的参数是一样的。这两个神经元的参数一样不代表输出也会一样,因为不同的感受野输入的值是不一样的。
前面讲到通过滑动的方式排布的感受野可以覆盖整个图片,假设每一个感受野有一个神经元进行观测,我们让所有的神经元参数共享。这样就相当于一个神经元每次只看一个局部,但是通过滑动扫描的方式将所有局部看了一遍,就等于把图片的整体看了一遍,这是合理的。参数共享之后参数的数量和神经元(感受野)的个数无关了,只和感受野的大小有关,比如针对6*6*3的图片,尽管通过滑动有9个感受野,对应9个神经元,但是这些神经元的参数是一样的,因此参数的个数就只有9个权值加1个偏置。
可以看出,通过局部感受野和参数共享的简化方式,参数的量已经大幅缩减了。但是还存在一个问题,一个神经元可能指对某个或某部分局部特征比较敏感,比如说只对鸟嘴比较敏感,而对鸟抓不敏感,那么就可能会丢失一些特征。那么如何做呢?一个办法是让多个神经元观测同一个感受野,这些神经元是不共享参数的。这样有的神经元可能对鸟嘴比较敏感,而有的神经元对鸟爪比较敏感。至于每个感受野设置多少个不同的神经元,是个人决定的。
4. 对CNN的总结
对上面的内容进行一个总结:
(1)我们设置一个局部感受野,假设感受野的大小为W*H*C,其中W表示感受野的宽度,H表示感受野的高度,C表示感受野的通道数。那么对应的神经元的参数的个数就为:W*H*C个权值加1个偏置。在卷积神经网络中,我们称这样一个神经元为一个滤波器(filter)。
(3)我们通过滑动的方式让感受野铺满整个图片,假设图片的尺寸是W1*H1*C,滑动步长为S,零填充的数量为P。假设感受野的个数是W2*H2,其中,
W
2
=
(
W
1
−
W
+
2
P
)
/
S
+
1
W2=(W1-W+2P)/S+1
W2=(W1−W+2P)/S+1
H
2
=
(
H
1
−
H
+
2
P
)
/
S
+
1
H2=(H1-H+2P)/S+1
H2=(H1−H+2P)/S+1
(4)我们让所有感受野的观测滤波器参数进行共享,即相当于一个滤波器通过滑动扫描的方式扫描了所有感受野。
(5)我们设置多个滤波器,假设滤波器的个数为K,这K个滤波器都通过滑动扫描的方式扫过整个图片。此时参数的个数为:(W*H*C+1)*K。
(6)由于每个滤波器每经过一个感受野都会进行一次计算输出一个值,所以输出的维度为:W2*H2*K。我们将这个输出称为特征图,所以特征图宽度为W2,高度为H2,通道数C2=K。
举个例子: 假设某个图片的大小是100*100*3,设置滤波器的大小为3*3*3,滤波器的个数为64,设置步长S=1,设置零填充的数量为P=0。那么卷积神经网络的参数为,
(
3
×
3
+
1
)
×
64
=
640
(3\times3+1)\times64=640
(3×3+1)×64=640相比前向全连接
3
×
1
0
6
3\times 10^6
3×106个参数,参数的个数缩小了几个数量级。
输出特征图的宽度和高度均为,
W
2
=
H
2
=
(
100
−
3
+
0
)
/
1
+
1
=
98
W2=H2=(100-3+0)/1+1=98
W2=H2=(100−3+0)/1+1=98输出特征图的通道数为,
C
2
=
64
C2=64
C2=64所以输出特征图的维度为98*98*64。
如果在上面输出的基础上再叠加一层卷积神经网络,滤波器的设置宽和高可以不变,但是通道数不再是3了,而是变成64了,因为输入特征图的通道数已经变64了。假设滤波器的大小为3*3*64,滤波器的个数为32,设置步长S=1,设置零填充的数量为P=0。可以计算出来,新的输出特征图的维度是96*96*32。
5. CNN的应用
以上就是卷积神经网络(CNN)的解析。但是CNN一般不是单独用的,因为一般提取图片的特征是为了分类,还需要进一步处理,常见的形式如下图所示。
其中Pooling的目的是下采样,以减小特征图的维度。具体的做法是在一个局部区域只取其中一个像素,其他像素都丢弃。比如在一个3*3的局部区域内取最大值,其他值均丢弃,这就是MaxPooling。其中Flatten是拉直,将3维的向量拉成一维向量,然后将这个一维向量输入到一个前向全连接层,以对图片的特征进行高层的融合。最后通过一个softmax层进行分类。