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.

flow_ctrl_pass.cc 23 kB

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
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
4 years ago
5 years ago
5 years ago
5 years ago
4 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
4 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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/flow_ctrl_pass.h"
  17. #include <memory>
  18. #include <string>
  19. #include <vector>
  20. #include "framework/common/debug/ge_log.h"
  21. #include "graph/debug/ge_attr_define.h"
  22. #include "graph/common/omg_util.h"
  23. #include "common/ge/ge_util.h"
  24. #include "graph/manager/graph_var_manager.h"
  25. #include "graph/passes/pass_utils.h"
  26. namespace ge {
  27. // when namespace change to ge, please delete the using code.
  28. Status FlowCtrlPass::Run(ComputeGraphPtr compute_graph) {
  29. GE_CHECK_NOTNULL(compute_graph);
  30. if (!PassUtils::IsNeedTrainIteFlowCtrl(compute_graph)) {
  31. GELOGI("No need FlowCtrl for graph %u", compute_graph->GetGraphID());
  32. return NOT_CHANGED;
  33. }
  34. GELOGI("FlowCtrl pass begin");
  35. bool graph_change = false;
  36. // 1. Add FP/BP flow ctrl (big cycle)
  37. for (auto &node : compute_graph->GetDirectNode()) {
  38. if (node == nullptr) {
  39. continue;
  40. }
  41. GE_IF_BOOL_EXEC(node->GetOpDesc() == nullptr, continue);
  42. uint32_t true_stream_id = 0;
  43. bool is_found = AttrUtils::GetInt(node->GetOpDesc(), ATTR_NAME_TRUE_BRANCH_STREAM, true_stream_id);
  44. // FP/BP cycle flag is true_stream_id == 0
  45. if (is_found && (true_stream_id == TRUE_STREAM_ID)) {
  46. // Add big cycle
  47. Status ret = AddFpBpIteratorCtrl(compute_graph, node);
  48. if (ret != SUCCESS) {
  49. GELOGE(ret, "AddFpBpIteratorCtrl fail, node: %s.", node->GetName().c_str());
  50. return ret;
  51. }
  52. graph_change = true;
  53. // only one big cycle, so break.
  54. break;
  55. }
  56. }
  57. // 2. Add special node flow ctrl. eg, IteratorGetNext. (small cycle)
  58. // NOTE: Small cycle share the variables with big cycle.
  59. for (auto &node : compute_graph->GetDirectNode()) {
  60. if (node == nullptr) {
  61. continue;
  62. }
  63. GE_IF_BOOL_EXEC(node->GetOpDesc() == nullptr, continue);
  64. bool need_cycle_flag = false;
  65. bool is_found = AttrUtils::GetBool(node->GetOpDesc(), ATTR_NAME_STREAM_CYCLE_EVENT_FLAG, need_cycle_flag);
  66. // small cycle flag is need_stream_cycle_event == true
  67. if (is_found && need_cycle_flag) {
  68. Status ret = AddSpecialNodeIteratorCtrl(compute_graph, node);
  69. if (ret != SUCCESS) {
  70. GELOGE(ret, "AddSpecialNodeIteratorCtrl fail, node: %s.", node->GetName().c_str());
  71. return ret;
  72. }
  73. graph_change = true;
  74. }
  75. }
  76. GELOGI("FlowCtrl pass end, graph is %s.", graph_change ? "changed" : "not changed");
  77. return graph_change ? SUCCESS : NOT_CHANGED;
  78. }
  79. bool FlowCtrlPass::CheckMultiDataSet(ComputeGraphPtr &compute_graph) {
  80. int data_set_num = 0;
  81. for (auto &node : compute_graph->GetDirectNode()) {
  82. if (node == nullptr) {
  83. continue;
  84. }
  85. string type;
  86. bool is_found = AttrUtils::GetStr(node->GetOpDesc(), ATTR_NAME_FRAMEWORK_ORIGINAL_TYPE, type);
  87. if (is_found && type == "IteratorV2") {
  88. data_set_num++;
  89. }
  90. }
  91. GELOGI("The ComputeGraph contain %d dataSet.", data_set_num);
  92. return (data_set_num > 1) ? true : false;
  93. }
  94. NodePtr FlowCtrlPass::InsertOp(ComputeGraphPtr &compute_graph, const string &node_type, const string &node_name,
  95. const std::vector<GeTensorDesc> &input_list,
  96. const std::vector<GeTensorDesc> &output_list) {
  97. OpDescPtr op_desc = MakeShared<OpDesc>(node_name, node_type);
  98. if (op_desc == nullptr) {
  99. GELOGE(FAILED, "Make OpDesc failed, name:%s, type:%s.", node_name.c_str(), node_type.c_str());
  100. return nullptr;
  101. }
  102. for (auto &input_desc : input_list) {
  103. graphStatus graph_status = op_desc->AddInputDesc(input_desc);
  104. if (graph_status != GRAPH_SUCCESS) {
  105. GELOGE(FAILED, "Add node:%s intput desc failed, error=%u.", node_name.c_str(), graph_status);
  106. return nullptr;
  107. }
  108. }
  109. for (auto &output_desc : output_list) {
  110. graphStatus graph_status = op_desc->AddOutputDesc(output_desc);
  111. if (graph_status != GRAPH_SUCCESS) {
  112. GELOGE(FAILED, "Add node:%s output desc failed, error=%u.", node_name.c_str(), graph_status);
  113. return nullptr;
  114. }
  115. }
  116. GE_IF_BOOL_EXEC(compute_graph == nullptr, DOMI_LOGE("compute_graph is nullptr"); return nullptr);
  117. NodePtr node = compute_graph->AddNode(op_desc);
  118. if (node == nullptr) {
  119. GELOGE(FAILED, "add node failed, name:%s, type:%s.", node_name.c_str(), node_type.c_str());
  120. return nullptr;
  121. }
  122. GELOGI("Insert op success, name:%s, type:%s.", node_name.c_str(), node_type.c_str());
  123. return node;
  124. }
  125. NodePtr FlowCtrlPass::InsertStreamSwitchOp(ComputeGraphPtr &compute_graph, const string &switch_name,
  126. const NodePtr &loop_cond, const NodePtr &iter_per_loop) {
  127. GE_IF_BOOL_EXEC(loop_cond == nullptr || loop_cond->GetOpDesc() == nullptr,
  128. GELOGE(FAILED, "loop_cond is null"); return nullptr);
  129. GE_IF_BOOL_EXEC(iter_per_loop == nullptr || iter_per_loop->GetOpDesc() == nullptr,
  130. GELOGE(FAILED, "iter_per_loop is nullptr"); return nullptr);
  131. std::vector<GeTensorDesc> input_desc_list = {loop_cond->GetOpDesc()->GetOutputDesc(0),
  132. iter_per_loop->GetOpDesc()->GetOutputDesc(0)};
  133. std::vector<GeTensorDesc> output_desc_list;
  134. NodePtr stream_switch = InsertOp(compute_graph, STREAMSWITCH, switch_name, input_desc_list, output_desc_list);
  135. if (stream_switch == nullptr) {
  136. GELOGE(FAILED, "InsertStreamSwitchOp failed, name:%s.", switch_name.c_str());
  137. return nullptr;
  138. }
  139. // set input 0
  140. graphStatus add_ret = GraphUtils::AddEdge(loop_cond->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(0));
  141. if (add_ret != GRAPH_SUCCESS) {
  142. GELOGE(FAILED, "Add loop_cond_node to switch_node:%s edge failed, ret = %u.", switch_name.c_str(), add_ret);
  143. return nullptr;
  144. }
  145. // set input 1
  146. add_ret = GraphUtils::AddEdge(iter_per_loop->GetOutDataAnchor(0), stream_switch->GetInDataAnchor(1));
  147. if (add_ret != GRAPH_SUCCESS) {
  148. GELOGE(FAILED, "Add iter_per_loop_node to switch_node:%s edge failed, ret = %u.", switch_name.c_str(), add_ret);
  149. return nullptr;
  150. }
  151. // stream switch op need switch cond by attr.
  152. GE_IF_BOOL_EXEC(!AttrUtils::SetInt(stream_switch->GetOpDesc(), ATTR_NAME_STREAM_SWITCH_COND,
  153. static_cast<int64_t>(RT_LESS)),
  154. DOMI_LOGE("set ATTR_NAME_STREAM_SWITCH_COND failed"); return nullptr);
  155. return stream_switch;
  156. }
  157. NodePtr FlowCtrlPass::AddVariableNode(ComputeGraphPtr &compute_graph, const string &name) {
  158. GE_IF_BOOL_EXEC(compute_graph == nullptr, DOMI_LOGE("compute_graph is nullptr"); return nullptr);
  159. NodePtr exist_node = compute_graph->FindNode(name);
  160. if (exist_node != nullptr) {
  161. GELOGD("Node %s already exist, no need add.", name.c_str());
  162. return exist_node;
  163. }
  164. // fetch and set tensor desc
  165. GeTensorDesc tensor_desc;
  166. if (ge::VarManager::Instance(compute_graph->GetSessionID()) == nullptr) {
  167. return nullptr;
  168. }
  169. Status ret = ge::VarManager::Instance(compute_graph->GetSessionID())->GetCurVarDesc(name, tensor_desc);
  170. if (ret != SUCCESS) {
  171. GELOGE(FAILED, "Get var desc fail, name:%s", name.c_str());
  172. return nullptr;
  173. }
  174. std::vector<GeTensorDesc> input_desc_list;
  175. std::vector<GeTensorDesc> output_desc_list = {tensor_desc};
  176. // insert node
  177. return InsertOp(compute_graph, VARIABLE, name, input_desc_list, output_desc_list);
  178. }
  179. Status FlowCtrlPass::AddGlobalStepVariableNode(ComputeGraphPtr &compute_graph) {
  180. NodePtr output_node = compute_graph->FindFirstNodeMatchType(NETOUTPUT);
  181. if (output_node == nullptr) {
  182. GELOGD("Node type %s can't be found in graph %u", NETOUTPUT, compute_graph->GetGraphID());
  183. return SUCCESS;
  184. }
  185. // Global step just add to main graph's netoutput node.And the main graph must be known shape
  186. if ((compute_graph->GetParentGraph() != nullptr) ||
  187. ((compute_graph->GetParentGraph() == nullptr) && (GraphUtils::IsUnknownShapeGraph(compute_graph)))) {
  188. GELOGD("Subgraph %s no need global step variable.", compute_graph->GetName().c_str());
  189. return SUCCESS;
  190. }
  191. NodePtr exist_node = compute_graph->FindNode(NODE_NAME_GLOBAL_STEP);
  192. if (exist_node != nullptr) {
  193. GELOGD("Node %s already exist, no need add.", NODE_NAME_GLOBAL_STEP.c_str());
  194. return SUCCESS;
  195. }
  196. // set global step tensor desc
  197. GeTensorDesc tensor_desc(GeShape({1}), FORMAT_ND, DT_UINT64);
  198. std::vector<GeTensorDesc> input_desc_list = {};
  199. std::vector<GeTensorDesc> output_desc_list = {tensor_desc};
  200. NodePtr global_step = InsertOp(compute_graph, VARIABLE, NODE_NAME_GLOBAL_STEP,
  201. input_desc_list, output_desc_list);
  202. if (global_step == nullptr) {
  203. GELOGE(FAILED, "Add global_step node failed, global_step is null.");
  204. return FAILED;
  205. }
  206. // add ctrl edges
  207. graphStatus add_ret = GraphUtils::AddEdge(global_step->GetOutControlAnchor(), output_node->GetInControlAnchor());
  208. if (add_ret != GRAPH_SUCCESS) {
  209. GELOGE(FAILED, "Add global_step to netoutput edge failed, add_ret=%u.", add_ret);
  210. return FAILED;
  211. }
  212. GELOGD("Add global_step to netoutput edge in graph %u success", compute_graph->GetGraphID());
  213. return SUCCESS;
  214. }
  215. NodePtr FlowCtrlPass::InsertAssignOp(ge::ComputeGraphPtr &compute_graph, const string &node_type,
  216. const string &node_name, const NodePtr &ref_node, const NodePtr &value_node) {
  217. GE_IF_BOOL_EXEC(ref_node == nullptr || value_node == nullptr ||
  218. ref_node->GetOpDesc() == nullptr || value_node->GetOpDesc() == nullptr,
  219. GELOGE(FAILED, "ref node or value node is null");
  220. return nullptr);
  221. GeTensorDesc ref_tensor_desc = ref_node->GetOpDesc()->GetOutputDesc(0);
  222. GeTensorDesc val_tensor_desc = value_node->GetOpDesc()->GetOutputDesc(0);
  223. std::vector<GeTensorDesc> input_desc_list = {ref_tensor_desc, val_tensor_desc};
  224. std::vector<GeTensorDesc> output_desc_list = {ref_tensor_desc};
  225. NodePtr assign_node = InsertOp(compute_graph, node_type, node_name, input_desc_list, output_desc_list);
  226. if (assign_node == nullptr) {
  227. GELOGE(FAILED, "Insert node %s(%s) failed.", node_name.c_str(), node_type.c_str());
  228. return nullptr;
  229. }
  230. // assign node input 0 = ref_node
  231. graphStatus add_ret = GraphUtils::AddEdge(ref_node->GetOutDataAnchor(0), assign_node->GetInDataAnchor(0));
  232. if (add_ret != GRAPH_SUCCESS) {
  233. GELOGE(FAILED, "Add ref_node to %s edge failed, add_ret=%u.", node_name.c_str(), add_ret);
  234. return nullptr;
  235. }
  236. // assign input 1 = value_node
  237. add_ret = GraphUtils::AddEdge(value_node->GetOutDataAnchor(0), assign_node->GetInDataAnchor(1));
  238. if (add_ret != GRAPH_SUCCESS) {
  239. GELOGE(FAILED, "Add value_node to %s edge failed, add_ret=%u.", node_name.c_str(), add_ret);
  240. return nullptr;
  241. }
  242. (void)ge::AttrUtils::SetBool(assign_node->GetOpDesc(), ATTR_NEED_COMPILE, true);
  243. return assign_node;
  244. }
  245. Status FlowCtrlPass::CreateIterCtrlTrueBranch(ComputeGraphPtr &compute_graph, const NodePtr &loop_cond_node,
  246. const NodePtr &loop_inc_node, NodePtr &switch_node) {
  247. /*
  248. * loopCond
  249. * |
  250. * v
  251. * switch --> AssignAdd --> active
  252. * ^
  253. * |
  254. * loopIncrement
  255. */
  256. // Insert AssignAdd node
  257. NodePtr assign_add_node =
  258. InsertAssignOp(compute_graph, ASSIGNADD, NODE_NAME_FLOWCTRL_LOOP_ASSIGNADD, loop_cond_node, loop_inc_node);
  259. if (assign_add_node == nullptr || switch_node == nullptr) {
  260. GELOGE(PARAM_INVALID, "assign add node or switch node is null");
  261. return FAILED;
  262. }
  263. string active_name = switch_node->GetName() + "_StreamActive";
  264. // add attr for stream assign model to break branch.
  265. GE_CHK_STATUS_RET(SetStreamLabel(assign_add_node, active_name), "set stream label failed");
  266. // used for stream assign to find true branch
  267. GE_CHK_STATUS_RET(SetActiveLabelList(switch_node, { active_name }), "set active label list failed");
  268. // 2. Insert active node
  269. NodePtr active_node = InsertOp(compute_graph, STREAMACTIVE, active_name, {}, {});
  270. if (active_node == nullptr) {
  271. GELOGE(FAILED, "Insert stream active node:%s for IterCtrlTrueStream failed.", active_name.c_str());
  272. return FAILED;
  273. }
  274. GE_CHK_STATUS_RET(SetStreamLabel(active_node, active_name), "set stream label failed");
  275. GE_IF_BOOL_EXEC(!AttrUtils::SetBool(active_node->GetOpDesc(), ATTR_NAME_IS_LOOP_ACTIVE, true),
  276. DOMI_LOGE("set ATTR_NAME_IS_LOOP_ACTIVE failed"); return FAILED);
  277. // add ctrl edges
  278. graphStatus add_ret = GraphUtils::AddEdge(switch_node->GetOutControlAnchor(), assign_add_node->GetInControlAnchor());
  279. if (add_ret != GRAPH_SUCCESS) {
  280. GELOGE(FAILED, "Add switch_node to assign_add_node ctrl edge failed, add_ret=%u.", add_ret);
  281. return FAILED;
  282. }
  283. add_ret = GraphUtils::AddEdge(assign_add_node->GetOutControlAnchor(), active_node->GetInControlAnchor());
  284. if (add_ret != GRAPH_SUCCESS) {
  285. GELOGE(FAILED, "Add assign_add_node to active_node ctrl edge failed, add_ret=%u.", add_ret);
  286. return FAILED;
  287. }
  288. GELOGI("CreateIterCtrlTrueBranch success. StreamActive op:%s.", active_node->GetName().c_str());
  289. return SUCCESS;
  290. }
  291. Status FlowCtrlPass::CreateIterCtrlFalseBranch(ComputeGraphPtr &compute_graph, const NodePtr &loop_cond_node,
  292. const NodePtr &loop_reset_node, NodePtr &switch_node) {
  293. /*
  294. * loopCond
  295. * |
  296. * v
  297. * switch --> Assign --> active --> ModelExit
  298. * ^
  299. * |
  300. * loopReset
  301. */
  302. // Insert Assign node and ctrl edge
  303. NodePtr assign_node =
  304. InsertAssignOp(compute_graph, ASSIGN, NODE_NAME_FLOWCTRL_LOOP_ASSIGN, loop_cond_node, loop_reset_node);
  305. if (assign_node == nullptr || switch_node == nullptr) {
  306. GELOGE(PARAM_INVALID, "assign_node or switch node is null");
  307. return FAILED;
  308. }
  309. GE_CHK_STATUS_RET(SetStreamLabel(assign_node, switch_node->GetName()), "set stream label failed");
  310. graphStatus add_ret = GraphUtils::AddEdge(switch_node->GetOutControlAnchor(), assign_node->GetInControlAnchor());
  311. if (add_ret != GRAPH_SUCCESS) {
  312. GELOGE(FAILED, "Add switch_node to assign_node ctrl edge failed, add_ret=%u.", add_ret);
  313. return FAILED;
  314. }
  315. if (CheckMultiDataSet(compute_graph)) {
  316. GELOGI("Multi dataSae exist, model_exit node is need.");
  317. // 2. Insert active node and add ctrl edge
  318. string active_name = switch_node->GetName() + "_StreamExitActive";
  319. NodePtr active_node = InsertOp(compute_graph, STREAMACTIVE, active_name, {}, {});
  320. if (active_node == nullptr) {
  321. GELOGE(FAILED, "Insert stream active node:%s for IterCtrlTrueStream failed.", active_name.c_str());
  322. return FAILED;
  323. }
  324. GE_CHK_STATUS_RET(SetStreamLabel(active_node, switch_node->GetName()), "set stream label failed");
  325. GE_CHK_STATUS_RET(SetSwitchBranchNodeLabel(active_node, switch_node->GetName()),
  326. "set switch branch node label failed");
  327. string model_exit_name = switch_node->GetName() + "_ModelExit";
  328. GE_CHK_STATUS_RET(SetActiveLabelList(active_node, { model_exit_name }), "set active label list failed");
  329. add_ret = GraphUtils::AddEdge(assign_node->GetOutControlAnchor(), active_node->GetInControlAnchor());
  330. if (add_ret != GRAPH_SUCCESS) {
  331. GELOGE(FAILED, "Add assign_node to active_node ctrl edge failed, add_ret=%u.", add_ret);
  332. return FAILED;
  333. }
  334. // 3. Insert model exit node and add ctrl edge
  335. NodePtr model_exit_node = InsertOp(compute_graph, MODELEXIT, model_exit_name, {}, {});
  336. if (model_exit_node == nullptr) {
  337. GELOGE(FAILED, "Insert model_exit node:%s for IterCtrlTrueStream failed.", model_exit_name.c_str());
  338. return FAILED;
  339. }
  340. GE_CHK_STATUS_RET(SetStreamLabel(model_exit_node, model_exit_name), "set stream label failed");
  341. add_ret = GraphUtils::AddEdge(active_node->GetOutControlAnchor(), model_exit_node->GetInControlAnchor());
  342. if (add_ret != GRAPH_SUCCESS) {
  343. GELOGE(FAILED, "Add active_node to model_exit_node ctrl edge failed, add_ret=%u.", add_ret);
  344. return FAILED;
  345. }
  346. }
  347. GELOGI("CreateIterCtrlFalseBranch success.");
  348. return SUCCESS;
  349. }
  350. Status FlowCtrlPass::AddFpBpIteratorCtrl(ComputeGraphPtr &compute_graph, NodePtr &pre_node) {
  351. GE_IF_BOOL_EXEC(pre_node == nullptr, DOMI_LOGE("pre_node is nullptr"); return FAILED);
  352. string pre_node_name = pre_node->GetName();
  353. GELOGI("Add FpBp Iterator ctrl, pre node:%s.", pre_node_name.c_str());
  354. // 1. Get or add variables
  355. NodePtr loop_cond_node = AddVariableNode(compute_graph, NODE_NAME_FLOWCTRL_LOOP_COND);
  356. if (loop_cond_node == nullptr) {
  357. GELOGE(FAILED, "Add variable:%s failed.", NODE_NAME_FLOWCTRL_LOOP_COND.c_str());
  358. return FAILED;
  359. }
  360. NodePtr loop_inc_node = AddVariableNode(compute_graph, NODE_NAME_FLOWCTRL_LOOP_INCREMENT);
  361. if (loop_inc_node == nullptr) {
  362. GELOGE(FAILED, "Add variable:%s failed.", NODE_NAME_FLOWCTRL_LOOP_INCREMENT.c_str());
  363. return FAILED;
  364. }
  365. NodePtr loop_reset_node = AddVariableNode(compute_graph, NODE_NAME_FLOWCTRL_LOOP_RESETVALUE);
  366. if (loop_reset_node == nullptr) {
  367. GELOGE(FAILED, "Add variable:%s failed.", NODE_NAME_FLOWCTRL_LOOP_RESETVALUE.c_str());
  368. return FAILED;
  369. }
  370. NodePtr iter_per_loop_node = AddVariableNode(compute_graph, NODE_NAME_FLOWCTRL_LOOP_PER_ITER);
  371. if (iter_per_loop_node == nullptr) {
  372. GELOGE(FAILED, "Add variable:%s failed.", NODE_NAME_FLOWCTRL_LOOP_PER_ITER.c_str());
  373. return FAILED;
  374. }
  375. // 2. Add StreamSwitch
  376. string switch_name = pre_node_name + "_" + NODE_NAME_STREAM_SWITCH;
  377. NodePtr switch_node = InsertStreamSwitchOp(compute_graph, switch_name, loop_cond_node, iter_per_loop_node);
  378. if (switch_node == nullptr) {
  379. GELOGE(FAILED, "InsertStreamSwitchOp:%s failed.", switch_name.c_str());
  380. return FAILED;
  381. }
  382. GE_CHK_STATUS_RET(SetStreamLabel(switch_node, switch_name), "set stream label failed");
  383. graphStatus add_ret = GraphUtils::AddEdge(pre_node->GetOutControlAnchor(), switch_node->GetInControlAnchor());
  384. if (add_ret != GRAPH_SUCCESS) {
  385. GELOGE(FAILED, "Add pre node:%s to switch_node:%s ctrl edge failed, ret = %u.", pre_node_name.c_str(),
  386. switch_name.c_str(), add_ret);
  387. return FAILED;
  388. }
  389. // 3. Create switch false branch: return results and reset the loopCond
  390. Status ret = CreateIterCtrlFalseBranch(compute_graph, loop_cond_node, loop_reset_node, switch_node);
  391. if (ret != SUCCESS) {
  392. GELOGE(ret, "CreateIterCtrlFalseBranch fail, pre node:%s.", pre_node_name.c_str());
  393. return ret;
  394. }
  395. // 4. Create switch true branch:
  396. // active train streams and increase the loopCond
  397. ret = CreateIterCtrlTrueBranch(compute_graph, loop_cond_node, loop_inc_node, switch_node);
  398. if (ret != SUCCESS) {
  399. GELOGE(ret, "CreateIterCtrlTrueBranch fail, pre node:%s.", pre_node_name.c_str());
  400. return ret;
  401. }
  402. return SUCCESS;
  403. }
  404. Status FlowCtrlPass::AddSpecialNodeIteratorCtrl(ComputeGraphPtr &compute_graph, NodePtr &loop_after_node) {
  405. /*
  406. * before add:
  407. * iterator
  408. * |
  409. * v
  410. * MemcpyAsync
  411. *
  412. * after add:
  413. * iterator ----------┐
  414. * | ┆c
  415. * v c v c
  416. * MemcpyAsync-----> switch -----> active
  417. * ^
  418. * / \
  419. * itersPerLoop loopCond
  420. */
  421. GE_IF_BOOL_EXEC(loop_after_node == nullptr || compute_graph == nullptr,
  422. DOMI_LOGE("loop after node or compute graph is null"); return FAILED);
  423. InDataAnchorPtr in_anchor = loop_after_node->GetInDataAnchor(0);
  424. if (in_anchor == nullptr || in_anchor->GetPeerOutAnchor() == nullptr) {
  425. GELOGE(FAILED, "Find %s in data anchor failed.", loop_after_node->GetName().c_str());
  426. return FAILED;
  427. }
  428. NodePtr loop_pre_node = in_anchor->GetPeerOutAnchor()->GetOwnerNode();
  429. // 1. Get variables
  430. NodePtr loop_cond_node = compute_graph->FindNode(NODE_NAME_FLOWCTRL_LOOP_COND);
  431. if (loop_cond_node == nullptr) {
  432. GELOGE(FAILED, "Find node :%s failed.", NODE_NAME_FLOWCTRL_LOOP_COND.c_str());
  433. return FAILED;
  434. }
  435. NodePtr iter_per_loop_node = compute_graph->FindNode(NODE_NAME_FLOWCTRL_LOOP_PER_ITER);
  436. if (iter_per_loop_node == nullptr) {
  437. GELOGE(FAILED, "Find node :%s failed.", NODE_NAME_FLOWCTRL_LOOP_PER_ITER.c_str());
  438. return FAILED;
  439. }
  440. // 2. Add StreamSwitch and edges to switch_node.
  441. GE_IF_BOOL_EXEC(loop_pre_node == nullptr, DOMI_LOGE("loop pre node is null"); return FAILED);
  442. string switch_name = loop_pre_node->GetName() + "_" + NODE_NAME_STREAM_SWITCH;
  443. NodePtr switch_node = InsertStreamSwitchOp(compute_graph, switch_name, loop_cond_node, iter_per_loop_node);
  444. if (switch_node == nullptr) {
  445. GELOGE(FAILED, "InsertStreamSwitchOp:%s failed.", switch_name.c_str());
  446. return FAILED;
  447. }
  448. GE_CHK_STATUS_RET(SetStreamLabel(switch_node, switch_name), "set stream label failed");
  449. graphStatus add_ret = GraphUtils::AddEdge(loop_pre_node->GetOutControlAnchor(), switch_node->GetInControlAnchor());
  450. if (add_ret != GRAPH_SUCCESS) {
  451. GELOGE(FAILED, "Add loop_pre_node:%s to switch_node:%s ctrl edge failed, ret = %u.",
  452. loop_pre_node->GetName().c_str(), switch_name.c_str(), add_ret);
  453. return FAILED;
  454. }
  455. add_ret = GraphUtils::AddEdge(loop_after_node->GetOutControlAnchor(), switch_node->GetInControlAnchor());
  456. if (add_ret != GRAPH_SUCCESS) {
  457. GELOGE(FAILED, "Add node:%s to switch_node:%s ctrl edge failed, ret = %u.", loop_after_node->GetName().c_str(),
  458. switch_name.c_str(), add_ret);
  459. return FAILED;
  460. }
  461. // 3. Create switch true branch: only active
  462. string active_name = switch_name + "_StreamActive";
  463. NodePtr active_node = InsertOp(compute_graph, STREAMACTIVE, active_name, {}, {});
  464. if (active_node == nullptr) {
  465. GELOGE(FAILED, "Insert stream active node:%s for SpecialNodeIteratorCtrl failed.", active_name.c_str());
  466. return FAILED;
  467. }
  468. GE_CHK_STATUS_RET(SetStreamLabel(active_node, active_name), "set stream label failed");
  469. GE_IF_BOOL_EXEC(!AttrUtils::SetBool(active_node->GetOpDesc(), ATTR_NAME_IS_LOOP_ACTIVE, true),
  470. DOMI_LOGE("set ATTR_NAME_IS_LOOP_ACTIVE failed"); return FAILED);
  471. add_ret = GraphUtils::AddEdge(switch_node->GetOutControlAnchor(), active_node->GetInControlAnchor());
  472. if (add_ret != GRAPH_SUCCESS) {
  473. GELOGE(FAILED, "Add switch_node:%s to active_node:%s ctrl edge failed, ret = %u.", switch_name.c_str(),
  474. active_name.c_str(), add_ret);
  475. return FAILED;
  476. }
  477. // used for stream assign to find true branch
  478. GE_CHK_STATUS_RET(SetActiveLabelList(switch_node, { active_name }), "set active label list failed");
  479. // used for stream assign to find active stream
  480. GE_CHK_STATUS_RET(SetActiveLabelList(active_node, { loop_pre_node->GetName() }), "set active label list failed");
  481. return SUCCESS;
  482. }
  483. } // namespace ge

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