本小节主要围绕卷积神经网络,典型结构,卷积核,卷积神经网络的特性和类型展开介绍。
卷积神经网络(CNN,Convolutional Neural Net)是神经网络的类型之一,在图像识别和分类领域中取得了非常好的效果,比如识别人脸、物体、交通标识等,这就为机器人、自动驾驶等应用提供了坚实的技术基础。
在下面图 2.7.1$^{[11]}$ 和图 2.7.2$^{[11]}$ 中,卷积神经网络展现了识别人类日常生活中的各种物体的能力。
图 2.7.1 识别出四个人在一条船上
图 2.7.2 识别出当前场景为“两个骑车人”
一个典型的卷积神经网络的结构如图 2.7.3 所示。
图 2.7.3 卷积神经网络的典型结构图
我们分析一下它的层级结构:
- 原始的输入是一张图片,可以是彩色的,也可以是灰度的或黑白的。这里假设是只有一个通道的图片,目的是识别0~9的手写体数字;
- 第一层卷积,我们使用了4个卷积核,得到了4张feature map;激活函数层没有单独画出来,这里我们紧接着卷积操作使用了Relu激活函数;
- 第二层是池化,使用了Max Pooling方式,把图片的高宽各缩小一倍,但仍然是4个feature map;
- 第三层卷积,我们使用了4x6个卷积核,其中4对应着输入通道,6对应着输出通道,从而得到了6张feature map,当然也使用了Relu激活函数;
- 第四层再次做一次池化,现在得到的图片尺寸只是原始尺寸的四分之一左右;
- 第五层把第四层的6个图片展平成一维,成为一个fully connected层;
- 第六层再接一个小一些的fully connected层;
- 最后接一个softmax函数,判别10个分类。
所以,在一个典型的卷积神经网络中,会至少包含以下几个层:
- 卷积层
- 激活函数层
- 池化层
- 全连接分类层
我们会在后续的小节中讲解卷积层和池化层的具体工作原理。
我们遇到了一个新的概念:卷积核。卷积网络之所以能工作,完全是卷积核的功劳。什么是卷积核呢?卷积核其实就是一个小矩阵,类似这样:
1.1 0.23 -0.45
0.1 -2.1 1.24
0.74 -1.32 0.01
这是一个3x3的卷积核,还会有1x1、5x5、7x7、9x9、11x11的卷积核。在卷积层中,我们会用输入数据与卷积核相乘,得到输出数据,就类似全连接层中的Weights一样,所以卷积核里的数值,也是通过反向传播的方法学习到的。
下面我们看看卷积核的具体作用。
图 2.7.4 卷积核的作用
图 2.7.4 中所示的内容,是使用9个不同的卷积核在同一张图上运算后得到的结果,而表 2.7.1 中按顺序列出了9个卷积核的数值和名称,可以一一对应到上面的9张图中。
表 2.7.1 卷积的效果
1 | 2 | 3 | |
---|---|---|---|
1 | 0,-1, 0 -1, 5,-1 0,-1, 0 |
0, 0, 0 -1, 2,-1 0, 0, 0 |
1, 1, 1 1,-9, 1 1, 1, 1 |
锐化 | 检测竖边 | 周边检测 | |
2 | -1,-2, -1 0, 0, 0 1, 2, 1 |
0, 0, 0 0, 1, 0 0, 0, 0 |
0,-1, 0 0, 2, 0 0,-1, 0 |
纵向亮度差分 | 原始图片 | 横边检测 | |
3 | 0.11,0.11,0.11 0.11,0.11,0.11 0.11,0.11,0.11 |
-1, 0, 1 -2, 0, 2 -1, 0, 1 |
2, 0, 0 0,-1, 0 0, 0,-1 |
模糊 | 横向亮度差分 | 浮雕 |
我们先说中间那个图,就是第5个卷积核,叫做"nothing"。为什么叫nothing呢?因为这个卷积核在与原始图片计算后得到的结果,和原始图片一模一样,所以我们看到的图5就是相当于原始图片,放在中间是为了方便和其它卷积核的效果做对比。
前面我们认识到了卷积核的强大能力,卷积神经网络通过反向传播而令卷积核自我学习,找到分布在图片中的不同的feature,最后形成的卷积核中的数据。但是如果想达到这种效果,只有卷积层的话是不够的,还需要激活函数、池化等操作的配合。
图 2.7.5 中的四个子图,依次展示了:
- 原图
- 卷积结果
- 激活结果
- 池化结果
图 2.7.5 原图经过卷积-激活-池化操作后的效果
- 注意图一是原始图片,用cv2读取出来的图片,其顺序是反向的,即:
- 第一维是高度
- 第二维是宽度
- 第三维是彩色通道数,但是其顺序为BGR,而不是常用的RGB
-
我们对原始图片使用了一个3x1x3x3的卷积核,因为原始图片为彩色图片,所以第一个维度是3,对应RGB三个彩色通道;我们希望只输出一张feature map,以便于说明,所以第二维是1;我们使用了3x3的卷积核,用的是sobel x算子。所以图二是卷积后的结果。
-
图三做了一层Relu激活计算,把小于0的值都去掉了,只留下了一些边的特征。
-
图四是图三的四分之一大小,虽然图片缩小了,但是特征都没有丢失,反而因为图像尺寸变小而变得密集,亮点的密度要比图三大而粗。
从整体图中,可以看到在卷积-池化等一些列操作的后面,要接全连接层,这里的全连接层和我们在前面学习的深度网络的功能一模一样,都是做为分类层使用。
在最后一层的池化后面,把所有特征数据变成一个一维的全连接层,然后就和普通的深度全连接网络一样了,通过在最后一层的softmax分类函数,以及多分类交叉熵函数,对比图片的OneHot编码标签,回传误差值,从全连接层传回到池化层,通过激活函数层再回传给卷积层,对卷积核的数值进行梯度更新,实现卷积核数值的自我学习。
但是这里有个问题,回忆一下MNIST数据集,所有的样本数据都是处于28x28方形区域的中间地带,如图 2.7.6 中的左上角的图片A所示。
图 2.7.6 同一个背景下数字8的大小、位置、形状的不同
我们的问题是:
- 如果这个“8”的位置很大地偏移到了右下角,使得左侧留出来一大片空白,即发生了平移,如上图右上角子图B
- “8”做了一些旋转或者翻转,即发生了旋转视角,如上图左下角子图C
- “8”缩小了很多或放大了很多,即发生了尺寸变化,如上图右下角子图D
尽管发生了变化,但是对于人类的视觉系统来说都可以轻松应对,即平移不变性、旋转视角不变性、尺度不变性。那么卷积神经网络网络如何处理呢?
-
平移不变性
对于原始图A,平移后得到图B,对于同一个卷积核来说,都会得到相同的特征,这就是卷积核的权值共享。但是特征处于不同的位置,由于距离差距较大,即使经过多层池化后,也不能处于近似的位置。此时,后续的全连接层会通过权重值的调整,把这两个相同的特征看作同一类的分类标准之一。如果是小距离的平移,通过池化层就可以处理了。
-
旋转不变性
对于原始图A,有小角度的旋转得到C,卷积层在A图上得到特征a,在C图上得到特征c,可以想象a与c的位置间的距离不是很远,在经过两层池化以后,基本可以重合。所以卷积网络对于小角度旋转是可以容忍的,但是对于较大的旋转,需要使用数据增强来增加训练样本。一个极端的例子是当6旋转90度时,谁也不能确定它到底是6还是9。
-
尺度不变性
对于原始图A和缩小的图D,人类可以毫不费力地辨别出它们是同一个东西。池化在这里是不是有帮助呢?没有!因为神经网络对A做池化的同时,也会用相同的方法对D做池化,这样池化的次数一致,最终D还是比A小。如果我们有多个卷积视野,相当于从两米远的地方看图A,从一米远的地方看图D,那么A和D就可以很相近似了。这就是Inception的想法,用不同尺寸的卷积核去同时寻找同一张图片上的特征。
二维卷积一般用于图像处理上。在二维图片上做卷积,如果把图像Image简写为$I$,把卷积核Kernal简写为$K$,则目标图片的第$(i,j)$个像素的卷积值为:
在图像处理中,自相关函数和互相关函数定义如下:
- 自相关:设原函数是f(t),则$h=f(t) \star f(-t)$,其中$\star$表示卷积
- 互相关:设两个函数分别是f(t)和g(t),则$h=f(t) \star g(-t)$
互相关函数的运算,是两个序列滑动相乘,两个序列都不翻转。卷积运算也是滑动相乘,但是其中一个序列需要先翻转,再相乘。所以,从数学意义上说,机器学习实现的是互相关函数,而不是原始含义上的卷积。但我们为了简化,把公式5也称作为卷积。这就是卷积的来源。
结论:
- 我们实现的卷积操作不是原始数学含义的卷积,而是工程上的卷积,可以简称为卷积
- 在实现卷积操作时,并不会反转卷积核
在传统的图像处理中,卷积操作多用来进行滤波,锐化或者边缘检测啥的。我们可以认为卷积是利用某些设计好的参数组合(卷积核)去提取图像空域上相邻的信息。
按照公式,我们可以在4x4的图片上,用一个3x3的卷积核,通过卷积运算得到一个2x2的图片,运算的过程如图 2.7.7 所示。
图 2.7.7 卷积运算的过程
原始输入是一维的图片,但是我们可以用多个卷积核分别对其计算,从而得到多个特征输出。如图 2.7.8 所示。
图 2.7.8 单入多出的升维卷积
一张4x4的图片,用两个卷积核并行地处理,输出为2个2x2的图片。在训练过程中,这两个卷积核会完成不同的特征学习。
一张图片,通常是彩色的,具有红绿蓝三个通道。我们可以有两个选择来处理:
- 变成灰度的,每个像素只剩下一个值,就可以用二维卷积
- 对于三个通道,每个通道都使用一个卷积核,分别处理红绿蓝三种颜色的信息
显然第2种方法可以从图中学习到更多的特征,于是出现了三维卷积,即有三个卷积核分别对应书的三个通道,三个子核的尺寸是一样的,比如都是2x2,这样的话,这三个卷积核就是一个3x2x2的立体核,称为过滤器Filter,所以称为三维卷积。
图 2.7.9 多入单出的降维卷积
在上图中,每一个卷积核对应着左侧相同颜色的输入通道,三个过滤器的值并不一定相同。对三个通道各自做卷积后,得到右侧的三张特征图,然后再按照原始值不加权地相加在一起,得到最右侧的白色特征图,这张图里面已经把三种颜色的特征混在一起了,所以画成了白色,表示没有颜色特征了。
虽然输入图片是多个通道的,或者说是三维的,但是在相同数量的过滤器的计算后,相加在一起的结果是一个通道,即2维数据,所以称为降维。这当然简化了对多通道数据的计算难度,但同时也会损失多通道数据自带的颜色信息。
在上面的例子中,是一个过滤器Filter内含三个卷积核Kernal。我们假设有一个彩色图片为3x3的,如果有两组3x2x2的卷积核的话,会做什么样的卷积计算?看图 2.7.10。
图 2.7.10 多入多出的卷积运算
第一个过滤器Filter-1为棕色所示,它有三卷积核(Kernal),命名为Kernal-1,Keanrl-2,Kernal-3,分别在红绿蓝三个输入通道上进行卷积操作,生成三个2x2的输出Feature-1,n。然后三个Feature-1,n相加,并再加上b1偏移值,形成最后的棕色输出Result-1。
对于灰色的过滤器Filter-2也是一样,先生成三个Feature-2,n,然后相加再加b2,最后得到Result-2。
之所以Feature-m,n还用红绿蓝三色表示,是因为在此时,它们还保留着红绿蓝三种色彩的各自的信息,一旦相加后得到Result,这种信息就丢失了。
前面的例子中,每次计算后,卷积核会向右或者向下移动一个单元,即步长stride = 1。而在图 2.7.11 这个卷积操作中,卷积核每次向右或向下移动两个单元,即stride = 2。
图 2.7.11 步长为2的卷积
在后续的步骤中,由于每次移动两格,所以最终得到一个2x2的图片。
如果原始图为4x4,用3x3的卷积核进行卷积后,目标图片变成了2x2。如果我们想保持目标图片和原始图片为同样大小,该怎么办呢?一般我们会向原始图片周围填充一圈0,然后再做卷积。如图 2.7.12。
图 2.7.12 带填充的卷积
综合以上所有情况,可以得到卷积后的输出图片的大小的公式:
以图 2.7.11 为例:
以图 2.7.12 为例:
两点注意:
- 一般情况下,我们用正方形的卷积核,且为奇数
- 如果计算出的输出图片尺寸为小数,则取整,不做四舍五入
下面我们会用一个简单的例子来说明卷积核的训练过程。我们先制作一张样本图片,然后使用“横边检测”算子做为卷积核对该样本进行卷积,得到对比如图 2.7.13。
图 2.7.13 原图和经过横边检测算子的卷积结果
左侧为原始图片(80x80的灰度图),右侧为经过3x3的卷积后的结果图片(78x78的灰度图)。由于算子是横边检测,所以只保留了原始图片中的横边。
卷积核矩阵:
现在我们转换一下问题:假设我们有一张原始图片(如左侧)和一张目标图片(如右侧),我们如何得到对应的卷积核呢?
我们在前面学习了线性拟合的解决方案,实际上这个问题是同一种性质的,只不过把直线拟合点阵的问题,变成了图像拟合图像的问题,如表 2.7.2 所示。
表 2.7.2 直线拟合与图像拟合的比较
样本数据 | 标签数据 | 预测数据 | 公式 | 损失函数 | |
---|---|---|---|---|---|
直线拟合 | 样本点x | 标签值y | 预测直线z | 均方差 | |
图片拟合 | 原始图片x | 目标图片y | 预测图片z | 均方差 |
直线拟合中的均方差,是计算预测值与样本点之间的距离;图片拟合中的均方差,可以直接计算两张图片对应的像素点之间的差值。
为了简化问题,我们令b=0,只求卷积核w的值,则前向公式为:
反向求解w的梯度公式(从公式11得到):
即
训练部分的代码实现如下:
def train(x, w, b, y):
output = create_zero_array(x, w)
for i in range(10000):
# forward
jit_conv_2d(x, w, b, output)
# loss
t1 = (output - y)
m = t1.shape[0]*t1.shape[1]
LOSS = np.multiply(t1, t1)
loss = np.sum(LOSS)/2/m
print(i,loss)
if loss < 1e-7:
break
# delta
delta = output - y
# backward
dw = np.zeros(w.shape)
jit_conv_2d(x, delta, b, dw)
w = w - 0.5 * dw/m
#end for
return w
一共迭代10000次:
- 用jit_conv_2d(x,w...)做一次前向计算
- 计算loss值以便检测停止条件,当loss值小于1e-7时停止迭代
- 然后计算delta值
- 再用jit_conv_2d(x,delta)做一次反向计算,得到w的梯度
- 最后更新卷积核w的值
运行结果:
......
3458 1.0063169744079507e-07
3459 1.0031151142628902e-07
3460 9.999234418532805e-08
w_true:
[[ 0 -1 0]
[ 0 2 0]
[ 0 -1 0]]
w_result:
[[-1.86879237e-03 -9.97261724e-01 -1.01212359e-03]
[ 2.58961697e-03 1.99494606e+00 2.74435794e-03]
[-8.67754199e-04 -9.97404263e-01 -1.87580756e-03]]
w allclose: True
y allclose: True
当迭代到3460次的时候,loss值小于1e-7,迭代停止。比较w_true和w_result的值,两者非常接近。用numpy.allclose()方法比较真实卷积核和训练出来的卷积核的值,结果为True。比如-1.86879237e-03,接近于0;-9.97261724e-01,接近于-1。
再比较卷积结果,当然也会非常接近,误差很小,allclose结果为True。用图示方法显示卷积结果比较如图 2.7.14。
图 2.7.14 真实值和训练值的卷积结果区别
人眼是看不出什么差异来的。由此我们可以直观地理解到卷积核的训练过程并不复杂。
本小节主要介绍了卷积神经网络,典型结构,卷积核,卷积神经网络的特性和类型。
请读者思考如何将卷积转换为 for 循环运算?
-
《智能之门》,胡晓武等著,高等教育出版社
-
Duchi, J., Hazan, E., & Singer, Y. (2011). Adaptive subgradient methods for online learning and stochastic optimization. Journal of Machine Learning Research, 12(Jul), 2121-2159.
-
Zeiler, M. D. (2012). ADADELTA: an adaptive learning rate method. arXiv preprint arXiv:1212.5701.
-
Tieleman, T., & Hinton, G. (2012). Lecture 6.5-rmsprop: Divide the gradient by a running average of its recent magnitude. COURSERA: Neural networks for machine learning, 4(2), 26-31.
-
Kingma, D. P., & Ba, J. (2014). Adam: A method for stochastic optimization. arXiv preprint arXiv:1412.6980.
-
周志华老师的西瓜书《机器学习》
-
Chawla N V, Bowyer K W, Hall L O, et al. SMOTE: synthetic minority over-sampling technique[J]. Journal of Artificial Intelligence Research, 2002, 16(1):321-357.
-
Inoue H. Data Augmentation by Pairing Samples for Images Classification[J]. 2018.
-
Zhang H, Cisse M, Dauphin Y N, et al. mixup: Beyond Empirical Risk Minimization[J]. 2017.
-
《深度学习》- 伊恩·古德费洛
-
Shaoqing Ren, Kaiming He, Ross Girshick, and Jian Sun, Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks. Link: https://arxiv.org/pdf/1506.01497v3.pdf