AI模型部署 | onnxruntime部署YOLOv8分割模型详细教程

这篇具有很好参考价值的文章主要介绍了AI模型部署 | onnxruntime部署YOLOv8分割模型详细教程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文首发于公众号【DeepDriving】,欢迎关注。

0. 引言

我之前写的文章《基于YOLOv8分割模型实现垃圾识别》介绍了如何使用YOLOv8分割模型来实现垃圾识别,主要是介绍如何用自定义的数据集来训练YOLOv8分割模型。那么训练好的模型该如何部署呢?YOLOv8分割模型相比检测模型多了一个实例分割的分支,部署的时候还需要做一些后处理操作才能得到分割结果。
本文将详细介绍如何使用onnxruntime框架来部署YOLOv8分割模型,为了方便理解,代码采用Python实现。

1. 准备工作

  • 安装onnxruntime

    onnxruntime分为GPU版本和CPU版本,均可以通过pip直接安装:

    pip install onnxruntime-gpu  #安装GPU版本
    
    pip install onnxruntime  #安装CPU版本
    

    注意: GPU版本和CPU版本建议只选其中一个安装,否则默认会使用CPU版本

  • 下载YOLOv8分割模型权重

    Ultralytics官方提供了用COCO数据集训练的模型权重,我们可以直接从官方网站https://docs.ultralytics.com/tasks/segment/下载使用,本文使用的模型为yolov8m-seg.pt

    yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

  • 转换onnx模型

    调用下面的命令可以把YOLOv8m-seg.pt模型转换为onnx格式的模型:

    yolo task=segment mode=export model=yolov8m-seg.pt format=onnx
    

    转换成功后得到的模型为yolov8m-seg.onnx

2. 模型部署

2.1 加载onnx模型

首先导入onnxruntime包,然后调用其API加载模型即可:

import onnxruntime as ort

session = ort.InferenceSession("yolov8m-seg.onnx", providers=["CUDAExecutionProvider"])

因为我使用的是GPU版本的onnxruntime,所以providers参数设置的是"CUDAExecutionProvider";如果是CPU版本,则需设置为"CPUExecutionProvider"

模型加载成功后,我们可以查看一下模型的输入、输出层的属性:

for input in session.get_inputs():
    print("input name: ", input.name)
    print("input shape: ", input.shape)
    print("input type: ", input.type)

for output in session.get_outputs():
    print("output name: ", output.name)
    print("output shape: ", output.shape)
    print("output type: ", output.type)

结果如下:

input name:  images
input shape:  [1, 3, 640, 640]
input type:  tensor(float)
output name:  output0
output shape:  [1, 116, 8400]
output type:  tensor(float)
output name:  output1
output shape:  [1, 32, 160, 160]
output type:  tensor(float)

从上面的打印信息可以知道,模型有一个尺寸为[1, 3, 640, 640]的输入层和两个尺寸分别为[1, 116, 8400][1, 32, 160, 160]的输出层。

2.2 数据预处理

数据预处理采用OpenCVNumpy实现,首先导入这两个包

import cv2
import numpy as np

OpenCV读取图片后,把数据按照YOLOv8的要求做预处理

image = cv2.imread("soccer.jpg")
image_height, image_width, _ = image.shape
input_tensor = prepare_input(image, model_width, model_height)
print("input_tensor shape: ", input_tensor.shape)

其中预处理函数prepare_input的实现如下:

def prepare_input(bgr_image, width, height):
    image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
    image = cv2.resize(image, (width, height)).astype(np.float32)
    image = image / 255.0
    image = np.transpose(image, (2, 0, 1))
    input_tensor = np.expand_dims(image, axis=0)
    return input_tensor

处理流程如下:

1. 把OpenCV读取的BGR格式的图片转换为RGB格式;
2. 把图片resize到模型输入尺寸640x640;
3. 对像素值除以255做归一化操作;
4. 把图像数据的通道顺序由HWC调整为CHW;
5. 扩展数据维度,将数据的维度调整为NCHW。

经过预处理后,输入数据input_tensor的维度变为[1, 3, 640, 640],与模型的输入尺寸一致。

2.3 模型推理

输入数据准备好以后,就可以送入模型进行推理:

outputs = session.run(None, {session.get_inputs()[0].name: input_tensor})

前面我们打印了模型的输入输出属性,可以知道模型有两个输出分支,其中一个output0是目标检测分支,另一个output1则是实例分割分支,这里打印一下它们的尺寸看一下

#squeeze函数是用于删除shape中为1的维度,对output0做transpose操作是为了方便后续操作
output0 = np.squeeze(outputs[0]).transpose()
output1 = np.squeeze(outputs[1])
print("output0 shape:", output0.shape)
print("output1 shape:", output1.shape)

结果如下:

output0 shape: (8400, 116)
output1 shape: (32, 160, 160)

处理后目标检测分支的维度为[8400, 116],表示模型总共可以检测出8400个目标(大部分是无效的目标),每个目标包含116个参数。刚接触YOLOv8分割模型的时候可能会对116这个数字感到困惑,这里有必要解释一下:每个目标的参数包含4个坐标属性(x,y,w,h)、80个类别置信度和32个实例分割参数,所以总共是116个参数。实例分割分支的维度为[32, 160, 160],其中第一个维度32与目标检测分支中的32个实例分割参数对应,后面两个维度则由模型输入的宽和高除以4得到,本文所用的模型输入宽和高都是640,所以这两个维度都是160

2.4 后处理

首先把目标检测分支输出的数据分为两个部分,把实例分割相关的参数从中剥离。

boxes = output0[:, 0:84]
masks = output0[:, 84:]
print("boxes shape:", boxes.shape)
print("masks shape:", masks.shape)
boxes shape: (8400, 84)
masks shape: (8400, 32)

然后实例分割这部分数据masks要与模型的另外一个分支输出的数据output1做矩阵乘法操作,在这之前要把output1的维度变换为二维。

output1 = output1.reshape(output1.shape[0], -1)
masks = masks @ output1
print("masks shape:", masks.shape)
masks shape: (8400, 25600)

做完矩阵乘法后,就得到了8400个目标对应的实例分割掩码数据masks,可以把它与目标检测的结果boxes拼接到一起。

detections = np.hstack([boxes, masks])
print("detections shape:", detections.shape)
detections shape: (8400, 25684)

到这里读者应该就能理解清楚了,YOLOv8模型总共可以检测出8400个目标,每个目标的参数包含4个坐标属性(x,y,w,h)、80个类别置信度和一个160x160=25600大小的实例分割掩码。

由于YOLOv8模型检测出的8400个目标中有大量的无效目标,所以先要通过置信度过滤去除置信度低于阈值的目标,对于满足置信度满足要求的目标还需要通过非极大值抑制(NMS)操作去除重复的目标。

objects = []
for row in detections:
    prob = row[4:84].max()
    if prob < 0.5:
        continue
    class_id = row[4:84].argmax()
    label = COCO_CLASSES[class_id]
    xc, yc, w, h = row[:4]
    // 把x1, y1, x2, y2的坐标恢复到原始图像坐标
    x1 = (xc - w / 2) / model_width * image_width
    y1 = (yc - h / 2) / model_height * image_height
    x2 = (xc + w / 2) / model_width * image_width
    y2 = (yc + h / 2) / model_height * image_height
    // 获取实例分割mask
    mask = get_mask(row[84:25684], (x1, y1, x2, y2), image_width, image_height)
    // 从mask中提取轮廓
    polygon = get_polygon(mask, x1, y1)
    objects.append([x1, y1, x2, y2, label, prob, polygon, mask])

// NMS
objects.sort(key=lambda x: x[5], reverse=True)
results = []
while len(objects) > 0:
    results.append(objects[0])
    objects = [object for object in objects if iou(object, objects[0]) < 0.5]

这里重点讲一下获取实例分割掩码的过程。

前面说了每个目标对应的实例分割掩码数据大小为160x160,但是这个尺寸是对应整幅图的掩码。对于单个目标来说,还要从这个160x160的掩码中去截取属于自己的掩码,截取的范围由目标的box决定。上面的代码得到的box是相对于原始图像大小,截取掩码的时候需要把box的坐标转换到相对于160x160的大小,截取完后再把这个掩码的尺寸调整回相对于原始图像大小。截取到box大小的数据后,还需要对数据做sigmoid操作把数值变换到01的范围内,也就是求这个box范围内的每个像素属于这个目标的置信度。最后通过阈值操作,置信度大于0.5的像素被当做目标,否则被认为是背景。

具体实现的代码如下:

def get_mask(row, box, img_width, img_height):
  mask = row.reshape(160, 160)
  x1, y1, x2, y2 = box
  // box坐标是相对于原始图像大小,需转换到相对于160*160的大小
  mask_x1 = round(x1 / img_width * 160)
  mask_y1 = round(y1 / img_height * 160)
  mask_x2 = round(x2 / img_width * 160)
  mask_y2 = round(y2 / img_height * 160)
  mask = mask[mask_y1:mask_y2, mask_x1:mask_x2]
  mask = sigmoid(mask)
  // 把mask的尺寸调整到相对于原始图像大小
  mask = cv2.resize(mask, (round(x2 - x1), round(y2 - y1)))
  mask = (mask > 0.5).astype("uint8") * 255
  return mask

这里需要注意的是,160x160是相对于模型输入尺寸为640x640来的,如果模型输入是其他尺寸,那么上面的代码需要做相应的调整。

如果需要检测的是下面这个图片:

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

通过上面的代码可以得到最左边那个人的分割掩码为

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

但是我们需要的并不是这样一张图片,而是需要用于表示这个目标的轮廓,这可以通过OpenCVfindContours函数来实现。findContours函数返回的是一个用于表示该目标的点集,然后我们可以在原始图像中用fillPoly函数画出该目标的分割结果。

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

全部目标的检测与分割结果如下:

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

3. 一点其他的想法

从前面的部署过程可以知道,做后处理的时候需要对实例分割的数据做矩阵乘法、sigmoid激活、维度变换等操作,实际上这些操作也可以在导出模型的时候集成到onnx模型中去,这样就可以简化后处理操作。

首先需要修改ultralytics代码仓库中ultralytics/nn/modules/head.py文件的代码,把SegmentForward函数最后的代码修改为:

if self.export:
    output1 = p.reshape(p.shape[0], p.shape[1], -1)
    boxes = x.permute(0, 2, 1)
    masks = torch.sigmoid(mc.permute(0, 2, 1) @ output1)
    out = torch.cat([boxes, masks], dim=2)
    return out
else:
    return (torch.cat([x[0], mc], 1), (x[1], mc, p))

然后修改ultralytics/engine/exporter.py文件中torch.onnx.export的参数,把模型的输出数量改为1个。

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

代码修改完成后,执行命令pip install -e '.[dev]'使之生效,然后再重新用yolo命令导出模型。用netron工具可以看到模型只有一个shape[1,8400,25684]的输出。

yolov8图像预处理,自动驾驶与深度学习,人工智能,YOLO,深度学习

这样在后处理的时候就可以直接去解析boxmask了,并且mask的数据不需要进行sigmoid激活。文章来源地址https://www.toymoban.com/news/detail-856879.html

4. 参考资料

  • How to implement instance segmentation using YOLOv8 neural network
  • https://github.com/AndreyGermanov/yolov8_segmentation_python

到了这里,关于AI模型部署 | onnxruntime部署YOLOv8分割模型详细教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 瑞芯微RK3588 C++部署Yolov8检测和分割模型

    最近这一个月在研究国产瑞芯微板子上部署yolov8的检测和分割模型,踩了很多坑,记录一下部署的过程和遇到的一些问题: 需要的环境和代码主要包括: (1)rknn-toolkit2-1.5.2:工具链,开发环境 (2)rockchip-yolov8:pt模型转onnx模型 (3)yolov8_onnx2rknn:在(2)的基础上转检测

    2024年04月09日
    浏览(41)
  • 如何加载模型YOLOv8 ONNXRuntime

    YOLOv8 是 YOLO(You Only Look Once)目标检测系统的最新版本(v8)。YOLO 是一种实时、一次性目标检测系统,旨在在网络的单次前向传递中执行目标检测,使其快速高效。YOLOv8是之前YOLO模型的改进版本,具有更高的精度和更快的推理速度。 ONNX(开放神经网络交换)是一种表示深度

    2024年02月14日
    浏览(24)
  • 使用c++onnxruntime部署yolov5模型并使用CUDA加速(超详细)

    前言 1.Yolo简介 2.onnxruntime简介 3.Yolov5模型训练及转换 4.利用cmake向C++部署该onnx模型 总结 接到一个项目,需要用c++和单片机通信,还要使用yolo模型来做到目标检测的任务,但目前网上的各种博客并没有完整的流程教程,让我在部署过程费了不少劲,也踩了不少坑(甚至一度把

    2024年02月02日
    浏览(34)
  • 2023.01更新 c++下面部署yolov8检测和实例分割模型(七)

    2023.12.05 更新: 新增yolov8的RT-DETR部署 先开贴占个坑。 yolov8:https://github.com/ultralytics/ultralytics 这次的v8更新的是一个框架,里面也可以用v5和v3。 但是这次更新来说,目前模型的检测效果和之前的yolov7刚出来一样,会多出很多误检,在某些情况下这些误检反而效果不好。另外最

    2024年02月11日
    浏览(25)
  • YOLOV8 Onnxruntime Opencv DNN C++部署

          OpenCV由各种不同组件组成。OpenCV源代码主要由OpenCV core(核心库)、opencv_contrib和opencv_extra等子仓库组成。近些年,OpenCV的主仓库增加了深度学习相关的子仓库:OpenVINO(即DLDT, Deep Learning Deployment Toolkit)、open_model_zoo,以及标注工具CVAT等。         OpenCV深度学习模块只

    2024年02月16日
    浏览(38)
  • 从零开始部署yolov8到安卓手机详细教程【Android Studio】

    首先你需要配置好pytorch环境,本文不再详细阐述,若未配置好环境,可以参考: https://blog.csdn.net/weixin_43507693/article/details/109015177 安装yolov8可参考: https://blog.csdn.net/weixin_44120785/article/details/128681117 Android Studio官网链接:https://developer.android.google.cn/ 自行配置AS环境(网上很多相

    2024年01月25日
    浏览(39)
  • yolov8 实例分割 onnx runtime C++部署

    如果第一次部署分割,建议先看这篇博客: YOLOv5 实例分割 用 OPenCV DNN C++ 部署_爱钓鱼的歪猴的博客-CSDN博客 目录 Pre 一、OpenCV DNN C++ 部署 二、ONNX RUNTIME C++ 部署 yolov8_seg_utils.h yolov8_seg_utils.cpp yolov8_seg_onnx.h yolov8_seg_onnx.cpp main.cpp CMakelist.txt 一定要知道,yolov8的输出与Yolov5 7.0 实例

    2024年02月11日
    浏览(63)
  • 基于.Net6使用YoloV8的分割模型

    在目标检测一文中,我们学习了如何处理Onnx模型,并的到目标检测结果,在此基础上,本文实现基于.Net平台的实例分割任务。 执行YoloV8的分割任务后可以得到分割.pt模型。由于Python基本不用于工业软件的部署,最终还是希望能在.Net平台使用训练好的模型进行预测。我们可以

    2024年02月09日
    浏览(25)
  • C++模型部署:qt+yolov5/6+onnxruntime+opencv

    作者平时主要是写 c++ 库的,界面方面了解不多,也没有发现“美”的眼镜,界面有点丑,大家多包涵。 本次介绍的项目主要是通过 cmake 构建一个 基于 c++ 语言的,以 qt 为框架的,包含 opencv 第三方库在内的,跨平台的,使用 ONNX RUNTIME 进行前向推理的 yolov5/6 演示平台。文章

    2024年02月05日
    浏览(37)
  • 超详细||YOLOv8基础教程(环境搭建,训练,测试,部署看一篇就够)(在推理视频中添加FPS信息)

    这篇文章将跳过基础的深度学习环境的搭建,如果没有完成的可以看我的这篇博客:超详细||深度学习环境搭建记录cuda+anaconda+pytorch+pycharm-CSDN博客 1. 在github上下载源码: GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch ONNX OpenVINO CoreML TFLite 2. 安装ultralytics(YOLOv8改名为ultraly

    2024年02月05日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包