Ejemplo n.º 1
0
import os
import sys
import tensorflow as tf
from tensorflow.python.platform import gfile
from tensorflow.core.protobuf import saved_model_pb2
from tensorflow.python.util import compat
from tensorflow.python.framework import ops

path=os.path.join(os.getcwd(),"model","saved_model.pb")\

with tf.compat.v1.Session(graph=ops.Graph()) as sess:
    with gfile.GFile(path, "rb") as f:
        data = compat.as_bytes(f.read())
        sm = saved_model_pb2.SavedModel()
        sm.ParseFromString(data)
        g_in = tf.import_graph_def(sm.meta_graphs[0].graph_def)
        train_writer = tf.summary.create_file_writer("./log",tf.get_default_graph())
        #train_writer.add_graph(sess.graph)
        train_writer.set_as_default()
        train_writer.flush()
        train_writer.close()
Ejemplo n.º 2
0
def save(obj, export_dir, signatures=None):
  # pylint: disable=line-too-long
  """Exports the Trackable object `obj` to [SavedModel format](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md).

  Example usage:

  ```python
  class Adder(tf.train.Checkpoint):

    @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
    def add(self, x):
      return x + x + 1.

  to_export = Adder()
  tf.saved_model.save(to_export, '/tmp/adder')
  ```

  The resulting SavedModel is then servable with an input named "x", its value
  having any shape and dtype float32.

  The optional `signatures` argument controls which methods in `obj` will be
  available to programs which consume `SavedModel`s, for example serving
  APIs. Python functions may be decorated with
  `@tf.function(input_signature=...)` and passed as signatures directly, or
  lazily with a call to `get_concrete_function` on the method decorated with
  `@tf.function`.

  If the `signatures` argument is omitted, `obj` will be searched for
  `@tf.function`-decorated methods. If exactly one `@tf.function` is found, that
  method will be used as the default signature for the SavedModel. This behavior
  is expected to change in the future, when a corresponding
  `tf.saved_model.load` symbol is added. At that point signatures will be
  completely optional, and any `@tf.function` attached to `obj` or its
  dependencies will be exported for use with `load`.

  When invoking a signature in an exported SavedModel, `Tensor` arguments are
  identified by name. These names will come from the Python function's argument
  names by default. They may be overridden by specifying a `name=...` argument
  in the corresponding `tf.TensorSpec` object. Explicit naming is required if
  multiple `Tensor`s are passed through a single argument to the Python
  function.

  The outputs of functions used as `signatures` must either be flat lists, in
  which case outputs will be numbered, or a dictionary mapping string keys to
  `Tensor`, in which case the keys will be used to name outputs.

  Signatures are available in objects returned by `tf.saved_model.load` as a
  `.signatures` attribute. This is a reserved attribute: `tf.saved_model.save`
  on an object with a custom `.signatures` attribute will raise an exception.

  Since `tf.keras.Model` objects are also Trackable, this function can be
  used to export Keras models. For example, exporting with a signature
  specified:

  ```python
  class Model(tf.keras.Model):

    @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.string)])
    def serve(self, serialized):
      ...

  m = Model()
  tf.saved_model.save(m, '/tmp/saved_model/')
  ```

  Exporting from a function without a fixed signature:

  ```python
  class Model(tf.keras.Model):

    @tf.function
    def call(self, x):
      ...

  m = Model()
  tf.saved_model.save(
      m, '/tmp/saved_model/',
      signatures=m.call.get_concrete_function(
          tf.TensorSpec(shape=[None, 3], dtype=tf.float32, name="inp")))
  ```

  `tf.keras.Model` instances constructed from inputs and outputs already have a
  signature and so do not require a `@tf.function` decorator or a `signatures`
  argument. If neither are specified, the model's forward pass is exported.

  ```python
  x = input_layer.Input((4,), name="x")
  y = core.Dense(5, name="out")(x)
  model = training.Model(x, y)
  tf.saved_model.save(model, '/tmp/saved_model/')
  # The exported SavedModel takes "x" with shape [None, 4] and returns "out"
  # with shape [None, 5]
  ```

  Variables must be tracked by assigning them to an attribute of a tracked
  object or to an attribute of `obj` directly. TensorFlow objects (e.g. layers
  from `tf.keras.layers`, optimizers from `tf.train`) track their variables
  automatically. This is the same tracking scheme that `tf.train.Checkpoint`
  uses, and an exported `Checkpoint` object may be restored as a training
  checkpoint by pointing `tf.train.Checkpoint.restore` to the SavedModel's
  "variables/" subdirectory. Currently variables are the only stateful objects
  supported by `tf.saved_model.save`, but others (e.g. tables) will be supported
  in the future.

  `tf.function` does not hard-code device annotations from outside the function
  body, instead using the calling context's device. This means for example that
  exporting a model which runs on a GPU and serving it on a CPU will generally
  work, with some exceptions. `tf.device` annotations inside the body of the
  function will be hard-coded in the exported model; this type of annotation is
  discouraged. Device-specific operations, e.g. with "cuDNN" in the name or with
  device-specific layouts, may cause issues. Currently a `DistributionStrategy`
  is another exception: active distribution strategies will cause device
  placements to be hard-coded in a function. Exporting a single-device
  computation and importing under a `DistributionStrategy` is not currently
  supported, but may be in the future.

  SavedModels exported with `tf.saved_model.save` [strip default-valued
  attributes](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md#stripping-default-valued-attributes)
  automatically, which removes one source of incompatibilities when the consumer
  of a SavedModel is running an older TensorFlow version than the
  producer. There are however other sources of incompatibilities which are not
  handled automatically, such as when the exported model contains operations
  which the consumer does not have definitions for.

  The current implementation of `tf.saved_model.save` targets serving use-cases,
  but omits information which will be necessary for the planned future
  implementation of `tf.saved_model.load`. Exported models using the current
  `save` implementation, and other existing SavedModels, will not be compatible
  with `tf.saved_model.load` when it is implemented. Further, `save` will in the
  future attempt to export `@tf.function`-decorated methods which it does not
  currently inspect, so some objects which are exportable today will raise
  exceptions on export in the future (e.g. due to complex/non-serializable
  default arguments). Such backwards-incompatible API changes are expected only
  prior to the TensorFlow 2.0 release.

  Args:
    obj: A trackable object to export.
    export_dir: A directory in which to write the SavedModel.
    signatures: Optional, either a `tf.function` with an input signature
      specified or the result of `f.get_concrete_function` on a
      `@tf.function`-decorated function `f`, in which case `f` will be used to
      generate a signature for the SavedModel under the default serving
      signature key. `signatures` may also be a dictionary, in which case it
      maps from signature keys to either `tf.function` instances with input
      signatures or concrete functions. The keys of such a dictionary may be
      arbitrary strings, but will typically be from the
      `tf.saved_model.signature_constants` module.

  Raises:
    ValueError: If `obj` is not trackable.

  @compatibility(eager)
  Not supported when graph building. From TensorFlow 1.x,
  `tf.enable_eager_execution()` must run first. May not be called from within a
  function body.
  @end_compatibility
  """
  if not context.executing_eagerly():
    with ops.init_scope():
      if context.executing_eagerly():
        raise AssertionError(
            "tf.saved_model.save is not supported inside a traced "
            "@tf.function. Move the call to the outer eagerly-executed "
            "context.")
      else:
        raise AssertionError(
            "tf.saved_model.save is not supported when graph building. "
            "tf.enable_eager_execution() must run first when calling it from "
            "TensorFlow 1.x.")
  # pylint: enable=line-too-long
  if not isinstance(obj, base.Trackable):
    raise ValueError(
        "Expected a Trackable object for export, got {}.".format(obj))

  checkpoint_graph_view = _AugmentedGraphView(obj)
  if signatures is None:
    signatures = signature_serialization.find_function_to_export(
        checkpoint_graph_view)

  signatures = signature_serialization.canonicalize_signatures(signatures)
  signature_serialization.validate_saveable_view(checkpoint_graph_view)
  signature_map = signature_serialization.create_signature_map(signatures)
  checkpoint_graph_view.add_object(
      parent_node=checkpoint_graph_view.root,
      name_in_parent=signature_serialization.SIGNATURE_ATTRIBUTE_NAME,
      subgraph_root=signature_map)

  # Use _SaveableView to provide a frozen listing of properties and functions.
  # Note we run this twice since, while constructing the view the first time
  # there can be side effects of creating variables.
  _ = _SaveableView(checkpoint_graph_view)
  saveable_view = _SaveableView(checkpoint_graph_view)

  # TODO(allenl): Factor out some subset of SavedModelBuilder which is 2.x
  # compatible (no sessions) and share it with this export API rather than
  # making a SavedModel proto and writing it directly.
  saved_model = saved_model_pb2.SavedModel()
  meta_graph_def = saved_model.meta_graphs.add()
  object_saver = util.TrackableSaver(checkpoint_graph_view)
  asset_info, exported_graph = _fill_meta_graph_def(
      meta_graph_def, saveable_view, signatures)
  saved_model.saved_model_schema_version = (
      constants.SAVED_MODEL_SCHEMA_VERSION)
  # So far we've just been generating protocol buffers with no I/O. Now we write
  # the checkpoint, copy assets into the assets directory, and write out the
  # SavedModel proto itself.
  utils_impl.get_or_create_variables_dir(export_dir)
  object_saver.save(utils_impl.get_variables_path(export_dir))
  builder_impl.copy_assets_to_destination_dir(asset_info.asset_filename_map,
                                              export_dir)
  path = os.path.join(
      compat.as_bytes(export_dir),
      compat.as_bytes(constants.SAVED_MODEL_FILENAME_PB))
  object_graph_proto = _serialize_object_graph(
      saveable_view, asset_info.asset_index)
  meta_graph_def.object_graph_def.CopyFrom(object_graph_proto)
  file_io.write_string_to_file(path, saved_model.SerializeToString())
  # Clean reference cycles so repeated export()s don't make work for the garbage
  # collector. Before this point we need to keep references to captured
  # constants in the saved graph.
  ops.dismantle_graph(exported_graph)
Ejemplo n.º 3
0
                                          central_fraction=central_fraction)

        if height and width:
            # Resize the image to the specified height and width.
            image = tf.expand_dims(image, 0)
            image = tf.image.resize_bilinear(image, [height, width],
                                             align_corners=False)
            image = tf.squeeze(image, [0])
        image = tf.subtract(image, 0.5)
        image = tf.multiply(image, 2.0)
        return image


detection_graph = tf.Graph()
with detection_graph.as_default():
    od_graph_def = saved_model_pb2.SavedModel()
    with tf.gfile.GFile(PATH_TO_PRETRAIN_DET, 'rb') as fid:
        serialized_graph = compat.as_bytes(fid.read())
        od_graph_def.ParseFromString(serialized_graph)
        tf.import_graph_def(od_graph_def.meta_graphs[0].graph_def, name='')

with detection_graph.as_default():
    with tf.Session(graph=detection_graph) as sess:
        # Definite input and output Tensors for detection_graph
        image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
        # Each box represents a part of the image where a particular object was detected.
        detection_boxes = detection_graph.get_tensor_by_name(
            'detection_boxes:0')
        # Each score represent how level of confidence for each of the objects.
        # Score is shown on the result image, together with the class label.
        detection_scores = detection_graph.get_tensor_by_name(
Ejemplo n.º 4
0
    def testTextFormatAndNewExportDir(self):
        path = os.path.join(
            compat.as_bytes(self._saved_model_path),
            compat.as_bytes(constants.SAVED_MODEL_FILENAME_PBTXT))
        file_io.write_string_to_file(path, str(_SAVED_MODEL_PROTO))

        updater = method_name_updater.MethodNameUpdater(self._saved_model_path)
        updater.replace_method_name(signature_key="foo",
                                    method_name="regress",
                                    tags="serve")
        updater.replace_method_name(signature_key="bar",
                                    method_name="classify",
                                    tags=["gpu", "serve"])

        new_export_dir = tempfile.mkdtemp(prefix=test.get_temp_dir())
        updater.save(new_export_dir)

        self.assertTrue(
            file_io.file_exists(
                os.path.join(
                    compat.as_bytes(new_export_dir),
                    compat.as_bytes(constants.SAVED_MODEL_FILENAME_PBTXT))))
        actual = loader.parse_saved_model(new_export_dir)
        self.assertProtoEquals(
            actual,
            text_format.Parse(
                """
        saved_model_schema_version: 1
        meta_graphs {
          meta_info_def {
            tags: "serve"
          }
          signature_def: {
            key: "serving_default"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "predict"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape {
                    dim { size: -1 }
                    dim { size: 100 }
                  }
                }
              }
            }
          }
          signature_def: {
            key: "foo"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "regress"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape { dim { size: 1 } }
                }
              }
            }
          }
        }
        meta_graphs {
          meta_info_def {
            tags: "serve"
            tags: "gpu"
          }
          signature_def: {
            key: "serving_default"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "predict"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape {
                    dim { size: -1 }
                  }
                }
              }
            }
          }
          signature_def: {
            key: "bar"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "classify"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape { dim { size: 1 } }
                }
              }
            }
          }
        }
    """, saved_model_pb2.SavedModel()))
Ejemplo n.º 5
0
def save(obj, export_dir, signatures=None, options=None):
    # pylint: disable=line-too-long
    """Exports the Trackable object `obj` to [SavedModel format](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md).

  Example usage:

  ```python
  class Adder(tf.Module):

    @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
    def add(self, x):
      return x + x + 1.

  to_export = Adder()
  tf.saved_model.save(to_export, '/tmp/adder')
  ```

  The resulting SavedModel is then servable with an input named "x", its value
  having any shape and dtype float32.

  The optional `signatures` argument controls which methods in `obj` will be
  available to programs which consume `SavedModel`s, for example, serving
  APIs. Python functions may be decorated with
  `@tf.function(input_signature=...)` and passed as signatures directly, or
  lazily with a call to `get_concrete_function` on the method decorated with
  `@tf.function`.

  If the `signatures` argument is omitted, `obj` will be searched for
  `@tf.function`-decorated methods. If exactly one `@tf.function` is found, that
  method will be used as the default signature for the SavedModel. This behavior
  is expected to change in the future, when a corresponding
  `tf.saved_model.load` symbol is added. At that point signatures will be
  completely optional, and any `@tf.function` attached to `obj` or its
  dependencies will be exported for use with `load`.

  When invoking a signature in an exported SavedModel, `Tensor` arguments are
  identified by name. These names will come from the Python function's argument
  names by default. They may be overridden by specifying a `name=...` argument
  in the corresponding `tf.TensorSpec` object. Explicit naming is required if
  multiple `Tensor`s are passed through a single argument to the Python
  function.

  The outputs of functions used as `signatures` must either be flat lists, in
  which case outputs will be numbered, or a dictionary mapping string keys to
  `Tensor`, in which case the keys will be used to name outputs.

  Signatures are available in objects returned by `tf.saved_model.load` as a
  `.signatures` attribute. This is a reserved attribute: `tf.saved_model.save`
  on an object with a custom `.signatures` attribute will raise an exception.

  Since `tf.keras.Model` objects are also Trackable, this function can be
  used to export Keras models. For example, exporting with a signature
  specified:

  ```python
  class Model(tf.keras.Model):

    @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.string)])
    def serve(self, serialized):
      ...

  m = Model()
  tf.saved_model.save(m, '/tmp/saved_model/')
  ```

  Exporting from a function without a fixed signature:

  ```python
  class Model(tf.keras.Model):

    @tf.function
    def call(self, x):
      ...

  m = Model()
  tf.saved_model.save(
      m, '/tmp/saved_model/',
      signatures=m.call.get_concrete_function(
          tf.TensorSpec(shape=[None, 3], dtype=tf.float32, name="inp")))
  ```

  `tf.keras.Model` instances constructed from inputs and outputs already have a
  signature and so do not require a `@tf.function` decorator or a `signatures`
  argument. If neither are specified, the model's forward pass is exported.

  ```python
  x = input_layer.Input((4,), name="x")
  y = core.Dense(5, name="out")(x)
  model = training.Model(x, y)
  tf.saved_model.save(model, '/tmp/saved_model/')
  # The exported SavedModel takes "x" with shape [None, 4] and returns "out"
  # with shape [None, 5]
  ```

  Variables must be tracked by assigning them to an attribute of a tracked
  object or to an attribute of `obj` directly. TensorFlow objects (e.g. layers
  from `tf.keras.layers`, optimizers from `tf.train`) track their variables
  automatically. This is the same tracking scheme that `tf.train.Checkpoint`
  uses, and an exported `Checkpoint` object may be restored as a training
  checkpoint by pointing `tf.train.Checkpoint.restore` to the SavedModel's
  "variables/" subdirectory. Currently, variables are the only stateful objects
  supported by `tf.saved_model.save`, but others (e.g. tables) will be supported
  in the future.

  `tf.function` does not hard-code device annotations from outside the function
  body, instead of using the calling context's device. This means for example
  that exporting a model that runs on a GPU and serving it on a CPU will
  generally work, with some exceptions. `tf.device` annotations inside the body
  of the function will be hard-coded in the exported model; this type of
  annotation is discouraged. Device-specific operations, e.g. with "cuDNN" in
  the name or with device-specific layouts, may cause issues. Currently a
  `DistributionStrategy` is another exception: active distribution strategies
  will cause device placements to be hard-coded in a function. Exporting a
  single-device computation and importing under a `DistributionStrategy` is
  not currently supported, but may be in the future.

  SavedModels exported with `tf.saved_model.save` [strip default-valued
  attributes](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md#stripping-default-valued-attributes)
  automatically, which removes one source of incompatibilities when the consumer
  of a SavedModel is running an older TensorFlow version than the
  producer. There are however other sources of incompatibilities which are not
  handled automatically, such as when the exported model contains operations
  which the consumer does not have definitions for.

  A single tf.function can generate many ConcreteFunctions. If a downstream tool
  wants to refer to all concrete functions generated by a single tf.function you
  can use the `function_aliases` argument to store a map from the alias name to
  all concrete function names.
  E.g.
  ```python
  class MyModel:
  @tf.function
  def func():
    ...

  @tf.function
  def serve():
    ...
    func()

  model = MyModel()
  signatures = {
      'serving_default': model.serve.get_concrete_function(),
  }
  options = tf.saved_model.SaveOptions(function_aliases={
      'my_func': func,
  })
  tf.saved_model.save(model, export_dir, signatures, options)
  ```

  Args:
    obj: A trackable object to export.
    export_dir: A directory in which to write the SavedModel.
    signatures: Optional, either a `tf.function` with an input signature
      specified or the result of `f.get_concrete_function` on a
      `@tf.function`-decorated function `f`, in which case `f` will be used to
      generate a signature for the SavedModel under the default serving
      signature key. `signatures` may also be a dictionary, in which case it
      maps from signature keys to either `tf.function` instances with input
      signatures or concrete functions. The keys of such a dictionary may be
      arbitrary strings, but will typically be from the
      `tf.saved_model.signature_constants` module.
    options: Optional, `tf.saved_model.SaveOptions` object that specifies
      options for saving.

  Raises:
    ValueError: If `obj` is not trackable.

  @compatibility(eager)
  Not well supported when graph building. From TensorFlow 1.x,
  `tf.compat.v1.enable_eager_execution()` should run first. Calling
  tf.saved_model.save in a loop when graph building from TensorFlow 1.x will
  add new save operations to the default graph each iteration.

  May not be called from within a function body.
  @end_compatibility
  """
    options = options or save_options.SaveOptions()
    # TODO(allenl): Factor out some subset of SavedModelBuilder which is 2.x
    # compatible (no sessions) and share it with this export API rather than
    # making a SavedModel proto and writing it directly.
    saved_model = saved_model_pb2.SavedModel()
    meta_graph_def = saved_model.meta_graphs.add()

    _, exported_graph, object_saver, asset_info = _build_meta_graph(
        obj, export_dir, signatures, options, meta_graph_def)
    saved_model.saved_model_schema_version = constants.SAVED_MODEL_SCHEMA_VERSION

    # Write the checkpoint, copy assets into the assets directory, and write out
    # the SavedModel proto itself.
    utils_impl.get_or_create_variables_dir(export_dir)
    ckpt_options = checkpoint_options.CheckpointOptions(
        experimental_io_device=options.experimental_io_device)
    object_saver.save(utils_impl.get_variables_path(export_dir),
                      options=ckpt_options)
    builder_impl.copy_assets_to_destination_dir(asset_info.asset_filename_map,
                                                export_dir)
    # Note that this needs to be the last file operation when saving the
    # SavedModel. Users rely on checking saved_model_dir/saved_model.pb as an
    # indication that the SavedModel is completely written.
    if context.executing_eagerly():
        try:
            context.async_wait()  # Ensure save operations have completed.
        except errors.NotFoundError as err:
            raise FileNotFoundError(
                str(err) +
                "\n If trying to save on a different device from the "
                "computational device, consider using setting the "
                "`experimental_io_device` option on tf.saved_model.SaveOptions "
                "to the io_device such as '/job:localhost'.")

    path = os.path.join(compat.as_str(export_dir),
                        compat.as_str(constants.SAVED_MODEL_FILENAME_PB))
    file_io.atomic_write_string_to_file(
        path, saved_model.SerializeToString(deterministic=True))

    # Clean reference cycles so repeated export()s don't make work for the garbage
    # collector. Before this point, we need to keep references to captured
    # constants in the saved graph.
    ops.dismantle_graph(exported_graph)
Ejemplo n.º 6
0
      inputs: {
        key: "inputs"
        value { name: "input_node:0" }
      }
      method_name: "predict"
      outputs: {
        key: "outputs"
        value {
          dtype: DT_FLOAT
          tensor_shape { dim { size: 1 } }
        }
      }
    }
  }
}
""", saved_model_pb2.SavedModel())


class MethodNameUpdaterTest(test.TestCase):
    def setUp(self):
        super(MethodNameUpdaterTest, self).setUp()
        self._saved_model_path = tempfile.mkdtemp(prefix=test.get_temp_dir())

    def testBasic(self):
        path = os.path.join(compat.as_bytes(self._saved_model_path),
                            compat.as_bytes(constants.SAVED_MODEL_FILENAME_PB))
        file_io.write_string_to_file(
            path, _SAVED_MODEL_PROTO.SerializeToString(deterministic=True))

        updater = method_name_updater.MethodNameUpdater(self._saved_model_path)
        updater.replace_method_name(signature_key="serving_default",
Ejemplo n.º 7
0
    def testBasic(self):
        path = os.path.join(compat.as_bytes(self._saved_model_path),
                            compat.as_bytes(constants.SAVED_MODEL_FILENAME_PB))
        file_io.write_string_to_file(
            path, _SAVED_MODEL_PROTO.SerializeToString(deterministic=True))

        updater = method_name_updater.MethodNameUpdater(self._saved_model_path)
        updater.replace_method_name(signature_key="serving_default",
                                    method_name="classify")
        updater.save()

        actual = loader.parse_saved_model(self._saved_model_path)
        self.assertProtoEquals(
            actual,
            text_format.Parse(
                """
        saved_model_schema_version: 1
        meta_graphs {
          meta_info_def {
            tags: "serve"
          }
          signature_def: {
            key: "serving_default"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "classify"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape {
                    dim { size: -1 }
                    dim { size: 100 }
                  }
                }
              }
            }
          }
          signature_def: {
            key: "foo"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "predict"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape { dim { size: 1 } }
                }
              }
            }
          }
        }
        meta_graphs {
          meta_info_def {
            tags: "serve"
            tags: "gpu"
          }
          signature_def: {
            key: "serving_default"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "classify"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape {
                    dim { size: -1 }
                  }
                }
              }
            }
          }
          signature_def: {
            key: "bar"
            value: {
              inputs: {
                key: "inputs"
                value { name: "input_node:0" }
              }
              method_name: "predict"
              outputs: {
                key: "outputs"
                value {
                  dtype: DT_FLOAT
                  tensor_shape { dim { size: 1 } }
                }
              }
            }
          }
        }
    """, saved_model_pb2.SavedModel()))
Ejemplo n.º 8
0
def inference(filename, od_model_path, cls_model_path):
    # load the frozen object detection model and make inference on the image
    detection_graph = tf.Graph()
    with detection_graph.as_default():
        od_graph_def = saved_model_pb2.SavedModel()
        with tf.gfile.GFile(od_model_path, 'rb') as fid:
            serialized_graph = compat.as_bytes(fid.read())
            od_graph_def.ParseFromString(serialized_graph)
            tf.import_graph_def(od_graph_def.meta_graphs[0].graph_def, name='')

        with tf.Session(graph=detection_graph) as sess:
            # Definite input and output Tensors for detection_graph
            image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
            # Each box represents a part of the image where a particular object was detected.
            detection_boxes = detection_graph.get_tensor_by_name(
                'detection_boxes:0')
            # Each score represent how level of confidence for each of the objects.
            # Score is shown on the result image, together with the class label.
            detection_scores = detection_graph.get_tensor_by_name(
                'detection_scores:0')
            detection_classes = detection_graph.get_tensor_by_name(
                'detection_classes:0')
            num_detections = detection_graph.get_tensor_by_name(
                'num_detections:0')

            image = Image.open(filename)
            # the array based representation of the image will be used later in order to prepare the
            # result image with boxes and labels on it.
            (image_np, im_height,
             im_width) = load_image_into_numpy_array(image)
            # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
            image_np_expanded = np.expand_dims(image_np, axis=0)
            # Actual detection.
            (boxes, scores, classes,
             num) = sess.run([
                 detection_boxes, detection_scores, detection_classes,
                 num_detections
             ],
                             feed_dict={image_tensor: image_np_expanded})
            # squeeze classes, boxes, scores
            classes = np.squeeze(classes).astype(np.int32)
            boxes = np.squeeze(boxes)
            scores = np.squeeze(scores)

    # find the car box index with the max level of confidence, get its confidence level value
    car_index = np.where(classes == 3)[0][0]
    score = scores[car_index]
    if score > 0.2:
        # if confidence > 0.2, make classification inference on the bounding box part
        bbox = boxes[car_index]
        y1 = int(bbox[0] * im_height)
        x1 = int(bbox[1] * im_width)
        y2 = int(bbox[2] * im_height)
        x2 = int(bbox[3] * im_width)
        # bounding box height and width
        crop_height = y2 - y1
        crop_width = x2 - x1
        # crop the bounding box part
        with tf.name_scope('image_crop_by_bbox'):
            image_crop = tf.image.crop_to_bounding_box(
                image_np,
                offset_height=y1,
                offset_width=x1,
                target_height=crop_height,
                target_width=crop_width)
        img_crop = Image.fromarray(tf.Session().run(image_crop), 'RGB')

        # preprocess for classification inference
        with tf.name_scope('preprocess'):
            image_in = tf.placeholder(tf.uint8,
                                      shape=[None, None, 3],
                                      name='image_in')
            image_preprocessed = preprocess_for_class_infer(image_in, 299, 299)
        img_preproc = tf.Session().run(image_preprocessed,
                                       feed_dict={image_in: img_crop})
        img_np_expanded = np.expand_dims(img_preproc, axis=0)

        # load the frozen classification model
        class_graph = tf.Graph()
        with class_graph.as_default():
            with open(cls_model_path, 'rb') as f:
                graph_def = tf.GraphDef()
                graph_def.ParseFromString(f.read())
                _ = tf.import_graph_def(graph_def, name='')
            # make inference
            with tf.Session(graph=class_graph) as sess:
                softmax_tensor = sess.graph.get_tensor_by_name(
                    'InceptionV4/Logits/Predictions:0')
                predictions = sess.run(softmax_tensor,
                                       feed_dict={'input:0': img_np_expanded})
                predictions = np.squeeze(predictions)
                class_index = np.where(
                    predictions == np.max(predictions))[0][0]
                prob = np.max(predictions) * 100
                category_index = create_category_index(
                    label_file=FLAGS.label_file)
                class_name = category_index[class_index]['name']

        # read in image file and initialize drawing
        im = cv2.imread(filename, cv2.COLOR_BGR2RGB)
        pil_im = Image.fromarray(im)
        draw = ImageDraw.Draw(pil_im)
        font = ImageFont.truetype('./simhei.ttf', 16, encoding='utf-8')

        # combine the display string to "write"
        class_name = category_index[class_index]['name']
        disp_str = class_name + ': ' + ('%s' % str(int(prob))) + '%'
        # define the text background width, draw text background
        len_disp_str = len(disp_str.encode('gb2312'))
        draw.rectangle((x1, y1, x1 + len_disp_str * 8, y1 + 16),
                       fill=(211, 211, 211),
                       outline=None)
        # "write" the display string
        draw.text((x1, y1), disp_str, (255, 0, 255), font=font)
        # draw the bounding box
        draw.line((x1, y1, x2, y1), (0, 255, 0), width=3)
        draw.line((x2, y1, x2, y2), (0, 255, 0), width=3)
        draw.line((x2, y2, x1, y2), (0, 255, 0), width=3)
        draw.line((x1, y2, x1, y1), (0, 255, 0), width=3)

        # save drawing
        im = np.array(pil_im)
        cv2.imwrite(
            os.path.join(FLAGS.output_folder, os.path.basename(filename)), im)

    else:
        # confidence level <= 0.2, means "there's no car"
        prob = 0.0
        class_name = 'There\'s no car!'

    if score > 0.2:
        # if there's any car, show the result image on the webpage
        new_url = '/static/%s' % os.path.basename(filename)
        image_tag = '<img src="%s"></img><p>'
        new_tag = image_tag % new_url
    else:
        # if there's no car, show the primary image
        copy2(filename,
              os.path.join(FLAGS.output_folder, os.path.basename(filename)))
        new_url = '/static/%s' % os.path.basename(filename)
        image_tag = '<img src="%s"></img><p>'
        new_tag = image_tag % new_url

    # print classification result and score
    format_string = '%s (score: %.1f%%)' % (class_name, prob)
    ret_string = new_tag + format_string + '<BR>'
    return ret_string
Ejemplo n.º 9
0
def save(obj, export_dir, signatures=None):
    # pylint: disable=line-too-long
    """Exports the Checkpointable object `obj` to [SavedModel format](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md).

  Example usage:

  ```python
  class Adder(tf.train.Checkpoint):

    @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
    def add(self, x):
      return x + x + 1.

  to_export = Adder()
  tf.saved_model.save(to_export, '/tmp/adder')
  ```

  The resulting SavedModel is then servable with an input named "x", its value
  having any shape and dtype float32.

  The optional `signatures` argument controls which methods in `obj` will be
  available to programs which consume `SavedModel`s, for example serving
  APIs. Python functions may be decorated with
  `@tf.function(input_signature=...)` and passed as signatures directly, or
  lazily with a call to `get_concrete_function` on the method decorated with
  `@tf.function`.

  If the `signatures` argument is omitted, `obj` will be searched for
  `@tf.function`-decorated methods. If exactly one `@tf.function` is found, that
  method will be used as the default signature for the SavedModel. This behavior
  is expected to change in the future, when a corresponding
  `tf.saved_model.load` symbol is added. At that point signatures will be
  completely optional, and any `@tf.function` attached to `obj` or its
  dependencies will be exported for use with `load`.

  When invoking a signature in an exported SavedModel, `Tensor` arguments are
  identified by name. These names will come from the Python function's argument
  names by default. They may be overridden by specifying a `name=...` argument
  in the corresponding `tf.TensorSpec` object. Explicit naming is required if
  multiple `Tensor`s are passed through a single argument to the Python
  function.

  The outputs of functions used as `signatures` must either be flat lists, in
  which case outputs will be numbered, or a dictionary mapping string keys to
  `Tensor`, in which case the keys will be used to name outputs.

  Since `tf.keras.Model` objects are also Checkpointable, this function can be
  used to export Keras models. For example, exporting with a signature
  specified:

  ```python
  class Model(tf.keras.Model):

    @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.string)])
    def serve(self, serialized):
      ...

  m = Model()
  tf.saved_model.save(m, '/tmp/saved_model/')
  ```

  Exporting from a function without a fixed signature:

  ```python
  class Model(tf.keras.Model):

    @tf.function
    def call(self, x):
      ...

  m = Model()
  tf.saved_model.save(
      m, '/tmp/saved_model/',
      signatures=m.call.get_concrete_function(
          tf.TensorSpec(shape=[None, 3], dtype=tf.float32, name="inp")))
  ```

  `tf.keras.Model` instances constructed from inputs and outputs already have a
  signature and so do not require a `@tf.function` decorator or a `signatures`
  argument. If neither are specified, the model's forward pass is exported.

  ```python
  x = input_layer.Input((4,), name="x")
  y = core.Dense(5, name="out")(x)
  model = training.Model(x, y)
  tf.saved_model.save(model, '/tmp/saved_model/')
  # The exported SavedModel takes "x" with shape [None, 4] and returns "out"
  # with shape [None, 5]
  ```

  Variables must be tracked by assigning them to an attribute of a tracked
  object or to an attribute of `obj` directly. TensorFlow objects (e.g. layers
  from `tf.keras.layers`, optimizers from `tf.train`) track their variables
  automatically. This is the same tracking scheme that `tf.train.Checkpoint`
  uses, and an exported `Checkpoint` object may be restored as a training
  checkpoint by pointing `tf.train.Checkpoint.restore` to the SavedModel's
  "variables/" subdirectory. Currently variables are the only stateful objects
  supported by `tf.saved_model.save`, but others (e.g. tables) will be supported
  in the future.

  `tf.function` does not hard-code device annotations from outside the function
  body, instead using the calling context's device. This means for example that
  exporting a model which runs on a GPU and serving it on a CPU will generally
  work, with some exceptions. `tf.device` annotations inside the body of the
  function will be hard-coded in the exported model; this type of annotation is
  discouraged. Device-specific operations, e.g. with "cuDNN" in the name or with
  device-specific layouts, may cause issues. Currently a `DistributionStrategy`
  is another exception: active distribution strategies will cause device
  placements to be hard-coded in a function. Exporting a single-device
  computation and importing under a `DistributionStrategy` is not currently
  supported, but may be in the future.

  SavedModels exported with `tf.saved_model.save` [strip default-valued
  attributes](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md#stripping-default-valued-attributes)
  automatically, which removes one source of incompatibilities when the consumer
  of a SavedModel is running an older TensorFlow version than the
  producer. There are however other sources of incompatibilities which are not
  handled automatically, such as when the exported model contains operations
  which the consumer does not have definitions for.

  The current implementation of `tf.saved_model.save` targets serving use-cases,
  but omits information which will be necessary for the planned future
  implementation of `tf.saved_model.load`. Exported models using the current
  `save` implementation, and other existing SavedModels, will not be compatible
  with `tf.saved_model.load` when it is implemented. Further, `save` will in the
  future attempt to export `@tf.function`-decorated methods which it does not
  currently inspect, so some objects which are exportable today will raise
  exceptions on export in the future (e.g. due to complex/non-serializable
  default arguments). Such backwards-incompatible API changes are expected only
  prior to the TensorFlow 2.0 release.

  Args:
    obj: A checkpointable object to export.
    export_dir: A directory in which to write the SavedModel.
    signatures: Optional, either a `tf.function` with an input signature
      specified or the result of `f.get_concrete_function` on a
      `@tf.function`-decorated function `f`, in which case `f` will be used to
      generate a signature for the SavedModel under the default serving
      signature key. `signatures` may also be a dictionary, in which case it
      maps from signature keys to either `tf.function` instances with input
      signatures or concrete functions. The keys of such a dictionary may be
      arbitrary strings, but will typically be from the
      `tf.saved_model.signature_constants` module.

  Raises:
    ValueError: If `obj` is not checkpointable.
  """
    # pylint: enable=line-too-long
    if not isinstance(obj, base.CheckpointableBase):
        raise ValueError(
            "Expected a Checkpointable object for export, got {}.".format(obj))
    if signatures is None:
        # Note that we run this before saving the checkpoint, since looping over
        # attributes may have the side effect of creating variables in some cases.
        signatures = _find_function_to_export(obj)
    object_saver = util.CheckpointableSaver(obj)
    utils_impl.get_or_create_variables_dir(export_dir)
    object_saver.save(utils_impl.get_variables_path(export_dir))

    signatures = _canonicalize_signatures(signatures)
    graph_def, signatures, saver_def = _make_graph_def(obj, signatures,
                                                       object_saver)
    saved_model = saved_model_pb2.SavedModel()
    saved_model.saved_model_schema_version = (
        constants.SAVED_MODEL_SCHEMA_VERSION)
    meta_graph_def = saved_model.meta_graphs.add()
    meta_graph_def.meta_info_def.tags.append(tag_constants.SERVING)
    meta_graph_def.saver_def.CopyFrom(saver_def)
    # TODO(allenl): Factor out some subset of SavedModelBuilder which is 2.x
    # compatible (no sessions) and share it with this export API rather than
    # making a SavedModel proto and writing it directly.
    meta_graph_def.graph_def.MergeFrom(graph_def)
    for signature_key, signature in signatures.items():
        meta_graph_def.signature_def[signature_key].MergeFrom(signature)
    meta_graph.strip_graph_default_valued_attrs(meta_graph_def)
    path = os.path.join(compat.as_bytes(export_dir),
                        compat.as_bytes(constants.SAVED_MODEL_FILENAME_PB))
    file_io.write_string_to_file(path, saved_model.SerializeToString())
Ejemplo n.º 10
0
def export(obj, export_dir, signatures=None):
  # pylint: disable=line-too-long
  """Exports the Checkpointable object `obj` to [SavedModel format](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md).

  The `signatures` argument indicates TensorFlow functions which will be
  available to programs which consume `SavedModel`s, for example serving
  APIs. Python functions may be decorated with
  `@tf.function(input_signature=...)` and passed as signatures directly, or
  created without a signature using `@tf.function` and then converted to a
  concrete TensorFlow function using `f.get_concrete_function(...)`.

  In either case, `Tensor` inputs to `signatures` functions which are not
  associated with a unique Python argument name must have names explicitly
  specified in their `tf.TensorSpec` objects. Cases where this is necessary
  include positional arguments passed through variadic `*args` and multiple
  `Tensor` inputs which are part of the same nested structure.

  The outputs of functions used as `signatures` must either be flat lists, in
  which case outputs will be numbered, or a dictionary mapping string keys to
  Tensors, in which case the string keys will be used to name outputs.

  Exporting with a signature specified:

  ```python
  class Model(tf.keras.Model):

    @tf.function(input_signature=tf.TensorSpec(shape=[None], dtype=tf.string))
    def serve(serialized):
      ...

  m = Model()
  tf.saved_model.export(m, '/tmp/saved_model/', signatures=m.serve)
  ```

  Exporting from a function without a fixed signature:

  ```python
  class Model(tf.keras.Model):

    @tf.function
    def compute(x):
      ...

  m = Model()
  tf.saved_model.export(
      m, '/tmp/saved_model/',
      signatures=m.compute.get_concrete_function(
          tf.TensorSpec(shape=[None, 3], dtype=tf.float32, name="inp")))
  ```

  Args:
    obj: A checkpointable object to export.
    export_dir: A directory in which to write the SavedModel.
    signatures: Optional, either a `tf.function` with an input signature
      specified or the result of `f.get_concrete_function` on a
      `tf.function`-decorated function `f`, in which case `f` will be used to
      generate a signature for the SavedModel under the default serving
      signature key. `signatures` may also be a dictionary, in which case it
      maps from signature keys to either `tf.function` instances with input
      signatures or concrete functions. The keys of such a dictionary may be
      arbitrary strings, but will typically be from the
      `tf.saved_model.signature_constants` module.

  Raises:
    ValueError: If `obj` is not checkpointable.
  """
  # pylint: enable=line-too-long
  if not isinstance(obj, checkpointable.CheckpointableBase):
    raise ValueError(
        "Expected a Checkpointable object for export, got {}.".format(obj))
  signatures = _canonicalize_signatures(signatures)
  graph_def, signatures = _make_graph_def(signatures)
  saved_model = saved_model_pb2.SavedModel()
  saved_model.saved_model_schema_version = (
      constants.SAVED_MODEL_SCHEMA_VERSION)
  meta_graph_def = saved_model.meta_graphs.add()
  # TODO(allenl): Factor out some subset of SavedModelBuilder which is 2.x
  # compatible (no sessions) and share it with this export API rather than
  # making a SavedModel proto and writing it directly.
  meta_graph_def.graph_def.MergeFrom(graph_def)
  for signature_key, signature in signatures.items():
    meta_graph_def.signature_def[signature_key].MergeFrom(signature)
  file_io.recursive_create_dir(export_dir)
  path = os.path.join(
      compat.as_bytes(export_dir),
      compat.as_bytes(constants.SAVED_MODEL_FILENAME_PB))
  file_io.write_string_to_file(path, saved_model.SerializeToString())
Ejemplo n.º 11
0
def _make_saved_model(payload: Dict[str, Any]):
    result = saved_model_pb2.SavedModel()
    json_format.ParseDict(payload, result)
    return result
Ejemplo n.º 12
0
 def __init__(self):
     self._proto = saved_model_pb2.SavedModel()