Tensorflow笔记之Tensorflow模型持久化

本文介绍了如何在Tensorflow中保存和加载神经网络模型,包括使用tf.train.Saver类进行完整模型的保存和加载,选择性保存和加载部分变量,以及如何处理变量的滑动平均。还提到了convert_variables_to_constants函数用于简化模型,方便离线预测。
摘要由CSDN通过智能技术生成

为了让训练结果可以复用,需要将训练得到的神经网络模型持久化。Tensorflow提供了一个非常简单的API来保存和还原一个神经网络,这个API就是tf.train.Saver类,下面代码给出了保存Tensorflow计算图的方法,如下所示
 

import tensorflow as tf
#声明两个变量并计算它们的和。
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)
    #将模型保存到/path/to/model/model/model.ckpt文件
    saver.save(sess,"/path/to/model/model.ckpt")

上述代码通过saver.save函数将Tensorflow模型保存到/path/model/model.ckpt文件中。后缀一般为.ckpt。路径下会出现三个文件。因为Tensorflow会将计算图的结构和图上参数的取值分开保存。生成的第一个文件为model.ckpt.meta,保存Tensorflow计算图的结构。第二个文件为model.ckpt。保存Tensorflow程序中的变量取值。最后一个文件为checkpoint,保存了这个文件下所有模型文件类表。下面代码给出加载这个已经保存的Tensorflow模型方法。

import tensorflow as tf
#使用和保存模型代码中一样的方式来声明变量。
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
saver=tf.train.Saver()
with tf.Session() as sess:
    #加载已经保存的模型,并通过已经保存的模型中变量的值来计算加法
    saver.restore(sess,"/path/to/model/model.ckpt")
    print(sess.run(result))

在加载模型的程序也是先定义Tensorflow计算图上的所有运算,并声明一个tf.train.Saver类。两端代码唯一不同的是,在加载模型的代码中没有运行变量的初始化过程,而是将变量的值通过已保存的模型加载进来。如果不希望重复定义图上的运算,也可以直接加载已经持久化的图,以下代码给出了一个样例。

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

上面给出的程序默认保存和加载了Tensorflow计算图上定义的全部变量。但是有时候可能只需要保存或加载部分变量,比如之前训练好一个五层神经网络,现在想尝试六层,那么可以将前五层神经网络参数直接加载到新的模型中,仅仅将最后一层神经网络重新训练。

为了保存或加载部分变量,在声明tf.train.Saver类时,可以提供一个列表来指定需要保存或者加载的变量。比如在加载模型的代码中使用saver=tf.train.Saver([v1])命令来构建tf.train.Saver类,那么只有变量v1会被加载进来除了可选去需要被加载的变量,tf.train.Saver类也支持在保存或者加载时给变量重命名。下面给出一个简单的样例程序说明重命名是如何被使用的、

#这里声明的变量名称和已经保存的模型中变量的名称不同。
v1=tf.Variable(tf.constant(1.0,shape=[1]),name="other-v1")
v2=tf.variable(tf.constant(2.0,shape=[1]),name="other-v2")
#如果直接使用tf.train.Saver()来加载模型会报变量找不到的错误
#使用一个字典来重命名变量就可以加载原来的模型。
#这个字典制定了原来名称为v1的变量现在加载到变量v1中,名称为other-v1
#名称为v2的变量加载到现在变量v2中,名称为other-v2
saver=tf.train.Saver({"v1":v1,"v2":v2})

Tensorflow可以通过字典将模型保存时的变量名和需要加载的变量联系起来,这样做的目的之一是方便使用变量的滑动平均值。以下代码给出了一个保存滑动平均模型的样例。

import tensorflow as tf
v=tf.Variable(0,dtype=tf.float32,name="v")
#在没有申明滑动平均模型时,只有一个变量v,所以以下语句只会输出“v:0”。
for variables in tf.global_variables():
    print(variables.name)
ema=tf.train.ExponentialMovingAverage(0.99)
maintain_average_op=ema.apply(tf.global_variables())
#在申明滑动平均模型之后,Tensorflow会自动生成一个影子变量
#v/ExponentialMoving Average。于是以下语句会输出
#“V:0”和“v/ExponentialMovingAverage:0”。
for variables in tf.global_variables():
    print(variables.name)
saver=tf.train.Saver()
with tf.Session() as sess:
    init_op=tf.global_variables_initializer()
    sess.run(init_op)
    sess.run(tf.assign(v,10))
    sess.run(maintain_average_op)
    saver.save(sess,"/path/to/model/model.ckpt")
    print(sess.run([v,ema.average(v)]))

以下代码给出了如何通过变量重命名直接读取变量的滑动平均,通过这个方法就可以使用完全一样的代码来计算滑动平均模型前向传播的结果。

v=tf.Variable(0,dtype=tf.float32,name="v")
#通过变量重命名将原来变量v的滑动平均值直接赋值给v
saver=tf.train.Saver({"v/ExponentialMovingAverage":v})
with tf.Session() as sess:
     saver.restore(sess,"/path/to/model/model.ckpt")
     print sess.run(v)#输出为元模型变量v的滑动平均值

为了方便加载时重命名滑动平均变量,tf.train.ExponetialMovingAverage类提供了variables_to_restore函数生成tf.train.Saver类所需的变量重命名字典,代码如下:

import tensorflow as tf
v=tf.Variable(0,dtype=tf.float32,name="v")
ema=tf.train.ExponentialMovingAverage(0.99)
print(ema.variables_to_restore())
saver=tf.train.Saver(ema.variables_to_restore())
with tf.Session() as sess:
    saver.restore(sess,"/path/to/model/model.ckpt")
    print(sess.run(v))

使用tf.train.Saver会保存运行Tensorflow程序所需要的全部信息,然而有时候并不需要某些信息,比如在测试或者离线预测时,只需要知道如何从神经网络的输入层经过前向传播计算输出层即可,而不需要类似变量初始化、模型保存等辅助节点的信息。Tensorflow提供了convert_variables_to_constants函数,通过这个函数可以将计算图中的变量及其取值通过常量的方式保存,从而使整个Tensorflow计算图可以统一存放在一个文件夹中,代码样例如下:

import tensorflow as tf
from tensorflow.python.framework import graph_util
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()
with tf.Session() as sess:
    sess.run(init_op)
    # 导出当前计算图的GraphDef部分,只需要这一部分就可以完成从输入到输出层的计算过程
    graph_def = tf.get_default_graph().as_graph_def()
    # 将图中变量及其取值转化为常量,同时将图中不必要的节点去掉。
    # 在线面一行代码中,最后一个参数['add']给出了需要保存的节点名称。add节点是上面定义
    # 的两个变量相加的操作。注意这里给出的是计算节点的名称,所以没有后面的:0.
    output_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, ['add'])
    #将导出的模型存入文件
    with tf.gfile.GFile("/path/to/model/combine_model.pb","wb") as f:
        f.write(output_graph_def.SerializeToString())

通过下面的程序可以直接计算定义的加法运算,只需要得到计算图中某个节点的取值时,这提供了一个更加方便的方法。

import tensorflow as tf
from tensorflow.python.platform import gfile

with tf.Session() as sess:
    model_filename = "/path/to/model/combined_model.pb"
    # 读取保存的模型文件,并将文件解析成对应的GraphDef Protocol Buffer
    with gfile.FastGFile(model_filename,'rb') as f:
        graph_def=tf.GraphDef()
        graph_def.ParseFromString(f.read())
    # 将graph_def中保存的图加载到当前的图中。return_elements=["add:0"]给出了返回的张量
    # 的名称。在保存的时候给出的是计算节点的名称,所以“add”。在加载的时候给出的是张量的
    # 名称,所以是add:0.
    result=tf.import_graph_def(graph_def,return_elements=["add:0"])
    # 输出[3.0]
    print(sess.run(result))

模型持久化总结:首先声明一个tf.train.Saver,在运行会话的时候保存会话,saver.save(sess),保存了模型

                         加载模型也先声明一个tf.train.Save人,在运行会话时,saver.restore(sess,"路径")

                  直接加载计算图,可以用saver=tf.train.import_meta_graph("路径")

                  在会话中选择性加载变量,声明时可用如下声明:saver=tf.train.Saver([v1])

             ema.variable_to_restore()函数生成tf.train.Saver类所需的滑动平均类所需的字典。

               将变量和计算图结构存放到一个文件夹中convert_variables_to_constants函数,通过常量保存,方便使用。

取出的时候使用代码如下:

 model_filename = "/path/to/model/combined_model.pb"
    # 读取保存的模型文件,并将文件解析成对应的GraphDef Protocol Buffer
    with gfile.FastGFile(model_filename,'rb') as f:
        graph_def=tf.GraphDef()
        graph_def.ParseFromString(f.read())

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值