paddlex.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. // Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "include/paddlex/paddlex.h"
  15. namespace PaddleX {
  16. void Model::create_predictor(const std::string& model_dir,
  17. bool use_gpu,
  18. bool use_trt,
  19. int gpu_id,
  20. std::string key) {
  21. // 读取配置文件
  22. if (!load_config(model_dir)) {
  23. std::cerr << "Parse file 'model.yml' failed!" << std::endl;
  24. exit(-1);
  25. }
  26. paddle::AnalysisConfig config;
  27. std::string model_file = model_dir + OS_PATH_SEP + "__model__";
  28. std::string params_file = model_dir + OS_PATH_SEP + "__params__";
  29. #ifdef WITH_ENCRYPTION
  30. if (key != ""){
  31. model_file = model_dir + OS_PATH_SEP + "__model__.encrypted";
  32. params_file = model_dir + OS_PATH_SEP + "__params__.encrypted";
  33. paddle_security_load_model(&config, key.c_str(), model_file.c_str(), params_file.c_str());
  34. }
  35. #endif
  36. if (key == ""){
  37. config.SetModel(model_file, params_file);
  38. }
  39. if (use_gpu) {
  40. config.EnableUseGpu(100, gpu_id);
  41. } else {
  42. config.DisableGpu();
  43. }
  44. config.SwitchUseFeedFetchOps(false);
  45. config.SwitchSpecifyInputNames(true);
  46. // 开启内存优化
  47. config.EnableMemoryOptim();
  48. if (use_trt) {
  49. config.EnableTensorRtEngine(
  50. 1 << 20 /* workspace_size*/,
  51. 32 /* max_batch_size*/,
  52. 20 /* min_subgraph_size*/,
  53. paddle::AnalysisConfig::Precision::kFloat32 /* precision*/,
  54. true /* use_static*/,
  55. false /* use_calib_mode*/);
  56. }
  57. predictor_ = std::move(CreatePaddlePredictor(config));
  58. }
  59. bool Model::load_config(const std::string& model_dir) {
  60. std::string yaml_file = model_dir + OS_PATH_SEP + "model.yml";
  61. YAML::Node config = YAML::LoadFile(yaml_file);
  62. type = config["_Attributes"]["model_type"].as<std::string>();
  63. name = config["Model"].as<std::string>();
  64. std::string version = config["version"].as<std::string>();
  65. if (version[0] == '0') {
  66. std::cerr << "[Init] Version of the loaded model is lower than 1.0.0, deployment "
  67. << "cannot be done, please refer to "
  68. << "https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/tutorials/deploy/upgrade_version.md "
  69. << "to transfer version."
  70. << std::endl;
  71. return false;
  72. }
  73. bool to_rgb = true;
  74. if (config["TransformsMode"].IsDefined()) {
  75. std::string mode = config["TransformsMode"].as<std::string>();
  76. if (mode == "BGR") {
  77. to_rgb = false;
  78. } else if (mode != "RGB") {
  79. std::cerr << "[Init] Only 'RGB' or 'BGR' is supported for TransformsMode"
  80. << std::endl;
  81. return false;
  82. }
  83. }
  84. // 构建数据处理流
  85. transforms_.Init(config["Transforms"], to_rgb);
  86. // 读入label list
  87. labels.clear();
  88. for (const auto& item : config["_Attributes"]["labels"]) {
  89. int index = labels.size();
  90. labels[index] = item.as<std::string>();
  91. }
  92. return true;
  93. }
  94. bool Model::preprocess(const cv::Mat& input_im, ImageBlob* blob) {
  95. cv::Mat im = input_im.clone();
  96. if (!transforms_.Run(&im, &inputs_)) {
  97. return false;
  98. }
  99. return true;
  100. }
  101. bool Model::predict(const cv::Mat& im, ClsResult* result) {
  102. inputs_.clear();
  103. if (type == "detector") {
  104. std::cerr << "Loading model is a 'detector', DetResult should be passed to "
  105. "function predict()!"
  106. << std::endl;
  107. return false;
  108. } else if (type == "segmenter") {
  109. std::cerr << "Loading model is a 'segmenter', SegResult should be passed "
  110. "to function predict()!"
  111. << std::endl;
  112. return false;
  113. }
  114. // 处理输入图像
  115. if (!preprocess(im, &inputs_)) {
  116. std::cerr << "Preprocess failed!" << std::endl;
  117. return false;
  118. }
  119. // 使用加载的模型进行预测
  120. auto in_tensor = predictor_->GetInputTensor("image");
  121. int h = inputs_.new_im_size_[0];
  122. int w = inputs_.new_im_size_[1];
  123. in_tensor->Reshape({1, 3, h, w});
  124. in_tensor->copy_from_cpu(inputs_.im_data_.data());
  125. predictor_->ZeroCopyRun();
  126. // 取出模型的输出结果
  127. auto output_names = predictor_->GetOutputNames();
  128. auto output_tensor = predictor_->GetOutputTensor(output_names[0]);
  129. std::vector<int> output_shape = output_tensor->shape();
  130. int size = 1;
  131. for (const auto& i : output_shape) {
  132. size *= i;
  133. }
  134. outputs_.resize(size);
  135. output_tensor->copy_to_cpu(outputs_.data());
  136. // 对模型输出结果进行后处理
  137. auto ptr = std::max_element(std::begin(outputs_), std::end(outputs_));
  138. result->category_id = std::distance(std::begin(outputs_), ptr);
  139. result->score = *ptr;
  140. result->category = labels[result->category_id];
  141. }
  142. bool Model::predict(const cv::Mat& im, DetResult* result) {
  143. result->clear();
  144. inputs_.clear();
  145. if (type == "classifier") {
  146. std::cerr << "Loading model is a 'classifier', ClsResult should be passed "
  147. "to function predict()!"
  148. << std::endl;
  149. return false;
  150. } else if (type == "segmenter") {
  151. std::cerr << "Loading model is a 'segmenter', SegResult should be passed "
  152. "to function predict()!"
  153. << std::endl;
  154. return false;
  155. }
  156. // 处理输入图像
  157. if (!preprocess(im, &inputs_)) {
  158. std::cerr << "Preprocess failed!" << std::endl;
  159. return false;
  160. }
  161. int h = inputs_.new_im_size_[0];
  162. int w = inputs_.new_im_size_[1];
  163. auto im_tensor = predictor_->GetInputTensor("image");
  164. im_tensor->Reshape({1, 3, h, w});
  165. im_tensor->copy_from_cpu(inputs_.im_data_.data());
  166. if (name == "YOLOv3") {
  167. auto im_size_tensor = predictor_->GetInputTensor("im_size");
  168. im_size_tensor->Reshape({1, 2});
  169. im_size_tensor->copy_from_cpu(inputs_.ori_im_size_.data());
  170. } else if (name == "FasterRCNN" || name == "MaskRCNN") {
  171. auto im_info_tensor = predictor_->GetInputTensor("im_info");
  172. auto im_shape_tensor = predictor_->GetInputTensor("im_shape");
  173. im_info_tensor->Reshape({1, 3});
  174. im_shape_tensor->Reshape({1, 3});
  175. float ori_h = static_cast<float>(inputs_.ori_im_size_[0]);
  176. float ori_w = static_cast<float>(inputs_.ori_im_size_[1]);
  177. float new_h = static_cast<float>(inputs_.new_im_size_[0]);
  178. float new_w = static_cast<float>(inputs_.new_im_size_[1]);
  179. float im_info[] = {new_h, new_w, inputs_.scale};
  180. float im_shape[] = {ori_h, ori_w, 1.0};
  181. im_info_tensor->copy_from_cpu(im_info);
  182. im_shape_tensor->copy_from_cpu(im_shape);
  183. }
  184. // 使用加载的模型进行预测
  185. predictor_->ZeroCopyRun();
  186. std::vector<float> output_box;
  187. auto output_names = predictor_->GetOutputNames();
  188. auto output_box_tensor = predictor_->GetOutputTensor(output_names[0]);
  189. std::vector<int> output_box_shape = output_box_tensor->shape();
  190. int size = 1;
  191. for (const auto& i : output_box_shape) {
  192. size *= i;
  193. }
  194. output_box.resize(size);
  195. output_box_tensor->copy_to_cpu(output_box.data());
  196. if (size < 6) {
  197. std::cerr << "[WARNING] There's no object detected." << std::endl;
  198. return true;
  199. }
  200. int num_boxes = size / 6;
  201. // 解析预测框box
  202. for (int i = 0; i < num_boxes; ++i) {
  203. Box box;
  204. box.category_id = static_cast<int>(round(output_box[i * 6]));
  205. box.category = labels[box.category_id];
  206. box.score = output_box[i * 6 + 1];
  207. float xmin = output_box[i * 6 + 2];
  208. float ymin = output_box[i * 6 + 3];
  209. float xmax = output_box[i * 6 + 4];
  210. float ymax = output_box[i * 6 + 5];
  211. float w = xmax - xmin + 1;
  212. float h = ymax - ymin + 1;
  213. box.coordinate = {xmin, ymin, w, h};
  214. result->boxes.push_back(std::move(box));
  215. }
  216. // 实例分割需解析mask
  217. if (name == "MaskRCNN") {
  218. std::vector<float> output_mask;
  219. auto output_mask_tensor = predictor_->GetOutputTensor(output_names[1]);
  220. std::vector<int> output_mask_shape = output_mask_tensor->shape();
  221. int masks_size = 1;
  222. for (const auto& i : output_mask_shape) {
  223. masks_size *= i;
  224. }
  225. int mask_pixels = output_mask_shape[2] * output_mask_shape[3];
  226. int classes = output_mask_shape[1];
  227. output_mask.resize(masks_size);
  228. output_mask_tensor->copy_to_cpu(output_mask.data());
  229. result->mask_resolution = output_mask_shape[2];
  230. for (int i = 0; i < result->boxes.size(); ++i) {
  231. Box* box = &result->boxes[i];
  232. auto begin_mask =
  233. output_mask.begin() + (i * classes + box->category_id) * mask_pixels;
  234. auto end_mask = begin_mask + mask_pixels;
  235. box->mask.data.assign(begin_mask, end_mask);
  236. box->mask.shape = {static_cast<int>(box->coordinate[2]),
  237. static_cast<int>(box->coordinate[3])};
  238. }
  239. }
  240. }
  241. bool Model::predict(const cv::Mat& im, SegResult* result) {
  242. result->clear();
  243. inputs_.clear();
  244. if (type == "classifier") {
  245. std::cerr << "Loading model is a 'classifier', ClsResult should be passed "
  246. "to function predict()!"
  247. << std::endl;
  248. return false;
  249. } else if (type == "detector") {
  250. std::cerr << "Loading model is a 'detector', DetResult should be passed to "
  251. "function predict()!"
  252. << std::endl;
  253. return false;
  254. }
  255. // 处理输入图像
  256. if (!preprocess(im, &inputs_)) {
  257. std::cerr << "Preprocess failed!" << std::endl;
  258. return false;
  259. }
  260. int h = inputs_.new_im_size_[0];
  261. int w = inputs_.new_im_size_[1];
  262. auto im_tensor = predictor_->GetInputTensor("image");
  263. im_tensor->Reshape({1, 3, h, w});
  264. im_tensor->copy_from_cpu(inputs_.im_data_.data());
  265. // 使用加载的模型进行预测
  266. predictor_->ZeroCopyRun();
  267. // 获取预测置信度,经过argmax后的labelmap
  268. auto output_names = predictor_->GetOutputNames();
  269. auto output_label_tensor = predictor_->GetOutputTensor(output_names[0]);
  270. std::vector<int> output_label_shape = output_label_tensor->shape();
  271. int size = 1;
  272. for (const auto& i : output_label_shape) {
  273. size *= i;
  274. result->label_map.shape.push_back(i);
  275. }
  276. result->label_map.data.resize(size);
  277. output_label_tensor->copy_to_cpu(result->label_map.data.data());
  278. // 获取预测置信度scoremap
  279. auto output_score_tensor = predictor_->GetOutputTensor(output_names[1]);
  280. std::vector<int> output_score_shape = output_score_tensor->shape();
  281. size = 1;
  282. for (const auto& i : output_score_shape) {
  283. size *= i;
  284. result->score_map.shape.push_back(i);
  285. }
  286. result->score_map.data.resize(size);
  287. output_score_tensor->copy_to_cpu(result->score_map.data.data());
  288. // 解析输出结果到原图大小
  289. std::vector<uint8_t> label_map(result->label_map.data.begin(),
  290. result->label_map.data.end());
  291. cv::Mat mask_label(result->label_map.shape[1],
  292. result->label_map.shape[2],
  293. CV_8UC1,
  294. label_map.data());
  295. cv::Mat mask_score(result->score_map.shape[2],
  296. result->score_map.shape[3],
  297. CV_32FC1,
  298. result->score_map.data.data());
  299. int idx = 1;
  300. int len_postprocess = inputs_.im_size_before_resize_.size();
  301. for (std::vector<std::string>::reverse_iterator iter =
  302. inputs_.reshape_order_.rbegin();
  303. iter != inputs_.reshape_order_.rend();
  304. ++iter) {
  305. if (*iter == "padding") {
  306. auto before_shape = inputs_.im_size_before_resize_[len_postprocess - idx];
  307. inputs_.im_size_before_resize_.pop_back();
  308. auto padding_w = before_shape[0];
  309. auto padding_h = before_shape[1];
  310. mask_label = mask_label(cv::Rect(0, 0, padding_w, padding_h));
  311. mask_score = mask_score(cv::Rect(0, 0, padding_w, padding_h));
  312. } else if (*iter == "resize") {
  313. auto before_shape = inputs_.im_size_before_resize_[len_postprocess - idx];
  314. inputs_.im_size_before_resize_.pop_back();
  315. auto resize_w = before_shape[0];
  316. auto resize_h = before_shape[1];
  317. cv::resize(mask_label,
  318. mask_label,
  319. cv::Size(resize_h, resize_w),
  320. 0,
  321. 0,
  322. cv::INTER_NEAREST);
  323. cv::resize(mask_score,
  324. mask_score,
  325. cv::Size(resize_h, resize_w),
  326. 0,
  327. 0,
  328. cv::INTER_NEAREST);
  329. }
  330. ++idx;
  331. }
  332. result->label_map.data.assign(mask_label.begin<uint8_t>(),
  333. mask_label.end<uint8_t>());
  334. result->label_map.shape = {mask_label.rows, mask_label.cols};
  335. result->score_map.data.assign(mask_score.begin<float>(),
  336. mask_score.end<float>());
  337. result->score_map.shape = {mask_score.rows, mask_score.cols};
  338. }
  339. } // namespce of PaddleX