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.

single_op_parser.cc 18 kB

4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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 "single_op_parser.h"
  17. #include <vector>
  18. #include <algorithm>
  19. #include <fstream>
  20. #include <sstream>
  21. #include <nlohmann/json.hpp>
  22. #include "framework/common/debug/ge_log.h"
  23. #include "common/util/error_manager/error_manager.h"
  24. #include "common/ge_inner_error_codes.h"
  25. #include "framework/common/util.h"
  26. #include "graph/utils/tensor_utils.h"
  27. #include "graph/utils/op_desc_utils.h"
  28. #include "graph/operator_factory_impl.h"
  29. using Json = nlohmann::json;
  30. using std::map;
  31. using std::string;
  32. using std::vector;
  33. namespace ge {
  34. namespace {
  35. constexpr char const *kKeyOp = "op";
  36. constexpr char const *kKeyInputDesc = "input_desc";
  37. constexpr char const *kKeyOutputDesc = "output_desc";
  38. constexpr char const *kKeyAttr = "attr";
  39. constexpr char const *kKeyName = "name";
  40. constexpr char const *kKeyType = "type";
  41. constexpr char const *kKeyShape = "shape";
  42. constexpr char const *kKeyShapeRange = "shape_range";
  43. constexpr char const *kKeyValue = "value";
  44. constexpr char const *kKeyFormat = "format";
  45. constexpr char const *kFileSuffix = ".om";
  46. constexpr int kDumpJsonIndent = 2;
  47. constexpr int kShapeRangePairSize = 2;
  48. constexpr int kShapeRangeLow = 0;
  49. constexpr int kShapeRangeHigh = 1;
  50. map<string, GeAttrValue::ValueType> kAttrTypeDict = {
  51. {"bool", GeAttrValue::VT_BOOL},
  52. {"int", GeAttrValue::VT_INT},
  53. {"float", GeAttrValue::VT_FLOAT},
  54. {"string", GeAttrValue::VT_STRING},
  55. {"list_bool", GeAttrValue::VT_LIST_BOOL},
  56. {"list_int", GeAttrValue::VT_LIST_INT},
  57. {"list_float", GeAttrValue::VT_LIST_FLOAT},
  58. {"list_string", GeAttrValue::VT_LIST_STRING},
  59. {"list_list_int", GeAttrValue::VT_LIST_LIST_INT},
  60. {"data_type", GeAttrValue::VT_DATA_TYPE},
  61. };
  62. map<string, DataType> kDataTypeDict = {
  63. {"bool", DT_BOOL}, {"int8", DT_INT8}, {"uint8", DT_UINT8}, {"int16", DT_INT16}, {"uint16", DT_UINT16},
  64. {"int32", DT_INT32}, {"uint32", DT_UINT32}, {"int64", DT_INT64}, {"uint64", DT_UINT64}, {"float16", DT_FLOAT16},
  65. {"half", DT_FLOAT16}, {"fp16", DT_FLOAT16}, {"float", DT_FLOAT}, {"float32", DT_FLOAT}, {"double", DT_DOUBLE},
  66. };
  67. map<string, Format> kFormatDict = {
  68. {"nchw", FORMAT_NCHW}, {"nhwc", FORMAT_NHWC}, {"nd", FORMAT_ND}, {"fractal_nz", FORMAT_FRACTAL_NZ},
  69. {"fractal_z", FORMAT_FRACTAL_Z}, {"nc1hwc0", FORMAT_NC1HWC0},
  70. };
  71. } // namespace
  72. template <typename T>
  73. void SetAttrValue(const Json &j, SingleOpAttr &attr) {
  74. attr.value.SetValue<T>(j.at(kKeyValue).get<T>());
  75. }
  76. template <typename T>
  77. T GetValue(const map<string, T> &dict, string &key, T default_val) {
  78. transform(key.begin(), key.end(), key.begin(), ::tolower);
  79. auto it = dict.find(key);
  80. if (it == dict.end()) {
  81. return default_val;
  82. }
  83. return it->second;
  84. }
  85. void from_json(const Json &j, SingleOpTensorDesc &desc) {
  86. desc.dims = j.at(kKeyShape).get<vector<int64_t>>();
  87. auto it = j.find(kKeyShapeRange);
  88. if (it != j.end()) {
  89. desc.dim_ranges = j.at(kKeyShapeRange).get<vector<std::vector<int64_t>>>();
  90. }
  91. string format_str = j.at(kKeyFormat).get<string>();
  92. string type_str = j.at(kKeyType).get<string>();
  93. desc.format = GetValue(kFormatDict, format_str, FORMAT_RESERVED);
  94. desc.type = GetValue(kDataTypeDict, type_str, DT_UNDEFINED);
  95. auto tensor_name = j.find(kKeyName);
  96. if (tensor_name != j.end()) {
  97. desc.name = tensor_name->get<string>();
  98. }
  99. }
  100. void from_json(const Json &j, SingleOpAttr &attr) {
  101. attr.name = j.at(kKeyName).get<string>();
  102. attr.type = j.at(kKeyType).get<string>();
  103. auto it = kAttrTypeDict.find(attr.type);
  104. if (it == kAttrTypeDict.end()) {
  105. GELOGE(UNSUPPORTED, "Parse attr[%s] failed. Unsupported type: %s", attr.name.c_str(), attr.type.c_str());
  106. return;
  107. }
  108. switch (it->second) {
  109. case GeAttrValue::VT_BOOL:
  110. SetAttrValue<bool>(j, attr);
  111. break;
  112. case GeAttrValue::VT_INT:
  113. SetAttrValue<int64_t>(j, attr);
  114. break;
  115. case GeAttrValue::VT_FLOAT:
  116. SetAttrValue<float>(j, attr);
  117. break;
  118. case GeAttrValue::VT_STRING:
  119. SetAttrValue<string>(j, attr);
  120. break;
  121. case GeAttrValue::VT_LIST_BOOL:
  122. SetAttrValue<vector<bool>>(j, attr);
  123. break;
  124. case GeAttrValue::VT_LIST_INT:
  125. SetAttrValue<vector<int64_t>>(j, attr);
  126. break;
  127. case GeAttrValue::VT_LIST_FLOAT:
  128. SetAttrValue<vector<float>>(j, attr);
  129. break;
  130. case GeAttrValue::VT_LIST_STRING:
  131. SetAttrValue<vector<string>>(j, attr);
  132. break;
  133. case GeAttrValue::VT_LIST_LIST_INT:
  134. SetAttrValue<vector<vector<int64_t>>>(j, attr);
  135. break;
  136. case GeAttrValue::VT_DATA_TYPE:
  137. SetAttrValue<DataType>(j, attr);
  138. break;
  139. default:
  140. GELOGE(UNSUPPORTED, "Parse attr[%s] failed. Unsupported type: %s", attr.name.c_str(), attr.type.c_str());
  141. break;
  142. }
  143. }
  144. void from_json(const Json &j, SingleOpDesc &desc) {
  145. desc.op = j.at(kKeyOp).get<string>();
  146. auto input_desc = j.find(kKeyInputDesc);
  147. if (input_desc != j.end()) {
  148. desc.input_desc = input_desc->get<vector<SingleOpTensorDesc>>();
  149. }
  150. auto output_desc = j.find(kKeyOutputDesc);
  151. if (output_desc != j.end()) {
  152. desc.output_desc = output_desc->get<vector<SingleOpTensorDesc>>();
  153. }
  154. auto attr_field = j.find(kKeyAttr);
  155. if (attr_field != j.end()) {
  156. desc.attrs = attr_field->get<vector<SingleOpAttr>>();
  157. }
  158. }
  159. Status SingleOpParser::ReadJsonFile(const std::string &file, Json &json_obj) {
  160. std::string real_path = RealPath(file.c_str());
  161. if (real_path.empty()) {
  162. ErrorManager::GetInstance().ATCReportErrMessage("E10023", {"value"}, {file});
  163. GELOGE(FAILED, "Input parameter[--singleop]'s value[%s] is not a valid path.", file.c_str());
  164. return INTERNAL_ERROR;
  165. }
  166. std::ifstream ifs(real_path);
  167. if (!ifs.is_open()) {
  168. ErrorManager::GetInstance().ATCReportErrMessage("E10024", {"value"}, {file});
  169. GELOGE(FAILED, "Open file[%s] provided in input parameter[--singleop] failed.", file.c_str());
  170. return FAILED;
  171. }
  172. try {
  173. ifs >> json_obj;
  174. } catch (const std::exception &e) {
  175. ErrorManager::GetInstance().ATCReportErrMessage("E10025", {"realpath", "errmsg"}, {real_path, e.what()});
  176. GELOGE(PARAM_INVALID, "Parse file[%s] provided in input parameter[--singleop] failed, exception = %s.",
  177. real_path.c_str(), e.what());
  178. return PARAM_INVALID;
  179. }
  180. ifs.close();
  181. return SUCCESS;
  182. }
  183. bool SingleOpParser::Validate(const SingleOpDesc &op_desc) {
  184. if (op_desc.op.empty()) {
  185. ErrorManager::GetInstance().ATCReportErrMessage("E10026");
  186. GELOGE(PARAM_INVALID, "Op name is empty");
  187. return false;
  188. }
  189. int index = 0;
  190. for (auto &tensor_desc : op_desc.input_desc) {
  191. if (tensor_desc.type == DT_UNDEFINED) {
  192. ErrorManager::GetInstance().ATCReportErrMessage("E10027", {"input", "index"}, {"input", std::to_string(index)});
  193. GELOGE(false, "Input's dataType is invalid when the index is %d", index);
  194. return false;
  195. }
  196. if (tensor_desc.format == FORMAT_RESERVED) {
  197. ErrorManager::GetInstance().ATCReportErrMessage("E10028", {"input", "index"}, {"input", std::to_string(index)});
  198. GELOGE(PARAM_INVALID, "Input's format is invalid when the index is %d", index);
  199. return false;
  200. }
  201. ++index;
  202. }
  203. index = 0;
  204. for (auto &tensor_desc : op_desc.output_desc) {
  205. if (tensor_desc.type == DT_UNDEFINED) {
  206. ErrorManager::GetInstance().ATCReportErrMessage("E10027", {"input", "index"}, {"output", std::to_string(index)});
  207. GELOGE(PARAM_INVALID, "Output's dataType is invalid when the index is %d", index);
  208. return false;
  209. }
  210. if (tensor_desc.format == FORMAT_RESERVED) {
  211. ErrorManager::GetInstance().ATCReportErrMessage("E10028", {"input", "index"}, {"output", std::to_string(index)});
  212. GELOGE(PARAM_INVALID, "Output's format is invalid when the index is %d", index);
  213. return false;
  214. }
  215. ++index;
  216. }
  217. for (auto &attr : op_desc.attrs) {
  218. if (attr.name.empty()) {
  219. ErrorManager::GetInstance().ATCReportErrMessage("E10029");
  220. GELOGE(PARAM_INVALID, "attr name is empty");
  221. return false;
  222. }
  223. if (attr.value.IsEmpty()) {
  224. ErrorManager::GetInstance().ATCReportErrMessage("E10030", {"attrname"}, {attr.name});
  225. GELOGE(PARAM_INVALID, "Parse attr \"%s\" failed. ", attr.name.c_str());
  226. return false;
  227. }
  228. }
  229. return true;
  230. }
  231. std::unique_ptr<OpDesc> SingleOpParser::CreateOpDesc(const string &op_type) {
  232. return std::unique_ptr<OpDesc>(new (std::nothrow) OpDesc(op_type, op_type));
  233. }
  234. Status SingleOpParser::ConvertToBuildParam(int index, const SingleOpDesc &single_op_desc,
  235. SingleOpBuildParam &build_param) {
  236. auto op_desc = CreateOpDesc(single_op_desc.op);
  237. if (op_desc == nullptr) {
  238. GELOGE(MEMALLOC_FAILED, "Failed to create instance of opDesc");
  239. return MEMALLOC_FAILED;
  240. }
  241. std::stringstream file_name;
  242. file_name << index;
  243. file_name << "_" << single_op_desc.op;
  244. for (auto &desc : single_op_desc.input_desc) {
  245. file_name << "_" << desc.type << "_" << desc.format;
  246. for (auto dim : desc.dims) {
  247. file_name << "_" << dim;
  248. }
  249. GeTensorDesc ge_tensor_desc(GeShape(desc.dims), desc.format, desc.type);
  250. ge_tensor_desc.SetOriginFormat(desc.format);
  251. GE_CHK_STATUS_RET_NOLOG(SetShapeRange(op_desc->GetName(), desc, ge_tensor_desc));
  252. TensorUtils::SetRealDimCnt(ge_tensor_desc, desc.dims.size());
  253. TensorUtils::SetInputTensor(ge_tensor_desc, true);
  254. TensorUtils::SetOutputTensor(ge_tensor_desc, false);
  255. if (desc.name.empty()) {
  256. op_desc->AddInputDesc(ge_tensor_desc);
  257. } else {
  258. op_desc->AddInputDesc(desc.name, ge_tensor_desc);
  259. }
  260. build_param.inputs.emplace_back(ge_tensor_desc);
  261. }
  262. for (auto &desc : single_op_desc.output_desc) {
  263. file_name << "_" << desc.type << "_" << desc.format;
  264. for (auto dim : desc.dims) {
  265. file_name << "_" << dim;
  266. }
  267. GeTensorDesc ge_tensor_desc(GeShape(desc.dims), desc.format, desc.type);
  268. ge_tensor_desc.SetOriginFormat(desc.format);
  269. GE_CHK_STATUS_RET_NOLOG(SetShapeRange(op_desc->GetName(), desc, ge_tensor_desc));
  270. TensorUtils::SetRealDimCnt(ge_tensor_desc, desc.dims.size());
  271. TensorUtils::SetInputTensor(ge_tensor_desc, false);
  272. TensorUtils::SetOutputTensor(ge_tensor_desc, true);
  273. if (desc.name.empty()) {
  274. op_desc->AddOutputDesc(ge_tensor_desc);
  275. } else {
  276. op_desc->AddOutputDesc(desc.name, ge_tensor_desc);
  277. }
  278. build_param.outputs.emplace_back(ge_tensor_desc);
  279. }
  280. for (const auto &attr : single_op_desc.attrs) {
  281. op_desc->SetAttr(attr.name, attr.value);
  282. }
  283. if (VerifyOpInputOutputSizeByIr(*op_desc) != SUCCESS) {
  284. GELOGE(PARAM_INVALID, "Verify op [%s] input or output size failed.", op_desc->GetType().c_str());
  285. return PARAM_INVALID;
  286. }
  287. file_name << kFileSuffix;
  288. build_param.file_name = file_name.str();
  289. build_param.op_desc.reset(op_desc.release());
  290. return SUCCESS;
  291. }
  292. Status SingleOpParser::VerifyOpInputOutputSizeByIr(const OpDesc &current_op_desc) {
  293. ge::Operator operator_ir = ge::OperatorFactory::CreateOperator("tmp_operator", current_op_desc.GetType());
  294. if (!operator_ir.IsEmpty()) {
  295. auto opdesc_ir = ge::OpDescUtils::GetOpDescFromOperator(operator_ir);
  296. GE_CHECK_NOTNULL(opdesc_ir);
  297. size_t current_opdesc_inputs_num = current_op_desc.GetInputsSize();
  298. size_t ir_opdesc_inputs_num = opdesc_ir->GetInputsSize();
  299. if (current_opdesc_inputs_num < ir_opdesc_inputs_num) {
  300. string reason = "is smaller than the ir needed input size " + std::to_string(ir_opdesc_inputs_num);
  301. ErrorManager::GetInstance().ATCReportErrMessage(
  302. "E19014", {"opname", "value", "reason"},
  303. {current_op_desc.GetName(), "input size " + std::to_string(current_opdesc_inputs_num), reason});
  304. GELOGE(PARAM_INVALID, "This op [%s] input size %zu is smaller than the ir needed input size %zu",
  305. current_op_desc.GetName().c_str(), current_opdesc_inputs_num, ir_opdesc_inputs_num);
  306. return PARAM_INVALID;
  307. }
  308. size_t current_opdesc_outputs_num = current_op_desc.GetOutputsSize();
  309. size_t ir_opdesc_outputs_num = opdesc_ir->GetOutputsSize();
  310. if (current_opdesc_outputs_num < ir_opdesc_outputs_num) {
  311. string reason = "is smaller than the ir needed output size " + std::to_string(ir_opdesc_outputs_num);
  312. ErrorManager::GetInstance().ATCReportErrMessage(
  313. "E19014", {"opname", "value", "reason"},
  314. {current_op_desc.GetName(), "output size " + std::to_string(current_opdesc_outputs_num), reason});
  315. GELOGE(PARAM_INVALID, "This op [%s] output size %zu is smaller than the ir needed output size %zu",
  316. current_op_desc.GetName().c_str(), current_opdesc_outputs_num, ir_opdesc_outputs_num);
  317. return PARAM_INVALID;
  318. }
  319. }
  320. return SUCCESS;
  321. }
  322. Status SingleOpParser::SetShapeRange(const std::string &op_name, const SingleOpTensorDesc &tensor_desc,
  323. GeTensorDesc &ge_tensor_desc) {
  324. auto num_shape_ranges = tensor_desc.dim_ranges.size();
  325. GELOGD("Number of shape ranges = %zu", num_shape_ranges);
  326. auto it = std::find(tensor_desc.dims.begin(), tensor_desc.dims.end(), ge::UNKNOWN_DIM_NUM);
  327. if (it != tensor_desc.dims.end()) {
  328. if (tensor_desc.dims != ge::UNKNOWN_RANK) {
  329. ErrorManager::GetInstance().ATCReportErrMessage("E19014", {"opname", "value", "reason"},
  330. {op_name, "shape", "has unknown rank but dim size is not one"});
  331. GELOGE(PARAM_INVALID, "Invalid tensor shape: [%s]", ge_tensor_desc.MutableShape().ToString().c_str());
  332. return PARAM_INVALID;
  333. }
  334. if (!tensor_desc.dim_ranges.empty()) {
  335. ErrorManager::GetInstance().ATCReportErrMessage(
  336. "E19014", {"opname", "value", "reason"},
  337. {op_name, "shape range", "is not needed while the rank the shape is unknown"});
  338. GELOGE(PARAM_INVALID, "Shape range is not needed while the rank the shape is unknown");
  339. return PARAM_INVALID;
  340. }
  341. GELOGD("Shape is unknown rank, do not set shape range");
  342. return SUCCESS;
  343. }
  344. std::vector<std::pair<int64_t, int64_t>> shape_range;
  345. size_t range_index = 0;
  346. for (auto dim : tensor_desc.dims) {
  347. if (dim >= 0) {
  348. shape_range.emplace_back(dim, dim);
  349. GELOGD("Adding shape range: [%ld, %ld]", dim, dim);
  350. } else {
  351. GELOGD("To get shape range by index = %zu", range_index);
  352. if (range_index >= num_shape_ranges) {
  353. string reason = "is smaller than the unknown dim size " + std::to_string(++range_index);
  354. ErrorManager::GetInstance().ATCReportErrMessage(
  355. "E19014", {"opname", "value", "reason"},
  356. {op_name, "shape range size " + std::to_string(num_shape_ranges), reason});
  357. GELOGE(PARAM_INVALID, "The number of shape_range mismatches that of unknown dims.");
  358. return PARAM_INVALID;
  359. }
  360. auto &range = tensor_desc.dim_ranges[range_index];
  361. if (range.size() != kShapeRangePairSize) {
  362. string reason = "has " + std::to_string(range.size()) + " item(s)";
  363. ErrorManager::GetInstance().ATCReportErrMessage(
  364. "E19014", {"opname", "value", "reason"}, {op_name, "shape range " + std::to_string(range_index), reason});
  365. GELOGE(PARAM_INVALID, "Invalid shape range entry. index = %zu, size = %zu", range_index, range.size());
  366. return PARAM_INVALID;
  367. }
  368. shape_range.emplace_back(range[kShapeRangeLow], range[kShapeRangeHigh]);
  369. GELOGD("Adding shape range: [%ld, %ld]", range[kShapeRangeLow], range[kShapeRangeHigh]);
  370. ++range_index;
  371. }
  372. }
  373. if (num_shape_ranges != range_index) {
  374. string reason = "is greater than the unknown dim size " + std::to_string(range_index);
  375. ErrorManager::GetInstance().ATCReportErrMessage(
  376. "E19014", {"opname", "value", "reason"},
  377. {op_name, "shape range size " + std::to_string(num_shape_ranges), reason});
  378. GELOGE(PARAM_INVALID, "The number of shape_range(%zu) mismatches that of unknown dims(%zu).", num_shape_ranges,
  379. range_index);
  380. return PARAM_INVALID;
  381. }
  382. if (range_index > 0) {
  383. ge_tensor_desc.SetShapeRange(shape_range);
  384. }
  385. return SUCCESS;
  386. }
  387. Status SingleOpParser::ParseSingleOpList(const std::string &file, std::vector<SingleOpBuildParam> &op_list) {
  388. Json single_op_list_json;
  389. auto ret = ReadJsonFile(file, single_op_list_json);
  390. if (ret != SUCCESS) {
  391. return ret;
  392. }
  393. int index = 0;
  394. for (const Json &single_op_json : single_op_list_json) {
  395. SingleOpDesc single_op_desc;
  396. try {
  397. GELOGI("Parsing op[%d], jsonStr = %s", index, single_op_json.dump(kDumpJsonIndent).c_str());
  398. single_op_desc = single_op_json;
  399. } catch (const nlohmann::json::exception &e) {
  400. ErrorManager::GetInstance().ATCReportErrMessage("E10032", {"index", "jsonfile", "exception"},
  401. {std::to_string(index), file, e.what()});
  402. GELOGE(PARAM_INVALID, "Parse the index[%d] of op failed when read json file[%s], exception %s", index,
  403. file.c_str(), e.what());
  404. return PARAM_INVALID;
  405. }
  406. if (!Validate(single_op_desc)) {
  407. GELOGE(PARAM_INVALID, "Validate the index[%d] of op failed when read json file[%s].", index, file.c_str());
  408. return PARAM_INVALID;
  409. }
  410. SingleOpBuildParam param;
  411. ret = ConvertToBuildParam(index, single_op_desc, param);
  412. if (ret != SUCCESS) {
  413. return ret;
  414. }
  415. op_list.emplace_back(param);
  416. GELOGI("Parse the index[%d] of op success", index);
  417. index += 1;
  418. }
  419. return SUCCESS;
  420. }
  421. } // namespace ge

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