liqing 2020-02-02
数字图像划分为彩色图像、灰度图像、二值图像和索引图像几种。其中,像素是构成图像的基本单位,例如一张28×28像素的图片,即表示横向有28个像素点,纵向有28个像素点。
最常用的彩色图像和灰度图像:
通过上述的描述,可以通过像素的方式将图片量化,形成数据。
P.S. 图像的像素点越多,图像越清晰,也就是说图像的分辨率越大,尺寸也就越大。
下图是传统的全连接神经网络的示意图
根据前面对图像数据化的描述,一张28×28像素的图片包含784个数据信息。
那么,如果采用全连接神经网络对该图像进行处理,该神经网络输入层(input layer)的节点个数需要有784个,对于一个只有两个隐含层的神经网络(各层节点个数为256个),输出层节点数为10(10类),所需要权值的个数: 28×28×256+256×256+256×10 = 268800; 所需要的阈值个数 256+256+10 = 522,总共需要269322个参数。
对于像素高一些的图片,例如1000×1000的,仅输入层到第一个隐含层的权重个数就需要1000×1000×256 = 2亿多个权值。如果再换为彩色图片,则需要再乘以3。参数过多将消耗大量的内存和运算量。
可以看出,图像是原生的高维数据。而对于传统前向型全连接神经网络,只能通过增加隐含层节点个数和节点层数进行调节, 高维数据限制了全连接神经网络调节的灵活性。
参数过多、全连接的神经网络不适合处理图像数据。
卷积神经网络其实也是前向型神经网络,同样具有反向传播的过程,只是层与层之间的功能和形式做了变化,也就是后面将要介绍的卷积操作和池化操作,也可以称之为特征提取层。为了实现分类等操作,也会有特征映射层。CNN的基本结构就是由这两层构成。
具体来说,卷积神经网络CNN一般包括5个部分,即输入层、若干个卷积操作和池化层的结合、全局平均池化层(之前为1~3个全连接层)、输出层。如下图所示,(将全连接层替换为全局平均池化层,采样层即池化层)。随着学习的渐进,便会发现可以使用步长大于1的卷积操作替换池化操作,形成全卷积网络FC。
根据前文的描述,传统前向型全连接神经网络的弊端之一就在于参数过多,而图像自身就是以像素为数据,数据信息维数较大。如果不设法将输入的数据量减少,那么很难能够将参数减少,从而加快速度。 减少参数量是将神经网络应用于图像的重中之重,也是卷积神经网络的精妙之处。
卷积神经网络的精妙之处主要体现在两个方面:
1. 局部感知
一般而言,生物对外界的认知是从局部到全局的,而图像的空间联系也是局部的像素联系较为紧密,距离较远的像素相关性则较弱。以人对外界的认知来考虑,我们在观察事物时,往往能够直接抓住事物的特征,而与事物无关的部分会忽略。因而,在神经网络中,对于每一个神经元其实没有必要对全局的图像进行感知,只需要对局部进行感知,然后在更高层将局部的信息综合起来从而得到全局的信息,也就是局部连接。这也是受启发于生物学里面的视觉系统结构。视觉皮层的神经元就是局部接受信息的(即这些神经元只响应某些特定区域的刺激)。
如下图所示,左侧的图可以看作是一种全连接的形式,对整张图的所有信息进行感知;右侧的图为局部连接的形式,也可以称之为特征提取的方式,每个神经元只和10×10的像素相连,对于1M的隐含层节点个数,权值个数为1000000×100,减少为原来的万分之一。
在右图中,假如每个神经元只和10×10个像素值相连,那么权值数据为1000000×100个参数,减少为原来的万分之一。而那10×10个像素值对应的10×10个参数,其实就相当于卷积操作。
(通过局部感知的操作,确实使参数减少了不少。但1000000×100个参数仍然好多。)
2. 权值共享
在上面的局部连接中,如果每个隐含层节点(1000000个)对应的100个参数都是相等的,那么参数的数目就锐减到了100。
那权值共享该怎么理解呢,同样的参数会不会得到同样的结果?其实,在图像的处理中,由于图像自身二维的性质,使得这100个参数可以看做是一种特征提取的方式,它作用在不同的位置,也就是说该图像的所有位置都使用相同的特征提取方式,或者说是采用相同的学习模式,使用一个名为卷积核的过滤器(filter)在图像上将符合条件的特征筛选出来。
如下图所示,是一个3×3的卷积核作用于一张5×5的图像上的效果,生成了一张3×3的结果(feature_map)。
由于单一卷积核对图像进行特征提取可能不够充分,因此可以采用多个不同的卷积核。同一卷积核作用于图像的各个位置时,权值是共享的,不同卷积核之间是相互独立的。
通过前面的介绍,想必对于卷积神经网络有了一个模糊的印象,下面将对于CNN中主要的两个部分:卷积操作和池化操作做进一步介绍。
通过卷积神经网络的命名方式可以看出卷积操作在CNN中的重要程度。再通过下图对卷积操作进行进一步的描述。
如图所示,在一张5×5的图像中,使用一个3×3的卷积核:
1 0 1
0 1 0
1 0 1
对图像进行水平方向步长为1,竖直方向步长也为1的卷积操作(步长stride即为卷积核在图像中移动的格数),卷积操作可以理解为是一个滑动窗口以一定的步长把卷积核与对应的图像像素分别做乘积后再求和,得到3×3的卷积结果,通常称计算完的结果称为feature_map。卷积核其实就是一个特征提取器。
从卷积后的结果可以看出,生成feature_map的尺寸比原图的尺寸要小,这种卷积方式称之为“窄卷积(valid卷积)”,这种卷积方式不进行padding(补零)操作,即边缘不填充。feature_map尺寸的大小可以通过输入尺寸的大小、卷积核(filter)尺寸的大小以及步长来确定(ceil表示向上取整):
output_width = ceil(in_width - filter_width +1) / stride_width
output_height = ceil(in_height - filter_height +1) / stride_height
另外,同卷积(same卷积)也是一种常用的卷积方式,从名字上可以理解其代表的意思是卷积后生成的feature_map的尺寸与卷积前的尺寸一样大,其实也就是通过padding(补零)的方式进行边缘填充,使得在进行卷积操作时,卷积核能够到达图像的边缘,避免了边缘遗失的效果。在这种卷积方式下,只有当步长为1时,才能够使得卷积前后的尺寸一样大,而步长不为1时,只是起到了避免边缘遗失的效果。
在该卷积方式下,feature_map的的尺寸与卷积核的尺寸无关,只与输入尺寸和步长有关:
output_width = ceil(in_width / stride_width)
output_height = ceil(in_height / stride_height)
接下来,介绍一下padding操作。
padding操作其实就是在输入外围(上、下、左、右)补若干圈0的操作。如下图的Input Volume就是在四周都补了一排0。(在卷积操作处理时序问题时,将有可能会接触到另一种卷积方式:空洞卷积【也叫因果卷积】,其会在feature map各元素间填充若干0,目的在于增加网络的感受野)
这样的目的是使卷积核在以任意步长移动时,都能够到达输入的边缘。可以看出padding操作与步长有着密切的关系。例如,一个13×13的输入和卷积核为6×6以步长为5的方式进行卷积,下图为简易一维示意图,可以看出,经过两次卷积后,已不能再进行以步长为5的水平移动,位于12,13的边缘图像信息将丢失。
那么,padding操作进行补零的维度可以通过下式来确定:
1. 首先确定水平、竖直方向各需要补多少0
pad_height = max((output_height - 1) × stride_height +filter_hright - in_height, 0)
pad_width = max((output_width - 1) × stride_width +filter_width - in_width, 0)
2. 再计算上下、左右两侧各需要补多少0
pad_top = ceil( pad_height / 2) (上)
pad_bottom = pad_height - pad_top (下)
pad_left = ceil(pad_width / 2) (左)
pad_right = pad_width - pad_left (右)
纸上谈兵了这么多,其实在TensorFlow框架中,只需要tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu)一条指令便可以实现卷积操作:
import tensorflow as tf input1 = tf.Variable(tf.constant(1.0, shape = [1, 5, 5, 1])) # 1batch, 5*5图,1通道 filter1 = tf.Variable(tf.constant([-1.0, 0, 0, -1], shape=[2, 2, 1, 1]))# 2*2卷积核, 1通道,1个卷积核 op1 = tf.nn.conv2d(input1, filter, strides=[1, 2, 2,1], padding=‘SAME‘) # 定义卷积运算 init = tf.gloabal_Variables_initializer() with tf.Session() as sess: sess.run(init) sess.run([op1, filter1])
P.S. 完整的卷积层操作 还会在卷积结果后添加偏置项,并结合激活函数生成最终的卷积层输出。
每一层的卷积核大小和个数可以自己定义,不过一般情况下,根据实验得到的经验来看,会在越靠近输入层的卷积层设定少量的卷积核,越往后,卷积层设定的卷积核数目就越多。减小输入尺寸的同时,增大通道数量。
Pooling层主要的作用是下采样,也就是降维,通过去掉Feature Map中不重要的样本,进一步减少参数数量。主要包括:
如下图所示,2×2的filter 以步长为2作用于4×4的图像上进行最大池化操作
在TensorFlow框架中,通过tf.nn.max_pool(avg_pool)进行最大池化操作,输入主要包括:
通过上述的介绍,可以看到最初输入的图像经过卷积层,池化层后大小会发生变化。 通常情况,在设计时,高度和宽度在一段时间内应该保持一致,而通道数量一般是递增的(即使用的卷积核的个数是递增的)。但一般来说,尽量不要自己设置超参数,而是通过查看文献中别人采用了哪些超参数。
卷积神经网络包含卷积操作和池化操作两部分,核心操作是卷积操作。在实际使用中,使用卷积神经网络的深度学习网络结构中,卷积操作只是其中的基础组成部分。根据输出的需求,设计网络结构的超参数。使用基于卷积神经网络的深度学习网络结构处理图像数据,可以在一定程度上减少特征工程部分的工作量。
可以参考深度学习中的经典网络结构:LeNet、AlexNet、VGG、GoogLeNet、ResNet、DenseNet、ResXNet、MobileNet等。
可以参考目标检测、目标追踪的网络结构:R-CNN系列、YOLO系列、Mask-RCNN、SiamFC、SiamRPN、SiamMask等。
也可以关注本博客后续的分享内容~