| 212 | } |
| 213 | |
| 214 | Status MakeGrapplerFunctionItem(const FunctionDef& func, |
| 215 | const AttrSlice& func_instantiation_attr, |
| 216 | const FunctionLibraryDefinition& flib, |
| 217 | const int graph_def_version, |
| 218 | GrapplerFunctionItem* item) { |
| 219 | const OpDef& signature = func.signature(); |
| 220 | |
| 221 | if (signature.name().empty()) { |
| 222 | return errors::InvalidArgument("Function name must be specified"); |
| 223 | } |
| 224 | |
| 225 | // Function types will be resolved from function instantiation attributes. All |
| 226 | // other attributes will be lost during conversion to FunctionDef. |
| 227 | for (const OpDef::AttrDef& attr : signature.attr()) { |
| 228 | if (attr.type() != "type") { |
| 229 | return errors::InvalidArgument( |
| 230 | "Function signature must have only type attributes"); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | // Instantiate function into a statically defined FunctionBody Graph. |
| 235 | std::unique_ptr<FunctionBody> fbody; |
| 236 | TF_RETURN_IF_ERROR( |
| 237 | FunctionDefToBodyHelper(func, func_instantiation_attr, &flib, &fbody)); |
| 238 | |
| 239 | GraphDef function_body; |
| 240 | fbody->graph->ToGraphDef(&function_body); |
| 241 | |
| 242 | // Function body shares the library with the graph that instantiated it. We do |
| 243 | // not need a full copy of the function library, just the reachable subset. |
| 244 | *function_body.mutable_library() = flib.ReachableDefinitions(func).ToProto(); |
| 245 | |
| 246 | VLOG(3) << absl::Substitute( |
| 247 | "Deleted $0 unreachable functions from the Grappler function item " |
| 248 | "instantiation of $1 (library size = $2)", |
| 249 | flib.num_functions() - function_body.library().function_size(), |
| 250 | signature.name(), function_body.library().function_size()); |
| 251 | |
| 252 | const int num_instantiated_inputs = fbody->arg_types.size(); |
| 253 | const int num_instantiated_outputs = fbody->ret_types.size(); |
| 254 | |
| 255 | std::vector<InputArgInstantiation> inputs; |
| 256 | inputs.reserve(num_instantiated_inputs); |
| 257 | |
| 258 | for (int in_id = 0; in_id < num_instantiated_inputs; ++in_id) { |
| 259 | const Node* node = fbody->arg_nodes[in_id]; |
| 260 | const DataType& dtype = fbody->arg_types[in_id]; |
| 261 | inputs.emplace_back(node->name(), dtype); |
| 262 | } |
| 263 | |
| 264 | std::vector<OutputArgInstantiation> outputs; |
| 265 | outputs.reserve(num_instantiated_outputs); |
| 266 | |
| 267 | for (int out_id = 0; out_id < num_instantiated_outputs; ++out_id) { |
| 268 | const Node* node = fbody->ret_nodes[out_id]; |
| 269 | const DataType& dtype = fbody->ret_types[out_id]; |
| 270 | outputs.emplace_back(node->name(), dtype); |
| 271 | } |