C++到Python全搞定,教你如何为FastDeploy贡献代码

咱们好,我是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供给了RKNPU2rknn-toolkit2这两个别离面向C++和Python的推理引擎,咱们还要运用FastDeploy进行开发呢?简略来说,RKNPU2和rknn-toolkit2是推理引擎,它们侧重于推理;FastDeploy是推理布置东西侧重于布置。给RKNPU2输入一张图片,会得到一串数字。给FastDeploy输入一张图片,会直接得到通过后处理后的图片。这样就能大大减少开发者在项目落地过程中的一些困难。

  • RKNPU2

    github.com/rockchip-li…

  • rknn-toolkit2

    github.com/rockchip-li…

奉献过程

给FastDeploy奉献代码,我一般按以下过程进行,当然你能够依据自己的才能拟定自己的开发过程。

C++到Python全搞定,教你如何为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.hscrfd.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&params_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.txtCMakeLists.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.