• TensorFlow学习笔记(三)MNIST数字识别问题


    一、MNSIT数据处理

    MNSIT是一个非常有名的手写体数字识别数据集。包含60000张训练图片,10000张测试图片。每张图片是28X28的数字。

    TonserFlow提供了一个类来处理  MNSIT数据。这个类会自动下载并转化数据结构。

    MNIST Digits

    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist_data = input_data.read_data_sets("mnist_set",one_hot=True)
    # print training data size
    print("training_data_size",mnist_data.train.num_examples)
    # print validation data size
    print("validating_data_size",mnist_data.validation.num_examples)
    #print testing data size
    print("testing data size",mnist_data.test.num_examples)
    print("example train image :",mnist_data.train.images[0])
    print("example train label :",mnist_data.train.labels[0])

    为了方便使用随机梯度下降,

    input_data.read_data_sets还提供train.next_batch函数
    batch_size = 100
    train_x ,train_y = mnist_data.train.next_batch(batch_size)
    print("X_shape",train_x.shape)
    print("Y_shape",train_y.shape)
    
    ##
    #X_shape (100, 784)
    #Y_shape (100, 10)

    二、神经网络模型训练及不同模型效果的对比

    1.TF训练神经网络

    利用上一篇介绍的方法搭建网络。

    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    mnist = input_data.read_data_sets("mnist_set",one_hot=True)
    #数据集相关常数
    INPUT_NODE = 784
    OUTPU_NODE = 10
    #配置神经网络参数
    LAYER1_NODE = 500
    BATCH_SIZE = 100
    LEARNING_RATE_BASE = 0.8 #基础学习率
    LEARNING_RATE_DECAY = 0.99#学习衰减率
    REGULARIZATION_RATE = 0.0001#正则的惩罚系数
    MOVE_AVG_RATE = 0.99 #滑动平均衰减率
    TRAIN_STEPS = 30000
    
    
    def inference(input_tensor,weights1,biases1,weight2,biases2,avg_class=None):
        #当没有提供滑动平均类时,直接使用当前值
        if avg_class == None:
            #计算隐藏层的前向传播结果,使用RELU激活函数
            layer1 = tf.nn.relu(tf.matmul(input_tensor,weights1)+biases1)
            #返回输出层的前向传播
            return tf.matmul(layer1,weight2)+ biases2
        else:
            #前向传播之前,用avg——class计算出变量的滑动平均值
            layer1 = tf.nn.relu(tf.matmul(input_tensor,avg_class.average(weights1))+avg_class.average(biases1))
            return tf.matmul(layer1,avg_class.average(weight2))+ avg_class.average(biases2)
    #模型的训练过程
    def train(mnist):
        x = tf.placeholder(tf.float32,[None,INPUT_NODE],name='x-input')
        y_ = tf.placeholder(tf.float32,[None,OUTPU_NODE],name="y_input")
    
        #隐藏层参数
        w1 = tf.Variable(tf.random_normal([INPUT_NODE,LAYER1_NODE],stddev=0.1))
        b1 = tf.Variable(tf.constant(0.1,shape=[LAYER1_NODE]))
        #输出层参数
        w2 = tf.Variable(tf.random_normal([LAYER1_NODE,OUTPU_NODE],stddev=0.1))
        b2 = tf.Variable(tf.constant(0.1,shape=[OUTPU_NODE]))
        y = inference(x,w1,b1,w2,b2)
        #定义存储训练轮数的变量,设为不可训练
        global_step = tf.Variable(0,trainable=False)
        #初始化滑动平均类
        variable_averages = tf.train.ExponentialMovingAverage(MOVE_AVG_RATE,global_step)
        #在神经网络的所有参数变量上使用滑动平均
        variable_averages_op = variable_averages.apply(tf.trainable_variables())
        averages_y = inference(x,w1,b1,w2,b2,avg_class=variable_averages)
        #计算交叉熵损失
        cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
        #计算交叉熵平均值
        cross_entropy_mean = tf.reduce_mean(cross_entropy)
        #计算L2正则的损失函数
        regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
        regularization = regularizer(w1)+ regularizer(w2)
        #总的损失
        loss = cross_entropy_mean + regularization
    
        #设置指数衰减的学习率
        training_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,mnist.train.num_examples/BATCH_SIZE,LEARNING_RATE_DECAY)
        train_step = tf.train.GradientDescentOptimizer(training_rate).minimize(loss,global_step)
        #更新滑动平均值
        with tf.control_dependencies([train_step,variable_averages_op]):
            train_op = tf.no_op(name='train')
    
        #验证前向传播结果是否正确
        correct_prediction = tf.equal(tf.argmax(averages_y,1),tf.argmax(y_,1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
    
        #初始会话,开始训练
        with tf.Session() as sess:
            tf.global_variables_initializer().run()
            #准备验证数据和测试数据
            validate_feed = {x:mnist.validation.images,y_: mnist.validation.labels}
            test_feed = {x:mnist.test.images,y_: mnist.test.labels}
            #迭代训练神经网络
            for i in range(TRAIN_STEPS):
                if i % 1000 == 0:
                    validate_acc = sess.run(accuracy,feed_dict=validate_feed)
                    print("After %s training steps ,validation accuracy is %s"%(i,validate_acc))
                xs,ys = mnist.train.next_batch(BATCH_SIZE)
                sess.run(train_op,feed_dict={x:xs,y_:ys})
            #训练结束后,在测试集上验证准确率
            test_acc =  sess.run(accuracy,test_feed)
            print("After %s training steps ,test accuracy is %s"%(TRAIN_STEPS,test_acc))
    
    def main(argv=None):
        mnist = input_data.read_data_sets("mnist_set",one_hot=True)
        train(mnist)
    if __name__ == '__main__':
        #TF 提供了一个主程序入口,tf.app.run会自动调用上面的main()
        tf.app.run()

     2.使用验证数据集判断模型效果

    为了评判不同网络在不同参数下的效果,一般从训练数据中抽取一部分作为验证数据,使用验证数据可以评判不同参数下模型的表现。除了使用验证数据,还可以使用交叉验证的方式。

    三、变量管理

    TensorFlow提供了一个通过变量名称来创建或者获取变量的机制。通过这个机制可以,在不同的函数中可以通过变量的名字来使用变量。通过变量名称来获取变量的函数是

    tf.get_variable和tf.variable_scope.

    tf.get_variable除了获取变量,还具有与tf.Variable相似的功能。均可用来创建变量。

    #下面两个定义是等价的
    v = tf.Variable(tf.constant(1.0,shape=[1]),name="v")
    v = tf.get_variable(name="v",shape=[1],initializer=tf.constant_initializer(1.0))

    TF提供了7中不同的初始化函数

    tf.get_variable和tf.Variable最大的区别在于指定变量名称的参数,tf.Variable的变量名称是可选参数,tf.get_variable的变量名称是必填参数。

    如果需要通过tf.get_variable获取一个已经创建的变量,需要通过tf.variable_scope来创建一个上下文管理器,

    with tf.variable_scope("foo"):
        v = tf.get_variable("v",[1],initializer=tf.constant_initializer(1.0))
    #如果命名空间foo中已经存在了v,这会报错
    #ValueError: Variable foo/v already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?
    
    #在声明上下文管理器的时候,直接将reuse设为True,tf。get_variable则会直接获取已经存在的变量,但设为true的时候tf。get_variable不能创建变量
    with tf.variable_scope("foo",reuse=True):
        v1 = tf.get_variable("v",[1])

    TensorFlow中tf.variable_scope函数可以嵌套。

    with tf.variable_scope("root",reuse=True):
        print(tf.get_variable_scope().reuse) #True
        with tf.variable_scope("bar",reuse=False):
            print(tf.get_variable_scope().reuse) #True 与外层的保持一致
            with tf.variable_scope("foo",reuse=False):
                print(tf.get_variable_scope().reuse) #即使指定了reuse,也会保持与外层一致
            print(tf.get_variable_scope().reuse)
        print(tf.get_variable_scope().reuse)
    with tf.variable_scope("root"):
        print(tf.get_variable_scope().reuse) #false
        with tf.variable_scope("bar",reuse=True):
            print(tf.get_variable_scope().reuse)  #true
            with tf.variable_scope("foo"):
                print(tf.get_variable_scope().reuse) #true
            print(tf.get_variable_scope().reuse) #true
        print(tf.get_variable_scope().reuse) #false

    利用tf.get_variable和tf.variable_scope来改进我们MNIST的程序

    def inference(input_tensor,avg_class=None,reuse = False):
        #当没有提供滑动平均类时,直接使用当前值
        if avg_class == None:
            #计算隐藏层的前向传播结果,使用RELU激活函数
            with tf.variable_scope("layer1",reuse=reuse):
                weight = tf.get_variable("weight",shape=[INPUT_NODE,LAYER1_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
                biases = tf.get_variable("biases",shape=[LAYER1_NODE],initializer=tf.constant_initializer(0.0))
                layer1 = tf.nn.relu(tf.matmul(input_tensor,weight)+biases)
            #返回输出层的前向传播
            with tf.variable_scope("layer2",reuse=reuse):
                weight = tf.get_variable("weight",shape=[LAYER1_NODE,OUTPU_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
                biases = tf.get_variable("biases",shape=[OUTPU_NODE],initializer=tf.constant_initializer(0.0))
                layer2 = tf.nn.relu(tf.matmul(layer1,weight)+biases)
            return layer2
        else:
            #前向传播之前,用avg——class计算出变量的滑动平均值
            with tf.variable_scope("layer1",reuse=reuse):
                weight = tf.get_variable("weight",shape=[INPUT_NODE,LAYER1_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
                biases = tf.get_variable("biases",shape=[LAYER1_NODE],initializer=tf.constant_initializer(0.0))
                layer1 = tf.nn.relu(tf.matmul(input_tensor,avg_class.average(weight))+avg_class.average(biases))
            #返回输出层的前向传播
            with tf.variable_scope("layer2",reuse=reuse):
                weight = tf.get_variable("weight",shape=[LAYER1_NODE,OUTPU_NODE],initializer=tf.truncated_normal_initializer(stddev=0.1))
                biases = tf.get_variable("biases",shape=[OUTPU_NODE],initializer=tf.constant_initializer(0.0))
                layer2 = tf.nn.relu(tf.matmul(layer1,avg_class.average(weight))+avg_class.average(biases))
            return layer2

    四、模型的持久化

    之前给出的样例代码在训练完成之后就直接退出,并没有将训练得到的模型保存下来。TF提供了模型的持久化,还可以从持久化的模型文件中还原被保存的模型。

    1、模型持久化的代码实现

    TensorFlow提供了一个简单的API(tf.train.Saver)来保存模型。

    v1 = tf.Variable(tf.constant(1.0,shape=[1],name="v1"))
    v2 = tf.Variable(tf.constant(2.0,shape=[1],name="v2"))
    result = v1 + v2
    init_op = tf.global_variables_initializer()
    #声明tf.train.Saver类用于保存模型
    saver = tf.train.Saver()
    
    with tf.Session() as sess:
        sess.run(init_op)
        #将模型保存到model。ckpt文件中
        saver.save(sess,"Model/model.ckpt")

    加载保存的模型

    v1 = tf.Variable(tf.constant(1.0,shape=[1],name="v1"))
    v2 = tf.Variable(tf.constant(2.0,shape=[1],name="v2"))
    result = v1 + v2
    # init_op = tf.global_variables_initializer()
    #声明tf.train.Saver类用于保存模型
    saver = tf.train.Saver()
    
    with tf.Session() as sess:
        # sess.run(init_op)
        #将模型保存到model。ckpt文件中
        saver.restore(sess,"Model/model.ckpt")
        print(sess.run(result))

    这里加载模型的代码和保存模型的代码基本一致,也需要先定义计算图模型的运算只是没有运行变量初始化。如果不希望重复定义图上的运算,也可以直接加载已经持久化的图。TensorFlow提供了这样的方法tf.train.import_meta_graph

    #直接加载持久化计算图
    saver = tf.train.import_meta_graph("Model/model.ckpt.meta")
    
    with tf.Session() as sess:
    
        saver.restore(sess,"Model/model.ckpt")
        #通过张量的名称来获取张量
        print(sess.run(tf.get_default_graph().get_tensor_by_name("add:0")))

    上面的程序,默认保存或加载了TF计算图中的全部变量。但有时只需要保存或加载部分变量。在声明tf.train.Saver类时可以提供一个列表来制定需要保存或加载的变量。例如

    tf.train.Saver([v1]).

    除了选择需要加载的变量,tf.train.Saver还支持在保存或加载时给变量重命名。

    #保存模型
    
    v1 = tf.Variable(tf.constant(1.0,shape=[1],name="outer_v1"))
    v2 = tf.Variable(tf.constant(2.0,shape=[1],name="outer_v2"))
    result = v1 + v2
    init_op = tf.global_variables_initializer()
    #声明tf.train.Saver类用于保存模型
    saver = tf.train.Saver([v1,v2])
    with tf.Session() as sess:
        sess.run(init_op)
        saver.save(sess,"Model/model.ckpt")
    
    
    
    
    #加载模型
    v1 = tf.Variable(tf.constant(1.0,shape=[1],name="outer_v1"))
    v2 = tf.Variable(tf.constant(2.0,shape=[1],name="outer_v2"))
    saver = tf.train.Saver({"v1":v1,"v2":v2})
  • 相关阅读:
    [模板]RMQ(冲刺准备中)
    洛谷 P2569[SCOI2010]股票交易(动规+单调队列)
    洛谷 P3659 [USACO17FEB]Why Did the Cow Cross the Road I G
    粗略了解fill与fill_n
    计蒜客D2T2 蒜头君的排序(动态维护树状数组)
    洛谷 P3478 [POI2008]STA-Station
    洛谷 P2899 [USACO08JAN]手机网络Cell Phone Network
    洛谷 P3112 [USACO14DEC]后卫马克Guard Mark
    洛谷 P3092 [USACO13NOV]没有找零No Change
    洛谷 P2850 [USACO06DEC]虫洞Wormholes 判负环
  • 原文地址:https://www.cnblogs.com/zuoshoushizi/p/9170751.html
Copyright © 2020-2023  润新知