软硬件环境
- yolov5
- ncnn
- android studio 4.1.2
- oneplus 8
- pytorch 1.6
- onnx
- netron
视频看这里
Youtube
Bilibili
前言
前面几篇文章,我们已经详细介绍过 yolov5
的检测、训练、可视化等内容,本文继续 yolov5
的话题,这回我们来看看,如何在 android
中去使用 yolov5
来进行目标检测?
什么是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 studio
、sdk
、ndk
等等,本文不做介绍,有问题的话,可以在留言区中留言。
我们直接拉取 yolov5 for android
的源码
git clone https://github.com/nihui/ncnn-android-yolov5
然后来到 ncnn
的版本发布页,下载编译好的包 https://github.com/Tencent/ncnn/releases,如果你有兴趣的话,也可以通过 ndk
自己去编译
下载解压后拷贝到 ncnn-android-yolov5
项目的 app/src/main/jni
目录下,目录结构是这样的
然后修改同级目录下的 CMakeLists.txt
,将其中的 ncnn_DIR
变量值修改成
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/${ANDROID_ABI}/lib/cmake/ncnn)
保存后就可以进行项目的编译了。
这里使用真机进行测试,需要自己打开手机的开发者模式,允许 USB
调试,APP
安装后打开,首页是这样的
界面布局非常简单,总共就三个按钮,一个选图,一个使用 CPU
检测,一个使用 GPU
检测。经过测试发现 CPU
的速度要比 GPU
慢上一倍,我的 OnePlus 8
的 GPU
速度也只有 5fps
。
如何使用自己的模型
当我们训练了自己的检测模型后,就需要一种中介,通过它,可以实现在不同框架之间进行转换。 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
同时在 best.pt
的同级目录,还生成了 best.onnx
、best.mlmodel
和 best.torchscript.pt
这里需要提醒一下大家,上述的导出操作在 pytorch1.7
和 yolov5 v4.0
版本上会报错,我这里的环境是 pytorch1.6
、yolov5 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
下面开始编译 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
的版本号
接下来,需要编译 ncnn
,目的是生成 onnx
转 ncnn
的命令行工具
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
,报错了
这是由于 slice
没有被支持。为了解决这个问题,我们需要编辑生成的 param
文件,使用文本工具打开即可
修改后的 param
是这样的
第二行的第一个数是层数,因为我们删除了8个 Crop
和1个 Concat
,所以它的值是 201-9=192
另外,需要修改的是 Reshape
层的输出 grid
,将对应的值都改成 -1,这是为了解决实际中出现的多检测框的问题
可以用 netron
这个工具打开查看网络结构,windows
、linux
、macos
上都有,地址 https://github.com/lutzroeder/netron/releases/tag/v4.7.5
图片中,我们要删除 Split
、Concat
和8个 Crop
节点,并且加入新的节点 YoloV5Focus
,这个节点名称是和 android
源码中的 yolov5ncnn_jni.cpp
中的类名匹配的。这里可以将文本编辑器和 netron
结合起来用,修改完后立刻查看。
接下来就可以替换原 android
工程中 assets
文件夹下的 yolov5s.param
和 yolov5s.bin
然后接着修改源码文件 yolov5ncnn_jni.cpp
,修改2个 Permute
节点的 output
最后,修改 class names
重新编译工程,连上手机,安装 apk
并运行
最后的检测效果如下
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
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
版本号,再次同步
Cause: jcenter.bintray.com:443 failed to respond
这个问题可能跟代理相关,在 File
–> Settings
–> HTTP Proxy
,关闭代理
或者编辑文件 ~\.gradle\gradle.properties
,将 proxy
相关的语句注释掉
另一个错误,是在编译 ncnn
的时候,出现 tiff
相关的错误信息
这里主要是 anaconda
的环境与系统环境冲突导致,我的做法是完全退出 anaconda
环境,从而去使用系统的环境,那么就可以通过 apt
去安装对应的库了
conda deactivate
unset LD_LIBRARY_PATH
最后一个问题,模型转换经常碰到的错误
这个错误是 yolov5ncnn_jni.cpp
中的 output
没有和实际模型匹配起来导致的
源码下载
链接:https://pan.quark.cn/s/302b8d81b3b7