一 基本流程
1.python脚本中定义自己的模型,训练完成后将tensorflow graph定位导出为protobuf的二进制文件或者文本文件(一个仅有tensor定义但是不含有权重参数的文件);
2.python脚本训练过程保存模型参数文件*.ckpt;
3.调用tensorflow自带的freeze_graph.py小工具,输入格式为*.pb活在*.pbtxt的protobuf文件和*.ckpt的参数文件,输出为一个新的同时包含图定义和参数的*.pb文件(这个步骤的作用是把checkpoint .ckpt文件中的参数转化为常量const operator后和之前的tensor定义绑在一起)。
二 具体操作
1.几个用到的python API
(1)tf.train.write_graph
write_graph(
graph_or_graph_def,
logdir,
name,
as_text=True
)
The graph is written as text proto unless as_text is False.
v = tf.Variable(0, name='my_variable')
sess = tf.Session()
tf.train.write_graph(sess.graph_def, '/tmp/my-model', 'train.pbtxt')
or
v = tf.Variable(0, name='my_variable')
sess = tf.Session()
tf.train.write_graph(sess.graph, '/tmp/my-model', 'train.pbtxt')
Args:
- graph_or_graph_def: A Graph or a GraphDef protocol buffer.
- logdir:Directory where to write the graph. This can refer to remote fiesystems, such as Google Cloud Storage (GCS).
- name:Filename for the graph.
- as_text: If True ,writes the graph as an ASCII proto.
Returns:
The path of the output proto file.
(2)tf.name_scope
Aliases:
- tf.contrib.keras.backend.name_scope
- tf.name_scope
name_scope(
name,
default_name=None,
values=None
)
For example, to define a new python op called my_op:
def my_op(a, b, c, name=None):
with tf.name_scope(name, "MyOp", [a, b, c]) as scope:
a = tf.convert_to_tensor(a, name="a")
b = tf.convert_to_tensor(b, name="b")
c = tf.convert_to_tensor(c, name="c")
# Define some computation that uses `a`, `b`, and `c`.
return foo_op(..., name=scope)
Args:
- name: The name argument that is passed to the op function.
- default_name:The default name to use if the name argument is None.
- values: The list of Tensor arguments that are passed to the op function.
Returns:
A context manager for use in defining Python ops. Yields the name scope.
Raises:
- ValueError: if neither name nor default_name is provided but values are.
2.操作举例
用一个简单的脚本,来训练一个包含1个隐含层的ANN模型来对Iris数据集分类,模型每层节点数:【5,64,3】
具体脚本参考:https://github.com/rockingdingo/tensorflow-tutorial
(1)定义Graph中输入和输出tensor名称
为了方便我们在调用C++ API时,能够准确根据Tensor的名称取出对应的结果,在Python脚本训练时就定义好每个tensor的tensor_name。如果tensor包含命名空间namespace的如“namespace_A/tensor_A"需要用完整的名称。
在这个例子中,我们定义以下三个tensor的tensorname:
class TensorNameConfig(object):
input_tensor = "inputs"
target_tensor = "target"
output_tensor = "output_node"
# To Do
(2)输出graph的定义文件*.pb和参数文件*.ckpt
我们要在训练的脚本nn_model.py中加入两处代码:
第一处是将tensorflow的graph_def保存成./models/目录下一个文件nn_model.pbtxt,里面包含由图中各个tensor的定义名称等信息;
第二处是在训练代码红加入保存参数文件的代码,将训练好的ANN模型的权重Weight和Bias同时保存到./ckpt目录下的*.ckpt,*.meta等文件。
最后执行python nn_model.py就可以完成训练过程。
# 保存图模型
tf.train.write_graph(session.graph_def, FLAGS.model_dir, "nn_model.pbtxt", as_text=True)
# 保存 Checkpoint
checkpoint_path = os.path.join(FLAGS.train_dir, "nn_model.ckpt")
model.saver.save(session, checkpoint_path)
# 执行命令完成训练过程
python nn_model.py
(3)使用freeze_graph.py小工具整合模型freeze_graph
最后利用tensorflow自带的freeze_graph.py小工具把.ckpt文件中的参数固定在graph内,输出nn_model_frozen.pb
# 运行freeze_graph.py 小工具
# freeze the graph and the weights
python freeze_graph.py --input_graph=../model/nn_model.pbtxt --input_checkpoint=../ckpt/nn_model.ckpt --output_graph=../model/nn_model_frozen.pb --output_node_names=output_node
# 或者执行
sh build.sh
# 成功标志:
# Converted 2 variables to const ops.
# 9 ops in the final graph.
Args:
- --input_graph:模型的图的定义文件nn_model.pb(不包含权重);
- --input_checkpoint:模型的参数文件nn_model.ckpt;
- --output_graph:绑定后包含参数的图模型文件nn_model_frozen.pb;
- --output_node_names:输出待机算的tensor名字