我正在尝试从两个几乎完全相同的模型中创建一个模型,并在不同条件下对其进行训练,并在张量流内平均其输出。我们希望最终模型具有相同的推理接口。
我们保存了两个模型的检查点,这是我们试图解决问题的方法:
merged_graph = tf.Graph()
with merged_graph.as_default():
saver1 = tf.train.import_meta_graph('path_to_checkpoint1_model1.meta', import_scope='g1')
saver2 = tf.train.import_meta_graph('path_to_checkpoint1_model2.meta', import_scope='g2')
with tf.Session(graph=merged_graph) as sess:
saver1.restore(sess, 'path_to_checkpoint1_model1')
saver1.restore(sess, 'path_to_checkpoint1_model2')
sess.run(tf.global_variables_initializer())
# export as a saved_model
builder = tf.saved_model.builder.SavedModelBuilder(kPathToExportDir)
builder.add_meta_graph_and_variables(sess,
[tf.saved_model.tag_constants.SERVING],
strip_default_attrs=True)
builder.save()
上述方法至少存在3个缺陷,我们尝试了许多路线,但无法使之起作用:
_
Expected exactly one main op in : model
Expected exactly one SavedModel main op. Found: [u'g1/group_deps', u'g2/group_deps']
两个模型都有自己的Placeholder节点用于输入(即合并后的g1 / Placeholder和g2 / Placeholder)。我们无法找到一种方法来删除占位符节点,以创建一个新的占位符节点来为两个模型提供输入(我们不希望有一个新的接口,我们需要将数据输入两个不同的占位符)。
两个图都有自己的init_all,restore_all节点。我们无法弄清楚如何将这些NoOp操作组合到单个节点中。这与问题#1相同。
我们也无法在tensorflow内部找到这种模式集合的示例实现。示例代码可能会回答上述所有问题。
注意:我的两个模型是使用tf.estimator.Estimator训练的,并已导出为save_models。结果,它们包含main_op。
答案 0 :(得分:0)
对于问题1,不是必须具有save_model
对于问题2,可以使用input_map
中的tf.train.import_meta_graph
arg
对于问题3,您确实不需要全部还原或初始化所有操作
此代码快照可以向您展示如何组合两个图并在tensorflow中对它们的输出求平均:
import tensorflow as tf
merged_graph = tf.Graph()
with merged_graph.as_default():
input = tf.placeholder(dtype=tf.float32, shape=WhatEverYourShape)
saver1 = tf.train.import_meta_graph('path_to_checkpoint1_model1.meta', import_scope='g1',
input_map={"YOUR/INPUT/NAME": input})
saver2 = tf.train.import_meta_graph('path_to_checkpoint1_model2.meta', import_scope='g2',
input_map={"YOUR/INPUT/NAME": input})
output1 = merged_graph.get_tensor_by_name("g1/YOUR/OUTPUT/TENSOR/NAME")
output2 = merged_graph.get_tensor_by_name("g2/YOUR/OUTPUT/TENSOR/NAME")
final_output = (output1 + output2) / 2
with tf.Session(graph=merged_graph) as sess:
saver1.restore(sess, 'path_to_checkpoint1_model1')
saver1.restore(sess, 'path_to_checkpoint1_model2')
# this line should NOT run because it will initialize all variables, your restore op will have no effect
# sess.run(tf.global_variables_initializer())
fianl_output_numpy = sess.run(final_output, feed_dict={input: YOUR_NUMPY_INPUT})
答案 1 :(得分:0)
我没有解决,但是找到了解决上述问题的方法。
主要问题是,每当使用saved_model API导出模型时,都会添加main_op node。由于我的两个模型都是使用此API导出的,因此两个模型都具有 main_op 节点,该节点将被导入到新图形中。然后,新图形将包含两个 main_ops ,稍后会加载,因为正好是一个主操作。
我选择使用的解决方法不是使用save_model API导出最终模型,而是使用方便的freeze_graph导出到单个.pb
文件中。
这是我的工作代码段:
# set some constants:
# INPUT_SHAPE, OUTPUT_NODE_NAME, OUTPUT_FILE_NAME,
# TEMP_DIR, TEMP_NAME, SCOPE_PREPEND_NAME, EXPORT_DIR
# Set path for trained models which are exported with the saved_model API
input_model_paths = [PATH_TO_MODEL1,
PATH_TO_MODEL2,
PATH_TO_MODEL3, ...]
num_model = len(input_model_paths)
def load_model(sess, path, scope, input_node):
tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING],
path,
import_scope=scope,
input_map={"Placeholder": input_node})
output_tensor = tf.get_default_graph().get_tensor_by_name(
scope + "/" + OUTPUT_NODE_NAME + ":0")
return output_tensor
with tf.Session(graph=tf.Graph()) as sess:
new_input = tf.placeholder(dtype=tf.float32,
shape=INPUT_SHAPE, name="Placeholder")
output_tensors = []
for k, path in enumerate(input_model_paths):
output_tensors.append(load_model(sess,
path,
SCOPE_PREPEND_NAME+str(k),
new_input))
# Mix together the outputs (e.g. sum, weighted sum, etc.)
sum_outputs = output_tensors[0] + output_tensors[1]
for i in range(2, num_model):
sum_outputs = sum_outputs + output_tensors[i]
final_output = tf.divide(sum_outputs, float(num_model), name=OUTPUT_NODE_NAME)
# Save checkpoint to be loaded later by the freeze_graph!
saver_checkpoint = tf.train.Saver()
saver_checkpoint.save(sess, os.path.join(TEMP_DIR, TEMP_NAME))
tf.train.write_graph(sess.graph_def, TEMP_DIR, TEMP_NAME + ".pbtxt")
freeze_graph.freeze_graph(
os.path.join(TEMP_DIR, TEMP_NAME + ".pbtxt"),
"",
False,
os.path.join(TEMP_DIR, TEMP_NAME),
OUTPUT_NODE_NAME,
"", # deprecated
"", # deprecated
os.path.join(EXPORT_DIR, OUTPUT_FILE_NAME),
False,
"")