持久化的基于L2正則化和平均滑動模型的MNIST手寫數字識別模型
覺得有用的話,歡迎一起討論相互學習~Follow Me
參考文獻Tensorflow實戰Google深度學習框架
實驗平臺:
Tensorflow1.4.0
python3.5.0
MNIST數據集將四個文件下載后放到當前目錄下的MNIST_data文件夾下
定義模型框架與前向傳播
import tensorflow as tf# 定義神經網絡結構相關參數
INPUT_NODE = 784
OUTPUT_NODE = 10
LAYER1_NODE = 500# 設置權值函數
# 在訓練時會創建這些變量,在測試時會通過保存的模型加載這些變量的取值
# 因為可以在變量加載時將滑動平均變量均值重命名,所以這個函數可以直接通過同樣的名字在訓練時使用變量本身
# 而在測試時使用變量的滑動平均值,在這個函數中也會將變量的正則化損失加入損失集合def get_weight_variable(shape, regularizer):weights = tf.get_variable("weights", shape, initializer=tf.truncated_normal_initializer(stddev=0.1))# 如果使用正則化方法會將該張量加入一個名為'losses'的集合if regularizer != None: tf.add_to_collection('losses', regularizer(weights))return weights# 定義神經網絡前向傳播過程
def inference(input_tensor, regularizer):with tf.variable_scope('layer1'):weights = get_weight_variable([INPUT_NODE, LAYER1_NODE], regularizer)biases = tf.get_variable("biases", [LAYER1_NODE], initializer=tf.constant_initializer(0.0))layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases)with tf.variable_scope('layer2'):weights = get_weight_variable([LAYER1_NODE, OUTPUT_NODE], regularizer)biases = tf.get_variable("biases", [OUTPUT_NODE], initializer=tf.constant_initializer(0.0))layer2 = tf.matmul(layer1, weights) + biasesreturn layer2
模型訓練與模型框架及參數持久化
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_inference
import os# 配置神經網絡參數
BATCH_SIZE = 100 # 批處理數據大小
LEARNING_RATE_BASE = 0.8 # 基礎學習率
LEARNING_RATE_DECAY = 0.99 # 學習率衰減速度
REGULARIZATION_RATE = 0.0001 # 正則化項
TRAINING_STEPS = 30000 # 訓練次數
MOVING_AVERAGE_DECAY = 0.99 # 平均滑動模型衰減參數
# 模型保存的路徑和文件名
MODEL_SAVE_PATH = "MNIST_model/"
MODEL_NAME = "mnist_model"def train(mnist):# 定義輸入輸出placeholderx = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input') # 可以直接引用mnist_inference中的超參數y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')# 定義L2正則化器regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)# 在前向傳播時使用L2正則化y = mnist_inference.inference(x, regularizer)global_step = tf.Variable(0, trainable=False)# 在可訓練參數上定義平均滑動模型variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)# tf.trainable_variables()返回的是圖上集合GraphKeys.TRAINABLE_VARIABLES中的元素。這個集合中的元素是所有沒有指定trainable=False的參數variables_averages_op = variable_averages.apply(tf.trainable_variables())cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))cross_entropy_mean = tf.reduce_mean(cross_entropy)# 在交叉熵函數的基礎上增加權值的L2正則化部分loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))# 設置學習率,其中學習率使用逐漸遞減的原則learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,mnist.train.num_examples/BATCH_SIZE, LEARNING_RATE_DECAY,staircase=True)# 使用梯度下降優化器train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)# with tf.control_dependencies([train_step, variables_averages_op]):# train_op = tf.no_op(name='train')# 在反向傳播的過程中,不僅更新神經網絡中的參數還更新每一個參數的滑動平均值train_op = tf.group(train_step, variables_averages_op)# 定義Saver模型保存器saver = tf.train.Saver()with tf.Session() as sess:tf.global_variables_initializer().run()for i in range(TRAINING_STEPS):xs, ys = mnist.train.next_batch(BATCH_SIZE)_, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})# 每1000輪保存一次模型if i%1000 == 0:# 輸出當前的訓練情況,這里只輸出了模型在當前訓練batch上的損失函數大小# 通過損失函數的大小可以大概了解訓練的情況,# 在驗證數據集上的正確率信息會有一個單獨的程序來生成print("After %d training step(s), loss on training batch is %g."%(step, loss_value))# 模型保存saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)def main(argv=None):mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)train(mnist)if __name__ == '__main__':tf.app.run()
模型恢復與評價測試集上的效果
import time
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_inference
import mnist_train# 每10秒加載一次最新的模型
# 加載的時間間隔。
EVAL_INTERVAL_SECS = 10def evaluate(mnist):with tf.Graph().as_default() as g:x = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')validate_feed = {x: mnist.validation.images, y_: mnist.validation.labels}# 直接通過調用封裝好的函數來計算前向傳播的結果,因為測試時不關注正則化損失的值所以這里用于計算正則化損失的函數被設置為Noney = mnist_inference.inference(x, None)correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))# 如果需要離線預測未知數據的類別,只需要將計算正確率的部分改為答案的輸出即可。accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))# 通過獲取變量重命名的方式來加載模型,這樣在前向傳播的過程中就不需要調用滑動平均的函數來獲取平均值# 這樣可以完全共用mnist_inference.py重定義的前向傳播過程variable_averages = tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DECAY)variables_to_restore = variable_averages.variables_to_restore()saver = tf.train.Saver(variables_to_restore)while True:with tf.Session() as sess:# tf.train.get_checkpoint_state函數會通過checkpoint文件自動找到目錄中最新模型的文件名ckpt = tf.train.get_checkpoint_state(mnist_train.MODEL_SAVE_PATH)if ckpt and ckpt.model_checkpoint_path:# 加載模型saver.restore(sess, ckpt.model_checkpoint_path)# 通過文件名得到模型保存是迭代的輪數global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]accuracy_score = sess.run(accuracy, feed_dict=validate_feed)print("After %s training step(s), validation accuracy = %g"%(global_step, accuracy_score))else:print('No checkpoint file found')returntime.sleep(EVAL_INTERVAL_SECS)# 每次運行都是讀取最新保存的模型,并在MNIST驗證數據集上計算模型的正確率# 每隔EVAL_INTERVAL_SECS秒來調用一側計算正確率的過程以檢驗訓練過程中的正確率變化# ### 主程序
def main(argv=None):mnist = input_data.read_data_sets("./MNIST_data", one_hot=True)evaluate(mnist)if __name__ == '__main__':main()# After 29001 training step(s), validation accuracy = 0.9854