关于paddle:C到Python全搞定教你如何为FastDeploy贡献代码

47次阅读

共计 11399 个字符,预计需要花费 29 分钟才能阅读完成。

大家好!明天为大家带来的是一篇教训帖文。本次分享的主人公是黑客松较量参赛者郑必城,他将为大家带来比赛项目“No.80 瑞芯微 RK3588:通过 Paddle2ONNX 买通 5 个飞桨模型的部署中如何为 FastDeploy”工作中的一些心得体会,快来看看他是如何为 FastDeploy 奉献代码的吧!

RKNPU2 是瑞芯微 Rockchip 推出的针对 RK356X/RK3588/RV1103/RV1106 的 C ++ 推理工具。在加入黑客松较量时,FastDeploy 仓库 [1] 还没有集成 RKNPU2 的引擎。开发者须要应用 RKNPU2 从头编写代码。在加入完黑客松之后,我为 FastDeploy 仓库奉献了 RKNPU2 的后端推理引擎的代码,当初能间接应用 FastDeploy 疾速开发基于 RKNPU2 的代码。本次教程将以奉献 SCRFD 模型 [2] 为例,教你如何给 FastDeploy 奉献代码。

  • Zheng_Bicheng 主页

    https://github.com/Zheng-Bicheng

  • No.80 瑞芯微 RK3588:通过 Paddle2ONNX 买通 5 个飞桨模型的部署链接

    https://github.com/PaddlePadd…

FastDeploy 简介

FastDeploy 是一款全场景、易用灵便、极致高效的 AI 推理部署工具,提供开箱即用的云边端部署体验,反对超过 150+ 文本、计算机视觉、语音和跨模态模型,并实现端到端的推理性能优化。其利用于图像分类、物体检测、图像宰割、人脸检测、人脸识别、关键点检测、抠图、OCR、NLP、TTS 等工作,满足开发者多场景、多硬件、多平台的产业部署需要。同时,FastDeploy 集成了多种后端推理引擎,其中就包含 RKNPU2。开发者可能疾速基于现有的模型以及后端来进行开发。

很多开发者可能会有纳闷,为什么 Rockchip 提供了 RKNPU2rknn-toolkit2这两个别离面向 C ++ 和 Python 的推理引擎,咱们还要应用 FastDeploy 进行开发呢?简略来说,RKNPU2 和 rknn-toolkit2 是推理引擎,它们侧重于推理;FastDeploy 是推理部署工具侧重于部署。给 RKNPU2 输出一张图片,会失去一串数字。给 FastDeploy 输出一张图片,会间接失去通过后处理后的图片。这样就能大大减少开发者在我的项目落地过程中的一些艰难。

  • RKNPU2

    https://github.com/rockchip-linux/rknpu2

  • rknn-toolkit2

    https://github.com/rockchip-linux/rknn-toolkit2

奉献步骤

给 FastDeploy 奉献代码,我个别按以下步骤进行,当然你能够依据本人的能力制订本人的开发步骤。

由上图所示,给 FastDeploy 奉献代码的步骤个别为编写 C ++ 代码、编写 C ++ example、编写 Python 代码、编写 Python example 代码、编写文档、提交 PR。

奉献代码指南

上面我以奉献 SCRFD 模型为例子,给大家具体介绍每个奉献环节中的注意事项。

转换模型

不论你是在 FastDeploy 上开发 C ++ 还是 Python 的代码,转换模型都是你首先须要实现的工作。通常状况下,转换模型的工具个别应用 rknn-toolkit2,然而这个工具 API 比拟多,用起来较为简单。为了让大家可能更疾速的转换模型,在 FastDeploy 中,我曾经编写了转换模型的代码并且提供了具体的文档。详情请查看 FastDeploy RKNPU2 模型转换文档。这里为了缩短篇幅,间接给出模型转换的配置文件以及模型转换的文档。大家能够参考这几个文档转换本人的模型。

  • FastDeploy RKNPU2 模型转换文档

    https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/rknpu2/export.md

  • 模型转换的文档

    https://github.com/PaddlePaddle/FastDeploy/tree/develop/examples/vision/facedet/scrfd/rknpu2

编写 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

    https://github.com/PaddlePaddle/FastDeploy/blob/develop/fastdeploy/vision/facedet/contrib/scrfd.h

#pragma once
#include <unordered_map>
#include "fastdeploy/fastdeploy_model.h"
#include "fastdeploy/vision/common/processors/transform.h"
#include "fastdeploy/vision/common/result.h"
namespace fastdeploy {
namespace vision {
namespace facedet {
class FASTDEPLOY_DECL SCRFD : public FastDeployModel {
 public:
  SCRFD(const std::string& model_file, const std::string& params_file = "",
        const RuntimeOption& custom_option = RuntimeOption(), const ModelFormat& model_format = ModelFormat::ONNX);
  std::string ModelName() const { return "scrfd";}
  virtual bool Predict(cv::Mat* im, FaceDetectionResult* result, float conf_threshold = 0.25f, float nms_iou_threshold = 0.4f);
 private:
  bool Initialize();
  bool Preprocess(Mat* mat, FDTensor* output, std::map<std::string, std::array<float, 2>>* im_info);
  bool Postprocess(std::vector<FDTensor>& infer_result, FaceDetectionResult* result, const std::map<std::string, std::array<float, 2>>& im_info, float conf_threshold, float nms_iou_threshold);
};
}  // namespace facedet
}  // namespace vision
}  // namespace fastdeploy
  • 编写 scrfd.cc

scrfd.cc 负责对在 scrfd.h 中申明的函数进行了实现。在编写预处理的过程中要留神,RKNPU2 目前仅反对 NHWC 格局的输出数据,因而必须屏蔽 Permute 操作。我这里应用 disable_permute_ 变量管制Permute 操作。此外因为 FastDeploy 采纳的是 RKNPU2 的零拷贝流程来实现后端的解决和运算,因而能够思考将 Normalize 操作放在 NPU 上来做,晋升速度,我这里应用 disable_normalize_ 变量管制Normalize 的开关。如果须要具体的代码,请拜访以下链接。

  • 代码链接

    https://github.com/PaddlePaddle/FastDeploy/blob/develop/fastdeploy/vision/facedet/contrib/scrfd.cc

#include "fastdeploy/vision/facedet/contrib/scrfd.h"
#include "fastdeploy/utils/perf.h"
#include "fastdeploy/vision/utils/utils.h"
namespace fastdeploy {
namespace vision {
namespace facedet {bool SCRFD::Preprocess(Mat* mat, FDTensor* output, std::map<std::string, std::array<float, 2>>* im_info) {return true;}

bool SCRFD::Postprocess(std::vector<FDTensor>& infer_result, FaceDetectionResult* result, const std::map<std::string, std::array<float, 2>>& im_info, float conf_threshold, float nms_iou_threshold) {return true;}

bool SCRFD::Predict(cv::Mat* im, FaceDetectionResult* result, float conf_threshold, float nms_iou_threshold) {return true;}
}  // namespace facedet
}  // namespace vision
}  // namespace fastdeploy
  • 在 vision.h 中增加咱们的模型

咱们编写完 scrfd 的代码之后,咱们还须要让 FastDeploy 晓得咱们曾经编写了 scrfd 代码,因而咱们须要在 fastdeploy/vision.h 文件中补充 scrfd.h 头文件的门路。

编译 FastDeploy C++ SDK

编写完 C ++ 代码后,咱们须要编译 C ++ 版本的 FastDeploy。一是为了测试咱们编写的代码是否有程序上的破绽,二是为了后续编写 example 能够链接 FastDeploy 编译进去的动静库。编译的细节详情请参考 FastDeploy C++ 代码编译指南。

  • FastDeploy C++ 代码编译指南

    https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/rknpu2/build.md

这里间接给出编译时的命令:

git clone https://github.com/PaddlePaddle/FastDeploy.git
cd FastDeploy
mkdir build && cd build
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
make install

编写 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"
void RKNPU2Infer(const std::string& model_dir, const std::string& image_file) {auto model = fastdeploy::vision::facedet::SCRFD(model_file, params_file, option, format);
  model.Initialized();
  model.DisableNormalize();
  model.DisablePermute();
  auto im = cv::imread(image_file);
  fastdeploy::vision::FaceDetectionResult res;
  model.Predict(&im, &res)
  auto vis_im = fastdeploy::vision::VisFaceDetection(im, res);
  cv::imwrite("infer_rknn.jpg", vis_im);
  std::cout << "Visualized result saved in ./infer_rknn.jpg" << std::endl;
}

int main(int argc, char* argv[]) {if (argc < 3) {
    std::cout
        << "Usage: infer_demo path/to/model_dir path/to/image run_option,"
           "e.g ./infer_model ./picodet_model_dir ./test.jpeg"
        << std::endl;
    return -1;
  }

  RKNPU2Infer(argv[1], argv[2]);
  return 0;
}
  • 编写 CMakeLists.txt

编写完 C ++ example 的代码后,咱们还须要编写 CMakeLists.txtCMakeLists.txt 相当于编译时的配置文件,负责链接 infer_model_name.cc 和 FastDeploy 的动静库,并且把模型推理须要用到的货色集成在 install 目录下。

CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
project(rknpu_test)
set(CMAKE_CXX_STANDARD 14)
# 指定下载解压后的 fastdeploy 库门路
set(FASTDEPLOY_INSTALL_DIR "thirdpartys/fastdeploy-0.7.0")
include(${FASTDEPLOY_INSTALL_DIR}/FastDeployConfig.cmake)
include_directories(${FastDeploy_INCLUDE_DIRS})
add_executable(rknpu_test infer.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"
namespace fastdeploy {void BindSCRFD(pybind11::module& m) {
  // Bind SCRFD
  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,
              float conf_threshold, float nms_iou_threshold) {auto mat = PyArrayToCvMat(data);
             vision::FaceDetectionResult res;
             self.Predict(&mat, &res, conf_threshold, nms_iou_threshold);
             return res;
           })
      .def("disable_normalize",&vision::facedet::SCRFD::DisableNormalize)
      .def("disable_permute",&vision::facedet::SCRFD::DisablePermute);
}
}  // namespace fastdeploy
  • 在 facedet_pybind.cc 中增加申明

和在 vision.h 文件中增加申明一样,在编写完 pybind 代码之后,咱们还须要在 fastdeploy/vision/facedet/facedet_pybind.cc 中增加申明。目标是通知编译器咱们曾经编写了 pybind 的代码,并且在编译 Python 时请把咱们的代码加上。外围代码如下:

#include "fastdeploy/pybind/main.h"
namespace fastdeploy {void BindSCRFD(pybind11::module& m);
void BindFaceDet(pybind11::module& m) {auto facedet_module = m.def_submodule("facedet", "Face detection models.");
  BindSCRFD(facedet_module);
}
}
  • 编写 scrfd.py

编写完 pybind.cc 后,咱们还须要编写对应的 py 文件调用 pybind 裸露进去的 C ++ API。代码如下

from __future__ import absolute_import
import logging
from .... import FastDeployModel, ModelFormat
from .... import c_lib_wrap as C
class SCRFD(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)
        assert self.initialized, "SCRFD initialize failed."

    def predict(self, input_image, conf_threshold=0.7, nms_iou_threshold=0.3):
        return self._model.predict(input_image, conf_threshold, nms_iou_threshold)

编译 FastDeploy Python SDK

编写 example 之前咱们必定须要编译 Python 版本的 FastDeploy 代码,请参考 FastDeploy RKNPU2 编译指南编译 Python 版本的 FastDeploy。

  • FastDeploy RKNPU2 编译指南

    https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/rknpu2/build.md

这里给出我常常应用的编译命令:

cd FastDeploy
cd python
export ENABLE_ORT_BACKEND=ON
export ENABLE_RKNPU2_BACKEND=ON
export ENABLE_VISION=ON
export RKNN2_TARGET_SOC=RK3588
python3 setup.py build
python3 setup.py bdist_wheel
cd dist
pip3 install fastdeploy_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 函数进行解决,最初应用对应的可视化函数进行可视化。

import fastdeploy as fd
import cv2
import os
def parse_arguments():
    import argparse
    import ast
    parser = argparse.ArgumentParser()
    parser.add_argument("--model_file", required=True, help="Path of FaceDet model.")
    parser.add_argument("--image", type=str, required=True, help="Path of test image file.")
    return parser.parse_args()
def build_option(args):
    option = fd.RuntimeOption()
    option.use_rknpu2()
    return option
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("Visualized result save in ./visualized_result.jpg")

编写文档以及提交 pr

请参考 SCRFD example 编写 模型的转换文档、模型的 cpp example 运行文档、模型的 python 运行文档 共三份文档,而后向 FastDeploy 的 Github 仓库提交 PR。待审核过后,你的奉献就会被记录啦。

  • SCRFD example

    https://github.com/PaddlePaddle/FastDeploy/tree/develop/examples/vision/facedet/scrfd/rknpu2

总结

在飞桨做开源奉献的体验是无可比拟的,首先可能疾速实现编程能力晋升,在奉献代码的过程中,你会更加粗浅的了解书本上的内容,把握行业前沿的代码逻辑和编程标准。同时在开发过程中,你还会意识飞桨研发团队的同学以及很多气味相投的好友,与他们独特发明一些乏味的成绩,在修复 bug 的过程中体验成就感。欢送和我一起退出奉献代码的行列。

参考文献

[1]https://github.com/PaddlePadd…

[2]Guo J , Deng J , Lattas A , et al. Sample and Computation Redistribution for Efficient Face Detection[J]. 2021.

正文完
 0