Skip to content

Latest commit

 

History

History
425 lines (266 loc) · 20.2 KB

2.7-卷积神经网络.md

File metadata and controls

425 lines (266 loc) · 20.2 KB

2.7 卷积神经网络

本小节主要围绕卷积神经网络,典型结构,卷积核,卷积神经网络的特性和类型展开介绍。

2.7.1 卷积神经网络的能力

卷积神经网络(CNN,Convolutional Neural Net)是神经网络的类型之一,在图像识别和分类领域中取得了非常好的效果,比如识别人脸、物体、交通标识等,这就为机器人、自动驾驶等应用提供了坚实的技术基础。

在下面图 2.7.1$^{[11]}$ 和图 2.7.2$^{[11]}$ 中,卷积神经网络展现了识别人类日常生活中的各种物体的能力。

图 2.7.1 识别出四个人在一条船上

图 2.7.2 识别出当前场景为“两个骑车人”

2.7.2 卷积神经网络的典型结构

一个典型的卷积神经网络的结构如图 2.7.3 所示。

图 2.7.3 卷积神经网络的典型结构图

我们分析一下它的层级结构:

  1. 原始的输入是一张图片,可以是彩色的,也可以是灰度的或黑白的。这里假设是只有一个通道的图片,目的是识别0~9的手写体数字;
  2. 第一层卷积,我们使用了4个卷积核,得到了4张feature map;激活函数层没有单独画出来,这里我们紧接着卷积操作使用了Relu激活函数;
  3. 第二层是池化,使用了Max Pooling方式,把图片的高宽各缩小一倍,但仍然是4个feature map;
  4. 第三层卷积,我们使用了4x6个卷积核,其中4对应着输入通道,6对应着输出通道,从而得到了6张feature map,当然也使用了Relu激活函数;
  5. 第四层再次做一次池化,现在得到的图片尺寸只是原始尺寸的四分之一左右;
  6. 第五层把第四层的6个图片展平成一维,成为一个fully connected层;
  7. 第六层再接一个小一些的fully connected层;
  8. 最后接一个softmax函数,判别10个分类。

所以,在一个典型的卷积神经网络中,会至少包含以下几个层:

  • 卷积层
  • 激活函数层
  • 池化层
  • 全连接分类层

我们会在后续的小节中讲解卷积层和池化层的具体工作原理。

2.7.3 卷积核的作用

我们遇到了一个新的概念:卷积核。卷积网络之所以能工作,完全是卷积核的功劳。什么是卷积核呢?卷积核其实就是一个小矩阵,类似这样:

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就是相当于原始图片,放在中间是为了方便和其它卷积核的效果做对比。

2.7.4 卷积后续的运算

前面我们认识到了卷积核的强大能力,卷积神经网络通过反向传播而令卷积核自我学习,找到分布在图片中的不同的feature,最后形成的卷积核中的数据。但是如果想达到这种效果,只有卷积层的话是不够的,还需要激活函数、池化等操作的配合。

图 2.7.5 中的四个子图,依次展示了:

  1. 原图
  2. 卷积结果
  3. 激活结果
  4. 池化结果

图 2.7.5 原图经过卷积-激活-池化操作后的效果

  1. 注意图一是原始图片,用cv2读取出来的图片,其顺序是反向的,即:
  • 第一维是高度
  • 第二维是宽度
  • 第三维是彩色通道数,但是其顺序为BGR,而不是常用的RGB
  1. 我们对原始图片使用了一个3x1x3x3的卷积核,因为原始图片为彩色图片,所以第一个维度是3,对应RGB三个彩色通道;我们希望只输出一张feature map,以便于说明,所以第二维是1;我们使用了3x3的卷积核,用的是sobel x算子。所以图二是卷积后的结果。

  2. 图三做了一层Relu激活计算,把小于0的值都去掉了,只留下了一些边的特征。

  3. 图四是图三的四分之一大小,虽然图片缩小了,但是特征都没有丢失,反而因为图像尺寸变小而变得密集,亮点的密度要比图三大而粗。

2.7.5 卷积神经网络的特性

从整体图中,可以看到在卷积-池化等一些列操作的后面,要接全连接层,这里的全连接层和我们在前面学习的深度网络的功能一模一样,都是做为分类层使用。

在最后一层的池化后面,把所有特征数据变成一个一维的全连接层,然后就和普通的深度全连接网络一样了,通过在最后一层的softmax分类函数,以及多分类交叉熵函数,对比图片的OneHot编码标签,回传误差值,从全连接层传回到池化层,通过激活函数层再回传给卷积层,对卷积核的数值进行梯度更新,实现卷积核数值的自我学习。

但是这里有个问题,回忆一下MNIST数据集,所有的样本数据都是处于28x28方形区域的中间地带,如图 2.7.6 中的左上角的图片A所示。

图 2.7.6 同一个背景下数字8的大小、位置、形状的不同

我们的问题是:

  1. 如果这个“8”的位置很大地偏移到了右下角,使得左侧留出来一大片空白,即发生了平移,如上图右上角子图B
  2. “8”做了一些旋转或者翻转,即发生了旋转视角,如上图左下角子图C
  3. “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的想法,用不同尺寸的卷积核去同时寻找同一张图片上的特征。

2.7.6 卷积类型

卷积的数学定义

二维卷积一般用于图像处理上。在二维图片上做卷积,如果把图像Image简写为$I$,把卷积核Kernal简写为$K$,则目标图片的第$(i,j)$个像素的卷积值为:

$$ h(i,j) = (I*K)(i,j)=\sum_m \sum_n I(i+m,j+n)K(m,n) $$

在图像处理中,自相关函数和互相关函数定义如下:

  • 自相关:设原函数是f(t),则$h=f(t) \star f(-t)$,其中$\star$表示卷积
  • 互相关:设两个函数分别是f(t)和g(t),则$h=f(t) \star g(-t)$

互相关函数的运算,是两个序列滑动相乘,两个序列都不翻转。卷积运算也是滑动相乘,但是其中一个序列需要先翻转,再相乘。所以,从数学意义上说,机器学习实现的是互相关函数,而不是原始含义上的卷积。但我们为了简化,把公式5也称作为卷积。这就是卷积的来源。

结论:

  1. 我们实现的卷积操作不是原始数学含义的卷积,而是工程上的卷积,可以简称为卷积
  2. 在实现卷积操作时,并不会反转卷积核

在传统的图像处理中,卷积操作多用来进行滤波,锐化或者边缘检测啥的。我们可以认为卷积是利用某些设计好的参数组合(卷积核)去提取图像空域上相邻的信息。

单入单出的二维卷积

按照公式,我们可以在4x4的图片上,用一个3x3的卷积核,通过卷积运算得到一个2x2的图片,运算的过程如图 2.7.7 所示。

图 2.7.7 卷积运算的过程

单入多出的升维卷积

原始输入是一维的图片,但是我们可以用多个卷积核分别对其计算,从而得到多个特征输出。如图 2.7.8 所示。

图 2.7.8 单入多出的升维卷积

一张4x4的图片,用两个卷积核并行地处理,输出为2个2x2的图片。在训练过程中,这两个卷积核会完成不同的特征学习。

多入单出的降维卷积

一张图片,通常是彩色的,具有红绿蓝三个通道。我们可以有两个选择来处理:

  1. 变成灰度的,每个像素只剩下一个值,就可以用二维卷积
  2. 对于三个通道,每个通道都使用一个卷积核,分别处理红绿蓝三种颜色的信息

显然第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

前面的例子中,每次计算后,卷积核会向右或者向下移动一个单元,即步长stride = 1。而在图 2.7.11 这个卷积操作中,卷积核每次向右或向下移动两个单元,即stride = 2。

图 2.7.11 步长为2的卷积

在后续的步骤中,由于每次移动两格,所以最终得到一个2x2的图片。

填充 padding

如果原始图为4x4,用3x3的卷积核进行卷积后,目标图片变成了2x2。如果我们想保持目标图片和原始图片为同样大小,该怎么办呢?一般我们会向原始图片周围填充一圈0,然后再做卷积。如图 2.7.12。

图 2.7.12 带填充的卷积

输出结果

综合以上所有情况,可以得到卷积后的输出图片的大小的公式:

$$ H_{Output}= {H_{Input} - H_{Kernal} + 2Padding \over Stride} + 1 $$

$$ W_{Output}= {W_{Input} - W_{Kernal} + 2Padding \over Stride} + 1 $$

以图 2.7.11 为例:

$$H_{Output}={5 - 3 + 2 \times 0 \over 2}+1=2$$

以图 2.7.12 为例:

$$H_{Output}={4 - 3 + 2 \times 1 \over 1}+1=4$$

两点注意:

  1. 一般情况下,我们用正方形的卷积核,且为奇数
  2. 如果计算出的输出图片尺寸为小数,则取整,不做四舍五入

2.7.7 计算卷积核梯度的实例说明

下面我们会用一个简单的例子来说明卷积核的训练过程。我们先制作一张样本图片,然后使用“横边检测”算子做为卷积核对该样本进行卷积,得到对比如图 2.7.13。

图 2.7.13 原图和经过横边检测算子的卷积结果

左侧为原始图片(80x80的灰度图),右侧为经过3x3的卷积后的结果图片(78x78的灰度图)。由于算子是横边检测,所以只保留了原始图片中的横边。

卷积核矩阵:

$$ w=\begin{pmatrix} 0 & -1 & 0 \\ 0 & 2 & 0 \\ 0 & -1 & 0 \end{pmatrix} $$

现在我们转换一下问题:假设我们有一张原始图片(如左侧)和一张目标图片(如右侧),我们如何得到对应的卷积核呢?

我们在前面学习了线性拟合的解决方案,实际上这个问题是同一种性质的,只不过把直线拟合点阵的问题,变成了图像拟合图像的问题,如表 2.7.2 所示。

表 2.7.2 直线拟合与图像拟合的比较

样本数据 标签数据 预测数据 公式 损失函数
直线拟合 样本点x 标签值y 预测直线z $z=x \cdot w+b$ 均方差
图片拟合 原始图片x 目标图片y 预测图片z $z=x * w+b$ 均方差

直线拟合中的均方差,是计算预测值与样本点之间的距离;图片拟合中的均方差,可以直接计算两张图片对应的像素点之间的差值。

为了简化问题,我们令b=0,只求卷积核w的值,则前向公式为:

$$ z = x * w $$ $$ loss = \frac{1}{2}(z-y)^2 $$

反向求解w的梯度公式(从公式11得到):

$$ \frac{\partial loss}{\partial w}=\frac{\partial loss}{\partial z}\frac{\partial z}{\partial w}=x * (z-y) $$

$w$ 的梯度为预测图片 $z$ 减去目标图片 $y$ 的结果,再与原始图片 $x$ 做卷积,其中 $x$ 为被卷积图片,$(z-y)$ 为卷积核。

训练部分的代码实现如下:

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次:

  1. 用jit_conv_2d(x,w...)做一次前向计算
  2. 计算loss值以便检测停止条件,当loss值小于1e-7时停止迭代
  3. 然后计算delta值
  4. 再用jit_conv_2d(x,delta)做一次反向计算,得到w的梯度
  5. 最后更新卷积核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 循环运算?

参考文献

  1. 《智能之门》,胡晓武等著,高等教育出版社

  2. 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.

  3. Zeiler, M. D. (2012). ADADELTA: an adaptive learning rate method. arXiv preprint arXiv:1212.5701.

  4. 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.

  5. Kingma, D. P., & Ba, J. (2014). Adam: A method for stochastic optimization. arXiv preprint arXiv:1412.6980.

  6. 周志华老师的西瓜书《机器学习》

  7. 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.

  8. Inoue H. Data Augmentation by Pairing Samples for Images Classification[J]. 2018.

  9. Zhang H, Cisse M, Dauphin Y N, et al. mixup: Beyond Empirical Risk Minimization[J]. 2017.

  10. 《深度学习》- 伊恩·古德费洛

  11. 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