Tensorflow入门:(三)训练Mnist数据集

  1、使用softmax回归对mnist数据集进行分类,准确率大概为0.92左右
  2、使用多层感知机(3层)对mnist数据集分类,准确率大概为0,98

  3、使用CNN对mnist进行分类,准确率为0.99  

#coding=utf-8
import pickle
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import time 

# 定义一个mnist数据集的类
class mnistReader():  
    def __init__(self,mnistPath,onehot=True):  
        self.mnistPath=mnistPath
        self.onehot=onehot  
        self.batch_index=0
        print ('read:',self.mnistPath)
        fo = open(self.mnistPath, 'rb')
        self.train_set,self.valid_set,self.test_set = pickle.load(fo,encoding='bytes')
        fo.close()        
        self.data_label_train=list(zip(self.train_set[0],self.train_set[1]))
        np.random.shuffle(self.data_label_train)          
               

    # 打印一些数据集的信息
    def data_info(self):
    	#  train_set是一个元组,元组第一个元素是图片像素,元组第二个元素是图片对应的数字
    	print ("type:",type(self.train_set))
    	rdata = self.train_set[0] 
    	rlabel=self.train_set[1]  	
    	print ("train_set:",type(rdata)) #可以看到训练集大小为(50000,28*28)的二维矩阵  
    	print ("train_label:",type(rlabel)) # 可以看到训练集标签大小为(50000,)的数组   	
    	

    # 打印数据集的图片
    def show_image(self):
    	rdata,rlabel = self.train_set      	
    	pic=np.reshape(rdata[0],(28,28))
    	print (pic)
    	print (rlabel[0])    	
    	plt.imshow(pic)
    	plt.show()

    # 获取下一个训练集的batch
    def next_train_batch(self,batch_size=100):
        if self.batch_index < len(self.data_label_train)/batch_size:  
            print ("batch_index:",self.batch_index )
            datum=self.data_label_train[self.batch_index*batch_size:(self.batch_index+1)*batch_size]  
            self.batch_index+=1  
            return self._decode(datum,self.onehot)  
        else:  
            self.batch_index=0  
            np.random.shuffle(self.data_label_train)  
            datum=self.data_label_train[self.batch_index*batch_size:(self.batch_index+1)*batch_size]  
            self.batch_index+=1  
            return self._decode(datum,self.onehot)          
    
    # 获取测试集的数据
    def test_data(self):
        tdata,tlabel=self.test_set
        data_label_test=list(zip(tdata,tlabel))
        return self._decode(data_label_test,self.onehot)
    
    
    # 把一个batch的训练数据转换为可以放入模型训练的数据 
    def _decode(self,datum,onehot):  
        rdata=list()     # batch训练数据
        rlabel=list()  
        if onehot:  
            for d,l in datum:  
                rdata.append(np.reshape(d,[784]))   # 转变形状为:一维向量
                hot=np.zeros(10)    
                hot[int(l)]=1            # label设为100维的one-hot向量
                rlabel.append(hot)  
        else:  
            for d,l in datum:  
                rdata.append(np.reshape(d,[784]))  
                rlabel.append(int(l))  
        return rdata,rlabel  



 

 # ------------softmax回归的模型------------------
def softmax_model():
    sess=tf.InteractiveSession()
    """
       placeholder是输入数据的地方,第一个参数是数据类型,第二个参数代表tensor的shape,也就是数据的尺寸
       ,这里None代表不限条数的输入,784代表每条输入是一个784维的向量
    """
    x=tf.placeholder(tf.float32,[None,784],name='x')  # 训练集的输入数据
    w=tf.Variable(tf.zeros([784,10]))    # softmax回归的权重值
    b=tf.Variable(tf.zeros([10]))        # softmax回归的参数值

    y=tf.nn.softmax(tf.matmul(x,w)+b,name='y')     # softmax回归的公式定义
    y_=tf.placeholder(tf.float32,[None,10],name='y_')  # 真实的label输入
    cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1]))  #交叉熵的定义,类似损失函数,
    train_step=tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)  # 梯度下降法,学习率为0.5
    tf.global_variables_initializer().run()    # 初始化全局变量
    
    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl") 
    # 开始训练数据   
    for i in range(1000):
    	batch_x,batch_y=mnist.next_train_batch()    	
    	train_step.run({x:batch_x,y_:batch_y})
    
    # 训练完成后计算准确率
    correction_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))  # 预测结果类别和真实类别是否相同

    accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32)) # 转换为float值,并求平均

    test_data,test_label=mnist.test_data()   # 获得测试数据和训练数据

    print (accuracy.eval({x:test_data,y_:test_label}))  # 将测试数据输入评测流程accuracy,计算准确率

    # 保存模型
    saver = tf.train.Saver() 
    save_path = saver.save(sess,"./Softmax/model.ckpt")  
    print("save model:{0} Finished".format(save_path))    

# 加载训练好的 softmax 回归模型用于预测
def load_softmax():

    # 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
    saver = tf.train.import_meta_graph("./Softmax/model.ckpt.meta")  

    sess=tf.InteractiveSession()    

    # 即将固化到硬盘中的Session从保存路径再读取出来
    saver.restore(sess,'./Softmax/model.ckpt')

    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
    data,label=mnist.test_data()

    graph = tf.get_default_graph()

    # 通过张量的名称来获取张量
    x = graph.get_tensor_by_name("x:0")  
    logits = graph.get_tensor_by_name("y:0")     

    # 填充需要预测的样本点
    feed=np.reshape(data[0],[1,784])    
    feed_dict = {x:feed} 
    
    # 进行预测
    result=sess.run(logits,feed_dict)  

    #输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
    print ("predict result:",tf.argmax(result,1).eval()) 
    print ("real result:",tf.argmax(label[0],0).eval())



#--------多层感知机模型(只有一个隐藏层)--------------
def multi_perceptron():
    sess=tf.InteractiveSession()
    
    # 网络的参数设置
    in_units=784  # 输入节点数
    h1_units=300  # 隐藏层的输出节点数
    w1=tf.Variable(tf.truncated_normal([in_units,h1_units],stddev=0.1))# 隐藏层权重,正太分布,标准差为0.1
    b1=tf.Variable(tf.zeros([h1_units]))         # 隐藏层的偏置
    w2=tf.Variable(tf.zeros([h1_units,10]))      # 输出层的权重
    b2=tf.Variable(tf.zeros([10]))               # 输出层的偏置
    
    # 网络的输入值
    x=tf.placeholder(tf.float32,shape=[None,in_units],name='x') # 网络的输入,注意要命名
    keep_prob=tf.placeholder(tf.float32,name='keep_prob')      # Dropout比率,注意命名
    y_=tf.placeholder(tf.float32,[None,10],name='y_')        # 真实的label,注意命名

    # 网络各层的计算
    hidden1=tf.nn.relu(tf.matmul(x,w1)+b1)         # 隐藏层的模型
    hidden1_drop=tf.nn.dropout(hidden1,keep_prob)  # Dropout:随机将一部分节点置0
    y=tf.nn.softmax(tf.matmul(hidden1_drop,w2)+b2,name='y') # 输出层的模型,注意命名
    
    # 定义损失函数和优化器
    cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1])) #定义交叉熵为损失函数
    train_step=tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)  # 定义优化方法,学习率为0.3
    

    # 开始训练
    tf.global_variables_initializer().run()
    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
    for i in range(1000):
        batch_x,batch_y = mnist.next_train_batch()        
        train_step.run({x:batch_x,y_:batch_y,keep_prob:0.75})        

    # 计算测试集上的准确率
    correction_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))     
    accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32))
    test_data,test_label=mnist.test_data()
    print (accuracy.eval({x:test_data,y_:test_label,keep_prob:1.0}))
    
    # 保存模型的参数
    saver = tf.train.Saver() 
    save_path = saver.save(sess,"./MLP/model.ckpt")  #保存模型,生成了4个文件:.data、.index、.meta、checkpoint
    print("save model:{0} Finished".format(save_path))


# 加载训练好的MLP模型用于预测
def load_mlp():

    # 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
    saver = tf.train.import_meta_graph("./MLP/model.ckpt.meta")  

    sess=tf.InteractiveSession()    

    # 即将固化到硬盘中的Session从保存路径再读取出来
    saver.restore(sess,'./MLP/model.ckpt')

    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
    data,label=mnist.test_data()

    graph = tf.get_default_graph()

    # 通过张量的名称来获取张量
    x = graph.get_tensor_by_name("x:0")  
    logits = graph.get_tensor_by_name("y:0") 
    keep_prob=graph.get_tensor_by_name("keep_prob:0")

    # 填充需要预测的样本点
    feed=np.reshape(data[0],[1,784])    
    feed_dict = {x:feed,keep_prob:1.0} 
    
    # 进行预测
    result=sess.run(logits,feed_dict)  

    #输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
    print ("predict result:",tf.argmax(result,1).eval()) 
    print ("real result:",tf.argmax(label[0],0).eval())



# -----------卷积神经网络---------------------------
def CNN():
    sess=tf.InteractiveSession()

    x=tf.placeholder(tf.float32,[None,784],name='x')
    y_=tf.placeholder(tf.float32,[None,10],name='y_')
    x_image=tf.reshape(x,[-1,28,28,1]) #转为28*28的原始结构,第一个-1代表数量不确定,最后一个-1代表通道
    
    # 第一个卷积层的定义
    w_conv1=weight_variable([5,5,1,32]) # 初始化第一个卷积层卷积核参数
    b_conv1=bias_variable([32])  # 初始化第一个卷积层的偏置
    h_conv1=tf.nn.relu(conv2d(x_image,w_conv1)+b_conv1)  # 第一个卷积层的卷积运算
    h_pool1=max_pool_2x2(h_conv1)    # 第一个卷积层的池化运算

    # 第二个卷积层的定义
    w_conv2=weight_variable([5,5,32,64]) # 初始化第二个卷积层卷积核参数
    b_conv2=bias_variable([64])  # 初始化第二个卷积层的偏置
    h_conv2=tf.nn.relu(conv2d(h_pool1,w_conv2)+b_conv2)  # 第二个卷积层的卷积运算
    h_pool2=max_pool_2x2(h_conv2)    # 第二个卷积层的池化运算  

    # 全连接层
    w_fc1=weight_variable([7*7*64,1024])
    b_fc1=bias_variable([1024])
    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层
    keep_prob=tf.placeholder(tf.float32,name='keep_prob')
    h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)

    # Softmax层
    w_fc2=weight_variable([1024,10])
    b_fc2=bias_variable([10])
    y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop,w_fc2)+b_fc2,name='y')

    # 定义交叉熵和优化器
    cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv),reduction_indices=[1]))
    train_step=tf.train.AdagradOptimizer(1e-4).minimize(cross_entropy)

    # 用于保存模型的Saver类
    saver = tf.train.Saver(max_to_keep=10)    # 保存最新的10个文件,默认为 5个      

    # 开始训练
    tf.global_variables_initializer().run()
    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl") 
    
    start=time.time()
    print ("begin training...")     
    for i in range(20000):
        batch_x,batch_y = mnist.next_train_batch()        
        train_step.run(feed_dict={x:batch_x,y_:batch_y,keep_prob:0.5})

        # 每1000轮保存一次中间结果
        if i%1000 ==0:
            save_path=saver.save(sess,"./testCNN/model.ckpt",global_step=i)
            print("save model:{0} Finished".format(save_path))
      
    # 计算准确率
    correction_prediction=tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))     
    accuracy=tf.reduce_mean(tf.cast(correction_prediction,tf.float32))
    test_data,test_label=mnist.test_data()
    print (accuracy.eval(feed_dict={x:test_data,y_:test_label,keep_prob:1.0}))    
    print ("cast time:",time.time() - start)
           
# 加载训练好的CNN模型用于预测
def load_cnn():

    # 加载了TensorFlow计算图上定义的全部变量 ,直接加载持久化的图
    saver = tf.train.import_meta_graph("./CNN/model.ckpt-19000.meta")  

    sess=tf.InteractiveSession()    

    # 即将固化到硬盘中的Session从保存路径再读取出来,需要指定保存的文件名
    # saver.restore(sess,'./CNN/model.ckpt-19000')

    # 获取最新的模型,只需要指定保存模型的目录即可
    ckpt=tf.train.get_checkpoint_state('./CNN/') 
    saver.restore(sess, ckpt.model_checkpoint_path) 

    mnist=mnistReader(mnistPath="E:/testdata/mnist.pkl")
    data,label=mnist.test_data()

    graph = tf.get_default_graph()

    # 通过张量的名称来获取张量
    x = graph.get_tensor_by_name("x:0")  
    logits = graph.get_tensor_by_name("y:0") 
    keep_prob=graph.get_tensor_by_name("keep_prob:0")

    # 填充需要预测的样本点
    feed=np.reshape(data[0],[1,784])    
    feed_dict = {x:feed,keep_prob:1.0} 
    
    # 进行预测
    result=sess.run(logits,feed_dict)  

    #输出结果,返回最大的数的下标,1代表1维,返回一个tensor,用eval()来去取出tensor的值
    print ("predict result:",tf.argmax(result,1).eval()) 
    print ("real result:",tf.argmax(label[0],0).eval())

# 权重初始化函数,正太分布,方差为0.1
def weight_variable(shape):
    initial =tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(initial)

# 偏置初始化函数,常数0.1
def bias_variable(shape):
    initial=tf.constant(0.1,shape=shape)
    return tf.Variable(initial)

# 2维卷积层
'''
    x为输入
    w为卷积核参数,如[5,5,1,32],前面两个代表核尺寸,第三个代表通道,最后一个是核数量
    strides为卷积核移动步长,都是1代表不遗漏的划过每个点
    padding为边界处理填充方式
'''
def conv2d(x,w):
    return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding='SAME') 

# 2维池化层
'''
    ksize为池化核大小,这里为2*2
    strides步长这里设为横竖两个方向以2为步长
'''
def max_pool_2x2(x):
    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

#-----------------------------------------------------------------------------


if __name__ == '__main__':
    # softmax_model()  # softmax回归得到的准确率大概为0.92左右
    # load_softmax() # 加载softmax回归保存的模型

    # multi_perceptron() # 多层感知机得到的准确率大概为0.98左右
    # load_mlp()   # 加载多层感知机保存的模型用于预测

    CNN()  # 卷积神经网络据说可以达到0.99的准确率,没跑过
    # load_cnn() # 加载CNN保存的模型用于预测



猜你喜欢

转载自blog.csdn.net/mou_it/article/details/80600656