LeNet-5模型详解及其TensorFlow代码实现
2017-08-07 18:08
971 查看
本文先分析了LeNet-5模型的结构,然后基于LeNet-5模型写了TensorFlow代码实现mnist数字识别,代码部分进行了详细注解,目前也在学习阶段,有错误欢迎指出,大家一起学习。
LeNet-5模型结构图如下图:
LeNet-5模型总共有7层。
第一层:卷积层
第一层卷积层的输入为原始的图像,原始图像的尺寸为32×32×1。卷积层的过滤器尺寸为5×5,深度为6,不使用全0补充,步长为1。由于没有使用全0补充,所以这一层的输出的尺寸为32-5+1=28,深度为6。这一个卷积层总共有5×5×1×6+6=156个参数,其中6为偏置项参数个数,卷积层的参数个数只和过滤器的尺寸,深度以及当前层节点矩阵的深度有关。因为下一层节点矩阵有28×28×6=4704个节点,每个节点和5×5=25个当前层节点相连,所以本层卷积层总共有4704×(25+1)=122304个连接。
第二层:池化层
这一层的输入为第一层的输出,是一个28×28×6的节点矩阵。本层采用的过滤器大小为2×2,步长为2,所以本层的输出矩阵大小为14×14×6。
第三层:卷积层
本层的输入矩阵大小为14×14×6,采用的过滤器大小为5×5,深度为16,不使用全0补充,步长为1。这一层的输出的尺寸为14-5+1=10,深度为16,即输出矩阵大小为10×10×16。本层参数有5×5×6×16+16=2416个,连接有10×10×16×(5×5+1)=41600个。
第四层:池化层
本层的输入矩阵大小为10×10×16,采用的过滤器大小为2×2,步长为2,本层的输出矩阵大小为5×5×16。
第五层:全连接层
本层的输入矩阵大小为5×5×16,在LeNet-5模型的论文中将这一层称为卷积层,但是因为过滤器的大小就是5×5,所以和全连接层没有区别,这里直接看成全连接层。本层输入为5×5×16矩阵,将其拉直为一个长度为5×5×16的向量,即将一个三维矩阵拉直到一维空间以向量的形式表示,这样才可以进入全连接层进行训练。本层的输出节点个数为120,所以总共有5×5×16×120+120=48120个参数。
第六层:全连接层
本层的输入节点个数为120个,输出节点个数为84个,总共有120×84+84=10164个参数。
第七层:全连接层
本层的输入节点个数为84个,输出节点个数为10个,总共有84×10+10=850个参数。
接下来以TensorFlow代码展示一个基于LeNet-5模型的mnist数字识别代码。
mnist数据集png图片格式下载链接:链接:http://pan.baidu.com/s/1eRG6TqU 密码:uf4m
tensorflow版本:1.2.1
代码如下:
最终测试准确率大概在99%左右。
随机运行一次的训练及测试结果如下:
参考:《TensorFlow:实战Google深度学习框架》
LeNet-5模型结构图如下图:
LeNet-5模型总共有7层。
第一层:卷积层
第一层卷积层的输入为原始的图像,原始图像的尺寸为32×32×1。卷积层的过滤器尺寸为5×5,深度为6,不使用全0补充,步长为1。由于没有使用全0补充,所以这一层的输出的尺寸为32-5+1=28,深度为6。这一个卷积层总共有5×5×1×6+6=156个参数,其中6为偏置项参数个数,卷积层的参数个数只和过滤器的尺寸,深度以及当前层节点矩阵的深度有关。因为下一层节点矩阵有28×28×6=4704个节点,每个节点和5×5=25个当前层节点相连,所以本层卷积层总共有4704×(25+1)=122304个连接。
第二层:池化层
这一层的输入为第一层的输出,是一个28×28×6的节点矩阵。本层采用的过滤器大小为2×2,步长为2,所以本层的输出矩阵大小为14×14×6。
第三层:卷积层
本层的输入矩阵大小为14×14×6,采用的过滤器大小为5×5,深度为16,不使用全0补充,步长为1。这一层的输出的尺寸为14-5+1=10,深度为16,即输出矩阵大小为10×10×16。本层参数有5×5×6×16+16=2416个,连接有10×10×16×(5×5+1)=41600个。
第四层:池化层
本层的输入矩阵大小为10×10×16,采用的过滤器大小为2×2,步长为2,本层的输出矩阵大小为5×5×16。
第五层:全连接层
本层的输入矩阵大小为5×5×16,在LeNet-5模型的论文中将这一层称为卷积层,但是因为过滤器的大小就是5×5,所以和全连接层没有区别,这里直接看成全连接层。本层输入为5×5×16矩阵,将其拉直为一个长度为5×5×16的向量,即将一个三维矩阵拉直到一维空间以向量的形式表示,这样才可以进入全连接层进行训练。本层的输出节点个数为120,所以总共有5×5×16×120+120=48120个参数。
第六层:全连接层
本层的输入节点个数为120个,输出节点个数为84个,总共有120×84+84=10164个参数。
第七层:全连接层
本层的输入节点个数为84个,输出节点个数为10个,总共有84×10+10=850个参数。
接下来以TensorFlow代码展示一个基于LeNet-5模型的mnist数字识别代码。
mnist数据集png图片格式下载链接:链接:http://pan.baidu.com/s/1eRG6TqU 密码:uf4m
tensorflow版本:1.2.1
代码如下:
from skimage import io,transform import os import glob import numpy as np import tensorflow as tf #将所有的图片重新设置尺寸为32*32 w = 32 h = 32 c = 1 #mnist数据集中训练数据和测试数据保存地址 train_path = "E:/data/datasets/mnist/train/" test_path = "E:/data/datasets/mnist/test/" #读取图片及其标签函数 def read_image(path): label_dir = [path+x for x in os.listdir(path) if os.path.isdir(path+x)] images = [] labels = [] for index,folder in enumerate(label_dir): for img in glob.glob(folder+'/*.png'): print("reading the image:%s"%img) image = io.imread(img) image = transform.resize(image,(w,h,c)) images.append(image) labels.append(index) return np.asarray(images,dtype=np.float32),np.asarray(labels,dtype=np.int32) #读取训练数据及测试数据 train_data,train_label = read_image(train_path) test_data,test_label = read_image(test_path) #打乱训练数据及测试数据 train_image_num = len(train_data) train_image_index = np.arange(train_image_num) np.random.shuffle(train_image_index) train_data = train_data[train_image_index] train_label = train_label[train_image_index] test_image_num = len(test_data) test_image_index = np.arange(test_image_num) np.random.shuffle(test_image_index) test_data = test_data[test_image_index] test_label = test_label[test_image_index] #搭建CNN x = tf.placeholder(tf.float32,[None,w,h,c],name='x') y_ = tf.placeholder(tf.int32,[None],name='y_') def inference(input_tensor,train,regularizer): #第一层:卷积层,过滤器的尺寸为5×5,深度为6,不使用全0补充,步长为1。 #尺寸变化:32×32×1->28×28×6 with tf.variable_scope('layer1-conv1'): conv1_weights = tf.get_variable('weight',[5,5,c,6],initializer=tf.truncated_normal_initializer(stddev=0.1)) conv1_biases = tf.get_variable('bias',[6],initializer=tf.constant_initializer(0.0)) conv1 = tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding='VALID') relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases)) #第二层:池化层,过滤器的尺寸为2×2,使用全0补充,步长为2。 #尺寸变化:28×28×6->14×14×6 with tf.name_scope('layer2-pool1'): pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME') #第三层:卷积层,过滤器的尺寸为5×5,深度为16,不使用全0补充,步长为1。 #尺寸变化:14×14×6->10×10×16 with tf.variable_scope('layer3-conv2'): conv2_weights = tf.get_variable('weight',[5,5,6,16],initializer=tf.truncated_normal_initializer(stddev=0.1)) conv2_biases = tf.get_variable('bias',[16],initializer=tf.constant_initializer(0.0)) conv2 = tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding='VALID') relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases)) #第四层:池化层,过滤器的尺寸为2×2,使用全0补充,步长为2。 #尺寸变化:10×10×6->5×5×16 with tf.variable_scope('layer cdec 4-pool2'): pool2 = tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME') #将第四层池化层的输出转化为第五层全连接层的输入格式。第四层的输出为5×5×16的矩阵,然而第五层全连接层需要的输入格式 #为向量,所以我们需要把代表每张图片的尺寸为5×5×16的矩阵拉直成一个长度为5×5×16的向量。 #举例说,每次训练64张图片,那么第四层池化层的输出的size为(64,5,5,16),拉直为向量,nodes=5×5×16=400,尺寸size变为(64,400) pool_shape = pool2.get_shape().as_list() nodes = pool_shape[1]*pool_shape[2]*pool_shape[3] reshaped = tf.reshape(pool2,[-1,nodes]) #第五层:全连接层,nodes=5×5×16=400,400->120的全连接 #尺寸变化:比如一组训练样本为64,那么尺寸变化为64×400->64×120 #训练时,引入dropout,dropout在训练时会随机将部分节点的输出改为0,dropout可以避免过拟合问题。 #这和模型越简单越不容易过拟合思想一致,和正则化限制权重的大小,使得模型不能任意拟合训练数据中的随机噪声,以此达到避免过拟合思想一致。 #本文最后训练时没有采用dropout,dropout项传入参数设置成了False,因为训练和测试写在了一起没有分离,不过大家可以尝试。 with tf.variable_scope('layer5-fc1'): fc1_weights = tf.get_variable('weight',[nodes,120],initializer=tf.truncated_normal_initializer(stddev=0.1)) if regularizer != None: tf.add_to_collection('losses',regularizer(fc1_weights)) fc1_biases = tf.get_variable('bias',[120],initializer=tf.constant_initializer(0.1)) fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights) + fc1_biases) if train: fc1 = tf.nn.dropout(fc1,0.5) #第六层:全连接层,120->84的全连接 #尺寸变化:比如一组训练样本为64,那么尺寸变化为64×120->64×84 with tf.variable_scope('layer6-fc2'): fc2_weights = tf.get_variable('weight',[120,84],initializer=tf.truncated_normal_initializer(stddev=0.1)) if regularizer != None: tf.add_to_collection('losses',regularizer(fc2_weights)) fc2_biases = tf.get_variable('bias',[84],initializer=tf.truncated_normal_initializer(stddev=0.1)) fc2 = tf.nn.relu(tf.matmul(fc1,fc2_weights) + fc2_biases) if train: fc2 = tf.nn.dropout(fc2,0.5) #第七层:全连接层(近似表示),84->10的全连接 #尺寸变化:比如一组训练样本为64,那么尺寸变化为64×84->64×10。最后,64×10的矩阵经过softmax之后就得出了64张图片分类于每种数字的概率, #即得到最后的分类结果。 with tf.variable_scope('layer7-fc3'): fc3_weights = tf.get_variable('weight',[84,10],initializer=tf.truncated_normal_initializer(stddev=0.1)) if regularizer != None: tf.add_to_collection('losses',regularizer(fc3_weights)) fc3_biases = tf.get_variable('bias',[10],initializer=tf.truncated_normal_initializer(stddev=0.1)) logit = tf.matmul(fc2,fc3_weights) + fc3_biases return logit #正则化,交叉熵,平均交叉熵,损失函数,最小化损失函数,预测和实际equal比较,tf.equal函数会得到True或False, #accuracy首先将tf.equal比较得到的布尔值转为float型,即True转为1.,False转为0,最后求平均值,即一组样本的正确率。 #比如:一组5个样本,tf.equal比较为[True False True False False],转化为float型为[1. 0 1. 0 0],准确率为2./5=40%。 regularizer = tf.contrib.layers.l2_regularizer(0.001) y = inference(x,False,regularizer) cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=y_) cross_entropy_mean = tf.reduce_mean(cross_entropy) loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses')) train_op = tf.train.AdamOptimizer(0.001).minimize(loss) correct_prediction = tf.equal(tf.cast(tf.argmax(y,1),tf.int32),y_) accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) #每次获取batch_size个样本进行训练或测试 def get_batch(data,label,batch_size): for start_index in range(0,len(data)-batch_size+1,batch_size): slice_index = slice(start_index,start_index+batch_size) yield data[slice_index],label[slice_index] #创建Session会话 with tf.Session() as sess: #初始化所有变量(权值,偏置等) sess.run(tf.global_variables_initializer()) #将所有样本训练10次,每次训练中以64个为一组训练完所有样本。 #train_num可以设置大一些。 train_num = 10 batch_size = 64 for i in range(train_num): train_loss,train_acc,batch_num = 0, 0, 0 for train_data_batch,train_label_batch in get_batch(train_data,train_label,batch_size): _,err,acc = sess.run([train_op,loss,accuracy],feed_dict={x:train_data_batch,y_:train_label_batch}) train_loss+=err;train_acc+=acc;batch_num+=1 print("train loss:",train_loss/batch_num) print("train acc:",train_acc/batch_num) test_loss,test_acc,batch_num = 0, 0, 0 for test_data_batch,test_label_batch in get_batch(test_data,test_label,batch_size): err,acc = sess.run([loss,accuracy],feed_dict={x:test_data_batch,y_:test_label_batch}) test_loss+=err;test_acc+=acc;batch_num+=1 print("test loss:",test_loss/batch_num) print("test acc:",test_acc/batch_num)
最终测试准确率大概在99%左右。
随机运行一次的训练及测试结果如下:
... test loss: 0.0766476487789 test acc: 0.98577724359 train loss: 0.0529618164884 train acc: 0.993930096051 test loss: 0.0702898033345 test acc: 0.987680288462 train loss: 0.0511233446804 train acc: 0.994213580576 test loss: 0.0881681445843 test acc: 0.982672275641 train loss: 0.0503073274342 train acc: 0.994030149413 test loss: 0.0700190923033 test acc: 0.986979166667
参考:《TensorFlow:实战Google深度学习框架》
相关文章推荐
- 81、Tensorflow实现LeNet-5模型,多层卷积层,识别mnist数据集
- LeNet-5及其TensorFlow实现
- Tensorflow模型持久化的代码实现
- 详解字典树Trie结构及其Python代码实现
- TensorFlow使用C++加载使用训练好的模型,.cc文件代码实现的相关类及方法总结
- tensorflow5——CNN实现LeNet-5模型
- 基本的传染病模型:SI、SIS、SIR及其Python代码实现
- 基于tensorflow和mnist的LeNet-5模型实现
- 主题模型及其变种的实现代码汇总
- C45算法代码实现及其详解
- TensorFlow实现mnist数字识别——CNN LeNet-5模型
- Deep Learning-TensorFlow (1) CNN卷积神经网络_MNIST手写数字识别代码实现详解
- tensorflow实现LeNet-5模型
- 详解字典树Trie结构及其Python代码实现
- 81、Tensorflow实现LeNet-5模型,多层卷积层,识别mnist数据集
- 拾取模型的原理及其在THREE.JS中的代码实现
- 主题模型及其变种的实现代码汇总
- 进程、线程调度模型及其在Windows2000中的实现
- html视频播放器的代码 及其参数详解
- 商务智能及其实现模型