From d19510fe770e5cb22982439b2c7dd65af65b48b0 Mon Sep 17 00:00:00 2001 From: yunyaoXYY <109218879+yunyaoXYY@users.noreply.github.com> Date: Thu, 8 Dec 2022 23:32:14 +0800 Subject: [PATCH 01/77] [Other] Update PP-OCRv2/v3 example. (#838) * Fix links in readme * Fix links in readme * Update PPOCRv2/v3 examples --- examples/vision/ocr/PP-OCRv2/cpp/infer.cc | 17 +++++++++++++--- examples/vision/ocr/PP-OCRv2/python/infer.py | 21 ++++++++++++++++---- examples/vision/ocr/PP-OCRv3/cpp/infer.cc | 18 ++++++++++++++--- examples/vision/ocr/PP-OCRv3/python/infer.py | 21 ++++++++++++++++---- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/examples/vision/ocr/PP-OCRv2/cpp/infer.cc b/examples/vision/ocr/PP-OCRv2/cpp/infer.cc index 7bac320d5..6cde6390f 100644 --- a/examples/vision/ocr/PP-OCRv2/cpp/infer.cc +++ b/examples/vision/ocr/PP-OCRv2/cpp/infer.cc @@ -33,13 +33,18 @@ void InitAndInfer(const std::string& det_model_dir, const std::string& cls_model auto cls_option = option; auto rec_option = option; + // The cls and rec model can inference a batch of images now. + // User could initialize the inference batch size and set them after create PPOCR model. + int cls_batch_size = 1; + int rec_batch_size = 6; + // If use TRT backend, the dynamic shape will be set as follow. // We recommend that users set the length and height of the detection model to a multiple of 32. det_option.SetTrtInputShape("x", {1, 3, 64,64}, {1, 3, 640, 640}, {1, 3, 960, 960}); - cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {10, 3, 48, 320}, {32, 3, 48, 1024}); - rec_option.SetTrtInputShape("x", {1, 3, 32, 10}, {10, 3, 32, 320}, - {32, 3, 32, 2304}); + cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {cls_batch_size, 3, 48, 320}, {cls_batch_size, 3, 48, 1024}); + rec_option.SetTrtInputShape("x", {1, 3, 32, 10}, {rec_batch_size, 3, 32, 320}, + {rec_batch_size, 3, 32, 2304}); // Users could save TRT cache file to disk as follow. // det_option.SetTrtCacheFile(det_model_dir + sep + "det_trt_cache.trt"); @@ -58,6 +63,12 @@ void InitAndInfer(const std::string& det_model_dir, const std::string& cls_model // auto ppocr_v2 = fastdeploy::pipeline::PPOCRv2(&det_model, &rec_model); auto ppocr_v2 = fastdeploy::pipeline::PPOCRv2(&det_model, &cls_model, &rec_model); + // Set inference batch size for cls model and rec model, the value could be -1 and 1 to positive infinity. + // When inference batch size is set to -1, it means that the inference batch size + // of the cls and rec models will be the same as the number of boxes detected by the det model. + ppocr_v2.SetClsBatchSize(cls_batch_size); + ppocr_v2.SetRecBatchSize(rec_batch_size); + if(!ppocr_v2.Initialized()){ std::cerr << "Failed to initialize PP-OCR." << std::endl; return; diff --git a/examples/vision/ocr/PP-OCRv2/python/infer.py b/examples/vision/ocr/PP-OCRv2/python/infer.py index af915143a..1487d795f 100644 --- a/examples/vision/ocr/PP-OCRv2/python/infer.py +++ b/examples/vision/ocr/PP-OCRv2/python/infer.py @@ -106,6 +106,11 @@ rec_label_file = args.rec_label_file # 用户也可根据自行需求分别配置 runtime_option = build_option(args) +# PPOCR的cls和rec模型现在已经支持推理一个Batch的数据 +# 定义下面两个变量后, 可用于设置trt输入shape, 并在PPOCR模型初始化后, 完成Batch推理设置 +cls_batch_size = 1 +rec_batch_size = 6 + # 当使用TRT时,分别给三个模型的runtime设置动态shape,并完成模型的创建. # 注意: 需要在检测模型创建完成后,再设置分类模型的动态输入并创建分类模型, 识别模型同理. # 如果用户想要自己改动检测模型的输入shape, 我们建议用户把检测模型的长和高设置为32的倍数. @@ -118,16 +123,18 @@ det_model = fd.vision.ocr.DBDetector( det_model_file, det_params_file, runtime_option=det_option) cls_option = runtime_option -cls_option.set_trt_input_shape("x", [1, 3, 48, 10], [10, 3, 48, 320], - [32, 3, 48, 1024]) +cls_option.set_trt_input_shape("x", [1, 3, 48, 10], + [cls_batch_size, 3, 48, 320], + [cls_batch_size, 3, 48, 1024]) # 用户可以把TRT引擎文件保存至本地 # cls_option.set_trt_cache_file(args.cls_model + "/cls_trt_cache.trt") cls_model = fd.vision.ocr.Classifier( cls_model_file, cls_params_file, runtime_option=cls_option) rec_option = runtime_option -rec_option.set_trt_input_shape("x", [1, 3, 32, 10], [10, 3, 32, 320], - [32, 3, 32, 2304]) +rec_option.set_trt_input_shape("x", [1, 3, 32, 10], + [rec_batch_size, 3, 32, 320], + [rec_batch_size, 3, 32, 2304]) # 用户可以把TRT引擎文件保存至本地 # rec_option.set_trt_cache_file(args.rec_model + "/rec_trt_cache.trt") rec_model = fd.vision.ocr.Recognizer( @@ -137,6 +144,12 @@ rec_model = fd.vision.ocr.Recognizer( ppocr_v2 = fd.vision.ocr.PPOCRv2( det_model=det_model, cls_model=cls_model, rec_model=rec_model) +# 给cls和rec模型设置推理时的batch size +# 此值能为-1, 和1到正无穷 +# 当此值为-1时, cls和rec模型的batch size将默认和det模型检测出的框的数量相同 +ppocr_v2.cls_batch_size = cls_batch_size +ppocr_v2.rec_batch_size = rec_batch_size + # 预测图片准备 im = cv2.imread(args.image) diff --git a/examples/vision/ocr/PP-OCRv3/cpp/infer.cc b/examples/vision/ocr/PP-OCRv3/cpp/infer.cc index 911b311e3..90b77679f 100644 --- a/examples/vision/ocr/PP-OCRv3/cpp/infer.cc +++ b/examples/vision/ocr/PP-OCRv3/cpp/infer.cc @@ -33,13 +33,19 @@ void InitAndInfer(const std::string& det_model_dir, const std::string& cls_model auto cls_option = option; auto rec_option = option; + // The cls and rec model can inference a batch of images now. + // User could initialize the inference batch size and set them after create PPOCR model. + int cls_batch_size = 1; + int rec_batch_size = 6; + // If use TRT backend, the dynamic shape will be set as follow. // We recommend that users set the length and height of the detection model to a multiple of 32. + // We also recommend that users set the Trt input shape as follow. det_option.SetTrtInputShape("x", {1, 3, 64,64}, {1, 3, 640, 640}, {1, 3, 960, 960}); - cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {10, 3, 48, 320}, {64, 3, 48, 1024}); - rec_option.SetTrtInputShape("x", {1, 3, 48, 10}, {10, 3, 48, 320}, - {64, 3, 48, 2304}); + cls_option.SetTrtInputShape("x", {1, 3, 48, 10}, {cls_batch_size, 3, 48, 320}, {cls_batch_size, 3, 48, 1024}); + rec_option.SetTrtInputShape("x", {1, 3, 48, 10}, {rec_batch_size, 3, 48, 320}, + {rec_batch_size, 3, 48, 2304}); // Users could save TRT cache file to disk as follow. // det_option.SetTrtCacheFile(det_model_dir + sep + "det_trt_cache.trt"); @@ -57,6 +63,12 @@ void InitAndInfer(const std::string& det_model_dir, const std::string& cls_model // The classification model is optional, so the PP-OCR can also be connected in series as follows // auto ppocr_v3 = fastdeploy::pipeline::PPOCRv3(&det_model, &rec_model); auto ppocr_v3 = fastdeploy::pipeline::PPOCRv3(&det_model, &cls_model, &rec_model); + + // Set inference batch size for cls model and rec model, the value could be -1 and 1 to positive infinity. + // When inference batch size is set to -1, it means that the inference batch size + // of the cls and rec models will be the same as the number of boxes detected by the det model. + ppocr_v3.SetClsBatchSize(cls_batch_size); + ppocr_v3.SetRecBatchSize(rec_batch_size); if(!ppocr_v3.Initialized()){ std::cerr << "Failed to initialize PP-OCR." << std::endl; diff --git a/examples/vision/ocr/PP-OCRv3/python/infer.py b/examples/vision/ocr/PP-OCRv3/python/infer.py index b6b27b240..1ec962cb5 100644 --- a/examples/vision/ocr/PP-OCRv3/python/infer.py +++ b/examples/vision/ocr/PP-OCRv3/python/infer.py @@ -106,6 +106,11 @@ rec_label_file = args.rec_label_file # 用户也可根据自行需求分别配置 runtime_option = build_option(args) +# PPOCR的cls和rec模型现在已经支持推理一个Batch的数据 +# 定义下面两个变量后, 可用于设置trt输入shape, 并在PPOCR模型初始化后, 完成Batch推理设置 +cls_batch_size = 1 +rec_batch_size = 6 + # 当使用TRT时,分别给三个模型的runtime设置动态shape,并完成模型的创建. # 注意: 需要在检测模型创建完成后,再设置分类模型的动态输入并创建分类模型, 识别模型同理. # 如果用户想要自己改动检测模型的输入shape, 我们建议用户把检测模型的长和高设置为32的倍数. @@ -118,16 +123,18 @@ det_model = fd.vision.ocr.DBDetector( det_model_file, det_params_file, runtime_option=det_option) cls_option = runtime_option -cls_option.set_trt_input_shape("x", [1, 3, 48, 10], [10, 3, 48, 320], - [64, 3, 48, 1024]) +cls_option.set_trt_input_shape("x", [1, 3, 48, 10], + [cls_batch_size, 3, 48, 320], + [cls_batch_size, 3, 48, 1024]) # 用户可以把TRT引擎文件保存至本地 # cls_option.set_trt_cache_file(args.cls_model + "/cls_trt_cache.trt") cls_model = fd.vision.ocr.Classifier( cls_model_file, cls_params_file, runtime_option=cls_option) rec_option = runtime_option -rec_option.set_trt_input_shape("x", [1, 3, 48, 10], [10, 3, 48, 320], - [64, 3, 48, 2304]) +rec_option.set_trt_input_shape("x", [1, 3, 48, 10], + [rec_batch_size, 3, 48, 320], + [rec_batch_size, 3, 48, 2304]) # 用户可以把TRT引擎文件保存至本地 # rec_option.set_trt_cache_file(args.rec_model + "/rec_trt_cache.trt") rec_model = fd.vision.ocr.Recognizer( @@ -137,6 +144,12 @@ rec_model = fd.vision.ocr.Recognizer( ppocr_v3 = fd.vision.ocr.PPOCRv3( det_model=det_model, cls_model=cls_model, rec_model=rec_model) +# 给cls和rec模型设置推理时的batch size +# 此值能为-1, 和1到正无穷 +# 当此值为-1时, cls和rec模型的batch size将默认和det模型检测出的框的数量相同 +ppocr_v3.cls_batch_size = cls_batch_size +ppocr_v3.rec_batch_size = rec_batch_size + # 预测图片准备 im = cv2.imread(args.image) From 22325d23ed1543b7034f3214d7f8be3ff6a1c8db Mon Sep 17 00:00:00 2001 From: MistEO Date: Fri, 9 Dec 2022 09:20:55 +0800 Subject: [PATCH 02/77] [Other] Add const modifier to some OCR interface parameters (#836) * [Other] Add const modifier to some OCR interface parameters * [Other] Add a Predict interface to PPOCR with const parameters For interface compatibility, I chose to add rather than modify --- examples/vision/ocr/PP-OCRv2/cpp/README.md | 1 + fastdeploy/vision/ocr/ppocr/classifier.cc | 2 +- fastdeploy/vision/ocr/ppocr/classifier.h | 2 +- fastdeploy/vision/ocr/ppocr/ppocr_v2.cc | 8 ++++++-- fastdeploy/vision/ocr/ppocr/ppocr_v2.h | 1 + fastdeploy/vision/ocr/ppocr/recognizer.cc | 2 +- fastdeploy/vision/ocr/ppocr/recognizer.h | 2 +- 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/vision/ocr/PP-OCRv2/cpp/README.md b/examples/vision/ocr/PP-OCRv2/cpp/README.md index 965ece716..1bb794f5e 100644 --- a/examples/vision/ocr/PP-OCRv2/cpp/README.md +++ b/examples/vision/ocr/PP-OCRv2/cpp/README.md @@ -82,6 +82,7 @@ PPOCRv2 的初始化,由检测,识别模型串联构成(无分类器) > ``` > bool Predict(cv::Mat* img, fastdeploy::vision::OCRResult* result); +> bool Predict(const cv::Mat& img, fastdeploy::vision::OCRResult* result); > ``` > > 模型预测接口,输入一张图片,返回OCR预测结果 diff --git a/fastdeploy/vision/ocr/ppocr/classifier.cc b/fastdeploy/vision/ocr/ppocr/classifier.cc index 4be9a3556..216d50fd2 100755 --- a/fastdeploy/vision/ocr/ppocr/classifier.cc +++ b/fastdeploy/vision/ocr/ppocr/classifier.cc @@ -50,7 +50,7 @@ bool Classifier::Initialize() { return true; } -bool Classifier::Predict(cv::Mat& img, int32_t* cls_label, float* cls_score) { +bool Classifier::Predict(const cv::Mat& img, int32_t* cls_label, float* cls_score) { std::vector cls_labels(1); std::vector cls_scores(1); bool success = BatchPredict({img}, &cls_labels, &cls_scores); diff --git a/fastdeploy/vision/ocr/ppocr/classifier.h b/fastdeploy/vision/ocr/ppocr/classifier.h index ddc4db27a..5a4ed02a0 100755 --- a/fastdeploy/vision/ocr/ppocr/classifier.h +++ b/fastdeploy/vision/ocr/ppocr/classifier.h @@ -43,7 +43,7 @@ class FASTDEPLOY_DECL Classifier : public FastDeployModel { const ModelFormat& model_format = ModelFormat::PADDLE); /// Get model's name std::string ModelName() const { return "ppocr/ocr_cls"; } - virtual bool Predict(cv::Mat& img, int32_t* cls_label, float* cls_score); + virtual bool Predict(const cv::Mat& img, int32_t* cls_label, float* cls_score); /** \brief BatchPredict the input image and get OCR classification model cls_result. * * \param[in] images The list of input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. diff --git a/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc b/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc index 2ee2f903f..756604dde 100755 --- a/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc +++ b/fastdeploy/vision/ocr/ppocr/ppocr_v2.cc @@ -74,11 +74,15 @@ bool PPOCRv2::Initialized() const { } return true; } - bool PPOCRv2::Predict(cv::Mat* img, fastdeploy::vision::OCRResult* result) { + return Predict(*img, result); +} + +bool PPOCRv2::Predict(const cv::Mat& img, + fastdeploy::vision::OCRResult* result) { std::vector batch_result(1); - bool success = BatchPredict({*img},&batch_result); + bool success = BatchPredict({img},&batch_result); if(!success){ return success; } diff --git a/fastdeploy/vision/ocr/ppocr/ppocr_v2.h b/fastdeploy/vision/ocr/ppocr/ppocr_v2.h index 05f2b9309..f603a45f9 100755 --- a/fastdeploy/vision/ocr/ppocr/ppocr_v2.h +++ b/fastdeploy/vision/ocr/ppocr/ppocr_v2.h @@ -59,6 +59,7 @@ class FASTDEPLOY_DECL PPOCRv2 : public FastDeployModel { * \return true if the prediction successed, otherwise false. */ virtual bool Predict(cv::Mat* img, fastdeploy::vision::OCRResult* result); + virtual bool Predict(const cv::Mat& img, fastdeploy::vision::OCRResult* result); /** \brief BatchPredict the input image and get OCR result. * * \param[in] images The list of input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. diff --git a/fastdeploy/vision/ocr/ppocr/recognizer.cc b/fastdeploy/vision/ocr/ppocr/recognizer.cc index a20f312c2..8965e73d9 100755 --- a/fastdeploy/vision/ocr/ppocr/recognizer.cc +++ b/fastdeploy/vision/ocr/ppocr/recognizer.cc @@ -53,7 +53,7 @@ bool Recognizer::Initialize() { return true; } -bool Recognizer::Predict(cv::Mat& img, std::string* text, float* rec_score) { +bool Recognizer::Predict(const cv::Mat& img, std::string* text, float* rec_score) { std::vector texts(1); std::vector rec_scores(1); bool success = BatchPredict({img}, &texts, &rec_scores); diff --git a/fastdeploy/vision/ocr/ppocr/recognizer.h b/fastdeploy/vision/ocr/ppocr/recognizer.h index 4ee12bb6a..8a5f5bc70 100755 --- a/fastdeploy/vision/ocr/ppocr/recognizer.h +++ b/fastdeploy/vision/ocr/ppocr/recognizer.h @@ -45,7 +45,7 @@ class FASTDEPLOY_DECL Recognizer : public FastDeployModel { const ModelFormat& model_format = ModelFormat::PADDLE); /// Get model's name std::string ModelName() const { return "ppocr/ocr_rec"; } - virtual bool Predict(cv::Mat& img, std::string* text, float* rec_score); + virtual bool Predict(const cv::Mat& img, std::string* text, float* rec_score); /** \brief BatchPredict the input image and get OCR recognition model result. * * \param[in] images The list of input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format. From f3c5d4ad763f9e28783bebc74aa5b4b8bb75de3e Mon Sep 17 00:00:00 2001 From: chenjian Date: Fri, 9 Dec 2022 10:04:38 +0800 Subject: [PATCH 03/77] [Doc] add fastdeploy client doc (#803) * add fastdeploy client doc * update doc --- serving/README_CN.md | 1 + serving/docs/zh_CN/client.md | 479 +++++++++++++++++++++++++++++++++++ 2 files changed, 480 insertions(+) create mode 100644 serving/docs/zh_CN/client.md diff --git a/serving/README_CN.md b/serving/README_CN.md index 84017b399..2c858b6f7 100644 --- a/serving/README_CN.md +++ b/serving/README_CN.md @@ -33,6 +33,7 @@ docker pull paddlepaddle/fastdeploy:1.0.0-gpu-cuda11.4-trt8.4-21.10 - [模型仓库目录说明](docs/zh_CN/model_repository.md) (说明如何准备模型仓库目录) - [模型配置说明](docs/zh_CN/model_configuration.md) (说明runtime的配置选项) - [服务化部署示例](docs/zh_CN/demo.md) (服务化部署示例) +- [客户端访问说明](docs/zh_CN/client.md) (客户端访问说明) ### 服务化部署示例 diff --git a/serving/docs/zh_CN/client.md b/serving/docs/zh_CN/client.md new file mode 100644 index 000000000..2ca376591 --- /dev/null +++ b/serving/docs/zh_CN/client.md @@ -0,0 +1,479 @@ +# 客户端访问说明 +本文以访问使用fastdeployserver部署的yolov5模型为例,讲述客户端如何请求服务端进行推理服务。关于如何使用fastdeployserver部署yolov5模型,可以参考文档[yolov5服务化部署](../../../examples/vision/detection/yolov5/serving) + +## 基本原理介绍 +fastdeployserver实现了由[kserve](https://github.com/kserve/kserve)提出的为机器学习模型推理服务而设计的[Predict Protocol协议](https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md) API,该API既简单易用同时又支持高性能部署的使用场景,目前提供基于HTTP和GRPC两种网络协议的访问方式。 + + +当fastdeployserver启动后,默认情况下,8000端口用于响应HTTP请求,8001端口用于响应GRPC请求。用户需要请求的资源通常有两种: + +### **模型的元信息(metadata)** + +**HTTP** + +访问方式: GET `v2/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]` + +使用GET请求该url路径可以获取参与服务的模型的元信息,其中`${MODEL_NAME}`表示模型的名字,${MODEL_VERSION}表示模型的版本。服务器会把模型的元信息以json格式返回,返回的格式为一个字典,以$metadata_model_response表示返回的对象,各字段和内容形式表示如下: + +```json +$metadata_model_response = + { + "name" : $string, + "versions" : [ $string, ... ] #optional, + "platform" : $string, + "inputs" : [ $metadata_tensor, ... ], + "outputs" : [ $metadata_tensor, ... ] + } + +$metadata_tensor = + { + "name" : $string, + "datatype" : $string, + "shape" : [ $number, ... ] + } +``` + +**GRPC** + +模型服务的GRPC定义为 + +```text +service GRPCInferenceService +{ + // Check liveness of the inference server. + rpc ServerLive(ServerLiveRequest) returns (ServerLiveResponse) {} + + // Check readiness of the inference server. + rpc ServerReady(ServerReadyRequest) returns (ServerReadyResponse) {} + + // Check readiness of a model in the inference server. + rpc ModelReady(ModelReadyRequest) returns (ModelReadyResponse) {} + + // Get server metadata. + rpc ServerMetadata(ServerMetadataRequest) returns (ServerMetadataResponse) {} + + // Get model metadata. + rpc ModelMetadata(ModelMetadataRequest) returns (ModelMetadataResponse) {} + + // Perform inference using a specific model. + rpc ModelInfer(ModelInferRequest) returns (ModelInferResponse) {} +} +``` + +访问方式:使用GRPC客户端调用模型服务GRPC接口中定义的ModelMetadata方法。 + +接口中请求的ModelMetadataRequest message和返回的ServerMetadataResponse message结构如下,可以看到和上面的HTTP里使用的json结构基本相同。 + +```text +message ModelMetadataRequest +{ + // The name of the model. + string name = 1; + + // The version of the model to check for readiness. If not given the + // server will choose a version based on the model and internal policy. + string version = 2; +} + +message ModelMetadataResponse +{ + // Metadata for a tensor. + message TensorMetadata + { + // The tensor name. + string name = 1; + + // The tensor data type. + string datatype = 2; + + // The tensor shape. A variable-size dimension is represented + // by a -1 value. + repeated int64 shape = 3; + } + + // The model name. + string name = 1; + + // The versions of the model available on the server. + repeated string versions = 2; + + // The model's platform. See Platforms. + string platform = 3; + + // The model's inputs. + repeated TensorMetadata inputs = 4; + + // The model's outputs. + repeated TensorMetadata outputs = 5; +} +``` + + +### **推理服务** + +**HTTP** + +访问方式:POST `v2/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]/infer` + +使用POST请求该url路径可以请求模型的推理服务,获取推理结果。POST请求中的数据同样以json格式上传,以$inference_request表示上传的对象,各字段和内容形式表示如下: +```json + $inference_request = + { + "id" : $string #optional, + "parameters" : $parameters #optional, + "inputs" : [ $request_input, ... ], + "outputs" : [ $request_output, ... ] #optional + } + +$request_input = + { + "name" : $string, + "shape" : [ $number, ... ], + "datatype" : $string, + "parameters" : $parameters #optional, + "data" : $tensor_data + } + +$request_output = + { + "name" : $string, + "parameters" : $parameters #optional, + } + +$parameters = +{ + $parameter, ... +} + +$parameter = $string : $string | $number | $boolean +``` +其中$tensor_data表示一维或多维数组,如果是一维数据,必须按照行主序的方式进行排列tensor中的数据。 +服务器推理完成后,返回结果数据,以$inference_response表示返回的对象,各字段和内容形式表示如下: + +```json +$inference_response = + { + "model_name" : $string, + "model_version" : $string #optional, + "id" : $string, + "parameters" : $parameters #optional, + "outputs" : [ $response_output, ... ] + } + +$response_output = + { + "name" : $string, + "shape" : [ $number, ... ], + "datatype" : $string, + "parameters" : $parameters #optional, + "data" : $tensor_data + } +``` + +**GRPC** + +访问方式:使用GRPC客户端调用模型服务GRPC接口中定义的ModelInfer方法。 + +接口中请求的ModelInferRequest message和返回的ModelInferResponse message结构如下,更完整的结构定义可以参考kserve Predict Protocol [GRPC部分](https://github.com/kserve/kserve/blob/master/docs/predict-api/v2/required_api.md#grpc) + +```text +message ModelInferRequest +{ + // An input tensor for an inference request. + message InferInputTensor + { + // The tensor name. + string name = 1; + + // The tensor data type. + string datatype = 2; + + // The tensor shape. + repeated int64 shape = 3; + + // Optional inference input tensor parameters. + map parameters = 4; + + // The tensor contents using a data-type format. This field must + // not be specified if "raw" tensor contents are being used for + // the inference request. + InferTensorContents contents = 5; + } + + // An output tensor requested for an inference request. + message InferRequestedOutputTensor + { + // The tensor name. + string name = 1; + + // Optional requested output tensor parameters. + map parameters = 2; + } + + // The name of the model to use for inferencing. + string model_name = 1; + + // The version of the model to use for inference. If not given the + // server will choose a version based on the model and internal policy. + string model_version = 2; + + // Optional identifier for the request. If specified will be + // returned in the response. + string id = 3; + + // Optional inference parameters. + map parameters = 4; + + // The input tensors for the inference. + repeated InferInputTensor inputs = 5; + + // The requested output tensors for the inference. Optional, if not + // specified all outputs produced by the model will be returned. + repeated InferRequestedOutputTensor outputs = 6; + + // The data contained in an input tensor can be represented in "raw" + // bytes form or in the repeated type that matches the tensor's data + // type. To use the raw representation 'raw_input_contents' must be + // initialized with data for each tensor in the same order as + // 'inputs'. For each tensor, the size of this content must match + // what is expected by the tensor's shape and data type. The raw + // data must be the flattened, one-dimensional, row-major order of + // the tensor elements without any stride or padding between the + // elements. Note that the FP16 and BF16 data types must be represented as + // raw content as there is no specific data type for a 16-bit float type. + // + // If this field is specified then InferInputTensor::contents must + // not be specified for any input tensor. + repeated bytes raw_input_contents = 7; +} + +message ModelInferResponse +{ + // An output tensor returned for an inference request. + message InferOutputTensor + { + // The tensor name. + string name = 1; + + // The tensor data type. + string datatype = 2; + + // The tensor shape. + repeated int64 shape = 3; + + // Optional output tensor parameters. + map parameters = 4; + + // The tensor contents using a data-type format. This field must + // not be specified if "raw" tensor contents are being used for + // the inference response. + InferTensorContents contents = 5; + } + + // The name of the model used for inference. + string model_name = 1; + + // The version of the model used for inference. + string model_version = 2; + + // The id of the inference request if one was specified. + string id = 3; + + // Optional inference response parameters. + map parameters = 4; + + // The output tensors holding inference results. + repeated InferOutputTensor outputs = 5; + + // The data contained in an output tensor can be represented in + // "raw" bytes form or in the repeated type that matches the + // tensor's data type. To use the raw representation 'raw_output_contents' + // must be initialized with data for each tensor in the same order as + // 'outputs'. For each tensor, the size of this content must match + // what is expected by the tensor's shape and data type. The raw + // data must be the flattened, one-dimensional, row-major order of + // the tensor elements without any stride or padding between the + // elements. Note that the FP16 and BF16 data types must be represented as + // raw content as there is no specific data type for a 16-bit float type. + // + // If this field is specified then InferOutputTensor::contents must + // not be specified for any output tensor. + repeated bytes raw_output_contents = 6; +} +``` + + +## 客户端工具 + +了解了fastdeployserver服务提供的接口之后,用户可以HTTP客户端工具来请求HTTP服务器,或者是使用GRPC客户端工具请求GRPC服务器。默认情况下,fastdeployserver启动后,8000端口用于响应HTTP请求,8001端口用于响应GRPC请求。 + +### 使用HTTP客户端 + +这里分别介绍如何使用tritonclient和requests库来访问fastdeployserver的HTTP服务,第一种工具是专门为模型服务做的客户端,对请求和响应进行了封装,方便用户使用。而第二种工具通用的http客户端工具,使用该工具进行访问可以帮助用户更好地理解上述原理描述中的数据结构。 + +一. 使用tritonclient访问服务 + +安装tritonclient\[http\] + +```bash +pip install tritonclient[http] +``` + +1.获取yolov5的模型元数据 +```python +import tritonclient.http as httpclient # 导入httpclient +server_addr = 'localhost:8000' # 这里写fastdeployserver服务器的实际地址 +client = httpclient.InferenceServerClient(server_addr) # 创建client +model_metadata = client.get_model_metadata( + model_name='yolov5', model_version='1') # 请求yolov5模型的元数据 +``` +可以打印看一下模型的输入和输出有哪些 +```python +print(model_metadata.inputs) +``` + +```text +[{'name': 'INPUT', 'datatype': 'UINT8', 'shape': [-1, -1, -1, 3]}] +``` + +```python +print(model_metadata.outputs) +``` + +```text +[{'name': 'detction_result', 'datatype': 'BYTES', 'shape': [-1, -1]}] +``` + +2.请求推理服务 + +根据模型的inputs和outputs构造数据,然后请求推理 + +```python +# 假设图像数据的文件名为000000014439.jpg +import cv2 +image = cv2.imread('000000014439.jpg') +image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)[None] + +inputs = [] +infer_input = httpclient.InferInput('INPUT', image.shape, 'UINT8') # 构造输入 +infer_input.set_data_from_numpy(image) # 载入输入数据 +inputs.append(infer_input) +outputs = [] +infer_output = httpclient.InferRequestedOutput('detction_result') # 构造输出 +outputs.append(infer_output) +response = client.infer( + 'yolov5', inputs, model_version='1', outputs=outputs) # 请求推理 +response_outputs = response.as_numpy('detction_result') # 根据输出变量名获取结果 +``` + +二. 使用requests访问服务 + +安装requests +```bash +pip install requests +``` +1.获取yolov5的模型元数据 + +```python +import requests +url = 'http://localhost:8000/v2/models/yolov5/versions/1' # 根据上述章节中"模型的元信息"的获取接口构造url +response = requests.get(url) +response = response.json() # 返回数据为json,以json格式解析 +``` +打印一下返回的模型元数据 +```python +print(response) +``` +```text +{'name': 'yolov5', 'versions': ['1'], 'platform': 'ensemble', 'inputs': [{'name': 'INPUT', 'datatype': 'UINT8', 'shape': [-1, -1, -1, 3]}], 'outputs': [{'name': 'detction_result', 'datatype': 'BYTES', 'shape': [-1, -1]}]} +``` +2.请求推理服务 + +根据模型的inputs和outputs构造数据,然后请求推理。 +```python +url = 'http://localhost:8000/v2/models/yolov5/versions/1/infer' # 根据上述章节中"推理服务"的接口构造url +# 假设图像数据的文件名为000000014439.jpg +import cv2 +image = cv2.imread('000000014439.jpg') +image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)[None] + +payload = { + "inputs" : [ + { + "name" : "INPUT", + "shape" : image.shape, + "datatype" : "UINT8", + "data" : image.tolist() + } + ], + "outputs" : [ + { + "name" : "detction_result" + } + ] +} +response = requests.post(url, data=json.dumps(payload)) +response = response.json() # 返回数据为json,以json格式解析后即为推理后返回的结果 +``` + +### 使用GRPC客户端 + +安装tritonclient\[grpc\] +```bash +pip install tritonclient[grpc] +``` +tritonclient\[grpc\]提供了使用GRPC的客户端,并且对GRPC的交互进行了封装,使得用户不用手动和服务端建立连接,也不用去直接使用grpc的stub去调用服务器的接口,而是封装后给用户提供了和tritonclient HTTP客户端一样的接口进行使用。 + +1.获取yolov5的模型元数据 +```python +import tritonclient.grpc as grpcclient # 导入grpc客户端 +server_addr = 'localhost:8001' # 这里写fastdeployserver grpc服务器的实际地址 +client = grpcclient.InferenceServerClient(server_addr) # 创建client +model_metadata = client.get_model_metadata( + model_name='yolov5', model_version='1') # 请求yolov5模型的元数据 +``` +2.请求推理服务 +根据返回的model_metadata来构造请求数据。首先看一下模型的输入和输出有哪些 +```python +print(model_metadata.inputs) +``` +```text +[name: "INPUT" +datatype: "UINT8" +shape: -1 +shape: -1 +shape: -1 +shape: 3 +] +``` + +```python +print(model_metadata.outputs) +``` + +```text +[name: "detction_result" +datatype: "BYTES" +shape: -1 +shape: -1 +] +``` + +根据模型的inputs和outputs构造数据,然后请求推理 +```python +# 假设图像数据的文件名为000000014439.jpg +import cv2 +image = cv2.imread('000000014439.jpg') +image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)[None] + +inputs = [] +infer_input = grpcclient.InferInput('INPUT', image.shape, 'UINT8') # 构造输入 +infer_input.set_data_from_numpy(image) # 载入输入数据 +inputs.append(infer_input) +outputs = [] +infer_output = grpcclient.InferRequestedOutput('detction_result') # 构造输出 +outputs.append(infer_output) +response = client.infer( + 'yolov5', inputs, model_version='1', outputs=outputs) # 请求推理 +response_outputs = response.as_numpy('detction_result') # 根据输出变量名获取结果 +``` From 788ca79e5f2574745735cbae274c1d24abf6b79b Mon Sep 17 00:00:00 2001 From: Zeref996 <53218160+Zeref996@users.noreply.github.com> Date: Fri, 9 Dec 2022 10:50:37 +0800 Subject: [PATCH 04/77] Fix doc version (#841) * Change FastDeploy Doc Version from 1.0.0 to 1.0.1 * fix android doc version * fix android doc version 1 --- .../download_prebuilt_libraries.md | 18 +++++++-------- .../download_prebuilt_libraries.md | 22 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/cn/build_and_install/download_prebuilt_libraries.md b/docs/cn/build_and_install/download_prebuilt_libraries.md index 2f48c2c06..1a2c4f94e 100755 --- a/docs/cn/build_and_install/download_prebuilt_libraries.md +++ b/docs/cn/build_and_install/download_prebuilt_libraries.md @@ -20,7 +20,7 @@ FastDeploy提供各平台预编译库,供开发者直接下载安装使用。 ### Python安装 -Release版本(当前最新1.0.0)安装 +Release版本(当前最新1.0.1)安装 ```bash pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html ``` @@ -41,8 +41,8 @@ Release版本 | 平台 | 文件 | 说明 | | :--- | :--- | :---- | -| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2编译产出 | -| Windows x64 | [fastdeploy-win-x64-gpu-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2编译产出 | +| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.1.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2编译产出 | +| Windows x64 | [fastdeploy-win-x64-gpu-1.0.1.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.1.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2编译产出 | Develop版本(Nightly build) @@ -63,7 +63,7 @@ Develop版本(Nightly build) ### Python安装 -Release版本(当前最新1.0.0)安装 +Release版本(当前最新1.0.1)安装 ```bash pip install fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html ``` @@ -79,11 +79,11 @@ Release版本 | 平台 | 文件 | 说明 | | :--- | :--- | :---- | -| Linux x64 | [fastdeploy-linux-x64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.0.tgz) | g++ 8.2编译产出 | -| Windows x64 | [fastdeploy-win-x64-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.0.zip) | Visual Studio 16 2019编译产出 | -| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.0.tgz) | clang++ 10.0.0编译产出| -| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.0.tgz) | clang++ 13.0.0编译产出 | -| Linux aarch64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.0.tgz) | gcc 6.3编译产出 | +| Linux x64 | [fastdeploy-linux-x64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.1.tgz) | g++ 8.2编译产出 | +| Windows x64 | [fastdeploy-win-x64-1.0.1.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.1.zip) | Visual Studio 16 2019编译产出 | +| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.1.tgz) | clang++ 10.0.0编译产出| +| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.1.tgz) | clang++ 13.0.0编译产出 | +| Linux aarch64 | [fastdeploy-osx-arm64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.1.tgz) | gcc 6.3编译产出 | | Android armv7&v8 | [fastdeploy-android-1.0.0-shared.tgz](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-1.0.0-shared.tgz) | NDK 25及clang++编译产出, 支持arm64-v8a及armeabi-v7a | ## Java SDK安装 diff --git a/docs/en/build_and_install/download_prebuilt_libraries.md b/docs/en/build_and_install/download_prebuilt_libraries.md index 52dbdd627..37b199ba0 100644 --- a/docs/en/build_and_install/download_prebuilt_libraries.md +++ b/docs/en/build_and_install/download_prebuilt_libraries.md @@ -22,7 +22,7 @@ FastDeploy supports Computer Vision, Text and NLP model deployment on CPU and Nv ### Python SDK -Install the released version(the newest 1.0.0 for now) +Install the released version(the newest 1.0.1 for now) ``` pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html @@ -42,12 +42,12 @@ conda config --add channels conda-forge && conda install cudatoolkit=11.2 cudnn= ### C++ SDK -Install the released version(Latest 1.0.0) +Install the released version(Latest 1.0.1) | Platform | File | Description | |:----------- |:--------------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------------- | -| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.0.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2 | -| Windows x64 | [fastdeploy-win-x64-gpu-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.0.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2 | +| Linux x64 | [fastdeploy-linux-x64-gpu-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-gpu-1.0.1.tgz) | g++ 8.2, CUDA 11.2, cuDNN 8.2 | +| Windows x64 | [fastdeploy-win-x64-gpu-1.0.1.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-gpu-1.0.1.zip) | Visual Studio 16 2019, CUDA 11.2, cuDNN 8.2 | Install the Develop version(Nightly build) @@ -69,7 +69,7 @@ FastDeploy supports computer vision, text and NLP model deployment on CPU with P ### Python SDK -Install the released version(Latest 1.0.0 for now) +Install the released version(Latest 1.0.1 for now) ``` pip install fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html @@ -83,15 +83,15 @@ pip install fastdeploy-python==0.0.0 -f https://www.paddlepaddle.org.cn/whl/fast ### C++ SDK -Install the released version(Latest 1.0.0 for now, Android is 1.0.0) +Install the released version(Latest 1.0.1 for now, Android is 1.0.1) | Platform | File | Description | |:------------- |:--------------------------------------------------------------------------------------------------------------------- |:------------------------------ | -| Linux x64 | [fastdeploy-linux-x64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.0.tgz) | g++ 8.2 | -| Windows x64 | [fastdeploy-win-x64-1.0.0.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.0.zip) | Visual Studio 16 2019 | -| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.0.tgz) | clang++ 10.0.0| -| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.0.tgz) | clang++ 13.0.0 | -| Linux aarch64 | [fastdeploy-osx-arm64-1.0.0.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.0.tgz) | gcc 6.3 | +| Linux x64 | [fastdeploy-linux-x64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-1.0.1.tgz) | g++ 8.2 | +| Windows x64 | [fastdeploy-win-x64-1.0.1.zip](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-win-x64-1.0.1.zip) | Visual Studio 16 2019 | +| Mac OSX x64 | [fastdeploy-osx-x86_64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-x86_64-1.0.1.tgz) | clang++ 10.0.0| +| Mac OSX arm64 | [fastdeploy-osx-arm64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-osx-arm64-1.0.1.tgz) | clang++ 13.0.0 | +| Linux aarch64 | [fastdeploy-osx-arm64-1.0.1.tgz](https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-aarch64-1.0.1.tgz) | gcc 6.3 | | Android armv7&v8 | [fastdeploy-android-1.0.0-shared.tgz](https://bj.bcebos.com/fastdeploy/release/android/fastdeploy-android-1.0.0-shared.tgz)| NDK 25, clang++, support arm64-v8a及armeabi-v7a | ## Java SDK From b0988bf423ec96d9da203bec6773adefae2e1f4c Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 11:41:19 +0800 Subject: [PATCH 05/77] [Compile] Support custom paddle inference (#839) * Support custom paddle inference * update setup.py --- cmake/paddle_inference.cmake | 93 +++++++++++++++++++++--------------- python/setup.py | 2 + 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/cmake/paddle_inference.cmake b/cmake/paddle_inference.cmake index f1b5ee6c7..3ab45454a 100644 --- a/cmake/paddle_inference.cmake +++ b/cmake/paddle_inference.cmake @@ -13,6 +13,8 @@ # limitations under the License. include(ExternalProject) +option(PADDLEINFERENCE_DIRECTORY "Directory of Paddle Inference library" OFF) + set(PADDLEINFERENCE_PROJECT "extern_paddle_inference") set(PADDLEINFERENCE_PREFIX_DIR ${THIRD_PARTY_PATH}/paddle_inference) set(PADDLEINFERENCE_SOURCE_DIR @@ -27,6 +29,10 @@ set(PADDLEINFERENCE_LIB_DIR set(CMAKE_BUILD_RPATH "${CMAKE_BUILD_RPATH}" "${PADDLEINFERENCE_LIB_DIR}") +if(PADDLEINFERENCE_DIRECTORY) + set(PADDLEINFERENCE_INC_DIR ${PADDLEINFERENCE_DIRECTORY}/paddle/include) +endif() + include_directories(${PADDLEINFERENCE_INC_DIR}) if(WIN32) set(PADDLEINFERENCE_COMPILE_LIB @@ -47,50 +53,59 @@ else() endif(WIN32) -set(PADDLEINFERENCE_URL_BASE "https://bj.bcebos.com/fastdeploy/third_libs/") -set(PADDLEINFERENCE_VERSION "2.4-dev3") -if(WIN32) - if (WITH_GPU) - set(PADDLEINFERENCE_FILE "paddle_inference-win-x64-gpu-trt-${PADDLEINFERENCE_VERSION}.zip") - else() - set(PADDLEINFERENCE_FILE "paddle_inference-win-x64-${PADDLEINFERENCE_VERSION}.zip") - endif() -elseif(APPLE) - if(CURRENT_OSX_ARCH MATCHES "arm64") - message(FATAL_ERROR "Paddle Backend doesn't support Mac OSX with Arm64 now.") - set(PADDLEINFERENCE_FILE "paddle_inference-osx-arm64-${PADDLEINFERENCE_VERSION}.tgz") - else() - set(PADDLEINFERENCE_FILE "paddle_inference-osx-x86_64-${PADDLEINFERENCE_VERSION}.tgz") +if(PADDLEINFERENCE_DIRECTORY) + if(EXISTS "${THIRD_PARTY_PATH}/install/paddle_inference") + file(REMOVE_RECURSE "${THIRD_PARTY_PATH}/install/paddle_inference") endif() + find_package(Python COMPONENTS Interpreter Development REQUIRED) + message(STATUS "Copying ${PADDLEINFERENCE_DIRECTORY} to ${THIRD_PARTY_PATH}/install/paddle_inference ...") + execute_process(COMMAND ${Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/scripts/copy_directory.py ${PADDLEINFERENCE_DIRECTORY} ${THIRD_PARTY_PATH}/install/paddle_inference) else() - if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") - message(FATAL_ERROR "Paddle Backend doesn't support linux aarch64 now.") - set(PADDLEINFERENCE_FILE "paddle_inference-linux-aarch64-${PADDLEINFERENCE_VERSION}.tgz") - else() - set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-${PADDLEINFERENCE_VERSION}.tgz") - if(WITH_GPU) - set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-gpu-trt-${PADDLEINFERENCE_VERSION}.tgz") + set(PADDLEINFERENCE_URL_BASE "https://bj.bcebos.com/fastdeploy/third_libs/") + set(PADDLEINFERENCE_VERSION "2.4-dev3") + if(WIN32) + if (WITH_GPU) + set(PADDLEINFERENCE_FILE "paddle_inference-win-x64-gpu-trt-${PADDLEINFERENCE_VERSION}.zip") + else() + set(PADDLEINFERENCE_FILE "paddle_inference-win-x64-${PADDLEINFERENCE_VERSION}.zip") endif() - if (WITH_IPU) - set(PADDLEINFERENCE_VERSION "2.4-dev1") - set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-ipu-${PADDLEINFERENCE_VERSION}.tgz") + elseif(APPLE) + if(CURRENT_OSX_ARCH MATCHES "arm64") + message(FATAL_ERROR "Paddle Backend doesn't support Mac OSX with Arm64 now.") + set(PADDLEINFERENCE_FILE "paddle_inference-osx-arm64-${PADDLEINFERENCE_VERSION}.tgz") + else() + set(PADDLEINFERENCE_FILE "paddle_inference-osx-x86_64-${PADDLEINFERENCE_VERSION}.tgz") + endif() + else() + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") + message(FATAL_ERROR "Paddle Backend doesn't support linux aarch64 now.") + set(PADDLEINFERENCE_FILE "paddle_inference-linux-aarch64-${PADDLEINFERENCE_VERSION}.tgz") + else() + set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-${PADDLEINFERENCE_VERSION}.tgz") + if(WITH_GPU) + set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-gpu-trt-${PADDLEINFERENCE_VERSION}.tgz") + endif() + if (WITH_IPU) + set(PADDLEINFERENCE_VERSION "2.4-dev1") + set(PADDLEINFERENCE_FILE "paddle_inference-linux-x64-ipu-${PADDLEINFERENCE_VERSION}.tgz") + endif() endif() endif() -endif() -set(PADDLEINFERENCE_URL "${PADDLEINFERENCE_URL_BASE}${PADDLEINFERENCE_FILE}") - -ExternalProject_Add( - ${PADDLEINFERENCE_PROJECT} - ${EXTERNAL_PROJECT_LOG_ARGS} - URL ${PADDLEINFERENCE_URL} - PREFIX ${PADDLEINFERENCE_PREFIX_DIR} - DOWNLOAD_NO_PROGRESS 1 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - UPDATE_COMMAND "" - INSTALL_COMMAND - ${CMAKE_COMMAND} -E copy_directory ${PADDLEINFERENCE_SOURCE_DIR} ${PADDLEINFERENCE_INSTALL_DIR} - BUILD_BYPRODUCTS ${PADDLEINFERENCE_COMPILE_LIB}) + set(PADDLEINFERENCE_URL "${PADDLEINFERENCE_URL_BASE}${PADDLEINFERENCE_FILE}") + + ExternalProject_Add( + ${PADDLEINFERENCE_PROJECT} + ${EXTERNAL_PROJECT_LOG_ARGS} + URL ${PADDLEINFERENCE_URL} + PREFIX ${PADDLEINFERENCE_PREFIX_DIR} + DOWNLOAD_NO_PROGRESS 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${PADDLEINFERENCE_SOURCE_DIR} ${PADDLEINFERENCE_INSTALL_DIR} + BUILD_BYPRODUCTS ${PADDLEINFERENCE_COMPILE_LIB}) +endif(PADDLEINFERENCE_DIRECTORY) if(UNIX AND (NOT APPLE) AND (NOT ANDROID)) add_custom_target(patchelf_paddle_inference ALL COMMAND bash -c "PATCHELF_EXE=${PATCHELF_EXE} python ${PROJECT_SOURCE_DIR}/scripts/patch_paddle_inference.py ${PADDLEINFERENCE_INSTALL_DIR}/paddle/lib/libpaddle_inference.so" DEPENDS ${LIBRARY_NAME}) diff --git a/python/setup.py b/python/setup.py index 1f01322bb..b4dc111c6 100755 --- a/python/setup.py +++ b/python/setup.py @@ -78,6 +78,8 @@ setup_configs["LIBRARY_NAME"] = PACKAGE_NAME setup_configs["PY_LIBRARY_NAME"] = PACKAGE_NAME + "_main" setup_configs["OPENCV_DIRECTORY"] = os.getenv("OPENCV_DIRECTORY", "") setup_configs["ORT_DIRECTORY"] = os.getenv("ORT_DIRECTORY", "") +setup_configs["PADDLEINFERENCE_DIRECTORY"] = os.getenv("PADDLEINFERENCE_DIRECTORY", "") + setup_configs["RKNN2_TARGET_SOC"] = os.getenv("RKNN2_TARGET_SOC", "") if setup_configs["RKNN2_TARGET_SOC"] != "" or setup_configs["BUILD_ON_JETSON"] != "OFF": REQUIRED_PACKAGES = REQUIRED_PACKAGES.replace("opencv-python", "") From 3c05c745136bf9947d005de322e488552a7bc163 Mon Sep 17 00:00:00 2001 From: shentanyue <34421038+shentanyue@users.noreply.github.com> Date: Fri, 9 Dec 2022 13:20:33 +0800 Subject: [PATCH 06/77] [Paddle Lite] Support stable-diffusion model (#830) * support stable-diffusion model for paddlelite * update code --- fastdeploy/backends/lite/lite_backend.cc | 10 +++++----- fastdeploy/pybind/main.cc.in | 6 +++++- fastdeploy/pybind/main.h | 6 ++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/fastdeploy/backends/lite/lite_backend.cc b/fastdeploy/backends/lite/lite_backend.cc index 04f139256..7e3e09f8d 100755 --- a/fastdeploy/backends/lite/lite_backend.cc +++ b/fastdeploy/backends/lite/lite_backend.cc @@ -206,24 +206,24 @@ bool LiteBackend::Infer(std::vector& inputs, // Adjust dims only, allocate lazy. tensor->Resize(inputs[i].shape); if (inputs[i].dtype == FDDataType::FP32) { - tensor->CopyFromCpu( + tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); } else if (inputs[i].dtype == FDDataType::INT32) { - tensor->CopyFromCpu( + tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); } else if (inputs[i].dtype == FDDataType::INT8) { - tensor->CopyFromCpu( + tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); } else if (inputs[i].dtype == FDDataType::UINT8) { - tensor->CopyFromCpu( + tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); } else if (inputs[i].dtype == FDDataType::INT64) { #ifdef __aarch64__ - tensor->CopyFromCpu( + tensor->CopyFromCpu( reinterpret_cast(const_cast( inputs[i].CpuData()))); #else diff --git a/fastdeploy/pybind/main.cc.in b/fastdeploy/pybind/main.cc.in index 97aafc64a..1b227edc6 100644 --- a/fastdeploy/pybind/main.cc.in +++ b/fastdeploy/pybind/main.cc.in @@ -35,6 +35,8 @@ pybind11::dtype FDDataTypeToNumpyDataType(const FDDataType& fd_dtype) { dt = pybind11::dtype::of(); } else if (fd_dtype == FDDataType::UINT8) { dt = pybind11::dtype::of(); + } else if (fd_dtype == FDDataType::INT8) { + dt = pybind11::dtype::of(); } else if (fd_dtype == FDDataType::FP16) { dt = pybind11::dtype::of(); } else { @@ -55,12 +57,14 @@ FDDataType NumpyDataTypeToFDDataType(const pybind11::dtype& np_dtype) { return FDDataType::FP64; } else if (np_dtype.is(pybind11::dtype::of())) { return FDDataType::UINT8; + } else if (np_dtype.is(pybind11::dtype::of())) { + return FDDataType::INT8; } else if (np_dtype.is(pybind11::dtype::of())) { return FDDataType::FP16; } FDASSERT(false, "NumpyDataTypeToFDDataType() only support " - "int32/int64/float32/float64/float16 now."); + "int8/int32/int64/float32/float64/float16 now."); return FDDataType::FP32; } diff --git a/fastdeploy/pybind/main.h b/fastdeploy/pybind/main.h index 471579ab1..c0ea4497a 100644 --- a/fastdeploy/pybind/main.h +++ b/fastdeploy/pybind/main.h @@ -67,9 +67,11 @@ FDDataType CTypeToFDDataType() { return FDDataType::FP32; } else if (std::is_same::value) { return FDDataType::FP64; + } else if (std::is_same::value) { + return FDDataType::INT8; } - FDASSERT(false, - "CTypeToFDDataType only support int32/int64/float32/float64 now."); + FDASSERT(false, "CTypeToFDDataType only support " + "int8/int32/int64/float32/float64 now."); return FDDataType::FP32; } From b19fe6a965a2b0a86a1ae27bf97f916138548dac Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 14:28:00 +0800 Subject: [PATCH 07/77] Update cpu.md --- docs/cn/build_and_install/cpu.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/cn/build_and_install/cpu.md b/docs/cn/build_and_install/cpu.md index c6fb2a893..b0057e677 100644 --- a/docs/cn/build_and_install/cpu.md +++ b/docs/cn/build_and_install/cpu.md @@ -27,6 +27,11 @@ Linux上编译需满足 - gcc/g++ >= 5.4(推荐8.2) - cmake >= 3.18.0 +此外更推荐开发者自行安装,编译时通过`-DOPENCV_DIRECTORY`来指定环境中的OpenCV(如若不指定-DOPENCV_DIRECTORY,会自动下载FastDeploy提供的预编译的OpenCV,但在**Linux平台**无法支持Video的读取,以及imshow等可视化界面功能) +``` +sudo apt-get install libopencv-dev +``` + ```bash git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy @@ -36,6 +41,7 @@ cmake .. -DENABLE_ORT_BACKEND=ON \ -DENABLE_OPENVINO_BACKEND=ON \ -DCMAKE_INSTALL_PREFIX=${PWD}/compiled_fastdeploy_sdk \ -DENABLE_VISION=ON \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 \ -DENABLE_TEXT=ON make -j12 make install @@ -90,6 +96,8 @@ export ENABLE_PADDLE_BACKEND=ON export ENABLE_OPENVINO_BACKEND=ON export ENABLE_VISION=ON export ENABLE_TEXT=ON +# OPENCV_DIRECTORY可选,不指定会自动下载FastDeploy提供的预编译OpenCV库 +export OPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 python setup.py build python setup.py bdist_wheel From 4ccec075a14a3e1404e5bcd6bfc8335ad74431bf Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 14:29:44 +0800 Subject: [PATCH 08/77] Update gpu.md --- docs/cn/build_and_install/gpu.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/cn/build_and_install/gpu.md b/docs/cn/build_and_install/gpu.md index 3d6aba116..1e9a0d26f 100644 --- a/docs/cn/build_and_install/gpu.md +++ b/docs/cn/build_and_install/gpu.md @@ -33,6 +33,11 @@ Linux上编译需满足 - cuda >= 11.2 - cudnn >= 8.2 +此外更推荐开发者自行安装,编译时通过`-DOPENCV_DIRECTORY`来指定环境中的OpenCV(如若不指定-DOPENCV_DIRECTORY,会自动下载FastDeploy提供的预编译的OpenCV,但在**Linux平台**无法支持Video的读取,以及imshow等可视化界面功能) +``` +sudo apt-get install libopencv-dev +``` + ```bash git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy @@ -46,6 +51,7 @@ cmake .. -DENABLE_ORT_BACKEND=ON \ -DCUDA_DIRECTORY=/usr/local/cuda \ -DCMAKE_INSTALL_PREFIX=${PWD}/compiled_fastdeploy_sdk \ -DENABLE_VISION=ON \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 \ -DENABLE_TEXT=ON make -j12 make install @@ -115,6 +121,8 @@ export ENABLE_TRT_BACKEND=ON export WITH_GPU=ON export TRT_DIRECTORY=/Paddle/TensorRT-8.4.1.5 export CUDA_DIRECTORY=/usr/local/cuda +# OPENCV_DIRECTORY可选,不指定会在编译过程下载FastDeploy预编译的OpenCV库 +export OPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 \ python setup.py build python setup.py bdist_wheel From 195132a1c70990a5488fd2eb077368bfea696782 Mon Sep 17 00:00:00 2001 From: DefTruth <31974251+DefTruth@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:53:26 +0800 Subject: [PATCH 09/77] [Android] Update Android build scripts & app download tasks (#835) * [Android] Add ERNIE3.0 intent and slot task jni support * [Bug Fix] fix app sdk download tasks * [Bug Fix] fix app sdk download tasks * [JNI] remove empty .cc files * [Android] Update Android build scripts --- cmake/paddlelite.cmake | 4 +- java/android/app/build.gradle | 24 ++-- java/android/fastdeploy/build.gradle | 10 +- scripts/android/build_android_aar.sh | 9 +- scripts/android/build_android_app.sh | 6 +- scripts/android/build_android_cpp.sh | 2 +- .../build_android_cpp_with_text_api.sh | 118 ++++++++++++++++++ 7 files changed, 146 insertions(+), 27 deletions(-) create mode 100755 scripts/android/build_android_cpp_with_text_api.sh diff --git a/cmake/paddlelite.cmake b/cmake/paddlelite.cmake index 12a069f6e..299843a6d 100755 --- a/cmake/paddlelite.cmake +++ b/cmake/paddlelite.cmake @@ -52,9 +52,9 @@ endif() if(WIN32 OR APPLE OR IOS) message(FATAL_ERROR "Doesn't support windows/mac/ios platform with backend Paddle Lite now.") elseif(ANDROID) - set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-android-${ANDROID_ABI}-latest.tgz") + set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-android-${ANDROID_ABI}-latest-dev.tgz") if(ANDROID_ABI MATCHES "arm64-v8a") - set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-android-${ANDROID_ABI}-fp16-latest.tgz") + set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-android-${ANDROID_ABI}-fp16-latest-dev.tgz") endif() else() # Linux if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") diff --git a/java/android/app/build.gradle b/java/android/app/build.gradle index d58cb3dd5..fde73b3b3 100644 --- a/java/android/app/build.gradle +++ b/java/android/app/build.gradle @@ -95,11 +95,13 @@ task downloadAndExtractModels(type: DefaultTask) { String[] modelPaths = model.src.split("/") String modelName = modelPaths[modelPaths.length - 1] String modelPrefix = modelName.substring(0, modelName.length() - 4) - // Download the target model if not exists - boolean copyFiles = !file("${model.dest}/${modelPrefix}").exists() - if (!file("${cachePath}/${modelName}").exists()) { - println "[INFO] Downloading ${model.src} -> ${cachePath}/${modelName}" - ant.get(src: model.src, dest: file("${cachePath}/${modelName}")) + boolean copyFiles = false + if (!file("${model.dest}/${modelPrefix}").exists()) { + // Download the target model if not exists + if (!file("${cachePath}/${modelName}").exists()) { + println "[INFO] Downloading ${model.src} -> ${cachePath}/${modelName}" + ant.get(src: model.src, dest: file("${cachePath}/${modelName}")) + } copyFiles = true } if (copyFiles) { @@ -127,11 +129,13 @@ task downloadAndExtractSDKs(type: DefaultTask) { FD_JAVA_SDK.eachWithIndex { sdk, index -> String[] sdkPaths = sdk.src.split("/") String sdkName = sdkPaths[sdkPaths.length - 1] - // Download the target SDK if not exists - boolean copyFiles = !file("${sdk.dest}/${sdkName}").exists() - if (!file("${cachePath}/${sdkName}").exists()) { - println "[INFO] Downloading ${sdk.src} -> ${cachePath}/${sdkName}" - ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}")) + boolean copyFiles = false + if (!file("${sdk.dest}/${sdkName}").exists()) { + // Download the target SDK if not exists + if (file("${cachePath}/${sdkName}").exists()) { + println "[INFO] Downloading ${sdk.src} -> ${cachePath}/${sdkName}" + ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}")) + } copyFiles = true } if (copyFiles) { diff --git a/java/android/fastdeploy/build.gradle b/java/android/fastdeploy/build.gradle index f16248440..d6d4abb7c 100644 --- a/java/android/fastdeploy/build.gradle +++ b/java/android/fastdeploy/build.gradle @@ -67,10 +67,12 @@ task downloadAndExtractLibs(type: DefaultTask) { String[] libPaths = lib.src.split("/") String libName = libPaths[libPaths.length - 1] libName = libName.split("\\.")[0] - boolean copyFiles = !file("${lib.dest}/${libName}").exists() - if (!file("${cachePath}/${libName}.tgz").exists()) { - println "[INFO] Downloading ${lib.src} -> ${cachePath}/${libName}.tgz" - ant.get(src: lib.src, dest: file("${cachePath}/${libName}.tgz")) + boolean copyFiles = false + if (!file("${lib.dest}/${libName}").exists()) { + if (!file("${cachePath}/${libName}.tgz").exists()) { + println "[INFO] Downloading ${lib.src} -> ${cachePath}/${libName}.tgz" + ant.get(src: lib.src, dest: file("${cachePath}/${libName}.tgz")) + } copyFiles = true } if (copyFiles) { diff --git a/scripts/android/build_android_aar.sh b/scripts/android/build_android_aar.sh index bc5a61760..f1e4178b7 100755 --- a/scripts/android/build_android_aar.sh +++ b/scripts/android/build_android_aar.sh @@ -2,20 +2,15 @@ set -e set +x -PACKAGE_VERSION=$1 FASTDEPLOY_DIR=$(pwd) BUILT_PACKAGE_DIR=build/Android -CXX_PACKAGE_PREFIX=fastdeploy-android-${PACKAGE_VERSION}-shared +CXX_PACKAGE_PREFIX=fastdeploy-android-latest-dev-shared CXX_PACKAGE_NAME=${BUILT_PACKAGE_DIR}/${CXX_PACKAGE_PREFIX} ARMV8_CXX_PACKAGE_NAME=${BUILT_PACKAGE_DIR}/arm64-v8a-api-21/install ARMV7_CXX_PACKAGE_NAME=${BUILT_PACKAGE_DIR}/armeabi-v7a-api-21/install # check package name echo "[INFO] --- FASTDEPLOY_DIR: ${FASTDEPLOY_DIR}" -if [ "$PACKAGE_VERSION" = "dev" ]; then - CXX_PACKAGE_PREFIX=fastdeploy-android-latest-shared-dev - CXX_PACKAGE_NAME=${BUILT_PACKAGE_DIR}/fastdeploy-android-latest-shared-dev -fi # check arm v7 & v8 c++ sdk if [ ! -d "${BUILT_PACKAGE_DIR}" ]; then @@ -76,4 +71,4 @@ echo "[INFO] --- Built java aar package!" ls -lh ${JNI_LIB_DIR}/build/outputs/aar/ # Usage: -# ./scripts/android/build_android_aar.sh dev +# ./scripts/android/build_android_aar.sh diff --git a/scripts/android/build_android_app.sh b/scripts/android/build_android_app.sh index 24db66fed..5df19148a 100755 --- a/scripts/android/build_android_app.sh +++ b/scripts/android/build_android_app.sh @@ -1,4 +1,4 @@ -# build java aar package +# build FastDeploy app FASTDEPLOY_DIR=$(pwd) JAVA_ANDROID_DIR=${FASTDEPLOY_DIR}/java/android JNI_LIB_DIR=${JAVA_ANDROID_DIR}/fastdeploy @@ -7,7 +7,7 @@ APP_DIR=${JAVA_ANDROID_DIR}/app APP_LIBS_DIR=${APP_DIR}/libs cd ${JAVA_ANDROID_DIR} -# check aar package +# check aar package first! echo "[INFO] --- JAVA_ANDROID_DIR: ${JAVA_ANDROID_DIR}" if [ ! -d "${JNI_LIB_DIR}/build/outputs/aar" ]; then echo "-- [ERROR] ${JNI_LIB_DIR} not exists, please build aar package first!" @@ -28,7 +28,7 @@ if [ -f "${APP_LIBS_DIR}/fastdeploy-android-sdk-latest-dev.aar" ]; then echo "[INFO] --- Update aar package done!" fi # build android app -echo "[INFO] --- Building FastDeploy Android app ..." +echo "[INFO] --- Building FastDeploy Android App ..." chmod +x gradlew ./gradlew app:assembleDebug echo "[INFO] --- Built FastDeploy Android app." diff --git a/scripts/android/build_android_cpp.sh b/scripts/android/build_android_cpp.sh index 7ca62330f..5179a5117 100755 --- a/scripts/android/build_android_cpp.sh +++ b/scripts/android/build_android_cpp.sh @@ -90,7 +90,7 @@ __build_fastdeploy_android_shared() { -DENABLE_LITE_BACKEND=ON \ -DENABLE_PADDLE_FRONTEND=OFF \ -DENABLE_FLYCV=ON \ - -DENABLE_TEXT=ON \ + -DENABLE_TEXT=OFF \ -DENABLE_VISION=ON \ -DENABLE_VISION_VISUALIZE=ON \ -DBUILD_EXAMPLES=ON \ diff --git a/scripts/android/build_android_cpp_with_text_api.sh b/scripts/android/build_android_cpp_with_text_api.sh new file mode 100755 index 000000000..ac1ca4e6f --- /dev/null +++ b/scripts/android/build_android_cpp_with_text_api.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -e +set +x + +# ------------------------------------------------------------------------------- +# mutable global variables +# ------------------------------------------------------------------------------- +TOOLCHAIN=clang # gcc/clang toolchain + +# ------------------------------------------------------------------------------- +# readonly global variables +# ------------------------------------------------------------------------------- +readonly ROOT_PATH=$(pwd) +readonly ANDROID_ABI=$1 +readonly ANDROID_PLATFORM="android-$2" +readonly BUILD_ROOT=build/Android +readonly BUILD_DIR=${BUILD_ROOT}/${ANDROID_ABI}-api-$2 + +# ------------------------------------------------------------------------------- +# tasks +# ------------------------------------------------------------------------------- +__make_build_dir() { + if [ ! -d "${BUILD_DIR}" ]; then + echo "-- [INFO] BUILD_DIR: ${BUILD_DIR} not exists, setup manually ..." + if [ ! -d "${BUILD_ROOT}" ]; then + mkdir -p "${BUILD_ROOT}" && echo "-- [INFO] Created ${BUILD_ROOT} !" + fi + mkdir -p "${BUILD_DIR}" && echo "-- [INFO] Created ${BUILD_DIR} !" + else + echo "-- [INFO] Found BUILD_DIR: ${BUILD_DIR}" + fi +} + +__check_cxx_envs() { + if [ $LDFLAGS ]; then + echo "-- [INFO] Found LDFLAGS: ${LDFLAGS}, \c" + echo "unset it before crossing compiling ${ANDROID_ABI}" + unset LDFLAGS + fi + if [ $CPPFLAGS ]; then + echo "-- [INFO] Found CPPFLAGS: ${CPPFLAGS}, \c" + echo "unset it before crossing compiling ${ANDROID_ABI}" + unset CPPFLAGS + fi + if [ $CPLUS_INCLUDE_PATH ]; then + echo "-- [INFO] Found CPLUS_INCLUDE_PATH: ${CPLUS_INCLUDE_PATH}, \c" + echo "unset it before crossing compiling ${ANDROID_ABI}" + unset CPLUS_INCLUDE_PATH + fi + if [ $C_INCLUDE_PATH ]; then + echo "-- [INFO] Found C_INCLUDE_PATH: ${C_INCLUDE_PATH}, \c" + echo "unset it before crossing compiling ${ANDROID_ABI}" + unset C_INCLUDE_PATH + fi +} + +__set_android_ndk() { + if [ -z $ANDROID_NDK ]; then + echo "-- [INFO] ANDROID_NDK not exists, please setup manually ..." + exit 0 + else + echo "-- [INFO] Found ANDROID_NDK: ${ANDROID_NDK}" + fi + if [ "$ANDROID_NDK" ]; then + NDK_VERSION=$(echo $ANDROID_NDK | egrep -o "[0-9]{2}" | head -n 1) + if [ "$NDK_VERSION" -gt 17 ]; then + TOOLCHAIN=clang + fi + echo "-- [INFO] Checked ndk version: ${NDK_VERSION}" + echo "-- [INFO] Selected toolchain: ${TOOLCHAIN}" + fi +} + +__build_fastdeploy_android_shared() { + + local ANDROID_STL=c++_shared # c++_static + local ANDROID_TOOLCHAIN=${TOOLCHAIN} + local TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake + local FASDEPLOY_INSTALL_DIR="${ROOT_PATH}/${BUILD_DIR}/install" + cd "${BUILD_DIR}" && echo "-- [INFO] Working Dir: ${PWD}" + + cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DANDROID_ABI=${ANDROID_ABI} \ + -DANDROID_NDK=${ANDROID_NDK} \ + -DANDROID_PLATFORM=${ANDROID_PLATFORM} \ + -DANDROID_STL=${ANDROID_STL} \ + -DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN} \ + -DENABLE_ORT_BACKEND=OFF \ + -DENABLE_LITE_BACKEND=ON \ + -DENABLE_PADDLE_FRONTEND=OFF \ + -DENABLE_FLYCV=ON \ + -DENABLE_TEXT=ON \ + -DENABLE_VISION=ON \ + -DENABLE_VISION_VISUALIZE=ON \ + -DBUILD_EXAMPLES=ON \ + -DWITH_OPENCV_STATIC=OFF \ + -DWITH_LITE_STATIC=OFF \ + -DWITH_OPENMP=OFF \ + -DCMAKE_INSTALL_PREFIX=${FASDEPLOY_INSTALL_DIR} \ + -Wno-dev ../../.. && make -j8 && make install + + echo "-- [INFO][built][${ANDROID_ABI}][${BUILD_DIR}/install]" +} + +main() { + __make_build_dir + __check_cxx_envs + __set_android_ndk + __build_fastdeploy_android_shared + exit 0 +} + +main + +# Usage: +# ./scripts/android/build_android_cpp_with_text_api.sh arm64-v8a 21 +# ./scripts/android/build_android_cpp_with_text_api.sh armeabi-v7a 21 From 54a8fe0e88ee35e8080c5606e761bd901259790d Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 15:59:16 +0800 Subject: [PATCH 10/77] Update cpu.md --- docs/en/build_and_install/cpu.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/en/build_and_install/cpu.md b/docs/en/build_and_install/cpu.md index f280cce69..bc01fb1f2 100644 --- a/docs/en/build_and_install/cpu.md +++ b/docs/en/build_and_install/cpu.md @@ -30,6 +30,11 @@ Prerequisite for Compiling on Linux & Mac: - gcc/g++ >= 5.4 (8.2 is recommended) - cmake >= 3.18.0 +It it recommend install OpenCV library manually, and define `-DOPENCV_DIRECTORY` to set path of OpenCV library(If the flag is not defined, a prebuilt OpenCV library will be downloaded automaticly while building FastDeploy, but the prebuilt OpenCV cannot support reading video file or other function e.g `imshow`) +``` +sudo apt-get install libopencv-dev +``` + ``` git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy @@ -38,7 +43,8 @@ cmake .. -DENABLE_ORT_BACKEND=ON \ -DENABLE_PADDLE_BACKEND=ON \ -DENABLE_OPENVINO_BACKEND=ON \ -DCMAKE_INSTALL_PREFIX=${PWD}/compiled_fastdeploy_sdk \ - -DENABLE_VISION=ON + -DENABLE_VISION=ON \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 make -j12 make install ``` @@ -84,6 +90,11 @@ All compilation options are introduced via environment variables ### Linux & Mac +It it recommend install OpenCV library manually, and define `-DOPENCV_DIRECTORY` to set path of OpenCV library(If the flag is not defined, a prebuilt OpenCV library will be downloaded automaticly while building FastDeploy, but the prebuilt OpenCV cannot support reading video file or other function e.g `imshow`) +``` +sudo apt-get install libopencv-dev +``` + ``` git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy/python @@ -91,6 +102,8 @@ export ENABLE_ORT_BACKEND=ON export ENABLE_PADDLE_BACKEND=ON export ENABLE_OPENVINO_BACKEND=ON export ENABLE_VISION=ON +# The OPENCV_DIRECTORY is optional, if not exported, a prebuilt OpenCV library will be downloaded +export OPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 python setup.py build python setup.py bdist_wheel From ee144090057c728928b2ced0d888e36da3bbea5b Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 16:00:09 +0800 Subject: [PATCH 11/77] Update gpu.md --- docs/en/build_and_install/gpu.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/en/build_and_install/gpu.md b/docs/en/build_and_install/gpu.md index 40357f118..df0645262 100644 --- a/docs/en/build_and_install/gpu.md +++ b/docs/en/build_and_install/gpu.md @@ -34,6 +34,11 @@ Prerequisite for Compiling on Linux: - cuda >= 11.2 - cudnn >= 8.2 +It it recommend install OpenCV library manually, and define `-DOPENCV_DIRECTORY` to set path of OpenCV library(If the flag is not defined, a prebuilt OpenCV library will be downloaded automaticly while building FastDeploy, but the prebuilt OpenCV cannot support reading video file or other function e.g `imshow`) +``` +sudo apt-get install libopencv-dev +``` + ``` git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy @@ -46,7 +51,8 @@ cmake .. -DENABLE_ORT_BACKEND=ON \ -DTRT_DIRECTORY=/Paddle/TensorRT-8.4.1.5 \ -DCUDA_DIRECTORY=/usr/local/cuda \ -DCMAKE_INSTALL_PREFIX=${PWD}/compiled_fastdeploy_sdk \ - -DENABLE_VISION=ON + -DENABLE_VISION=ON \ + -DOPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 make -j12 make install ``` @@ -106,6 +112,11 @@ Prerequisite for Compiling on Linux: All compilation options are imported via environment variables +It it recommend install OpenCV library manually, and define `-DOPENCV_DIRECTORY` to set path of OpenCV library(If the flag is not defined, a prebuilt OpenCV library will be downloaded automaticly while building FastDeploy, but the prebuilt OpenCV cannot support reading video file or other function e.g `imshow`) +``` +sudo apt-get install libopencv-dev +``` + ``` git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy/python @@ -117,6 +128,8 @@ export ENABLE_TRT_BACKEND=ON export WITH_GPU=ON export TRT_DIRECTORY=/Paddle/TensorRT-8.4.1.5 export CUDA_DIRECTORY=/usr/local/cuda +# The OPENCV_DIRECTORY is optional, if not exported, a prebuilt OpenCV library will be downloaded +export OPENCV_DIRECTORY=/usr/lib/x86_64-linux-gnu/cmake/opencv4 python setup.py build python setup.py bdist_wheel From 24327044e99ee9e6d3062ce49994124df4b8b8a3 Mon Sep 17 00:00:00 2001 From: DefTruth <31974251+DefTruth@users.noreply.github.com> Date: Fri, 9 Dec 2022 17:40:57 +0800 Subject: [PATCH 12/77] [cmake] Update paddlelite.cmake (#845) Update paddlelite.cmake --- cmake/paddlelite.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/paddlelite.cmake b/cmake/paddlelite.cmake index 299843a6d..bcc0eb470 100755 --- a/cmake/paddlelite.cmake +++ b/cmake/paddlelite.cmake @@ -58,7 +58,7 @@ elseif(ANDROID) endif() else() # Linux if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") - set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-linux-arm64-20220920.tgz") + set(PADDLELITE_URL "${PADDLELITE_URL_PREFIX}/lite-linux-arm64-20221209.tgz") else() if(ENABLE_TIMVX) set(PADDLELITE_URL "https://bj.bcebos.com/fastdeploy/test/lite-linux_armhf_1130.tgz") From 035e51e6a4865ef615fba0f26651310bc7ee93aa Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 17:48:28 +0800 Subject: [PATCH 13/77] Update jetson.md --- docs/cn/build_and_install/jetson.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/cn/build_and_install/jetson.md b/docs/cn/build_and_install/jetson.md index f60aa280c..43a3bb51e 100644 --- a/docs/cn/build_and_install/jetson.md +++ b/docs/cn/build_and_install/jetson.md @@ -10,12 +10,17 @@ FastDeploy当前在Jetson仅支持ONNX Runtime CPU和TensorRT GPU两种后端推 - cmake >= 3.10.0 - jetpack >= 4.6.1 + +如果需要集成Paddle Inference后端,在[Paddle Inference预编译库](https://www.paddlepaddle.org.cn/inference/v2.4/guides/install/download_lib.html#c)页面根据开发环境选择对应的Jetpack C++包下载,并解压。 + ```bash git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy mkdir build && cd build cmake .. -DBUILD_ON_JETSON=ON \ -DENABLE_VISION=ON \ + -DENABLE_PADDLE_BACKEND=ON \ + -DPADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson \ -DCMAKE_INSTALL_PREFIX=${PWD}/installed_fastdeploy make -j8 make install @@ -34,6 +39,8 @@ make install Python打包依赖`wheel`,编译前请先执行`pip install wheel` +如果需要集成Paddle Inference后端,在[Paddle Inference预编译库](https://www.paddlepaddle.org.cn/inference/v2.4/guides/install/download_lib.html#c)页面根据开发环境选择对应的Jetpack C++包下载,并解压。 + 所有编译选项通过环境变量导入 ```bash @@ -41,6 +48,8 @@ git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy/python export BUILD_ON_JETSON=ON export ENABLE_VISION=ON +export ENABLE_PADDLE_BACKEND=ON +export PADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson python setup.py build python setup.py bdist_wheel From 924d0e0e7b7077f5d2b3f24a07d1e5da39258817 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 17:52:08 +0800 Subject: [PATCH 14/77] Update jetson.md --- docs/en/build_and_install/jetson.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/en/build_and_install/jetson.md b/docs/en/build_and_install/jetson.md index e606b6d29..8d16f3149 100644 --- a/docs/en/build_and_install/jetson.md +++ b/docs/en/build_and_install/jetson.md @@ -1,7 +1,7 @@ # How to Build FastDeploy Library on Nvidia Jetson Platform -FastDeploy supports CPU inference with ONNX Runtime and GPU inference with Nvidia TensorRT on Nvidia Jetson platform +FastDeploy supports CPU inference with ONNX Runtime and GPU inference with Nvidia TensorRT/Paddle Inference on Nvidia Jetson platform ## How to Build and Install FastDeploy C++ Library @@ -11,12 +11,16 @@ Prerequisite for Compiling on NVIDIA Jetson: - cmake >= 3.10.0 - jetpack >= 4.6.1 +If you need to integrate Paddle Inference backend(Support CPU/GPU),please download and decompress the prebuilt library in [Paddle Inference prebuild libraries](https://www.paddlepaddle.org.cn/inference/v2.4/guides/install/download_lib.html#c) according to your develop envriment. + ``` git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy mkdir build && cd build cmake .. -DBUILD_ON_JETSON=ON \ -DENABLE_VISION=ON \ + -DENABLE_PADDLE_BACKEND=ON \ # This is optional, can be OFF if you don't need + -DPADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson \ -DCMAKE_INSTALL_PREFIX=${PWD}/installed_fastdeploy make -j8 make install @@ -35,6 +39,8 @@ Prerequisite for Compiling on NVIDIA Jetson: Notice the `wheel` is required if you need to pack a wheel, execute `pip install wheel` first. +If you need to integrate Paddle Inference backend(Support CPU/GPU),please download and decompress the prebuilt library in [Paddle Inference prebuild libraries](https://www.paddlepaddle.org.cn/inference/v2.4/guides/install/download_lib.html#c) according to your develop envriment. + All compilation options are imported via environment variables ``` @@ -43,6 +49,10 @@ cd FastDeploy/python export BUILD_ON_JETSON=ON export ENABLE_VISION=ON +# ENABLE_PADDLE_BACKEND & PADDLEINFERENCE_DIRECTORY are optional +export ENABLE_PADDLE_BACKEND=ON +export PADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson + python setup.py build python setup.py bdist_wheel ``` From 6f5521e63e1bc59999dba47797bc0238016f5ae5 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 9 Dec 2022 17:53:04 +0800 Subject: [PATCH 15/77] Update jetson.md --- docs/cn/build_and_install/jetson.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/cn/build_and_install/jetson.md b/docs/cn/build_and_install/jetson.md index 43a3bb51e..97ab59083 100644 --- a/docs/cn/build_and_install/jetson.md +++ b/docs/cn/build_and_install/jetson.md @@ -1,7 +1,7 @@ # Jetson部署库编译 -FastDeploy当前在Jetson仅支持ONNX Runtime CPU和TensorRT GPU两种后端推理 +FastDeploy当前在Jetson仅支持ONNX Runtime CPU和TensorRT GPU/Paddle Inference两种后端推理 ## C++ SDK编译安装 @@ -19,7 +19,7 @@ cd FastDeploy mkdir build && cd build cmake .. -DBUILD_ON_JETSON=ON \ -DENABLE_VISION=ON \ - -DENABLE_PADDLE_BACKEND=ON \ + -DENABLE_PADDLE_BACKEND=ON \ # 可选项,如若不需要Paddle Inference后端,可关闭 -DPADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson \ -DCMAKE_INSTALL_PREFIX=${PWD}/installed_fastdeploy make -j8 @@ -48,6 +48,8 @@ git clone https://github.com/PaddlePaddle/FastDeploy.git cd FastDeploy/python export BUILD_ON_JETSON=ON export ENABLE_VISION=ON + +# ENABLE_PADDLE_BACKEND & PADDLEINFERENCE_DIRECTORY为可选项 export ENABLE_PADDLE_BACKEND=ON export PADDLEINFERENCE_DIRECTORY=/Download/paddle_inference_jetson From c7dc7d5eeea2ecc461d7015284a256b61b6f87ce Mon Sep 17 00:00:00 2001 From: Zheng_Bicheng <58363586+Zheng-Bicheng@users.noreply.github.com> Date: Sat, 10 Dec 2022 15:44:00 +0800 Subject: [PATCH 16/77] Add RKYOLOv5 RKYOLOX RKYOLOV7 (#709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 更正代码格式 * 更正代码格式 * 修复语法错误 * fix rk error * update * update * update * update * update * update * update Co-authored-by: Jason --- .../paddledetection/rknpu2/README.md | 2 + examples/vision/detection/rkyolo/README.md | 18 ++ .../detection/rkyolo/cpp/CMakeLists.txt | 37 +++ .../vision/detection/rkyolo/cpp/README.md | 69 +++++ .../detection/rkyolo/cpp/infer_rkyolo.cc | 53 ++++ .../vision/detection/rkyolo/python/README.md | 34 +++ .../vision/detection/rkyolo/python/infer.py | 53 ++++ .../backends/rknpu/rknpu2/rknpu2_backend.cc | 7 +- fastdeploy/core/fd_tensor.cc | 10 + fastdeploy/core/fd_tensor.h | 5 + fastdeploy/vision.h | 1 + .../vision/detection/contrib/rknpu2/model.h | 92 +++++++ .../detection/contrib/rknpu2/postprocessor.cc | 239 ++++++++++++++++++ .../detection/contrib/rknpu2/postprocessor.h | 105 ++++++++ .../detection/contrib/rknpu2/preprocessor.cc | 127 ++++++++++ .../detection/contrib/rknpu2/preprocessor.h | 100 ++++++++ .../vision/detection/contrib/rknpu2/rkyolo.cc | 73 ++++++ .../vision/detection/contrib/rknpu2/rkyolo.h | 64 +++++ .../detection/contrib/rknpu2/rkyolo_pybind.cc | 95 +++++++ .../vision/detection/contrib/rknpu2/utils.cc | 93 +++++++ .../vision/detection/contrib/rknpu2/utils.h | 26 ++ .../vision/detection/detection_pybind.cc | 2 + .../fastdeploy/vision/detection/__init__.py | 1 + .../detection/contrib/rkyolo/__init__.py | 16 ++ .../detection/contrib/rkyolo/rkyolov5.py | 195 ++++++++++++++ 25 files changed, 1516 insertions(+), 1 deletion(-) create mode 100644 examples/vision/detection/rkyolo/README.md create mode 100644 examples/vision/detection/rkyolo/cpp/CMakeLists.txt create mode 100644 examples/vision/detection/rkyolo/cpp/README.md create mode 100644 examples/vision/detection/rkyolo/cpp/infer_rkyolo.cc create mode 100644 examples/vision/detection/rkyolo/python/README.md create mode 100644 examples/vision/detection/rkyolo/python/infer.py create mode 100644 fastdeploy/vision/detection/contrib/rknpu2/model.h create mode 100755 fastdeploy/vision/detection/contrib/rknpu2/postprocessor.cc create mode 100755 fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h create mode 100755 fastdeploy/vision/detection/contrib/rknpu2/preprocessor.cc create mode 100755 fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h create mode 100644 fastdeploy/vision/detection/contrib/rknpu2/rkyolo.cc create mode 100644 fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h create mode 100755 fastdeploy/vision/detection/contrib/rknpu2/rkyolo_pybind.cc create mode 100644 fastdeploy/vision/detection/contrib/rknpu2/utils.cc create mode 100644 fastdeploy/vision/detection/contrib/rknpu2/utils.h create mode 100644 python/fastdeploy/vision/detection/contrib/rkyolo/__init__.py create mode 100644 python/fastdeploy/vision/detection/contrib/rkyolo/rkyolov5.py diff --git a/examples/vision/detection/paddledetection/rknpu2/README.md b/examples/vision/detection/paddledetection/rknpu2/README.md index d5f339db5..98f1ada10 100644 --- a/examples/vision/detection/paddledetection/rknpu2/README.md +++ b/examples/vision/detection/paddledetection/rknpu2/README.md @@ -113,5 +113,7 @@ Preprocess: type: Resize ``` +## 其他链接 +- [Cpp部署](./cpp) - [Python部署](./python) - [视觉模型预测结果](../../../../../docs/api/vision_results/) diff --git a/examples/vision/detection/rkyolo/README.md b/examples/vision/detection/rkyolo/README.md new file mode 100644 index 000000000..015e22506 --- /dev/null +++ b/examples/vision/detection/rkyolo/README.md @@ -0,0 +1,18 @@ +# RKYOLO准备部署模型 + +RKYOLO参考[rknn_model_zoo](https://github.com/airockchip/rknn_model_zoo/tree/main/models/CV/object_detection/yolo)的代码 +对RKYOLO系列模型进行了封装,目前支持RKYOLOV5系列模型的部署。 + +## 支持模型列表 + +* RKYOLOV5 + +## 模型转换example + +请参考[RKNN_model_convert](https://github.com/airockchip/rknn_model_zoo/tree/main/models/CV/object_detection/yolo/RKNN_model_convert) + + +## 其他链接 +- [Cpp部署](./cpp) +- [Python部署](./python) +- [视觉模型预测结果](../../../../docs/api/vision_results/) diff --git a/examples/vision/detection/rkyolo/cpp/CMakeLists.txt b/examples/vision/detection/rkyolo/cpp/CMakeLists.txt new file mode 100644 index 000000000..524b94fea --- /dev/null +++ b/examples/vision/detection/rkyolo/cpp/CMakeLists.txt @@ -0,0 +1,37 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.10) +project(rknpu2_test) + +set(CMAKE_CXX_STANDARD 14) + +# 指定下载解压后的fastdeploy库路径 +set(FASTDEPLOY_INSTALL_DIR "thirdpartys/fastdeploy-0.0.3") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeployConfig.cmake) +include_directories(${FastDeploy_INCLUDE_DIRS}) + +add_executable(infer_rkyolo infer_rkyolo.cc) +target_link_libraries(infer_rkyolo ${FastDeploy_LIBS}) + + + +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/build/install) + +install(TARGETS infer_rkyolo DESTINATION ./) + +install(DIRECTORY model DESTINATION ./) +install(DIRECTORY images DESTINATION ./) + +file(GLOB FASTDEPLOY_LIBS ${FASTDEPLOY_INSTALL_DIR}/lib/*) +message("${FASTDEPLOY_LIBS}") +install(PROGRAMS ${FASTDEPLOY_LIBS} DESTINATION lib) + +file(GLOB ONNXRUNTIME_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/onnxruntime/lib/*) +install(PROGRAMS ${ONNXRUNTIME_LIBS} DESTINATION lib) + +install(DIRECTORY ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/opencv/lib DESTINATION ./) + +file(GLOB PADDLETOONNX_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/paddle2onnx/lib/*) +install(PROGRAMS ${PADDLETOONNX_LIBS} DESTINATION lib) + +file(GLOB RKNPU2_LIBS ${FASTDEPLOY_INSTALL_DIR}/third_libs/install/rknpu2_runtime/${RKNN2_TARGET_SOC}/lib/*) +install(PROGRAMS ${RKNPU2_LIBS} DESTINATION lib) diff --git a/examples/vision/detection/rkyolo/cpp/README.md b/examples/vision/detection/rkyolo/cpp/README.md new file mode 100644 index 000000000..16f8df72d --- /dev/null +++ b/examples/vision/detection/rkyolo/cpp/README.md @@ -0,0 +1,69 @@ +# RKYOLO C++部署示例 + +本目录下提供`infer_xxxxx.cc`快速完成RKYOLO模型在Rockchip板子上上通过二代NPU加速部署的示例。 + +在部署前,需确认以下两个步骤: + +1. 软硬件环境满足要求 +2. 根据开发环境,下载预编译部署库或者从头编译FastDeploy仓库 + +以上步骤请参考[RK2代NPU部署库编译](../../../../../docs/cn/build_and_install/rknpu2.md)实现 + +## 生成基本目录文件 + +该例程由以下几个部分组成 +```text +. +├── CMakeLists.txt +├── build # 编译文件夹 +├── image # 存放图片的文件夹 +├── infer_rkyolo.cc +├── model # 存放模型文件的文件夹 +└── thirdpartys # 存放sdk的文件夹 +``` + +首先需要先生成目录结构 +```bash +mkdir build +mkdir images +mkdir model +mkdir thirdpartys +``` + +## 编译 + +### 编译并拷贝SDK到thirdpartys文件夹 + +请参考[RK2代NPU部署库编译](../../../../../../docs/cn/build_and_install/rknpu2.md)仓库编译SDK,编译完成后,将在build目录下生成 +fastdeploy-0.0.3目录,请移动它至thirdpartys目录下. + +### 拷贝模型文件,以及配置文件至model文件夹 +在Paddle动态图模型 -> Paddle静态图模型 -> ONNX模型的过程中,将生成ONNX文件以及对应的yaml配置文件,请将配置文件存放到model文件夹内。 +转换为RKNN后的模型文件也需要拷贝至model。 + +### 准备测试图片至image文件夹 +```bash +wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg +cp 000000014439.jpg ./images +``` + +### 编译example + +```bash +cd build +cmake .. +make -j8 +make install +``` + +## 运行例程 + +```bash +cd ./build/install +./infer_picodet model/ images/000000014439.jpg +``` + + +- [模型介绍](../../) +- [Python部署](../python) +- [视觉模型预测结果](../../../../../../docs/api/vision_results/) diff --git a/examples/vision/detection/rkyolo/cpp/infer_rkyolo.cc b/examples/vision/detection/rkyolo/cpp/infer_rkyolo.cc new file mode 100644 index 000000000..c7c1be43b --- /dev/null +++ b/examples/vision/detection/rkyolo/cpp/infer_rkyolo.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "fastdeploy/vision.h" + +void RKNPU2Infer(const std::string& model_file, const std::string& image_file) { + struct timeval start_time, stop_time; + + auto option = fastdeploy::RuntimeOption(); + option.UseRKNPU2(); + + auto format = fastdeploy::ModelFormat::RKNN; + + auto model = fastdeploy::vision::detection::RKYOLOV5( + model_file, option,format); + + auto im = cv::imread(image_file); + + fastdeploy::vision::DetectionResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + std::cout << res.Str() << std::endl; + auto vis_im = fastdeploy::vision::VisDetection(im, res,0.5); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.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; +} + diff --git a/examples/vision/detection/rkyolo/python/README.md b/examples/vision/detection/rkyolo/python/README.md new file mode 100644 index 000000000..4549ec0f9 --- /dev/null +++ b/examples/vision/detection/rkyolo/python/README.md @@ -0,0 +1,34 @@ +# RKYOLO Python部署示例 + +在部署前,需确认以下两个步骤 + +- 1. 软硬件环境满足要求,参考[FastDeploy环境要求](../../../../../../docs/cn/build_and_install/rknpu2.md) + +本目录下提供`infer.py`快速完成Picodet在RKNPU上部署的示例。执行如下脚本即可完成 + +```bash +# 下载部署示例代码 +git clone https://github.com/PaddlePaddle/FastDeploy.git +cd FastDeploy/examples/vision/detection/rkyolo/python + +# 下载图片 +wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg + +# copy model +cp -r ./model /path/to/FastDeploy/examples/vision/detection/rkyolo/python + +# 推理 +python3 infer.py --model_file ./model/ \ + --image 000000014439.jpg +``` + + +## 注意事项 +RKNPU上对模型的输入要求是使用NHWC格式,且图片归一化操作会在转RKNN模型时,内嵌到模型中,因此我们在使用FastDeploy部署时, + +## 其它文档 + +- [PaddleDetection 模型介绍](..) +- [PaddleDetection C++部署](../cpp) +- [模型预测结果说明](../../../../../../docs/api/vision_results/) +- [转换PaddleDetection RKNN模型文档](../README.md) diff --git a/examples/vision/detection/rkyolo/python/infer.py b/examples/vision/detection/rkyolo/python/infer.py new file mode 100644 index 000000000..38eea0e8c --- /dev/null +++ b/examples/vision/detection/rkyolo/python/infer.py @@ -0,0 +1,53 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +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 rknn model.") + parser.add_argument( + "--image", type=str, required=True, help="Path of test image file.") + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_arguments() + + model_file = args.model_file + params_file = "" + + # 配置runtime,加载模型 + runtime_option = fd.RuntimeOption() + runtime_option.use_rknpu2() + + model = fd.vision.detection.RKYOLOV5( + model_file, + runtime_option=runtime_option, + model_format=fd.ModelFormat.RKNN) + + # 预测图片分割结果 + im = cv2.imread(args.image) + result = model.predict(im) + print(result) + + # 可视化结果 + vis_im = fd.vision.vis_detection(im, result, score_threshold=0.5) + cv2.imwrite("visualized_result.jpg", vis_im) + print("Visualized result save in ./visualized_result.jpg") diff --git a/fastdeploy/backends/rknpu/rknpu2/rknpu2_backend.cc b/fastdeploy/backends/rknpu/rknpu2/rknpu2_backend.cc index 16edf7561..b577c2791 100644 --- a/fastdeploy/backends/rknpu/rknpu2/rknpu2_backend.cc +++ b/fastdeploy/backends/rknpu/rknpu2/rknpu2_backend.cc @@ -190,6 +190,8 @@ bool RKNPU2Backend::GetModelInputOutputInfos() { FDERROR << "rknpu2_backend only support input format is NHWC or UNDEFINED" << std::endl; } + DumpTensorAttr(input_attrs_[i]); + // copy input_attrs_ to input tensor info std::string temp_name = input_attrs_[i].name; std::vector temp_shape{}; @@ -234,6 +236,8 @@ bool RKNPU2Backend::GetModelInputOutputInfos() { << std::endl; } + DumpTensorAttr(output_attrs_[i]); + // copy output_attrs_ to output tensor std::string temp_name = output_attrs_[i].name; std::vector temp_shape{}; @@ -342,7 +346,6 @@ bool RKNPU2Backend::Infer(std::vector& inputs, return false; } // default output type is depend on model, this requires float32 to compute top5 - output_attrs_[i].type = RKNN_TENSOR_FLOAT32; ret = rknn_set_io_mem(ctx, output_mems_[i], &output_attrs_[i]); // set output memory and attribute if (ret != RKNN_SUCC) { @@ -389,6 +392,8 @@ bool RKNPU2Backend::Infer(std::vector& inputs, } (*outputs)[i].Resize(temp_shape, outputs_desc_[i].dtype, outputs_desc_[i].name); + std::vector output_scale = {output_attrs_[i].scale}; + (*outputs)[i].SetQuantizationInfo(output_attrs_[i].zp, output_scale); memcpy((*outputs)[i].MutableData(), (float*)output_mems_[i]->virt_addr, (*outputs)[i].Nbytes()); } diff --git a/fastdeploy/core/fd_tensor.cc b/fastdeploy/core/fd_tensor.cc index e84535ac9..484e03913 100644 --- a/fastdeploy/core/fd_tensor.cc +++ b/fastdeploy/core/fd_tensor.cc @@ -138,6 +138,11 @@ void FDTensor::Resize(const std::vector& new_shape) { external_data_ptr = nullptr; } +void FDTensor::SetQuantizationInfo(int32_t zero_point,std::vector& scale){ + quantized_parameter_.first = zero_point; + quantized_parameter_.second = scale; +} + void FDTensor::Resize(const std::vector& new_shape, const FDDataType& data_type, const std::string& tensor_name, @@ -450,4 +455,9 @@ FDTensor& FDTensor::operator=(FDTensor&& other) { return *this; } +const std::pair> +FDTensor::GetQuantizationInfo() const{ + return quantized_parameter_; +} + } // namespace fastdeploy diff --git a/fastdeploy/core/fd_tensor.h b/fastdeploy/core/fd_tensor.h index 3c79b0c88..e3e373c43 100644 --- a/fastdeploy/core/fd_tensor.h +++ b/fastdeploy/core/fd_tensor.h @@ -25,6 +25,11 @@ namespace fastdeploy { struct FASTDEPLOY_DECL FDTensor { + // These two parameters are general parameters of quantitative model. + std::pair> quantized_parameter_ = {0, {0}}; + void SetQuantizationInfo(int32_t zero_point, std::vector& scale); + const std::pair> GetQuantizationInfo() const; + // std::vector data; void* buffer_ = nullptr; std::vector shape = {0}; diff --git a/fastdeploy/vision.h b/fastdeploy/vision.h index 9bea1550e..5ccaeb2dd 100644 --- a/fastdeploy/vision.h +++ b/fastdeploy/vision.h @@ -28,6 +28,7 @@ #include "fastdeploy/vision/detection/contrib/yolov7end2end_ort.h" #include "fastdeploy/vision/detection/contrib/yolov7end2end_trt.h" #include "fastdeploy/vision/detection/contrib/yolox.h" +#include "fastdeploy/vision/detection/contrib/rknpu2/model.h" #include "fastdeploy/vision/detection/ppdet/model.h" #include "fastdeploy/vision/facealign/contrib/face_landmark_1000.h" #include "fastdeploy/vision/facealign/contrib/pfld.h" diff --git a/fastdeploy/vision/detection/contrib/rknpu2/model.h b/fastdeploy/vision/detection/contrib/rknpu2/model.h new file mode 100644 index 000000000..9a0fd423d --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/model.h @@ -0,0 +1,92 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h" +namespace fastdeploy { +namespace vision { +namespace detection { + +class FASTDEPLOY_DECL RKYOLOV5 : public RKYOLO { + public: + /** \brief Set path of model file and configuration file, and the configuration of runtime + * + * \param[in] model_file Path of model file, e.g picodet/model.pdmodel + * \param[in] params_file Path of parameter file, e.g picodet/model.pdiparams, if the model format is ONNX, this parameter will be ignored + * \param[in] config_file Path of configuration file for deployment, e.g picodet/infer_cfg.yml + * \param[in] custom_option RuntimeOption for inference, the default will use cpu, and choose the backend defined in `valid_cpu_backends` + * \param[in] model_format Model format of the loaded model, default is Paddle format + */ + RKYOLOV5(const std::string& model_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::RKNN) + : RKYOLO(model_file, custom_option, model_format) { + valid_cpu_backends = {}; + valid_gpu_backends = {}; + valid_rknpu_backends = {Backend::RKNPU2}; + GetPostprocessor().SetModelType(ModelType::RKYOLOV5); + } + + virtual std::string ModelName() const { return "RKYOLOV5"; } +}; + +class FASTDEPLOY_DECL RKYOLOV7 : public RKYOLO { + public: + /** \brief Set path of model file and configuration file, and the configuration of runtime + * + * \param[in] model_file Path of model file, e.g picodet/model.pdmodel + * \param[in] params_file Path of parameter file, e.g picodet/model.pdiparams, if the model format is ONNX, this parameter will be ignored + * \param[in] config_file Path of configuration file for deployment, e.g picodet/infer_cfg.yml + * \param[in] custom_option RuntimeOption for inference, the default will use cpu, and choose the backend defined in `valid_cpu_backends` + * \param[in] model_format Model format of the loaded model, default is Paddle format + */ + RKYOLOV7(const std::string& model_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::RKNN) + : RKYOLO(model_file, custom_option, model_format) { + valid_cpu_backends = {}; + valid_gpu_backends = {}; + valid_rknpu_backends = {Backend::RKNPU2}; + GetPostprocessor().SetModelType(ModelType::RKYOLOV7); + } + + virtual std::string ModelName() const { return "RKYOLOV7"; } +}; + +class FASTDEPLOY_DECL RKYOLOX : public RKYOLO { + public: + /** \brief Set path of model file and configuration file, and the configuration of runtime + * + * \param[in] model_file Path of model file, e.g picodet/model.pdmodel + * \param[in] params_file Path of parameter file, e.g picodet/model.pdiparams, if the model format is ONNX, this parameter will be ignored + * \param[in] config_file Path of configuration file for deployment, e.g picodet/infer_cfg.yml + * \param[in] custom_option RuntimeOption for inference, the default will use cpu, and choose the backend defined in `valid_cpu_backends` + * \param[in] model_format Model format of the loaded model, default is Paddle format + */ + RKYOLOX(const std::string& model_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::RKNN) + : RKYOLO(model_file, custom_option, model_format) { + valid_cpu_backends = {}; + valid_gpu_backends = {}; + valid_rknpu_backends = {Backend::RKNPU2}; + GetPostprocessor().SetModelType(ModelType::RKYOLOX); + } + + virtual std::string ModelName() const { return "RKYOLOV7"; } +}; + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.cc b/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.cc new file mode 100755 index 000000000..bb46eff5c --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.cc @@ -0,0 +1,239 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h" +#include "fastdeploy/vision/utils/utils.h" + +namespace fastdeploy { +namespace vision { +namespace detection { + +RKYOLOPostprocessor::RKYOLOPostprocessor() {} + +void RKYOLOPostprocessor::SetModelType(ModelType model_type) { + model_type_ = model_type; + if (model_type == RKYOLOV5) { + anchors_ = {10, 13, 16, 30, 33, 23, 30, 61, 62, + 45, 59, 119, 116, 90, 156, 198, 373, 326}; + anchor_per_branch_ = 3; + } else if (model_type == RKYOLOX) { + anchors_ = {10, 13, 16, 30, 33, 23, 30, 61, 62, + 45, 59, 119, 116, 90, 156, 198, 373, 326}; + anchor_per_branch_ = 1; + } else if (model_type == RKYOLOV7) { + anchors_ = {12, 16, 19, 36, 40, 28, 36, 75, 76, + 55, 72, 146, 142, 110, 192, 243, 459, 401}; + anchor_per_branch_ = 3; + } else { + return; + } +} + +bool RKYOLOPostprocessor::Run(const std::vector& tensors, + std::vector* results) { + if (model_type_ == ModelType::UNKNOWN) { + FDERROR << "RKYOLO Only Support YOLOV5,YOLOV7,YOLOX" << std::endl; + return false; + } + + results->resize(tensors[0].shape[0]); + for (int num = 0; num < tensors[0].shape[0]; ++num) { + int validCount = 0; + std::vector filterBoxes; + std::vector boxesScore; + std::vector classId; + for (int i = 0; i < tensors.size(); i++) { + auto tensor_shape = tensors[i].shape; + auto skip_num = std::accumulate(tensor_shape.begin(), tensor_shape.end(), + 1, std::multiplies()); + int skip_address = num * skip_num; + int stride = strides_[i]; + int grid_h = height_ / stride; + int grid_w = width_ / stride; + int* anchor = &(anchors_.data()[i * 2 * anchor_per_branch_]); + if (tensors[i].dtype == FDDataType::INT8 || tensors[i].dtype == FDDataType::UINT8) { + auto quantization_info = tensors[i].GetQuantizationInfo(); + validCount = validCount + + ProcessInt8((int8_t*)tensors[i].Data() + skip_address, + anchor, grid_h, grid_w, stride, filterBoxes, + boxesScore, classId, conf_threshold_, + quantization_info.first, quantization_info.second[0]); + } else { + FDERROR << "RKYOLO Only Support INT8 Model" << std::endl; + } + } + + // no object detect + if (validCount <= 0) { + FDINFO << "The number of object detect is 0." << std::endl; + return true; + } + + std::vector indexArray; + for (int i = 0; i < validCount; ++i) { + indexArray.push_back(i); + } + + QuickSortIndiceInverse(boxesScore, 0, validCount - 1, indexArray); + + if (model_type_ == RKYOLOV5 || model_type_ == RKYOLOV7) { + NMS(validCount, filterBoxes, classId, indexArray, nms_threshold_, false); + } else if (model_type_ == RKYOLOX) { + NMS(validCount, filterBoxes, classId, indexArray, nms_threshold_, true); + } + + int last_count = 0; + (*results)[num].Clear(); + (*results)[num].Reserve(validCount); + + /* box valid detect target */ + for (int i = 0; i < validCount; ++i) { + if (indexArray[i] == -1 || boxesScore[i] < conf_threshold_ || + last_count >= obj_num_bbox_max_size) { + continue; + } + int n = indexArray[i]; + float x1 = filterBoxes[n * 4 + 0]; + float y1 = filterBoxes[n * 4 + 1]; + float x2 = x1 + filterBoxes[n * 4 + 2]; + float y2 = y1 + filterBoxes[n * 4 + 3]; + int id = classId[n]; + (*results)[num].boxes.emplace_back(std::array{ + (float)((clamp(x1, 0, width_) - pad_hw_values_[num][1] / 2) / + scale_[num]), + (float)((clamp(y1, 0, height_) - pad_hw_values_[num][0] / 2) / + scale_[num]), + (float)((clamp(x2, 0, width_) - pad_hw_values_[num][1] / 2) / + scale_[num]), + (float)((clamp(y2, 0, height_) - pad_hw_values_[num][0] / 2) / + scale_[0])}); + (*results)[num].label_ids.push_back(id); + (*results)[num].scores.push_back(boxesScore[i]); + last_count++; + } + std::cout << "last_count" << last_count << std::endl; + } + return true; +} + +int RKYOLOPostprocessor::ProcessInt8(int8_t* input, int* anchor, int grid_h, + int grid_w, int stride, + std::vector& boxes, + std::vector& boxScores, + std::vector& classId, float threshold, + int32_t zp, float scale) { + int validCount = 0; + int grid_len = grid_h * grid_w; + float thres = threshold; + auto thres_i8 = QntF32ToAffine(thres, zp, scale); + for (int a = 0; a < anchor_per_branch_; a++) { + for (int i = 0; i < grid_h; i++) { + for (int j = 0; j < grid_w; j++) { + int8_t box_confidence = + input[(prob_box_size * a + 4) * grid_len + i * grid_w + j]; + if (box_confidence >= thres_i8) { + int offset = (prob_box_size * a) * grid_len + i * grid_w + j; + int8_t* in_ptr = input + offset; + + int8_t maxClassProbs = in_ptr[5 * grid_len]; + int maxClassId = 0; + for (int k = 1; k < obj_class_num; ++k) { + int8_t prob = in_ptr[(5 + k) * grid_len]; + if (prob > maxClassProbs) { + maxClassId = k; + maxClassProbs = prob; + } + } + + float box_conf_f32 = DeqntAffineToF32(box_confidence, zp, scale); + float class_prob_f32 = DeqntAffineToF32(maxClassProbs, zp, scale); + float limit_score = 0; + if (model_type_ == RKYOLOX) { + limit_score = box_conf_f32 * class_prob_f32; + } else { + limit_score = class_prob_f32; + } + //printf("limit score: %f\n", limit_score); + if (limit_score > conf_threshold_) { + float box_x, box_y, box_w, box_h; + if (model_type_ == RKYOLOX) { + box_x = DeqntAffineToF32(*in_ptr, zp, scale); + box_y = DeqntAffineToF32(in_ptr[grid_len], zp, scale); + box_w = DeqntAffineToF32(in_ptr[2 * grid_len], zp, scale); + box_h = DeqntAffineToF32(in_ptr[3 * grid_len], zp, scale); + box_w = exp(box_w) * stride; + box_h = exp(box_h) * stride; + } else { + box_x = DeqntAffineToF32(*in_ptr, zp, scale) * 2.0 - 0.5; + box_y = DeqntAffineToF32(in_ptr[grid_len], zp, scale) * 2.0 - 0.5; + box_w = DeqntAffineToF32(in_ptr[2 * grid_len], zp, scale) * 2.0; + box_h = DeqntAffineToF32(in_ptr[3 * grid_len], zp, scale) * 2.0; + box_w = box_w * box_w; + box_h = box_h * box_h; + } + box_x = (box_x + j) * (float)stride; + box_y = (box_y + i) * (float)stride; + box_w *= (float)anchor[a * 2]; + box_h *= (float)anchor[a * 2 + 1]; + box_x -= (box_w / 2.0); + box_y -= (box_h / 2.0); + + boxes.push_back(box_x); + boxes.push_back(box_y); + boxes.push_back(box_w); + boxes.push_back(box_h); + boxScores.push_back(box_conf_f32 * class_prob_f32); + classId.push_back(maxClassId); + validCount++; + } + } + } + } + } + return validCount; +} + +int RKYOLOPostprocessor::QuickSortIndiceInverse(std::vector& input, + int left, int right, + std::vector& indices) { + float key; + int key_index; + int low = left; + int high = right; + if (left < right) { + key_index = indices[left]; + key = input[left]; + while (low < high) { + while (low < high && input[high] <= key) { + high--; + } + input[low] = input[high]; + indices[low] = indices[high]; + while (low < high && input[low] >= key) { + low++; + } + input[high] = input[low]; + indices[high] = indices[low]; + } + input[low] = key; + indices[low] = key_index; + QuickSortIndiceInverse(input, left, low - 1, indices); + QuickSortIndiceInverse(input, low + 1, right, indices); + } + return low; +} + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h b/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h new file mode 100755 index 000000000..0332b2efd --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h @@ -0,0 +1,105 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "fastdeploy/vision/common/processors/transform.h" +#include "fastdeploy/vision/common/result.h" +#include "fastdeploy/vision/detection/contrib/rknpu2/utils.h" +#include +namespace fastdeploy { +namespace vision { +namespace detection { +/*! @brief Postprocessor object for YOLOv5 serials model. + */ +class FASTDEPLOY_DECL RKYOLOPostprocessor { + public: + /** \brief Create a postprocessor instance for YOLOv5 serials model + */ + RKYOLOPostprocessor(); + + /** \brief Process the result of runtime and fill to DetectionResult structure + * + * \param[in] tensors The inference result from runtime + * \param[in] result The output result of detection + * \param[in] ims_info The shape info list, record input_shape and output_shape + * \return true if the postprocess successed, otherwise false + */ + bool Run(const std::vector& tensors, + std::vector* results); + + /// Set nms_threshold, default 0.45 + void SetNMSThreshold(const float& nms_threshold) { + nms_threshold_ = nms_threshold; + } + + /// Set conf_threshold, default 0.25 + void SetConfThreshold(const float& conf_threshold) { + conf_threshold_ = conf_threshold; + } + + /// Get conf_threshold, default 0.25 + float GetConfThreshold() const { return conf_threshold_; } + + /// Get nms_threshold, default 0.45 + float GetNMSThreshold() const { return nms_threshold_; } + + // Set model_type + void SetModelType(ModelType model_type); + + // Set height and weight + void SetHeightAndWeight(int& height, int& width) { + height_ = height; + width_ = width; + } + + // Set pad_hw_values + void SetPadHWValues(std::vector> pad_hw_values) { + pad_hw_values_ = pad_hw_values; + } + + // Set scale + void SetScale(std::vector scale) { scale_ = scale; } + + private: + ModelType model_type_ = ModelType::UNKNOWN; + std::vector anchors_ = {10, 13, 16, 30, 33, 23, 30, 61, 62, + 45, 59, 119, 116, 90, 156, 198, 373, 326}; + int strides_[3] = {8, 16, 32}; + int height_ = 0; + int width_ = 0; + int anchor_per_branch_ = 0; + + // Process Int8 Model + int ProcessInt8(int8_t* input, int* anchor, int grid_h, int grid_w, + int stride, std::vector& boxes, + std::vector& boxScores, std::vector& classId, + float threshold, int32_t zp, float scale); + + // Model + int QuickSortIndiceInverse(std::vector& input, int left, int right, + std::vector& indices); + + // post_process values + std::vector> pad_hw_values_; + std::vector scale_; + float nms_threshold_ = 0.45; + float conf_threshold_ = 0.25; + int prob_box_size = 85; + int obj_class_num = 80; + int obj_num_bbox_max_size = 200; +}; + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.cc b/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.cc new file mode 100755 index 000000000..29480459b --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h" +#include "fastdeploy/function/concat.h" + +namespace fastdeploy { +namespace vision { +namespace detection { + +RKYOLOPreprocessor::RKYOLOPreprocessor() { + size_ = {640, 640}; + padding_value_ = {114.0, 114.0, 114.0}; + is_mini_pad_ = false; + is_no_pad_ = false; + is_scale_up_ = true; + stride_ = 32; + max_wh_ = 7680.0; +} + +void RKYOLOPreprocessor::LetterBox(FDMat* mat) { + std::cout << "mat->Height() = " << mat->Height() << std::endl; + std::cout << "mat->Width() = " << mat->Width() << std::endl; + + float scale = + std::min(size_[1] * 1.0 / mat->Height(), size_[0] * 1.0 / mat->Width()); + std::cout << "RKYOLOPreprocessor scale_ = " << scale << std::endl; + if (!is_scale_up_) { + scale = std::min(scale, 1.0f); + } + std::cout << "RKYOLOPreprocessor scale_ = " << scale << std::endl; + scale_.push_back(scale); + + int resize_h = int(round(mat->Height() * scale)); + int resize_w = int(round(mat->Width() * scale)); + + int pad_w = size_[0] - resize_w; + int pad_h = size_[1] - resize_h; + if (is_mini_pad_) { + pad_h = pad_h % stride_; + pad_w = pad_w % stride_; + } else if (is_no_pad_) { + pad_h = 0; + pad_w = 0; + resize_h = size_[1]; + resize_w = size_[0]; + } + + pad_hw_values_.push_back({pad_h,pad_w}); + + if (std::fabs(scale - 1.0f) > 1e-06) { + Resize::Run(mat, resize_w, resize_h); + } + if (pad_h > 0 || pad_w > 0) { + float half_h = pad_h * 1.0 / 2; + int top = int(round(half_h - 0.1)); + int bottom = int(round(half_h + 0.1)); + float half_w = pad_w * 1.0 / 2; + int left = int(round(half_w - 0.1)); + int right = int(round(half_w + 0.1)); + Pad::Run(mat, top, bottom, left, right, padding_value_); + } +} + +bool RKYOLOPreprocessor::Preprocess(FDMat* mat, FDTensor* output) { + // process after image load +// float ratio = std::min(size_[1] * 1.0f / static_cast(mat->Height()), +// size_[0] * 1.0f / static_cast(mat->Width())); +// if (std::fabs(ratio - 1.0f) > 1e-06) { +// int interp = cv::INTER_AREA; +// if (ratio > 1.0) { +// interp = cv::INTER_LINEAR; +// } +// int resize_h = int(mat->Height() * ratio); +// int resize_w = int(mat->Width() * ratio); +// Resize::Run(mat, resize_w, resize_h, -1, -1, interp); +// } + + // RKYOLO's preprocess steps + // 1. letterbox + // 2. convert_and_permute(swap_rb=true) + LetterBox(mat); + BGR2RGB::Run(mat); + mat->ShareWithTensor(output); + output->ExpandDim(0); // reshape to n, h, w, c + return true; +} + +bool RKYOLOPreprocessor::Run(std::vector* images, + std::vector* outputs) { + if (images->size() == 0) { + FDERROR << "The size of input images should be greater than 0." + << std::endl; + return false; + } + outputs->resize(1); + // Concat all the preprocessed data to a batch tensor + std::vector tensors(images->size()); + for (size_t i = 0; i < images->size(); ++i) { + if (!Preprocess(&(*images)[i], &tensors[i])) { + FDERROR << "Failed to preprocess input image." << std::endl; + return false; + } + } + + if (tensors.size() == 1) { + (*outputs)[0] = std::move(tensors[0]); + } else { + function::Concat(tensors, &((*outputs)[0]), 0); + } + return true; +} + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h b/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h new file mode 100755 index 000000000..e6ecfe452 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h @@ -0,0 +1,100 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "fastdeploy/vision/common/processors/transform.h" +#include "fastdeploy/vision/common/result.h" + +namespace fastdeploy { +namespace vision { + +namespace detection { +/*! @brief Preprocessor object for YOLOv5 serials model. + */ +class FASTDEPLOY_DECL RKYOLOPreprocessor { + public: + /** \brief Create a preprocessor instance for YOLOv5 serials model + */ + RKYOLOPreprocessor(); + + /** \brief Process the input image and prepare input tensors for runtime + * + * \param[in] images The input image data list, all the elements are returned by cv::imread() + * \param[in] outputs The output tensors which will feed in runtime + * \param[in] ims_info The shape info list, record input_shape and output_shape + * \return true if the preprocess successed, otherwise false + */ + bool Run(std::vector* images, std::vector* outputs); + + /// Set target size, tuple of (width, height), default size = {640, 640} + void SetSize(const std::vector& size) { size_ = size; } + + /// Get target size, tuple of (width, height), default size = {640, 640} + std::vector GetSize() const { return size_; } + + /// Set padding value, size should be the same as channels + void SetPaddingValue(const std::vector& padding_value) { + padding_value_ = padding_value; + } + + /// Get padding value, size should be the same as channels + std::vector GetPaddingValue() const { return padding_value_; } + + /// Set is_scale_up, if is_scale_up is false, the input image only + /// can be zoom out, the maximum resize scale cannot exceed 1.0, default true + void SetScaleUp(bool is_scale_up) { is_scale_up_ = is_scale_up; } + + /// Get is_scale_up, default true + bool GetScaleUp() const { return is_scale_up_; } + + std::vector> GetPadHWValues() const { + return pad_hw_values_; + } + std::vector GetScale() const { return scale_; } + + protected: + bool Preprocess(FDMat* mat, FDTensor* output); + + void LetterBox(FDMat* mat); + + // target size, tuple of (width, height), default size = {640, 640} + std::vector size_; + + // padding value, size should be the same as channels + std::vector padding_value_; + + // only pad to the minimum rectange which height and width is times of stride + bool is_mini_pad_; + + // while is_mini_pad = false and is_no_pad = true, + // will resize the image to the set size + bool is_no_pad_; + + // if is_scale_up is false, the input image only can be zoom out, + // the maximum resize scale cannot exceed 1.0 + bool is_scale_up_; + + // padding stride, for is_mini_pad + int stride_; + + // for offseting the boxes by classes when using NMS + float max_wh_; + + std::vector> pad_hw_values_; + std::vector scale_; +}; + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.cc b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.cc new file mode 100644 index 000000000..017cb1be3 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.cc @@ -0,0 +1,73 @@ +#include "fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h" + +namespace fastdeploy { +namespace vision { +namespace detection { + +RKYOLO::RKYOLO(const std::string& model_file, + const fastdeploy::RuntimeOption& custom_option, + const fastdeploy::ModelFormat& model_format) { + if (model_format == ModelFormat::RKNN) { + valid_cpu_backends = {}; + valid_gpu_backends = {}; + valid_rknpu_backends = {Backend::RKNPU2}; + } else { + FDERROR << "RKYOLO Only Support run in RKNPU2" << std::endl; + } + runtime_option = custom_option; + runtime_option.model_format = model_format; + runtime_option.model_file = model_file; + initialized = Initialize(); +} + +bool RKYOLO::Initialize() { + if (!InitRuntime()) { + FDERROR << "Failed to initialize fastdeploy backend." << std::endl; + return false; + } + auto size = GetPreprocessor().GetSize(); + GetPostprocessor().SetHeightAndWeight(size[0],size[1]); + return true; +} + +bool RKYOLO::Predict(const cv::Mat& im, + DetectionResult* result) { + std::vector results; + if (!BatchPredict({im}, &results)) { + return false; + } + *result = std::move(results[0]); + return true; +} + +bool RKYOLO::BatchPredict(const std::vector& images, + std::vector* results) { + std::vector fd_images = WrapMat(images); + + if (!preprocessor_.Run(&fd_images, &reused_input_tensors_)) { + FDERROR << "Failed to preprocess the input image." << std::endl; + return false; + } + auto pad_hw_values_ = preprocessor_.GetPadHWValues(); + postprocessor_.SetPadHWValues(preprocessor_.GetPadHWValues()); + std::cout << "preprocessor_ scale_ = " << preprocessor_.GetScale()[0] << std::endl; + postprocessor_.SetScale(preprocessor_.GetScale()); + + reused_input_tensors_[0].name = InputInfoOfRuntime(0).name; + if (!Infer(reused_input_tensors_, &reused_output_tensors_)) { + FDERROR << "Failed to inference by runtime." << std::endl; + return false; + } + + + if (!postprocessor_.Run(reused_output_tensors_, results)) { + FDERROR << "Failed to postprocess the inference results by runtime." << std::endl; + return false; + } + + return true; +} + +} // namespace detection +} // namespace vision +} // namespace fastdeploy \ No newline at end of file diff --git a/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h new file mode 100644 index 000000000..d7190eb73 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo.h @@ -0,0 +1,64 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. //NOLINT +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "fastdeploy/fastdeploy_model.h" +#include "fastdeploy/vision/detection/contrib/rknpu2/postprocessor.h" +#include "fastdeploy/vision/detection/contrib/rknpu2/preprocessor.h" + +namespace fastdeploy { +namespace vision { +namespace detection { + +class FASTDEPLOY_DECL RKYOLO : public FastDeployModel { + public: + RKYOLO(const std::string& model_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::RKNN); + + std::string ModelName() const { return "RKYOLO"; } + + /** \brief Predict the detection result for an input image + * + * \param[in] img The input image data, comes from cv::imread(), is a 3-D array with layout HWC, BGR format + * \param[in] result The output detection result will be writen to this structure + * \return true if the prediction successed, otherwise false + */ + virtual bool Predict(const cv::Mat& img, DetectionResult* result); + + /** \brief Predict the detection results for a batch of input images + * + * \param[in] imgs, The input image list, each element comes from cv::imread() + * \param[in] results The output detection result list + * \return true if the prediction successed, otherwise false + */ + virtual bool BatchPredict(const std::vector& imgs, + std::vector* results); + + /// Get preprocessor reference of YOLOv5 + RKYOLOPreprocessor& GetPreprocessor() { return preprocessor_; } + + /// Get postprocessor reference of YOLOv5 + RKYOLOPostprocessor& GetPostprocessor() { return postprocessor_; } + + protected: + bool Initialize(); + RKYOLOPreprocessor preprocessor_; + RKYOLOPostprocessor postprocessor_; +}; + +} // namespace detection +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/rkyolo_pybind.cc b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo_pybind.cc new file mode 100755 index 000000000..716464458 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/rkyolo_pybind.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fastdeploy/pybind/main.h" + +namespace fastdeploy { +void BindRKYOLO(pybind11::module& m) { + pybind11::class_( + m, "RKYOLOPreprocessor") + .def(pybind11::init<>()) + .def("run", [](vision::detection::RKYOLOPreprocessor& self, + std::vector& im_list) { + std::vector images; + for (size_t i = 0; i < im_list.size(); ++i) { + images.push_back(vision::WrapMat(PyArrayToCvMat(im_list[i]))); + } + std::vector outputs; + if (!self.Run(&images, &outputs)) { + throw std::runtime_error("Failed to preprocess the input data in PaddleClasPreprocessor."); + } + for (size_t i = 0; i < outputs.size(); ++i) { + outputs[i].StopSharing(); + } + return outputs; + }) + .def_property("size", &vision::detection::RKYOLOPreprocessor::GetSize, + &vision::detection::RKYOLOPreprocessor::SetSize) + .def_property("padding_value", &vision::detection::RKYOLOPreprocessor::GetPaddingValue, + &vision::detection::RKYOLOPreprocessor::SetPaddingValue) + .def_property("is_scale_up", &vision::detection::RKYOLOPreprocessor::GetScaleUp, + &vision::detection::RKYOLOPreprocessor::SetScaleUp); + + pybind11::class_( + m, "RKYOLOPostprocessor") + .def(pybind11::init<>()) + .def("run", [](vision::detection::RKYOLOPostprocessor& self, + std::vector& inputs) { + std::vector results; + if (!self.Run(inputs, &results)) { + throw std::runtime_error("Failed to postprocess the runtime result in RKYOLOV5Postprocessor."); + } + return results; + }) + .def("run", [](vision::detection::RKYOLOPostprocessor& self, + std::vector& input_array) { + std::vector results; + std::vector inputs; + PyArrayToTensorList(input_array, &inputs, /*share_buffer=*/true); + if (!self.Run(inputs, &results)) { + throw std::runtime_error("Failed to postprocess the runtime result in RKYOLOV5Postprocessor."); + } + return results; + }) + .def_property("conf_threshold", &vision::detection::RKYOLOPostprocessor::GetConfThreshold, + &vision::detection::RKYOLOPostprocessor::SetConfThreshold) + .def_property("nms_threshold", &vision::detection::RKYOLOPostprocessor::GetNMSThreshold, + &vision::detection::RKYOLOPostprocessor::SetNMSThreshold); + + pybind11::class_(m, "RKYOLOV5") + .def(pybind11::init()) + .def("predict", + [](vision::detection::RKYOLOV5& self, + pybind11::array& data) { + auto mat = PyArrayToCvMat(data); + vision::DetectionResult res; + self.Predict(mat, &res); + return res; + }) + .def("batch_predict", [](vision::detection::RKYOLOV5& self, + std::vector& data) { + std::vector images; + for (size_t i = 0; i < data.size(); ++i) { + images.push_back(PyArrayToCvMat(data[i])); + } + std::vector results; + self.BatchPredict(images, &results); + return results; + }) + .def_property_readonly("preprocessor", &vision::detection::RKYOLOV5::GetPreprocessor) + .def_property_readonly("postprocessor", &vision::detection::RKYOLOV5::GetPostprocessor); +} +} // namespace fastdeploy diff --git a/fastdeploy/vision/detection/contrib/rknpu2/utils.cc b/fastdeploy/vision/detection/contrib/rknpu2/utils.cc new file mode 100644 index 000000000..faac26983 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/utils.cc @@ -0,0 +1,93 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. //NOLINT +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "fastdeploy/vision/detection/contrib/rknpu2/utils.h" +float clamp(float val, int min, int max) { + return val > min ? (val < max ? val : max) : min; +} + +float Sigmoid(float x) { return 1.0 / (1.0 + expf(-x)); } + +float UnSigmoid(float y) { return -1.0 * logf((1.0 / y) - 1.0); } + +inline int32_t __clip(float val, float min, float max) { + float f = val <= min ? min : (val >= max ? max : val); + return f; +} + +int8_t QntF32ToAffine(float f32, int32_t zp, float scale) { + float dst_val = (f32 / scale) + zp; + int8_t res = (int8_t)__clip(dst_val, -128, 127); + return res; +} + +float DeqntAffineToF32(int8_t qnt, int32_t zp, float scale) { + return ((float)qnt - (float)zp) * scale; +} + +static float CalculateOverlap(float xmin0, float ymin0, float xmax0, float ymax0, float xmin1, float ymin1, float xmax1, float ymax1) +{ + float w = fmax(0.f, fmin(xmax0, xmax1) - fmax(xmin0, xmin1) + 1.0); + float h = fmax(0.f, fmin(ymax0, ymax1) - fmax(ymin0, ymin1) + 1.0); + float i = w * h; + float u = (xmax0 - xmin0 + 1.0) * (ymax0 - ymin0 + 1.0) + (xmax1 - xmin1 + 1.0) * (ymax1 - ymin1 + 1.0) - i; + return u <= 0.f ? 0.f : (i / u); +} + +int NMS(int validCount, + std::vector &outputLocations, + std::vector &class_id, + std::vector &order, + float threshold, + bool class_agnostic) +{ + // printf("class_agnostic: %d\n", class_agnostic); + for (int i = 0; i < validCount; ++i) + { + if (order[i] == -1) + { + continue; + } + int n = order[i]; + for (int j = i + 1; j < validCount; ++j) + { + int m = order[j]; + if (m == -1) + { + continue; + } + + if (!class_agnostic && class_id[n] != class_id[m]){ + continue; + } + + float xmin0 = outputLocations[n * 4 + 0]; + float ymin0 = outputLocations[n * 4 + 1]; + float xmax0 = outputLocations[n * 4 + 0] + outputLocations[n * 4 + 2]; + float ymax0 = outputLocations[n * 4 + 1] + outputLocations[n * 4 + 3]; + + float xmin1 = outputLocations[m * 4 + 0]; + float ymin1 = outputLocations[m * 4 + 1]; + float xmax1 = outputLocations[m * 4 + 0] + outputLocations[m * 4 + 2]; + float ymax1 = outputLocations[m * 4 + 1] + outputLocations[m * 4 + 3]; + + float iou = CalculateOverlap(xmin0, ymin0, xmax0, ymax0, xmin1, ymin1, xmax1, ymax1); + + if (iou > threshold) + { + order[j] = -1; + } + } + } + return 0; +} \ No newline at end of file diff --git a/fastdeploy/vision/detection/contrib/rknpu2/utils.h b/fastdeploy/vision/detection/contrib/rknpu2/utils.h new file mode 100644 index 000000000..4414cb8a5 --- /dev/null +++ b/fastdeploy/vision/detection/contrib/rknpu2/utils.h @@ -0,0 +1,26 @@ +// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. //NOLINT +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include +#include +typedef enum { RKYOLOX = 0, RKYOLOV5, RKYOLOV7, UNKNOWN } ModelType; +float clamp(float val, int min, int max); +float Sigmoid(float x); +float UnSigmoid(float y); +inline static int32_t __clip(float val, float min, float max); +int8_t QntF32ToAffine(float f32, int32_t zp, float scale); +float DeqntAffineToF32(int8_t qnt, int32_t zp, float scale); +int NMS(int validCount, std::vector& outputLocations, + std::vector& class_id, std::vector& order, float threshold, + bool class_agnostic); diff --git a/fastdeploy/vision/detection/detection_pybind.cc b/fastdeploy/vision/detection/detection_pybind.cc index b3a7a6ad9..9d585e18c 100644 --- a/fastdeploy/vision/detection/detection_pybind.cc +++ b/fastdeploy/vision/detection/detection_pybind.cc @@ -27,6 +27,7 @@ void BindNanoDetPlus(pybind11::module& m); void BindPPDet(pybind11::module& m); void BindYOLOv7End2EndTRT(pybind11::module& m); void BindYOLOv7End2EndORT(pybind11::module& m); +void BindRKYOLO(pybind11::module& m); void BindDetection(pybind11::module& m) { auto detection_module = @@ -42,5 +43,6 @@ void BindDetection(pybind11::module& m) { BindNanoDetPlus(detection_module); BindYOLOv7End2EndTRT(detection_module); BindYOLOv7End2EndORT(detection_module); + BindRKYOLO(detection_module); } } // namespace fastdeploy diff --git a/python/fastdeploy/vision/detection/__init__.py b/python/fastdeploy/vision/detection/__init__.py index b5f01f3a7..afd1cd8ce 100755 --- a/python/fastdeploy/vision/detection/__init__.py +++ b/python/fastdeploy/vision/detection/__init__.py @@ -24,3 +24,4 @@ from .contrib.yolov6 import YOLOv6 from .contrib.yolov7end2end_trt import YOLOv7End2EndTRT from .contrib.yolov7end2end_ort import YOLOv7End2EndORT from .ppdet import * +from .contrib.rkyolo import * diff --git a/python/fastdeploy/vision/detection/contrib/rkyolo/__init__.py b/python/fastdeploy/vision/detection/contrib/rkyolo/__init__.py new file mode 100644 index 000000000..ce89483ce --- /dev/null +++ b/python/fastdeploy/vision/detection/contrib/rkyolo/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +from .rkyolov5 import * diff --git a/python/fastdeploy/vision/detection/contrib/rkyolo/rkyolov5.py b/python/fastdeploy/vision/detection/contrib/rkyolo/rkyolov5.py new file mode 100644 index 000000000..bfefb2127 --- /dev/null +++ b/python/fastdeploy/vision/detection/contrib/rkyolo/rkyolov5.py @@ -0,0 +1,195 @@ +# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +import logging +from ..... import FastDeployModel, ModelFormat +from ..... import c_lib_wrap as C + + +class RKYOLOPreprocessor: + def __init__(self): + """Create a preprocessor for RKYOLOV5 + """ + self._preprocessor = C.vision.detection.RKYOLOPreprocessor() + + def run(self, input_ims): + """Preprocess input images for RKYOLOV5 + + :param: input_ims: (list of numpy.ndarray)The input image + :return: list of FDTensor + """ + return self._preprocessor.run(input_ims) + + @property + def size(self): + """ + Argument for image preprocessing step, the preprocess image size, tuple of (width, height), default size = [640, 640] + """ + return self._preprocessor.size + + @property + def padding_value(self): + """ + padding value for preprocessing, default [114.0, 114.0, 114.0] + """ + # padding value, size should be the same as channels + return self._preprocessor.padding_value + + @property + def is_scale_up(self): + """ + is_scale_up for preprocessing, the input image only can be zoom out, the maximum resize scale cannot exceed 1.0, default true + """ + return self._preprocessor.is_scale_up + + @size.setter + def size(self, wh): + assert isinstance(wh, (list, tuple)), \ + "The value to set `size` must be type of tuple or list." + assert len(wh) == 2, \ + "The value to set `size` must contatins 2 elements means [width, height], but now it contains {} elements.".format( + len(wh)) + self._preprocessor.size = wh + + @padding_value.setter + def padding_value(self, value): + assert isinstance( + value, + list), "The value to set `padding_value` must be type of list." + self._preprocessor.padding_value = value + + @is_scale_up.setter + def is_scale_up(self, value): + assert isinstance( + value, + bool), "The value to set `is_scale_up` must be type of bool." + self._preprocessor.is_scale_up = value + + +class RKYOLOPostprocessor: + def __init__(self): + """Create a postprocessor for RKYOLOV5 + """ + self._postprocessor = C.vision.detection.RKYOLOPostprocessor() + + def run(self, runtime_results): + """Postprocess the runtime results for RKYOLOV5 + + :param: runtime_results: (list of FDTensor)The output FDTensor results from runtime + :param: ims_info: (list of dict)Record input_shape and output_shape + :return: list of DetectionResult(If the runtime_results is predict by batched samples, the length of this list equals to the batch size) + """ + return self._postprocessor.run(runtime_results) + + @property + def conf_threshold(self): + """ + confidence threshold for postprocessing, default is 0.25 + """ + return self._postprocessor.conf_threshold + + @property + def nms_threshold(self): + """ + nms threshold for postprocessing, default is 0.5 + """ + return self._postprocessor.nms_threshold + + @property + def multi_label(self): + """ + multi_label for postprocessing, set true for eval, default is True + """ + return self._postprocessor.multi_label + + @conf_threshold.setter + def conf_threshold(self, conf_threshold): + assert isinstance(conf_threshold, float), \ + "The value to set `conf_threshold` must be type of float." + self._postprocessor.conf_threshold = conf_threshold + + @nms_threshold.setter + def nms_threshold(self, nms_threshold): + assert isinstance(nms_threshold, float), \ + "The value to set `nms_threshold` must be type of float." + self._postprocessor.nms_threshold = nms_threshold + + @multi_label.setter + def multi_label(self, value): + assert isinstance( + value, + bool), "The value to set `multi_label` must be type of bool." + self._postprocessor.multi_label = value + + +class RKYOLOV5(FastDeployModel): + def __init__(self, + model_file, + params_file="", + runtime_option=None, + model_format=ModelFormat.ONNX): + """Load a RKYOLOV5 model exported by RKYOLOV5. + + :param model_file: (str)Path of model file, e.g ./yolov5.onnx + :param params_file: (str)Path of parameters file, e.g yolox/model.pdiparams, if the model_fomat is ModelFormat.ONNX, this param will be ignored, can be set as empty string + :param runtime_option: (fastdeploy.RuntimeOption)RuntimeOption for inference this model, if it's None, will use the default backend on CPU + :param model_format: (fastdeploy.ModelForamt)Model format of the loaded model + """ + # 调用基函数进行backend_option的初始化 + # 初始化后的option保存在self._runtime_option + super(RKYOLOV5, self).__init__(runtime_option) + + self._model = C.vision.detection.RKYOLOV5( + model_file, self._runtime_option, model_format) + # 通过self.initialized判断整个模型的初始化是否成功 + assert self.initialized, "RKYOLOV5 initialize failed." + + def predict(self, input_image, conf_threshold=0.25, nms_iou_threshold=0.5): + """Detect an input image + + :param input_image: (numpy.ndarray)The input image data, 3-D array with layout HWC, BGR format + :param conf_threshold: confidence threshold for postprocessing, default is 0.25 + :param nms_iou_threshold: iou threshold for NMS, default is 0.5 + :return: DetectionResult + """ + + self.postprocessor.conf_threshold = conf_threshold + self.postprocessor.nms_threshold = nms_iou_threshold + return self._model.predict(input_image) + + def batch_predict(self, images): + """Classify a batch of input image + + :param im: (list of numpy.ndarray) The input image list, each element is a 3-D array with layout HWC, BGR format + :return list of DetectionResult + """ + + return self._model.batch_predict(images) + + @property + def preprocessor(self): + """Get RKYOLOV5Preprocessor object of the loaded model + + :return RKYOLOV5Preprocessor + """ + return self._model.preprocessor + + @property + def postprocessor(self): + """Get RKYOLOV5Postprocessor object of the loaded model + + :return RKYOLOV5Postprocessor + """ + return self._model.postprocessor From e877f0fd073145dfef4c476fee3366356bd934a2 Mon Sep 17 00:00:00 2001 From: Winter <1558270516@qq.com> Date: Sun, 11 Dec 2022 12:57:59 +0800 Subject: [PATCH 17/77] [Android] add VoiceAssistant app example (#834) * [Android]add VoiceAssistant. * Create VoiceAssistantDemo * Update and rename VoiceAssistantDemo to VoiceAssistantDemo.md * Update VoiceAssistantDemo.md * Delete VoiceAssistantDemo.md * [Android]1.delete about core folder. 2.build and configure bdasr_V3_20210628_cfe8c44.aar file. * change app/build.gradle etc. * Update build.gradle Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> --- java/android/app/build.gradle | 10 +- .../VoiceAssistantMainActivity.java | 211 ++++++++++++++++++ .../VoiceAssistantWelcomeActivity.java | 30 +++ .../layout/voice_assistant_activity_main.xml | 89 ++++++++ .../res/layout/voice_assistant_welcome.xml | 76 +++++++ java/android/ui/src/main/AndroidManifest.xml | 2 + .../com/baidu/paddle/fastdeploy/ui/Utils.java | 26 +++ 7 files changed, 441 insertions(+), 3 deletions(-) create mode 100644 java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantMainActivity.java create mode 100644 java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantWelcomeActivity.java create mode 100644 java/android/app/src/main/res/layout/voice_assistant_activity_main.xml create mode 100644 java/android/app/src/main/res/layout/voice_assistant_welcome.xml diff --git a/java/android/app/build.gradle b/java/android/app/build.gradle index fde73b3b3..23b204135 100644 --- a/java/android/app/build.gradle +++ b/java/android/app/build.gradle @@ -5,7 +5,7 @@ android { defaultConfig { applicationId 'com.baidu.paddle.fastdeploy.app.examples' - minSdkVersion 15 + minSdkVersion 16 //noinspection ExpiredTargetSdkVersion targetSdkVersion 28 versionCode 1 @@ -79,6 +79,10 @@ def FD_JAVA_SDK = [ [ 'src' : 'https://bj.bcebos.com/fastdeploy/test/fastdeploy-android-sdk-latest-dev.aar', 'dest': 'libs' + ], + [ + 'src' : 'https://bj.bcebos.com/fastdeploy/test/bdasr_V3_20210628_cfe8c44.aar', + 'dest': 'libs' ] ] @@ -132,7 +136,7 @@ task downloadAndExtractSDKs(type: DefaultTask) { boolean copyFiles = false if (!file("${sdk.dest}/${sdkName}").exists()) { // Download the target SDK if not exists - if (file("${cachePath}/${sdkName}").exists()) { + if (!file("${cachePath}/${sdkName}").exists()) { println "[INFO] Downloading ${sdk.src} -> ${cachePath}/${sdkName}" ant.get(src: sdk.src, dest: file("${cachePath}/${sdkName}")) } @@ -152,4 +156,4 @@ task downloadAndExtractSDKs(type: DefaultTask) { } preBuild.dependsOn downloadAndExtractSDKs -preBuild.dependsOn downloadAndExtractModels \ No newline at end of file +preBuild.dependsOn downloadAndExtractModels diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantMainActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantMainActivity.java new file mode 100644 index 000000000..cd1592502 --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantMainActivity.java @@ -0,0 +1,211 @@ +package com.baidu.paddle.fastdeploy.app.examples.ernie.applications; + +import static com.baidu.paddle.fastdeploy.ui.Utils.isNetworkAvailable; + +import android.Manifest; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.baidu.aip.asrwakeup3.core.mini.AutoCheck; +import com.baidu.aip.asrwakeup3.core.util.AuthUtil; +import com.baidu.paddle.fastdeploy.app.examples.R; +import com.baidu.speech.EventListener; +import com.baidu.speech.EventManager; +import com.baidu.speech.EventManagerFactory; +import com.baidu.speech.asr.SpeechConstant; + +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class VoiceAssistantMainActivity extends Activity implements View.OnClickListener, EventListener { + private Button startVoiceBtn; + private TextView voiceOutput; + private Button startIntentBtn; + private TextView intentOutput; + private ImageView back; + private EventManager asr; + private Boolean isStartVoice = false; + private String voiceTxt = ""; + private int times = 0; + private final int REQUEST_PERMISSION = 0; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Fullscreen + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.voice_assistant_activity_main); + + init(); + } + + private void init() { + checkPermission(); + asr = EventManagerFactory.create(this, "asr"); + asr.registerListener(this); + startVoiceBtn = findViewById(R.id.btn_voice); + startVoiceBtn.setOnClickListener(this); + voiceOutput = findViewById(R.id.tv_voice_output); + back = findViewById(R.id.iv_back); + back.setOnClickListener(this); + startIntentBtn = findViewById(R.id.btn_intent); + startIntentBtn.setOnClickListener(this); + intentOutput = findViewById(R.id.tv_intent_output); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_voice: + if (!isNetworkAvailable(this)) { + new AlertDialog.Builder(VoiceAssistantMainActivity.this) + .setMessage("请先连接互联网。") + .setCancelable(true) + .show(); + return; + } + if (!isStartVoice) { + isStartVoice = true; + startVoiceBtn.setText("停止录音"); + start(); + } else { + isStartVoice = false; + startVoiceBtn.setText("开始录音"); + stop(); + } + break; + case R.id.iv_back: + finish(); + break; + case R.id.btn_intent: + if (voiceTxt.equals("")) { + new AlertDialog.Builder(VoiceAssistantMainActivity.this) + .setMessage("请先录音。") + .setCancelable(true) + .show(); + return; + } + intentOutput.setText("我刚才说了:" + voiceTxt); + break; + } + } + + @Override + public void onEvent(String name, String params, byte[] data, int offset, int length) { + if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) { + if (params.contains("\"final_result\"")) { + if (params.contains("[")) { + voiceTxt = params.substring(params.lastIndexOf('[') + 1, params.lastIndexOf(']')); + } + voiceOutput.setText(voiceTxt); + } + } + } + + private void start() { + Map params = AuthUtil.getParam(); + String event = null; + event = SpeechConstant.ASR_START; + params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false); + (new AutoCheck(getApplicationContext(), new Handler() { + public void handleMessage(Message msg) { + if (msg.what == 100) { + AutoCheck autoCheck = (AutoCheck) msg.obj; + synchronized (autoCheck) { + String message = autoCheck.obtainErrorMessage(); + Log.e(getClass().getName(), message); + } + } + } + }, false)).checkAsr(params); + String json = null; + json = new JSONObject(params).toString(); + asr.send(event, json, null, 0, 0); + } + + private void stop() { + asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0); + } + + @Override + protected void onPause() { + super.onPause(); + asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0); + asr.unregisterListener(this); + } + + private void checkPermission() { + times++; + final List permissionsList = new ArrayList<>(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if ((checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)) + permissionsList.add(Manifest.permission.RECORD_AUDIO); + if ((checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED)) + permissionsList.add(Manifest.permission.ACCESS_NETWORK_STATE); + if ((checkSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED)) { + permissionsList.add(Manifest.permission.INTERNET); + } + if ((checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) { + permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + if (permissionsList.size() != 0) { + if (times == 1) { + requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), + REQUEST_PERMISSION); + } else { + new AlertDialog.Builder(this) + .setCancelable(true) + .setTitle("提示") + .setMessage("获取不到授权,APP将无法正常使用,请允许APP获取权限!") + .setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface arg0, int arg1) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), + REQUEST_PERMISSION); + } + } + }).setNegativeButton("取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface arg0, int arg1) { + finish(); + } + }).show(); + } + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + checkPermission(); + } +} diff --git a/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantWelcomeActivity.java b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantWelcomeActivity.java new file mode 100644 index 000000000..f81c1c0ca --- /dev/null +++ b/java/android/app/src/main/java/com/baidu/paddle/fastdeploy/app/examples/ernie/applications/VoiceAssistantWelcomeActivity.java @@ -0,0 +1,30 @@ +package com.baidu.paddle.fastdeploy.app.examples.ernie.applications; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.View; + +import com.baidu.paddle.fastdeploy.app.examples.R; + +public class VoiceAssistantWelcomeActivity extends Activity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + ); + getWindow().setStatusBarColor(Color.TRANSPARENT); + } + setContentView(R.layout.voice_assistant_welcome); + } + + public void startActivity(View view) { + Intent intent = new Intent(VoiceAssistantWelcomeActivity.this, VoiceAssistantMainActivity.class); + startActivity(intent); + } +} diff --git a/java/android/app/src/main/res/layout/voice_assistant_activity_main.xml b/java/android/app/src/main/res/layout/voice_assistant_activity_main.xml new file mode 100644 index 000000000..c6376ac38 --- /dev/null +++ b/java/android/app/src/main/res/layout/voice_assistant_activity_main.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + +