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.

hybrid_model.cc 14 kB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /**
  2. * Copyright 2019-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 "hybrid_model.h"
  17. #include <vector>
  18. #include "graph/debug/ge_attr_define.h"
  19. #include "graph/load/new_model_manager/model_utils.h"
  20. #include "graph/utils/graph_utils.h"
  21. #include "graph/utils/node_utils.h"
  22. #include "graph/utils/tensor_utils.h"
  23. #include "graph/utils/type_utils.h"
  24. #include "hybrid/common/npu_memory_allocator.h"
  25. #include "hybrid/model/hybrid_model_builder.h"
  26. #include "hybrid/node_executor/node_executor.h"
  27. #include "common/op/ge_op_utils.h"
  28. namespace ge {
  29. namespace hybrid {
  30. namespace {
  31. const int64_t kMemSizeUnknownShape = -1; // Unknown shape mem size
  32. }
  33. HybridModel::HybridModel(GeRootModelPtr ge_model) : ge_root_model_(std::move(ge_model)) {
  34. }
  35. HybridModel::~HybridModel() {
  36. GELOGD("[%s] HybridModel destroyed.", model_name_.c_str());
  37. }
  38. Status HybridModel::Init() {
  39. GELOGD("Start to init hybrid model.");
  40. GE_CHK_STATUS_RET(HybridModelBuilder(*this).Build(), "Failed to build hybrid model.");
  41. GELOGD("HybridModel initialized successfully.");
  42. return SUCCESS;
  43. }
  44. TensorValue* HybridModel::GetVariable(const string &name) const {
  45. auto it = variable_tensors_.find(name);
  46. if (it == variable_tensors_.end()) {
  47. GELOGD("Failed to get variable tensor. var name = [%s]", name.c_str());
  48. return nullptr;
  49. }
  50. GELOGD("Got variable tensor. var name = [%s], tensor = %s", name.c_str(), it->second->DebugString().c_str());
  51. return it->second.get();
  52. }
  53. NodePtr HybridModel::GetVariableNode(const string &name) const {
  54. auto it = device_variable_nodes_.find(name);
  55. if (it != device_variable_nodes_.end()) {
  56. return it->second;
  57. }
  58. auto host_find = host_variable_nodes_.find(name);
  59. if (host_find != host_variable_nodes_.end()) {
  60. return host_find->second;
  61. }
  62. GELOGD("Failed to get variable node by name = [%s]", name.c_str());
  63. return nullptr;
  64. }
  65. const std::vector<domi::TaskDef> *HybridModel::GetTaskDefs(const NodePtr &node) const {
  66. auto it = task_defs_.find(node);
  67. if (it == task_defs_.end()) {
  68. return nullptr;
  69. }
  70. return &it->second;
  71. }
  72. NodeItem *HybridModel::MutableNodeItem(const NodePtr &node) {
  73. auto it = node_items_.find(node);
  74. if (it == node_items_.end()) {
  75. return nullptr;
  76. }
  77. return it->second.get();
  78. }
  79. const NodeItem *HybridModel::GetNodeItem(const NodePtr &node) const {
  80. auto it = node_items_.find(node);
  81. if (it == node_items_.end()) {
  82. return nullptr;
  83. }
  84. return it->second.get();
  85. }
  86. GeModelPtr HybridModel::GetGeModel(const NodePtr &node) const {
  87. auto it = known_shape_sub_models_.find(node);
  88. if (it == known_shape_sub_models_.end()) {
  89. GELOGE(INTERNAL_ERROR, "[%s] Failed to get GeModel for subgraph node.", node->GetName().c_str());
  90. return nullptr;
  91. }
  92. return it->second;
  93. }
  94. const GraphItem* HybridModel::GetRootGraphItem() const {
  95. return root_graph_item_.get();
  96. }
  97. const GraphItem *HybridModel::GetSubgraphItem(const std::string &graph_name) const {
  98. GELOGD("To find subgraph item by name = %s", graph_name.c_str());
  99. auto it = subgraph_items_.find(graph_name);
  100. if (it == subgraph_items_.end()) {
  101. GELOGD("Subgraph item not found by node = %s", graph_name.c_str());
  102. return nullptr;
  103. }
  104. return it->second.get();
  105. }
  106. const GraphItem *HybridModel::GetSubgraphItem(const ComputeGraphPtr &subgraph) const {
  107. if (subgraph == nullptr) {
  108. GELOGE(PARAM_INVALID, "subgraph is nullptr");
  109. return nullptr;
  110. }
  111. auto subgraph_name = subgraph->GetName();
  112. return GetSubgraphItem(subgraph_name);
  113. }
  114. const string &HybridModel::GetModelName() const {
  115. return model_name_;
  116. }
  117. Status HybridModel::GetDynamicBatchInfo(std::vector<std::vector<int64_t>> &batch_info, int32_t &dynamic_type) {
  118. // dynamic shape do not need dynamic batch
  119. batch_info = {};
  120. dynamic_type = -1;
  121. return SUCCESS;
  122. }
  123. void HybridModel::GetUserDesignateShapeOrder(std::vector<std::string> &user_input_shape_order) {
  124. // dynamic shape do not need dynamic batch
  125. user_input_shape_order = {};
  126. }
  127. void HybridModel::GetModelAttr(std::vector<std::string> &dynamic_output_shape_info) {
  128. dynamic_output_shape_info = {};
  129. }
  130. Status HybridModel::GetInputOutputDescInfo(vector<InputOutputDescInfo> &input_desc,
  131. vector<InputOutputDescInfo> &output_desc,
  132. std::vector<uint32_t> &input_formats,
  133. std::vector<uint32_t> &output_formats) {
  134. auto node_item_list = root_graph_item_->GetInputNodes();
  135. if (node_item_list.empty()) {
  136. GELOGE(FAILED, "node item list is empty!");
  137. return FAILED;
  138. }
  139. GE_CHECK_NOTNULL(node_item_list[0]->node);
  140. GE_CHECK_NOTNULL(node_item_list[0]->node->GetOpDesc());
  141. if (node_item_list[0]->node->GetOpDesc()->GetInputsSize() != 1) {
  142. GELOGE(FAILED, "input size of op is not 1!");
  143. return FAILED;
  144. }
  145. GE_CHK_STATUS_RET(GetInputDescInfo(input_desc, input_formats), "get input desc info failed");
  146. GE_CHK_STATUS_RET(GetOutputDescInfo(output_desc, output_formats), "get ouput desc info failed");
  147. return SUCCESS;
  148. }
  149. void HybridModel::SetInputDimsAndShapeRangesInfo(const vector<int64_t> &model_input_dims, std::vector<std::pair<int64_t,int64_t>> &shape_ranges,
  150. Format &format, InputOutputDescInfo &input) {
  151. uint32_t n, c, h, w;
  152. n = format == FORMAT_NHWC ? NHWC_DIM_N : NCHW_DIM_N;
  153. c = format == FORMAT_NHWC ? NHWC_DIM_C : NCHW_DIM_C;
  154. h = format == FORMAT_NHWC ? NHWC_DIM_H : NCHW_DIM_H;
  155. w = format == FORMAT_NHWC ? NHWC_DIM_W : NCHW_DIM_W;
  156. if (model_input_dims.size() == static_cast<size_t>(NORMAL_TENSOR_SIZE)) {
  157. input.shape_info.num = model_input_dims[n];
  158. input.shape_info.height = model_input_dims[h];
  159. input.shape_info.width = model_input_dims[w];
  160. input.shape_info.channel = model_input_dims[c];
  161. }
  162. for (auto model_input_dim : model_input_dims) {
  163. input.shape_info.dims.push_back(model_input_dim);
  164. }
  165. input.shape_info.shape_ranges = shape_ranges;
  166. return;
  167. }
  168. void HybridModel::CreateInputDimsInfo(const OpDescPtr &op_desc, Format format, InputOutputDescInfo &input) {
  169. std::vector<std::pair<int64_t,int64_t>> shape_ranges;
  170. if (is_new_model_desc_ && op_desc->HasAttr(ATTR_NAME_INPUT_DIMS)) {
  171. // When static aipp is set, need to get the model input dims which processed by aipp
  172. vector<int64_t> model_input_dims;
  173. (void)AttrUtils::GetListInt(op_desc, ATTR_NAME_INPUT_DIMS, model_input_dims);
  174. SetInputDimsAndShapeRangesInfo(model_input_dims, shape_ranges, format, input);
  175. return;
  176. }
  177. // judge if this data is linked dynamic aipp first, multiply batch has been considered
  178. if (op_desc->HasAttr("_dynamic_aipp_input_dims")) {
  179. vector<int64_t> dynamic_aipp_input_dims;
  180. (void)AttrUtils::GetListInt(op_desc, "_dynamic_aipp_input_dims", dynamic_aipp_input_dims);
  181. SetInputDimsAndShapeRangesInfo(dynamic_aipp_input_dims, shape_ranges, format, input);
  182. return;
  183. } else {
  184. vector<int64_t> input_dims = op_desc->GetInputDescPtr(0)->GetShape().GetDims();
  185. op_desc->GetInputDescPtr(0)->GetShapeRange(shape_ranges);
  186. SetInputDimsAndShapeRangesInfo(input_dims, shape_ranges, format, input);
  187. return;
  188. }
  189. }
  190. Status HybridModel::GetInputDescInfo(vector<InputOutputDescInfo> &input_desc, std::vector<uint32_t> &formats) {
  191. auto node_item_list = root_graph_item_->GetInputNodes();
  192. for (auto &node_item : node_item_list) {
  193. InputOutputDescInfo input;
  194. GE_CHECK_NOTNULL(node_item->node);
  195. auto op_desc = node_item->node->GetOpDesc();
  196. GE_CHECK_NOTNULL(op_desc);
  197. GE_CHECK_NOTNULL(op_desc->GetInputDescPtr(0));
  198. Format format = op_desc->GetInputDescPtr(0)->GetFormat();
  199. input.data_type = op_desc->GetInputDescPtr(0)->GetDataType();
  200. input.name = op_desc->GetName();
  201. int64_t input_size = 0;
  202. GE_CHK_STATUS_RET(TensorUtils::GetSize(*op_desc->GetInputDescPtr(0), input_size), "get input size failed.");
  203. // support dynamic shape
  204. if (input_size < 0) {
  205. GELOGD("dynamic shape scene, input size is unknown. "
  206. "format=%d, data_type=%d, input_size=%ld",
  207. format, input.data_type, input_size);
  208. input_size = kMemSizeUnknownShape; // -1
  209. }
  210. // not support dynamic shape input for now, so input_size here will be not less than zero.
  211. input.size = input_size;
  212. CreateInputDimsInfo(op_desc, format, input);
  213. formats.push_back(format);
  214. input_desc.push_back(input);
  215. }
  216. is_new_model_desc_ = false;
  217. return SUCCESS;
  218. }
  219. void HybridModel::CreateOutput(ConstGeTensorDescPtr &output_desc, InputOutputDescInfo &output_desc_info, uint32_t &format_result) {
  220. GE_IF_BOOL_EXEC(output_desc == nullptr, GELOGE(FAILED, "output desc ptr is nullptr"); return );
  221. Format format = output_desc->GetFormat();
  222. GeShape shape = output_desc->GetShape();
  223. std::vector<std::pair<int64_t,int64_t>> shape_ranges;
  224. output_desc->GetShapeRange(shape_ranges);
  225. DataType data_type = output_desc->GetDataType();
  226. int64_t dims[] = {1, 1, 1, 1};
  227. format_result = format;
  228. if (format == FORMAT_ND) { // for ND tensor
  229. for (size_t i = 0; i < shape.GetDimNum() && i < (sizeof(dims) / sizeof(dims[0])); i++) {
  230. dims[i] = shape.GetDim(i);
  231. }
  232. } else { // FOR FORMAT_NHWC or FORMAT_NCHW
  233. dims[0] = shape.GetDim(format == FORMAT_NHWC ? NHWC_DIM_N : NCHW_DIM_N); // 0: first dim
  234. dims[1] = shape.GetDim(format == FORMAT_NHWC ? NHWC_DIM_C : NCHW_DIM_C); // 1: second dim
  235. dims[2] = shape.GetDim(format == FORMAT_NHWC ? NHWC_DIM_H : NCHW_DIM_H); // 2: third dim
  236. dims[3] = shape.GetDim(format == FORMAT_NHWC ? NHWC_DIM_W : NCHW_DIM_W); // 3: forth dim
  237. }
  238. output_desc_info.shape_info.num = dims[0]; // 0: first dim
  239. output_desc_info.shape_info.channel = dims[1]; // 1: second dim
  240. output_desc_info.shape_info.height = dims[2]; // 2: third dim
  241. output_desc_info.shape_info.width = dims[3]; // 3: forth dim
  242. if (format == FORMAT_FRACTAL_Z) { // FraczToHWCK
  243. int64_t k = shape.GetDim(0); // 0: first dim
  244. int64_t c = shape.GetDim(1); // 1: second dim
  245. int64_t h = shape.GetDim(2); // 2: third dim
  246. int64_t w = shape.GetDim(3); // 3: forth dim
  247. output_desc_info.shape_info.dims.push_back(h);
  248. output_desc_info.shape_info.dims.push_back(w);
  249. output_desc_info.shape_info.dims.push_back(c);
  250. output_desc_info.shape_info.dims.push_back(k);
  251. if (shape_ranges.size() == 4) { // 4 dims
  252. output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[2]); // h:2
  253. output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[3]); // w:3
  254. output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[1]); // c:1
  255. output_desc_info.shape_info.shape_ranges.push_back(shape_ranges[0]); // k:0
  256. }
  257. format_result = FORMAT_HWCN;
  258. } else {
  259. for (size_t j = 0; j < shape.GetDimNum(); j++) {
  260. output_desc_info.shape_info.dims.push_back(shape.GetDim(j));
  261. }
  262. output_desc_info.shape_info.shape_ranges = shape_ranges;
  263. }
  264. int64_t tensor_size = 0;
  265. (void)TensorUtils::CalcTensorMemSize(shape, format, data_type, tensor_size);
  266. output_desc_info.size = static_cast<uint64_t>(tensor_size);
  267. output_desc_info.data_type = output_desc->GetDataType();
  268. }
  269. Status HybridModel::GetOutputDescInfo(vector<InputOutputDescInfo> &output_desc, std::vector<uint32_t> &formats) {
  270. std::vector<ConstGeTensorDescPtr> output_desc_list;
  271. GE_CHK_STATUS_RET(root_graph_item_->GetOutputDescList(output_desc_list), "get output desc info failed"); // output_desc_list contains vaild input desc
  272. vector<std::string> out_node_names;
  273. (void)ge::AttrUtils::GetListStr(ge_root_model_->GetRootGraph(), ATTR_MODEL_OUT_NODES_NAME, out_node_names);
  274. GE_CHECK_NOTNULL(root_graph_item_->GetOutputNode());
  275. auto op_desc = root_graph_item_->GetOutputNode()->op_desc;
  276. GE_CHECK_NOTNULL(op_desc);
  277. auto out_size = static_cast<uint32_t>(op_desc->GetInputsSize());
  278. GE_CHK_BOOL_RET_STATUS(out_size == output_desc_list.size(), FAILED, "output size[%u] not match output_desc_list size[%zu]", out_size, output_desc_list.size());
  279. for (uint32_t index = 0; index < out_size; ++index) {
  280. string output_name;
  281. std::vector<std::string> src_name = op_desc->GetSrcName();
  282. std::vector<int64_t> src_index = op_desc->GetSrcIndex();
  283. if (out_size == out_node_names.size()) {
  284. bool contains_colon = out_node_names[index].find(":") != std::string::npos;
  285. output_name = contains_colon ? out_node_names[index] : out_node_names[index] + ":" + std::to_string(src_index[index]);
  286. } else {
  287. output_name = std::string("output_") + std::to_string(index) + "_" + src_name[index] + "_" + std::to_string(src_index[index]);
  288. }
  289. InputOutputDescInfo output_desc_info;
  290. output_desc_info.name = output_name;
  291. uint32_t format_result;
  292. CreateOutput(output_desc_list[index], output_desc_info, format_result);
  293. output_desc.push_back(output_desc_info);
  294. formats.push_back(format_result);
  295. }
  296. return SUCCESS;
  297. }
  298. } // namespace hybrid
  299. } // namespace ge

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