前言

本文旨在记录本人将YOLO5训练好的模型转化为安卓 APP 的经历,使用的项目源码为,点击进入,下面开始分步骤进行讲解。

项目目录

项目的src文件夹下包含下面的文件夹,其中:
1 asserts 里面存放的是 YOLO5s.bin和YOLO5s.param,
2 java 中存放的是 java 源代码
3 jni c存储的是 YOLO5s的C++版本
4 res存放的android所需要的配置文件
使用 Android studio 直接在该文件的根目录打开就行
在这里插入图片描述

基础编译

该项目首页展示了如何进行代码的编译,可以参见官网进入,这里把自己的调试经验记录下。

1 首先在NCNN下载编译所需的ncnn包,下载页面为点击进入,下载箭头指向的文件

在这里插入图片描述
下载解压 之后存放在 jni 文件中,主要原因是在于项目源码中包含了此选项,如果下载上面页面中的 ncnn-android 其实也能编译,不过要替换这里的画横线部分
在这里插入图片描述

2 进行编译运行成为 APK文件(这个可以自行百度过程,也可按照下方操作)

在这里插入图片描述
在这里插入图片描述
如果您第一次生成APK可能需要配置下这里的账号和密码,存在一个指定文件夹中
在这里插入图片描述
按照以下选择,点击 finish 按钮即可
在这里插入图片描述
最终会在 src 同根目录生成 release 文件夹,里面存放的就是 APK文件

在这里插入图片描述

在这里插入图片描述
通过 QQ(不能通过微信,微信会自动在APK后缀加.1导致文件损坏) 传到手机,安装就行,下面这个是从官网截的图片,大概界面就是这样,很简洁2,不过功能自己可以再多完善

在这里插入图片描述

讲到这里,大家会发现,以上都是基于官方的 源码编译的结果,如果自己训练好的模型,怎么才能转化为 上述文件夹中的 bin 和 param 呢。怎样进行配置自定义的APP?这个网站上有些专栏介绍的有,这里我结合自己的经验进行详细记录。

转化前的准备

参照编译安装配置NCNN环境

如果上述过程没问题,那就基本完成 80% 了

1 训练自己的YOLO5模型,这里建议YOLO5s,因为上述源码基于 YOLO5 s 如果需要其他的模型,自己需要写对应的C++代码,另外最大原因是 YOLO5s 的效率高,对移动端友好。训练YOLO5 参看进入

2 训练好的 pt 转 bin 和 param

2.1 先将 pt 转 onnx

这个是在 yolo5中的 models文件夹下的 export .py,最好将这个export.py 复制到根目录,不然会报 models 未定义的异常,然后在根目录直接使用下面的命令执行,这个 ONNX是 Open Neural Network Exchange(开放神经网络交换)格式,是一个用于表示深度学习模型的标准,可使模型在不同框架之间进行转移,所以这个是模型转化的第一步,将 pt 转为一种万能格式。

python export.py --weights ./runs/exp0/weights/best.pt --img 640 --batch 1

一般此步骤不会出错,当然我用的是 yolo5-2.0 版本,新版本没有尝试,不过大概率也是没问题。
这里是将模型进行简化,需要安装 onnxsim 的,安装命令:

pip install onnx-simplifier

然后使用该命令,简化刚才的 onnx ,其实有点类似模型压缩

python -m onnxsim best.onnx best-sim.onnx
2.2 onnx2ncnn

在编译安装好的目录中,找到 onnx2ncnn 文件,这个是个可执行的文件,然后将自己的 pt 复制到该文件夹,主要是操作方便,也可不复制,直接使用路径访问。

在这里插入图片描述
然后使用命令

./onnx2ncnn best-sim.onnx best.param best.bin

如果没有报错,那么你就转化成功了,但由于 YOLO5中的 Focus 模块,一般会有以下的异常

Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
Unsupported slice step !

这需要您打开生成的 param 文件,按照下面的策略进行编辑,将圈出来的部分替换为下面的图片,其中 201- 192这个其实目前我还不是很理解,可能和 java 源码中对应的,我后来看看,转为那个 YoloV5Focus是在 java 中有对应的操作,其实该步骤的含义是将 Focus 模块转化为一个简单的模块。
在这里插入图片描述

在这里插入图片描述
原Focus结构(图像由 param 文件 用 Netron 可视化得到 ):
在这里插入图片描述
转化后的结构

在这里插入图片描述
如果不满足以上的 YoloV5Focus 转化,自己可以在 github 找实现代码点击进入

以上步骤之后,需要使用 ncnn 文件夹下的 ncnnoptimize进行再次整合优化,后面的 65536 也可以替换为 1 已在将模型转为FP16 单精度计算,节省运算时间,为0时,为FP32 双精度计算

在这里插入图片描述

./ncnnoptimize best.param best.bin best-opt.param best-opt.bin 65536

将生成的 bin 和 param 文件复制到 asserts 文件夹 后,不要着急编译为 APK

里面需要调整的参数有:

jni/yolov5ncnn_jni.cpp中的 anchor参数需要调整为和自己网路训练anchor 配置一致,这里我是用了4个anchor 共 8个 w 和 h

在这里插入图片描述

jni/yolov5ncnn_jni.cpp中的 blob 名字

这个名字是用来提取输出结果的,对应的是 param 文件的 画圈部分的id 值
在这里插入图片描述
在这里插入图片描述

种类名需要替换为自己的
static const char* class_names[] ={"name_1","name_2","name_3",...}
YOLO v5 的后处理

pytorch的后处理在 yolov5/models/yolo.py Detect类 forward函数,对着改写成 cpp, 写在 jni 下的 cpp文件即可,也可以自定义

U版yolov5 是支持动态尺寸推理的

静态尺寸:按长边缩放到 640xH 或 Wx640,padding 到 640x640 再检测,如果 H/W 比较小,会在 padding 上浪费大量运算
动态尺寸:按长边缩放到 640xH 或 Wx640,padding 到 640xH2 或 W2x640 再检测,其中 H2/W2 是 H/W 向上取32倍数,计算量少,速度更快
ncnn天然支持动态尺寸输入,无需reshape或重新初始化,给多少就算多少
如果出现对于小图像的检测有问题,可以将param的reshape 变为 -1,后处理部分也不可写死 sqrt(num_grid),要根据图片宽高和 stride 自适应
在这里插入图片描述

然后这就可以进行编译APK了,祝顺利!

本文参考进入

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐