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