在反向传播过程中,一般会间隔一定轮数保存一次神经网络模型,并产生三个文件(保存当前图结构.meta文件、保存当前参数名.index文件、保存当前参数的.data文件)。
saver=tf.train.Saver()
with tf.Session() as sess:
for i in range(STEPS):
if i%轮数 == 0:
saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),
global_step=global_step)
其中,tf.train.Saver用来实例化对象。每隔一定训练轮数将神经网络中所有的参数信息保存到指定的路径中,并在文件名称中标明保存时的训练轮数。
with tf.Session() as sess:
ckpt=tf.train.get_checkpoint_state(路径)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess,ckpt.model_checkpoint_path)
ckpt会识别最新的训练模型并加载到当前会话sess。
在保存模型时,若模型采用滑动平均,则参数的滑动平均值会被保存到响应文件中。通过实例化saver对象,实现参数滑动平均值的加载,加载时的代码如下:
ema=tf.train.ExponentialMovingAverage(滑动平均基数)
ema_restore=ema.variabls_to_restore)_
saver=tf.train.Saver(ema_restore)
在网络评估中,通过计算在一组数据(mnist自带的test集)上的识别准确率,评估神经网络的效果。在TensorFlow中这样表示:
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
实现手写mnist数据集的识别任务,共分为三个模块文件,分别是描述网络结构的前向传播文件(mnist_forward.py)、描述网络参数优化的反向传播文件(mnist_backward.py)、验证模型准确率的测试过程文件(mnist_test.py)
import tensorflow as tf
INPUT_NODE=784
OUTPUT_NODE=10
LAYER1_NODE=500
def get_weight(shape, regularizer):
w=tf.Variable(tf.truncated_normal(shape,stddev=0.1))
if regularizer != None:
tf.add_to_collection("losses",tf.contrib.layers.l2_regularizer(regularizer)(w))
return w
def get_bias(shape):
b=tf.Variable(tf.zeros(shape))
return b
def forward(x,regularizer):
w1=get_weight([INPUT_NODE,LAYER1_NODE],regularizer)
b1=get_bias([LAYER1_NODE])
y1=tf.nn.relu(tf.matmul(x,w1)+b1)
w2=get_weight([LAYER1_NODE,OUTPUT_NODE],regularizer)
b2=get_bias([OUTPUT_NODE])
y=tf.matmul(y1,w2)+b2
return y
由上述代码可知,在前向传播过程中,规定网络输入结点为784个,隐藏层结点为500个,输入结点为10个。由输入层到隐藏层的参数w1形状是[784,500],由隐藏层到输出层的参数w2形状是[500,10],参数满足截断正态分布,并使用正则化,将每个参数的正则化损失函数加到总损失中。前向传播结构第一层为输入x与参数w1矩阵相乘加上偏置b1,再经过relu函数,得到隐藏层输出y1。前向传播结构第二层为隐藏层输出y1与参数w2矩阵相乘加上偏置b2,得到输出y。由于输出y要经过softmax函数,使其符合概率分布,故输出y不经过relu函数。
关于正则化:在get_weight函数中,将所有参数w正则化后加入到集合losses中(tf.add_to_collection()语句),在下面的backward.py中的tf.add_n(tf.get_collection('losses’))将集合losses中的所有正则化项加入总loss。
反向传播过程中实现利用训练数据集对神经网络模型训练,通过降低损失函数值,改变模型参数实现模型优化,从而得到准确率高且泛化能力强的模型。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import os
BATCH_SIZE=200
LEARNING_RATE_BASE=0.1
LEARNING_RATE_DECAY=0.99
REGULARIZER=0.0001
STEPS=50000
MOVING_AVERAGE_DECAY=0.99
MODEL_SAVE_PATH="./model/"
MODEL_NAME="mnist_model"
def backward(mnist):
x=tf.placeholder(tf.float32,[None,mnist_forward.INPUT_NODE])
y_=tf.placeholder(tf.float32,[None,mnist_forward.OUTPUT_NODE])
y=mnist_forward.forward(x,REGULARIZER)
global_step=tf.Variable(0,trainable=False)
ce=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
cem=tf.reduce_mean(ce)
loss=cem+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)
ema=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
ema_op=ema.apply(tf.trainable_variables())
with tf.control_dependencies([train_step,ema_op]):
train_op=tf.no_op(name='train')
saver=tf.train.Saver()
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)
ckpt=tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess,ckpt.model_checkpoint_path)
for i in range(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})
if i%1000 ==0:
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():
mnist=input_data.read_data_sets('./mnist_data/',one_hot=True)
backward(mnist)
if __name__=='__main__':
main()
在反向传波函数backward中,首先读入mnist,用placeholder给训练数据x和标签y_占位,调用mnist_forward文件中的forward()定义前向传播过程,设置正则化losses,计算训练集上的也测结果y,并给当前轮数计数器赋值,设定为不可训练。接着,调用包含所有参数正则化损失的损失函数loss,并设定指数衰减学习率learning_rate。然后,在with结构中,实现所有参数初始化,每次喂入batch_size组训练数据集和对应标签,循环迭代STEPS轮,每隔1000轮打印损失函数值信息,并将当前会话加载到指定路径。最后,通过主函数main(),加载指定路径下的训练数据集,并调用规定的backward()函数训练模型。
训练完模型后,用mnist数据集的测试集(test)对模型准确率进行验证。测试集和训练集是独立的。
import tensorflow as tf
import time
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import mnist_backward
TEST_INTERVAL_SECS=5
def test(mnist):
with tf.Graph().as_default() as g:
x=tf.placeholder(tf.float32,[None,mnist_forward.INPUT_NODE])
y_=tf.placeholder(tf.float32,[None,mnist_forward.OUTPUT_NODE])
y=mnist_forward.forward(x,None)
ema=tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
ema_restore=ema.variables_to_restore()
saver=tf.train.Saver(ema_restore)
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
while True:
with tf.Session() as sess:
ckpt=tf.train.get_checkpoint_state(mnist_backward.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={x:mnist.test.images,y_:mnist.test.labels})
print("After %s training step(s), test accuracy = %g"%(global_step,accuracy_score))
else:
print("No checkpoint file found")
return
time.sleep(TEST_INTERVAL_SECS)
def main():
mnist=input_data.read_data_sets("./mnist_data/",one_hot=True)
test(mnist)
if __name__=='__main__':
main()
在上述代码中,首先引入time模块、tensorflow模块、input_data模块、前向传播模块、反向传播模块和os模块,规定5s的循环间隔时间。利用tf.Graph()复现之前定义好的计算图,利用placeholder给训练数据x和标签y_占位,调用mnist_forward文件的forward()函数。然后实例化具有滑动平均的saver对象,从而在会话被加载时模型中的所有参数被赋值为各自的滑动平均值,增强模型的稳定性。在with结构中,加载指定路径下的ckpt,若模型存在,则加载到当前会话,在测试数据集上进行准确率验证,并打印出当前轮数下的准确率;若模型不存在,则打印出模型不存在的提示,从而test()函数完成。通过主函数main(),加载指定路径下的测试数据集,并调用规定的test函数进行准确率验证。
可以看出模型在测试集上的准确率在不断上升,大约为97%,有比较好的泛化能力。
中国大学mooc《人工智能实践:Tensorflow笔记》