欢迎访问我的网站,希望内容对您有用,感兴趣的可以加入免费知识星球。

借助NCNN,在Android上运行YOLOv5目标检测

YOLO 迷途小书童 3年前 (2021-02-02) 28674次浏览 3个评论

软硬件环境

  • yolov5
  • ncnn
  • android studio 4.1.2
  • oneplus 8
  • pytorch 1.6
  • onnx
  • netron

视频看这里

Youtube

Bilibili

前言

前面几篇文章,我们已经详细介绍过 yolov5 的检测、训练、可视化等内容,本文继续 yolov5 的话题,这回我们来看看,如何在 android 中去使用 yolov5 来进行目标检测?

yolov5 ncnn android

什么是ncnn

下面这段是官方的定义

ncnn 是腾讯公司开源的一个专为手机端极致优化的高性能神经网络前向计算框架。ncnn 从设计之初,就深刻考虑手机端的部署和使用,无需第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖。

目前 ncnn 已经支持大部分的 CNN 网络,包括本文中用到的 yolov5

  • Classical CNN: VGG AlexNet GoogleNet Inception …
  • Practical CNN: ResNet DenseNet SENet FPN …
  • Light-weight CNN: SqueezeNet MobileNetV1/V2/V3 ShuffleNetV1/V2 MNasNet …
  • Face Detection: MTCNN RetinaFace …
  • Detection: VGG-SSD MobileNet-SSD SqueezeNet-SSD MobileNetV2-SSDLite MobileNetV3-SSDLite …
  • Detection: Faster-RCNN R-FCN …
  • Detection: YOLOV2 YOLOV3 MobileNet-YOLOV3 YOLOV4 YOLOV5 …
  • Segmentation: FCN PSPNet UNet YOLACT …
  • Pose Estimation: SimplePose …

项目实操

关于基础环境部分,这里需要用到 android 的开发环境,像 android studiosdkndk 等等,本文不做介绍,有问题的话,可以在留言区中留言。

我们直接拉取 yolov5 for android 的源码

git clone https://github.com/nihui/ncnn-android-yolov5

然后来到 ncnn 的版本发布页,下载编译好的包 https://github.com/Tencent/ncnn/releases,如果你有兴趣的话,也可以通过 ndk 自己去编译

yolov5 ncnn android

下载解压后拷贝到 ncnn-android-yolov5 项目的 app/src/main/jni 目录下,目录结构是这样的

yolov5 ncnn android

然后修改同级目录下的 CMakeLists.txt,将其中的 ncnn_DIR 变量值修改成

set(ncnn_DIR ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib/cmake/ncnn)

yolov5 ncnn android

保存后就可以进行项目的编译了。

这里使用真机进行测试,需要自己打开手机的开发者模式,允许 USB 调试,APP 安装后打开,首页是这样的

yolov5 ncnn android

界面布局非常简单,总共就三个按钮,一个选图,一个使用 CPU 检测,一个使用 GPU 检测。经过测试发现 CPU 的速度要比 GPU 慢上一倍,我的 OnePlus 8GPU 速度也只有 5fps

yolov5 ncnn android

yolov5 ncnn android

如何使用自己的模型

当我们训练了自己的检测模型后,就需要一种中介,通过它,可以实现在不同框架之间进行转换。 Open Neural Network Exchange 简称 ONNX,意思是开放神经网络交换格式,它就是我们需要的中介。

yolov5 的模型训练请参考这篇 https://xugaoxiang.com/2020/07/02/yolov5-training/,作为测试,我们也使用上文中训练出来的口罩检测模型

安装依赖库

pip install onnx coremltools onnx-simplifier

执行命令

python models/export.py --weights runs/exp2/weights/best.pt

yolov5 ncnn android

同时在 best.pt 的同级目录,还生成了 best.onnxbest.mlmodelbest.torchscript.pt

yolov5 ncnn android

这里需要提醒一下大家,上述的导出操作在 pytorch1.7yolov5 v4.0 版本上会报错,我这里的环境是 pytorch1.6yolov5 3.0 版本。报错信息如下

Converting op 143 : listconstruct
Adding op '143' of type const
Converting op 144 : listconstruct
Adding op '144' of type const
Converting op 145 : listconstruct
Adding op '145' of type const
Converting op x.2 : _convolution
Converting Frontend ==> MIL Ops:   3%|██                                                           | 21/620 [00:00<00:00, 1350.49 ops/s]
CoreML export failure: unexpected number of inputs for node x.2 (_convolution): 13

Export complete (12.83s). Visualize with https://github.com/lutzroeder/netron.

这是 coremltools 的一个 bug。相关链接请查看 https://github.com/ultralytics/yolov5/issues/1667

接下来使用工具 onnx-simplifier 来简化 onnx,执行命令

python -m onnxsim runs/exp2/weights/best.onnx runs/exp2/weights/best-sim.onnx

yolov5 ncnn android

下面开始编译 ncnn,首先准备基础环境

sudo apt install build-essential libopencv-dev cmake

编译安装 protobuf 依赖库

git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git submodule update --init --recursive
./autogen.sh
./configure
make
make install
sudo ldconfig

编译安装好以后,可以查看下 protobuf 的版本号

yolov5 ncnn android

接下来,需要编译 ncnn,目的是生成 onnxncnn 的命令行工具

git clone https://github.com/Tencent/ncnn.git
cd ncnn
git submodule update --init
mkdir build
cd build
cmake ..
make -j8
make install

编译安装完成后,就可以使用 onnx2ncnn 工具进行转换了

cd tools/onnx
./onnx2ncnn ~/Works/weights/best-sim.onnx ~/Works/weights/model.param ~/Works/weights/model.bin

oh, no,报错了

yolov5 ncnn android

这是由于 slice 没有被支持。为了解决这个问题,我们需要编辑生成的 param 文件,使用文本工具打开即可

yolov5 ncnn android

修改后的 param 是这样的

yolov5 ncnn android

第二行的第一个数是层数,因为我们删除了8个 Crop 和1个 Concat,所以它的值是 201-9=192

另外,需要修改的是 Reshape 层的输出 grid,将对应的值都改成 -1,这是为了解决实际中出现的多检测框的问题

yolov5 ncnn android

yolov5 ncnn android

可以用 netron 这个工具打开查看网络结构,windowslinuxmacos 上都有,地址 https://github.com/lutzroeder/netron/releases/tag/v4.7.5

yolov5 ncnn android

图片中,我们要删除 SplitConcat 和8个 Crop 节点,并且加入新的节点 YoloV5Focus,这个节点名称是和 android 源码中的 yolov5ncnn_jni.cpp 中的类名匹配的。这里可以将文本编辑器和 netron 结合起来用,修改完后立刻查看。

yolov5 ncnn android

yolov5 ncnn android

接下来就可以替换原 android 工程中 assets 文件夹下的 yolov5s.paramyolov5s.bin

yolov5 ncnn android

然后接着修改源码文件 yolov5ncnn_jni.cpp,修改2个 Permute 节点的 output

yolov5 ncnn android

yolov5 ncnn android

yolov5 ncnn android

最后,修改 class names

yolov5 ncnn android

重新编译工程,连上手机,安装 apk 并运行

最后的检测效果如下

yolov5 ncnn android

FAQ

这里列出了几个常见问题,供大家参考。

Could not install Gradle distribution from 'https://services.gradle.org/distributions/gradle-5.4.1-all.zip'.

关闭 android studio,手动从站点 https://services.gradle.org/distributions/gradle-5.4.1-all.zip 下载压缩包,然后进入文件夹 C:\Users\Administrator\.gradle\wrapper\dists\gradle-5.4.1-all\3221gyojl5jsh0helicew7rwx,将原有的内容全部删除,将下载的压缩包拷贝进来,再次打开 android studio,点击右上角的 Sync Project with Gradle Files

yolov5 ncnn android

No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi

这个错误是由于使用了较新的 ndk,但是原始 android 工程中使用的 gradle 版本太低,解决的方法就是去升级 gradle,升级方法参考上个问题,手动下载 gradle 压缩包,然后更新文件 gradle/wrapper/gradle-wrapper.properties 中的 gradle 版本号,再次同步

yolov5 ncnn android

Cause: jcenter.bintray.com:443 failed to respond

这个问题可能跟代理相关,在 File –> Settings –> HTTP Proxy,关闭代理

yolov5 ncnn android

或者编辑文件 ~\.gradle\gradle.properties,将 proxy 相关的语句注释掉

yolov5 ncnn android

另一个错误,是在编译 ncnn 的时候,出现 tiff 相关的错误信息

yolov5 ncnn android

这里主要是 anaconda 的环境与系统环境冲突导致,我的做法是完全退出 anaconda 环境,从而去使用系统的环境,那么就可以通过 apt 去安装对应的库了

conda deactivate
unset LD_LIBRARY_PATH

最后一个问题,模型转换经常碰到的错误

yolov5 ncnn android

这个错误是 yolov5ncnn_jni.cpp 中的 output 没有和实际模型匹配起来导致的

源码下载

链接:https://pan.quark.cn/s/302b8d81b3b7

参考资料

喜欢 (3)

您必须 登录 才能发表评论!

(3)个小伙伴在吐槽