I trained a tensorflow model that i'd like to run predictions on from numpy arrays. This is for image processing within videos. I will pass the images to the model as they happen. Not every frame is passed.
I reload my SavedModel within a session like so
def run(self):
with tf.Session(graph=tf.Graph()) as sess:
tf.saved_model.loader.load(sess,
[tf.saved_model.tag_constants.SERVING], "model")
My code works perfectly if I pass a list of images (self.tfimages) to the prediction. Condensed to:
softmax_tensor = sess.graph.get_tensor_by_name('final_ops/softmax:0')
predictions = sess.run(softmax_tensor, {'Placeholder:0': self.tfimages})
But i won't have all the images at once. Do I really have to reload the model from file each time (takes 2+ minutes).
I thought to do something like this
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})
but that yields
builtins.RuntimeError: Attempted to use a closed Session
Is there a way to keep a session open, or perhaps load SavedModel independent of a session?
EDIT I tried the first answer to create a session in two steps:
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().
Whereas
with tf.Session(graph=tf.Graph()) as sess:
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
executes without error.
As for the second idea of passing sess as a variable to class, which is a good one. This works:
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)
But this doesn't
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)
It would be pretty awkward to wrap my program into the with as sess statement.
Full code:
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)
pb stands for protobuf. In TensorFlow, the protbuf file contains the graph definition as well as the weights of the model. Thus, a pb file is all you need to be able to run a given trained model. Given a pb file, you can load it as follow.
GraphDef is the proto defined here. This is the serialized version of graph. You can print, store, or restore a GraphDef in any TensorFlow frontend (Python, R, C++, Java, ...).
Others have explained why you can't put your session in a with
statement in the constructor.
The reason you see different behavior when using the context manager vs. not is because tf.saved_model.loader.load
has some weird interactions between the default graph and the graph that is part of the session.
The solution is simple; don't pass a graph to session if you're not using it in a with
block:
sess=tf.Session()
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING], "model")
Here's some example code for a class to do predictions:
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()]))
Your code creates a scope which is exited after it leaves 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")
The following should work for you if you have everything else working properly.
def __init__(self):
self.sess=tf.Session(graph=tf.Graph())
tf.saved_model.loader.load(self.sess[tf.saved_model.tag_constants.SERVING], "model")
When I do something like this I also usually create the option of passing the session to the class by a parameter, then when I call the class I pass in a session create by with
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With