赞
踩
几个小时前,我整理了一个新版(v7.0) YOLOv5
的 NCNN
部署教程:
详细记录u版YOLOv5目标检测ncnn实现(第三版) - 知乎
常言道用新不用旧,我顺便把 YOLOv8
的 NCNN
部署放出来吧!(把自己观念持续贯彻!)
本文将基于当前时间最新的 YOLOv8
进行模型转换和模型推理部署。
YOLO
系列在短短的两年多升级了不知道多少代了,但是最火的还是 YOLOv5
,同属于这个公司的 YOLOv8
想必也是精品,ultralytics
公司野心很大,发布 YOLOv8
的同时也想一统 YOLO
,我们需要持续观望一波!
版本号 v8.0.38
commit id: d99e04daa1290c226a3fae825401361b17ce164c
YOLOv8
相对于 YOLOv5
在主干上改动较小,最大的改动就是检测头了,变成了基于 DFL
的 anchor free
模型, 这部分变化较大的就是框解码了,我总结了下面 3 点:
DFL
模块 Reshape+Transpose+Softmax+Conv+Reshape 这套组合是真折腾ltrb
格式还要转回 xywh
比较麻烦。argmax
。本文同样,重新组织后处理代码,然后实现 NCNN
推理 YOLOv8
。
首先是下载当前时间最新的 YOLOv8 ,当前时间是 : 2023-02-15 16:00
- git clone https://github.com/ultralytics/ultralytics.git # clone
- cd ultralytics
- git checkout d99e04daa1290c226a3fae825401361b17ce164c # switch to commit id
- pip install -r requirements.txt # install
- pip install -e . # install ultralytics as package
YOLOv8
开始支持命令行启动任务了,对于搞 YOLOv5
的人转过来调试还是不太舒服。
老样子,用默认的配置和预训练模型推理一张图片:
yolo predict model=yolov8s.pt source=ultralytics/assets/bus.jpg show=True
接下来动源码,ultralytics/nn/modules.py
中的 398-411 行注释掉,换成下面的内容:
- # def forward(self, x):
- # shape = x[0].shape # BCHW
- # for i in range(self.nl):
- # x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
- # if self.training:
- # return x
- # elif self.dynamic or self.shape != shape:
- # self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
- # self.shape = shape
- #
- # box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1)
- # dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
- # y = torch.cat((dbox, cls.sigmoid()), 1)
- # return y if self.export else (y, x)
-
- def forward(self, x):
- z = [] # inference output
- for i in range(self.nl):
- boxes = self.cv2[i](x[i]).permute(0, 2, 3, 1)
- scores = self.cv3[i](x[i]).sigmoid().permute(0, 2, 3, 1)
- feat = torch.cat((boxes, scores), -1)
- z.append(feat)
- return tuple(z)
导出 torchscript:
yolo export model=yolov8s.pt format=torchscript
会在当前工作目录下生成 yolov8s.torchscript
。
用 Netron
看一眼清爽的后处理长什么样:
会有三个上述的结构,这是我们修改的 forward
中的内容,把分类预测分支的 sigmoid
弄到了模型,然后 permute
+ cat
。
下载编译好的 pnnx 工具包:PNNX
指定 inputshape
并且额外指定 inputshape2
转换成支持动态 shape 输入的模型:
./pnnx yolov8s.torchscript inputshape=[1,3,640,640] inputshape2=[1,3,320,320]
转换日志:
转换主要产物:
看一眼 yolov8s.ncnn.param
:
in0
对应输入,尺寸是 3*640*640 或者动态输入的尺寸。
out0
对应输出,尺寸是 80*80*144 或者动态输出的尺寸。
out1
对应输出,尺寸是 40*40*144 或者动态输出的尺寸。
out2
对应输出,尺寸是 20*20*144 或者动态输出的尺寸。
注意,本文用pnnx转换后的模型,尾巴上有sigmoid层和permute层。
pytorch的后处理在ultralytics/nn/modules.py
Detect类 forward
函数,也就是我们注释掉的部分,对着它改写成 cpp。
本文最后的输出形状:
C = 80 或 40 或 20
H = 80 或 40 或 20
W = 144 = 64+80
64 对应了 DFL
中的 reg_max=16
, 最终回归的 bbox 格式是 ltrb
。
ncnn实现代码和转好的模型已上传到github:
GitHub - triple-Mu/ncnn-examples: Learning ncnn with some examples
使用方式:
- git clone https://github.com/triple-Mu/ncnn-examples.git
- cd ncnn-examples/yolov8
- mkdir build
- cmake .. && make -j$(nproc)
- mv triplemu-yolov8 .. && cd ..
- ./triplemu-yolov8 ../bus.jpg
与其他的教程相同,本文也支持动态输入尺寸,更多的探索请查看源码 src/triplemu-yolov8.cpp
。
允许在不修改内容前提下转载本文!!
欢迎大家通过 triple-Mu 联系我哈~
顺便宣传一下我的 YOLOv8-TensorRT 部署仓库:
GitHub - triple-Mu/YOLOv8-TensorRT: YOLOv8 using TensorRT accelerate !
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。