一、背景:
我们建立了10个CNN模型,然后我们又写了一个预测类Predict,这个类会从已经保存好的模型restore恢复相应的图结构以及模型参数。然后我们会创建10个Predict的对象Instance,每个Instance负责一个模型的预测。
再者,我们有个NLP服务,比如要加keras训练的句子分类,还有深度相似度模型。那么有两个模型同时在该进程里。
这样会出错。类似于出现ValueError: Tensor Tensor("Pooler-Dense", shape=(?, 768), dtype=float32) is not an element of this graph
二、原因
主要是因为不同对象里面的不同sess使用了同一进程空间下的相同的默认图graph
tf.get_default_graph()获取默认图,
import tensorflow as tf
a=tf.constant([1.0,2.0],name="a")
b=tf.constant([3.0,4.0],name="b")
c=a+b
print(c.graph)
print(tf.get_default_graph())
#结果:
#tensorflow.python.framework.ops.Graph object at 0x000001E4F528CB70
#tensorflow.python.framework.ops.Graph object at 0x000001E4F528CB70
上面因为只有一个模型(图)实例,那么就一样,如果两个模型(图)实例,那就会出错了。
三、解决办法
每一个实例生成一个图调用tf.Graph(),解决模板
class MyModel():
def __init__(self):
self.gragh = tf.Graph()
with self.gragh.as_default():
self.sess = tf.Session()
with self.sess.as_default():
# 建立加载模型
bert = build_transformer_model()
self.model = keras.models.Model(bert.model.inputs, bert.model.outputs[0])
def predict(self, s):
with self.gragh.as_default():
with self.sess.as_default():
self.model.predict(s)
其次如果用bert预训练的模型,截取其中的图的模型,那么可以先保存为keras的model,然后用load_model函数加载
# 1 保存h5模型
# 建立加载模型
bert = build_transformer_model()
model = keras.models.Model(bert.model.inputs, bert.model.outputs[0])
model.save("model.h5")
# 2.load_model h5模型
class MyModel():
def __init__(self):
self.graph= tf.Graph()
with self.graph.as_default():
self.session = Session()
with self.session.as_default():
self.model = load_model(model_path)
def predict(self,s):
with self.session.as_default(): # 注意这里不需要with self.gragh.as_default(),包含了图
self.model.predit(s)
四、实际例子
tensorflow加载训练的模型。来自于58的 qa_match开源项目模型加载
class MyModel():
def __init__(self):
self.model_file = tf.train.latest_checkpoint(model_path)
self.graph = tf.Graph() # 为每个类(实例)单独创建一个graph
with self.graph.as_default():
self.model_file = tf.train.latest_checkpoint(model_path)
self.saver = tf.train.import_meta_graph("{}.meta".format(self.model_file)) # 创建恢复器
# 注意!恢复器必须要在新创建的图里面生成,否则会出错。
self.sess = tf.Session()
with self.sess.as_default():
self.saver.restore(self.sess, self.model_file)
def predict(self,input_y_value,length_y_value):
with self.graph.as_default(): # 看清这里有两个with 这一句特别重要,因为要在该图下执行tensor获取和session
with self.sess.as_default():
input_x = self.graph.get_tensor_by_name("input_x:0")
length_x = self.graph.get_tensor_by_name("length_x:0")
input_y = self.graph.get_tensor_by_name("input_y:0")
length_y = self.graph.get_tensor_by_name("length_y:0")
keep_prob = self.graph.get_tensor_by_name("keep_prob:0")
q_y_raw = self.graph.get_tensor_by_name("representation/q_y_raw:0")
qs_y_raw = self.graph.get_tensor_by_name("representation/qs_y_raw:0")
qs_y_raw_out = self.sess.run(qs_y_raw, feed_dict={input_y:np.array(input_y_value, dtype=np.int32),length_y: np.array(length_y_value, dtype=np.int32), keep_prob: 1.0})
小彩蛋:向量相似度
a_vecs = a_vecs / (a_vecs**2).sum(axis=1, keepdims=True)**0.5 b_vecs = b_vecs / (b_vecs**2).sum(axis=1, keepdims=True)**0.5 sims = (a_vecs * b_vecs).sum(axis=1)