postprocessor.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright (c) 2022 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 "ultra_infer/vision/segmentation/ppseg/postprocessor.h"
  15. #include "ultra_infer/function/cast.h"
  16. #include "yaml-cpp/yaml.h"
  17. namespace ultra_infer {
  18. namespace vision {
  19. namespace segmentation {
  20. PaddleSegPostprocessor::PaddleSegPostprocessor(const std::string &config_file) {
  21. FDASSERT(ReadFromConfig(config_file),
  22. "Failed to create PaddleSegPreprocessor.");
  23. initialized_ = true;
  24. }
  25. bool PaddleSegPostprocessor::ReadFromConfig(const std::string &config_file) {
  26. YAML::Node cfg;
  27. try {
  28. cfg = YAML::LoadFile(config_file);
  29. } catch (YAML::BadFile &e) {
  30. FDERROR << "Failed to load yaml file " << config_file
  31. << ", maybe you should check this file." << std::endl;
  32. return false;
  33. }
  34. if (cfg["Deploy"]["output_op"]) {
  35. std::string output_op = cfg["Deploy"]["output_op"].as<std::string>();
  36. if (output_op == "softmax") {
  37. is_with_softmax_ = true;
  38. is_with_argmax_ = false;
  39. } else if (output_op == "argmax") {
  40. is_with_softmax_ = false;
  41. is_with_argmax_ = true;
  42. } else if (output_op == "none") {
  43. is_with_softmax_ = false;
  44. is_with_argmax_ = false;
  45. } else {
  46. FDERROR << "Unexcepted output_op operator in deploy.yml: " << output_op
  47. << "." << std::endl;
  48. return false;
  49. }
  50. }
  51. return true;
  52. }
  53. bool PaddleSegPostprocessor::SliceOneResultFromBatchInferResults(
  54. const FDTensor &infer_results, FDTensor *infer_result,
  55. const std::vector<int64_t> &infer_result_shape, const int64_t &start_idx) {
  56. int64_t infer_batch = infer_results.shape[0];
  57. if (infer_batch == 1) {
  58. *infer_result = infer_results;
  59. // batch is 1, so ignore
  60. infer_result->shape = infer_result_shape;
  61. } else {
  62. if (infer_results.dtype == FDDataType::FP32) {
  63. const float_t *infer_results_ptr =
  64. reinterpret_cast<const float_t *>(infer_results.CpuData()) +
  65. start_idx;
  66. infer_result->SetExternalData(
  67. infer_result_shape, FDDataType::FP32,
  68. reinterpret_cast<void *>(const_cast<float_t *>(infer_results_ptr)));
  69. } else if (infer_results.dtype == FDDataType::INT64) {
  70. const int64_t *infer_results_ptr =
  71. reinterpret_cast<const int64_t *>(infer_results.CpuData()) +
  72. start_idx;
  73. infer_result->SetExternalData(
  74. infer_result_shape, FDDataType::INT64,
  75. reinterpret_cast<void *>(const_cast<int64_t *>(infer_results_ptr)));
  76. } else if (infer_results.dtype == FDDataType::INT32) {
  77. const int32_t *infer_results_ptr =
  78. reinterpret_cast<const int32_t *>(infer_results.CpuData()) +
  79. start_idx;
  80. infer_result->SetExternalData(
  81. infer_result_shape, FDDataType::INT32,
  82. reinterpret_cast<void *>(const_cast<int32_t *>(infer_results_ptr)));
  83. } else if (infer_results.dtype == FDDataType::UINT8) {
  84. const uint8_t *infer_results_ptr =
  85. reinterpret_cast<const uint8_t *>(infer_results.CpuData()) +
  86. start_idx;
  87. infer_result->SetExternalData(
  88. infer_result_shape, FDDataType::UINT8,
  89. reinterpret_cast<void *>(const_cast<uint8_t *>(infer_results_ptr)));
  90. } else {
  91. FDASSERT(
  92. false,
  93. "Require the data type for slicing is int64, fp32 or int32, but now "
  94. "it's %s.",
  95. Str(infer_results.dtype).c_str())
  96. return false;
  97. }
  98. }
  99. return true;
  100. }
  101. bool PaddleSegPostprocessor::ProcessWithScoreResult(
  102. const FDTensor &infer_result, const int64_t &out_num,
  103. SegmentationResult *result) {
  104. const uint8_t *argmax_infer_result_buffer = nullptr;
  105. const float_t *score_infer_result_buffer = nullptr;
  106. FDTensor argmax_infer_result;
  107. FDTensor max_score_result;
  108. std::vector<int64_t> reduce_dim{-1};
  109. function::ArgMax(infer_result, &argmax_infer_result, -1, FDDataType::UINT8);
  110. function::Max(infer_result, &max_score_result, reduce_dim);
  111. score_infer_result_buffer =
  112. reinterpret_cast<const float_t *>(max_score_result.CpuData());
  113. std::memcpy(result->score_map.data(), score_infer_result_buffer,
  114. out_num * sizeof(float_t));
  115. argmax_infer_result_buffer =
  116. reinterpret_cast<const uint8_t *>(argmax_infer_result.CpuData());
  117. std::memcpy(result->label_map.data(), argmax_infer_result_buffer,
  118. out_num * sizeof(uint8_t));
  119. return true;
  120. }
  121. bool PaddleSegPostprocessor::ProcessWithLabelResult(
  122. const FDTensor &infer_result, const int64_t &out_num,
  123. SegmentationResult *result) {
  124. if (infer_result.dtype == FDDataType::INT64) {
  125. const int64_t *infer_result_buffer =
  126. reinterpret_cast<const int64_t *>(infer_result.CpuData());
  127. for (int i = 0; i < out_num; i++) {
  128. result->label_map[i] = static_cast<uint8_t>(*(infer_result_buffer + i));
  129. }
  130. } else if (infer_result.dtype == FDDataType::INT32) {
  131. const int32_t *infer_result_buffer =
  132. reinterpret_cast<const int32_t *>(infer_result.CpuData());
  133. for (int i = 0; i < out_num; i++) {
  134. result->label_map[i] = static_cast<uint8_t>(*(infer_result_buffer + i));
  135. }
  136. } else if (infer_result.dtype == FDDataType::UINT8) {
  137. const uint8_t *infer_result_buffer =
  138. reinterpret_cast<const uint8_t *>(infer_result.CpuData());
  139. memcpy(result->label_map.data(), infer_result_buffer,
  140. out_num * sizeof(uint8_t));
  141. } else {
  142. FDASSERT(
  143. false,
  144. "Require the data type to process is int64, int32 or uint8, but now "
  145. "it's %s.",
  146. Str(infer_result.dtype).c_str());
  147. return false;
  148. }
  149. return true;
  150. }
  151. bool PaddleSegPostprocessor::Run(
  152. const std::vector<FDTensor> &infer_results,
  153. std::vector<SegmentationResult> *results,
  154. const std::map<std::string, std::vector<std::array<int, 2>>> &imgs_info) {
  155. // PaddleSeg has three types of inference output:
  156. // 1. output with argmax and without softmax. 3-D matrix N(C)HW, Channel
  157. // is batch_size, the element in matrix is classified label_id INT64 type.
  158. // 2. output without argmax and without softmax. 4-D matrix NCHW, N(batch)
  159. // is batch_size, Channel is the num of classes. The element is the logits
  160. // of classes FP32 type
  161. // 3. output without argmax and with softmax. 4-D matrix NCHW, the result
  162. // of 2 with softmax layer
  163. // Xdeploy output:
  164. // 1. label_map
  165. // 2. score_map(optional)
  166. // 3. shape: 2-D HW
  167. if (!initialized_) {
  168. FDERROR << "Postprocessor is not initialized." << std::endl;
  169. return false;
  170. }
  171. FDDataType infer_results_dtype = infer_results[0].dtype;
  172. FDASSERT(infer_results_dtype == FDDataType::INT64 ||
  173. infer_results_dtype == FDDataType::FP32 ||
  174. infer_results_dtype == FDDataType::INT32,
  175. "Require the data type of output is int64, fp32 or int32, but now "
  176. "it's %s.",
  177. Str(infer_results_dtype).c_str());
  178. auto iter_input_imgs_shape_list = imgs_info.find("shape_info");
  179. FDASSERT(iter_input_imgs_shape_list != imgs_info.end(),
  180. "Cannot find shape_info from imgs_info.");
  181. // For Argmax Softmax function to store transformed result below
  182. FDTensor transform_infer_results;
  183. int64_t infer_batch = infer_results[0].shape[0];
  184. int64_t infer_channel = 0;
  185. int64_t infer_height = 0;
  186. int64_t infer_width = 0;
  187. if (is_with_argmax_) {
  188. // infer_results with argmax
  189. infer_channel = 1;
  190. infer_height = infer_results[0].shape[1];
  191. infer_width = infer_results[0].shape[2];
  192. } else {
  193. // infer_results without argmax
  194. infer_channel = 1;
  195. infer_height = infer_results[0].shape[2];
  196. infer_width = infer_results[0].shape[3];
  197. if (store_score_map_) {
  198. infer_channel = infer_results[0].shape[1];
  199. std::vector<int64_t> dim{0, 2, 3, 1};
  200. function::Transpose(infer_results[0], &transform_infer_results, dim);
  201. if (!is_with_softmax_ && apply_softmax_) {
  202. function::Softmax(transform_infer_results, &transform_infer_results, 1);
  203. }
  204. } else {
  205. function::ArgMax(infer_results[0], &transform_infer_results, 1,
  206. FDDataType::UINT8);
  207. infer_results_dtype = transform_infer_results.dtype;
  208. }
  209. }
  210. int64_t infer_chw = infer_channel * infer_height * infer_width;
  211. results->resize(infer_batch);
  212. for (int i = 0; i < infer_batch; i++) {
  213. SegmentationResult *result = &((*results)[i]);
  214. result->Clear();
  215. int64_t start_idx = i * infer_chw;
  216. FDTensor infer_result;
  217. std::vector<int64_t> infer_result_shape = {infer_height, infer_width,
  218. infer_channel};
  219. if (is_with_argmax_) {
  220. SliceOneResultFromBatchInferResults(infer_results[0], &infer_result,
  221. infer_result_shape, start_idx);
  222. } else {
  223. SliceOneResultFromBatchInferResults(transform_infer_results,
  224. &infer_result, infer_result_shape,
  225. start_idx);
  226. }
  227. bool is_resized = false;
  228. int input_height = iter_input_imgs_shape_list->second[i][0];
  229. int input_width = iter_input_imgs_shape_list->second[i][1];
  230. if (input_height != infer_height || input_width != infer_width) {
  231. is_resized = true;
  232. }
  233. FDMat mat;
  234. // Resize interpration
  235. int interpolation = cv::INTER_LINEAR;
  236. if (is_resized) {
  237. if (infer_results_dtype == FDDataType::INT64 ||
  238. infer_results_dtype == FDDataType::INT32) {
  239. function::Cast(infer_result, &infer_result, FDDataType::UINT8);
  240. // label map resize with nearest interpolation
  241. interpolation = cv::INTER_NEAREST;
  242. }
  243. mat = std::move(Mat::Create(infer_result, ProcLib::OPENCV));
  244. Resize::Run(&mat, input_width, input_height, -1.0f, -1.0f, interpolation,
  245. false, ProcLib::OPENCV);
  246. mat.ShareWithTensor(&infer_result);
  247. }
  248. result->shape = infer_result.shape;
  249. // output shape is 2-D HW layout, so out_num = H * W
  250. int out_num =
  251. std::accumulate(result->shape.begin(), result->shape.begin() + 2, 1,
  252. std::multiplies<int>());
  253. if (!is_with_argmax_ && store_score_map_) {
  254. // output with label_map and score_map
  255. result->contain_score_map = true;
  256. result->Resize(out_num);
  257. ProcessWithScoreResult(infer_result, out_num, result);
  258. } else {
  259. result->Resize(out_num);
  260. ProcessWithLabelResult(infer_result, out_num, result);
  261. }
  262. // HWC remove C
  263. result->shape.erase(result->shape.begin() + 2);
  264. }
  265. return true;
  266. }
  267. } // namespace segmentation
  268. } // namespace vision
  269. } // namespace ultra_infer