使用TensorFlow搭建一个简单的卷积神经网络实现Cifar10数据集分类,这个神经网络模型包括两个卷积层,两个池化层,卷积操作后在后面加三个全连层,最后一个全连层用于输出分类。整个神经网络架构图如下:
名词解释
名字 | 说明 |
---|---|
输入层 | 输入层是整个神经网络的输入。在用于图像分类的卷积神经网络中,它一般代表的是一张图片的像素矩阵。根据通道数的不同,图片像素的矩阵也有着不同的深度数值,比如黑白图片只有一个通道,所以其深度为1;而在RGB色彩模式下图像有3个通道,所以深度为3。 |
卷积层 | 如上图所示,该神经网络有两个卷积层。卷积层由一系列执行了卷积操作而得到的特征映射图组成。这里卷积运算的过程是:对于单个卷积核,有3个通道,每个通道的分量分别与对应的被卷积张量的对应通道卷积,得到3个通道的卷积结果,然后这3个通道的卷积结果按元素叠加,生成一个通道的卷积结果,然后该卷积结果再经过激活函数,得到最终的卷积结果。至此,一个3通道的张量,经过一个3通道的卷积核后,得到了一个单通道的张量。常用的卷积核大小有3x3或者5x5.为了能从神经网络中的每一小块得到更多的抽像特征,一般卷积层的单元矩阵会比上一层的单元矩阵更深,也就是使用了多个卷积核。 |
池化层 | 池化层的单元矩阵深度不会比上一层的单元矩阵更深,但是它能在宽度和高度方向缩小矩阵的大小。另外,加入池化层也能达到减少整个神经网络中参数的目的。 |
全连层 | 如上图所示,在得到池化层的结果后连接了3个全连层。我们可以将卷积层和池化层看成是图像特征提取的结果,图像中的信息在经过几轮卷积操作和池化操作的处理后,得到了更抽象的表达,这就是图像最基本的特征。在得到了提取的特征后,为了完成分类任务仍需要构建几个全连层。其实可以简单地理解为卷积层和池化层相当于人类的眼睛,专门用于信息特征的提取,全连层相当于人类的大脑,将提取到的特征进行整合处理,算出结果。 |
softmax层 | 通过softmax层,可以得到输入样例所属种类的概率分布情况。 |
Cifar-10数据集
Cifar-10数据集中包含60000张32*32彩色图像,其中训练集图像50000张,测试集图像10000张。这个数据集中包含了十个类别的图片,分别是airplane,automobile,bird,cat,deer,dog,frog,horse,ship和truck,并且其中没有任何重叠的情况,下面开始对这些图像进行分类。
首先去下载这个数据集,网址为 http://www.cs.toronto.edu/~kriz/cifar.html, 点击下载CIFAR-10 python version,然后解压。
开始编写.py文件
数据读取和预处理
导入相关库和定义一些需要用到的变量
import os
import tensorflow as tf
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import numpy as np
import time
import math
num_classes = 10 #一共有10个类别
num_examples_pre_epoch_for_train = 50000 #50000个样本用于训练
num_examples_pre_epoch_for_eval = 10000 #10000个样本用于测试
max_steps = 4000 #训练4000步
batch_size = 100 #每次训练100个样本
num_examples_for_eval = 10000
data_dir = "C:/Users/Administrator/Desktop/Tensorflow/cifar-10-batches-bin" #下载的样本的路径
class CIFAR10Record(object): #定义一个空类,用于返回读取的Cifar-10数据
pass
接着定义一个read_cifar10()函数用于读取文件队列中的数据
def read_cifar10(file_queue): #file_queue为图片路径
result = CIFAR10Record() #创建一个CIFAR10Record对象
label_bytes = 1 #标签占一个字节
result.height = 32 #图像高为32像素
result.width = 32 #图像宽为32像素
result.depth = 3 #因为是RGB三通道,所以深度为3
image_bytes = result.height * result.width * result.depth #结果为3072,即一幅图像的大小为3072字节
record_bytes = label_bytes + image_bytes #加上标签,即一个样本一共有3073字节
reader = tf.FixedLengthRecordReader(record_bytes=record_bytes) #使用FixedLengthRecordReader类创建一个用于读取固定长度字节数信息的对象(针对bin文件而言)
result.key, value = reader.read(file_queue) #使用该类的read()方法读取指定路径下的文件
#这里得到的value就是record_bytes长度的包含多个label数据和image数据的字符串
record_bytes = tf.decode_raw(value, tf.uint8)
#decode_raw()可以将字符串解析成图像对应的像素数组
#strided_slice(input,begin,end)用于对输入的input截取[begin,end)区间的数据
result.label = tf.cast(tf.strided_slice(record_bytes, [0], [label_bytes]), tf.int32)
#这里把record_bytes的第一个元素截取下来然后转换成int32类型的数
#剪切label之后剩下的就是图片数据,我们将这些数据的格式从[depth*height*width]转换为[depth,height,width]
depth_major = tf.reshape(tf.strided_slice(record_bytes, [label_bytes], [label_bytes + image_bytes]),
[result.depth, result.height, result.width])
#将[depth,height,width]的格式转换为[height,width,depth]的格式
result.uint8image = tf.transpose(depth_major, [1, 2, 0])
return result
紧接着read_cifar10()函数的是inputs函数,这个函数用于构建文件路径,将构建的文件路径传给read_cifar10()函数读取样本,对读取到的样本进行数据增强处理。