You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

net_output_pass.cc 38 kB

5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /**
  2. * Copyright 2020 Huawei Technologies Co., Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "graph/passes/net_output_pass.h"
  17. #include <map>
  18. #include <memory>
  19. #include <string>
  20. #include <utility>
  21. #include <vector>
  22. #include "common/ge/ge_util.h"
  23. #include "framework/common/debug/ge_log.h"
  24. #include "framework/common/ge_inner_error_codes.h"
  25. #include "framework/omg/omg_inner_types.h"
  26. #include "graph/debug/ge_attr_define.h"
  27. #include "common/local_context.h"
  28. #include "graph/passes/pass_utils.h"
  29. #include "graph/utils/tensor_utils.h"
  30. #include "graph/utils/type_utils.h"
  31. namespace ge {
  32. static std::map<std::string, ge::DataType> output_type_str_to_datatype = {
  33. {"FP32", ge::DT_FLOAT}, {"FP16", ge::DT_FLOAT16}, {"INT8", ge::DT_INT8}, {"INT16", ge::DT_INT16},
  34. {"UINT16", ge::DT_UINT16}, {"UINT8", ge::DT_UINT8}, {"INT32", ge::DT_INT32}, {"INT64", ge::DT_INT64},
  35. {"UINT32", ge::DT_UINT32}, {"UINT64", ge::DT_UINT64}, {"DOUBLE", ge::DT_DOUBLE}};
  36. // the size of user defined output datatype or format string after split by ":".
  37. const size_t kUserDefinedElementCount = 2;
  38. const size_t kNodesCount = 2;
  39. Status NetOutputPass::GetRetvalOutputInfo(const ge::NodePtr &node,
  40. std::map<int32_t, RetvalInfo> &retval_node_index_map) {
  41. GE_CHECK_NOTNULL(node);
  42. GE_CHECK_NOTNULL(node->GetOpDesc());
  43. int64_t output_index = 0;
  44. if (!AttrUtils::GetInt(node->GetOpDesc(), RETVAL_ATTR_NAME_INDEX, output_index)) {
  45. REPORT_CALL_ERROR("E19999", "Get Attr:%s from op:%s(%s) failed", RETVAL_ATTR_NAME_INDEX.c_str(),
  46. node->GetName().c_str(), node->GetType().c_str());
  47. GELOGE(PARAM_INVALID, "[Get][Attr] %s from op:%s(%s) failed", RETVAL_ATTR_NAME_INDEX.c_str(),
  48. node->GetName().c_str(), node->GetType().c_str());
  49. return PARAM_INVALID;
  50. }
  51. if (retval_node_index_map.count(output_index) > 0) {
  52. REPORT_INNER_ERROR("E19999", "Attr:%s from op:%s(%s), value:%ld duplicate with other node, check invalid",
  53. RETVAL_ATTR_NAME_INDEX.c_str(), node->GetName().c_str(), node->GetType().c_str(), output_index);
  54. GELOGE(PARAM_INVALID, "[Check][Param] Attr:%s from op:%s(%s), value:%ld duplicate with other node.",
  55. RETVAL_ATTR_NAME_INDEX.c_str(), node->GetName().c_str(), node->GetType().c_str(), output_index);
  56. return PARAM_INVALID;
  57. }
  58. int parent_node_index = -1;
  59. (void)AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_PARENT_NODE_INDEX, parent_node_index);
  60. InDataAnchorPtr in_data_anchor = node->GetInDataAnchor(0);
  61. GE_CHECK_NOTNULL(in_data_anchor);
  62. GE_CHECK_NOTNULL(in_data_anchor->GetPeerOutAnchor());
  63. int32_t src_node_index = in_data_anchor->GetPeerOutAnchor()->GetIdx();
  64. NodePtr src_node_ptr = in_data_anchor->GetPeerOutAnchor()->GetOwnerNode();
  65. retval_node_index_map[output_index] = {src_node_ptr, src_node_index, parent_node_index};
  66. // if user targets include retval node,delete it from set and insert its input node instead
  67. // better to GetInNodes here
  68. auto iter = targets_.find(node);
  69. if (iter != targets_.end()) {
  70. targets_.erase(iter);
  71. targets_.insert(src_node_ptr);
  72. GELOGI("Node [%s] is in user def targets, do not output result to user!", node->GetName().c_str());
  73. }
  74. is_include_special_node_ = true;
  75. return SUCCESS;
  76. }
  77. Status NetOutputPass::GetOutputNode(const ge::ComputeGraphPtr &graph, std::vector<RetvalInfo> &output_nodes_info) {
  78. std::map<int32_t, RetvalInfo> retval_node_index_map;
  79. for (NodePtr &node : graph->GetDirectNode()) {
  80. Status ret = SUCCESS;
  81. if ((node->GetOpDesc() != nullptr) && (node->GetOpDesc()->HasAttr(RETVAL_ATTR_NAME_INDEX))) {
  82. /// Set the output according to the Retval operator,
  83. /// identify by whether there is an index parameter
  84. ret = GetRetvalOutputInfo(node, retval_node_index_map);
  85. }
  86. if (ret != SUCCESS) {
  87. GELOGE(ret, "[Get][RetvalOutputInfo] for node:%s failed", node->GetName().c_str());
  88. return ret;
  89. }
  90. }
  91. GELOGI("Get retval node size:%zu.", retval_node_index_map.size());
  92. std::vector<RetvalInfo> out_nodes_tmp;
  93. /// The Netoutput output is determined by Retval, and the input order
  94. /// of Netoutput is sorted according to the index value of Retval.
  95. for (auto &it : retval_node_index_map) {
  96. out_nodes_tmp.push_back(it.second);
  97. }
  98. // when user set targets, mean that no output result
  99. for (auto &ele : graph->GetGraphOutNodesInfo()) {
  100. auto iter = targets_.find(ele.first);
  101. if (iter != targets_.end()) {
  102. GELOGI("User set out node [%s] is found in user def targets, out node is prior!", ele.first->GetName().c_str());
  103. targets_.erase(iter);
  104. }
  105. auto op_desc = ele.first->GetOpDesc();
  106. GE_CHECK_NOTNULL(op_desc);
  107. if (op_desc->HasAttr(ATTR_ATC_USER_DEFINE_OUTPUT_NODES)) {
  108. is_user_define_ouput_nodes = true;
  109. }
  110. int parent_index = -1;
  111. auto output_desc = op_desc->MutableOutputDesc(ele.second);
  112. if (output_desc == nullptr) {
  113. GELOGE(FAILED, "[Get][OutputDesc]Can not find output tensor desc from node:%s, index %d",
  114. op_desc->GetName().c_str(), ele.second);
  115. return FAILED;
  116. }
  117. (void)ge::AttrUtils::GetInt(output_desc, ge::ATTR_NAME_PARENT_NODE_INDEX, parent_index);
  118. output_nodes_info.push_back({ele.first, ele.second, parent_index});
  119. }
  120. GELOGI("Output node set by user or leaf node, size:%zu.", output_nodes_info.size());
  121. for (auto &ele : out_nodes_tmp) {
  122. // add member, no need to remove duplicated because we need to keep all edges
  123. output_nodes_info.push_back(ele);
  124. }
  125. GELOGI("Get output node, size:%zu.", output_nodes_info.size());
  126. Status check_ret = CheckOutputNodeInfo(graph, output_nodes_info);
  127. if (check_ret != SUCCESS) {
  128. return check_ret;
  129. }
  130. return SUCCESS;
  131. }
  132. Status NetOutputPass::CheckOutputNodeInfo(const ComputeGraphPtr &graph, const std::vector<RetvalInfo> &outputs) {
  133. for (auto &item : outputs) {
  134. NodePtr node = item.output_node;
  135. if (node == nullptr) {
  136. REPORT_INNER_ERROR("E19999", "Param outputs has item which output_node is nullptr, check invalid");
  137. GELOGE(PARAM_INVALID, "[Check][Param] Node in outputs is nullptr.");
  138. return PARAM_INVALID;
  139. } else {
  140. if (graph->FindNode(node->GetName()) == nullptr) {
  141. REPORT_INNER_ERROR("E19999", "Find node:%s from graph:%s failed",
  142. node->GetName().c_str(), graph->GetName().c_str());
  143. GELOGE(INTERNAL_ERROR, "[Check][Param] Out node (%s) is not in graph:%s.",
  144. node->GetName().c_str(), graph->GetName().c_str());
  145. return INTERNAL_ERROR;
  146. }
  147. GE_CHECK_NOTNULL(node->GetOpDesc());
  148. int32_t out_size = node->GetOpDesc()->GetOutputsSize();
  149. int32_t index = item.node_output_index;
  150. if (index < 0 || index >= out_size) {
  151. REPORT_INNER_ERROR("E19999", "Index:%d in param outputs item, < 0 or > output size:%d of node:%s(%s)",
  152. index, out_size, node->GetName().c_str(), node->GetType().c_str());
  153. GELOGE(PARAM_INVALID, "[Check][Param] User declared out node (%s) output index:%d must be smaller "
  154. "than node ouput size:%d and cann't be negative!", node->GetName().c_str(), index, out_size);
  155. return PARAM_INVALID;
  156. }
  157. }
  158. }
  159. return SUCCESS;
  160. }
  161. Status NetOutputPass::RemoveUnusedNode(const ge::ComputeGraphPtr &graph) {
  162. std::vector<ge::NodePtr> node_to_delete;
  163. // Delete _Retval operator.
  164. for (auto &node : graph->GetDirectNode()) {
  165. GE_IF_BOOL_EXEC(node->GetOpDesc() == nullptr, GELOGW("Node OpDesc is nullptr"); continue);
  166. bool need_be_deleted = node->GetInDataNodes().size() != 0 && node->GetOutDataNodesSize() == 0 &&
  167. (node->GetOpDesc()->HasAttr(RETVAL_ATTR_NAME_INDEX));
  168. if (need_be_deleted) {
  169. node_to_delete.push_back(node);
  170. }
  171. }
  172. for (NodePtr &node : node_to_delete) {
  173. auto iter = targets_.find(node);
  174. if (iter != targets_.end()) {
  175. GELOGI("[Net output pass] node[%s] is in user set targets.so do not remove!", node->GetName().c_str());
  176. continue;
  177. }
  178. if (graph->RemoveNode(node) != GRAPH_SUCCESS) {
  179. REPORT_INNER_ERROR("E19999", "Remove node:%s(%s) from graph:%s failed",
  180. node->GetName().c_str(), node->GetType().c_str(), graph->GetName().c_str());
  181. GELOGE(INTERNAL_ERROR, "[Remove][Node] %s(%s) from graph:%s failed",
  182. node->GetName().c_str(), node->GetType().c_str(), graph->GetName().c_str());
  183. return INTERNAL_ERROR;
  184. }
  185. }
  186. return SUCCESS;
  187. }
  188. Status NetOutputPass::UpdateNetOutputDesc(const ge::NodePtr &net_output) {
  189. OpDescPtr net_output_desc = net_output->GetOpDesc();
  190. if (net_output_desc == nullptr) {
  191. REPORT_INNER_ERROR("E19999", "OpDesc in Param net_output is nullptr, check invalid");
  192. GELOGE(INTERNAL_ERROR, "[Get][OpDesc] failed, Opdesc of net output node is nullptr.");
  193. return INTERNAL_ERROR;
  194. }
  195. if (net_output_desc->GetInputsSize() == 0) {
  196. REPORT_INNER_ERROR("E19999", "Input desc num of node:%s(%s) is 0, check invalid",
  197. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str());
  198. GELOGE(INTERNAL_ERROR, "[Get][InputsSize] Net output node:%s(%s) input is empty.",
  199. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str());
  200. return INTERNAL_ERROR;
  201. }
  202. std::vector<bool> is_input_const;
  203. for (const auto &in_anchor : net_output->GetAllInDataAnchors()) {
  204. GE_CHECK_NOTNULL(in_anchor);
  205. auto index = static_cast<uint32_t>(in_anchor->GetIdx());
  206. if (index >= net_output_desc->GetAllInputsDesc().size()) {
  207. REPORT_INNER_ERROR("E19999", "Node:%s(%s) has in_anchor index:%u >= its input desc num:%zu, check invalid",
  208. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), index,
  209. net_output_desc->GetAllInputsDesc().size());
  210. GELOGE(INTERNAL_ERROR, "[Check][Param] Node:%s(%s) has in_anchor index:%u >= its input desc num:%zu",
  211. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), index,
  212. net_output_desc->GetAllInputsDesc().size());
  213. return INTERNAL_ERROR;
  214. }
  215. GE_CHECK_NOTNULL(in_anchor->GetPeerOutAnchor());
  216. is_input_const.push_back(PassUtils::IsConstant(in_anchor->GetPeerOutAnchor()->GetOwnerNode()));
  217. OpDescPtr src_op_desc = in_anchor->GetPeerOutAnchor()->GetOwnerNode()->GetOpDesc();
  218. GE_CHECK_NOTNULL(src_op_desc);
  219. uint32_t peer_index = static_cast<uint32_t>(in_anchor->GetPeerOutAnchor()->GetIdx());
  220. ge::GeTensorDesc output_in_desc = src_op_desc->GetOutputDesc(peer_index);
  221. if (net_output_desc->UpdateInputDesc(index, output_in_desc) != GRAPH_SUCCESS) {
  222. REPORT_CALL_ERROR("E19999", "Update input desc of op:%s(%s) failed, index:%u",
  223. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), index);
  224. GELOGE(INTERNAL_ERROR, "[Update][InputDesc] of op:%s(%s) failed, index:%u",
  225. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), index);
  226. return INTERNAL_ERROR;
  227. }
  228. GELOGD("Update desc, format:%s, data type:%s, index:%u.",
  229. TypeUtils::FormatToSerialString(output_in_desc.GetFormat()).c_str(),
  230. TypeUtils::DataTypeToSerialString(output_in_desc.GetDataType()).c_str(), index);
  231. }
  232. net_output_desc->SetIsInputConst(is_input_const);
  233. return SUCCESS;
  234. }
  235. Status NetOutputPass::AddCtrlEdgeForTargets(const ge::NodePtr &net_out_node) {
  236. if (net_out_node == nullptr) {
  237. REPORT_INNER_ERROR("E19999", "Param net_out_node is nullptr, check invalid");
  238. GELOGE(PARAM_INVALID, "[Check][Param] net out node is nullptr.");
  239. return PARAM_INVALID;
  240. }
  241. // Add ctrl edge for targets
  242. for (auto &node : targets_) {
  243. if (node == nullptr) {
  244. continue;
  245. }
  246. // no need to check null because have handled it in run SaveAndRemoveTargets function
  247. graphStatus status = GraphUtils::AddEdge(node->GetOutControlAnchor(), net_out_node->GetInControlAnchor());
  248. if (status != GRAPH_SUCCESS) {
  249. REPORT_CALL_ERROR("E19999", "Add control edge between op:%s(%s) and op:%s(%s) failed",
  250. node->GetName().c_str(), node->GetType().c_str(),
  251. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  252. GELOGE(INTERNAL_ERROR, "[Add][ControlEdge] between op:%s(%s) and op:%s(%s) failed",
  253. node->GetName().c_str(), node->GetType().c_str(),
  254. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  255. return INTERNAL_ERROR;
  256. }
  257. GELOGD("Add ctrl edge to netoutput node[%s] for target node [%s] success!", net_out_node->GetName().c_str(),
  258. node->GetName().c_str());
  259. }
  260. return SUCCESS;
  261. }
  262. void NetOutputPass::SaveAndRemoveTargets(const ge::ComputeGraphPtr &graph) {
  263. // save user targets node
  264. for (auto &node : graph->GetGraphTargetNodesInfo()) {
  265. if (node == nullptr) {
  266. GELOGW("User pointed targets contains null node.ignore it !");
  267. continue;
  268. }
  269. targets_.insert(node);
  270. }
  271. GELOGI("User pointed targets size is %zu !", targets_.size());
  272. }
  273. Status NetOutputPass::AddEdgesForNetOutput(const ge::ComputeGraphPtr &graph, const ge::NodePtr &net_out_node,
  274. const std::vector<RetvalInfo> &output_nodes_info) {
  275. int32_t net_input_index = 0;
  276. for (auto &item : output_nodes_info) {
  277. NodePtr src_node = item.output_node;
  278. GE_CHECK_NOTNULL(src_node);
  279. graphStatus status = GraphUtils::AddEdge(src_node->GetOutDataAnchor(item.node_output_index),
  280. net_out_node->GetInDataAnchor(net_input_index));
  281. if (status != GRAPH_SUCCESS) {
  282. REPORT_CALL_ERROR("E19999", "Add edge between op:%s(%s)(index:%u) and op:%s(%s)(index:%d) failed",
  283. src_node->GetName().c_str(), src_node->GetType().c_str(), item.node_output_index,
  284. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), net_input_index);
  285. GELOGE(INTERNAL_ERROR, "[Add][Edge] between op:%s(%s)(index:%u) and op:%s(%s)(index:%d) failed",
  286. src_node->GetName().c_str(), src_node->GetType().c_str(), item.node_output_index,
  287. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), net_input_index);
  288. return INTERNAL_ERROR;
  289. }
  290. GELOGD("AddEdge to output node, src name:%s, src index:%d, dst index:%d.", src_node->GetName().c_str(),
  291. item.node_output_index, net_input_index);
  292. if (item.parent_node_index >= 0) {
  293. GELOGI("Add parent node index %d for the netoutput input %d on graph %s", item.parent_node_index, net_input_index,
  294. graph->GetName().c_str());
  295. auto input_desc = net_out_node->GetOpDesc()->MutableInputDesc(net_input_index);
  296. if (input_desc == nullptr) {
  297. REPORT_CALL_ERROR("E19999", "Node:%s(%s) has no input desc index is %d, check invalid",
  298. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), net_input_index);
  299. GELOGE(INTERNAL_ERROR, "[Check][Param] Can not find intput tensor desc from NetOutput:%s(%s), index %d",
  300. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), net_input_index);
  301. return INTERNAL_ERROR;
  302. }
  303. if (!AttrUtils::SetInt(input_desc, ATTR_NAME_PARENT_NODE_INDEX, item.parent_node_index)) {
  304. REPORT_CALL_ERROR("E19999", "Set Attr:%s to input:%d tensor of op:%s(%s) failed",
  305. ATTR_NAME_PARENT_NODE_INDEX.c_str(), net_input_index,
  306. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  307. GELOGE(INTERNAL_ERROR, "[Set][Attr] %s to input:%d tensor of op:%s(%s) failed",
  308. ATTR_NAME_PARENT_NODE_INDEX.c_str(), net_input_index,
  309. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  310. return INTERNAL_ERROR;
  311. }
  312. }
  313. net_input_index++;
  314. }
  315. if (RemoveUnusedNode(graph) != SUCCESS) {
  316. GELOGE(INTERNAL_ERROR, "[Remove][UnusedNode] from graph:%s failed.", graph->GetName().c_str());
  317. return INTERNAL_ERROR;
  318. }
  319. if (AddCtrlEdgeForTargets(net_out_node) != SUCCESS) {
  320. GELOGE(INTERNAL_ERROR, "[Add][CtrlEdge] for targets failed, net_out_node:%s.", net_out_node->GetName().c_str());
  321. return INTERNAL_ERROR;
  322. }
  323. // Add true stream, netoutput is 0
  324. GE_IF_BOOL_EXEC(!ge::AttrUtils::SetInt(net_out_node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, 0),
  325. REPORT_CALL_ERROR("E19999", "Set Attr:%s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  326. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  327. GELOGE(INTERNAL_ERROR, "[Set][Attr] %s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  328. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  329. return INTERNAL_ERROR);
  330. return SUCCESS;
  331. }
  332. bool NetOutputPass::CheckNodeIsInOutputNodes(const ge::ComputeGraphPtr &graph, const ge::NodePtr &node) {
  333. for (auto &ele : graph->GetGraphOutNodesInfo()) {
  334. auto out_node = ele.first;
  335. if (node == out_node) {
  336. return true;
  337. }
  338. }
  339. return false;
  340. }
  341. Status NetOutputPass::UnLinkDataAnchorOfNetoutput(const ge::ComputeGraphPtr &graph, const ge::NodePtr &net_out_node) {
  342. if (net_out_node == nullptr) {
  343. REPORT_INNER_ERROR("E19999", "Param net_out_node is nullptr, check invalid");
  344. GELOGE(PARAM_INVALID, "[Check][Param] net out node is nullptr.");
  345. return PARAM_INVALID;
  346. }
  347. Status ret = SUCCESS;
  348. // unlink all anchor to data anchor of netoutput
  349. for (auto &in_data_anchor : net_out_node->GetAllInDataAnchors()) {
  350. if (in_data_anchor == nullptr) {
  351. continue;
  352. }
  353. auto peer_out_anchor = in_data_anchor->GetPeerOutAnchor();
  354. if (peer_out_anchor == nullptr) {
  355. GELOGI("PeerOutAnchor is null!");
  356. continue;
  357. }
  358. auto node = peer_out_anchor->GetOwnerNode();
  359. auto iter = targets_.find(node);
  360. if (iter != targets_.end()) {
  361. if (!CheckNodeIsInOutputNodes(graph, node)) {
  362. ret = in_data_anchor->Unlink(peer_out_anchor);
  363. if (ret != SUCCESS) {
  364. REPORT_CALL_ERROR("E19999", "Op:%s(%s) out index:%d unlink from op:%s(%s) in index:%d failed",
  365. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), in_data_anchor->GetIdx(),
  366. node->GetName().c_str(), node->GetType().c_str(), peer_out_anchor->GetIdx());
  367. GELOGE(INTERNAL_ERROR, "[Remove][Edge] Op:%s(%s) out index:%d unlink from op:%s(%s) in index:%d failed",
  368. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(), in_data_anchor->GetIdx(),
  369. node->GetName().c_str(), node->GetType().c_str(), peer_out_anchor->GetIdx());
  370. return ret;
  371. }
  372. } else {
  373. targets_.erase(iter);
  374. }
  375. }
  376. }
  377. return ret;
  378. }
  379. Status NetOutputPass::UnLinkControlAnchorOfNetoutput(const ge::ComputeGraphPtr &graph,
  380. const ge::NodePtr &net_out_node) {
  381. if (net_out_node == nullptr) {
  382. REPORT_INNER_ERROR("E19999", "Param net_out_node is nullptr, check invalid");
  383. GELOGE(PARAM_INVALID, "[Check][Param] net out node is nullptr.");
  384. return PARAM_INVALID;
  385. }
  386. Status ret = SUCCESS;
  387. auto in_control_anchor = net_out_node->GetInControlAnchor();
  388. if (in_control_anchor == nullptr) {
  389. REPORT_INNER_ERROR("E19999", "In control anchor of param net_out_node:%s(%s) is nullptr, check invalid",
  390. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  391. GELOGE(PARAM_INVALID, "[Check][Param] in control anchor of net_out_node:%s(%s) is nullptr.",
  392. net_out_node->GetName().c_str(), net_out_node->GetType().c_str());
  393. return PARAM_INVALID;
  394. }
  395. // unlink all data anchor to control anchor of netoutput
  396. for (auto &peer_out_data_anchor : in_control_anchor->GetPeerOutDataAnchors()) {
  397. if (peer_out_data_anchor == nullptr) {
  398. GELOGI("PeerOutControlAnchor is null!");
  399. } else {
  400. auto node = peer_out_data_anchor->GetOwnerNode();
  401. auto iter = targets_.find(node);
  402. if (iter != targets_.end()) {
  403. if (CheckNodeIsInOutputNodes(graph, node) == false) {
  404. ret = in_control_anchor->Unlink(peer_out_data_anchor);
  405. if (ret != SUCCESS) {
  406. REPORT_CALL_ERROR("E19999", "Op:%s(%s) unlink control edge from op:%s(%s) failed",
  407. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(),
  408. node->GetName().c_str(), node->GetType().c_str());
  409. GELOGE(INTERNAL_ERROR, "[Remove][Edge] Op:%s(%s) unlink control edge from op:%s(%s) failed",
  410. net_out_node->GetName().c_str(), net_out_node->GetType().c_str(),
  411. node->GetName().c_str(), node->GetType().c_str());
  412. return ret;
  413. }
  414. } else {
  415. targets_.erase(iter);
  416. }
  417. }
  418. }
  419. }
  420. /// check all control anchor to control anchor of netoutput and delete it from targets
  421. /// to avoid duplicated add control edge;
  422. for (auto &peer_out_control_anchor : in_control_anchor->GetPeerOutControlAnchors()) {
  423. if (peer_out_control_anchor == nullptr) {
  424. GELOGI("PeerOutControlAnchor is null");
  425. } else {
  426. auto node = peer_out_control_anchor->GetOwnerNode();
  427. auto iter = targets_.find(node);
  428. if (iter != targets_.end()) {
  429. targets_.erase(iter);
  430. }
  431. }
  432. }
  433. return ret;
  434. }
  435. Status NetOutputPass::UnLink(const ge::ComputeGraphPtr &graph, const ge::NodePtr &net_out_node) {
  436. GELOGI("[NetOutputPass] Enter Unlink process.");
  437. Status ret = UnLinkDataAnchorOfNetoutput(graph, net_out_node);
  438. if (ret != SUCCESS) {
  439. GELOGI("[NetOutputPass] UnLinkDataAnchorOfNetoutput process fail.");
  440. return ret;
  441. }
  442. ret = UnLinkControlAnchorOfNetoutput(graph, net_out_node);
  443. if (ret != SUCCESS) {
  444. GELOGI("[NetOutputPass] UnLinkControlAnchorOfNetoutput process fail.");
  445. return ret;
  446. }
  447. return ret;
  448. }
  449. Status NetOutputPass::ProcessWithNetoutput(const ge::ComputeGraphPtr &graph, const ge::NodePtr &output_node) {
  450. if (UpdateNetOutputDesc(output_node) != SUCCESS) {
  451. GELOGE(INTERNAL_ERROR, "[Update][NetOutputDesc] for node:%s failed.", output_node->GetName().c_str());
  452. return INTERNAL_ERROR;
  453. }
  454. if (UnLink(graph, output_node) != SUCCESS) {
  455. GELOGE(INTERNAL_ERROR, "[UnLink][Connection] between netoutput node:%s and user set target node",
  456. output_node->GetName().c_str());
  457. return INTERNAL_ERROR;
  458. }
  459. if (AddCtrlEdgeForTargets(output_node) != SUCCESS) {
  460. GELOGE(INTERNAL_ERROR, "[Add][CtrlEdge] for targets failed, output_node:%s.", output_node->GetName().c_str());
  461. return INTERNAL_ERROR;
  462. }
  463. return SUCCESS;
  464. }
  465. Status NetOutputPass::AddCtrlEdgesBetweenLeafAndNetOutput(const ge::ComputeGraphPtr &graph,
  466. const ge::NodePtr &net_out_node) {
  467. GE_CHECK_NOTNULL(net_out_node);
  468. if (!GetLocalOmgContext().user_out_nodes.empty() || is_user_define_ouput_nodes) {
  469. GELOGI("No need to add ctrl edge to netoutput because user out nodes have been set.");
  470. return SUCCESS;
  471. }
  472. bool graph_has_only_one_node_except_netoutput = (graph->GetDirectNodesSize() == kNodesCount);
  473. for (const auto &node : graph->GetDirectNode()) {
  474. if (node == nullptr || node->GetOpDesc() == nullptr || node->GetOpDesc()->GetType() == NETOUTPUT) {
  475. continue;
  476. }
  477. if ((node->GetInControlNodes().size() != 0 || node->GetInDataNodes().size() != 0 ||
  478. graph_has_only_one_node_except_netoutput) &&
  479. node->GetOutDataNodesSize() == 0 && node->GetOutControlNodes().size() == 0) {
  480. GE_CHK_GRAPH_STATUS_RET(GraphUtils::AddEdge(node->GetOutControlAnchor(), net_out_node->GetInControlAnchor()),
  481. "[Add][ControlEdge] between %s and %s failed",
  482. node->GetName().c_str(), net_out_node->GetName().c_str());
  483. GELOGD("Add ctrl edge success. src name :%s, dst name :%s", node->GetName().c_str(),
  484. net_out_node->GetName().c_str());
  485. }
  486. }
  487. return SUCCESS;
  488. }
  489. Status NetOutputPass::CreateNetOutputNode(OpDescPtr &net_output_desc, const ge::ComputeGraphPtr &graph) {
  490. // Only flush subgraph name
  491. string node_name =
  492. (graph->GetParentGraph() != nullptr) ? (graph->GetName() + "_" + NODE_NAME_NET_OUTPUT) : NODE_NAME_NET_OUTPUT;
  493. net_output_desc = MakeShared<OpDesc>(node_name, NETOUTPUT);
  494. if (net_output_desc == nullptr) {
  495. REPORT_CALL_ERROR("E19999", "New OpDesc failed");
  496. GELOGE(MEMALLOC_FAILED, "[New][OpDesc] failed.");
  497. return MEMALLOC_FAILED;
  498. }
  499. (void)AttrUtils::SetListStr(net_output_desc, ATTR_NAME_DATA_DUMP_ORIGIN_OP_NAMES,
  500. std::move(std::vector<std::string>()));
  501. return SUCCESS;
  502. }
  503. Status NetOutputPass::Run(ge::ComputeGraphPtr graph) {
  504. if (graph == nullptr) {
  505. REPORT_INNER_ERROR("E19999", "Param graph is nullptr, check invalid");
  506. GELOGE(GE_GRAPH_PARAM_NULLPTR, "[Check][Param] Compute graph is nullptr.");
  507. return GE_GRAPH_PARAM_NULLPTR;
  508. }
  509. GELOGI("[NETOUTPUT PASS] Run.graph is [%s]", graph->GetName().c_str());
  510. NodePtr output_node = graph->FindFirstNodeMatchType(NETOUTPUT);
  511. // save user targets node
  512. SaveAndRemoveTargets(graph);
  513. // If graph already has a netoutput node, doesn't need to create it again.
  514. if (output_node != nullptr) {
  515. (void)AttrUtils::SetListStr(output_node->GetOpDesc(), ATTR_NAME_DATA_DUMP_ORIGIN_OP_NAMES,
  516. std::move(std::vector<std::string>()));
  517. if (ProcessWithNetoutput(graph, output_node) != SUCCESS) {
  518. GELOGE(INTERNAL_ERROR, "[Process][WithNetoutput] failed, output_node:%s, graph:%s.",
  519. output_node->GetName().c_str(), graph->GetName().c_str());
  520. return INTERNAL_ERROR;
  521. }
  522. } else {
  523. if (AddNetOutputNodeToGraph(graph, output_node) != SUCCESS) {
  524. GELOGE(INTERNAL_ERROR, "[Add][NetOutputNode] to graph:%s failed.", graph->GetName().c_str());
  525. return INTERNAL_ERROR;
  526. }
  527. }
  528. // Add userdef attrs to netoutput node
  529. return SetUserDefDTypeAndFormatFromAtcParams(output_node);
  530. }
  531. Status NetOutputPass::AddNetOutputNodeToGraph(const ge::ComputeGraphPtr &graph, NodePtr &output_node) {
  532. OpDescPtr net_output_desc = nullptr;
  533. if (CreateNetOutputNode(net_output_desc, graph) != SUCCESS) {
  534. GELOGE(INTERNAL_ERROR, "[Create][NetOutputNode] in graph:%s failed.", graph->GetName().c_str());
  535. return INTERNAL_ERROR;
  536. }
  537. std::vector<RetvalInfo> output_nodes_info;
  538. if (GetOutputNode(graph, output_nodes_info) != SUCCESS) {
  539. GELOGE(INTERNAL_ERROR, "[Get][OutputNode] in graph:%s failed.", graph->GetName().c_str());
  540. return INTERNAL_ERROR;
  541. }
  542. GELOGI("[NETOUTPUT PASS] OutNodesInfo size:%zu, Targets Size:%zu, is_include_special_node_:%d",
  543. graph->GetGraphOutNodesInfo().size(), graph->GetGraphTargetNodesInfo().size(), is_include_special_node_);
  544. // If user does not set out nodes and targets and no retval node, also add netoutput node
  545. if ((graph->GetGraphOutNodesInfo().empty()) && (graph->GetGraphTargetNodesInfo().empty()) &&
  546. !is_include_special_node_) {
  547. GELOGI("[NETOUTPUT PASS] Both output, target and special nodes are empty! add net output node");
  548. output_node = graph->AddNode(net_output_desc);
  549. GE_CHK_STATUS_RET(AddCtrlEdgesBetweenLeafAndNetOutput(graph, output_node),
  550. "[Add][CtrlEdges] between leaf and netoutput in graph:%s failed", graph->GetName().c_str());
  551. if (!ge::AttrUtils::SetInt(output_node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, 0)) {
  552. REPORT_CALL_ERROR("E19999", "Set Attr:%s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  553. output_node->GetName().c_str(), output_node->GetType().c_str());
  554. GELOGE(INTERNAL_ERROR, "[Set][Attr] %s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  555. output_node->GetName().c_str(), output_node->GetType().c_str());
  556. return INTERNAL_ERROR;
  557. }
  558. GELOGI("[NETOUTPUT PASS] Add net output node succeed");
  559. return SUCCESS;
  560. }
  561. GELOGI("[NETOUTPUT PASS] Output node size:%zu.", output_nodes_info.size());
  562. if (output_nodes_info.empty()) {
  563. // because retval node is contained by output_nodes_info, here means targets is non-empty
  564. output_node = graph->AddNode(net_output_desc);
  565. if (output_node == nullptr) {
  566. REPORT_CALL_ERROR("E19999", "Add node:%s(%s) to graph:%s failed",
  567. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(),
  568. graph->GetName().c_str());
  569. GELOGE(INTERNAL_ERROR, "[Add][Node] %s(%s) to graph:%s failed",
  570. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), graph->GetName().c_str());
  571. return INTERNAL_ERROR;
  572. }
  573. GE_CHK_STATUS_RET(AddCtrlEdgeForTargets(output_node),
  574. "[Add][CtrlEdge] for targets failed, output node:%s", output_node->GetName().c_str());
  575. // Add true stream, netoutput is 0
  576. GE_IF_BOOL_EXEC(!ge::AttrUtils::SetInt(output_node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, 0),
  577. REPORT_CALL_ERROR("E19999", "Set Attr:%s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  578. output_node->GetName().c_str(), output_node->GetType().c_str());
  579. GELOGE(INTERNAL_ERROR, "[Set][Attr] %s to op:%s(%s) failed", ATTR_NAME_TRUE_BRANCH_STREAM.c_str(),
  580. output_node->GetName().c_str(), output_node->GetType().c_str());
  581. return INTERNAL_ERROR);
  582. return SUCCESS;
  583. }
  584. AddInOutForNetOutputOp(graph, net_output_desc, output_nodes_info);
  585. output_node = graph->AddNode(net_output_desc);
  586. if (output_node == nullptr) {
  587. REPORT_CALL_ERROR("E19999", "Add node:%s(%s) to graph:%s failed",
  588. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(),
  589. graph->GetName().c_str());
  590. GELOGE(INTERNAL_ERROR, "[Add][Node] %s(%s) to graph:%s failed",
  591. net_output_desc->GetName().c_str(), net_output_desc->GetType().c_str(), graph->GetName().c_str());
  592. return INTERNAL_ERROR;
  593. }
  594. if (AddEdgesForNetOutput(graph, output_node, output_nodes_info) != SUCCESS) {
  595. GELOGE(INTERNAL_ERROR, "[Add][Edges] for net output node in graph:%s failed.", graph->GetName().c_str());
  596. return INTERNAL_ERROR;
  597. }
  598. if (AddCtrlEdgesBetweenLeafAndNetOutput(graph, output_node) != SUCCESS) {
  599. GELOGE(INTERNAL_ERROR, "[Add][CtrlEdges] between leaf and netoutput in graph:%s failed.", graph->GetName().c_str());
  600. return INTERNAL_ERROR;
  601. }
  602. GELOGI("Add NetOutput node success.");
  603. return SUCCESS;
  604. }
  605. void NetOutputPass::AddInOutForNetOutputOp(const ComputeGraphPtr &graph, OpDescPtr &net_output_desc,
  606. vector<RetvalInfo> &output_nodes_info) {
  607. std::vector<bool> is_input_const;
  608. for (auto iter = output_nodes_info.begin(); iter != output_nodes_info.end();) {
  609. NodePtr src_node = iter->output_node;
  610. if (src_node == nullptr) {
  611. continue;
  612. }
  613. int32_t src_index = iter->node_output_index;
  614. // if src_node is in targets_, no need to Add in and out for netoutput
  615. auto it = targets_.find(src_node);
  616. if (it != targets_.end()) {
  617. iter = output_nodes_info.erase(iter);
  618. GELOGD("node [%s] is in processed targets, do not add inout for netoutput!", src_node->GetName().c_str());
  619. continue;
  620. }
  621. /// Get the output attribute of src_node,
  622. /// and set to the input/output of net_out_node.
  623. if (src_node == nullptr || src_node->GetOpDesc() == nullptr || net_output_desc == nullptr) {
  624. REPORT_INNER_ERROR("E19999", "Param output_nodes_info has RetvalInfo item, which src_node is invalid; "
  625. "or Param net_output_desc is nullptr, check invalid");
  626. GELOGE(INTERNAL_ERROR, "[Check][Param] src node or net output desc is nullptr.");
  627. return;
  628. }
  629. ge::GeTensorDesc out_desc = src_node->GetOpDesc()->GetOutputDesc(src_index);
  630. out_desc.SetFormat(FORMAT_ND);
  631. out_desc.SetOriginFormat(FORMAT_ND);
  632. GE_IF_BOOL_EXEC(net_output_desc->AddInputDesc(out_desc) != SUCCESS, GELOGW("add input desc failed"); return );
  633. is_input_const.push_back(PassUtils::IsConstant(src_node));
  634. ++iter;
  635. }
  636. net_output_desc->SetIsInputConst(is_input_const);
  637. }
  638. bool NeedUpdateOutputByOutputTypeParm(std::string &output_type, OpDescPtr &op_desc, uint32_t &src_index,
  639. ge::DataType &dt) {
  640. if (output_type_str_to_datatype.find(output_type) != output_type_str_to_datatype.end()) {
  641. dt = output_type_str_to_datatype[output_type];
  642. return true;
  643. }
  644. vector<string> output_dt_str;
  645. if (ge::AttrUtils::GetListStr(op_desc, "_user_defined_output_data_type", output_dt_str)) {
  646. for (const auto &dt_str : output_dt_str) {
  647. vector<string> dt_str_split = StringUtils::Split(dt_str, ':');
  648. if (dt_str_split.size() == kUserDefinedElementCount) {
  649. if (dt_str_split[0] == to_string(src_index)) {
  650. dt = TypeUtils::SerialStringToDataType(dt_str_split[1]);
  651. return true;
  652. }
  653. } else {
  654. GELOGW("The size of [%s] is not 2 after split.", dt_str.c_str());
  655. continue;
  656. }
  657. }
  658. }
  659. return false;
  660. }
  661. bool NeedUpdateOutputFp16Nc1hwc0(OpDescPtr &op_desc, uint32_t &src_index) {
  662. vector<string> output_dt_str;
  663. if (ge::AttrUtils::GetListStr(op_desc, "_user_defined_output_fp16_5hd", output_dt_str)) {
  664. for (const auto &dt_str : output_dt_str) {
  665. vector<string> dt_str_split = StringUtils::Split(dt_str, ':');
  666. if (dt_str_split.size() == kUserDefinedElementCount) {
  667. if (dt_str_split[0] == to_string(src_index)) {
  668. return true;
  669. }
  670. } else {
  671. GELOGW("The size of [%s] is not 2 after split.", dt_str.c_str());
  672. continue;
  673. }
  674. }
  675. }
  676. return false;
  677. }
  678. Status NetOutputPass::SetUserDefDTypeAndFormatFromAtcParams(const NodePtr &output_node) {
  679. if (output_node == nullptr) {
  680. GELOGI("[NETOUTPUT PASS] The graph no need netoutput node!");
  681. return SUCCESS;
  682. }
  683. auto output_type = GetLocalOmgContext().output_type;
  684. auto op_desc = output_node->GetOpDesc();
  685. GE_CHECK_NOTNULL(op_desc);
  686. std::vector<std::string> userdef_dtypes;
  687. std::vector<std::string> userdef_formats;
  688. ge::DataType output_data_type = ge::DT_FLOAT;
  689. for (const auto &in_anchor : output_node->GetAllInDataAnchors()) {
  690. auto index = static_cast<uint32_t>(in_anchor->GetIdx());
  691. auto peer_out = in_anchor->GetPeerOutAnchor();
  692. if (peer_out == nullptr) {
  693. // If user set target, peer_out anchor will be unlinked.
  694. continue;
  695. }
  696. auto src_index = static_cast<uint32_t>(peer_out->GetIdx());
  697. auto src_node = peer_out->GetOwnerNode();
  698. GE_CHECK_NOTNULL(src_node);
  699. OpDescPtr src_op_desc = src_node->GetOpDesc();
  700. GE_CHECK_NOTNULL(src_op_desc);
  701. // Update datatype
  702. if (NeedUpdateOutputByOutputTypeParm(output_type, src_op_desc, src_index, output_data_type)) {
  703. GELOGD("Add user-define datatype:%s to netoutput node.",
  704. TypeUtils::DataTypeToSerialString(output_data_type).c_str());
  705. userdef_dtypes.push_back(
  706. std::to_string(index).append(":").append(TypeUtils::DataTypeToSerialString(output_data_type)));
  707. continue;
  708. }
  709. // Output_node is not set,check if is_output_adjust_hw_layout is set
  710. bool set_fp16_nc1hwc0 = NeedUpdateOutputFp16Nc1hwc0(src_op_desc, src_index);
  711. if (set_fp16_nc1hwc0) {
  712. // Set DT_FLOAT16 & FORMAT_NC1HWC0
  713. userdef_dtypes.push_back(std::to_string(index).append(":").append(TypeUtils::DataTypeToSerialString(DT_FLOAT16)));
  714. userdef_formats.push_back(
  715. std::to_string(index).append(":").append(TypeUtils::FormatToSerialString(FORMAT_NC1HWC0)));
  716. }
  717. }
  718. if (!userdef_dtypes.empty() && !ge::AttrUtils::SetListStr(op_desc, ATTR_ATC_USER_DEFINE_DATATYPE, userdef_dtypes)) {
  719. REPORT_INNER_ERROR("E19999", "User define datatype is empty or Set Attr:%s to op:%s(%s) failed",
  720. ATTR_ATC_USER_DEFINE_DATATYPE.c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
  721. GELOGE(INTERNAL_ERROR, "[Check][Param] User define datatype is empty or Set Attr:%s to op:%s(%s) failed",
  722. ATTR_ATC_USER_DEFINE_DATATYPE.c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
  723. return INTERNAL_ERROR;
  724. }
  725. if (!userdef_formats.empty() && !ge::AttrUtils::SetListStr(op_desc, ATTR_ATC_USER_DEFINE_FORMAT, userdef_formats)) {
  726. REPORT_INNER_ERROR("E19999", "User define format is empty or Set Attr:%s to op:%s(%s) failed",
  727. ATTR_ATC_USER_DEFINE_FORMAT.c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
  728. GELOGE(INTERNAL_ERROR, "[Check][Param] User define format is empty or Set Attr:%s to op:%s(%s) failed",
  729. ATTR_ATC_USER_DEFINE_FORMAT.c_str(), op_desc->GetName().c_str(), op_desc->GetType().c_str());
  730. return INTERNAL_ERROR;
  731. }
  732. return SUCCESS;
  733. }
  734. } // namespace ge

图引擎模块(GE)是MindSpore的一个子模块,其代码由C++实现,位于前端模块ME和底层硬件之间,起到承接作用。图引擎模块以ME下发的图作为输入,然后进行一系列的深度图优化操作,最后输出一张可以在底层硬件上高效运行的图。GE针对昇腾AI处理器的硬件结构特点,做了特定的优化工作,以此来充分发挥出昇腾AI处理器的强大算力。在进行模型训练/推理时,GE会被自动调用而用户并不感知。GE主要由GE API和GE Core两部分组成,详细的架构图如下所示