Graph to FunctionDef conversion. This code is closely modeled on the Python function graph_to_function_def(), which is located in tensorflow/python/framework/graph_to_function_def.py.
| 303 | // function graph_to_function_def(), which is located in |
| 304 | // tensorflow/python/framework/graph_to_function_def.py. |
| 305 | Status GraphToFunctionDef(const Graph& fn_body, const string& fn_name, |
| 306 | bool append_hash_to_fn_name, |
| 307 | const std::vector<const Node*>& body_nodes, |
| 308 | const std::vector<OutputTensor>& inputs, |
| 309 | const std::vector<OutputTensor>& outputs, |
| 310 | const std::vector<string>& output_names, |
| 311 | const std::vector<const Node*>& control_outputs, |
| 312 | const std::vector<string>& control_output_names, |
| 313 | const char* description, FunctionDef* fdef) { |
| 314 | if (!output_names.empty()) { |
| 315 | DCHECK_EQ(output_names.size(), outputs.size()); |
| 316 | } |
| 317 | |
| 318 | if (description != nullptr) { |
| 319 | fdef->mutable_signature()->set_description(description); |
| 320 | } |
| 321 | |
| 322 | // Keep track of names we used and how we normalized them. |
| 323 | NodeNameMapping node_names; |
| 324 | |
| 325 | // Mapping from original names of tensors (i.e. "<node_name>:<idx>") to the |
| 326 | // name we used in the function: |
| 327 | // - For input tensors: |
| 328 | // {flat_tensor_name -> normalized_name_of_src_node} |
| 329 | // e.g. {In:3 -> in} |
| 330 | // - For tensors produced by nodes in function's body: |
| 331 | // {flat_tensor_name -> nested_tensor_name} |
| 332 | // e.g. {Add:3 -> add_0:z:1} |
| 333 | std::unordered_map<string, string> tensor_renaming; |
| 334 | |
| 335 | // Fill outputs in function's signature. |
| 336 | // We fill the outputs first to prevent output_names from colliding |
| 337 | // with the input names we pick below. With this order, no names are used in |
| 338 | // node_names yet, and output_names won't collide with anything (except |
| 339 | // potentially with themselves). |
| 340 | for (size_t i = 0; i < outputs.size(); ++i) { |
| 341 | const Node* node = outputs[i].node; |
| 342 | int idx = outputs[i].index; |
| 343 | OpDef::ArgDef* argdef = fdef->mutable_signature()->add_output_arg(); |
| 344 | argdef->set_type(node->output_type(idx)); |
| 345 | if (!output_names.empty()) { |
| 346 | TF_RETURN_IF_ERROR(node_names.UseOutputName(output_names[i])); |
| 347 | argdef->set_name(output_names[i]); |
| 348 | } else { |
| 349 | argdef->set_name(node_names.GetOutputName(node->name())); |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | // Fill inputs in function's signature. |
| 354 | for (size_t i = 0; i < inputs.size(); ++i) { |
| 355 | const Node* node = inputs[i].node; |
| 356 | int idx = inputs[i].index; |
| 357 | OpDef::ArgDef* argdef = fdef->mutable_signature()->add_input_arg(); |
| 358 | argdef->set_type(node->output_type(idx)); |
| 359 | const string& input_name = node_names.GetInputName(node->name()); |
| 360 | argdef->set_name(input_name); |
| 361 | auto& arg_attrs = (*fdef->mutable_arg_attr())[i]; |
| 362 | for (const auto& attr : node->attrs()) { |
no test coverage detected