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.

model_process.cc 15 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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 "serving/acl/model_process.h"
  17. #include <algorithm>
  18. #include <unordered_map>
  19. #include "include/infer_log.h"
  20. namespace mindspore {
  21. namespace inference {
  22. Status ModelProcess::PreInitModelResource() {
  23. model_desc_ = aclmdlCreateDesc();
  24. aclError acl_ret = aclmdlGetDesc(model_desc_, model_id_);
  25. if (acl_ret != ACL_ERROR_NONE) {
  26. MSI_LOG_ERROR << "Read model desc failed";
  27. return FAILED;
  28. }
  29. Status ret = InitInputsBuffer();
  30. if (ret != SUCCESS) {
  31. MSI_LOG_ERROR << "Create input buffer failed";
  32. return FAILED;
  33. }
  34. ret = InitOutputsBuffer();
  35. if (ret != SUCCESS) {
  36. MSI_LOG_ERROR << "Create output buffer failed";
  37. return FAILED;
  38. }
  39. return SUCCESS;
  40. }
  41. Status ModelProcess::LoadModelFromFile(const std::string &file_name, uint32_t &model_id) {
  42. aclError acl_ret = aclmdlLoadFromFile(file_name.c_str(), &model_id);
  43. if (acl_ret != ACL_ERROR_NONE) {
  44. MSI_LOG_ERROR << "Read model file failed, file name is " << file_name;
  45. return FAILED;
  46. }
  47. MSI_LOG_INFO << "Load model success " << file_name;
  48. model_id_ = model_id;
  49. if (PreInitModelResource() != SUCCESS) {
  50. aclmdlUnload(model_id_);
  51. MSI_LOG_ERROR << "Pre init model resource failed, file name is " << file_name;
  52. return FAILED;
  53. }
  54. return SUCCESS;
  55. }
  56. Status ModelProcess::InitInputsBuffer() {
  57. aclError ret;
  58. size_t input_size = aclmdlGetNumInputs(model_desc_);
  59. for (size_t i = 0; i < input_size; ++i) {
  60. auto buffer_size = aclmdlGetInputSizeByIndex(model_desc_, i);
  61. void *data_mem_buffer = nullptr;
  62. if (!is_run_on_device_) { // need to copy input/output to/from device
  63. ret = aclrtMalloc(&data_mem_buffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY);
  64. if (ret != ACL_ERROR_NONE) {
  65. MSI_LOG_ERROR << "Malloc device input buffer faild , input size " << buffer_size;
  66. return FAILED;
  67. }
  68. }
  69. aclmdlIODims dims;
  70. ret = aclmdlGetInputDims(model_desc_, i, &dims);
  71. if (ret != ACL_ERROR_NONE) {
  72. MSI_LOG_ERROR << "Get input shape failed";
  73. if (!is_run_on_device_) {
  74. aclrtFree(data_mem_buffer);
  75. }
  76. return FAILED;
  77. }
  78. aclDataType data_type = aclmdlGetInputDataType(model_desc_, i);
  79. std::vector<int64_t> shape(dims.dims, dims.dims + dims.dimCount);
  80. input_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape});
  81. }
  82. MSI_LOG_INFO << "Create model inputs success";
  83. return SUCCESS;
  84. }
  85. Status ModelProcess::CreateDataBuffer(void *&data_mem_buffer, size_t buffer_size, aclmdlDataset *dataset) {
  86. aclError ret;
  87. auto free_data_buffer = [this](void *dataMemBuffer) {
  88. if (!is_run_on_device_) {
  89. aclrtFree(dataMemBuffer);
  90. } else {
  91. aclrtFreeHost(dataMemBuffer);
  92. }
  93. };
  94. if (!is_run_on_device_) {
  95. ret = aclrtMalloc(&data_mem_buffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY);
  96. if (ret != ACL_ERROR_NONE) {
  97. MSI_LOG_ERROR << "Malloc device buffer faild , buffer size " << buffer_size;
  98. return FAILED;
  99. }
  100. } else {
  101. ret = aclrtMallocHost(&data_mem_buffer, buffer_size);
  102. if (ret != ACL_ERROR_NONE) {
  103. MSI_LOG_ERROR << "Malloc device buffer faild , buffer size " << buffer_size;
  104. return FAILED;
  105. }
  106. }
  107. auto data_buffer = aclCreateDataBuffer(data_mem_buffer, buffer_size);
  108. if (data_buffer == nullptr) {
  109. MSI_LOG_ERROR << "Create Data Buffer failed";
  110. free_data_buffer(data_mem_buffer);
  111. return FAILED;
  112. }
  113. ret = aclmdlAddDatasetBuffer(dataset, data_buffer);
  114. if (ret != ACL_ERROR_NONE) {
  115. MSI_LOG_ERROR << "add data buffer failed";
  116. free_data_buffer(data_mem_buffer);
  117. aclDestroyDataBuffer(data_buffer);
  118. return FAILED;
  119. }
  120. return SUCCESS;
  121. }
  122. Status ModelProcess::InitOutputsBuffer() {
  123. aclError ret;
  124. outputs_ = aclmdlCreateDataset();
  125. if (outputs_ == nullptr) {
  126. MSI_LOG_ERROR << "Create input dataset failed";
  127. return FAILED;
  128. }
  129. size_t output_size = aclmdlGetNumOutputs(model_desc_);
  130. for (size_t i = 0; i < output_size; ++i) {
  131. auto buffer_size = aclmdlGetOutputSizeByIndex(model_desc_, i);
  132. void *data_mem_buffer = nullptr;
  133. if (CreateDataBuffer(data_mem_buffer, buffer_size, outputs_) != SUCCESS) {
  134. MSI_LOG_ERROR << "add output data buffer failed, buffer size " << buffer_size;
  135. return FAILED;
  136. }
  137. aclmdlIODims dims;
  138. ret = aclmdlGetOutputDims(model_desc_, i, &dims);
  139. if (ret != ACL_ERROR_NONE) {
  140. MSI_LOG_ERROR << "Get input shape failed";
  141. if (!is_run_on_device_) {
  142. aclrtFree(data_mem_buffer);
  143. } else {
  144. aclrtFreeHost(data_mem_buffer);
  145. }
  146. return FAILED;
  147. }
  148. aclDataType data_type = aclmdlGetOutputDataType(model_desc_, i);
  149. std::vector<int64_t> shape(dims.dims, dims.dims + dims.dimCount);
  150. output_infos_.emplace_back(AclTensorInfo{data_mem_buffer, buffer_size, data_type, shape});
  151. }
  152. MSI_LOG_INFO << "Create model output success";
  153. return SUCCESS;
  154. }
  155. void ModelProcess::DestroyInputsDataset() {
  156. if (inputs_ == nullptr) {
  157. return;
  158. }
  159. for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(inputs_); i++) {
  160. auto dataBuffer = aclmdlGetDatasetBuffer(inputs_, i);
  161. aclDestroyDataBuffer(dataBuffer);
  162. }
  163. aclmdlDestroyDataset(inputs_);
  164. inputs_ = nullptr;
  165. }
  166. void ModelProcess::DestroyInputsDataMem() {
  167. if (!is_run_on_device_) {
  168. for (const auto &item : input_infos_) {
  169. aclrtFree(item.device_data);
  170. }
  171. }
  172. input_infos_.clear();
  173. }
  174. void ModelProcess::DestroyInputsBuffer() {
  175. DestroyInputsDataMem();
  176. DestroyInputsDataset();
  177. }
  178. void ModelProcess::DestroyOutputsBuffer() {
  179. for (const auto &item : output_infos_) {
  180. if (!is_run_on_device_) {
  181. aclrtFree(item.device_data);
  182. } else {
  183. aclrtFreeHost(item.device_data);
  184. }
  185. }
  186. output_infos_.clear();
  187. if (outputs_ == nullptr) {
  188. return;
  189. }
  190. for (size_t i = 0; i < aclmdlGetDatasetNumBuffers(outputs_); i++) {
  191. auto dataBuffer = aclmdlGetDatasetBuffer(outputs_, i);
  192. aclDestroyDataBuffer(dataBuffer);
  193. }
  194. aclmdlDestroyDataset(outputs_);
  195. outputs_ = nullptr;
  196. }
  197. void ModelProcess::UnLoad() {
  198. auto ret = aclmdlUnload(model_id_);
  199. if (ret != ACL_ERROR_NONE) {
  200. MSI_LOG_ERROR << "Unload model failed";
  201. }
  202. if (model_desc_ != nullptr) {
  203. aclmdlDestroyDesc(model_desc_);
  204. model_desc_ = nullptr;
  205. }
  206. DestroyInputsBuffer();
  207. DestroyOutputsBuffer();
  208. MSI_LOG_INFO << "End unload model " << model_id_;
  209. }
  210. Status ModelProcess::CheckAndInitInput(const RequestBase &request) {
  211. aclError ret;
  212. inputs_ = aclmdlCreateDataset();
  213. // check inputs
  214. if (request.size() != input_infos_.size()) {
  215. MSI_LOG_ERROR << "inputs count not match, required count " << input_infos_.size() << ", given count "
  216. << request.size();
  217. return INFER_STATUS(INVALID_INPUTS) << "inputs count not match, required count " << input_infos_.size()
  218. << ", given count " << request.size();
  219. }
  220. for (size_t i = 0; i < input_infos_.size(); i++) {
  221. if (request[i] == nullptr) {
  222. MSI_LOG_ERROR << "input " << i << " cannot be null";
  223. return FAILED;
  224. }
  225. if (request[i]->data_size() != input_infos_[i].buffer_size) {
  226. MSI_LOG_ERROR << "input " << i << " data size not match, required size " << input_infos_[i].buffer_size
  227. << ", given count " << request[i]->data_size();
  228. return INFER_STATUS(INVALID_INPUTS) << "input " << i << " data size not match, required size "
  229. << input_infos_[i].buffer_size << ", given count " << request[i]->data_size();
  230. }
  231. }
  232. // copy inputs
  233. for (size_t i = 0; i < input_infos_.size(); i++) {
  234. void *input_buffer = nullptr;
  235. auto &info = input_infos_[i];
  236. const void *data = request[i]->data();
  237. if (!is_run_on_device_) {
  238. ret = aclrtMemcpy(info.device_data, info.buffer_size, data, request[i]->data_size(), ACL_MEMCPY_HOST_TO_DEVICE);
  239. if (ret != ACL_ERROR_NONE) {
  240. MSI_LOG_ERROR << "memcpy input " << i << " data to device failed, buffer size " << request[i]->data_size();
  241. return FAILED;
  242. }
  243. input_buffer = info.device_data;
  244. } else {
  245. input_buffer = const_cast<void *>(data);
  246. }
  247. auto data_buffer = aclCreateDataBuffer(input_buffer, info.buffer_size);
  248. if (data_buffer == nullptr) {
  249. MSI_LOG_ERROR << "Create Data Buffer failed";
  250. return FAILED;
  251. }
  252. ret = aclmdlAddDatasetBuffer(inputs_, data_buffer);
  253. if (ret != ACL_ERROR_NONE) {
  254. MSI_LOG_ERROR << "add data buffer failed";
  255. aclDestroyDataBuffer(data_buffer);
  256. return FAILED;
  257. }
  258. }
  259. return SUCCESS;
  260. }
  261. Status ModelProcess::CheckAndInitDvppInput(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size,
  262. size_t input_index) {
  263. aclError ret;
  264. inputs_ = aclmdlCreateDataset();
  265. // check inputs
  266. if (input_index >= input_infos_.size()) {
  267. MSI_LOG_ERROR << "inputs count not match, required count " << input_infos_.size() << ", given index "
  268. << input_index;
  269. return INFER_STATUS(INVALID_INPUTS) << "inputs count not match, required count " << input_infos_.size()
  270. << ", given index " << input_index;
  271. }
  272. if (dvpp_outputs_buffer_dev == nullptr) {
  273. MSI_LOG_ERROR << "input " << 0 << " cannot be null";
  274. return FAILED;
  275. }
  276. if (dvpp_outputs_buffer_size != input_infos_[input_index].buffer_size) {
  277. MSI_LOG_ERROR << "input " << 0 << " data size not match, required size " << input_infos_[input_index].buffer_size
  278. << ", given count " << dvpp_outputs_buffer_size;
  279. return INFER_STATUS(INVALID_INPUTS) << "input " << 0 << " data size not match, required size "
  280. << input_infos_[input_index].buffer_size << ", given count "
  281. << dvpp_outputs_buffer_size;
  282. }
  283. // copy inputs
  284. auto &info = input_infos_[input_index];
  285. auto data_buffer = aclCreateDataBuffer(const_cast<void *>(dvpp_outputs_buffer_dev), info.buffer_size);
  286. if (data_buffer == nullptr) {
  287. MSI_LOG_ERROR << "Create Data Buffer failed";
  288. return FAILED;
  289. }
  290. ret = aclmdlAddDatasetBuffer(inputs_, data_buffer);
  291. if (ret != ACL_ERROR_NONE) {
  292. MSI_LOG_ERROR << "add data buffer failed";
  293. aclDestroyDataBuffer(data_buffer);
  294. return FAILED;
  295. }
  296. return SUCCESS;
  297. }
  298. Status ModelProcess::BuildOutputs(ReplyBase &reply) {
  299. aclError ret;
  300. // copy outputs
  301. reply.clear();
  302. std::unordered_map<aclDataType, inference::DataType> data_type_map = {
  303. {ACL_FLOAT16, inference::kMSI_Float16}, {ACL_FLOAT, inference::kMSI_Float32}, {ACL_DOUBLE, inference::kMSI_Float64},
  304. {ACL_INT8, inference::kMSI_Int8}, {ACL_INT16, inference::kMSI_Int16}, {ACL_INT32, inference::kMSI_Int32},
  305. {ACL_INT64, inference::kMSI_Int64}, {ACL_UINT8, inference::kMSI_Uint8}, {ACL_UINT16, inference::kMSI_Uint16},
  306. {ACL_UINT32, inference::kMSI_Uint32}, {ACL_UINT64, inference::kMSI_Uint64}, {ACL_BOOL, inference::kMSI_Bool},
  307. };
  308. auto trans_to_serving_type = [&data_type_map](aclDataType data_type) {
  309. auto it = data_type_map.find(data_type);
  310. if (it == data_type_map.end()) {
  311. return inference::kMSI_Unknown;
  312. } else {
  313. return it->second;
  314. }
  315. };
  316. for (size_t i = 0; i < output_infos_.size(); i++) {
  317. auto &info = output_infos_[i];
  318. auto output = reply.add();
  319. if (output == nullptr) {
  320. MSI_LOG_ERROR << "add new output failed";
  321. return FAILED;
  322. }
  323. output->set_data_type(trans_to_serving_type(info.data_type));
  324. output->set_shape(info.dims);
  325. if (!output->resize_data(info.buffer_size)) {
  326. MSI_LOG_ERROR << "new output data buffer failed, data size " << info.buffer_size;
  327. return FAILED;
  328. }
  329. if (!is_run_on_device_) {
  330. ret = aclrtMemcpy(output->mutable_data(), output->data_size(), info.device_data, info.buffer_size,
  331. ACL_MEMCPY_DEVICE_TO_HOST);
  332. if (ret != ACL_ERROR_NONE) {
  333. MSI_LOG_ERROR << "Memcpy output " << i << " to host failed, memory size " << info.buffer_size;
  334. return FAILED;
  335. }
  336. } else {
  337. ret = aclrtMemcpy(output->mutable_data(), output->data_size(), info.device_data, info.buffer_size,
  338. ACL_MEMCPY_HOST_TO_HOST);
  339. if (ret != ACL_ERROR_NONE) {
  340. MSI_LOG_ERROR << "Memcpy output " << i << " to host failed, memory size " << info.buffer_size;
  341. return FAILED;
  342. }
  343. }
  344. }
  345. return SUCCESS;
  346. }
  347. Status ModelProcess::Execute(const RequestBase &request, ReplyBase &reply) {
  348. aclError acl_ret;
  349. Status ret = CheckAndInitInput(request);
  350. if (ret != SUCCESS) {
  351. MSI_LOG_ERROR << "check or init input failed";
  352. DestroyInputsDataset();
  353. return ret; // forward status error
  354. }
  355. acl_ret = aclmdlExecute(model_id_, inputs_, outputs_);
  356. DestroyInputsDataset();
  357. if (acl_ret != ACL_ERROR_NONE) {
  358. MSI_LOG_ERROR << "Execute Model Failed";
  359. return FAILED;
  360. }
  361. ret = BuildOutputs(reply);
  362. if (ret != SUCCESS) {
  363. MSI_LOG_ERROR << "Build outputs faield";
  364. return FAILED;
  365. }
  366. MSI_LOG_INFO << "excute model success";
  367. return SUCCESS;
  368. }
  369. Status ModelProcess::Execute(const void *dvpp_outputs_buffer_dev, size_t dvpp_outputs_buffer_size, ReplyBase &reply) {
  370. aclError acl_ret;
  371. if (input_infos_.size() != 1) {
  372. MSI_LOG_ERROR << "can only support input size 1, now model inputs size is " << input_infos_.size();
  373. return INFER_STATUS(INVALID_INPUTS) << "can only support input size 1, now model inputs size is "
  374. << input_infos_.size();
  375. }
  376. Status ret = CheckAndInitDvppInput(dvpp_outputs_buffer_dev, dvpp_outputs_buffer_size, 0);
  377. if (ret != SUCCESS) {
  378. MSI_LOG_ERROR << "check or init input failed";
  379. DestroyInputsDataset();
  380. return ret; // forward status msg
  381. }
  382. acl_ret = aclmdlExecute(model_id_, inputs_, outputs_);
  383. DestroyInputsDataset();
  384. if (acl_ret != ACL_ERROR_NONE) {
  385. MSI_LOG_ERROR << "Execute Model Failed";
  386. return INFER_STATUS(FAILED) << "Execute Model Failed";
  387. }
  388. ret = BuildOutputs(reply);
  389. if (ret != SUCCESS) {
  390. MSI_LOG_ERROR << "Build outputs faield";
  391. return FAILED;
  392. }
  393. MSI_LOG_INFO << "excute model success";
  394. return SUCCESS;
  395. }
  396. size_t ModelProcess::GetBatchSize() const {
  397. if (input_infos_.empty()) {
  398. MSI_LOG_ERROR << "Model is not loaded";
  399. return 0;
  400. }
  401. if (input_infos_[0].dims.empty()) {
  402. return 1;
  403. }
  404. return static_cast<size_t>(input_infos_[0].dims[0]);
  405. }
  406. } // namespace inference
  407. } // namespace mindspore