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)
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)
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_standardized_signature_def_classify_classes_only(self): """Tests classification with one output tensor.""" with context.graph_mode(): input_tensors = { 'input-1': array_ops.placeholder( dtypes.string, 1, name='input-tensor-1') } classes = array_ops.placeholder(dtypes.string, 1, name='output-tensor-1') export_output = export_output_lib.ClassificationOutput(classes=classes) actual_signature_def = export_output.as_signature_def(input_tensors) expected_signature_def = meta_graph_pb2.SignatureDef() shape = tensor_shape_pb2.TensorShapeProto( dim=[tensor_shape_pb2.TensorShapeProto.Dim(size=1)]) dtype_string = types_pb2.DataType.Value('DT_STRING') expected_signature_def.inputs[ signature_constants.CLASSIFY_INPUTS].CopyFrom( meta_graph_pb2.TensorInfo(name='input-tensor-1:0', dtype=dtype_string, tensor_shape=shape)) expected_signature_def.outputs[ signature_constants.CLASSIFY_OUTPUT_CLASSES].CopyFrom( meta_graph_pb2.TensorInfo(name='output-tensor-1:0', dtype=dtype_string, tensor_shape=shape)) expected_signature_def.method_name = ( signature_constants.CLASSIFY_METHOD_NAME) self.assertEqual(actual_signature_def, expected_signature_def)
def test_classify_scores_must_be_float(self): with context.graph_mode(): scores = array_ops.placeholder(dtypes.string, 1, name='output-tensor-1') with self.assertRaisesRegexp( ValueError, 'Classification scores must be a float32 Tensor'): export_output_lib.ClassificationOutput(scores=scores)
def test_classify_classes_must_be_strings(self): with context.graph_mode(): classes = array_ops.placeholder(dtypes.float32, 1, name='output-tensor-1') with self.assertRaisesRegex( ValueError, 'Classification classes must be a string Tensor'): export_output_lib.ClassificationOutput(classes=classes)
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)
def test_export_outputs_for_mode(self): predictions = {"predictions": constant_op.constant([1.])} loss = {"loss": constant_op.constant([2.])} metrics = { "metrics": (constant_op.constant([3.]), constant_op.constant([4.])) } expected_metrics = { "metrics/value": metrics["metrics"][0], "metrics/update_op": metrics["metrics"][1] } def _build_export_output(mode): return export_utils.export_outputs_for_mode( mode, None, predictions, loss, metrics) ret = _build_export_output(KerasModeKeys.TRAIN) self.assertIn(signature_constants.DEFAULT_TRAIN_SIGNATURE_DEF_KEY, ret) export_out = ret[signature_constants.DEFAULT_TRAIN_SIGNATURE_DEF_KEY] self.assertIsInstance(export_out, export_output.TrainOutput) self.assertEqual(export_out.predictions, predictions) self.assertEqual(export_out.loss, loss) self.assertEqual(export_out.metrics, expected_metrics) ret = _build_export_output(KerasModeKeys.TEST) self.assertIn(signature_constants.DEFAULT_EVAL_SIGNATURE_DEF_KEY, ret) export_out = ret[signature_constants.DEFAULT_EVAL_SIGNATURE_DEF_KEY] self.assertIsInstance(export_out, export_output.EvalOutput) self.assertEqual(export_out.predictions, predictions) self.assertEqual(export_out.loss, loss) self.assertEqual(export_out.metrics, expected_metrics) ret = _build_export_output(KerasModeKeys.PREDICT) self.assertIn(signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY, ret) export_out = ret[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY] self.assertIsInstance(export_out, export_output.PredictOutput) self.assertEqual(export_out.outputs, predictions) classes = constant_op.constant(["class5"]) ret = export_utils.export_outputs_for_mode( KerasModeKeys.PREDICT, {"classify": export_output.ClassificationOutput(classes=classes)}) self.assertIn("classify", ret) export_out = ret["classify"] self.assertIsInstance(export_out, export_output.ClassificationOutput) self.assertEqual(export_out.classes, classes)
def test_classify_requires_classes_or_scores(self): with self.assertRaisesRegexp( ValueError, 'At least one of scores and classes must be set.'): export_output_lib.ClassificationOutput()
def test_classify_requires_classes_or_scores(self): with self.assertRaisesRegex( ValueError, 'Cannot create a ClassificationOutput with empty arguments'): export_output_lib.ClassificationOutput()
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)