保存模型并不限于在训练之后,在训练之中也需要保存,因为TensorFlow训练模型时难免会出现中断的情况。我们自然希望能够将辛苦得到的中间参数保留下来,否则下次又要重新开始。
这种在训练中保存模型,习惯上称之为保存检查点。
实例1:为模型添加保存检查点
实例描述
为一个线性回归任务的模型添加“保存检查点”功能。通过该功能,可以生成载入检查点文件,并能够指定生成检测点文件的个数。该例与保存模型的功能类似,只是保存的位置发生了些变化,我们希望在显示信息时将检查点保存起来,于是就将保存位置放在了迭代训练中的打印信息后面。
另外,本例用到了saver的另一个参数——max_to_keep=1,表明最多只保存一个检查点文件。在保存时使用了如下代码传入了迭代次数。
saver.save(sess, savedir+"linermodel.cpkt", global_step=epoch)
TensorFlow会将迭代次数一起放在检查点的名字上,所以在载入时,同样也要指定迭代次数。
saver.restore(sess2, savedir+"linermodel.cpkt-" + str(load_epoch))
完整的代码如下:
代码4-6 保存检查点
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
#定义生成loss可视化的函数
plotdata = { "batchsize":[], "loss":[] }
def moving_average(a, w=10):
if len(a) < w:
return a[:]
return [val if idx < w else sum(a[(idx - w):idx]) / w for idx, val in enumerate(a)]
#生成模拟数据
train_X = np.linspace(-1, 1, 100)
train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3 # y=2x,但是加入了噪声
#图形显示
plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.legend()
plt.show()
tf.reset_default_graph()
# 创建模型
# 占位符
X = tf.placeholder("float")
Y = tf.placeholder("float")
# 模型参数
W = tf.Variable(tf.random_normal([1]), name="weight")
b = tf.Variable(tf.zeros([1]), name="bias")
# 前向结构
z = tf.multiply(X, W)+ b
#反向优化
cost =tf.reduce_mean( tf.square(Y - z))
learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) #梯度下降
# 初始化所有变量
init = tf.global_variables_initializer()
# 定义学习参数
training_epochs = 20
display_step = 2
saver = tf.train.Saver(max_to_keep=1) # 生成saver
savedir = "log/"
# 启动图
with tf.Session() as sess:
sess.run(init)
# 向模型中输入数据
for epoch in range(training_epochs):
for (x, y) in zip(train_X, train_Y):
sess.run(optimizer, feed_dict={X: x, Y: y})
# 显示训练中的详细信息
if epoch % display_step == 0:
loss = sess.run(cost, feed_dict={X: train_X, Y: train_Y})
print("Epoch:", epoch + 1, "cost=", loss, "W=", sess.run(W), "b=", sess.run(b))
if not (loss == "NA"):
plotdata["batchsize"].append(epoch)
plotdata["loss"].append(loss)
saver.save(sess, savedir + "linermodel.cpkt", global_step=epoch)
print(" Finished!")
print("cost=", sess.run(cost, feed_dict={X: train_X, Y: train_Y}), "W=", sess.run(W), "b=", sess.run(b))
# 显示模型
plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line')
plt.legend()
plt.show()
plotdata["avgloss"] = moving_average(plotdata["loss"])
plt.figure(1)
plt.subplot(211)
plt.plot(plotdata["batchsize"], plotdata["avgloss"], 'b--')
plt.xlabel('Minibatch number')
plt.ylabel('Loss')
plt.title('Minibatch run vs. Training loss')
plt.show()
#重启一个session ,载入检查点
load_epoch = 18
with tf.Session() as sess2:
sess2.run(tf.global_variables_initializer())
saver.restore(sess2, savedir + "linermodel.cpkt-" + str(load_epoch))
print("x=0.2,z=", sess2.run(z, feed_dict={X: 0.2}))
上面代码运行完后,会看到在log文件夹下多了几个linermodel.cpkt-18*文件,就是检查点文件。
这里使用tf.train.Saver(max_to_keep=1)代码创建saver时传入的参数max_to_keep=1代表:在迭代过程中只保存一个文件。这样,在循环训练过程中,新生成的模型就会覆盖以前的模型。
注意: 如果觉得通过指定迭代次数比较麻烦,还有一个好方法可以快速获取到检查点文件。示例代码如下:
ckpt = tf.train.get_checkpoint_state(ckpt_dir)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
还可以再简洁一些,写成以下这样:
kpt = tf.train.latest_checkpoint(savedir)
if kpt!=None:
saver.restore(sess, kpt)
实例2:更简便地保存检查点
本例中介绍另一种更简便地保存检查点功能代码的方法——tf.train.MonitoredTraining Session函数。该函数可以直接实现保存及载入检查点模型的文件。与前面的方式不同,本例中并不是按照循环步数来保存,而是按照训练时间来保存的。通过指定save_checkpoint_secs参数的具体秒数,来设置每训练多久保存一次检查点。
实例描述
演示使用MonitoredTrainingSession函数来自动管理检查点文件。具体代码如下:
代码4-7 trainMonitored
import tensorflow as tf
tf.reset_default_graph()
global_step = tf train.get_or_create_global_step()
step = tf.assign_add(global_step, 1)
#设置检查点路径为log/checkpoints
with tf.train.MonitoredTrainingSession(checkpoint_dir='log/checkpoints', save_checkpoint_secs = 2) as sess:
print(sess.run([global_step]))
while not sess.should_stop(): #启用死循环,当sess不结束时就不停止
i = sess.run( step)
print( i)
运行代码,得到如下输出:
252 12851
252 12852
252 12853
252 12854
252 12855
252 12856
将程序停止,可以看到log/checkpoints
下面生成了检测点文件model.ckpt-8968.meta
。再次运行代码,输出如下:
252 8969
252 8970
252 8971
可见,程序自动载入检查点文件是从第8969次开始运行的。
注意:
如果不设置save_checkpoint_secs参数,默认的保存时间间隔为10分钟。这种按照时间保存的模式更适用于使用大型数据集来训练复杂模型的情况。
使用该方法时,必须要定义global_step变量,否则会报错误。