From 1e87951747af11b61206dd19f9363b309fc8e6f5 Mon Sep 17 00:00:00 2001 From: Brian Zhao Date: Mon, 17 Aug 2020 15:56:09 -0700 Subject: [PATCH] Start separating the type TF_ConcreteFunction from TF_SignatureDefFunction. The two have significant enough differences in semantics and implementation that they should have different representations; see the comments in tensorflow/cc/saved_model/experimental/public/signature_def_function.h for more details. PiperOrigin-RevId: 327117128 Change-Id: I54d5f5ca0ed51599b21e7b322e1d292212243871 --- .../c/experimental/saved_model/core/BUILD | 23 +++++ .../saved_model/core/concrete_function.h | 12 ++- .../saved_model/core/saved_model_api.h | 5 +- .../saved_model/core/signature_def_function.h | 62 +++++++++++++ .../core/signature_def_function_metadata.h | 27 ++++++ .../saved_model/core/tf_saved_model_api.cc | 3 +- .../saved_model/core/tf_saved_model_api.h | 3 +- .../c/experimental/saved_model/internal/BUILD | 73 +++++++++++++++ .../saved_model/internal/saved_model_api.cc | 9 +- .../internal/signature_def_function.cc | 53 +++++++++++ .../signature_def_function_metadata.cc | 20 +++++ .../signature_def_function_metadata_type.h | 31 +++++++ .../internal/signature_def_function_type.h | 31 +++++++ .../c/experimental/saved_model/public/BUILD | 14 +++ .../saved_model/public/c_saved_model_api.h | 2 + .../saved_model/public/concrete_function.h | 7 ++ .../saved_model/public/saved_model_api.h | 12 ++- .../public/signature_def_function.h | 50 +++++++++++ .../public/signature_def_function_metadata.h | 31 +++++++ .../cc/saved_model/experimental/public/BUILD | 24 +++++ .../experimental/public/saved_model_api.h | 11 +-- .../public/signature_def_function.h | 89 +++++++++++++++++++ .../public/signature_def_function_metadata.h | 47 ++++++++++ 23 files changed, 619 insertions(+), 20 deletions(-) create mode 100644 tensorflow/c/experimental/saved_model/core/signature_def_function.h create mode 100644 tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h create mode 100644 tensorflow/c/experimental/saved_model/internal/signature_def_function.cc create mode 100644 tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata.cc create mode 100644 tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h create mode 100644 tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h create mode 100644 tensorflow/c/experimental/saved_model/public/signature_def_function.h create mode 100644 tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h create mode 100644 tensorflow/cc/saved_model/experimental/public/signature_def_function.h create mode 100644 tensorflow/cc/saved_model/experimental/public/signature_def_function_metadata.h diff --git a/tensorflow/c/experimental/saved_model/core/BUILD b/tensorflow/c/experimental/saved_model/core/BUILD index b2e432782de..3e0989b257f 100644 --- a/tensorflow/c/experimental/saved_model/core/BUILD +++ b/tensorflow/c/experimental/saved_model/core/BUILD @@ -44,7 +44,9 @@ cc_library( ], deps = [ ":concrete_function", + ":signature_def_function", "//tensorflow/core:lib", + "@com_google_absl//absl/strings", ], ) @@ -70,6 +72,26 @@ cc_library( ], ) +cc_library( + name = "signature_def_function", + hdrs = [ + "signature_def_function.h", + ], + deps = [ + ":signature_def_function_metadata", + "//tensorflow/c/eager:immediate_execution_operation", + "//tensorflow/c/eager:immediate_execution_tensor_handle", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "signature_def_function_metadata", + hdrs = [ + "signature_def_function_metadata.h", + ], +) + cc_library( name = "test_utils", testonly = True, @@ -115,6 +137,7 @@ cc_library( ":concrete_function", ":saved_model_api", ":saved_model_utils", + ":signature_def_function", "//tensorflow/c:tensor_interface", "//tensorflow/c/eager:immediate_execution_context", "//tensorflow/c/eager:immediate_execution_tensor_handle", diff --git a/tensorflow/c/experimental/saved_model/core/concrete_function.h b/tensorflow/c/experimental/saved_model/core/concrete_function.h index da3a64b91a3..934fa6d2bda 100644 --- a/tensorflow/c/experimental/saved_model/core/concrete_function.h +++ b/tensorflow/c/experimental/saved_model/core/concrete_function.h @@ -26,10 +26,14 @@ limitations under the License. namespace tensorflow { -// Note that ConcreteFunctions's lifetimes are effectively bound -// to the SavedModel they are loaded from, since they retain pointers -// to the TensorHandles owned by the SavedModel, and the FunctionDef -// of the SavedModel. +// ConcreteFunctions correspond to an instance of a tf.function with a known set +// of inputs (either through get_concrete_function) or an input_signature. +// ConcreteFunction attempts to preserve the user-facing semantics of the +// tf.function python API and can take a limited set of types as arguments +// (to be modeled in tensorflow::Value), not just Tensors. +// SavedModelAPI's ConcreteFunctions' lifetimes are bound to the SavedModel they +// are loaded from, since they retain pointers to the TensorHandles owned by the +// SavedModel, and the FunctionDef of the SavedModel. // Note(bmzhao): This class is only TEMPORARILY virtual, as a way to unblock // TFRT integration with TF Serving. Do not add more virtual implementations of // this class. Eventually we want to remove this virtual base class indirection diff --git a/tensorflow/c/experimental/saved_model/core/saved_model_api.h b/tensorflow/c/experimental/saved_model/core/saved_model_api.h index 5d0ed63a765..ff891e13ba4 100644 --- a/tensorflow/c/experimental/saved_model/core/saved_model_api.h +++ b/tensorflow/c/experimental/saved_model/core/saved_model_api.h @@ -22,6 +22,7 @@ limitations under the License. #include #include "tensorflow/c/experimental/saved_model/core/concrete_function.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function.h" #include "tensorflow/core/platform/status.h" namespace tensorflow { @@ -39,11 +40,11 @@ class SavedModelAPI { virtual Status GetFunction(const std::string& function_path, ConcreteFunction** function) = 0; - // Retrieve a function from a SavedModel, using the key of the + // Retrieve a SignatureDefFunction from a SavedModel, using the key of the // SignatureDef map: // https://github.com/tensorflow/tensorflow/blob/69b08900b1e991d84bce31f3b404f5ed768f339f/tensorflow/core/protobuf/meta_graph.proto#L89 virtual Status GetSignatureDefFunction(const std::string& signature_def_key, - ConcreteFunction** function) = 0; + SignatureDefFunction** function) = 0; virtual std::vector ListFunctions() = 0; diff --git a/tensorflow/c/experimental/saved_model/core/signature_def_function.h b/tensorflow/c/experimental/saved_model/core/signature_def_function.h new file mode 100644 index 00000000000..0a217f3cc21 --- /dev/null +++ b/tensorflow/c/experimental/saved_model/core/signature_def_function.h @@ -0,0 +1,62 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_H_ + +#include +#include + +#include "absl/types/span.h" +#include "tensorflow/c/eager/immediate_execution_operation.h" +#include "tensorflow/c/eager/immediate_execution_tensor_handle.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h" + +namespace tensorflow { + +// See tensorflow/cc/experimental/saved_model/public/signature_def_function.h +// for SignatureDefFunction's intended user-facing semantics. +// This class is the "implementation" C++ part of the C++/C/C++ sandwich for +// a SignatureDefFunction. +// Note(bmzhao): Implementation-wise, SignatureDefFunctions are always saved as +// a "BareConcreteFunction", w/o a FunctionSpec, rather than a SavedFunction: +// https://github.com/tensorflow/tensorflow/blob/9bcefa44cd335c1db4a703a13da09f29ae1bbdb2/tensorflow/core/protobuf/saved_object_graph.proto#L60 +// Additionally they are guaranteed to be children of the .signatures attribute +// of the root object, where the child object "name" is the signature_def key: +// https://github.com/tensorflow/tensorflow/blob/9bcefa44cd335c1db4a703a13da09f29ae1bbdb2/tensorflow/python/saved_model/signature_serialization.py#L181-L230 +// One of the critical requirements of SignatureDef functions is that their +// inputs and outputs are "named". For example, a `.signatures` function: +// a. Requires users to pass: kwargs of all inputs: +// https://github.com/tensorflow/tensorflow/blob/26c4ee0c833e74f94d0102d8b005c41a28b44445/tensorflow/python/saved_model/signature_serialization.py#L119-L126 +// b. Returns a dictionary of named outputs. +// https://github.com/tensorflow/tensorflow/blob/26c4ee0c833e74f94d0102d8b005c41a28b44445/tensorflow/python/saved_model/signature_serialization.py#L153-L161 +// Since SignatureDefFunctions do not have FunctionSpecs, but guarantee the +// dictionary of inputs/outputs, we can parse these dictionaries' keys to obtain +// the input/output names of the SignatureDef: +// https://github.com/tensorflow/tensorflow/blob/9bcefa44cd335c1db4a703a13da09f29ae1bbdb2/tensorflow/core/protobuf/meta_graph.proto#L318-L321 +class SignatureDefFunction { + public: + virtual ~SignatureDefFunction() = default; + + // Creates a "Call" Op used to execute the function. + virtual Status MakeCallOp(absl::Span inputs, + ImmediateOpPtr* out) const = 0; + + virtual const SignatureDefFunctionMetadata& GetFunctionMetadata() const = 0; +}; + +} // namespace tensorflow + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_H_ diff --git a/tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h b/tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h new file mode 100644 index 00000000000..5a579676d4e --- /dev/null +++ b/tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h @@ -0,0 +1,27 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_METADATA_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_METADATA_H_ + +namespace tensorflow { + +class SignatureDefFunctionMetadata { + // TODO(bmzhao): Fill in with fields as necessary +}; + +} // namespace tensorflow + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_CORE_SIGNATURE_DEF_FUNCTION_METADATA_H_ diff --git a/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.cc b/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.cc index 0f0102be857..ab7052b52ed 100644 --- a/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.cc +++ b/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.cc @@ -34,6 +34,7 @@ limitations under the License. #include "tensorflow/c/experimental/saved_model/core/revived_types/tf_concrete_function.h" #include "tensorflow/c/experimental/saved_model/core/revived_types/variable.h" #include "tensorflow/c/experimental/saved_model/core/saved_model_utils.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function.h" #include "tensorflow/cc/saved_model/bundle_v2.h" #include "tensorflow/cc/saved_model/constants.h" #include "tensorflow/core/framework/attr_value.pb.h" @@ -305,7 +306,7 @@ Status TFSavedModelAPI::GetFunction(const std::string& function_path, } Status TFSavedModelAPI::GetSignatureDefFunction( - const std::string& signature_def_key, ConcreteFunction** function) { + const std::string& signature_def_key, SignatureDefFunction** function) { // TODO(bmzhao): Add support for retrieving a signaturedef function. return errors::Unimplemented( "Retrieving SignatureDef functions is unimplemented currently"); diff --git a/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.h b/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.h index fc8e738e86f..fd07c09474b 100644 --- a/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.h +++ b/tensorflow/c/experimental/saved_model/core/tf_saved_model_api.h @@ -28,6 +28,7 @@ limitations under the License. #include "tensorflow/c/experimental/saved_model/core/revived_types/tensorhandle_convertible.h" #include "tensorflow/c/experimental/saved_model/core/revived_types/tf_concrete_function.h" #include "tensorflow/c/experimental/saved_model/core/saved_model_api.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function.h" #include "tensorflow/cc/saved_model/bundle_v2.h" #include "tensorflow/core/platform/status.h" @@ -55,7 +56,7 @@ class TFSavedModelAPI : public SavedModelAPI { ConcreteFunction** function) override; Status GetSignatureDefFunction(const std::string& signature_def_key, - ConcreteFunction** function) override; + SignatureDefFunction** function) override; static Status Load( const std::string& directory, diff --git a/tensorflow/c/experimental/saved_model/internal/BUILD b/tensorflow/c/experimental/saved_model/internal/BUILD index 323298c5fc1..c0d121a4aee 100644 --- a/tensorflow/c/experimental/saved_model/internal/BUILD +++ b/tensorflow/c/experimental/saved_model/internal/BUILD @@ -142,6 +142,8 @@ cc_library( ":concrete_function_list_type", ":concrete_function_type", ":saved_model_api_type", + ":signature_def_function", + ":signature_def_function_type", "//tensorflow/c:c_api_macros", "//tensorflow/c:tf_status", "//tensorflow/c:tf_status_internal", @@ -165,6 +167,77 @@ cc_library( ], ) +cc_library( + name = "signature_def_function", + srcs = [ + "signature_def_function.cc", + ], + hdrs = [ + "//tensorflow/c/experimental/saved_model/public:signature_def_function.h", + ], + copts = tf_copts(), + visibility = [ + "//tensorflow/c/experimental/saved_model/public:__pkg__", + ], + deps = [ + ":signature_def_function_metadata", + ":signature_def_function_metadata_type", + ":signature_def_function_type", + "//tensorflow/c:c_api_macros", + "//tensorflow/c:tf_status_internal", + "//tensorflow/c/eager:abstract_tensor_handle", + "//tensorflow/c/eager:c_api", + "//tensorflow/c/eager:immediate_execution_operation", + "//tensorflow/c/eager:tfe_op_internal", + "//tensorflow/c/eager:tfe_tensorhandle_internal", + "//tensorflow/c/experimental/saved_model/core:signature_def_function", + "//tensorflow/c/experimental/saved_model/core:signature_def_function_metadata", + "//tensorflow/core:lib", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "signature_def_function_type", + hdrs = [ + "signature_def_function_type.h", + ], + deps = [ + "//tensorflow/c:conversion_macros", + "//tensorflow/c/experimental/saved_model/core:signature_def_function", + ], +) + +cc_library( + name = "signature_def_function_metadata", + srcs = [ + "signature_def_function_metadata.cc", + ], + hdrs = [ + "//tensorflow/c/experimental/saved_model/public:signature_def_function_metadata.h", + ], + copts = tf_copts(), + visibility = [ + "//tensorflow/c/experimental/saved_model/public:__pkg__", + ], + deps = [ + ":signature_def_function_metadata_type", + "//tensorflow/c:c_api_macros", + "//tensorflow/c/experimental/saved_model/core:signature_def_function_metadata", + ], +) + +cc_library( + name = "signature_def_function_metadata_type", + hdrs = [ + "signature_def_function_metadata_type.h", + ], + deps = [ + "//tensorflow/c:conversion_macros", + "//tensorflow/c/experimental/saved_model/core:signature_def_function_metadata", + ], +) + tf_cc_test( name = "saved_model_api_test", size = "small", diff --git a/tensorflow/c/experimental/saved_model/internal/saved_model_api.cc b/tensorflow/c/experimental/saved_model/internal/saved_model_api.cc index 983c98affb2..b89fb9f6d64 100644 --- a/tensorflow/c/experimental/saved_model/internal/saved_model_api.cc +++ b/tensorflow/c/experimental/saved_model/internal/saved_model_api.cc @@ -26,6 +26,7 @@ limitations under the License. #include "tensorflow/c/experimental/saved_model/internal/concrete_function_list_type.h" #include "tensorflow/c/experimental/saved_model/internal/concrete_function_type.h" #include "tensorflow/c/experimental/saved_model/internal/saved_model_api_type.h" +#include "tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h" #include "tensorflow/c/tf_status.h" #include "tensorflow/c/tf_status_internal.h" #include "tensorflow/core/common_runtime/eager/context.h" @@ -106,9 +107,11 @@ TF_ConcreteFunction* TF_GetSavedModelConcreteFunction(TF_SavedModel* model, return tensorflow::wrap(result); } -TF_CAPI_EXPORT extern TF_ConcreteFunction* TF_GetSavedModelSignatureDefFunction( - TF_SavedModel* model, const char* signature_def_key, TF_Status* status) { - tensorflow::ConcreteFunction* result = nullptr; +TF_CAPI_EXPORT extern TF_SignatureDefFunction* +TF_GetSavedModelSignatureDefFunction(TF_SavedModel* model, + const char* signature_def_key, + TF_Status* status) { + tensorflow::SignatureDefFunction* result = nullptr; tensorflow::Status get_function_status = tensorflow::unwrap(model)->GetSignatureDefFunction(signature_def_key, &result); diff --git a/tensorflow/c/experimental/saved_model/internal/signature_def_function.cc b/tensorflow/c/experimental/saved_model/internal/signature_def_function.cc new file mode 100644 index 00000000000..64f7506f32e --- /dev/null +++ b/tensorflow/c/experimental/saved_model/internal/signature_def_function.cc @@ -0,0 +1,53 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#include "tensorflow/c/experimental/saved_model/public/signature_def_function.h" + +#include "absl/types/span.h" +#include "tensorflow/c/eager/abstract_tensor_handle.h" +#include "tensorflow/c/eager/immediate_execution_operation.h" +#include "tensorflow/c/eager/tfe_op_internal.h" +#include "tensorflow/c/eager/tfe_tensorhandle_internal.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h" +#include "tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h" +#include "tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h" +#include "tensorflow/c/tf_status_internal.h" +#include "tensorflow/core/platform/status.h" + +extern "C" { + +TF_SignatureDefFunctionMetadata* TF_SignatureDefFunctionGetMetadata( + TF_SignatureDefFunction* func) { + return tensorflow::wrap(const_cast( + &tensorflow::unwrap(func)->GetFunctionMetadata())); +} + +TFE_Op* TF_SignatureDefFunctionMakeCallOp(TF_SignatureDefFunction* func, + TFE_TensorHandle** inputs, + int num_inputs, TF_Status* status) { + tensorflow::ImmediateOpPtr call_op; + absl::Span input_span( + reinterpret_cast( + tensorflow::unwrap(inputs)), + static_cast(num_inputs)); + status->status = tensorflow::unwrap(func)->MakeCallOp(input_span, &call_op); + if (!status->status.ok()) { + return nullptr; + } + return tensorflow::wrap(call_op.release()); +} + +} // end extern "C" diff --git a/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata.cc b/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata.cc new file mode 100644 index 00000000000..c5c3616211c --- /dev/null +++ b/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata.cc @@ -0,0 +1,20 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#include "tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h" + +#include "tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h" + +// TODO(bmzhao): Add getter functions here as necessary. diff --git a/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h b/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h new file mode 100644 index 00000000000..fa6d0f6541e --- /dev/null +++ b/tensorflow/c/experimental/saved_model/internal/signature_def_function_metadata_type.h @@ -0,0 +1,31 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_METADATA_TYPE_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_METADATA_TYPE_H_ + +#include "tensorflow/c/conversion_macros.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function_metadata.h" + +typedef struct TF_SignatureDefFunctionMetadata TF_SignatureDefFunctionMetadata; + +namespace tensorflow { + +DEFINE_CONVERSION_FUNCTIONS(tensorflow::SignatureDefFunctionMetadata, + TF_SignatureDefFunctionMetadata) + +} // namespace tensorflow + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_METADATA_TYPE_H_ diff --git a/tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h b/tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h new file mode 100644 index 00000000000..ca44dc43bd6 --- /dev/null +++ b/tensorflow/c/experimental/saved_model/internal/signature_def_function_type.h @@ -0,0 +1,31 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_TYPE_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_TYPE_H_ + +#include "tensorflow/c/conversion_macros.h" +#include "tensorflow/c/experimental/saved_model/core/signature_def_function.h" + +typedef struct TF_SignatureDefFunction TF_SignatureDefFunction; + +namespace tensorflow { + +DEFINE_CONVERSION_FUNCTIONS(tensorflow::SignatureDefFunction, + TF_SignatureDefFunction) + +} // namespace tensorflow + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_INTERNAL_SIGNATURE_DEF_FUNCTION_TYPE_H_ diff --git a/tensorflow/c/experimental/saved_model/public/BUILD b/tensorflow/c/experimental/saved_model/public/BUILD index af65e05e7f6..d29585ae1ba 100644 --- a/tensorflow/c/experimental/saved_model/public/BUILD +++ b/tensorflow/c/experimental/saved_model/public/BUILD @@ -24,6 +24,8 @@ exports_files( "concrete_function_list.h", "function_metadata.h", "saved_model_api.h", + "signature_def_function.h", + "signature_def_function_metadata.h", ], visibility = ["//tensorflow/c/experimental/saved_model/internal:__pkg__"], ) @@ -39,6 +41,8 @@ cc_library( ":concrete_function_list", ":function_metadata", ":saved_model_api", + ":signature_def_function", + ":signature_def_function_metadata", ], ) @@ -61,3 +65,13 @@ alias( name = "saved_model_api", actual = "//tensorflow/c/experimental/saved_model/internal:saved_model_api", ) + +alias( + name = "signature_def_function", + actual = "//tensorflow/c/experimental/saved_model/internal:signature_def_function", +) + +alias( + name = "signature_def_function_metadata", + actual = "//tensorflow/c/experimental/saved_model/internal:signature_def_function_metadata", +) diff --git a/tensorflow/c/experimental/saved_model/public/c_saved_model_api.h b/tensorflow/c/experimental/saved_model/public/c_saved_model_api.h index 30f533f140a..cedb9de66b8 100644 --- a/tensorflow/c/experimental/saved_model/public/c_saved_model_api.h +++ b/tensorflow/c/experimental/saved_model/public/c_saved_model_api.h @@ -21,6 +21,8 @@ limitations under the License. #include "tensorflow/c/experimental/saved_model/public/concrete_function_list.h" #include "tensorflow/c/experimental/saved_model/public/function_metadata.h" #include "tensorflow/c/experimental/saved_model/public/saved_model_api.h" +#include "tensorflow/c/experimental/saved_model/public/signature_def_function.h" +#include "tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h" // IWYU pragma: end_exports #endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_C_SAVED_MODEL_API_H_ diff --git a/tensorflow/c/experimental/saved_model/public/concrete_function.h b/tensorflow/c/experimental/saved_model/public/concrete_function.h index ee5292294d6..0fd0f70cf16 100644 --- a/tensorflow/c/experimental/saved_model/public/concrete_function.h +++ b/tensorflow/c/experimental/saved_model/public/concrete_function.h @@ -40,6 +40,13 @@ TF_CAPI_EXPORT extern TF_FunctionMetadata* TF_ConcreteFunctionGetMetadata( // The caller is responsible for deleting the returned TFE_Op. If op // construction fails, `status` will be non-OK and the returned pointer will be // null. +// TODO(bmzhao): Remove this function in a subsequent change; Design + implement +// a Function Execution interface for ConcreteFunction that accepts a tagged +// union of types (tensorflow::Value). This effectively requires moving much of +// the implementation of function.py/def_function.py to C++, and exposing a +// high-level API here. A strawman for what this interface could look like: +// TF_Value* TF_ExecuteFunction(TFE_Context*, TF_ConcreteFunction*, TF_Value* +// inputs, int num_inputs, TF_Status* status); TF_CAPI_EXPORT extern TFE_Op* TF_ConcreteFunctionGetCallOp( TF_ConcreteFunction* func, TFE_TensorHandle** inputs, int num_inputs, TF_Status* status); diff --git a/tensorflow/c/experimental/saved_model/public/saved_model_api.h b/tensorflow/c/experimental/saved_model/public/saved_model_api.h index 875167bec63..80ba37bab26 100644 --- a/tensorflow/c/experimental/saved_model/public/saved_model_api.h +++ b/tensorflow/c/experimental/saved_model/public/saved_model_api.h @@ -19,6 +19,7 @@ limitations under the License. #include "tensorflow/c/c_api_macros.h" #include "tensorflow/c/experimental/saved_model/public/concrete_function.h" #include "tensorflow/c/experimental/saved_model/public/concrete_function_list.h" +#include "tensorflow/c/experimental/saved_model/public/signature_def_function.h" #include "tensorflow/c/tf_status.h" #ifdef __cplusplus @@ -91,10 +92,13 @@ TF_CAPI_EXPORT extern TF_ConcreteFunction* TF_GetSavedModelConcreteFunction( // status - Set to OK on success and an appropriate error on failure. // Returns: // If status is not OK, returns nullptr. Otherwise, returns a -// TF_ConcreteFunction instance. Once `model` is deleted, all -// `TF_ConcreteFunctions` retrieved from it are invalid, and have been deleted. -TF_CAPI_EXPORT extern TF_ConcreteFunction* TF_GetSavedModelSignatureDefFunction( - TF_SavedModel* model, const char* signature_def_key, TF_Status* status); +// TF_SignatureDefFunction instance. Once `model` is deleted, all +// `TF_SignatureDefFunctions` retrieved from it are invalid, and have been +// deleted. +TF_CAPI_EXPORT extern TF_SignatureDefFunction* +TF_GetSavedModelSignatureDefFunction(TF_SavedModel* model, + const char* signature_def_key, + TF_Status* status); // Returns a list of all ConcreteFunctions stored in this SavedModel. // The lifetime of the returned list is bound to `model`. diff --git a/tensorflow/c/experimental/saved_model/public/signature_def_function.h b/tensorflow/c/experimental/saved_model/public/signature_def_function.h new file mode 100644 index 00000000000..16471fdc1fa --- /dev/null +++ b/tensorflow/c/experimental/saved_model/public/signature_def_function.h @@ -0,0 +1,50 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ + +#include "tensorflow/c/c_api_macros.h" +#include "tensorflow/c/eager/c_api.h" +#include "tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// An opaque type that corresponds to a SignatureDefFunction loaded from a +// SavedModel. +typedef struct TF_SignatureDefFunction TF_SignatureDefFunction; + +// Returns FunctionMetadata associated with `func`. Metadata's lifetime is +// bound to `func`, which is bound to the TF_SavedModel it was loaded from. +TF_CAPI_EXPORT extern TF_SignatureDefFunctionMetadata* +TF_SignatureDefFunctionGetMetadata(TF_SignatureDefFunction* func); + +// Returns a TFE_Op suitable for executing this function. Caller must provide +// all function inputs in `inputs`, and must not add any additional inputs on +// the returned op. (i.e. don't call TFE_OpAddInput or TFE_OpAddInputList). +// The caller is responsible for deleting the returned TFE_Op. If op +// construction fails, `status` will be non-OK and the returned pointer will be +// null. +TF_CAPI_EXPORT extern TFE_Op* TF_SignatureDefFunctionMakeCallOp( + TF_SignatureDefFunction* func, TFE_TensorHandle** inputs, int num_inputs, + TF_Status* status); + +#ifdef __cplusplus +} // end extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ diff --git a/tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h b/tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h new file mode 100644 index 00000000000..6f4459732c4 --- /dev/null +++ b/tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h @@ -0,0 +1,31 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_ +#define TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// An opaque type that corresponds to a SignatureDefFunction loaded from a +// SavedModel. +typedef struct TF_SignatureDefFunctionMetadata TF_SignatureDefFunctionMetadata; + +#ifdef __cplusplus +} // end extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_C_EXPERIMENTAL_SAVED_MODEL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_ diff --git a/tensorflow/cc/saved_model/experimental/public/BUILD b/tensorflow/cc/saved_model/experimental/public/BUILD index 3e9a671a61f..9640848ebf5 100644 --- a/tensorflow/cc/saved_model/experimental/public/BUILD +++ b/tensorflow/cc/saved_model/experimental/public/BUILD @@ -51,8 +51,32 @@ cc_library( deps = [ ":concrete_function", ":concrete_function_list", + ":signature_def_function", "//tensorflow/c/experimental/saved_model/public:saved_model_api", "//tensorflow/cc/experimental/base/public:runtime", "//tensorflow/cc/experimental/base/public:status", ], ) + +cc_library( + name = "signature_def_function", + hdrs = [ + "signature_def_function.h", + ], + deps = [ + ":signature_def_function_metadata", + "//tensorflow/c/eager:c_api", + "//tensorflow/c/experimental/saved_model/public:signature_def_function", + "//tensorflow/cc/experimental/base/public:status", + ], +) + +cc_library( + name = "signature_def_function_metadata", + hdrs = [ + "signature_def_function_metadata.h", + ], + deps = [ + "//tensorflow/c/experimental/saved_model/public:signature_def_function_metadata", + ], +) diff --git a/tensorflow/cc/saved_model/experimental/public/saved_model_api.h b/tensorflow/cc/saved_model/experimental/public/saved_model_api.h index 04018bf2aab..c2bfb4dcf83 100644 --- a/tensorflow/cc/saved_model/experimental/public/saved_model_api.h +++ b/tensorflow/cc/saved_model/experimental/public/saved_model_api.h @@ -26,6 +26,7 @@ limitations under the License. #include "tensorflow/cc/experimental/base/public/status.h" #include "tensorflow/cc/saved_model/experimental/public/concrete_function.h" #include "tensorflow/cc/saved_model/experimental/public/concrete_function_list.h" +#include "tensorflow/cc/saved_model/experimental/public/signature_def_function.h" namespace tensorflow { namespace experimental { @@ -80,8 +81,8 @@ class SavedModelAPI { // If status is not OK, returns nullptr. Otherwise, returns a // tensorflow::cc::ConcreteFunction pointer. The lifetime of this pointer // is bound to SavedModelAPI it was loaded from. - ConcreteFunction* GetSignatureDefFunction(const std::string& function_path, - Status* status); + SignatureDefFunction* GetSignatureDefFunction( + const std::string& function_path, Status* status); // Lists all Conrete Functions available from the SavedModel. std::vector ListFunctions(); @@ -140,14 +141,14 @@ inline ConcreteFunction* SavedModelAPI::GetConcreteFunction( return ConcreteFunction::wrap(function); } -inline ConcreteFunction* SavedModelAPI::GetSignatureDefFunction( +inline SignatureDefFunction* SavedModelAPI::GetSignatureDefFunction( const std::string& function_path, Status* status) { - TF_ConcreteFunction* function = TF_GetSavedModelSignatureDefFunction( + TF_SignatureDefFunction* function = TF_GetSavedModelSignatureDefFunction( saved_model_.get(), function_path.c_str(), status->GetTFStatus()); if (!status->ok()) { return nullptr; } - return ConcreteFunction::wrap(function); + return SignatureDefFunction::wrap(function); } inline std::vector SavedModelAPI::ListFunctions() { diff --git a/tensorflow/cc/saved_model/experimental/public/signature_def_function.h b/tensorflow/cc/saved_model/experimental/public/signature_def_function.h new file mode 100644 index 00000000000..bc72d208e87 --- /dev/null +++ b/tensorflow/cc/saved_model/experimental/public/signature_def_function.h @@ -0,0 +1,89 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ +#define TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ + +#include + +#include "tensorflow/c/eager/c_api.h" +#include "tensorflow/c/experimental/saved_model/public/signature_def_function.h" +#include "tensorflow/cc/experimental/base/public/status.h" +#include "tensorflow/cc/saved_model/experimental/public/signature_def_function_metadata.h" + +namespace tensorflow { +namespace experimental { +namespace cc { + +// SignatureDefFunctions are functions that correspond to either: +// "signatures" saved from a TF2 SavedModel APIs: +// https://github.com/tensorflow/tensorflow/blob/8ce0600f58ed84a8c84a7bbdb014d1f09e44f4c8/tensorflow/python/saved_model/save.py#L830-L854 +// Or the "SignatureDefMap" saved from TF1 SavedModel APIs: +// https://github.com/tensorflow/tensorflow/blob/8ce0600f58ed84a8c84a7bbdb014d1f09e44f4c8/tensorflow/python/saved_model/load_v1_in_v2_test.py#L170-L174 +// In both cases, a SignatureDef is serialized as a SignatureDef protobuf: +// https://github.com/tensorflow/tensorflow/blob/8ce0600f58ed84a8c84a7bbdb014d1f09e44f4c8/tensorflow/core/protobuf/meta_graph.proto#L260-L330 +// and represents a computation defined by a TF subgraph. +// These Signatures were primarily designed to be interoperable with the legacy +// TF 1 Session-based C++ SavedModelBundle loading APIs: +// https://github.com/tensorflow/tensorflow/blob/26c4ee0c833e74f94d0102d8b005c41a28b44445/tensorflow/cc/saved_model/loader.h#L96-L108 +// SignatureDefFunctions have different semantics from regular TF2 +// ConcreteFunctions, and are mainly intended provide a serving-friendly +// transition point from the TF1 Session API. +// First, SignatureDefFunctions have different calling conventions. +// SignatureDefFunctions' inputs and outputs are constrained to **flattened +// lists of TensorHandles only**. They do not support more exotic input/output +// types (like optionals, generators, etc). Additionally, this flattening means +// they will not preserve the exact interface of the original tf.function they +// were traced from, as things like composite tensors decay into their +// internal dense tensor representation. +// Second, all inputs and outputs are "named", and these names are load bearing +// (eg: they are part of the interface of tensorflow_serving): +// https://github.com/tensorflow/serving/blob/e0d247b2e4050713194b8fad0be24a0636df7209/tensorflow_serving/apis/predict.proto#L21 +// https://github.com/tensorflow/serving/blob/e0d247b2e4050713194b8fad0be24a0636df7209/tensorflow_serving/apis/predict.proto#L39 +// The name of each input/output is stored in the corresponding tf::Argument in +// SignatureDefFunctionMetadata::arguments(). Users must ensure the order of +// TensorHandles passed to the function matches with the order of named +// arguments. Similarly the name of the outputs is stored in +// SignatureDefFunctionMetadata::returns(). +class SignatureDefFunction final { + public: + // Returns FunctionMetadata associated with this ConcreteFunction. + const SignatureDefFunctionMetadata* GetFunctionMetadata(); + + private: + friend class SavedModelAPI; + friend class ConcreteFunctionList; + + // TODO(bmzhao): Consider adding a macro for wrapping/unwrapping + // when moving out of experimental. + static SignatureDefFunction* wrap(TF_SignatureDefFunction* p) { + return reinterpret_cast(p); + } + static TF_SignatureDefFunction* unwrap(SignatureDefFunction* p) { + return reinterpret_cast(p); + } +}; + +inline const SignatureDefFunctionMetadata* +SignatureDefFunction::GetFunctionMetadata() { + return SignatureDefFunctionMetadata::wrap( + TF_SignatureDefFunctionGetMetadata(unwrap(this))); +} + +} // namespace cc +} // namespace experimental +} // namespace tensorflow + +#endif // TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_H_ diff --git a/tensorflow/cc/saved_model/experimental/public/signature_def_function_metadata.h b/tensorflow/cc/saved_model/experimental/public/signature_def_function_metadata.h new file mode 100644 index 00000000000..6cb01bf1a26 --- /dev/null +++ b/tensorflow/cc/saved_model/experimental/public/signature_def_function_metadata.h @@ -0,0 +1,47 @@ +/* Copyright 2020 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. +==============================================================================*/ + +#ifndef TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_ +#define TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_ + +#include + +#include "tensorflow/c/experimental/saved_model/public/signature_def_function_metadata.h" + +namespace tensorflow { +namespace experimental { +namespace cc { + +// SignatureDefFunctionMetadata stores additional information on each input +// and output's names, dtypes, and shape. +class SignatureDefFunctionMetadata final { + // TODO(bmzhao): Add getters here as necessary. + private: + friend class SignatureDefFunction; + static SignatureDefFunctionMetadata* wrap( + TF_SignatureDefFunctionMetadata* p) { + return reinterpret_cast(p); + } + static TF_SignatureDefFunctionMetadata* unwrap( + SignatureDefFunctionMetadata* p) { + return reinterpret_cast(p); + } +}; + +} // namespace cc +} // namespace experimental +} // namespace tensorflow + +#endif // TENSORFLOW_CC_SAVED_MODEL_EXPERIMENTAL_PUBLIC_SIGNATURE_DEF_FUNCTION_METADATA_H_