實(shí)踐教程 | 詳細(xì)記錄insightface的SCRFD人臉檢測ncnn實(shí)現(xiàn)

來源 | https://zhuanlan.zhihu.com/p/372332267
編輯 | 極市平臺
極市導(dǎo)讀
?本文詳細(xì)記錄了insightface的SCRFD人臉檢測ncnn實(shí)現(xiàn)過程。>>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺的最前沿
0x0 SCRFD 人臉檢測
SCRFD 是高效率高精度人臉檢測算法,2021年5月剛發(fā)出來的,速度和精度相比其他算法都有提升!

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 是業(yè)界名氣響當(dāng)當(dāng)?shù)娜四標(biāo)惴ㄩ_源項(xiàng)目,也是 mxnet 框架茍到今日的重要原因。
現(xiàn)在,pytorch 大法好!
0x1 緣由
那天下午,insightface 作者 過客 大佬小窗敲了我

SCRFD 是用 pytorch + mmdet 做的,看看 github 上好像也缺一個 mmdet 部署 ncnn 的項(xiàng)目
這里就用 SCRFD 作為例子,介紹下如何轉(zhuǎn)換模型,后處理實(shí)現(xiàn)細(xì)節(jié),android 和 web 端移植
0x2 配環(huán)境
系統(tǒng)是 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 系統(tǒng)得改 /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 系統(tǒng)得改 /home/nihui/.local/lib/python3.9/site-packages/torch/utils/cpp_extension.py include_paths 附加 /usr/include/cuda 才可正常編譯
安裝依賴和 mmdet
按照 SCRFD README 步驟進(jìn)行即可
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 轉(zhuǎn)模型
下載 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
成功啦

導(dǎo)出 onnx
python?tools/scrfd2onnx.py?configs/scrfd/scrfd_500m.py?model.pth?--shape?640?640?--input-img?nihui.jpg
使用固定 shape 輸入可以更好的清除 onnx 膠水op,也不影響后續(xù) ncnn 的動態(tài) shape 輸入推理,因此推薦總是使用固定 shape 導(dǎo)出 onnx
onnx 文件會被存放在 onnx/scrfd_500m_shape640x640.onnx
onnx 轉(zhuǎn) 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
沒有任何報(bào)錯,groupnorm 也能正常轉(zhuǎn)換出來
手改 param,支持動態(tài) shape 推理
Interp 固定參數(shù)改為按系數(shù)放大

手改 param,head 輸出部分修復(fù)
檢測模型中,經(jīng)??吹阶詈筝敵鰰?transpose reshape 這樣的組合,對輸出數(shù)據(jù)做重排

實(shí)際可以不做重排,節(jié)省重排的時間,直接對原本的數(shù)據(jù)布局做后處理,關(guān)注數(shù)據(jù)布局的物理意義
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點(diǎn)坐標(biāo)偏移 score bbox kps 的 shape width height,即 xy 就是當(dāng)前圖片里對應(yīng)的 anchor grid xy 下標(biāo)
Permute
Reshape
Reshape
替換為 Noop
Noop
Noop
Noop


改完后再執(zhí)行一遍 ncnnoptimize,能自動清除 Noop
ncnnoptimize?scrfd_500m-opt.param?scrfd_500m-opt.bin?scrfd_500m-opt2.param?scrfd_500m-opt2.bin?1
0x4 實(shí)現(xiàn) SCRFD
實(shí)現(xiàn)動態(tài)輸入
SCRFD 的超參數(shù)都在 insightface/detection/scrfd/configs/scrfd/scrfd_500m.py 文件里
看 anchor_generator 設(shè)置可以得知,anchor 最小為 16x16,最大為 512x512,因此將圖片縮放到長邊為 640 是合理的
anchor stride 最大為 32,因此將輸入圖片的長寬補(bǔ)到 32 倍數(shù)是合理的
預(yù)處理的 mean norm 值可從 transforms 設(shè)置中獲得
實(shí)現(xiàn)后處理
后處理實(shí)現(xiàn)的時候,以之前 retinaface.cpp 代碼做模板,針對 mmdet SCRFD 的配置做些修改
anchor 的 center 起始值改為 (0,0),這是 mmdet 默認(rèn)配置,參考 insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py bbox 和關(guān)鍵點(diǎn)的計(jì)算,retinaface 的計(jì)算類似 mmdet 的 delta_xywh_bbox_coder,SCRFD 的計(jì)算方式是 anchor_center + x * stride,參考 insightface/detection/scrfd/mmdet/models/dense_heads/scrfd_head.py_get_bboxes_single()函數(shù)
https://github.com/Tencent/ncnn/blob/master/examples/scrfd.cppgithub.com/Tencent/ncnn/blob/master/examples/scrfd.cpp
0x5 實(shí)現(xiàn) android 攝像頭實(shí)時檢測
基于模板工程
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實(shí)現(xiàn),替換為調(diào)用 scrfd 檢測scrfd.cpp 直接從 examples/scrfd.cpp 拿來,封裝為類, ncnn::Mat::from_pixels_resize的 pixel 類型從 PIXEL_BGR2RGB 改為 PIXEL_RGB把 scrfd 的全部模型都轉(zhuǎn)出來,手改 param 統(tǒng)一了輸出層的 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
外網(wǎng)android apk安裝包下載:
https://github.com/nihui/ncnn-android-scrfd/releases/download/v1/com.tencent.scrfdncnn-release.apk
有關(guān)鍵點(diǎn)的2.5g模型在手機(jī)上可以實(shí)時檢測

0x6 實(shí)現(xiàn) web 攝像頭實(shí)時檢測
基于模板工程
nihui/ncnn-webassembly-nanodet:https://github.com/nihui/ncnn-webassembly-nanodet

全局字符串替換 nanodet 為 scrfd
修改 scrfdncnn.cpp 中的 static void on_image_render(cv::Mat& rgba)實(shí)現(xiàn),替換為調(diào)用 scrfd 檢測scrfd.cpp 直接從 examples/scrfd.cpp 拿來,封裝為類, ncnn::Mat::from_pixels_resize的 pixel 類型從 PIXEL_BGR2RGB 改為 PIXEL_RGBA2RGB把 scrfd_500m 模型放在 assets 文件夾里
https://nihui/ncnn-webassembly-scrfd
外網(wǎng)直接體驗(yàn)網(wǎng)址:
https://nihui.github.io/ncnn-webassembly-scrfd
i5-8250U 筆記本電腦 firefox 瀏覽器里 web 實(shí)時檢測

0x7 總結(jié)
最耗費(fèi)精力的是實(shí)現(xiàn)后處理,因?yàn)檫@需要一些 mmdet 和算法本身的知識,這也許是不懂算法不會訓(xùn)模型的算法優(yōu)化工程師唯一的門檻 android 和 web 端都準(zhǔn)備好了模板工程,以及很方便的 on_image_render接口,配備了 opencv 和 ncnn 預(yù)編譯庫,從 linux cpp 移植輕松許多web 端檢測兼容任意pc和手機(jī)瀏覽器,包括qq/微信內(nèi)置的webview,chrome體驗(yàn)最佳 ncnn 的主頁 readme 有 qq 群,歡迎加入。
如果覺得有用,就請分享到朋友圈吧!
公眾號后臺回復(fù)“transformer”獲取最新Transformer綜述論文下載~

#?CV技術(shù)社群邀請函?#

備注:姓名-學(xué)校/公司-研究方向-城市(如:小極-北大-目標(biāo)檢測-深圳)
即可申請加入極市目標(biāo)檢測/圖像分割/工業(yè)檢測/人臉/醫(yī)學(xué)影像/3D/SLAM/自動駕駛/超分辨率/姿態(tài)估計(jì)/ReID/GAN/圖像增強(qiáng)/OCR/視頻理解等技術(shù)交流群
每月大咖直播分享、真實(shí)項(xiàng)目需求對接、求職內(nèi)推、算法競賽、干貨資訊匯總、與?10000+來自港科大、北大、清華、中科院、CMU、騰訊、百度等名校名企視覺開發(fā)者互動交流~

