基于Tensorflow(CNN)的MNIST处理与验证(附代码与解析)

经过两周学习实现了Tensorflow入门程序的编写与理解,写这篇文章对两周的学习进行总结。

 


目  录

         一、导入数据集

二、定义函数与变量

三、定义层

四、定义损失函数并训练保存网络

 


一、导入数据

 在数据的导入过程中,注意自己的Tensorflow的版本,需要把数据集提前下载到MNIST_data目录下。

  MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分:

  • Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)
  • Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)
  • Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)
  • Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)
import tensorflow as tf 
import numpy as np 
from tensorflow.contrib.layers.python.layers import batch_norm  #TensorFlow内部的批量化函数
from tensorflow.examples.tutorials.mnist import input_data      
mnist = input_data.read_data_sets("MNIST_data",one_hot = True)
#导入MNIST数据集,从MNIST_data文件中,前提是吧数据集下载到MNIST_data文件中

二、定义函数与变量

 定义权重、偏值、卷积和池化函数。解析以及附到代码处

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)
#定义权值变量 ,截断产生正态随机函数 stddev(标准差)=0.1
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)
#同上 产生一个恒定值为0.1
def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
#定义卷积函数tf.nn.conv2d (input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)
#input 输入在卷积的图像(一个张量) 
#filter 卷积核(一个张量)  strides(卷积时每一维度的步长) padding(考虑边界)
def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    #同上
x = tf.placeholder(tf.float32, [None, 784]) #28*28
#定义占位符,数据维度[行任意,28*28]
y_ = tf.placeholder(tf.float32, [None, 10])  #0~9十个输出

train = tf.placeholder(tf.float32)

三、定义层 

对于MNIST数据的学习需要两层网络,定义两层卷积层两层池化层和两层全连接层。在卷积与池化的过程数据集维度(长宽)变小,深度变深。

第一层网络

W=【5,5,1,32】 卷积核大小为5*5,输入厚度为1,输出厚度(卷积层)32。 32是卷积层最好为2的n次方

将图片变为【-1,28,28,1】,28*28为图片像素,1为channel(灰度图片)-1可以通过其他维度自动计算

经过卷积层与池化层后,数据的维度在代码注释中可以看到

#构建网络结构,两层卷积层
W_conv1 = weight_variable([5, 5, 1, 32])
#W_conv1 维度为[5,5,1,32],5*5是卷积核,1是输入厚度,32是输出厚度
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1, 28, 28, 1])
#如果等于-1的话,
# 那么Numpy会根据剩下的维度计算出数组的另外一个shape属性值
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)  #28*28*32
#x,w先进行卷积,再加上+偏执b,最后通过激活函数
h_pool1 = max_pool_2x2(h_conv1)#14*14*32
#卷积后再进行池化

 

第二层网络

从第一层网络接收过来的数据维度为14*14*32

在经过卷积核池化后变为7*7*64

#*********第二层卷积层*************#
W_conv2 = weight_variable([5, 5, 32, 64])  
#卷积核大小为5*5 输入大小为32,输出大小为64(厚度)
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) #14*14*64
h_pool2 = max_pool_2x2(h_conv2)#7*7*64

 

   全连接层

由于全连接层是将所有的图像所有信息都进行输出,所以要将维度进行变化为【7*7*64,1024】

tf.matmul():定义矩阵乘法

tf.nn.dropout():定义失活函数,可以减小网络的过拟合问题

tf.nn.softmax():采用指数运算,将输出值变换到0-1之间

#***********定义全连接层************#
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
#[n,7,7,64]→[n,7*7*64] 
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#这里用的matmul乘法,不是用conv2d
keep_prob = tf.placeholder(tf.float32)
#定义dropout层 失活神经函数 
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#*********定义第二层全连接层********#
W_fc2 = weight_variable([1024, 10])
#输入深度为1024,输出为10  0~9
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
#Softmax的含义:Softmax简单的说就是把一个N*1的向量归一化为(0,1)之间的值,
# 由于其中采用指数运算,使得向量中数值较大的量特征更加明显。

四、定义损失函数并训练保存网络 

定义交叉熵损失函数:cross_entropy

采用Adam算法进行优化

saver = tf.train.Save()

saver.save(sess,'目录')

cross_entropy =tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv),
reduction_indices=[1])) 
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#利用Adam优化算法
#tf.equal 返回x=y,返回Ture or false
# tf.argmax(input,axis)  
# 根据axis取值的不同返回每行(1)或者每列(0)最大值的索引
correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
saver = tf.train.Saver()
#训练网络之后保存训练好的模型,以及在程序中读取已保存好的模型
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(20000):
        batch = mnist.train.next_batch(100) #每次批量为100
        if i % 100 == 0:
            train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})
            #eval() 其实就是tf.Tensor的Session.run() 的另外一种写法。 #没有失活
            #第一个元素为预测标签,第二个元素为one_hot标签
            print('step %d, training accuracy %g' % (i, train_accuracy))  #%g浮点数
        train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
    saver.save(sess, 'WModel/model.ckpt')
    #将模型存入到这个文件夹下
    print('test accuracy %g' % accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

 

 

结果实现

 从画板中写出“5”进行测试

                                                       

在进行模型保存后,可以利用电脑上的画图工具进行测试,注意:图像大小为28*28

结果如下:

                                  

 


总  结:

在学习的过程中需要有好硬件设备辅助跑代码,在我电脑(CPU)我的需要跑5个小时,在我同学的电脑(GPU)可能就需要几分钟就搞定了。虽然学习的内容很新,但是要坚持学下去,管它什么真理无穷,进一寸有一寸的欢喜!

Guess you like

Origin blog.csdn.net/abc123mma/article/details/109155567