使用ncnn部署yolox詳細(xì)記錄
前言
之前本人使用ncnn部署都是用pnnx版將模型轉(zhuǎn)換為ncnn,但由于ncnn的examples文件夾下沒(méi)有yolox的pnnx版本的c++文件,所以ncnn部署yolox采用onnx版進(jìn)行部署。
本文章為up本人部署時(shí)的理解并記錄過(guò)程,若文章中有不正確的地方,請(qǐng)多批評(píng)指教。
若參考本文章進(jìn)行ncnn部署yolox,需要有以下準(zhǔn)備:
有一個(gè)yolox的模型
已經(jīng)使用cmake成功編譯ncnn
看懂C++和Python
模型轉(zhuǎn)換onnx
根據(jù)yolox的tools路徑下的export_onnx.py文件中的make_parser函數(shù),設(shè)置模型轉(zhuǎn)onnx的參數(shù)

由于up的模型修改yolox的exps/example/yolox_voc路徑下的yolox_voc_s.py文件,修改改文件里的數(shù)據(jù)集目錄以及類別等之后用該文件進(jìn)行模型訓(xùn)練,所以export_onnx.py需要用參數(shù)中的-f 需要指定該文件;
模型訓(xùn)練完后,在yolox的YOLOX_output/yolox_voc_s路徑下有訓(xùn)練好的模型,export_onnx.py需要用參數(shù)中的-c 需要指定使用的模型
所以本人需求運(yùn)行以下命令將模型轉(zhuǎn)換為onnx:
onnx轉(zhuǎn)換ncnn
本人在ncnn路徑下創(chuàng)建build文件夾并在該文件夾下make編譯ncnn,所以編譯之后的ncnn文件夾下的build/tools/onnx路徑下有onnx2ncnn的可執(zhí)行文件。(如果你沒(méi)有tools的文件夾以及可執(zhí)行文件等,你需要通過(guò)cmake成功編譯ncnn)
將onnx文件放入當(dāng)前路徑下(也可放到你喜歡的路徑下),執(zhí)行onnx2ncnn的可執(zhí)行文件,生成ncnn需要的param文件和bin文件

執(zhí)行可執(zhí)行文件,第0個(gè)參數(shù)為可執(zhí)行文件名字,第一個(gè)參數(shù)是onnx文件,第二個(gè)參數(shù)是生成的param的名字,第三個(gè)參數(shù)是生成bin文件的名字,執(zhí)行代碼如下:
執(zhí)行后不出意外的話就要出意外了,程序會(huì)報(bào)“Unsupported slice step !”的錯(cuò)誤 ,并且也生成了我們需要的param文件和bin文件

根據(jù)ncnn的examples路徑下的yolox.cpp文件中,我們能看到代碼中的注釋寫著用著跟yolov5相同的focus,并且在ncnn加載模型前也先注冊(cè)了YoloV5Focus


所以yolox的這個(gè)錯(cuò)誤,我們可以跟yolov5一樣手工修復(fù)param,把ncnn不支持的算子替換掉,這里我們可以參考nihui大佬的文章(https://zhuanlan.zhihu.com/p/275989233)
我們通過(guò)netron打開yolox.param文件,需要將紅框內(nèi)刪除并換成YoloV5Focus

點(diǎn)擊split,查看到split輸入的是images

點(diǎn)擊concat,查看到conca輸出的是683

所以我們自定義的YoloV5Focus算子,它的輸入是images,輸出是683,并且是一個(gè)輸入一個(gè)輸出。
我們用記事本或者vscode打開param文件,找到split、crop、concat并刪除

在原來(lái)的位置插入YoloV5Focus,并且寫入1個(gè)輸入,1個(gè)輸出,輸入的名字,輸出的名字,如下圖所示:

由于我們?cè)趐aram文件里刪除了10行,再自己寫了1行,所以根據(jù)本人的文件里的第二行第一個(gè)參數(shù)需要改成286(295-10+1)

修改完成后保存并替換原來(lái)的param文件,再進(jìn)入ncnn的build/tools路徑下,執(zhí)行以下代碼使用 ncnnoptimize 工具修正模型,順便轉(zhuǎn)為 fp16 存儲(chǔ)減小模型體積。
執(zhí)行成功結(jié)果如下:

通過(guò)netron查看修改后的模型,發(fā)現(xiàn)已經(jīng)成功轉(zhuǎn)換了模型的算子了

xiug
修改yolox.cpp文件
最后我們根據(jù)自己的需求修改yolox.cpp文件了
我們先修改加載模型的路徑,并且由于我是在輕量級(jí)服務(wù)器跑的,所以不需要使用gpu得把
yolox.opt.use_vulkan_compute修改成false

還需要把修改類別,改成你的模型需要的

由于我在服務(wù)器跑ncnn,服務(wù)器沒(méi)有桌面版Linux,所以把顯示推理后圖片改成保存推理后圖片

修改完覆蓋ncnn的examples路徑下的yolox.cpp文件,并重新用cmake編譯ncnn,編譯完成如下圖:

結(jié)果測(cè)試
我們打開ncnn的build/examples路徑下將編譯生成的yolox可執(zhí)行文件復(fù)制到你想要的路徑下(嫌麻煩也可以直接用),以我本人為例,將可執(zhí)行文件復(fù)制到存放模型的文件夾里

執(zhí)行可執(zhí)行文件,第0個(gè)參數(shù)為可執(zhí)行文件名字,第一個(gè)參數(shù)為需要推理的圖片,推理完成后生成推理后的圖片(如果你沒(méi)改opencv為保存圖片的話就是圖片直接顯示)

打開推理后的圖片

總結(jié)
自此,ncnn部署yolox完畢!相信你已經(jīng)完全掌握了ncnn部署yolox和yolov5的步驟。
如果你訓(xùn)練的模型在ncnn里面有可以使用pnnx版的話,通過(guò)pnnx轉(zhuǎn)換為ncnn會(huì)方便很多。
nihui大佬yyds!
參考文章
https://zhuanlan.zhihu.com/p/275989233
https://zhuanlan.zhihu.com/p/471357671