咱们好,我是Zheng_Bicheng。很高兴和咱们分享黑客松比赛中“No.80瑞芯微RK3588:通过Paddle2ONNX打通5个飞桨模型的布置”任务的一些心得体会。
RKNPU2是瑞芯微Rockchip推出的针对RK356X/RK3588/RV1103/RV1106的C++推理东西。在参加黑客松比赛时,FastDeploy库房[1]还没有集成RKNPU2的引擎。开发者需求运用RKNPU2从头编写代码。在参加完黑客松之后,我为FastDeploy库房奉献了RKNPU2的后端推理引擎的代码,现在能直接运用FastDeploy快速开发基于RKNPU2的代码。本次教程将以奉献SCRFD模型[2]为例,教你如何给FastDeploy奉献代码。
-
Zheng_Bicheng主页
github.com/Zheng-Biche…
-
No.80瑞芯微RK3588:通过Paddle2ONNX打通5个飞桨模型的布置链接
github.com/PaddlePaddl…
FastDeploy简介
FastDeploy是一款全场景、易用灵活、极致高效的AI推理布置东西,供给开箱即用的云边端布置体验,支撑超过150+文本、计算机视觉、语音和跨模态模型,并完结端到端的推理性能优化。其应用于图像分类、物体检测、图像切割、人脸检测、人脸辨认、要害点检测、抠图、OCR、NLP、TTS等任务,满足开发者多场景、多硬件、多渠道的工业布置需求。一起,FastDeploy集成了多种后端推理引擎,其中就包含RKNPU2。开发者能够快速基于现有的模型以及后端来进行开发。
很多开发者可能会有疑问,为什么Rockchip供给了RKNPU2和rknn-toolkit2这两个别离面向C++和Python的推理引擎,咱们还要运用FastDeploy进行开发呢?简略来说,RKNPU2和rknn-toolkit2是推理引擎,它们侧重于推理;FastDeploy是推理布置东西侧重于布置。给RKNPU2输入一张图片,会得到一串数字。给FastDeploy输入一张图片,会直接得到通过后处理后的图片。这样就能大大减少开发者在项目落地过程中的一些困难。
-
RKNPU2
github.com/rockchip-li…
-
rknn-toolkit2
github.com/rockchip-li…
奉献过程
给FastDeploy奉献代码,我一般按以下过程进行,当然你能够依据自己的才能拟定自己的开发过程。
由上图所示,给FastDeploy奉献代码的过程一般为编写C++代码、编写C++ example、编写Python代码、编写Python example代码、编写文档、提交PR。
奉献代码攻略
下面我以奉献SCRFD模型为例子,给咱们具体介绍每个奉献环节中的注意事项。
转化模型
不管你是在FastDeploy上开发C++仍是Python的代码,转化模型都是你首先需求完结的任务。通常情况下,转化模型的东西一般运用rknn-toolkit2,可是这个东西API比较多,用起来较为杂乱。为了让咱们能够更快速的转化模型,在FastDeploy中,我现已编写了转化模型的代码而且供给了具体的文档。详情请检查FastDeploy RKNPU2模型转化文档。这儿为了缩短篇幅,直接给出模型转化的配置文件以及模型转化的文档。咱们能够参考这几个文档转化自己的模型。
-
FastDeploy RKNPU2模型转化文档
github.com/PaddlePaddl…
-
模型转化的文档
github.com/PaddlePaddl…
编写C++代码
上文说到,SCRFD的C++代码需求在fastdeploy/vision/facedet/contrib这个目录下编写,因而我创建了scrfd.h和scrfd.cc这两个文件,完结模型具体代码。这儿要注意与常见的文件命名形式不同,scrfd.cc这个C++代码文件的后缀不是 .cpp而是 .cc ,如果scrfd.cc改为scrfd.cpp将无法成功编译!
- 编写scrfd.h
scrfd.h里界说了SCRFD模型的一些基本参数以及需求重界说的函数。其中界说的SCRFD模型需求继承FastDeployModel这个公共的模型类,为的是继承FastDeploy的一些公共特性。如下面的代码所示,在头文件中,咱们需求重写FastDeployModel中的以下几个函数,包含Initialize、Preprocess、Postprocess、Predict、ModelName。别离对应初始化、预处理、后处理、猜测、模型称号。如果你需求完好具体的代码,请拜访下方链接。
-
scrfd.h
github.com/PaddlePaddl…
#pragmaonce
#include<unordered_map>
#include"fastdeploy/fastdeploy_model.h"
#include"fastdeploy/vision/common/processors/transform.h"
#include"fastdeploy/vision/common/result.h"
namespacefastdeploy{
namespacevision{
namespacefacedet{
classFASTDEPLOY_DECLSCRFD:publicFastDeployModel{
public:
SCRFD(conststd::string&model_file,conststd::string¶ms_file="",
constRuntimeOption&custom_option=RuntimeOption(),constModelFormat&model_format=ModelFormat::ONNX);
std::stringModelName()const{return"scrfd";}
virtualboolPredict(cv::Mat*im,FaceDetectionResult*result,floatconf_threshold=0.25f,floatnms_iou_threshold=0.4f);
private:
boolInitialize();
boolPreprocess(Mat*mat,FDTensor*output,std::map<std::string,std::array<float,2>>*im_info);
boolPostprocess(std::vector<FDTensor>&infer_result,FaceDetectionResult*result,conststd::map<std::string,std::array<float,2>>&im_info,floatconf_threshold,floatnms_iou_threshold);
};
}//namespacefacedet
}//namespacevision
}//namespacefastdeploy
- 编写scrfd.cc
scrfd.cc担任对在scrfd.h中声明的函数进行了完结。在编写预处理的过程中要注意,RKNPU2目前仅支撑NHWC格局的输入数据,因而必须屏蔽Permute操作。我这儿运用disable_permute_ 变量操控Permute操作。此外由于FastDeploy选用的是RKNPU2的零拷贝流程来完结后端的处理和运算,因而能够考虑将Normalize操作放在NPU上来做,提高速度,我这儿运用disable_normalize_ 变量操控Normalize的开关。如果需求具体的代码,请拜访以下链接。
-
代码链接
github.com/PaddlePaddl…
#include"fastdeploy/vision/facedet/contrib/scrfd.h"
#include"fastdeploy/utils/perf.h"
#include"fastdeploy/vision/utils/utils.h"
namespacefastdeploy{
namespacevision{
namespacefacedet{
boolSCRFD::Preprocess(Mat*mat,FDTensor*output,std::map<std::string,std::array<float,2>>*im_info){
returntrue;
}
boolSCRFD::Postprocess(std::vector<FDTensor>&infer_result,FaceDetectionResult*result,conststd::map<std::string,std::array<float,2>>&im_info,floatconf_threshold,floatnms_iou_threshold){
returntrue;
}
boolSCRFD::Predict(cv::Mat*im,FaceDetectionResult*result,floatconf_threshold,floatnms_iou_threshold){
returntrue;
}
}//namespacefacedet
}//namespacevision
}//namespacefastdeploy
- 在vision.h中增加咱们的模型
咱们编写完scrfd的代码之后,咱们还需求让FastDeploy知道咱们现已编写了scrfd代码,因而咱们需求在fastdeploy/vision.h文件中补充scrfd.h头文件的路径。
编译FastDeploy C++ SDK
编写完C++代码后,咱们需求编译C++版别的FastDeploy。一是为了测验咱们编写的代码是否有程序上的漏洞,二是为了后续编写example能够链接FastDeploy编译出来的动态库。编译的细节详情请参考FastDeploy C++代码编译攻略。
-
FastDeploy C++代码编译攻略
github.com/PaddlePaddl…
这儿直接给出编译时的命令:
gitclonehttps://github.com/PaddlePaddle/FastDeploy.git
cdFastDeploy
mkdirbuild&&cdbuild
cmake..-DENABLE_ORT_BACKEND=ON\
-DENABLE_RKNPU2_BACKEND=ON\
-DENABLE_VISION=ON\
-DRKNN2_TARGET_SOC=RK3588\
-DCMAKE_INSTALL_PREFIX=${PWD}/fastdeploy-0.0.3
make-j8
makeinstall
编写C++ example代码
为了调试咱们现已完结的C++代码,以及便利用户运用,在编写完上述代码之后,咱们需求编写对应example的代码来验证咱们的主意是否正确。在编写C++ example时,目录下的文件一般由infer_model_name.cc以及CMakeLists.txt组成。在CMakeLists.txt中需求对不同的infer_model_name.cc生成不同的infer_model_name程序。
- 编写infer.cc
infer.cc首要担任调用FastDeploy的C++代码来对SCRFD进行测验。在上文中,咱们说到vision.h能够让fastdeploy知道咱们现已编写了SCRFD模型。因而在编写example时,咱们只需求包含vision.h,即可让程序知道,咱们现已声明了FastDeploy所有现已完结的视觉模型。针对RKNPU的测验,其流程一般为初始化模型,然后依据转化模型时的配置决议是否需求disable_normalize和disable_permute,随后输入测验图片,调用Predict函数进行处理,最终运用对应的可视化函数进行可视化。
#include<iostream>
#include<string>
#include"fastdeploy/vision.h"
voidRKNPU2Infer(conststd::string&model_dir,conststd::string&image_file){
automodel=fastdeploy::vision::facedet::SCRFD(model_file,params_file,option,format);
model.Initialized();
model.DisableNormalize();
model.DisablePermute();
autoim=cv::imread(image_file);
fastdeploy::vision::FaceDetectionResultres;
model.Predict(&im,&res)
autovis_im=fastdeploy::vision::VisFaceDetection(im,res);
cv::imwrite("infer_rknn.jpg",vis_im);
std::cout<<"Visualizedresultsavedin./infer_rknn.jpg"<<std::endl;
}
intmain(intargc,char*argv[]){
if(argc<3){
std::cout
<<"Usage:infer_demopath/to/model_dirpath/to/imagerun_option,"
"e.g./infer_model./picodet_model_dir./test.jpeg"
<<std::endl;
return-1;
}
RKNPU2Infer(argv[1],argv[2]);
return0;
}
- 编写CMakeLists.txt
编写完C++ example的代码后,咱们还需求编写CMakeLists.txt。CMakeLists.txt相当于编译时的配置文件,担任链接infer_model_name.cc和FastDeploy的动态库,而且把模型推理需求用到的东西集成在install目录下。
CMAKE_MINIMUM_REQUIRED(VERSION3.10)
project(rknpu_test)
set(CMAKE_CXX_STANDARD14)
#指定下载解压后的fastdeploy库路径
set(FASTDEPLOY_INSTALL_DIR"thirdpartys/fastdeploy-0.7.0")
include(${FASTDEPLOY_INSTALL_DIR}/FastDeployConfig.cmake)
include_directories(${FastDeploy_INCLUDE_DIRS})
add_executable(rknpu_testinfer.cc)
target_link_libraries(rknpu_test${FastDeploy_LIBS})
编写Python代码
Python代码的编写首要包含pybind文件的编写以及py本体文件的编写。上文说到,在FastDeploy中,python代码通过调用pybind暴露出的C++ API来进行作业,因而咱们首先需求编写pybind.cc。
- 编写scrfd_pybind.cc
pybind.cc首要担任供给可用的API给Python调用。scrfd_pybind.cc中对SCRFD C++的代码进行了暴露,代码如下:
#include"fastdeploy/pybind/main.h"
namespacefastdeploy{
voidBindSCRFD(pybind11::module&m){
//BindSCRFD
pybind11::class_<vision::facedet::SCRFD,FastDeployModel>(m,"SCRFD")
.def(pybind11::init<std::string,std::string,RuntimeOption,
ModelFormat>())
.def("predict",
[](vision::facedet::SCRFD&self,pybind11::array&data,
floatconf_threshold,floatnms_iou_threshold){
automat=PyArrayToCvMat(data);
vision::FaceDetectionResultres;
self.Predict(&mat,&res,conf_threshold,nms_iou_threshold);
returnres;
})
.def("disable_normalize",&vision::facedet::SCRFD::DisableNormalize)
.def("disable_permute",&vision::facedet::SCRFD::DisablePermute);
}
}//namespacefastdeploy
- 在facedet_pybind.cc中增加声明
和在vision.h文件中增加声明一样,在编写完pybind代码之后,咱们还需求在fastdeploy/vision/facedet/facedet_pybind.cc中增加声明。意图是告知编译器咱们现已编写了pybind的代码,而且在编译Python时请把咱们的代码加上。核心代码如下:
#include"fastdeploy/pybind/main.h"
namespacefastdeploy{
voidBindSCRFD(pybind11::module&m);
voidBindFaceDet(pybind11::module&m){
autofacedet_module=m.def_submodule("facedet","Facedetectionmodels.");
BindSCRFD(facedet_module);
}
}
- 编写scrfd.py
编写完pybind.cc后,咱们还需求编写对应的py文件调用pybind暴露出来的C++ API。代码如下
from__future__importabsolute_import
importlogging
from....importFastDeployModel,ModelFormat
from....importc_lib_wrapasC
classSCRFD(FastDeployModel):
def__init__(self,
model_file,
params_file="",
runtime_option=None,
model_format=ModelFormat.ONNX):
super(SCRFD,self).__init__(runtime_option)
self._model=C.vision.facedet.SCRFD(model_file,params_file,self._runtime_option,model_format)
assertself.initialized,"SCRFDinitializefailed."
defpredict(self,input_image,conf_threshold=0.7,nms_iou_threshold=0.3):
returnself._model.predict(input_image,conf_threshold,nms_iou_threshold)
编译FastDeploy Python SDK
编写example之前咱们肯定需求编译Python版别的FastDeploy代码,请参考FastDeploy RKNPU2编译攻略编译Python版别的FastDeploy。
-
FastDeploy RKNPU2编译攻略
github.com/PaddlePaddl…
这儿给出我常常运用的编译命令:
cdFastDeploy
cdpython
exportENABLE_ORT_BACKEND=ON
exportENABLE_RKNPU2_BACKEND=ON
exportENABLE_VISION=ON
exportRKNN2_TARGET_SOC=RK3588
python3setup.pybuild
python3setup.pybdist_wheel
cddist
pip3installfastdeploy_python-0.0.0-cp39-cp39-linux_aarch64.whl
编写Python example代码
为了调试咱们现已完结的Python代码,以及便利用户运用,在编写完上述scrfd代码之后,咱们需求编写对应example的代码来验证咱们的主意是否正确。在编写Python example时,目录下的文件一般由infer_model_name.py组成。
- 编写infer.py
infer.py 首要担任调用FastDeploy的Python代码来对SCRFD的测验。与C++ example相似,针对RKNPU的测验,其流程一般为初始化模型,然后依据转化模型时的配置决议是否需求disable_normalize和disable_permute,随后输入测验图片,调用Predict函数进行处理,最终运用对应的可视化函数进行可视化。
importfastdeployasfd
importcv2
importos
defparse_arguments():
importargparse
importast
parser=argparse.ArgumentParser()
parser.add_argument("--model_file",required=True,help="PathofFaceDetmodel.")
parser.add_argument("--image",type=str,required=True,help="Pathoftestimagefile.")
returnparser.parse_args()
defbuild_option(args):
option=fd.RuntimeOption()
option.use_rknpu2()
returnoption
args=parse_arguments()
#配置runtime,加载模型
runtime_option=build_option(args)
model_file=args.model_file
params_file=""
model=fd.vision.facedet.SCRFD(model_file,params_file,runtime_option=runtime_option,model_format=fd.ModelFormat.RKNN)
model.disable_normalize()
model.disable_permute()
#猜测图片切割成果
im=cv2.imread(args.image)
result=model.predict(im)
print(result)
#可视化成果
vis_im=fd.vision.vis_face_detection(im,result)
cv2.imwrite("visualized_result.jpg",vis_im)
print("Visualizedresultsavein./visualized_result.jpg")
编写文档以及提交pr
请参考SCRFD example编写模型的转化文档、模型的cpp example运转文档、模型的python运转文档共三份文档,然后向FastDeploy的Github库房提交PR。待审阅过后,你的奉献就会被记载啦。
-
SCRFD example
github.com/PaddlePaddl…
总结
在飞桨做开源奉献的体验是无与伦比的,首先能够快速完结编程才能提高,在奉献代码的过程中,你会更加深入的了解书本上的内容,掌握行业前沿的代码逻辑和编程标准。一起在开发过程中,你还会知道飞桨研发团队的同学以及很多情投意合的好友,与他们共同发明一些风趣的成果,在修正bug的过程中体验成就感。欢迎和我一起加入奉献代码的队伍。
参考文献
[1]github.com/PaddlePaddl…
[2]Guo J , Deng J , Lattas A , et al. Sample and Computation Redistribution for Efficient Face Detection[J]. 2021.