| 895 | } |
| 896 | |
| 897 | TF_Operation* TFE_AddEagerOpToGraph(TFE_Op* op, TFE_TraceContext* trace_ctx, |
| 898 | TFE_TensorHandle** retvals, |
| 899 | int* num_retvals, TF_Status* status) { |
| 900 | VLOG(1) << "Calling TFE_AddEagerOpToGraph() with op " << op << ": " |
| 901 | << op->operation.DebugString(); |
| 902 | |
| 903 | const auto& op_type = op->operation.Name(); |
| 904 | auto op_name = |
| 905 | tensorflow::strings::StrCat(op_type, "_", trace_ctx->node_counter++); |
| 906 | std::unique_ptr<TF_OperationDescription> desc( |
| 907 | TF_NewOperation(trace_ctx->graph, op_type.c_str(), op_name.c_str())); |
| 908 | |
| 909 | VLOG(1) << "Adding attrs."; |
| 910 | tensorflow::AttrValueMap attrs; |
| 911 | op->operation.Attrs().FillAttrValueMap(&attrs); |
| 912 | for (const auto& attr : attrs) { |
| 913 | desc->node_builder.Attr(attr.first, attr.second); |
| 914 | } |
| 915 | |
| 916 | VLOG(1) << "Adding inputs."; |
| 917 | const auto& inputs = op->operation.Inputs(); |
| 918 | size_t inputIndex = 0; |
| 919 | const tensorflow::OpDef& op_def = desc->node_builder.op_def(); |
| 920 | for (const tensorflow::OpDef::ArgDef& input_arg : op_def.input_arg()) { |
| 921 | if (input_arg.type_list_attr().empty() && input_arg.number_attr().empty()) { |
| 922 | auto symbolic_input = |
| 923 | getOrCreateSymbolicTensor(trace_ctx, inputs[inputIndex++], status); |
| 924 | if (!status->status.ok()) return nullptr; |
| 925 | TF_AddInput(desc.get(), symbolic_input); |
| 926 | continue; |
| 927 | } |
| 928 | size_t list_size = 0; |
| 929 | if (!input_arg.type_list_attr().empty()) { |
| 930 | const std::string& type_list_attr = input_arg.type_list_attr(); |
| 931 | const auto& attr_value = attrs[type_list_attr]; |
| 932 | CHECK(attr_value.value_case() == tensorflow::AttrValue::kList) |
| 933 | << "Type list attribute should be a list!"; |
| 934 | list_size = attr_value.list().type_size(); |
| 935 | } else { |
| 936 | CHECK(!input_arg.number_attr().empty()); |
| 937 | const auto& attr_value = attrs[input_arg.number_attr()]; |
| 938 | CHECK(attr_value.value_case() == tensorflow::AttrValue::kI) |
| 939 | << "Number attribute should be int!"; |
| 940 | if (attr_value.i() < 0) { |
| 941 | status->status = tensorflow::errors::Internal( |
| 942 | "Number attribute for length should be >=0!"); |
| 943 | return nullptr; |
| 944 | } |
| 945 | list_size = attr_value.i(); |
| 946 | } |
| 947 | std::vector<TF_Output> list_inputs(list_size); |
| 948 | for (TF_Output& list_input : list_inputs) { |
| 949 | list_input = |
| 950 | getOrCreateSymbolicTensor(trace_ctx, inputs[inputIndex++], status); |
| 951 | if (!status->status.ok()) return nullptr; |
| 952 | } |
| 953 | TF_AddInputList(desc.get(), list_inputs.data(), list_inputs.size()); |
| 954 | } |