作者:行动派Xdpie
1. 图片数据处理
一张图片是由一个个像素组成,每个像素的颜色常常用RGB、HSB、CYMK、RGBA等颜色值来表示,每个颜色值的取值范围不一样,但都代表了一个像素点数据信息。对图片的数据处理过程中,RGB使用得最多,RGB表示红绿蓝三通道色,取值范围为0~255,所以一个像素点可以把它看作是一个三维数组,即:array([[[0, 255, 255]]]),三个数值分布表示R、G、B(红、绿、蓝)的颜色值。比如下图一张3*3大小的jpg格式的图片:
它的图片经过Tensorflow解码后,数据值输出为
image_path = 'images/image.jpg' filename_queue = tf.train.string_input_producer(tf.train.match_filenames_once(image_path)) image_reader = tf.WholeFileReader() _,image_file = image_reader.read(filename_queue) image = tf.image.decode_jpeg(image_file) # 如果是png格式的图片,使用tf.image.decode_png() sess.run(image) --result array([[[0, 0, 0], [255, 255, 255], [254, 0, 0]], [[0, 191, 0], [3, 108, 233], [0, 191, 0]], [[254, 0, 0], [255, 255, 255], [0, 0, 0]])
图片的数据处理不仅仅就是把RGB值转换成运算需要的值,还包括调整图片大小、图片截取、图片翻转、图片色彩调整,标注框、多线程处理图片等等,在这里就不一一介绍了,但是对于图片的处理是进行卷积网络的首要任务,你需要了解,并学会对图片的相关操作。这里只介绍RGB值的转换,为下一节的卷积提供数据支持。
2. 卷积神经网络
卷积神经网络(CNN)的基本架构通常包括卷积层,池化层,全链层三大层次,其中不同的层中可能还会包括一些非线性变化(RELU函数)、数据归一化处理、dropoout等。我们常听说的LeNet-5、AlexNet、VGG、ResNet等都是卷积神经网络,而且都是由这些层组成,只是每个网络的层数不一样,所达到的分类效果也不一样。
2.1. 卷积层
卷积层是整个神经网络中最重要的一层,该层最核心的部分为过滤器,或者称为卷积核,卷积核有大小和深度两个属性,大小常用的有3X3、5X5,也有11X11的卷积核,而深度通俗一点理解就是卷积核的个数。卷积核的大小和深度均由人工指定,而权重参数则在初始化的时候由程序随机生成,并在后期训练过程中不断优化这些权重值,以达到最好的分类效果。卷积的过程就是用这些权重值不断的去乘这些图片的RGB值,以提取图片数据信息。下面的动图完美地诠释了卷积是怎么发生的:
上面黄色3X3大小不停移动的就是卷积核,绿色部分是5X5的输入矩阵,粉色部分是卷积后的结果,称作特征值。从上面动图看出,卷积不仅提取了图片信息,也可以达到降维效果。如果希望卷积后的特征值维度和原图片一致,需要设置padding值(全零填充)为SAME(如果为VALID表示不填充),其中i为输入图片,k为卷积核大小,strides为移动步长(移动步长>1也可以达到降维的效果)。
tf.nn.conv2d(i, k,strides,padding='VALID')
在卷积层中,过滤器中的参数是共享的,即一个过滤器中的参数值在对所有图片数据进行卷积过程中保持不变,这样卷积层的参数个数就和图片大小无关,它只和过滤器的尺寸,深度,以及当前层节点的矩阵深度有关。比如,以手写图片为例,输入矩阵的维度是28X28X1,假设第一层卷积层使用的过滤器大小为5X5,深度为16,则该卷积层的参数个数为5X5X1X16+16=416个,而如果使用500个隐藏节点的全链层会有1.5百万个参数,相比之下,卷积层的参数个数远远小于全链层,这就是为什么卷积网络广泛用于图片识别上的原因。
对于卷积后的矩阵大小,有一个计算公式,如果使用了全0填充,则卷积后的矩阵大小为:
即输出矩阵的长等于输入矩阵长度除以长度方向上的步长,并向上取整数值;输出矩阵的宽度等于输入矩阵的宽度除以宽度方向上的步长,并向上取整数值。
如果不使用全0填充,则输出矩阵的大小为:
卷积计算完成后,往往会加入一个修正线性单元ReLU函数,也就是把数据非线性化。为什么要把数据进行非线性化呢,这是因为非线性代表了输入和输出的关系是一条曲线而不是直线,曲线能够刻画输入中更为复杂的变化。比如一个输入值大部分时间都很稳定,但有可能会在某个时间点出现极值,但是通过ReLU函数以后,数据变得平滑,这样以便对复杂的数据进行训练。
ReLU是分段线性的,当输入为非负时,输出将与输入相同;而当输入为负时,输出均为0。它的优点在于不受“梯度消失”的影响,且取值范围为[0,+∞];其缺点在于当使用了较大的学习速率时,易受达到饱和的神经元的影响。
2.2. 池化层
卷积层后一般会加入池化层,池化层可以非常有效地缩小矩阵的尺寸,从而减少最后全链层中的参数,使用池化层既可以加快计算速度也有防止过拟合问题的作用。
池化层也存在一个过滤器,但是过滤器对于输入的数据的处理并不是像卷积核对输入数据进行节点的加权和,而只是简单的计算最大值或者平均值。过滤器的大小、是否全0填充、步长等也是由人工指定,而深度跟卷积核深度不一样,卷积层使用过滤器是横跨整个深度的,而池化层使用的过滤器只影响一个深度上的节点,在计算过程中,池化层过滤器不仅要在长和宽两个维度移动,还要在深度这个维度移动。使用最大值操作的池化层被称之为最大池化层,这种池化层使用得最多,使用平均值操作的池化层被称之为平均池化层,这种池化层的使用相对要少一点。
以下动图可以看到最大值池化层的计算过程:
Tensorflow程序很容易就可以实现最大值池化层的操作:
pool = tf.nn.max_pool(i, ksize=[1,3,3,1], stride=[1,2,2,1], padding='SAME') # i为输入矩阵 # ksize为过滤器尺寸,其中第一个和第四个值必须为1,表示过滤器不可以垮不同的输入样列和节点矩阵深度。中间的两个值为尺寸,常使用2*2或3*3。 # stride为步长,第一个值和第四个值与ksize一样 # padding为全0填充,‘SAME’表示使用全0填充,‘VALID’表示不使用全0填充
2.3. 全链层
在KNN或线性分类中有对数据进行归一化处理,而在神经网络中,也会做数据归一化的处理,原因和之前的一样,避免数据值大的节点对分类造成影响。归一化的目标在于将输入保持在一个可接受的范围内。例如,将输入归一化到[0.0,1.0]区间内。在卷积神经网络中,对数据归一化的处理我们有可能放在数据正式输入到全链层之前或之后,或其他地方,每个网络都可能不一样。
全链层的作用就是进行正确的图片分类,不同神经网络的全链层层数不同,但作用确是相同的。输入到全链层的神经元个数通过卷积层和池化层的处理后大大的减少了,比如以AlexNet为例,一张227*227大小,颜色通道数为3的图片经过处理后,输入到全链层的神经元个数有4096个,最后softmax的输出,则可以根据实际分类标签数来定。
在全链层中,会使用dropout以随机的去掉一些神经元,这样能够比较有效地防止神经网络的过拟合。相对于一般如线性模型使用正则的方法来防止模型过拟合,而在神经网络中Dropout通过修改神经网络本身结构来实现。对于某一层神经元,通