【问题标题】:How to keep tensorflow session open between predictions? Loading from SavedModel如何在预测之间保持 tensorflow 会话打开?从 SavedModel 加载
【发布时间】:2017-04-30 01:00:35
【问题描述】:

我训练了一个张量流模型,我想从 numpy 数组中运行预测。这是用于视频中的图像处理。当图像发生时,我会将图像传递给模型。并非每一帧都通过。

我在这样的会话中reload我的 SavedModel

def run(self):                
    with tf.Session(graph=tf.Graph()) as sess:
        tf.saved_model.loader.load(sess,
                    [tf.saved_model.tag_constants.SERVING], "model")

如果我将图像列表 (self.tfimages) 传递给预测,我的代码将完美运行。浓缩为:

    softmax_tensor = sess.graph.get_tensor_by_name('final_ops/softmax:0')
    predictions = sess.run(softmax_tensor, {'Placeholder:0': self.tfimages})

但我不会一次获得所有图像。我真的每次都必须从文件中重新加载模型吗(需要 2 分钟以上)。

我想做这样的事情

class tensorflow_model:
def __init__(self):                
    with tf.Session(graph=tf.Graph()) as self.sess:
        tf.saved_model.loader.load(self.sess,
                    [tf.saved_model.tag_constants.SERVING], "model")
def predict(self):

        # Feed the image_data as input to the graph and get first prediction
        softmax_tensor = self.sess.graph.get_tensor_by_name('final_ops/softmax:0')

        predictions = self.sess.run(softmax_tensor, {'Placeholder:0': self.tfimages})

但这会产生

builtins.RuntimeError: 尝试使用已关闭的会话

有没有办法让会话保持打开状态,或者独立于会话加载 SavedModel?

编辑 我尝试了第一个答案,分两步创建会话:

sess=tf.Session(graph=tf.Graph())
sess
<tensorflow.python.client.session.Session object at 0x0000021ACBB62EF0>
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
Traceback (most recent call last):
  Debug Probe, prompt 138, line 1
  File "C:\Program Files\Python35\Lib\site-packages\tensorflow\python\saved_model\loader_impl.py", line 222, in load
    saver.restore(sess, variables_path)
  File "C:\Program Files\Python35\Lib\site-packages\tensorflow\python\training\saver.py", line 1428, in restore
    {self.saver_def.filename_tensor_name: save_path})
  File "C:\Program Files\Python35\Lib\site-packages\tensorflow\python\client\session.py", line 774, in run
    run_metadata_ptr)
  File "C:\Program Files\Python35\Lib\site-packages\tensorflow\python\client\session.py", line 905, in _run
    raise RuntimeError('The Session graph is empty.  Add operations to the '
builtins.RuntimeError: The Session graph is empty.  Add operations to the graph before calling run().

with tf.Session(graph=tf.Graph()) as sess:
    tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")

执行没有错误。

至于第二个思路,将sess作为变量传递给class,这个思路不错。这有效:

with tf.Session(graph=tf.Graph()) as sess:
    tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
    tensorflow_instance=tensorflow(read_from="file")
    tensorflow_instance.predict(sess)

但这不是

sess=tf.Session(graph=tf.Graph())
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
tensorflow_instance=tensorflow(read_from="file")
tensorflow_instance.predict(sess)

将我的程序包装到 with as sess 语句中会很尴尬。

完整代码:

import tensorflow as tf
import sys
from google.protobuf import text_format
from tensorflow.core.framework import graph_pb2
import os
import glob

class tensorflow:    

def __init__(self,read_from):

    #frames to be analyzed
    self.tfimages=[]    

    find_photos=glob.glob("*.jpg")

    # Read in the image_data
    if read_from=="file":
        for x in find_photos:
            image_data = tf.gfile.FastGFile(x, 'rb').read()    
            self.tfimages.append(image_data)

    # Loads label file, strips off carriage return
    self.label_lines = [line.rstrip() for line in tf.gfile.GFile("dict.txt")]

def predict(self,sess):

    # Feed the image_data as input to the graph and get first prediction
    softmax_tensor = sess.graph.get_tensor_by_name('final_ops/softmax:0')

    predictions = sess.run(softmax_tensor, {'Placeholder:0': self.tfimages})
    for prediction in predictions:
        # Sort to show labels of first prediction in order of confidence
        top_k = prediction.argsort()[-len(prediction):][::-1]

        for node_id in top_k:
            human_string = self.label_lines[node_id]
            score = prediction[node_id]
            print('%s (score = %.5f)' % (human_string, score))
        return(human_string)

if __name__ == "__main__":
    with tf.Session(graph=tf.Graph()) as sess:
        tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
        tensorflow_instance=tensorflow(read_from="file")
        tensorflow_instance.predict(sess)

    sess=tf.Session(graph=tf.Graph())
    tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
    tensorflow_instance=tensorflow(read_from="file")
    tensorflow_instance.predict(sess)

【问题讨论】:

    标签: python tensorflow


    【解决方案1】:

    其他人已经解释了为什么您不能将会话放在构造函数中的 with 语句中。

    您在使用上下文管理器与不使用上下文管理器时看到不同行为的原因是,tf.saved_model.loader.load 在默认图表和会话中的图表之间有一些奇怪的交互。

    解决方法很简单;如果您没有在 with 块中使用图表,请不要将图表传递给会话:

    sess=tf.Session()
    tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
    

    这是一个类进行预测的示例代码:

    class Model(object):
    
      def __init__(self, model_path):
        # Note, if you don't want to leak this, you'll want to turn Model into
        # a context manager. In practice, you probably don't have to worry
        # about it.
        self.session = tf.Session()
    
        tf.saved_model.loader.load(
            self.session,
            [tf.saved_model.tag_constants.SERVING],
            model_path)
    
        self.softmax_tensor = self.session.graph.get_tensor_by_name('final_ops/softmax:0')
    
      def predict(self, images):
        predictions = self.session.run(self.softmax, {'Placeholder:0': images})
        # TODO: convert to human-friendly labels
        return predictions
    
    
    images = [tf.gfile.FastGFile(f, 'rb').read() for f in glob.glob("*.jpg")]
    model = Model('model_path')
    print(model.predict(images))
    
    # Alternatively (uses less memory, but has lower throughput):
    for f in glob.glob("*.jpg"):
      print(model.predict([tf.gfile.FastGFile(f, 'rb').read()]))
    

    【讨论】:

    • 等待服务内置于 Tensorflow 中?我为什么要建造它
    • 查看下面关于 tensorflow_serving 以及github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/…的答案
    • FWIW -- 我必须调用 sess.__enter__() 才能在 Model 类中启动会话。请记住,with 会执行此操作,并且您需要 TF 会话的上下文管理器。
    【解决方案2】:

    您的代码创建了一个范围,该范围在它离开 init 后退出。

    def __init__(self): 
      with tf.Session(graph=tf.Graph()) as self.sess:
        tf.saved_model.loader.load(self.sess[tf.saved_model.tag_constants.SERVING], "model")
    

    如果您的其他一切工作正常,以下内容应该对您有用。

    def __init__(self):   
      self.sess=tf.Session(graph=tf.Graph())
      tf.saved_model.loader.load(self.sess[tf.saved_model.tag_constants.SERVING], "model")
    

    当我做这样的事情时,我通常还会创建通过参数将会话传递给类的选项,然后当我调用类时,我会传入由with 创建的会话

    【讨论】:

    • 不完全。上面编辑。返回“builtins.RuntimeError:会话图为空。在调用run()之前向图中添加操作。”
    【解决方案3】:

    您的代码不起作用,因为在您的 init 函数中您打开会话并关闭它。所以init完成后没有会话。

    如果你想在你的模型训练好之后做很多预测,我建议你不要重新发明轮子,而是使用这个工具,TF 开发者为此创建了:TF serving

    TensorFlow Serving 是一个灵活的高性能服务系统,适用于 机器学习模型,专为生产环境而设计。 TensorFlow Serving 使部署新算法和 实验,同时保持相同的服务器架构和 API。 TensorFlow Serving 提供与 TensorFlow 的开箱即用集成 模型,但可以轻松扩展以服务于其他类型的模型和 数据

    他们有很多从very basic ones 开始的教程,花一天时间学习一些东西可以节省几个月后的时间。

    【讨论】:

    • 虽然我同意用户不应该尝试重写服务系统,但似乎 OP 不一定想要服务系统,只是从模型中获得一些预测的简单方法使用熟悉/简单的语言。性能应该绰绰有余,因为 numpy 数组和 session.run 无论如何都是 C++ 代码。
    • @rhaertel80 你的回答没有错,只是想说没有必要重新发明轮子。这个问题之前已经解决了,现在只需要让自己熟悉一个解决方案。该语言仍然很熟悉,因为这是同一个 python。
    • TF Serving 包括用于推理的 C++ 库以及基于这些库构建的 gRPC 服务器。同意如果目标是服务和/或 C++ 推理,则 TF Serving 是首选工具。我确实认为对于非服务案例应该有一个更方便的 Python 解决方案,尽管如您所见,它只有大约 5 行代码。 FWIW, TF Serving 作者是提供 tf.saved_model.load 和相关功能的作者。
    猜你喜欢
    • 2018-02-04
    • 2020-01-13
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多