@@ -25,6 +25,7 @@ limitations under the License.
2525#include " tensorflow/core/framework/node_def_util.h"
2626#include " tensorflow/core/framework/types.h"
2727#include " tensorflow/core/graph/graph.h"
28+ #include " tensorflow/core/lib/strings/base64.h"
2829#include " tensorflow/core/lib/strings/strcat.h"
2930
3031using tensorflow::errors::InvalidArgument;
@@ -232,6 +233,7 @@ Status FillFunctionBody(
232233// Graph to FunctionDef conversion. This code is closely modeled on the Python
233234// code in third_party/tensorflow/python/framework/function.py.
234235Status GraphToFunctionDef (const Graph& fn_body, const string& fn_name,
236+ bool append_hash_to_fn_name,
235237 const std::vector<const Node*>& body_nodes,
236238 const std::vector<OutputTensor>& inputs,
237239 const std::vector<OutputTensor>& outputs,
@@ -241,7 +243,6 @@ Status GraphToFunctionDef(const Graph& fn_body, const string& fn_name,
241243 DCHECK_EQ (output_names.size (), outputs.size ());
242244 }
243245
244- fdef->mutable_signature ()->set_name (fn_name);
245246 if (description != nullptr ) {
246247 fdef->mutable_signature ()->set_description (description);
247248 }
@@ -328,7 +329,6 @@ Status GraphToFunctionDef(const Graph& fn_body, const string& fn_name,
328329 // Remap return values.
329330 for (int r = 0 ; r < fdef->signature ().output_arg_size (); ++r) {
330331 const string& ret_name = fdef->signature ().output_arg (r).name ();
331-
332332 // We convert this flat tensor name to the nested value
333333 // (e.g. `add:z:1`) that we stored in tensor_renaming.
334334 const string& return_value =
@@ -343,6 +343,24 @@ Status GraphToFunctionDef(const Graph& fn_body, const string& fn_name,
343343 (*fdef->mutable_ret ())[ret_name] = iter->second ;
344344 }
345345
346+ if (append_hash_to_fn_name) {
347+ const uint64 hash = FunctionDefHash (*fdef);
348+ string encoded;
349+ TF_RETURN_IF_ERROR (Base64Encode (
350+ StringPiece (reinterpret_cast <const char *>(&hash), sizeof (hash)),
351+ &encoded));
352+ // Besides letters and digits our Base64 encoding uses '_' and '-'.
353+ // Dash is invalid in operation names and multiple underscores in random
354+ // places look strange. Since we never need to decode the hash back,
355+ // replace these chars with with 'a' and 'A'. Replacing with different
356+ // letters keeps more entropy.
357+ std::replace (encoded.begin (), encoded.end (), ' -' , ' a' );
358+ std::replace (encoded.begin (), encoded.end (), ' _' , ' A' );
359+ fdef->mutable_signature ()->set_name (strings::StrCat (fn_name, " _" , encoded));
360+ } else {
361+ fdef->mutable_signature ()->set_name (fn_name);
362+ }
363+
346364 return Status::OK ();
347365}
348366
@@ -451,6 +469,7 @@ using tensorflow::Node;
451469using tensorflow::string;
452470
453471TF_Function* TF_GraphToFunction (const TF_Graph* fn_body, const char * fn_name,
472+ unsigned char append_hash_to_fn_name,
454473 int num_opers, const TF_Operation* const * opers,
455474 int ninputs, const TF_Output* inputs,
456475 int noutputs, const TF_Output* outputs,
@@ -489,9 +508,11 @@ TF_Function* TF_GraphToFunction(const TF_Graph* fn_body, const char* fn_name,
489508
490509 // Do the actual function creation.
491510 TF_Function* tf_function = new TF_Function ();
511+ DCHECK (append_hash_to_fn_name <= 1 );
492512 status->status = tensorflow::GraphToFunctionDef (
493- fn_body->graph , fn_name, body_nodes, input_tensors, output_tensors,
494- output_names_vec, description, &tf_function->fdef );
513+ fn_body->graph , fn_name, append_hash_to_fn_name != 0 , body_nodes,
514+ input_tensors, output_tensors, output_names_vec, description,
515+ &tf_function->fdef );
495516 if (!status->status .ok ()) {
496517 TF_DeleteFunction (tf_function);
497518 return nullptr ;
0 commit comments