实践教程 | 详细记录insightface的SCRFD人脸检测ncnn实现
来源 | https://zhuanlan.zhihu.com/p/372332267
编辑 | 极市平台
极市导读
本文详细记录了insightface的SCRFD人脸检测ncnn实现过程。>>加入极市CV技术交流群,走在计算机视觉的最前沿
0x0 SCRFD 人脸检测
SCRFD 是高效率高精度人脸检测算法,2021年5月刚发出来的,速度和精度相比其他算法都有提升!
deepinsight / insightface地址:https://github.com/deepinsight/insightface/tree/master/detection/scrfd
Sample and Computation Redistribution for Efficient Face Detection地址:https://arxiv.org/abs/2105.04714
总所周知,insightface 是业界名气响当当的人脸算法开源项目,也是 mxnet 框架苟到今日的重要原因。
现在,pytorch 大法好!
0x1 缘由
那天下午,insightface 作者 过客 大佬小窗敲了我
SCRFD 是用 pytorch + mmdet 做的,看看 github 上好像也缺一个 mmdet 部署 ncnn 的项目
这里就用 SCRFD 作为例子,介绍下如何转换模型,后处理实现细节,android 和 web 端移植
0x2 配环境
系统是 fedora 34,gcc 11.1.1,python 3.9,nvidia-driver 465.27,cuda 11.3
安装 pytorch torchvision onnx-simplifier
pip install -U torch --user
pip install -U torchvision --user
pip install -U onnx-simplifier --user
安装 thrust
git clone https://github.com/NVIDIA/thrust.git
cd thrust
git submodule update --init --recursive
mkdir build
cd build
cmake -DTHRUST_ENABLE_HEADER_TESTING=OFF -DTHRUST_ENABLE_TESTING=OFF -DTHRUST_ENABLE_EXAMPLES=OFF ..
make -j8
sudo make install
我的 fedora 系统得改 /usr/share/cmake/Modules/CMakeDetermineCUDACompiler.cmake 注释190行 FATAL_ERROR
才可正常编译
安装 mmcv
export MMCV_CUDA_ARGS='-ccbin=/usr/bin/cuda-gcc'
pip install mmcv-full --user
我的 fedora 系统得改 /home/nihui/.local/lib/python3.9/site-packages/torch/utils/cpp_extension.py include_paths
附加 /usr/include/cuda
才可正常编译
安装依赖和 mmdet
按照 SCRFD README 步骤进行即可
git clone https://github.com/deepinsight/insightface.git
cd insightface/detection/scrfd
pip install -r requirements/build.txt --user
pip install -v -e . --user
0x3 转模型
下载 pth模型
下载 pretrained 模型 SCRFD_500M
deepinsight/insightface:https://github.com/deepinsight/insightface/tree/master/detection/scrfd%23pretrained-models
pytorch 测试模型
python demo/image_demo.py nihui.jpg configs/scrfd/scrfd_500m.py model.pth
成功啦
导出 onnx
python tools/scrfd2onnx.py configs/scrfd/scrfd_500m.py model.pth --shape 640 640 --input-img nihui.jpg
使用固定 shape 输入可以更好的清除 onnx 胶水op,也不影响后续 ncnn 的动态 shape 输入推理,因此推荐总是使用固定 shape 导出 onnx
onnx 文件会被存放在 onnx/scrfd_500m_shape640x640.onnx
onnx 转 ncnn
onnx2ncnn scrfd_500m_shape640x640.onnx scrfd_500m.param scrfd_500m.bin
ncnnoptimize scrfd_500m.param scrfd_500m.bin scrfd_500m-opt.param scrfd_500m-opt.bin 1
没有任何报错,groupnorm 也能正常转换出来
手改 param,支持动态 shape 推理
Interp 固定参数改为按系数放大
手改 param,head 输出部分修复
检测模型中,经常看到最后输出会有 transpose reshape 这样的组合,对输出数据做重排
实际可以不做重排,节省重排的时间,直接对原本的数据布局做后处理,关注数据布局的物理意义
score 的 shape channel 为 2,即 2种 anchor ratio * 1个 prob人脸分类置信度 bbox 的 shape channel 为 8,即 2种 anchor ratio * 4个 bbox偏移 kps 的 shape channel 为 20,即 2种 anchor ratio * 5个 xy点坐标偏移 score bbox kps 的 shape width height,即 xy 就是当前图片里对应的 anchor grid xy 下标
Permute
Reshape
Reshape
替换为 Noop
Noop
Noop
Noop
改完后再执行一遍 ncnnoptimize,能自动清除 Noop
ncnnoptimize scrfd_500m-opt.param scrfd_500m-opt.bin scrfd_500m-opt2.param scrfd_500m-opt2.bin 1
0x4 实现 SCRFD
实现动态输入
SCRFD 的超参数都在 insightface/detection/scrfd/configs/scrfd/scrfd_500m.py 文件里
看 anchor_generator
设置可以得知,anchor 最小为 16x16,最大为 512x512,因此将图片缩放到长边为 640 是合理的
anchor stride 最大为 32,因此将输入图片的长宽补到 32 倍数是合理的
预处理的 mean norm 值可从 transforms
设置中获得
实现后处理
后处理实现的时候,以之前 retinaface.cpp 代码做模板,针对 mmdet SCRFD 的配置做些修改
anchor 的 center 起始值改为 (0,0),这是 mmdet 默认配置,参考 insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py bbox 和关键点的计算,retinaface 的计算类似 mmdet 的 delta_xywh_bbox_coder,SCRFD 的计算方式是 anchor_center + x * stride
,参考 insightface/detection/scrfd/mmdet/models/dense_heads/scrfd_head.py_get_bboxes_single()
函数
https://github.com/Tencent/ncnn/blob/master/examples/scrfd.cppgithub.com/Tencent/ncnn/blob/master/examples/scrfd.cpp
0x5 实现 android 摄像头实时检测
基于模板工程
nihui/ncnn-android-nanodet:https://github.com/nihui/ncnn-android-nanodet
全局字符串替换 nanodet 为 scrfd
修改 app/src/main/jni/scrfdncnn.cpp 中的 void MyNdkCamera::on_image_render(cv::Mat& rgb) const
实现,替换为调用 scrfd 检测scrfd.cpp 直接从 examples/scrfd.cpp 拿来,封装为类, ncnn::Mat::from_pixels_resize
的 pixel 类型从 PIXEL_BGR2RGB 改为 PIXEL_RGB把 scrfd 的全部模型都转出来,手改 param 统一了输出层的 blob 名字为 bbox_8 bbox_16 bbox_32 这样子,放在 assets 文件夹里 app/src/main/jni/scrfdncnn.cpp 和 app/src/main/res/values/strings.xml 文件里增加各个模型的名字
nihui/ncnn-android-scrfd:https://github.com/nihui/ncnn-android-scrfd
外网android apk安装包下载:
https://github.com/nihui/ncnn-android-scrfd/releases/download/v1/com.tencent.scrfdncnn-release.apk
有关键点的2.5g模型在手机上可以实时检测
0x6 实现 web 摄像头实时检测
基于模板工程
nihui/ncnn-webassembly-nanodet:https://github.com/nihui/ncnn-webassembly-nanodet
全局字符串替换 nanodet 为 scrfd
修改 scrfdncnn.cpp 中的 static void on_image_render(cv::Mat& rgba)
实现,替换为调用 scrfd 检测scrfd.cpp 直接从 examples/scrfd.cpp 拿来,封装为类, ncnn::Mat::from_pixels_resize
的 pixel 类型从 PIXEL_BGR2RGB 改为 PIXEL_RGBA2RGB把 scrfd_500m 模型放在 assets 文件夹里
https://nihui/ncnn-webassembly-scrfd
外网直接体验网址:
https://nihui.github.io/ncnn-webassembly-scrfd
i5-8250U 笔记本电脑 firefox 浏览器里 web 实时检测
0x7 总结
最耗费精力的是实现后处理,因为这需要一些 mmdet 和算法本身的知识,这也许是不懂算法不会训模型的算法优化工程师唯一的门槛 android 和 web 端都准备好了模板工程,以及很方便的 on_image_render
接口,配备了 opencv 和 ncnn 预编译库,从 linux cpp 移植轻松许多web 端检测兼容任意pc和手机浏览器,包括qq/微信内置的webview,chrome体验最佳 ncnn 的主页 readme 有 qq 群,欢迎加入。
如果觉得有用,就请分享到朋友圈吧!
公众号后台回复“transformer”获取最新Transformer综述论文下载~
# CV技术社群邀请函 #
备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)
即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群
每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~