一、背景:
我们建立了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)