def test_predict_outputs_valid(self):
    """Tests that no errors are raised when provided outputs are valid."""
    outputs = {
        'output0': constant_op.constant([0]),
        u'output1': constant_op.constant(['foo']),
    }
    export_output_lib.PredictOutput(outputs)

    # Single Tensor is OK too
    export_output_lib.PredictOutput(constant_op.constant([0]))
  def test_predict_outputs_invalid(self):
    with self.assertRaisesRegex(ValueError,
                                'Prediction output key must be a string'):
      export_output_lib.PredictOutput({1: constant_op.constant([0])})

    with self.assertRaisesRegex(ValueError,
                                'Prediction output value must be a Tensor'):
      export_output_lib.PredictOutput({
          'prediction1': sparse_tensor.SparseTensor(
              indices=[[0, 0]], values=[1], dense_shape=[1, 1]),
      })
Beispiel #3
0
  def test_build_all_signature_defs_without_receiver_alternatives(self):
    receiver_tensor = array_ops.placeholder(dtypes.string)
    output_1 = constant_op.constant([1.])
    output_2 = constant_op.constant(["2"])
    output_3 = constant_op.constant(["3"])
    export_outputs = {
        signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
            export_output.RegressionOutput(value=output_1),
        "head-2": export_output.ClassificationOutput(classes=output_2),
        "head-3": export_output.PredictOutput(outputs={
            "some_output_3": output_3
        }),
    }

    signature_defs = export_utils.build_all_signature_defs(
        receiver_tensor, export_outputs)

    expected_signature_defs = {
        "serving_default":
            signature_def_utils.regression_signature_def(receiver_tensor,
                                                         output_1),
        "head-2":
            signature_def_utils.classification_signature_def(receiver_tensor,
                                                             output_2, None),
        "head-3":
            signature_def_utils.predict_signature_def({
                "input": receiver_tensor
            }, {"some_output_3": output_3})
    }

    self.assertDictEqual(expected_signature_defs, signature_defs)
Beispiel #4
0
  def test_build_all_signature_defs_serving_only(self):
    receiver_tensor = {"input": array_ops.placeholder(dtypes.string)}
    output_1 = constant_op.constant([1.])
    export_outputs = {
        signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
            export_output.PredictOutput(outputs=output_1),
        "train": export_output.TrainOutput(loss=output_1),
    }

    signature_defs = export_utils.build_all_signature_defs(
        receiver_tensor, export_outputs)

    expected_signature_defs = {
        "serving_default": signature_def_utils.predict_signature_def(
            receiver_tensor, {"output": output_1})
    }

    self.assertDictEqual(expected_signature_defs, signature_defs)

    signature_defs = export_utils.build_all_signature_defs(
        receiver_tensor, export_outputs, serving_only=False)

    expected_signature_defs.update({
        "train": signature_def_utils.supervised_train_signature_def(
            receiver_tensor, loss={"loss": output_1})
    })

    self.assertDictEqual(expected_signature_defs, signature_defs)
Beispiel #5
0
def get_export_outputs(export_outputs, predictions):
    """Validate export_outputs or create default export_outputs.

  Args:
    export_outputs: Describes the output signatures to be exported to
      `SavedModel` and used during serving. Should be a dict or None.
    predictions:  Predictions `Tensor` or dict of `Tensor`.

  Returns:
    Valid export_outputs dict

  Raises:
    TypeError: if export_outputs is not a dict or its values are not
      ExportOutput instances.
  """
    if export_outputs is None:
        default_output = export_output_lib.PredictOutput(predictions)
        export_outputs = {
            signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
            default_output
        }

    if not isinstance(export_outputs, dict):
        raise TypeError(
            'export_outputs must be dict, given: {}'.format(export_outputs))
    for v in six.itervalues(export_outputs):
        if not isinstance(v, export_output_lib.ExportOutput):
            raise TypeError(
                'Values in export_outputs must be ExportOutput objects. '
                'Given: {}'.format(export_outputs))

    _maybe_add_default_serving_output(export_outputs)

    return export_outputs
    def test_build_all_signature_defs_without_receiver_alternatives(self):
        # Force the test to run in graph mode.
        # This tests a deprecated v1 API that depends on graph-only functions such
        # as build_tensor_info.
        with ops.Graph().as_default():
            receiver_tensor = array_ops.placeholder(dtypes.string)
            output_1 = constant_op.constant([1.])
            output_2 = constant_op.constant(["2"])
            output_3 = constant_op.constant(["3"])
            export_outputs = {
                signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                export_output.RegressionOutput(value=output_1),
                "head-2":
                export_output.ClassificationOutput(classes=output_2),
                "head-3":
                export_output.PredictOutput(
                    outputs={"some_output_3": output_3}),
            }

            signature_defs = export_utils.build_all_signature_defs(
                receiver_tensor, export_outputs)

            expected_signature_defs = {
                "serving_default":
                signature_def_utils.regression_signature_def(
                    receiver_tensor, output_1),
                "head-2":
                signature_def_utils.classification_signature_def(
                    receiver_tensor, output_2, None),
                "head-3":
                signature_def_utils.predict_signature_def(
                    {"input": receiver_tensor}, {"some_output_3": output_3})
            }

            self.assertDictEqual(expected_signature_defs, signature_defs)
    def test_build_all_signature_defs_serving_only(self):
        # Force the test to run in graph mode.
        # This tests a deprecated v1 API that depends on graph-only functions such
        # as build_tensor_info.
        with ops.Graph().as_default():
            receiver_tensor = {"input": array_ops.placeholder(dtypes.string)}
            output_1 = constant_op.constant([1.])
            export_outputs = {
                signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                export_output.PredictOutput(outputs=output_1),
                "train":
                export_output.TrainOutput(loss=output_1),
            }

            signature_defs = export_utils.build_all_signature_defs(
                receiver_tensor, export_outputs)

            expected_signature_defs = {
                "serving_default":
                signature_def_utils.predict_signature_def(
                    receiver_tensor, {"output": output_1})
            }

            self.assertDictEqual(expected_signature_defs, signature_defs)

            signature_defs = export_utils.build_all_signature_defs(
                receiver_tensor, export_outputs, serving_only=False)

            expected_signature_defs.update({
                "train":
                signature_def_utils.supervised_train_signature_def(
                    receiver_tensor, loss={"loss": output_1})
            })

            self.assertDictEqual(expected_signature_defs, signature_defs)
    def test_build_all_signature_defs_with_single_alternatives(self):
        # Force the test to run in graph mode.
        # This tests a deprecated v1 API that depends on graph-only functions such
        # as build_tensor_info.
        with ops.Graph().as_default():
            receiver_tensor = array_ops.placeholder(dtypes.string)
            receiver_tensors_alternative_1 = array_ops.placeholder(
                dtypes.int64)
            receiver_tensors_alternative_2 = array_ops.sparse_placeholder(
                dtypes.float32)
            # Note we are passing single Tensors as values of
            # receiver_tensors_alternatives, where normally that is a dict.
            # In this case a dict will be created using the default receiver tensor
            # name "input".
            receiver_tensors_alternatives = {
                "other1": receiver_tensors_alternative_1,
                "other2": receiver_tensors_alternative_2
            }
            output_1 = constant_op.constant([1.])
            output_2 = constant_op.constant(["2"])
            output_3 = constant_op.constant(["3"])
            export_outputs = {
                signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                export_output.RegressionOutput(value=output_1),
                "head-2":
                export_output.ClassificationOutput(classes=output_2),
                "head-3":
                export_output.PredictOutput(
                    outputs={"some_output_3": output_3}),
            }

            signature_defs = export_utils.build_all_signature_defs(
                receiver_tensor, export_outputs, receiver_tensors_alternatives)

            expected_signature_defs = {
                "serving_default":
                signature_def_utils.regression_signature_def(
                    receiver_tensor, output_1),
                "head-2":
                signature_def_utils.classification_signature_def(
                    receiver_tensor, output_2, None),
                "head-3":
                signature_def_utils.predict_signature_def(
                    {"input": receiver_tensor}, {"some_output_3": output_3}),
                "other1:head-3":
                signature_def_utils.predict_signature_def(
                    {"input": receiver_tensors_alternative_1},
                    {"some_output_3": output_3}),
                "other2:head-3":
                signature_def_utils.predict_signature_def(
                    {"input": receiver_tensors_alternative_2},
                    {"some_output_3": output_3})

                # Note that the alternatives 'other:serving_default' and
                # 'other:head-2' are invalid, because regression and classification
                # signatures must take a single string input.  Here we verify that
                # these invalid signatures are not included in the export_utils.
            }

            self.assertDictEqual(expected_signature_defs, signature_defs)
Beispiel #9
0
  def test_build_all_signature_defs_with_dict_alternatives(self):
    with context.graph_mode():
      receiver_tensor = array_ops.placeholder(dtypes.string)
      receiver_tensors_alternative_1 = {
          "foo": array_ops.placeholder(dtypes.int64),
          "bar": array_ops.sparse_placeholder(dtypes.float32)}
      receiver_tensors_alternatives = {"other": receiver_tensors_alternative_1}
      output_1 = constant_op.constant([1.])
      output_2 = constant_op.constant(["2"])
      output_3 = constant_op.constant(["3"])
      export_outputs = {
          signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
              export_output.RegressionOutput(value=output_1),
          "head-2": export_output.ClassificationOutput(classes=output_2),
          "head-3": export_output.PredictOutput(outputs={
              "some_output_3": output_3
          }),
      }

      signature_defs = export_utils.build_all_signature_defs(
          receiver_tensor, export_outputs, receiver_tensors_alternatives)

      expected_signature_defs = {
          "serving_default":
              signature_def_utils.regression_signature_def(
                  receiver_tensor,
                  output_1),
          "head-2":
              signature_def_utils.classification_signature_def(
                  receiver_tensor,
                  output_2, None),
          "head-3":
              signature_def_utils.predict_signature_def(
                  {"input": receiver_tensor},
                  {"some_output_3": output_3}),
          "other:head-3":
              signature_def_utils.predict_signature_def(
                  receiver_tensors_alternative_1,
                  {"some_output_3": output_3})

          # Note that the alternatives 'other:serving_default' and
          # 'other:head-2' are invalid, because regession and classification
          # signatures must take a single string input.  Here we verify that
          # these invalid signatures are not included in the export_utils.
      }

      self.assertDictEqual(expected_signature_defs, signature_defs)
Beispiel #10
0
  def test_build_all_signature_defs_with_dict_alternatives(self):
    # Force the test to run in graph mode.
    # This tests a deprecated v1 API that depends on graph-only functions such
    # as build_tensor_info.
    with ops.Graph().as_default():
      receiver_tensor = array_ops.placeholder(dtypes.string)

      receiver_tensors_alternative_1 = {
          "foo": array_ops.placeholder(dtypes.int64),
          "bar": array_ops.sparse_placeholder(dtypes.float32)
      }

      unfed_input = array_ops.placeholder(dtypes.bool)
      receiver_tensors_alternative_2 = {"unfed": unfed_input}

      receiver_tensors_alternatives = {
          "other": receiver_tensors_alternative_1,
          "with_unfed_input": receiver_tensors_alternative_2
      }

      output_1 = constant_op.constant([1.])
      output_2 = constant_op.constant(["2"])
      output_3 = constant_op.constant(["3"])
      output_4 = unfed_input
      output_5 = math_ops.logical_not(unfed_input)
      export_outputs = {
          signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
              export_output.RegressionOutput(value=output_1),
          "head-2":
              export_output.ClassificationOutput(classes=output_2),
          "head-3":
              export_output.PredictOutput(outputs={"some_output_3": output_3}),
          "head-4":
              export_output.PredictOutput(outputs={"some_output_4": output_4}),
          "head-5":
              export_output.PredictOutput(outputs={"some_output_5": output_5}),
      }

      signature_defs = export_utils.build_all_signature_defs(
          receiver_tensor, export_outputs, receiver_tensors_alternatives)

      expected_signature_defs = {
          "serving_default":
              signature_def_utils.regression_signature_def(
                  receiver_tensor, output_1),
          "head-2":
              signature_def_utils.classification_signature_def(
                  receiver_tensor, output_2, None),
          "head-3":
              signature_def_utils.predict_signature_def(
                  {"input": receiver_tensor}, {"some_output_3": output_3}),
          "other:head-3":
              signature_def_utils.predict_signature_def(
                  receiver_tensors_alternative_1, {"some_output_3": output_3}),

          # Note that the alternatives 'other:serving_default' and
          # 'other:head-2' are invalid, because regression and classification
          # signatures must take a single string input.  Here we verify that
          # these invalid signatures are not included in the export_utils.

          # Similarly, we verify that 'head-4' and 'head-5', which depend on an
          # input that is not being fed as a receiver tensor, are also omitted.

          # All the three heads are present when that input is fed, however:
          "with_unfed_input:head-3":
              signature_def_utils.predict_signature_def(
                  receiver_tensors_alternative_2, {"some_output_3": output_3}),
          "with_unfed_input:head-4":
              signature_def_utils.predict_signature_def(
                  receiver_tensors_alternative_2, {"some_output_4": output_4}),
          "with_unfed_input:head-5":
              signature_def_utils.predict_signature_def(
                  receiver_tensors_alternative_2, {"some_output_5": output_5})
      }

      self.assertDictEqual(expected_signature_defs, signature_defs)