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})

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM