Tensorflow: tensorboard: view graph from saved_model.pb file [feature request]

Created on 31 Mar 2017  路  28Comments  路  Source: tensorflow/tensorflow

Plot a graph from just a saved_model.pb file.

Currently tensorboard only works given a training folder containing checkpoints and summary events. Understanding the output graph is important, especially if you don't have access to the training output files.

Most helpful comment

@brandondutra As far as I know, you don't need to create any summaries to load the graph into Tensorboard. If you begin to create a summarywriter and then add the graph to it then you should see the graph appear in Tensorboard. I have some code that does that (as part of another project). I do however agree that being able to import something into Tensorboard would be handy.

I've quickly created a bit of code to load a graph into Tensorboard. See how that goes. Also available as a gist here

import tensorflow as tf
from tensorflow.python.platform import gfile
with tf.Session() as sess:
    model_filename ='PATH_TO_PB.pb'
    with gfile.FastGFile(model_filename, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        g_in = tf.import_graph_def(graph_def)
LOGDIR='YOUR_LOG_LOCATION'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

You should then be able to see this in Tensorboard.
Something like that perhaps in the mean time? I might put a PR in to get some conversation going,

All 28 comments

@brandondutra As far as I know, you don't need to create any summaries to load the graph into Tensorboard. If you begin to create a summarywriter and then add the graph to it then you should see the graph appear in Tensorboard. I have some code that does that (as part of another project). I do however agree that being able to import something into Tensorboard would be handy.

I've quickly created a bit of code to load a graph into Tensorboard. See how that goes. Also available as a gist here

import tensorflow as tf
from tensorflow.python.platform import gfile
with tf.Session() as sess:
    model_filename ='PATH_TO_PB.pb'
    with gfile.FastGFile(model_filename, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        g_in = tf.import_graph_def(graph_def)
LOGDIR='YOUR_LOG_LOCATION'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

You should then be able to see this in Tensorboard.
Something like that perhaps in the mean time? I might put a PR in to get some conversation going,

This is awesome! Thank you for your help. I took your script and ran it, but I ran into an issue:

google.protobuf.message.DecodeError: Error parsing message

Because the error is in parsing the message, I looked into tensorflow protos. I modified your script, and got it working on my saved_model.pb file.

import tensorflow as tf
import sys
from tensorflow.python.platform import gfile

from tensorflow.core.protobuf import saved_model_pb2
from tensorflow.python.util import compat

with tf.Session() as sess:
    model_filename ='saved_model.pb'
    with gfile.FastGFile(model_filename, 'rb') as f:

        data = compat.as_bytes(f.read())
        sm = saved_model_pb2.SavedModel()
        sm.ParseFromString(data)
        #print(sm)
        if 1 != len(sm.meta_graphs):
            print('More than one graph found. Not sure which to write')
            sys.exit(1)

        #graph_def = tf.GraphDef()
        #graph_def.ParseFromString(sm.meta_graphs[0])
        g_in = tf.import_graph_def(sm.meta_graphs[0].graph_def)
LOGDIR='YOUR_LOG_LOCATION'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

Again, thank you!

@brandondutra I guess that there was something odd with your .pb then. Worked fine on mine! Glad I could help.

Closing since this feature is available through existing TensorBoard functionality.

@aselle Can I just confirm what you mean by existing Tensorboard functionality? Do you mean the code that myself and @brandondutra wrote (and associated functions) or is there another way?

Yes that's what I mean. @dandelionmane, do you want to add a more direct way to visualize saved graphs?

Yes. Telling users to write a python script to visualize a saved model graph is a very bad user experience [it's not even documented as a thing that can be done], and seems like something tensorboard should be very good at.

Actually, tf.summary.FileWriter accepts a GraphDef parameter which marks as deprecated.

I think the point/ask of this issue is that tensorboard should show the graph from a saved_model.pb file

When trying to load a frozen pb model to visualise its graph, the snippets above didn't work for me in tensorflow 1.4, Python 3.6 (the resulting folder was empty).

Using the Upload - Choose file option in tensorboard's GUI gave Graph visualization failed: The graph is empty.

However, using the import_to_tensorboard function did the trick:

https://github.com/tensorflow/tensorflow/blob/r1.4/tensorflow/python/tools/import_pb_to_tensorboard.py

hey @MikulasZelinka how to use this function?

can you post an example how to call it with an example model and log dir?
For me somehow it does not work

@jubjamie your code works fine, thanks :+1:

Thank you!

@GustavZ You can visualize the graph of your frozen pb model using this command

python import_pb_to_tensorboard.py --model_dir="path/to/your/model/file.pb" --log_dir="path/to/your/log/dir"

I found I had to change @brandondutra script slightly to add a flush and close at the end.
Else on some models nothing would be written to the LOG_DIR.
Also found that import_pb_to_tensorboard gave the same error as google.protobuf.message.DecodeError: Error parsing message so had to use this in the first place.

import tensorflow as tf
import sys
from tensorflow.python.platform import gfile

from tensorflow.core.protobuf import saved_model_pb2
from tensorflow.python.util import compat

with tf.Session() as sess:
    model_filename =sys.argv[1]
    with gfile.FastGFile(model_filename, 'rb') as f:

        data = compat.as_bytes(f.read())
        sm = saved_model_pb2.SavedModel()
        sm.ParseFromString(data)
        #print(sm)
        if 1 != len(sm.meta_graphs):
            print('More than one graph found. Not sure which to write')
            sys.exit(1)

        #graph_def = tf.GraphDef()
        #graph_def.ParseFromString(sm.meta_graphs[0])
        g_in = tf.import_graph_def(sm.meta_graphs[0].graph_def)
    LOGDIR=sys.argv[2]

train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)
train_writer.flush()
train_writer.close()

@Jon889, I followed you suggestion and I can overcome error "the google.protobuf.message.DecodeError: Error parsing message"

But when I use tensorboard to view the graph, it is empty graph,

i made below change, and i can view graph,
I tested with .pb created by "mnist_saved_model.py" (https://github.com/tensorflow/serving/blob/master/tensorflow_serving/example/mnist_saved_model.py)

code snippet:

import argparse
import sys
import tensorflow as tf

from tensorflow.python.platform import app
from tensorflow.python.summary import summary

def import_to_tensorboard(model_dir, log_dir):
  """View an imported protobuf model (`.pb` file) as a graph in Tensorboard.

  Args:
    model_dir: The location of the protobuf (`pb`) model to visualize
    log_dir: The location for the Tensorboard log to begin visualization from.

  Usage:
    Call this function with your model location and desired log directory.
    Launch Tensorboard by pointing it to the log directory.
    View your imported `.pb` model as a graph.
  """

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

    pb_visual_writer = summary.FileWriter(log_dir)
    pb_visual_writer.add_graph(sess.graph)
    print("Model Imported. Visualize by running: "
          "tensorboard --logdir={}".format(log_dir))

If you have two .pb files with the same structure and format, is it possible to add them together???

Let say that you have a trained model then you made a fine-tune for new calsses, then you add the result pb file to the original one so you reduce training time and having one pb file like you made a full training operation

I don't really think import_pb_to_tensorboard solves the issue here: 1) firstly, model_dir takes a graph.pb, instead of a saved_model.pb; 2) what is it with "log_idr"?

On a separate note: I think TF folks could've done a much better job handling RFEs from users, instead of just keeping on closing them.

how tom open .pb files?

While adding my frozen.pb file to it, it gives me an error
Traceback (most recent call last):
File "convert.py", line 30, in
g_in = tf.import_graph_def(graph_def)
File "/home/ios/.local/lib/python2.7/site-packages/tensorflow/python/util/deprecation.py", line 432, in new_func
return func(args, *kwargs)
File "/home/ios/.local/lib/python2.7/site-packages/tensorflow/python/framework/importer.py", line 671, in import_graph_def
node, 'Input tensor %r %s' % (input_name, te)))
ValueError: graph_def is invalid at node u'Genc/Conv/BatchNorm/AssignMovingAvg': Input tensor 'Genc/Conv/BatchNorm/moving_mean:0' Cannot convert a tensor of type float32 to an input of type float32_ref.

and if run it through another code which is:

import tensorflow as tf
import sys
from tensorflow.python.platform import gfile

from tensorflow.core.protobuf import saved_model_pb2
from tensorflow.python.util import compat

with tf.Session() as sess:
model_filename ='saved_model.pb'
with gfile.FastGFile(model_filename, 'rb') as f:

data = compat.as_bytes(f.read())
sm = saved_model_pb2.SavedModel()
sm.ParseFromString(data)
#print(sm)
if 1 != len(sm.meta_graphs):
    print('More than one graph found. Not sure which to write')
    sys.exit(1)

#graph_def = tf.GraphDef()
#graph_def.ParseFromString(sm.meta_graphs[0])
g_in = tf.import_graph_def(sm.meta_graphs[0].graph_def)

LOGDIR='YOUR_LOG_LOCATION'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

and gave me error:

google.protobuf.message.DecodeError: Error parsing message

any solution for this..??

i converted to .pb file from checkpoint file using tensorflow frozen_python file.

I also tried to run it through import_pb_to_tensorboard.py file but in that also i got an error of float32 to float32_ref

I think there is something wrong in .pb file, but i converted it through frozen_graph.py of tensorflow . and passed all the correct output_node_name. so i dont figure what is error.

No you can't:

Traceback (most recent call last):
  File "/home/user/.local/lib/python3.6/site-packages/tensorflow_core/python/tools/import_pb_to_tensorboard.py", line 86, in <module>
    app.run(main=main, argv=[sys.argv[0]] + unparsed)
  File "/home/user/.local/lib/python3.6/site-packages/tensorflow_core/python/platform/app.py", line 40, in run
    _run(main=main, argv=argv, flags_parser=_parse_flags_tolerate_undef)
  File "/home/user/.local/lib/python3.6/site-packages/absl/app.py", line 300, in run
    _run_main(main, args)
  File "/home/user/.local/lib/python3.6/site-packages/absl/app.py", line 251, in _run_main
    sys.exit(main(argv))
  File "/home/user/.local/lib/python3.6/site-packages/tensorflow_core/python/tools/import_pb_to_tensorboard.py", line 68, in main
    import_to_tensorboard(FLAGS.model_dir, FLAGS.log_dir)
  File "/home/user/.local/lib/python3.6/site-packages/tensorflow_core/python/tools/import_pb_to_tensorboard.py", line 58, in import_to_tensorboard
    graph_def.ParseFromString(f.read())
google.protobuf.message.DecodeError: Error parsing message

This is in 2.0. The whole SavedModel debacle is an unmitigated disaster.

any solution to this?

^ the above PR should fix the problem. For those that are impatient:

wget https://raw.githubusercontent.com/ltn100/tensorflow/feature/LN/fix_import_pb_to_tensorboard/tensorflow/python/tools/import_pb_to_tensorboard.py
python import_pb_to_tensorboard.py --model_dir model_dir/1 --log_dir logs/001

@brandondutra As far as I know, you don't need to create any summaries to load the graph into Tensorboard. If you begin to create a summarywriter and then add the graph to it then you should see the graph appear in Tensorboard. I have some code that does that (as part of another project). I do however agree that being able to import something into Tensorboard would be handy.

I've quickly created a bit of code to load a graph into Tensorboard. See how that goes. Also available as a gist here

import tensorflow as tf
from tensorflow.python.platform import gfile
with tf.Session() as sess:
    model_filename ='PATH_TO_PB.pb'
    with gfile.FastGFile(model_filename, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        g_in = tf.import_graph_def(graph_def)
LOGDIR='YOUR_LOG_LOCATION'
train_writer = tf.summary.FileWriter(LOGDIR)
train_writer.add_graph(sess.graph)

You should then be able to see this in Tensorboard.
Something like that perhaps in the mean time? I might put a PR in to get some conversation going,

Don't forget to flush ;)

train_writer.flush()

Here's a handy Colab notebook in case anyone wants to try out this: https://colab.research.google.com/drive/13LAUUT9tEH2XeoNA_z9A7uE5omc-lzNv

@sayakpaul thanks for the notebook!
@jubjamie
@Jon889

any idea why that doesn't work like that - without your function?

from tensorflow.python.tools.import_pb_to_tensorboard import import_to_tensorboard
import os

model_dir = './model'
model = os.path.join(model_dir, 'saved_model.pb')
print(model)
import_to_tensorboard(model_dir=model, log_dir='./logs/')

I see this error:

~$ python main.py 
2020-03-06 23:14:33.962070: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-03-06 23:14:33.970833: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2200075000 Hz
2020-03-06 23:14:33.972744: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x563e6e9a9f60 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-03-06 23:14:33.972774: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Traceback (most recent call last):
  File "main4.py", line 7, in <module>
    import_to_tensorboard(model_dir=model, log_dir='./logs/')
  File "/home/mike18/venv/lib/python3.6/site-packages/tensorflow_core/python/tools/import_pb_to_tensorboard.py", line 58, in import_to_tensorboard
    graph_def.ParseFromString(f.read())
google.protobuf.message.DecodeError: Error parsing message

also why does this code not work with Tensorflow 2?
https://github.com/tobegit3hub/tfmodel/blob/22c1c48a7049a9cac8e533e317f41697fb85ff7a/tfmodel/savedmodel_analyst.py

when I use your function it works:

# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================
"""Imports a protobuf model as a graph in Tensorboard."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

from tensorflow.python.client import session
from tensorflow.python.framework import importer
from tensorflow.python.framework import ops
from tensorflow.python.platform import app
from tensorflow.python.summary import summary
from tensorflow.python.tools import saved_model_utils

# Try importing TensorRT ops if available
# TODO(aaroey): ideally we should import everything from contrib, but currently
# tensorrt module would cause build errors when being imported in
# tensorflow/contrib/__init__.py. Fix it.
# pylint: disable=unused-import,g-import-not-at-top,wildcard-import
try:
  from tensorflow.contrib.tensorrt.ops.gen_trt_engine_op import *
except ImportError:
  pass
# pylint: enable=unused-import,g-import-not-at-top,wildcard-import

def import_to_tensorboard(model_dir, log_dir, tag_set):
  """View an imported protobuf model (`.pb` file) as a graph in Tensorboard.

  Args:
    model_dir: The location of the protobuf (`pb`) model to visualize
    log_dir: The location for the Tensorboard log to begin visualization from.
    tag_set: Group of tag(s) of the MetaGraphDef to load, in string format,
        separated by ','. For tag-set contains multiple tags, all tags must be
        passed in.

  Usage:
    Call this function with your model location and desired log directory.
    Launch Tensorboard by pointing it to the log directory.
    View your imported `.pb` model as a graph.
  """
  with session.Session(graph=ops.Graph()) as sess:
    input_graph_def = saved_model_utils.get_meta_graph_def(
        model_dir, tag_set).graph_def
    importer.import_graph_def(input_graph_def)

    pb_visual_writer = summary.FileWriter(log_dir)
    pb_visual_writer.add_graph(sess.graph)
    print("Model Imported. Visualize by running: "
          "tensorboard --logdir={}".format(log_dir))


def main(_):
  import_to_tensorboard(FLAGS.model_dir, FLAGS.log_dir, FLAGS.tag_set)

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.register("type", "bool", lambda v: v.lower() == "true")
  parser.add_argument(
      "--model_dir",
      type=str,
      default="",
      required=True,
      help="The directory containing the SavedModel to import.")
  parser.add_argument(
      "--log_dir",
      type=str,
      default="",
      required=True,
      help="The location for the Tensorboard log to begin visualization from.")
  parser.add_argument(
      '--tag_set',
      type=str,
      default="serve",
      required=False,
      help='tag-set of graph in SavedModel to load, separated by \',\'')
  FLAGS, unparsed = parser.parse_known_args()
  app.run(main=main, argv=[sys.argv[0]] + unparsed)

and than run:

$ python import_pb_to_tensorboard.py --model_dir ./model --log_dir logs/
2020-03-06 23:23:07.019262: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-03-06 23:23:07.027290: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2200075000 Hz
2020-03-06 23:23:07.029262: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x557ede9a02e0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-03-06 23:23:07.029284: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Model Imported. Visualize by running: tensorboard --logdir=logs/

@sayakpaul thanks for the notebook!
@jubjamie
@Jon889

any idea why that doesn't work like that - without your function?

from tensorflow.python.tools.import_pb_to_tensorboard import import_to_tensorboard
import os

model_dir = './model'
model = os.path.join(model_dir, 'saved_model.pb')
print(model)
import_to_tensorboard(model_dir=model, log_dir='./logs/')

I see this error:

~$ python main.py 
2020-03-06 23:14:33.962070: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-03-06 23:14:33.970833: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2200075000 Hz
2020-03-06 23:14:33.972744: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x563e6e9a9f60 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-03-06 23:14:33.972774: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Traceback (most recent call last):
  File "main4.py", line 7, in <module>
    import_to_tensorboard(model_dir=model, log_dir='./logs/')
  File "/home/mike18/venv/lib/python3.6/site-packages/tensorflow_core/python/tools/import_pb_to_tensorboard.py", line 58, in import_to_tensorboard
    graph_def.ParseFromString(f.read())
google.protobuf.message.DecodeError: Error parsing message

also why does this code not work with Tensorflow 2?
https://github.com/tobegit3hub/tfmodel/blob/22c1c48a7049a9cac8e533e317f41697fb85ff7a/tfmodel/savedmodel_analyst.py

when I use your function it works:

# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ================================
"""Imports a protobuf model as a graph in Tensorboard."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

from tensorflow.python.client import session
from tensorflow.python.framework import importer
from tensorflow.python.framework import ops
from tensorflow.python.platform import app
from tensorflow.python.summary import summary
from tensorflow.python.tools import saved_model_utils

# Try importing TensorRT ops if available
# TODO(aaroey): ideally we should import everything from contrib, but currently
# tensorrt module would cause build errors when being imported in
# tensorflow/contrib/__init__.py. Fix it.
# pylint: disable=unused-import,g-import-not-at-top,wildcard-import
try:
  from tensorflow.contrib.tensorrt.ops.gen_trt_engine_op import *
except ImportError:
  pass
# pylint: enable=unused-import,g-import-not-at-top,wildcard-import

def import_to_tensorboard(model_dir, log_dir, tag_set):
  """View an imported protobuf model (`.pb` file) as a graph in Tensorboard.

  Args:
    model_dir: The location of the protobuf (`pb`) model to visualize
    log_dir: The location for the Tensorboard log to begin visualization from.
    tag_set: Group of tag(s) of the MetaGraphDef to load, in string format,
        separated by ','. For tag-set contains multiple tags, all tags must be
        passed in.

  Usage:
    Call this function with your model location and desired log directory.
    Launch Tensorboard by pointing it to the log directory.
    View your imported `.pb` model as a graph.
  """
  with session.Session(graph=ops.Graph()) as sess:
    input_graph_def = saved_model_utils.get_meta_graph_def(
        model_dir, tag_set).graph_def
    importer.import_graph_def(input_graph_def)

    pb_visual_writer = summary.FileWriter(log_dir)
    pb_visual_writer.add_graph(sess.graph)
    print("Model Imported. Visualize by running: "
          "tensorboard --logdir={}".format(log_dir))


def main(_):
  import_to_tensorboard(FLAGS.model_dir, FLAGS.log_dir, FLAGS.tag_set)

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.register("type", "bool", lambda v: v.lower() == "true")
  parser.add_argument(
      "--model_dir",
      type=str,
      default="",
      required=True,
      help="The directory containing the SavedModel to import.")
  parser.add_argument(
      "--log_dir",
      type=str,
      default="",
      required=True,
      help="The location for the Tensorboard log to begin visualization from.")
  parser.add_argument(
      '--tag_set',
      type=str,
      default="serve",
      required=False,
      help='tag-set of graph in SavedModel to load, separated by \',\'')
  FLAGS, unparsed = parser.parse_known_args()
  app.run(main=main, argv=[sys.argv[0]] + unparsed)

and than run:

$ python import_pb_to_tensorboard.py --model_dir ./model --log_dir logs/
2020-03-06 23:23:07.019262: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-03-06 23:23:07.027290: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2200075000 Hz
2020-03-06 23:23:07.029262: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x557ede9a02e0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-03-06 23:23:07.029284: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Model Imported. Visualize by running: tensorboard --logdir=logs/

Works for me.

Here's a handy Colab notebook in case anyone wants to try out this: https://colab.research.google.com/drive/13LAUUT9tEH2XeoNA_z9A7uE5omc-lzNv

I tried the coloab notebook but the graph in tensorboard is not showing anything, is it working for you?

Was this page helpful?
0 / 5 - 0 ratings