Tensorflow:模型保存和服务

Posted -柚子皮-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tensorflow:模型保存和服务相关的知识,希望对你有一定的参考价值。

tensorflow模型保存和使用

Tensorflow的保存分为四种:

1. checkpoint模式;
2. saved_model模式(包含pb文件和variables);
3. 纯pb模式;(只有一个pb文件)
4. keras的 h5 模式

方法比较多,按先进度写吧。

tf.saved_model模块

模型保存

示例1
session.graph._unsafe_unfinalize()

tf.saved_model.simple_save(
    session, export_dir=self.serving_root, inputs=self.serving_model_inputs,
    outputs=self.serving_model_outputs
)

session.graph.finalize()

保存结束之后,会得到下面的模型文件

|---------saved_model

          |---------variables

                     |---------variables.data-00000-of-00001

                     |---------variables.index

          |--------saved_model.pb

Note: 需要保存的文件夹export_dir文件夹不能事先存在,否则会提示已经存在了,不能保存模型。

示例2:tf.saved_model.simple_save内部实现
from tensorflow.python.framework import ops
from tensorflow.python.saved_model import builder
from tensorflow.python.saved_model import signature_constants
from tensorflow.python.saved_model import signature_def_utils
from tensorflow.python.saved_model import tag_constants
signature_def_map =
    signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
        signature_def_utils.predict_signature_def(self.serving_model_inputs, self.serving_model_outputs)

b = builder.SavedModelBuilder(self.serving_root)
b.add_meta_graph_and_variables(
    session,
    tags=[tag_constants.SERVING],
    signature_def_map=signature_def_map,
    assets_collection=ops.get_collection(ops.GraphKeys.ASSET_FILEPATHS),
    main_op=None,
    clear_devices=True)
b.save(as_text=True)

[tf.saved_model.simple_save]

SavedModel的结构

以SavedModel格式保存模型时,tensorflow将创建一个SavedModel目录,该目录由以下子目录和文件组成:

assets/
assets.extra/
variables/
    variables.data-?????-of-?????
    variables.index
saved_model.pb

各目录和文件的说明如下:

assets/是包含辅助(外部)文件(如词汇表)的子文件夹。资产被复制到SavedModel位置,并且可以在加载特定的MetaGraphDef时读取。
assets.extra是一个子文件夹,高级库和用户可以将自己的资源添加进去,这些资源将与模型共存但不由图形加载。此子文件夹不由SavedModel库管理。
variables/是包含tf.train.saver输出的子文件夹。
saved_model.pb或saved_model.pbtxt是SavedModel协议缓冲区。它将图形定义作为MetaGraphDef协议缓冲区。
assets/和assets.extra目录是可选的。

checkpoint与savedmodel其实也很结构上面相似的地方,

第一:在checkpoint中,graph的结构是存储在 xxx.meta文件中的,而真正的变量参数是存储的data文件中;savedmodel其实也是类似的, xxx.pb 文件仅仅保存graph的结构,真正的变量是存储的variables里面的,
第二:但是也有不同的地方,  xxx.pb  文件还可以保存常量,所以我可以将变量的值转化为常量,也就是所谓的freezing,然后整个graph结构以及各个常量、变量的值都可以存储在一个 pb 文件中了;
第三:另外,pb文件还可以使用签名,方便graph的重构与恢复

[tensorflow1.x版本的savedmodel格式的模型保存与加载]

模型读取|变量恢复

dataset = tf.data.TFRecordDataset(done_tffilenames[0]).take(1000)
dataset = dataset.apply(tf.data.experimental.ignore_errors())
dataset = dataset.batch(1).prefetch(1)
dataset_iterator = tf.data.make_initializable_iterator(dataset)
raw_inputs = dataset_iterator.get_next()
print("raw_inputs:".format(raw_inputs))

with tf.Session() as sess:
    print('Loading from '.format(local_model_dir))
    meta_graph = tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], local_model_dir)

    op_list = sess.graph.get_operations()  # load完后可以直接从sess.graph中获取所有节点
    print("...op.name & op.values...")
    with open("operations.txt", 'a+') as f:
        for index, op in enumerate(op_list):
            if index > 100: break
            print("\\t:\\n".format(str(op.name), str(op.values())))
            f.write(":\\n\\n".format(str(op.name), str(op.values())))

    signature = meta_graph.signature_def
    x = signature['serving_default'].inputs['examples'].name
    y = signature['serving_default'].outputs['output'].name
    model = 'input': x, 'output': y
    print("model:".format(model))

    sess.run([tf.global_variables_initializer(), dataset_iterator.initializer])
    predictions = sess.run(model['output'], feed_dict=model['input']: raw_inputs.eval())
    print("predictions:\\n".format(predictions))

[TensorFlow saved_model 模块]过程

[TensorFlow学习记录:saved_model模块的用法]过程及saved_model_cli工具

[tensorflow1.x版本的savedmodel格式的模型保存与加载]过程

变量恢复时的出错

bug: 在tf.train.import_meta_graph(meta_path)或者tf.saved_model.loader.load时出错:KeyError: '***',一般是tf版本问题,有的版本有一些key有的没有就会出错,save时和load时一定要保证tf版本完全一样。

[Trying to restore model, but tf.train.import_meta_graph(meta_path) raises error]

[KeyError: u'SaveV2' when loading exported model #5639]

-柚子皮-

tf.train.write_graph()方法直接将graph保存成pb文件

[tensorflow1.x版本的savedmodel格式的模型保存与加载]

tf.train.Saver()

TensorFlow是通过构造Graph的方式进行深度学习,任何操作(如卷积、池化等)都需要operator,保存和恢复操作也不例外。在tf.train.Saver()类初始化时,用于保存和恢复的save和restore operator会被加入Graph,所以类初始化操作应在搭建Graph时完成。TensorFlow会将变量保存在二进制checkpoint文件中,这类文件会将变量名称映射到张量值。

tf.train.Saver()是一个类,提供了变量、模型(也称图Graph)的保存和恢复模型方法。

Saver.save(
    sess,  # 必需参数,Session对象
    save_path,  # 必需参数,存储路径
    global_step=None,  # 可以是Tensor, Tensor name, 整型数
    latest_filename=None,  # 协议缓冲文件名,默认为'checkpoint',不用管
    meta_graph_suffix='meta',  # 图文件的后缀,默认为'.meta',不用管
    write_meta_graph=True,  # 是否保存Graph
    write_state=True,  # 建议选择默认值True
    strip_default_attrs=False  # 是否跳过具有默认值的节点)

保存变量

保存变量的例子:

 创建变量
 初始化变量
 实例化tf.train.Saver()
 创建Session并保存

import tensorflow as tf
# Create some variables.
v1 = tf.get_variable("v1_name", shape=[3], initializer = tf.zeros_initializer)
v2 = tf.get_variable("v2_name", shape=[5], initializer = tf.zeros_initializer)

inc_v1 = v1.assign(v1+1)
dec_v2 = v2.assign(v2-1)

# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()

# Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, initialize the variables, do some work, and save the
# variables to disk.
with tf.Session() as sess:
    sess.run(init_op)
    # Do some work with the model.
    inc_v1.op.run()
    dec_v2.op.run()
    # Save the variables to disk.
    save_path = saver.save(sess, "model/model.ckpt")  # 返回一个保存路径的字符串

保存路径中的文件为:

checkpoint:保存当前网络状态的文件
model.data-00000-of-00001
model.index
model.meta:保存Graph结构的文件

可以发现,没有名为 ‘model/model.ckpt’ 的实体文件,表示model目录下所有的文件,其中 ‘model’ 是一个与用户交互的前缀。

恢复变量

从checkpoint文件中提取变量值赋给新定义的变量。

tf.reset_default_graph()
# Create some variables
# !!!variable name必须与保存时的name一致
v1 = tf.get_variable("v1_name", shape=[3])
v2 = tf.get_variable("v2_name", shape=[5])

saver = tf.train.Saver()
with tf.Session() as sess:
    # Restore variables from disk
    saver.restore(sess, "model/model.ckpt")
    print("v1: %s" % v1.eval())
    print("v2: %s" % v2.eval())
'''output
INFO:tensorflow:Restoring parameters from model/model.ckpt
v1: [ 1.  1.  1.]
v2: [-1. -1. -1. -1. -1.]
'''

选择要保存和恢复的变量

向tf.train.Saver()的构造函数传递以下任意内容来轻松指定要保存或加载的名称和变量:

变量列表(要求变量与变量名之间的一一对应)
Python字典,其中,key是要使用的名称,value是要管理的变量(通过键值映射自定义变量与变量名之间的对应关系)

tf.reset_default_graph()
v1 = tf.get_variable("v1", [3], initializer = tf.zeros_initializer)
v2 = tf.get_variable("v2", [5], initializer = tf.zeros_initializer)
saver = tf.train.Saver("v2_name": v2)
with tf.Session() as sess:
    v1.initializer.run()
    saver.restore(sess, "model/model.ckpt")
    print("v1: %s" % v1.eval())
    print("v2: %s" % v2.eval())
'''output
INFO:tensorflow:Restoring parameters from model/model.ckpt
v1: [ 0.  0.  0.]
v2: [-1. -1. -1. -1. -1.]
'''

Note:1 如果需要保存和恢复模型变量的不同子集,您可以根据需要创建任意数量的Saver对象。同一个变量可以列在多个Saver对象中。
 2 变量的值只有在Saver.restore()方法运行时才会更改,这些变量不需要初始化。
 3 如果您仅在会话开始时恢复模型变量的子集,则必须为其他变量运行初始化 op。

查看ckpt二进制文件中的变量

使用 inspect_checkpoint 库快速检查某个检查点的变量。

Args    Description
file_name    Name of the checkpoint file
tensor_name    Name of the tensor in the checkpoint file
all_tensors    Boolean indicating whether to print all tensors
all_tensor_names    Boolean indicating whether to print all tensor names

from tensorflow.python.tools import inspect_checkpoint as ickpt
ickpt.print_tensors_in_checkpoint_file("model/model.ckpt", tensor_name="v1_name", all_tensors=False)
'''output
tensor_name:  v1_name
[ 1.  1.  1.]
'''

[TensorFlow保存和恢复变量——tf.train.Saver()]

[tensorflow训练好的模型怎么调用?]

[TensorFlow 模型保存/载入的两种方法]

-柚子皮-

estimator模型的保存和服务

estimator模型的保存

引入main.py中写好的model_fn,写一个输入接收器函数serving_input_receiver_fn后,estimator.export_saved_model。

DATADIR = '../../data/example'
PARAMS = './results/params.json'
MODELDIR = './results/model'


def serving_input_receiver_fn():
    """Serving input_fn that builds features from placeholders

    Returns
    -------
    tf.estimator.export.ServingInputReceiver
    """
    words = tf.placeholder(dtype=tf.string, shape=[None, None], name='words')
    nwords = tf.placeholder(dtype=tf.int32, shape=[None], name='nwords')
    receiver_tensors = 'words': words, 'nwords': nwords
    features = 'words': words, 'nwords': nwords
    return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)


if __name__ == '__main__':
    with open(PARAMS, 'r') as f:
        params = json.load(f)

    estimator = tf.estimator.Estimator(model_fn, MODELDIR, params=params)
    estimator.export_saved_model('saved_model', serving_input_receiver_fn)

estimator模型的服务

在export_dir中找到最新的输出模型,predictor.from_saved_model即可。

"""Reload and serve a saved model"""

import os
from tensorflow.contrib import predictor

params = 
    'lang': 'chn',

LINE = '输入的句子'
export_dir = 'saved_model'

if __name__ == '__main__':
    subdirs = [os.path.join(export_dir, x) for x in os.listdir(export_dir) if
               os.path.isdir(os.path.join(export_dir, x)) and 'temp' not in str(x)]
    latest = str(sorted(subdirs)[-1])
    predict_fn = predictor.from_saved_model(latest)

    if params['lang'] == 'chn':
        words = [w.encode('utf-8') for w in LINE.strip()]
    else:
        words = [w.encode() for w in LINE.strip().split()]

    nwords = len(words)
    predictions = predict_fn('words': [words], 'nwords': [nwords])
    print(predictions)

Note: 好像也可以用于load saver保存的模型。待测试。

from: -柚子皮-

ref: 

以上是关于Tensorflow:模型保存和服务的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow 服务:导出模型时“没有要保存/写入的资产”

保存tensorflow模型为pb文件

PyTorch:模型save和load

PyTorch:模型save和load

TensorFlow模型保存和提取方法

如何将保存的模型转换或加载到 TensorFlow 或 Keras?