
基于OpenVINO部署PP-YOLOE
使用OpenVINO模型部署工具部署使用飞桨YOLOE模型
★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>
PP-YOLOE
目标检测作为计算机视觉领域的顶梁柱,不仅可以独立完成车辆、商品、缺陷检测等任务,也是人脸识别、视频分析、以图搜图等复合技术的核心模块,在自动驾驶、工业视觉、安防交通等领域的商业价值有目共睹。
PaddleDetection为基于飞桨PaddlePaddle的端到端目标检测套件,内置30+模型算法及250+预训练模型,覆盖目标检测、实例分割、跟踪、关键点检测等方向,其中包括服务器端和移动端高精度、轻量级产业级SOTA模型、冠军方案和学术前沿算法,并提供配置化的网络模块组件、十余种数据增强策略和损失函数等高阶优化支持和多种部署方案,在打通数据处理、模型开发、训练、压缩、部署全流程的基础上,提供丰富的案例及教程,加速算法产业落地应用。
PP-YOLOE 是PaddleDetection推出的一种高精度SOTA目标检测模型,基于PP-YOLOv2的卓越的单阶段Anchor-free模型,超越了多种流行的YOLO模型。
- 尺寸多样:PP-YOLOE根据不同应用场景设计了s/m/l/x,4个尺寸的模型来支持不同算力水平的硬件,无论是哪个尺寸,精度-速度的平衡都超越当前所有同等计算量下的YOLO模型!可以通过width multiplier和depth multiplier配置。
- 性能卓越:具体来说,PP-YOLOE-l在COCO test-dev上以精度51.4%,TRT FP16推理速度149 FPS的优异数据,相较YOLOX,精度提升1.3%,加速25%;相较YOLOv5,精度提升0.7%,加速26.8%。训练速度较PP-YOLOv2提高33%,降低模型训练成本。
- 部署友好:与此同时,PP-YOLOE在结构设计上避免使用如deformable convolution或者matrix NMS之类的特殊算子,使其能轻松适配更多硬件。当前已经完备支持NVIDIA V100、T4这样的云端GPU架构以及如Jetson系列等边缘端GPU和FPGA开发板。
OpenVINOTM
OpenVINOTM是英特尔基于自身现有的硬件平台开发的一种可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,用于快速开发应用程序和解决方案,以解决各种任务(包括人类视觉模拟、自动语音识别、自然语言处理和推荐系统等)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqbyKIYn-1681820775519)(/home/aistudio/image/image-20221012150224745.png)]
该工具套件基于最新一代的人工神经网络,包括卷积神经网络 (CNN)、递归网络和基于注意力的网络,可扩展跨英特尔® 硬件的计算机视觉和非视觉工作负载,从而最大限度地提高性能。它通过从边缘到云部署的高性能、人工智能和深度学习推理来为应用程序加速,并且允许直接异构执行。极大的提高计算机视觉、自动语音识别、自然语言处理和其他常见任务中的深度学习性能;使用使用流行的框架(如TensorFlow,PyTorch等)训练的模型;减少资源需求,并在从边缘到云的一系列英特尔®平台上高效部署;支持在Windows与Linux系统,且官方支持编程语言为Python与C++语言。
OpenVINOTM工具套件2022.1版于2022年3月22日正式发布,与以往版本相比发生了重大革新,提供预处理API函数、ONNX前端API、AUTO 设备插件,并且支持直接读入飞桨模型,在推理中中支持动态改变模型的形状,这极大地推动了不同网络的应用落地。2022年9月23日,OpenVINOTM 工具套件2022.2版推出,对2022.1进行了微调,以包括对英特尔最新 CPU 和离散 GPU 的支持,以实现更多的人工智能创新和机会。
1.配置OpenVINO运行环境
此处需要安装OpenVINOTM2022.3版本,python环境可以通过pipi安装,运行下面指令进行安装。
# 更新pip
!python -m pip install --upgrade pip
# 安装OpenVINO
!pip install openvino-dev[ONNX]==2022.3.0
# 验证安装是否成功,如果成功,无任何输出
!python -c "from openvino.runtime import Core"
2.获取PP-YOLOE模型
2.1 安装 PaddleDetection
# 下载PaddleDetection
!git clone https://github.com/PaddlePaddle/PaddleDetection.git
# 安装其他依赖
%cd PaddleDetection/
!pip install -r requirements.txt --user
# 编译安装paddledet
!python setup.py install
2.2 导出官方训练的模型
首先下载PP-YOLOE官方训练模型,该模型由PaddleDetection提供,基于COCO数据集训练,可以识别80种常见物体。此处采用的是PaddleDetection release/2.5版本,PP-YOLOE+模型,具体可以参考官方文件PP-YOLOE。
使用命令,导出我们要使用的模型,在命令行种依次输入以下指令,导出我们所使用的模型文件:
# 导出模型
# 如果使用的paddlepaddle为cpu版本,请将/home/aistudio/PaddleDetection/configs/runtime.yml文件中的use_gpu改为false
!python /home/aistudio/PaddleDetection/tools/export_model.py -c /home/aistudio/PaddleDetection/configs/ppyoloe/ppyoloe_plus_crn_l_80e_coco.yml -o weights=https://paddledet.bj.bcebos.com/models/ppyoloe_plus_crn_l_80e_coco.pdparams trt=False --output_dir /home/aistudio/model
2.3 模型裁剪
直接导出的模型在OpenVINO中无法直接使用,需要对模型进行裁剪,将模型后处理过程去掉,使用下面大神的提供的工具可以直接实现对Paddle模型直接裁剪:jiangjiajun/PaddleUtils: Some tools to operate PaddlePaddle model 。
%cd /home/aistudio
!git clone https://github.com/jiangjiajun/PaddleUtils.git
指令说明:
标志位 | 说明 | 输入 |
---|---|---|
–model_dir | 模型文件路径 | ppyoloe_plus_crn_l_80e_coco |
–model_filename | 静态图模型文件 | model.pdmodel |
–params_filename | 模型配置文件信息 | model.pdiparams |
–output_names | 输出节点名 | tmp_16 concat_14.tmp_0 |
–save_dir | 模型保存路径 | export_model |
此处主要关注输出节点名这一项输入,由于原模型输入包含后处理这一部分,在模型部署时会出错,所以模型裁剪的主要目的就是将模型后处理这一步去掉,因此将模型输出设置为后处理开始前的模型节点,此处主要存在两个节点:
第一个节点包含模型预测的置信度输出参数,其位置如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qTP69FnS-1681820775521)(/home/aistudio/image/image-20221004002756096.png)]
第二个节点是模型预测狂输出节点,其位置如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kkt7NpVJ-1681820775522)(/home/aistudio/image/image-20221004030109206.png)]
# 模型裁剪
!python /home/aistudio/PaddleUtils/paddle/prune_paddle_model.py --model_dir /home/aistudio/model/ppyoloe_plus_crn_l_80e_coco --model_filename model.pdmodel --params_filename model.pdiparams --output_names tmp_16 concat_14.tmp_0 --save_dir /home/aistudio/model/ppyoloe_cut
2.4 模型转换ONNX
由于Paddle模型未指定bath_size大小,在使用时会出现问题,因此通过将该模型转为ONNX并指定bath_size大小,此处使用paddle2onnx工具便可以实现。
在命令提示符中依次输入以下指令,将上一步导出的模型转为ONNX格式:
# 模型转换
!paddle2onnx --model_dir /home/aistudio/model/ppyoloe_cut --model_filename model.pdmodel --params_filename model.pdiparams --input_shape_dict "{'image':[1,3,640,640]}" --opset_version 11 --save_file /home/aistudio/model/ppyoloe_plus_crn_l_80e_coco.onnx
from openvino.runtime import Core
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def process_image(input_image, size):
"""输入图片与处理方法,按照PP-Yoloe模型要求预处理图片数据
Args:
input_image (uint8): 输入图片矩阵
size (int): 模型输入大小
Returns:
float32: 返回处理后的图片矩阵数据
"""
max_len = max(input_image.shape)
img = np.zeros([max_len,max_len,3],np.uint8)
img[0:input_image.shape[0],0:input_image.shape[1]] = input_image # 将图片放到正方形背景中
img = cv.cvtColor(img,cv.COLOR_BGR2RGB) # BGR转RGB
img = cv.resize(img, (size, size), cv.INTER_NEAREST) # 缩放图片
img = np.transpose(img,[2, 0, 1]) # 转换格式
img = img / 255.0 # 归一化
img = np.expand_dims(img,0) # 增加维度
return img
def process_result(box_results, conf_results):
"""按照PP-Yolove模型输出要求,处理数据,非极大值抑制,提取预测结果
Args:
box_results (float32): 预测框预测结果
conf_results (float32): 置信度预测结果
Returns:
float: 预测框
float: 分数
int: 类别
"""
conf_results = np.transpose(conf_results,[0, 2, 1]) # 转换数据通道
# 设置输出形状
box_results =box_results.reshape(8400,4)
conf_results = conf_results.reshape(8400,80)
scores = []
classes = []
boxes = []
for i in range(8400):
conf = conf_results[i,:] # 预测分数
score = np.max(conf) # 获取类别
# 筛选较小的预测类别
if score > 0.5:
classes.append(np.argmax(conf))
scores.append(score)
boxes.append(box_results[i,:])
scores = np.array(scores)
boxes = np.array(boxes)
# 非极大值抑制筛选重复的预测结果
picked_boxes, picked_score, indexs = nms(boxes,scores)
print(indexs)
# 处理非极大值抑制后的结果
result_box = []
result_score = []
result_class = []
for i, index in enumerate(indexs):
result_score.append(scores[index])
result_box.append(boxes[index,:])
result_class.append(classes[index])
# 返沪结果转为矩阵
return np.array(result_box),np.array(result_score),np.array(result_class)
def draw_box(image, boxes, scores, classes, lables):
"""将预测结果绘制到图像上
Args:
image (uint8): 原图片
boxes (float32): 预测框
scores (float32): 分数
classes (int): 类别
lables (str): 标签
Returns:
uint8: 标注好的图片
"""
scale = max(image.shape) / 640.0 # 缩放比例
for i in range(len(classes)):
box = boxes[i,:]
x1 = int(box[0] * scale)
y1 = int(box[1] * scale)
x2 = int(box[2] * scale)
y2 = int(box[3] * scale)
lable = lables[classes[i]]
score = scores[i]
cv.rectangle(image, (x1, y1), (x2, y2), (0,0,255), 2, cv.LINE_8)
cv.putText(image,lable+":"+str(score),(x1,y1-20),cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
return image
def read_lable(lable_path):
"""读取lable文件
Args:
lable_path (str): 文件路径
Returns:
str: _description_
"""
f = open(lable_path)
lable = []
line = f.readline()
while line:
lable.append(line)
line = f.readline()
f.close()
return lable
def nms( bounding_boxes, confidence_score):
'''
:param bounding_boxes: 候选框列表,[左上角坐标, 右下角坐标], [min_x, min_y, max_x, max_y], 原点在图像左上角
:param confidence_score: 候选框置信度
:param threshold: IOU阈值
:return: 抑制后的bbox和置信度
'''
picked = []
for i in range(confidence_score.shape[-1]):
if confidence_score[i] > 0.35:
picked.append(i)
bounding_boxes = bounding_boxes[picked,:]
confidence_score = confidence_score[picked]
# 如果没有bbox,则返回空列表
if len(bounding_boxes) == 0:
return [], []
# bbox转为numpy格式方便计算
boxes = np.array(bounding_boxes)
# 分别取出bbox的坐标
start_x = boxes[:, 0]
start_y = boxes[:, 1]
end_x = boxes[:, 2]
end_y = boxes[:, 3]
# 置信度转为numpy格式方便计算
score = np.array(confidence_score) # [0.9 0.75 0.8 0.85]
# 筛选后的bbox和置信度
picked_boxes = []
picked_score = []
# 计算每一个框的面积
areas = (end_x - start_x + 1) * (end_y - start_y + 1)
# 将score中的元素从小到大排列,提取其对应的index(索引),然后输出到order
order = np.argsort(score) # [1 2 3 0]
indexs = []
# Iterate bounding boxes
while order.size > 0:
# The index of largest confidence score
# 取出最大置信度的索引
index = order[-1]
indexs.append(index)
# Pick the bounding box with largest confidence score
# 将最大置信度和最大置信度对应的框添加进筛选列表里
picked_boxes.append(bounding_boxes[index])
picked_score.append(confidence_score[index])
# 求置信度最大的框与其他所有框相交的长宽,为下面计算相交面积做准备
# 令左上角为原点,
# 两个框的左上角坐标x取大值,右下角坐标x取小值,小值-大值+1==相交区域的长度
# 两个框的左上角坐标y取大值,右下角坐标y取小值,小值-大值+1==相交区域的高度
# 这里可以在草稿纸上画个图,清晰明了
x1 = np.maximum(start_x[index], start_x[order[:-1]])
x2 = np.minimum(end_x[index], end_x[order[:-1]])
y1 = np.maximum(start_y[index], start_y[order[:-1]])
y2 = np.minimum(end_y[index], end_y[order[:-1]])
# 计算相交面积,当两个框不相交时,w和h必有一个为0,面积也为0
w = np.maximum(0.0, x2 - x1 + 1)
h = np.maximum(0.0, y2 - y1 + 1)
intersection = w * h
# 计算IOU
ratio = intersection / (areas[index] + areas[order[:-1]] - intersection)
# 保留小于阈值的框的索引
left = np.where(ratio < 0.25)
# 根据该索引修正order中的索引(order里放的是按置信度从小到大排列的索引)
order = order[left]
return picked_boxes, picked_score, indexs
class Predictor:
"""
OpenVINO 模型推理器
"""
def __init__(self, model_path):
ie_core = Core()
model = ie_core.read_model(model=model_path)
self.compiled_model = ie_core.compile_model(model=model, device_name="CPU")
def get_inputs_name(self, num):
return self.compiled_model.input(num)
def get_outputs_name(self, num):
return self.compiled_model.output(num)
def predict(self, input_data):
return self.compiled_model([input_data])
def yoloe_infer(image_path):
'''-------------------1. 导入相关信息 ----------------------'''
# yoloe_model_path = "E:/Text_Model/pp-yoloe/ppyoloe_plus_crn_s_80e_coco.onnx"
yoloe_model_path = "/home/aistudio/model/ppyoloe_plus_crn_l_80e_coco.onnx"
lable_path = "/home/aistudio/model/lable.txt";
'''-------------------2. 创建模型预测器 ----------------------'''
predictor = Predictor(model_path = yoloe_model_path)
'''-------------------3. 预处理模型输入数据 ----------------------'''
image = cv.imread(image_path)
input_image = process_image(image, 640)
'''-------------------4. 模型推理 ----------------------'''
results = predictor.predict(input_data=input_image)
'''-------------------5. 后处理预测结果 ----------------------'''
boxes_name = predictor.get_outputs_name(0)
conf_name = predictor.get_outputs_name(1)
boxes, scores, classes = process_result(box_results=results[boxes_name], conf_results=results[conf_name]) # 处理结果
lables = read_lable(lable_path=lable_path) # 读取lable
result_image = draw_box(image=image, boxes=boxes, scores=scores, classes=classes, lables=lables) # 绘制结果
return result_image
根据模型推理流程,最后调用模型推理类进行实现:
- 导入相关信息:主要是定义模型地址、待预测图片地址和类别文件;
- 创建模型预测器:主要初始化预测类,读取本地模型,此处可以读取ONNX模型和IR模型两种格式;
- 预处理图片:调用定义的图片处理方法,将本地图片数据转为模型推理的数据;
- 模型推理:将处理好的图片数据加载到模型中,并获取模型推理结果;
- 处理模型结果:主要是调用结果处理方法实现,如果需要可视化,可以将预测结果绘制到图片中。
image_path = "/home/aistudio/image/demo_3.jpg"
image =yoloe_infer(image_path)
image = image[:,:,::-1] #把图像转成rgb
plt.imshow(image)
plt.show()
[9, 5, 29, 18, 40, 36, 10, 49, 38, 47]
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.
此文章为转载
原为链接
更多推荐
所有评论(0)