实践教程 | 详细记录insightface的SCRFD人脸检测ncnn实现

共 5570字,需浏览 12分钟

 ·

2021-12-18 21:32

↑ 点击蓝字 关注极市平台

作者 | nihui@知乎
来源 | 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 的配置做些修改

  1. anchor 的 center 起始值改为 (0,0),这是 mmdet 默认配置,参考 insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py
  2. 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 摄像头实时检测

  1. 基于模板工程

nihui/ncnn-android-nanodet:https://github.com/nihui/ncnn-android-nanodet

全局字符串替换 nanodet 为 scrfd

  1. 修改 app/src/main/jni/scrfdncnn.cpp 中的 void MyNdkCamera::on_image_render(cv::Mat& rgb) const 实现,替换为调用 scrfd 检测
  2. scrfd.cpp 直接从 examples/scrfd.cpp 拿来,封装为类,ncnn::Mat::from_pixels_resize 的 pixel 类型从 PIXEL_BGR2RGB 改为 PIXEL_RGB
  3. 把 scrfd 的全部模型都转出来,手改 param 统一了输出层的 blob 名字为 bbox_8 bbox_16 bbox_32 这样子,放在 assets 文件夹里
  4. 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 摄像头实时检测

  1. 基于模板工程

nihui/ncnn-webassembly-nanodet:https://github.com/nihui/ncnn-webassembly-nanodet

全局字符串替换 nanodet 为 scrfd

  1. 修改 scrfdncnn.cpp 中的 static void on_image_render(cv::Mat& rgba) 实现,替换为调用 scrfd 检测
  2. scrfd.cpp 直接从 examples/scrfd.cpp 拿来,封装为类,ncnn::Mat::from_pixels_resize 的 pixel 类型从 PIXEL_BGR2RGB 改为 PIXEL_RGBA2RGB
  3. 把 scrfd_500m 模型放在 assets 文件夹里

https://nihui/ncnn-webassembly-scrfd

外网直接体验网址:

https://nihui.github.io/ncnn-webassembly-scrfd

i5-8250U 笔记本电脑 firefox 浏览器里 web 实时检测

0x7 总结

  1. 最耗费精力的是实现后处理,因为这需要一些 mmdet 和算法本身的知识,这也许是不懂算法不会训模型的算法优化工程师唯一的门槛
  2. android 和 web 端都准备好了模板工程,以及很方便的 on_image_render 接口,配备了 opencv 和 ncnn 预编译库,从 linux cpp 移植轻松许多
  3. web 端检测兼容任意pc和手机浏览器,包括qq/微信内置的webview,chrome体验最佳
  4. ncnn 的主页 readme 有 qq 群,欢迎加入。

如果觉得有用,就请分享到朋友圈吧!

△点击卡片关注极市平台,获取最新CV干货

公众号后台回复“transformer”获取最新Transformer综述论文下载~


极市干货
课程/比赛:珠港澳人工智能算法大赛保姆级零基础人工智能教程
算法trick目标检测比赛中的tricks集锦从39个kaggle竞赛中总结出来的图像分割的Tips和Tricks
技术综述:一文弄懂各种loss function工业图像异常检测最新研究总结(2019-2020)


CV技术社群邀请函 #

△长按添加极市小助手
添加极市小助手微信(ID : cvmart4)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)


即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群


每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~



觉得有用麻烦给个在看啦~  
浏览 275
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报