基于tensorflow搭建LeNet5网络实现手写数字MNIST识别任务
任务准备利用深度学习解决的任务无外乎以下几个关键步骤:
1、明确任务需求,准备训练数据
2、搭建网络模型
3、计算损失函数
4、定义优化器
5、迭代训练
6、测试
由于手写数字识别的任务需求是构建算法模型使其具有对手写的从0到9一共10个数字进行识别的功能。所以训练样本就是一定数量的0到9的数字图片,标签label就是数字0到9一共10类。比如数字图片3,它的label就是3:
手写数字识别一般都是采用MNIST数据集:
MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分:
1)Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本);
2)Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)
3)Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)
4)Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)
MNIST 数据集来自美国国家标准与技术研究所, National Institute of Standards and Technology (NIST). 训练集 (training set) 由来自 250 个不同人手写的数字构成, 其中 50% 是高中学生, 50% 来自人口普查局 (the Census Bureau) 的工作人员. 测试集(test set) 也是同样比例的手写数字数据。
由于本篇博客是识别手写数字,所以直接利用代码下载MNIST数据集作为任务的训练集,其实做深度学习的任务训练集的构建是十分关键的一步,后面博客会逐步讲解如何构建自己的训练集进行各种深度学习任务的尝试和研究。
这里下载MNIST数据集很简单,如下所示:
from tensorflow.examples.tutorials.mnist import input_data
mnist =input_data.read_data_sets("MNIST_data/",one_hot=True)
批量获取训练集和测试集以及对应的标签:
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
batch_xs,batch_ys=mnist.test.next_batch(batch_size)
下载和打印查看MINST数据集的完整代码如下:
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
import tensorflow as tf
#download dataset
from tensorflow.examples.tutorials.mnist import input_data
mnist =input_data.read_data_sets("MNIST_data/",one_hot=True)
#print message of MNIST
print('train_datas:',mnist.train.images)
print('train_shape:',mnist.train.images.shape)
import pylab
im=mnist.train.images[1]#调出第一张图
im=im.reshape(-1,28)
pylab.imshow(im)
pylab.show()
#打印MNIST测试集和验证集的信息
print('test_shape:',mnist.test.images.shape)
print('val_shape:',mnist.validation.images.shape)
LeNet5包含Input、卷积层1、池化层1、卷积层2、池化层2、全连接层、输出层:
INPUT: [28x28x1] weights: 0
CONV5-32: [28x28x32] weights: (5*5*1+1)*32
POOL1: [14x14x32] weights: 2*2*1
CONV5-64: [14x14x64] weights: (5*5*32+1)*64
POOL2: [7x7x64] weights: 2*2*1
FC: [1x1x1024] weights: (7*7*64+1)*1024
FC: [1x1x10] weights: (1*1*512+1)*10
网络结构显示如下:
搭建网络代码为:
##搭建网络模型##
#conv layer1
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
#conv+relu,输出大小为28*28*32
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
#pool layer1,输出大小为14*14*32
h_pool1=max_pool_2x2(h_conv1)
#conv layer2
W_conv2=weight_variable([5,5,32,64])
b_conv2=bias_variable([64])
#conv+relu,输出大小为14*14*64
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
#pool layer2,输出大小为7*7*64
h_pool2=max_pool_2x2(h_conv2)
#full connection layer1
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
#对输入的feature map进行reshape
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
#dropout防止过拟合
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
#full connection layer2
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
#利用softmax进行分类预测
prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
计算的是sofrmax交叉熵损失,prediction是softmax的输出。
cost=tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))
选择Adam优化器,学习率设置为0.001:
train_step=tf.train.AdamOptimizer(0.001).minimize(cost)
启动session进行训练,特别注意在训练过程中的验证测试以及训练完成时测试都需要将dropout的keep_prob设置为1,不然影响测试结果的稳定性。
完整的训练和测试代码示例,重点代码段都加了中文注释,很容易理解:
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"#指定GPU 0卡
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
#权重参数初始化函数
def weight_variable(shape):
initial=tf.truncated_normal(shape,stddev=0.1)#截断正态分布,标准差stddev=0.1
return tf.Variable(initial)
#偏置参数初始化函数
def bias_variable(shape):
initial=tf.constant(0.1,shape=shape)
return tf.Variable(initial)
#定义卷积层
def conv2d(x,W):
#stride[0]:在batch维度的步长,stride[1]:在height上的步长,stride[2]:在width上的步长,stride[3]:在channels维度的步长,一般情况下stride[0]和stride[3]都设为1
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding= 'SAME')
#定义2x2的pool层
def max_pool_2x2(x):
# ksize[0]:在batch维度的尺寸,ksize[1]:在height上的尺寸,ksize[2]:在width上的尺寸,ksize[3]:在channels维度的尺寸,一般情况下ksize[0]和ksize[3]都设为1
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding= 'SAME')
##define function finished##
#load MNIST
from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets("MNIST_data/",one_hot=True)
tf.reset_default_graph()
#定义输入输出数据的占位符placeholder
xs=tf.placeholder(tf.float32,[None,784])
ys=tf.placeholder(tf.float32,[None,10])
#dropout的系数
keep_prob=tf.placeholder(tf.float32)
#对数据进行重新排列,形成图像
x_image=tf.reshape(xs,shape=[-1,28,28,1])
##搭建网络模型##
#conv layer1
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
#conv+relu,输出大小为28*28*32
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
#pool layer1,输出大小为14*14*32
h_pool1=max_pool_2x2(h_conv1)
#conv layer2
W_conv2=weight_variable([5,5,32,64])
b_conv2=bias_variable([64])
#conv+relu,输出大小为14*14*64
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
#pool layer2,输出大小为7*7*64
h_pool2=max_pool_2x2(h_conv2)
#full connection layer1
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
#对输入的feature map进行reshape
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
#dropout防止过拟合
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
#full connection layer2
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
#利用softmax进行分类预测
prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
#计算loss
cost=tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))#reduction_indices=[1]表示按行求和再转置
#train
train_step=tf.train.AdamOptimizer(0.001).minimize(cost)
##构建模型end##
batch_size=128#数据按批次训练,每一批次喂入128个样本
#预测结果评估
print('prediction',prediction.shape)
print('ys',ys.shape)
correct=tf.equal(tf.argmax(prediction,1),tf.argmax(ys,1))
accuracy=tf.reduce_mean(tf.cast(correct,tf.float32))
#创建list保存每一次迭代的结果
train_accuracy_list = []
test_accuracy_list = []
train_cost_list = []
test_cost_list = []
#定义保存模型的saver和model_path
saver=tf.train.Saver()
model_path="log/521model.ckpt"
#定义session,启动会话
with tf.Session() as sess:
init=tf.global_variables_initializer()
sess.run(init)
#循环所有训练集
for i in range(200000):
batch_xs,batch_ys=mnist.train.next_batch(batch_size)
#开始训练
train_step.run(feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:0.7})
# 每迭代100次计算一次loss和准确率
if (i+1)%100 == 0:
#特别注意在训练集计算准确率dropout的keep_prob必须也要设置为1
train_accuracy,train_cost=sess.run([accuracy,cost],feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:1.0})
train_accuracy_list.append(train_accuracy)
train_cost_list.append(train_cost)
print('step {0}:Train set accuracy {1},cost {2}.'.format(i+1,train_accuracy,train_cost))
#保存模型
save_path=saver.save(sess,model_path)
print("Model saved in file: %s"%save_path)
print("train Finished!")
##test start##
print('test start!')
##循环测试##
for i in range(200):
batch_xs,batch_ys=mnist.test.next_batch(50)
test_accuracy,test_cost=sess.run([accuracy,cost],feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:1.0})
test_accuracy_list.append(test_accuracy)
test_cost_list.append(test_cost)
#每训练20次显示结果
if (i+1)%20 == 0:
print('step {0}:Test set accuracy {1},cost {2}.'.format(i + 1, test_accuracy, test_cost))
print('Test accuracy:',np.mean(test_accuracy_list))
##test finished##
print('test finished!')
有时如果想看网络训练过程中,或者网络训练完成后中间到底学了什么,可以将中间层的feature map显示出来进行查看,直接见代码示例:
##可视化conv1和pool1结果
#随意读取一张图像,比如第三张
img=mnist.train.images[2]
label=mnist.train.labels[2]
print('图像对应的标签 {0}'.format(np.argmax(label)))
plt.figure()
#子图1
plt.subplot(1,2,1)
plt.imshow(img.reshape(28,28))
plt.axis('off')
#子图2
plt.subplot(1,2,2)
plt.imshow(img.reshape(28,28),cmap='gray')
plt.axis('off')
plt.show()
##可视化卷积层结果##
plt.figure(figsize=(1.0*8,1.6*4))
plt.subplots_adjust(bottom=0,left=.01,right=.99,top=.90,hspace=.35)
conv1=h_conv1.eval(feed_dict={xs:img.reshape(-1,784),ys:label.reshape([-1,10]),keep_prob:1.0})
print('conv1 shape',conv1.shape)
for i in range(32):
show_image = conv1[:,:,:,1]
show_image.shape=[28,28]
plt.subplot(4,8,i+1)
plt.imshow(show_image,cmap='gray')
plt.axis('off')
plt.show()
##可视化池化层结果##
plt.figure(figsize=(1.2*8,2.0*4))
plt.subplots_adjust(bottom=0,left=.01,right=.99,top=.90,hspace=.35)
pool1=h_pool1.eval(feed_dict={xs:img.reshape([-1,784]),ys:label.reshape([-1,10]),keep_prob:1.0})
print('pool1 shape',pool1.shape)
for i in range(32):
show_image=pool1[:,:,:,1]
show_image.shape=[14,14]
plt.subplot(4,8,i+1)
plt.imshow(show_image,cmap='gray')
plt.axis('off')
plt.show()
有问题欢迎评论交流,一起进步!