C++到Python全搞定,教你如何為FastDeploy貢獻程式碼
大家好!今天為大家帶來的是一篇經驗帖文。本次分享的主人公是黑客鬆比賽參賽者鄭必城,他將為大家帶來比賽專案“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主頁
-
No.80瑞芯微RK3588:通過Paddle2ONNX打通5個飛槳模型的部署連結
https://github.com/PaddlePaddle/Paddle/issues/44068
FastDeploy簡介
FastDeploy是一款全場景、易用靈活、極致高效的AI推理部署工具,提供開箱即用的雲邊端部署體驗,支援超過150+文字、計算機視覺、語音和跨模態模型,並實現端到端的推理效能優化。其應用於影象分類、物體檢測、影象分割、人臉檢測、人臉識別、關鍵點檢測、摳圖、OCR、NLP、TTS等任務,滿足開發者多場景、多硬體、多平臺的產業部署需求。同時,FastDeploy集成了多種後端推理引擎,其中就包括RKNPU2。開發者能夠快速基於現有的模型以及後端來進行開發。
很多開發者可能會有疑惑,為什麼Rockchip提供了RKNPU2和rknn-toolkit2這兩個分別面向C++和Python的推理引擎,我們還要使用FastDeploy進行開發呢?簡單來說,RKNPU2和rknn-toolkit2是推理引擎,它們側重於推理;FastDeploy是推理部署工具側重於部署。給RKNPU2輸入一張圖片,會得到一串數字。給FastDeploy輸入一張圖片,會直接得到經過後處理後的圖片。這樣就能大大減少開發者在專案落地過程中的一些困難。
-
RKNPU2
-
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.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
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.txt。CMakeLists.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/PaddlePaddle/FastDeploy
[2]Guo J , Deng J , Lattas A , et al. Sample and Computation Redistribution for Efficient Face Detection[J]. 2021.
- 基於飛槳實現的特定領域知識圖譜融合方案:ERNIE-Gram 文字匹配演算法
- 文心一言:這48小時,我被問了xxxx個問題
- 百度生成式AI產品文心一言邀請測試,五大場景、五大能力革新生產力工具
- 成為AI架構師的三大能力
- 動轉靜兩大升級!一鍵轉靜成功率領先,重點模型訓練提速18%
- 即刻報名!飛槳黑客馬拉松第四期如約而至,等你挑戰
- 文心一言,3月16日見!
- 百度集團副總裁吳甜釋出文心大模型最新升級,AI應用步入新階段
- PGLBox全面解決圖訓練速度、成本、穩定性、複雜演算法四大問題!
- C 到Python全搞定,教你如何為FastDeploy貢獻程式碼
- 飛槳框架v2.4 API新升級!全面支援稀疏計算、圖學習、語音處理等任務
- 10w 訓練標籤?成本太高!PaddleNLP情感分析賦能消費“回暖”
- 文心ERNIE 3.0 Tiny新升級!端側壓縮部署“小” “快” “靈”!
- 帶你零門檻掌握基於大模型技術的AIGC場景應用
- 從百度飛槳YOLOSeries庫看各個YOLO模型
- 30分鐘使用百度EasyDL實現健康碼/行程碼智慧識別
- 智慧健身動作識別:PP-TinyPose打造AI虛擬健身教練!
- 超大規模的產業實用語義分割資料集PSSL與預訓練模型開源啦!
- 使用百度 EasyDL 實現電動車進電梯自動預警
- 中國信通院報告:百度飛槳超越TensorFlow和PyTorch,居中國市場應用規模第一