1、准备预测模型
这里直接使用paddlex --export_inference 导出的模型。模型文件内容如图
2、导入相关库
from paddle.inference import Config # AnalysisConfig的相关设置
from paddle.inference import create_predictor # 创建PaddlePredictor
# 其他的一些辅助库
import cv2
import numpy as np
import yaml
import time
import datetime
3、设置Config,创建predictor
# 根据预测部署的实际情况,设置Config
config = Config()
# 读取模型文件
config.set_prog_file(model_file)
config.set_params_file(params_file)
# Config默认是使用CPU预测,若要使用GPU预测,需要手动开启,设置运行的GPU卡号和分配的初始显存。
config.enable_use_gpu(300, 0)
# 可以设置开启IR优化、开启内存优化。
config.switch_ir_optim()
config.enable_memory_optim()
# 由于不使用tensorrt,注释相应配置
predictor = create_predictor(config)
4、设置输入
从Predictor中获取输入的names和handle,然后设置输入数据。这里Inference官方给的linux例子,不知道什么原因运行不起来,个人觉得可能是官方例子中用的模型可能对输入的要求与我这个训练的ppyolotiny模型不一样。经过半天的调试和各种查资料,ppyolotiny训练的inferenc模型,输入这块需要进行如下的操作。具体看代码
im_size = 608
# 被预测图片
img = cv2.imread('testplane/660.jpg')
# 对预测图片进行resize和归一化处理。
data = preprocess(img, im_size)
# x、y轴缩放比例
scale_factor = np.array([im_size * 1. / img.shape[0], im_size * 1. / img.shape[1]]).reshape((1, 2)).astype(
np.float32)
# ???
im_shape = np.array([im_size, im_size]).reshape((1, 2)).astype(np.float32)
# 这个是predictor.get_input_names()返回的数组,需要将这三个值传进入,才能正常执行predictor.run(),没查到对应的API.....
ims = [im_shape, data, scale_factor]
input_names = predictor.get_input_names()
for i, name in enumerate(input_names):
input_tensor = predictor.get_input_handle(name)
input_tensor.reshape(imgs[i].shape)
input_tensor.copy_from_cpu(imgs[i].copy())
5、执行预测并输出
# 执行Predictor
predictor.run()
# 获取输出
results = []
# 获取输出
output_names = predictor.get_output_names()
for i, name in enumerate(output_names):
output_tensor = predictor.get_output_handle(name)
output_data = output_tensor.copy_to_cpu()
results.append(output_data)
完整的代码如下:
import numpy as np
import cv2
from paddle.inference import Config
from paddle.inference import create_predictor
import yaml
def resize(img, target_size):
if not isinstance(img, np.ndarray):
raise TypeError('image type is not numpy.')
im_shape = img.shape
im_scale_x = float(target_size) / float(im_shape[1])
im_scale_y = float(target_size) / float(im_shape[0])
img = cv2.resize(img, None, None, fx=im_scale_x, fy=im_scale_y)
return img
def normalize(img, mean, std):
img = img / 255.0
mean = np.array(mean)[np.newaxis, np.newaxis, :]
std = np.array(std)[np.newaxis, np.newaxis, :]
img -= mean
img /= std
return img
# 图像预处理
def preprocess(img, img_size):
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
img = resize(img, img_size)
img = img[:, :, ::-1].astype('float32') # bgr -> rgb
img = normalize(img, mean, std)
img = img.transpose((2, 0, 1)) # hwc -> chw
return img[np.newaxis, :] # ??? 为什么要增加维度?
# ——————————————————————后处理函数—————————————————————————— #
def draw_bbox_image(frame, result, label_list, threshold=0.5):
for res in result:
cat_id, score, bbox = res[0], res[1], res[2:]
if score < threshold:
continue
for i in bbox:
int(i)
xmin, ymin, xmax, ymax = [int(pts) for pts in bbox]
cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (255, 0, 255), 2)
print('category id is {}, bbox is {}'.format(cat_id, bbox))
try:
label_id = label_list[int(cat_id)]
# #cv2.putText(图像, 文字, (x, y), 字体, 大小, (b, g, r), 宽度)
cv2.putText(frame, label_id, (int(xmin + 50), int(ymin - 2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
cv2.putText(frame, str(round(score, 2)), (int(xmin), int(ymin - 2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(0, 255, 0), 2)
except KeyError:
pass
if __name__ == '__main__':
# 加载inference模型文件
config = Config('inference_model/ppyolotiny/model.pdmodel','inference_model/ppyolotiny/model.pdiparams')
config.enable_use_gpu(500, 0)
config.switch_ir_optim()
config.enable_memory_optim()
# 加载yml文件,获取label_list,用于根据label_id获取label名称
infer_cfg = open('inference_model/ppyolotiny/model.yml')
data = infer_cfg.read()
yaml_reader = yaml.load(data)
label_list = yaml_reader['_Attributes']["labels"]
print(label_list)
# Create predictor
predictor = create_predictor(config)
# Set input
img = cv2.imread('testplane/660.jpg')
im_size = 608
data = preprocess(img, im_size)
scale_factor = np.array([im_size * 1. / img.shape[0], im_size * 1. / img.shape[1]]).reshape((1, 2)).astype(
np.float32)
im_shape = np.array([im_size, im_size]).reshape((1, 2)).astype(np.float32)
ims = [im_shape, data, scale_factor]
input_names = predictor.get_input_names()
for i, name in enumerate(input_names):
input_tensor = predictor.get_input_handle(name)
input_tensor.reshape(ims[i].shape)
input_tensor.copy_from_cpu(ims[i].copy())
# 执行Predictor
predictor.run()
# 获取输出
results = []
# 获取输出
output_names = predictor.get_output_names()
for i, name in enumerate(output_names):
output_tensor = predictor.get_output_handle(name)
output_data = output_tensor.copy_to_cpu()
results.append(output_data)
draw_bbox_image(img, results[0], label_list, threshold=0.5)
cv2.imshow("frame", img)
cv2.waitKey()
总结一下过程中遇到的问题:
1)、在pycharm的工程中引入from paddle.inference import create_predictor,create_predictor会显示红下划线,可以忽略。
2)、如果不显示标签的名称,yml文件实际是可以不引入的。
3)、不知道是不是paddlex的版本问题,如果在config中直接配置model_dir,是不行的。
4)、如果没用安装tensorrt,config中的tensorrt必须注释掉。
5)、设置输入时,建议调试模式看看input_names = predictor.get_input_names()中,input_names到底是什么,我花了半天时间都是在解决这个输入的问题,尽管最终还是没搞清楚,希望有大佬解释一下,或者给个api地址我学习一下,不胜感激。
6)还是关于输入ims = [im_shape, data, scale_factor],这里面的im_shape为什么w和h是一样的?data是预处理后的图片,已经进行了缩放,为什么还要给scale_factor,有什么用?
7)、输出的results中,是多个预测框吗?看调试好像有其他的数据。
希望官方大佬和各位达人给点指导,先感谢了!!!
写的很好,感谢贡献
大佬啊,帮忙回复一下最后面的问题啊?求解答
> 3)不知道是不是paddlex的版本问题,如果在config中直接配置model_dir,是不行的。
A: 这个与paddlex的版本没有关系哈,是推理引擎的接口是这样子设计的
> 5)、设置输入时,建议调试模式看看input_names = predictor.get_input_names()中,input_names到底是什么,我花了半天时间都是在解决这个输入的问题,尽管最终还是没搞清楚,希望有大佬解释一下,或者给个api地址我学习一下,不胜感激。
A: input_names是在test/infer阶段网络所需的输入tensort的名字,这个可以看下导出之前的组网代码 https://github.com/PaddlePaddle/PaddleX/blob/develop/paddlex/cv/models/detector.py#L63-L74
> 6)还是关于输入ims = [im_shape, data, scale_factor],这里面的im_shape为什么w和h是一样的?data是预处理后的图片,已经进行了缩放,为什么还要给scale_factor,有什么用?
im_shape定义的是缩放后的w和h,因为YOLO系列要求输入的w和h是相同大小,所以这里的w和h是一样的
scale_factor用于在模型的后处理阶段将预测结果还原成相对原始图片大小
7)、输出的results中,是多个预测框吗?看调试好像有其他的数据。
返回值可参考导出前的predict API文档说明 https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/apis/models/detection.md#predict 和相应的解析操作 https://github.com/PaddlePaddle/PaddleX/blob/develop/paddlex/cv/models/detector.py#L498
感谢大佬的回复!!!
我记录一下,以防看的时候github不能访问
input_names对应代码:
predict说明:
predict结果后处理函数
嗯嗯,python deploy我们正在开发适配中
请教一下,这步部署好之后,下一步要怎么引用呢,训练好的检测和识别模型是不是需要分别部署呢?
不太明白你的意思,部署好了,就是直接使用了,就是你如何给输入和处理输出的问题了,另外关于识别和检测模型是否要分别部署,这个我也搞不懂,具体你可以看看paddlex里的工业仪表识别示例,它是采用两个模型串联部署的
输出的results中,是多个预测框吗?看调试好像有其他的数据。
这个应该是置信度问题,弄的低,就识别多。。。。框多。。。。。。。。。。。。
你知道有什么方法让这个框少一点吗?除了使用调高置信度的方法,因为没必要在一些极低的框上浪费计算时间,有人说要调训练时候的nms中的什么参数
我也是这个卡了好几天,打印了get信息知道输入有这三个元素,但是苦于压根没有输入的格式说明,害得我又用paddledetertion又训练了一个模型,部署还是同样的问题。十分感谢!
优秀
这种部署主要是预处理和后处理很麻烦,中间的模型推理到时是一个固定的范式。
楼主的第四步在哪里查阅的资料?就是4、设置输入这个处理。可否给个参考,使用Faster-Rcnn模型时输入还是有问题,报错。
第四步是针对yolo系列的,fasterrcnn的查看paddle官方的inference开源项目源码
你好,为什么我直接使用paddlex --export_inference 导出的模型内并没有model.pdmodel和model.pdiparams文件,仅仅只有__model__、__params__和model.yml三个文件,还望答疑
太感谢你的代码了,要改动的地方只有1个就是输入时把data和img_shape互换位置,在输入这个问题卡了几天了,现在很激动