deploy.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. # copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
  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. import os
  15. import os.path as osp
  16. import cv2
  17. import numpy as np
  18. import yaml
  19. import paddlex
  20. import paddle.fluid as fluid
  21. class Predictor:
  22. def __init__(self,
  23. model_dir,
  24. use_gpu=True,
  25. gpu_id=0,
  26. use_mkl=False,
  27. use_trt=False,
  28. use_glog=False,
  29. memory_optimize=True):
  30. """ 创建Paddle Predictor
  31. Args:
  32. model_dir: 模型路径(必须是导出的部署或量化模型)
  33. use_gpu: 是否使用gpu,默认True
  34. gpu_id: 使用gpu的id,默认0
  35. use_mkl: 是否使用mkldnn计算库,CPU情况下使用,默认False
  36. use_trt: 是否使用TensorRT,默认False
  37. use_glog: 是否启用glog日志, 默认False
  38. memory_optimize: 是否启动内存优化,默认True
  39. """
  40. if not osp.isdir(model_dir):
  41. raise Exception("[ERROR] Path {} not exist.".format(model_dir))
  42. if not osp.exists(osp.join(model_dir, "model.yml")):
  43. raise Exception("There's not model.yml in {}".format(model_dir))
  44. with open(osp.join(model_dir, "model.yml")) as f:
  45. self.info = yaml.load(f.read(), Loader=yaml.Loader)
  46. self.status = self.info['status']
  47. if self.status != "Quant" and self.status != "Infer":
  48. raise Exception("[ERROR] Only quantized model or exported "
  49. "inference model is supported.")
  50. self.model_dir = model_dir
  51. self.model_type = self.info['_Attributes']['model_type']
  52. self.model_name = self.info['Model']
  53. self.num_classes = self.info['_Attributes']['num_classes']
  54. self.labels = self.info['_Attributes']['labels']
  55. if self.info['Model'] == 'MaskRCNN':
  56. if self.info['_init_params']['with_fpn']:
  57. self.mask_head_resolution = 28
  58. else:
  59. self.mask_head_resolution = 14
  60. transforms_mode = self.info.get('TransformsMode', 'RGB')
  61. if transforms_mode == 'RGB':
  62. to_rgb = True
  63. else:
  64. to_rgb = False
  65. self.transforms = self.build_transforms(self.info['Transforms'],
  66. to_rgb)
  67. self.predictor = self.create_predictor(
  68. use_gpu, gpu_id, use_mkl, use_trt, use_glog, memory_optimize)
  69. def create_predictor(self,
  70. use_gpu=True,
  71. gpu_id=0,
  72. use_mkl=False,
  73. use_trt=False,
  74. use_glog=False,
  75. memory_optimize=True):
  76. config = fluid.core.AnalysisConfig(
  77. os.path.join(self.model_dir, '__model__'),
  78. os.path.join(self.model_dir, '__params__'))
  79. if use_gpu:
  80. # 设置GPU初始显存(单位M)和Device ID
  81. config.enable_use_gpu(100, gpu_id)
  82. else:
  83. config.disable_gpu()
  84. if use_mkl:
  85. config.enable_mkldnn()
  86. if use_glog:
  87. config.enable_glog_info()
  88. else:
  89. config.disable_glog_info()
  90. if memory_optimize:
  91. config.enable_memory_optim()
  92. else:
  93. config.diable_memory_optim()
  94. # 开启计算图分析优化,包括OP融合等
  95. config.switch_ir_optim(True)
  96. # 关闭feed和fetch OP使用,使用ZeroCopy接口必须设置此项
  97. config.switch_use_feed_fetch_ops(False)
  98. predictor = fluid.core.create_paddle_predictor(config)
  99. return predictor
  100. def build_transforms(self, transforms_info, to_rgb=True):
  101. if self.model_type == "classifier":
  102. from paddlex.cls import transforms
  103. elif self.model_type == "detector":
  104. from paddlex.det import transforms
  105. elif self.model_type == "segmenter":
  106. from paddlex.seg import transforms
  107. op_list = list()
  108. for op_info in transforms_info:
  109. op_name = list(op_info.keys())[0]
  110. op_attr = op_info[op_name]
  111. if not hasattr(transforms, op_name):
  112. raise Exception(
  113. "There's no operator named '{}' in transforms of {}".
  114. format(op_name, self.model_type))
  115. op_list.append(getattr(transforms, op_name)(**op_attr))
  116. eval_transforms = transforms.Compose(op_list)
  117. if hasattr(eval_transforms, 'to_rgb'):
  118. eval_transforms.to_rgb = to_rgb
  119. self.arrange_transforms(eval_transforms)
  120. return eval_transforms
  121. def arrange_transforms(self, transforms):
  122. if self.model_type == 'classifier':
  123. arrange_transform = paddlex.cls.transforms.ArrangeClassifier
  124. elif self.model_type == 'segmenter':
  125. arrange_transform = paddlex.seg.transforms.ArrangeSegmenter
  126. elif self.model_type == 'detector':
  127. arrange_name = 'Arrange{}'.format(self.model_name)
  128. arrange_transform = getattr(paddlex.det.transforms, arrange_name)
  129. else:
  130. raise Exception("Unrecognized model type: {}".format(
  131. self.model_type))
  132. if type(transforms.transforms[-1]).__name__.startswith('Arrange'):
  133. transforms.transforms[-1] = arrange_transform(mode='test')
  134. else:
  135. transforms.transforms.append(arrange_transform(mode='test'))
  136. def preprocess(self, image):
  137. """ 对图像做预处理
  138. Args:
  139. image(str|np.ndarray): 图片路径或np.ndarray,如为后者,要求是BGR格式
  140. """
  141. res = dict()
  142. if self.model_type == "classifier":
  143. im, = self.transforms(image)
  144. im = np.expand_dims(im, axis=0).copy()
  145. res['image'] = im
  146. elif self.model_type == "detector":
  147. if self.model_name == "YOLOv3":
  148. im, im_shape = self.transforms(image)
  149. im = np.expand_dims(im, axis=0).copy()
  150. im_shape = np.expand_dims(im_shape, axis=0).copy()
  151. res['image'] = im
  152. res['im_size'] = im_shape
  153. if self.model_name.count('RCNN') > 0:
  154. im, im_resize_info, im_shape = self.transforms(image)
  155. im = np.expand_dims(im, axis=0).copy()
  156. im_resize_info = np.expand_dims(im_resize_info, axis=0).copy()
  157. im_shape = np.expand_dims(im_shape, axis=0).copy()
  158. res['image'] = im
  159. res['im_info'] = im_resize_info
  160. res['im_shape'] = im_shape
  161. elif self.model_type == "segmenter":
  162. im, im_info = self.transforms(image)
  163. im = np.expand_dims(im, axis=0).copy()
  164. res['image'] = im
  165. res['im_info'] = im_info
  166. return res
  167. def raw_predict(self, inputs):
  168. """ 接受预处理过后的数据进行预测
  169. Args:
  170. inputs(tuple): 预处理过后的数据
  171. """
  172. for k, v in inputs.items():
  173. try:
  174. tensor = self.predictor.get_input_tensor(k)
  175. except:
  176. continue
  177. tensor.copy_from_cpu(v)
  178. self.predictor.zero_copy_run()
  179. output_names = self.predictor.get_output_names()
  180. output_results = list()
  181. for name in output_names:
  182. output_tensor = self.predictor.get_output_tensor(name)
  183. output_results.append(output_tensor.copy_to_cpu())
  184. return output_results
  185. def classifier_postprocess(self, preds, topk=1):
  186. """ 对分类模型的预测结果做后处理
  187. """
  188. true_topk = min(self.num_classes, topk)
  189. pred_label = np.argsort(preds[0][0])[::-1][:true_topk]
  190. result = [{
  191. 'category_id': l,
  192. 'category': self.labels[l],
  193. 'score': preds[0][0, l],
  194. } for l in pred_label]
  195. return result
  196. def segmenter_postprocess(self, preds, preprocessed_inputs):
  197. """ 对语义分割结果做后处理
  198. """
  199. label_map = np.squeeze(preds[0]).astype('uint8')
  200. score_map = np.squeeze(preds[1])
  201. score_map = np.transpose(score_map, (1, 2, 0))
  202. im_info = preprocessed_inputs['im_info']
  203. for info in im_info[::-1]:
  204. if info[0] == 'resize':
  205. w, h = info[1][1], info[1][0]
  206. label_map = cv2.resize(label_map, (w, h), cv2.INTER_NEAREST)
  207. score_map = cv2.resize(score_map, (w, h), cv2.INTER_LINEAR)
  208. elif info[0] == 'padding':
  209. w, h = info[1][1], info[1][0]
  210. label_map = label_map[0:h, 0:w]
  211. score_map = score_map[0:h, 0:w, :]
  212. else:
  213. raise Exception("Unexpected info '{}' in im_info".format(info[
  214. 0]))
  215. return {'label_map': label_map, 'score_map': score_map}
  216. def detector_postprocess(self, preds, preprocessed_inputs):
  217. """ 对目标检测和实例分割结果做后处理
  218. """
  219. bboxes = {'bbox': (np.array(preds[0]), [[len(preds[0])]])}
  220. bboxes['im_id'] = (np.array([[0]]).astype('int32'), [])
  221. clsid2catid = dict({i: i for i in range(self.num_classes)})
  222. xywh_results = paddlex.cv.models.utils.detection_eval.bbox2out(
  223. [bboxes], clsid2catid)
  224. results = list()
  225. for xywh_res in xywh_results:
  226. del xywh_res['image_id']
  227. xywh_res['category'] = self.labels[xywh_res['category_id']]
  228. results.append(xywh_res)
  229. if len(preds) > 1:
  230. im_shape = preprocessed_inputs['im_shape']
  231. bboxes['im_shape'] = (im_shape, [])
  232. bboxes['mask'] = (np.array(preds[1]), [[len(preds[1])]])
  233. segm_results = paddlex.cv.models.utils.detection_eval.mask2out(
  234. [bboxes], clsid2catid, self.mask_head_resolution)
  235. import pycocotools.mask as mask_util
  236. for i in range(len(results)):
  237. results[i]['mask'] = mask_util.decode(segm_results[i][
  238. 'segmentation'])
  239. return results
  240. def predict(self, image, topk=1, threshold=0.5):
  241. """ 图片预测
  242. Args:
  243. image(str|np.ndarray): 图片路径或np.ndarray格式,如果后者,要求为BGR输入格式
  244. topk(int): 分类预测时使用,表示预测前topk的结果
  245. """
  246. preprocessed_input = self.preprocess(image)
  247. model_pred = self.raw_predict(preprocessed_input)
  248. if self.model_type == "classifier":
  249. results = self.classifier_postprocess(model_pred, topk)
  250. elif self.model_type == "detector":
  251. results = self.detector_postprocess(model_pred, preprocessed_input)
  252. elif self.model_type == "segmenter":
  253. results = self.segmenter_postprocess(model_pred,
  254. preprocessed_input)
  255. return results