diff --git a/benchmark/cpp/CMakeLists.txt b/benchmark/cpp/CMakeLists.txt index 2b54ac473..627d07714 100755 --- a/benchmark/cpp/CMakeLists.txt +++ b/benchmark/cpp/CMakeLists.txt @@ -40,6 +40,8 @@ add_executable(benchmark_ttfnet ${PROJECT_SOURCE_DIR}/benchmark_ttfnet.cc) add_executable(benchmark ${PROJECT_SOURCE_DIR}/benchmark.cc) add_executable(benchmark_ppdet ${PROJECT_SOURCE_DIR}/benchmark_ppdet.cc) add_executable(benchmark_dino ${PROJECT_SOURCE_DIR}/benchmark_dino.cc) +add_executable(benchmark_ppshituv2_rec ${PROJECT_SOURCE_DIR}/benchmark_ppshituv2_rec.cc) +add_executable(benchmark_ppshituv2_det ${PROJECT_SOURCE_DIR}/benchmark_ppshituv2_det.cc) if(UNIX AND (NOT APPLE) AND (NOT ANDROID)) target_link_libraries(benchmark_yolov5 ${FASTDEPLOY_LIBS} gflags pthread) @@ -75,6 +77,8 @@ if(UNIX AND (NOT APPLE) AND (NOT ANDROID)) target_link_libraries(benchmark ${FASTDEPLOY_LIBS} gflags pthread) target_link_libraries(benchmark_ppdet ${FASTDEPLOY_LIBS} gflags pthread) target_link_libraries(benchmark_dino ${FASTDEPLOY_LIBS} gflags pthread) + target_link_libraries(benchmark_ppshituv2_rec ${FASTDEPLOY_LIBS} gflags pthread) + target_link_libraries(benchmark_ppshituv2_det ${FASTDEPLOY_LIBS} gflags pthread) else() target_link_libraries(benchmark_yolov5 ${FASTDEPLOY_LIBS} gflags) target_link_libraries(benchmark_ppyolov5 ${FASTDEPLOY_LIBS} gflags) @@ -109,6 +113,8 @@ else() target_link_libraries(benchmark ${FASTDEPLOY_LIBS} gflags) target_link_libraries(benchmark_ppdet ${FASTDEPLOY_LIBS} gflags) target_link_libraries(benchmark_dino ${FASTDEPLOY_LIBS} gflags) + target_link_libraries(benchmark_ppshituv2_rec ${FASTDEPLOY_LIBS} gflags) + target_link_libraries(benchmark_ppshituv2_det ${FASTDEPLOY_LIBS} gflags) endif() # only for Android ADB test if(ANDROID) diff --git a/benchmark/cpp/benchmark.cc b/benchmark/cpp/benchmark.cc old mode 100755 new mode 100644 index e6f411d78..687e4b584 --- a/benchmark/cpp/benchmark.cc +++ b/benchmark/cpp/benchmark.cc @@ -25,7 +25,7 @@ DEFINE_string(dtypes, "FP32", "Set input dtypes for model."); DEFINE_string(trt_shapes, "1,3,224,224:1,3,224,224:1,3,224,224", "Set min/opt/max shape for trt/paddle_trt backend." "eg:--trt_shape 1,3,224,224:1,3,224,224:1,3,224,224"); -DEFINE_int32(batch, 1, "trt max batch size, default=1"); +DEFINE_int32(batch, 1, "trt max batch size, default=1"); DEFINE_bool(dump, false, "whether to dump output tensors."); DEFINE_bool(info, false, "only check the input infos of model"); DEFINE_bool(diff, false, "check the diff between two tensors."); @@ -33,12 +33,15 @@ DEFINE_string(tensors, "tensor_a.txt:tensor_b.txt", "The paths to dumped tensors."); DEFINE_bool(mem, false, "Whether to force to collect memory info."); DEFINE_int32(interval, -1, "Sampling interval for collect memory info."); -DEFINE_string(model_file, "UNKNOWN", "Optional, set specific model file," - "eg, model.pdmodel, model.onnx"); -DEFINE_string(params_file, "", "Optional, set specific params file," - "eg, model.pdiparams."); -DEFINE_string(model_format, "PADDLE", "Optional, set specific model format," - "eg, PADDLE/ONNX/RKNN/TORCHSCRIPT/SOPHGO"); +DEFINE_string(model_file, "UNKNOWN", + "Optional, set specific model file," + "eg, model.pdmodel, model.onnx"); +DEFINE_string(params_file, "", + "Optional, set specific params file," + "eg, model.pdiparams."); +DEFINE_string(model_format, "PADDLE", + "Optional, set specific model format," + "eg, PADDLE/ONNX/RKNN/TORCHSCRIPT/SOPHGO"); DEFINE_bool(disable_mkldnn, false, "disable mkldnn for paddle backend"); #if defined(ENABLE_BENCHMARK) @@ -117,9 +120,9 @@ static void RuntimeProfiling(int argc, char* argv[]) { model_file = FLAGS_model + sep + FLAGS_model_file; params_file = FLAGS_model + sep + FLAGS_params_file; model_format = GetModelFormat(FLAGS_model_format); - if (model_format == fastdeploy::ModelFormat::PADDLE - && FLAGS_params_file == "") { - std::cout << "[ERROR] params_file can not be empty for PADDLE" + if (model_format == fastdeploy::ModelFormat::PADDLE && + FLAGS_params_file == "") { + std::cout << "[ERROR] params_file can not be empty for PADDLE" << " format, Please, set your custom params_file manually." << std::endl; return; @@ -134,7 +137,7 @@ static void RuntimeProfiling(int argc, char* argv[]) { model_file = FLAGS_model + sep + model_name; params_file = FLAGS_model + sep + params_name; } - + option.SetModelPath(model_file, params_file, model_format); // Get input shapes/names/dtypes @@ -256,6 +259,9 @@ static void showInputInfos(int argc, char* argv[]) { if (!CreateRuntimeOption(&option, argc, argv, true)) { return; } + if (FLAGS_disable_mkldnn) { + option.paddle_infer_option.enable_mkldnn = false; + } std::unordered_map config_info; benchmark::ResultManager::LoadBenchmarkConfig(FLAGS_config_path, &config_info); @@ -286,7 +292,9 @@ static void showInputInfos(int argc, char* argv[]) { int main(int argc, char* argv[]) { #if defined(ENABLE_BENCHMARK) google::SetVersionString("0.0.0"); - google::SetUsageMessage("./benchmark -[info|diff|check|dump|mem] -model xxx -config_path xxx -[shapes|dtypes|names|tensors] -[model_file|params_file|model_format]"); + google::SetUsageMessage( + "./benchmark -[info|diff|check|dump|mem] -model xxx -config_path xxx " + "-[shapes|dtypes|names|tensors] -[model_file|params_file|model_format]"); google::ParseCommandLineFlags(&argc, &argv, true); if (FLAGS_diff) { CheckTensorDiff(argc, argv); diff --git a/benchmark/cpp/benchmark_picodet.cc b/benchmark/cpp/benchmark_picodet.cc old mode 100755 new mode 100644 index 58b92784c..da936f8d6 --- a/benchmark/cpp/benchmark_picodet.cc +++ b/benchmark/cpp/benchmark_picodet.cc @@ -49,8 +49,7 @@ int main(int argc, char* argv[]) { config_info["backend"] == "trt") { option.trt_option.SetShape("image", {1, 3, 640, 640}, {1, 3, 640, 640}, {1, 3, 640, 640}); - option.trt_option.SetShape("scale_factor", {1, 2}, {1, 2}, - {1, 2}); + option.trt_option.SetShape("scale_factor", {1, 2}, {1, 2}, {1, 2}); } auto model_picodet = vision::detection::PicoDet( model_file, params_file, config_file, option, model_format); @@ -81,9 +80,9 @@ int main(int argc, char* argv[]) { } // Run profiling BENCHMARK_MODEL(model_picodet, model_picodet.Predict(im, &res)) - auto vis_im = vision::VisDetection(im, res); + auto vis_im = vision::VisDetection(im, res, 0.5f); cv::imwrite("vis_result.jpg", vis_im); std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; #endif return 0; -} \ No newline at end of file +} diff --git a/benchmark/cpp/benchmark_ppshituv2_det.cc b/benchmark/cpp/benchmark_ppshituv2_det.cc new file mode 100644 index 000000000..c62ee6862 --- /dev/null +++ b/benchmark/cpp/benchmark_ppshituv2_det.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2023 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 "flags.h" +#include "macros.h" +#include "option.h" + +namespace vision = fastdeploy::vision; +namespace benchmark = fastdeploy::benchmark; + +DEFINE_bool(no_nms, false, "Whether the model contains nms."); + +int main(int argc, char* argv[]) { +#if defined(ENABLE_BENCHMARK) && defined(ENABLE_VISION) + // Initialization + auto option = fastdeploy::RuntimeOption(); + if (!CreateRuntimeOption(&option, argc, argv, true)) { + return -1; + } + auto im = cv::imread(FLAGS_image); + std::unordered_map config_info; + benchmark::ResultManager::LoadBenchmarkConfig(FLAGS_config_path, + &config_info); + std::string model_name, params_name, config_name; + auto model_format = fastdeploy::ModelFormat::PADDLE; + if (!UpdateModelResourceName(&model_name, ¶ms_name, &config_name, + &model_format, config_info)) { + return -1; + } + + auto model_file = FLAGS_model + sep + model_name; + auto params_file = FLAGS_model + sep + params_name; + auto config_file = FLAGS_model + sep + config_name; + if (config_info["backend"] == "paddle_trt") { + option.paddle_infer_option.collect_trt_shape = true; + } + if (config_info["backend"] == "paddle_trt" || + config_info["backend"] == "trt") { + option.trt_option.SetShape("image", {1, 3, 640, 640}, {1, 3, 640, 640}, + {1, 3, 640, 640}); + option.trt_option.SetShape("scale_factor", {1, 2}, {1, 2}, {1, 2}); + option.trt_option.SetShape("im_shape", {1, 2}, {1, 2}, {1, 2}); + } + auto model = vision::classification::PPShiTuV2Detector( + model_file, params_file, config_file, option, model_format); + if (FLAGS_no_nms) { + model.GetPostprocessor().ApplyNMS(); + } + vision::DetectionResult res; + if (config_info["precision_compare"] == "true") { + // Run once at least + model.Predict(im, &res); + // 1. Test result diff + std::cout << "=============== Test result diff =================\n"; + // Save result to -> disk. + std::string det_result_path = "ppshituv2_det_result.txt"; + benchmark::ResultManager::SaveDetectionResult(res, det_result_path); + // Load result from <- disk. + vision::DetectionResult res_loaded; + benchmark::ResultManager::LoadDetectionResult(&res_loaded, det_result_path); + // Calculate diff between two results. + auto det_diff = + benchmark::ResultManager::CalculateDiffStatis(res, res_loaded); + std::cout << "Boxes diff: mean=" << det_diff.boxes.mean + << ", max=" << det_diff.boxes.max + << ", min=" << det_diff.boxes.min << std::endl; + std::cout << "Label_ids diff: mean=" << det_diff.labels.mean + << ", max=" << det_diff.labels.max + << ", min=" << det_diff.labels.min << std::endl; + } + // Run profiling + BENCHMARK_MODEL(model, model.Predict(im, &res)) + auto vis_im = vision::VisDetection(im, res, 0.5f); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; +#endif + return 0; +} diff --git a/benchmark/cpp/benchmark_ppshituv2_rec.cc b/benchmark/cpp/benchmark_ppshituv2_rec.cc new file mode 100644 index 000000000..fb16a203b --- /dev/null +++ b/benchmark/cpp/benchmark_ppshituv2_rec.cc @@ -0,0 +1,93 @@ +// Copyright (c) 2023 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 "flags.h" +#include "macros.h" +#include "option.h" + +namespace vision = fastdeploy::vision; +namespace benchmark = fastdeploy::benchmark; + +DEFINE_string(trt_shape, "1,3,224,224:1,3,224,224:1,3,224,224", + "Set min/opt/max shape for trt/paddle_trt backend." + "eg:--trt_shape 1,3,224,224:1,3,224,224:1,3,224,224"); + +DEFINE_string(input_name, "x", + "Set input name for trt/paddle_trt backend." + "eg:--input_names x"); + +int main(int argc, char* argv[]) { +#if defined(ENABLE_BENCHMARK) && defined(ENABLE_VISION) + // Initialization + auto option = fastdeploy::RuntimeOption(); + if (!CreateRuntimeOption(&option, argc, argv, true)) { + return -1; + } + auto im = cv::imread(FLAGS_image); + std::unordered_map config_info; + benchmark::ResultManager::LoadBenchmarkConfig(FLAGS_config_path, + &config_info); + // Set max_batch_size 1 for best performance + if (config_info["backend"] == "paddle_trt") { + option.trt_option.max_batch_size = 1; + } + std::string model_name, params_name, config_name; + auto model_format = fastdeploy::ModelFormat::PADDLE; + if (!UpdateModelResourceName(&model_name, ¶ms_name, &config_name, + &model_format, config_info)) { + return -1; + } + + auto model_file = FLAGS_model + sep + model_name; + auto params_file = FLAGS_model + sep + params_name; + auto config_file = FLAGS_model + sep + config_name; + if (config_info["backend"] == "paddle_trt") { + option.paddle_infer_option.collect_trt_shape = true; + } + if (config_info["backend"] == "paddle_trt" || + config_info["backend"] == "trt") { + std::vector> trt_shapes = + benchmark::ResultManager::GetInputShapes(FLAGS_trt_shape); + option.trt_option.SetShape(FLAGS_input_name, trt_shapes[0], trt_shapes[1], + trt_shapes[2]); + } + + auto model = vision::classification::PPShiTuV2Recognizer( + model_file, params_file, config_file, option, model_format); + vision::ClassifyResult res; + if (config_info["precision_compare"] == "true") { + // Run once at least + model.Predict(im, &res); + // 1. Test result diff + std::cout << "=============== Test result diff =================\n"; + // Save result to -> disk. + std::string cls_result_path = "ppcls_result.txt"; + benchmark::ResultManager::SaveClassifyResult(res, cls_result_path); + // Load result from <- disk. + vision::ClassifyResult res_loaded; + benchmark::ResultManager::LoadClassifyResult(&res_loaded, cls_result_path); + // Calculate diff between two results. + auto cls_diff = + benchmark::ResultManager::CalculateDiffStatis(res, res_loaded); + std::cout << "Labels diff: mean=" << cls_diff.labels.mean + << ", max=" << cls_diff.labels.max + << ", min=" << cls_diff.labels.min << std::endl; + std::cout << "Scores diff: mean=" << cls_diff.scores.mean + << ", max=" << cls_diff.scores.max + << ", min=" << cls_diff.scores.min << std::endl; + } + BENCHMARK_MODEL(model, model.Predict(im, &res)) +#endif + return 0; +} \ No newline at end of file diff --git a/cmake/faiss.cmake b/cmake/faiss.cmake new file mode 100644 index 000000000..f2a0710d7 --- /dev/null +++ b/cmake/faiss.cmake @@ -0,0 +1,163 @@ +# 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(ExternalProject) + +set(FAISS_PROJECT external_faiss_download) +set(FAISS_FILENAME faiss) +set(FAISS_PREFIX_DIR ${THIRD_LIBS_PATH}/${FAISS_FILENAME}) +set(FAISS_SOURCE_DIR ${THIRD_LIBS_PATH}/${FAISS_FILENAME}/src/${FAISS_PROJECT}) +set(FAISS_INSTALL_DIR ${THIRD_LIBS_PATH}/install/${FAISS_FILENAME}) +set(FAISS_INC_DIR ${FAISS_INSTALL_DIR}/include CACHE PATH "faiss include directory." FORCE) +if(ANDROID) + set(FAISS_LIB_DIR ${FAISS_INSTALL_DIR}/lib/${ANDROID_ABI} CACHE PATH "faiss lib directory." FORCE) +else() + set(FAISS_LIB_DIR ${FAISS_INSTALL_DIR}/lib CACHE PATH "faiss lib directory." FORCE) +endif() + +if(NOT WITH_FAISS_STATIC) + message(FATAL_ERROR "Not support WITH_FAISS_STATIC=OFF now!") +endif() + +set(FAISS_URL_PREFIX "https://bj.bcebos.com/fastdeploy/test") +if(ANDROID) + # check ABI, toolchain + if((NOT ANDROID_ABI MATCHES "armeabi-v7a") AND (NOT ANDROID_ABI MATCHES "arm64-v8a")) + message(FATAL_ERROR "FAISS only support armeabi-v7a, arm64-v8a now.") + endif() + if(NOT ANDROID_TOOLCHAIN MATCHES "clang") + message(FATAL_ERROR "Currently, only support clang toolchain but found ${ANDROID_TOOLCHAIN}.") + endif() +endif() + +set(FAISS_VERSION 1.7.3) +# URL +if(NOT FAISS_URL) + if(WIN32) + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-win-x64-${FAISS_VERSION}.zip") + elseif(APPLE) + if(CURRENT_OSX_ARCH MATCHES "arm64") + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-osx-arm64-${FAISS_VERSION}.tgz") + else() + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-osx-x64-${FAISS_VERSION}.tgz") + endif() + elseif(ANDROID) + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-android-${ANDROID_ABI}-${FAISS_VERSION}.tgz") + else() # Linux + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") + message(FATAL_ERROR "Not support for Linux aarch64 now!") + else() + if(WITH_FAISS_GPU) + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-linux-x64-gpu-${FAISS_VERSION}.tgz") + else() + set(FAISS_URL "${FAISS_URL_PREFIX}/faiss-linux-x64-${FAISS_VERSION}.tgz") + endif() + endif() + endif() +endif() + +# FAISS Headers +include_directories(${FAISS_INC_DIR}) + +# FAISS Libs paths +if(WIN32) + set(FAISS_LIB "${FAISS_LIB_DIR}/faiss.lib") +elseif(APPLE) + set(FAISS_LIB "${FAISS_LIB_DIR}/libfaiss.a") +elseif(ANDROID) + set(FAISS_LIB "${FAISS_LIB_DIR}/libfaiss.a") +else() # Linux + set(FAISS_LIB "${FAISS_LIB_DIR}/libfaiss.a") +endif() + +# Download FAISS +if(ANDROID) + ExternalProject_Add( + ${FAISS_PROJECT} + ${EXTERNAL_PROJECT_LOG_ARGS} + URL ${FAISS_URL} + PREFIX ${FAISS_PREFIX_DIR} + DOWNLOAD_NO_PROGRESS 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E remove_directory ${FAISS_INSTALL_DIR} && + ${CMAKE_COMMAND} -E make_directory ${FAISS_INSTALL_DIR} && + ${CMAKE_COMMAND} -E make_directory ${FAISS_INSTALL_DIR}/lib && + ${CMAKE_COMMAND} -E rename ${FAISS_SOURCE_DIR}/lib/ ${FAISS_INSTALL_DIR}/lib/${ANDROID_ABI} && + ${CMAKE_COMMAND} -E copy_directory ${FAISS_SOURCE_DIR}/include ${FAISS_INC_DIR} + BUILD_BYPRODUCTS ${FAISS_LIB}) +else() + ExternalProject_Add( + ${FAISS_PROJECT} + ${EXTERNAL_PROJECT_LOG_ARGS} + URL ${FAISS_URL} + PREFIX ${FAISS_PREFIX_DIR} + DOWNLOAD_NO_PROGRESS 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + UPDATE_COMMAND "" + INSTALL_COMMAND + ${CMAKE_COMMAND} -E remove_directory ${FAISS_INSTALL_DIR} && + ${CMAKE_COMMAND} -E make_directory ${FAISS_INSTALL_DIR} && + ${CMAKE_COMMAND} -E rename ${FAISS_SOURCE_DIR}/lib/ ${FAISS_INSTALL_DIR}/lib && + ${CMAKE_COMMAND} -E copy_directory ${FAISS_SOURCE_DIR}/include ${FAISS_INC_DIR} + BUILD_BYPRODUCTS ${FAISS_LIB}) +endif() + +set(FAISS_LIBRARIES) + +add_library(external_faiss STATIC IMPORTED GLOBAL) +set_property(TARGET external_faiss PROPERTY IMPORTED_LOCATION ${FAISS_LIB}) +add_dependencies(external_faiss ${FAISS_PROJECT}) + +list(APPEND FAISS_LIBRARIES external_faiss) + +# Add BLAS/LAPACK/OpenBLAS (needed by FAISS) +if(WIN32) + add_library(external_blas STATIC IMPORTED GLOBAL) + set_property(TARGET external_blas PROPERTY IMPORTED_LOCATION ${FAISS_LIB_DIR}/BLAS.lib) + add_dependencies(external_blas ${FAISS_PROJECT}) + list(APPEND FAISS_LIBRARIES external_blas) + + add_library(external_lapack STATIC IMPORTED GLOBAL) + set_property(TARGET external_lapack PROPERTY IMPORTED_LOCATION ${FAISS_LIB_DIR}/LAPACK.lib) + add_dependencies(external_lapack ${FAISS_PROJECT}) + list(APPEND FAISS_LIBRARIES external_lapack) +elseif(APPLE) + find_package(BLAS REQUIRED) + list(APPEND FAISS_LIBRARIES ${BLAS_LIBRARIES}) + + find_package(LAPACK REQUIRED) + list(APPEND FAISS_LIBRARIES ${LAPACK_LIBRARIES}) +elseif(ANDROID) + # OpenBLAS static lib already merged into libfaiss.a + message(STATUS "For Android, OpenBLAS static lib was already merged into libfaiss.a") +else() # Linux + find_package(BLAS REQUIRED) + list(APPEND FAISS_LIBRARIES ${BLAS_LIBRARIES}) + + find_package(LAPACK REQUIRED) + list(APPEND FAISS_LIBRARIES ${LAPACK_LIBRARIES}) +endif() + +# Add OpenMP (REQUIRED), OpenMP must be avaliable. +find_package(OpenMP REQUIRED) +list(APPEND FAISS_LIBRARIES OpenMP::OpenMP_CXX) + +set(FAISS_INCLUDE_DIRS ${FAISS_INC_DIR}) +set(FAISS_LIBS ${FAISS_LIBRARIES}) +set(FAISS_FOUND TRUE) + + diff --git a/examples/vision/classification/ppshitu/cpu-gpu/README.md b/examples/vision/classification/ppshitu/cpu-gpu/README.md new file mode 100644 index 000000000..4d75db7c5 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/README.md @@ -0,0 +1,5 @@ +[English](README.md) | 简体中文 + +## 详细部署的部署示例 +- [Python部署](python) +- [C++部署](cpp) diff --git a/examples/vision/classification/ppshitu/cpu-gpu/cpp/CMakeLists.txt b/examples/vision/classification/ppshitu/cpu-gpu/cpp/CMakeLists.txt new file mode 100644 index 000000000..f2995c294 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/cpp/CMakeLists.txt @@ -0,0 +1,14 @@ +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10) + +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +include_directories(${FASTDEPLOY_INCS}) + +add_executable(infer_ppshituv2_det_demo ${PROJECT_SOURCE_DIR}/infer_ppshituv2_det.cc) +add_executable(infer_ppshituv2_rec_demo ${PROJECT_SOURCE_DIR}/infer_ppshituv2_rec.cc) + +target_link_libraries(infer_ppshituv2_det_demo ${FASTDEPLOY_LIBS}) +target_link_libraries(infer_ppshituv2_rec_demo ${FASTDEPLOY_LIBS}) diff --git a/examples/vision/classification/ppshitu/cpu-gpu/cpp/README.md b/examples/vision/classification/ppshitu/cpu-gpu/cpp/README.md new file mode 100755 index 000000000..6943d08a5 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/cpp/README.md @@ -0,0 +1,89 @@ +# PaddleClas CPU-GPU C++部署示例 + +本目录下提供`infer_shituv2_xxx.cc`快速完成PP-ShiTuV2系列模型在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。 + +## 1. 说明 +PP-ShiTuV2支持利用FastDeploy在NVIDIA GPU、X86 CPU、飞腾CPU、ARM CPU、Intel GPU(独立显卡/集成显卡)硬件上快速部署图像分类模型. + +## 2. 部署环境准备 +在部署前,需确认软硬件环境,同时下载预编译部署库,参考[FastDeploy安装文档](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install#FastDeploy预编译库安装)安装FastDeploy预编译库. + +## 3. 运行部署示例 +以Linux上推理为例,在本目录执行如下命令即可完成编译测试,支持此模型需保证FastDeploy版本1.0.0以上(x.x.x>=1.0.0) + +```bash +# 下载部署示例代码 +git clone https://github.com/PaddlePaddle/FastDeploy.git +cd FastDeploy/examples/vision/classification/ppshitu/cpu-gpu/cpp + +mkdir build +cd build +# 下载FastDeploy预编译库,用户可在上文提到的`FastDeploy预编译库`中自行选择合适的版本使用 +wget https://bj.bcebos.com/fastdeploy/release/cpp/fastdeploy-linux-x64-x.x.x.tgz +tar xvf fastdeploy-linux-x64-x.x.x.tgz +cmake .. -DFASTDEPLOY_INSTALL_DIR=${PWD}/fastdeploy-linux-x64-x.x.x +make -j + +# 下载模型文件和测试图片 +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/models/inference/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar && tar -xf picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/models/inference/PP-ShiTuV2/general_PPLCNetV2_base_pretrained_v1.0_infer.tar && tar -xf general_PPLCNetV2_base_pretrained_v1.0_infer.tar +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/data/drink_dataset_v2.0.tar && tar -xf drink_dataset_v2.0.tar + +# 在CPU上使用Paddle Inference推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 0 +# 在CPU上使用OenVINO推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 1 +# 在CPU上使用ONNX Runtime推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 2 +# 在CPU上使用Paddle Lite推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 3 +# 在GPU上使用Paddle Inference推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 4 +# 在GPU上使用Paddle TensorRT推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 5 +# 在GPU上使用ONNX Runtime推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 6 +# 在GPU上使用Nvidia TensorRT推理 +./infer_ppshituv2_det_demo picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer drink_dataset_v2.0/test_images/100.jpeg 7 +``` + +以上命令只适用于Linux或MacOS, Windows下SDK的使用方式请参考: +- [如何在Windows中使用FastDeploy C++ SDK](../../../../../docs/cn/faq/use_sdk_on_windows.md) + + +## 4. 部署示例选项说明 +在我们使用`infer_ppshituv2_det_demo`时, 输入了3个参数, 分别为分类模型, 预测图片, 与最后一位的数字选项. +现在下表将解释最后一位数字选项的含义. +|数字选项|含义| +|:---:|:---:| +|0| 在CPU上使用Paddle Inference推理 | +|1| 在CPU上使用OenVINO推理 | +|2| 在CPU上使用ONNX Runtime推理 | +|3| 在CPU上使用Paddle Lite推理 | +|4| 在GPU上使用Paddle Inference推理 | +|5| 在GPU上使用Paddle TensorRT推理 | +|6| 在GPU上使用ONNX Runtime推理 | +|7| 在GPU上使用Nvidia TensorRT推理 | + +- 关于如何通过FastDeploy使用更多不同的推理后端,以及如何使用不同的硬件,请参考文档:[如何切换模型推理后端引擎](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/how_to_change_backend.md) + +## 5. 更多指南 +- [PaddleClas系列 C++ API查阅](https://www.paddlepaddle.org.cn/fastdeploy-api-doc/cpp/html/namespacefastdeploy_1_1vision_1_1classification.html) +- [PaddleClas Python部署](../python) +- [PaddleClas C 部署](../c) +- [PaddleClas C# 部署](../csharp) + +## 6. 常见问题 +- PaddleClas能在FastDeploy支持的多种后端上推理,支持情况如下表所示, 如何切换后端, 详见文档[如何切换模型推理后端引擎](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/how_to_change_backend.md) + +|硬件类型|支持的后端| +|:---:|:---:| +|X86 CPU| Paddle Inference, ONNX Runtime, OpenVINO | +|ARM CPU| Paddle Lite | +|飞腾 CPU| ONNX Runtime | +|NVIDIA GPU| Paddle Inference, ONNX Runtime, TensorRT | + +- [Intel GPU(独立显卡/集成显卡)的使用](https://github.com/PaddlePaddle/FastDeploy/blob/develop/tutorials/intel_gpu/README.md) +- [编译CPU部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/cpu.md) +- [编译GPU部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md) +- [编译Jetson部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/jetson.md) diff --git a/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_det.cc b/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_det.cc new file mode 100644 index 000000000..a22013e98 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_det.cc @@ -0,0 +1,96 @@ +// 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" +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void InitAndInfer(const std::string &model_dir, const std::string &image_file, + const fastdeploy::RuntimeOption &option) { + auto model_file = model_dir + sep + "inference.pdmodel"; + auto params_file = model_dir + sep + "inference.pdiparams"; + auto config_file = model_dir + sep + "infer_cfg.yml"; + + auto model = fastdeploy::vision::classification::PPShiTuV2Detector( + model_file, params_file, config_file, option); + if (!model.Initialized()) { + std::cerr << "Failed to initialize." << std::endl; + return; + } + + auto im = cv::imread(image_file); + + fastdeploy::vision::DetectionResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + + // print res + 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 < 4) { + std::cout << "Usage: infer_demo path/to/model path/to/image run_option, " + "e.g ./infer_demo " + "./picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer ./test.jpeg 0" + << std::endl; + return -1; + } + + fastdeploy::RuntimeOption option; + int flag = std::atoi(argv[3]); + + if (flag == 0) { + option.UseCpu(); + option.UsePaddleBackend(); // Paddle Inference + } else if (flag == 1) { + option.UseCpu(); + option.UseOpenVINOBackend(); // OpenVINO + } else if (flag == 2) { + option.UseCpu(); + option.UseOrtBackend(); // ONNX Runtime + } else if (flag == 3) { + option.UseCpu(); + option.UseLiteBackend(); // Paddle Lite + } else if (flag == 4) { + option.UseGpu(); + option.UsePaddleBackend(); // Paddle Inference + } else if (flag == 5) { + option.UseGpu(); + option.UsePaddleInferBackend(); + option.paddle_infer_option.enable_trt = true; + option.trt_option.SetShape("image", {1, 3, 640, 640}, {1, 3, 640, 640}, + {1, 3, 640, 640}); + option.trt_option.SetShape("scale_factor", {1, 2}, {1, 2}, {1, 2}); + option.trt_option.SetShape("im_shape", {1, 2}, {1, 2}, {1, 2}); + } else if (flag == 6) { + option.UseGpu(); + option.UseOrtBackend(); // ONNX Runtime + } else if (flag == 7) { + option.UseGpu(); + option.UseTrtBackend(); // TensorRT + } + + std::string model_dir = argv[1]; + std::string image_dir = argv[2]; + InitAndInfer(model_dir, image_dir, option); +} diff --git a/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_rec.cc b/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_rec.cc new file mode 100644 index 000000000..e5584319c --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/cpp/infer_ppshituv2_rec.cc @@ -0,0 +1,89 @@ +// 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" +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void InitAndInfer(const std::string &model_dir, const std::string &image_file, + const fastdeploy::RuntimeOption &option) { + auto model_file = model_dir + sep + "inference.pdmodel"; + auto params_file = model_dir + sep + "inference.pdiparams"; + auto config_file = model_dir + sep + "inference_cls.yaml"; + + auto model = fastdeploy::vision::classification::PPShiTuV2Recognizer( + model_file, params_file, config_file, option); + if (!model.Initialized()) { + std::cerr << "Failed to initialize." << std::endl; + return; + } + + auto im = cv::imread(image_file); + + fastdeploy::vision::ClassifyResult res; + if (!model.Predict(im, &res)) { + std::cerr << "Failed to predict." << std::endl; + return; + } + + // print res + std::cout << res.Str() << std::endl; +} + +int main(int argc, char *argv[]) { + if (argc < 4) { + std::cout << "Usage: infer_demo path/to/model path/to/image run_option, " + "e.g ./infer_demo " + "./general_PPLCNetV2_base_pretrained_v1.0_infer ./test.jpeg 0" + << std::endl; + return -1; + } + + fastdeploy::RuntimeOption option; + int flag = std::atoi(argv[3]); + + if (flag == 0) { + option.UseCpu(); + option.UsePaddleBackend(); // Paddle Inference + } else if (flag == 1) { + option.UseCpu(); + option.UseOpenVINOBackend(); // OpenVINO + } else if (flag == 2) { + option.UseCpu(); + option.UseOrtBackend(); // ONNX Runtime + } else if (flag == 3) { + option.UseCpu(); + option.UseLiteBackend(); // Paddle Lite + } else if (flag == 4) { + option.UseGpu(); + option.UsePaddleBackend(); // Paddle Inference + } else if (flag == 5) { + option.UseGpu(); + option.UsePaddleInferBackend(); + option.paddle_infer_option.enable_trt = true; + } else if (flag == 6) { + option.UseGpu(); + option.UseOrtBackend(); // ONNX Runtime + } else if (flag == 7) { + option.UseGpu(); + option.UseTrtBackend(); // TensorRT + } + + std::string model_dir = argv[1]; + std::string image_dir = argv[2]; + InitAndInfer(model_dir, image_dir, option); +} diff --git a/examples/vision/classification/ppshitu/cpu-gpu/python/README.md b/examples/vision/classification/ppshitu/cpu-gpu/python/README.md new file mode 100755 index 000000000..969ca8b82 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/python/README.md @@ -0,0 +1,75 @@ +# PaddleClas CPU-GPU Python部署示例 +本目录下提供`infer_ppshituv2_det.py`快速完成PP-ShiTuV2在CPU/GPU上部署的示例. + +## 1. 说明 +PP-ShiTuV2支持利用FastDeploy在NVIDIA GPU、X86 CPU、飞腾CPU、ARM CPU、Intel GPU(独立显卡/集成显卡)硬件上快速部署图像分类模型 + +## 2. 部署环境准备 +在部署前,需确认软硬件环境,同时下载预编译部署库,参考[FastDeploy安装文档](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install#FastDeploy预编译库安装)安装FastDeploy预编译库. + +## 3. 运行部署示例 +```bash +# 安装FastDpeloy python包(详细文档请参考`部署环境准备`) +pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html +conda config --add channels conda-forge && conda install cudatoolkit=11.2 cudnn=8.2 + +# 下载部署示例代码 +git clone https://github.com/PaddlePaddle/FastDeploy.git +cd FastDeploy/examples/vision/classification/ppshitu/cpu-gpu/python + +# 下载模型文件和测试图片 +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/models/inference/picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar && tar -xf picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer.tar +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/models/inference/PP-ShiTuV2/general_PPLCNetV2_base_pretrained_v1.0_infer.tar && tar -xf general_PPLCNetV2_base_pretrained_v1.0_infer.tar +wget -nc https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/data/drink_dataset_v2.0.tar && tar -xf drink_dataset_v2.0.tar + +# 在CPU上使用Paddle Inference推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device cpu --backend paddle +# 在CPU上使用OenVINO推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device cpu --backend openvino +# 在CPU上使用ONNX Runtime推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device cpu --backend ort +# 在CPU上使用Paddle Lite推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device cpu --backend pplite +# 在GPU上使用Paddle Inference推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device gpu --backend paddle +# 在GPU上使用Paddle TensorRT推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device gpu --backend pptrt +# 在GPU上使用ONNX Runtime推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device gpu --backend ort +# 在GPU上使用Nvidia TensorRT推理 +python infer_ppshituv2_det.py --model picodet_PPLCNet_x2_5_mainbody_lite_v1.0_infer --image drink_dataset_v2.0/test_images/100.jpeg --device gpu --backend trt +``` + +## 4. 部署示例选项说明 + +|参数|含义|默认值 +|---|---|---| +|--model|指定模型文件夹所在的路径|None| +|--image|指定测试图片所在的路径|None| +|--device|指定即将运行的硬件类型,支持的值为`[cpu, gpu]`,当设置为cpu时,可运行在x86 cpu/arm cpu等cpu上|cpu| +|--device_id|使用gpu时, 指定设备号|0| +|--backend|部署模型时使用的后端, 支持的值为`[paddle,pptrt,pplite,ort,openvino,trt]` |openvino| +|--topk|返回的前topk准确率, 支持的为`1,5` |1| + +关于如何通过FastDeploy使用更多不同的推理后端,以及如何使用不同的硬件,请参考文档:[如何切换模型推理后端引擎](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/how_to_change_backend.md) + +## 5. 更多指南 +- [PaddleClas系列 Python API查阅](https://www.paddlepaddle.org.cn/fastdeploy-api-doc/python/html/image_classification.html) +- [PaddleClas C++ 部署](../cpp) +- [PaddleClas C 部署](../c) +- [PaddleClas C# 部署](../csharp) + +## 6. 常见问题 +- PaddleClas能在FastDeploy支持的多种后端上推理,支持情况如下表所示, 如何切换后端, 详见文档[如何切换模型推理后端引擎](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/how_to_change_backend.md) + +|硬件类型|支持的后端| +|:---:|:---:| +|X86 CPU| Paddle Inference, ONNX Runtime, OpenVINO | +|ARM CPU| Paddle Lite | +|飞腾 CPU| ONNX Runtime | +|NVIDIA GPU| Paddle Inference, ONNX Runtime, TensorRT | + +- [Intel GPU(独立显卡/集成显卡)的使用](https://github.com/PaddlePaddle/FastDeploy/blob/develop/tutorials/intel_gpu/README.md) +- [编译CPU部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/cpu.md) +- [编译GPU部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md) +- [编译Jetson部署库](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/jetson.md) diff --git a/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_det.py b/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_det.py new file mode 100755 index 000000000..e51b6bbc5 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_det.py @@ -0,0 +1,96 @@ +import fastdeploy as fd +import cv2 +import os + + +def parse_arguments(): + import argparse + import ast + parser = argparse.ArgumentParser() + parser.add_argument( + "--model", required=True, help="Path of PP-ShiTuV2 detector model.") + parser.add_argument( + "--image", type=str, required=True, help="Path of test image file.") + parser.add_argument( + "--device", + type=str, + default='cpu', + help="Type of inference device, support 'cpu' or 'gpu' or 'ipu' or 'kunlunxin' or 'ascend' ." + ) + parser.add_argument( + "--device_id", + type=int, + default=0, + help="Define which GPU card used to run model.") + parser.add_argument( + "--backend", + type=str, + default="default", + help="Type of inference backend, support ort/trt/paddle/openvino, default 'openvino' for cpu, 'tensorrt' for gpu" + ) + return parser.parse_args() + + +def build_option(args): + + option = fd.RuntimeOption() + + if args.device.lower() == "gpu": + option.use_gpu(args.device_id) + + if args.backend.lower() == "trt": + assert args.device.lower( + ) == "gpu", "TensorRT backend require inference on device GPU." + option.use_trt_backend() + + elif args.backend.lower() == "pptrt": + assert args.device.lower( + ) == "gpu", "Paddle-TensorRT backend require inference on device GPU." + option.use_paddle_infer_backend() + option.paddle_infer_option.enable_trt = True + option.paddle_infer_option.collect_trt_shape = True + option.trt_option.set_shape("image", [1, 3, 640, 640], + [1, 3, 640, 640], [1, 3, 640, 640]) + option.trt_option.set_shape("scale_factor", [1, 2], [1, 2], [1, 2]) + option.trt_option.set_shape("im_shape", [1, 2], [1, 2], [1, 2]) + + elif args.backend.lower() == "ort": + option.use_ort_backend() + + elif args.backend.lower() == "paddle": + option.use_paddle_infer_backend() + + elif args.backend.lower() == "openvino": + assert args.device.lower( + ) == "cpu", "OpenVINO backend require inference on device CPU." + option.use_openvino_backend() + + elif args.backend.lower() == "pplite": + assert args.device.lower( + ) == "cpu", "Paddle Lite backend require inference on device CPU." + option.use_lite_backend() + + return option + + +args = parse_arguments() + +# 配置runtime,加载模型 +runtime_option = build_option(args) + +model_file = os.path.join(args.model, "inference.pdmodel") +params_file = os.path.join(args.model, "inference.pdiparams") +config_file = os.path.join(args.model, "infer_cfg.yml") +model = fd.vision.classification.PPShiTuV2Detector( + model_file, params_file, config_file, runtime_option=runtime_option) + +# 预测主体检测结果 +im = cv2.imread(args.image) +result = model.predict(im) + +# 预测结果可视化 +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") + +print(result) diff --git a/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_rec.py b/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_rec.py new file mode 100755 index 000000000..0efd23288 --- /dev/null +++ b/examples/vision/classification/ppshitu/cpu-gpu/python/infer_ppshituv2_rec.py @@ -0,0 +1,85 @@ +import fastdeploy as fd +import cv2 +import os + + +def parse_arguments(): + import argparse + import ast + parser = argparse.ArgumentParser() + parser.add_argument( + "--model", required=True, help="Path of PP-ShiTuV2 recognizer model.") + parser.add_argument( + "--image", type=str, required=True, help="Path of test image file.") + parser.add_argument( + "--device", + type=str, + default='cpu', + help="Type of inference device, support 'cpu' or 'gpu' or 'ipu' or 'kunlunxin' or 'ascend' ." + ) + parser.add_argument( + "--device_id", + type=int, + default=0, + help="Define which GPU card used to run model.") + parser.add_argument( + "--backend", + type=str, + default="default", + help="Type of inference backend, support ort/trt/paddle/openvino, default 'openvino' for cpu, 'tensorrt' for gpu" + ) + return parser.parse_args() + + +def build_option(args): + + option = fd.RuntimeOption() + + if args.device.lower() == "gpu": + option.use_gpu(args.device_id) + + if args.backend.lower() == "trt": + assert args.device.lower( + ) == "gpu", "TensorRT backend require inference on device GPU." + option.use_trt_backend() + + elif args.backend.lower() == "pptrt": + assert args.device.lower( + ) == "gpu", "Paddle-TensorRT backend require inference on device GPU." + option.use_paddle_infer_backend() + option.paddle_infer_option.enable_trt = True + + elif args.backend.lower() == "ort": + option.use_ort_backend() + + elif args.backend.lower() == "paddle": + option.use_paddle_infer_backend() + + elif args.backend.lower() == "openvino": + assert args.device.lower( + ) == "cpu", "OpenVINO backend require inference on device CPU." + option.use_openvino_backend() + + elif args.backend.lower() == "pplite": + assert args.device.lower( + ) == "cpu", "Paddle Lite backend require inference on device CPU." + option.use_lite_backend() + + return option + + +args = parse_arguments() + +# 配置runtime,加载模型 +runtime_option = build_option(args) + +model_file = os.path.join(args.model, "inference.pdmodel") +params_file = os.path.join(args.model, "inference.pdiparams") +config_file = os.path.join(args.model, "inference_cls.yaml") +model = fd.vision.classification.PPShiTuV2Recognizer( + model_file, params_file, config_file, runtime_option=runtime_option) + +# 预测特征抽取结果 +im = cv2.imread(args.image) +result = model.predict(im) +print(result) diff --git a/fastdeploy/vision.h b/fastdeploy/vision.h index 0e8f7a9f6..1c302f6d7 100755 --- a/fastdeploy/vision.h +++ b/fastdeploy/vision.h @@ -18,6 +18,8 @@ #include "fastdeploy/vision/classification/contrib/resnet.h" #include "fastdeploy/vision/classification/contrib/yolov5cls/yolov5cls.h" #include "fastdeploy/vision/classification/ppcls/model.h" +#include "fastdeploy/vision/classification/ppshitu/ppshituv2_rec.h" +#include "fastdeploy/vision/classification/ppshitu/ppshituv2_det.h" #include "fastdeploy/vision/detection/contrib/nanodet_plus.h" #include "fastdeploy/vision/detection/contrib/scaledyolov4.h" #include "fastdeploy/vision/detection/contrib/yolor.h" diff --git a/fastdeploy/vision/classification/classification_pybind.cc b/fastdeploy/vision/classification/classification_pybind.cc index cae130de5..638f2ae93 100644 --- a/fastdeploy/vision/classification/classification_pybind.cc +++ b/fastdeploy/vision/classification/classification_pybind.cc @@ -18,12 +18,17 @@ namespace fastdeploy { void BindYOLOv5Cls(pybind11::module& m); void BindPaddleClas(pybind11::module& m); +void BindPPShiTuV2(pybind11::module& m); void BindResNet(pybind11::module& m); + void BindClassification(pybind11::module& m) { auto classification_module = m.def_submodule("classification", "Image classification models."); + BindYOLOv5Cls(classification_module); BindPaddleClas(classification_module); + BindPPShiTuV2(classification_module); BindResNet(classification_module); } + } // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshitu_pybind.cc b/fastdeploy/vision/classification/ppshitu/ppshitu_pybind.cc new file mode 100644 index 000000000..b0c164ba4 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshitu_pybind.cc @@ -0,0 +1,101 @@ +// 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 BindPPShiTuV2(pybind11::module& m) { + pybind11::class_(m, + "PPShiTuV2RecognizerPreprocessor") + .def(pybind11::init()) + .def("disable_normalize", + [](vision::classification::PPShiTuV2RecognizerPreprocessor& self) { + self.DisableNormalize(); + }) + .def("disable_permute", + [](vision::classification::PPShiTuV2RecognizerPreprocessor& self) { + self.DisablePermute(); + }) + .def("initial_resize_on_cpu", + [](vision::classification::PPShiTuV2RecognizerPreprocessor& self, + bool v) { self.InitialResizeOnCpu(v); }); + + pybind11::class_( + m, "PPShiTuV2RecognizerPostprocessor") + .def(pybind11::init<>()) + .def("run", + [](vision::classification::PPShiTuV2RecognizerPostprocessor& self, + std::vector& inputs) { + std::vector results; + if (!self.Run(inputs, &results)) { + throw std::runtime_error( + "Failed to postprocess the runtime result in " + "PPShiTuV2RecognizerPostprocessor."); + } + return results; + }) + .def("run", + [](vision::classification::PPShiTuV2RecognizerPostprocessor& 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 " + "PPShiTuV2RecognizerPostprocessor."); + } + return results; + }) + .def_property("feature_norm", + &vision::classification::PPShiTuV2RecognizerPostprocessor:: + GetFeatureNorm, + &vision::classification::PPShiTuV2RecognizerPostprocessor:: + SetFeatureNorm); + + pybind11::class_(m, "PPShiTuV2Recognizer") + .def(pybind11::init()) + .def("clone", + [](vision::classification::PPShiTuV2Recognizer& self) { + return self.Clone(); + }) + .def("predict", + [](vision::classification::PPShiTuV2Recognizer& self, + pybind11::array& data) { + cv::Mat im = PyArrayToCvMat(data); + vision::ClassifyResult result; + self.Predict(im, &result); + return result; + }) + .def("batch_predict", + [](vision::classification::PPShiTuV2Recognizer& 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::classification::PPShiTuV2Recognizer::GetPreprocessor) + .def_property_readonly( + "postprocessor", + &vision::classification::PPShiTuV2Recognizer::GetPostprocessor); +} +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_det.h b/fastdeploy/vision/classification/ppshitu/ppshituv2_det.h new file mode 100644 index 000000000..a127df2fc --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_det.h @@ -0,0 +1,26 @@ +// Copyright (c) 2023 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/ppdet/model.h" + + +namespace fastdeploy { +namespace vision { +namespace classification { + +typedef detection::PicoDet PPShiTuV2Detector; + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.cc b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.cc new file mode 100644 index 000000000..7bf5e7597 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.cc @@ -0,0 +1,121 @@ +// 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/classification/ppshitu/ppshituv2_rec.h" + +#include "fastdeploy/utils/unique_ptr.h" + +namespace fastdeploy { +namespace vision { +namespace classification { + +PPShiTuV2Recognizer::PPShiTuV2Recognizer(const std::string& model_file, + const std::string& params_file, + const std::string& config_file, + const RuntimeOption& custom_option, + const ModelFormat& model_format) + : preprocessor_(config_file) { + if (model_format == ModelFormat::PADDLE) { + valid_cpu_backends = {Backend::OPENVINO, Backend::PDINFER, Backend::ORT, + Backend::LITE}; + valid_gpu_backends = {Backend::ORT, Backend::PDINFER, Backend::TRT}; + valid_timvx_backends = {Backend::LITE}; + valid_ascend_backends = {Backend::LITE}; + valid_kunlunxin_backends = {Backend::LITE}; + valid_ipu_backends = {Backend::PDINFER}; + valid_directml_backends = {Backend::ORT}; + } else if (model_format == ModelFormat::SOPHGO) { + valid_sophgonpu_backends = {Backend::SOPHGOTPU}; + } else { + valid_cpu_backends = {Backend::ORT, Backend::OPENVINO}; + valid_gpu_backends = {Backend::ORT, Backend::TRT}; + valid_rknpu_backends = {Backend::RKNPU2}; + valid_directml_backends = {Backend::ORT}; + } + + runtime_option = custom_option; + runtime_option.model_format = model_format; + runtime_option.model_file = model_file; + runtime_option.params_file = params_file; + initialized = Initialize(); +} + +std::unique_ptr PPShiTuV2Recognizer::Clone() const { + std::unique_ptr clone_model = + utils::make_unique(PPShiTuV2Recognizer(*this)); + clone_model->SetRuntime(clone_model->CloneRuntime()); + return clone_model; +} + +bool PPShiTuV2Recognizer::Initialize() { + if (!InitRuntime()) { + FDERROR << "Failed to initialize fastdeploy backend." << std::endl; + return false; + } + return true; +} + +bool PPShiTuV2Recognizer::Predict(cv::Mat* im, ClassifyResult* result) { + if (!Predict(*im, result)) { + return false; + } + return true; +} + +bool PPShiTuV2Recognizer::Predict(const cv::Mat& im, ClassifyResult* result) { + FDMat mat = WrapMat(im); + return Predict(mat, result); +} + +bool PPShiTuV2Recognizer::BatchPredict(const std::vector& images, + std::vector* results) { + std::vector mats = WrapMat(images); + return BatchPredict(mats, results); +} + +bool PPShiTuV2Recognizer::Predict(const FDMat& mat, ClassifyResult* result) { + std::vector results; + std::vector mats = {mat}; + if (!BatchPredict(mats, &results)) { + return false; + } + *result = std::move(results[0]); + return true; +} + +bool PPShiTuV2Recognizer::BatchPredict(const std::vector& mats, + std::vector* results) { + std::vector fd_mats = mats; + if (!preprocessor_.Run(&fd_mats, &reused_input_tensors_)) { + FDERROR << "Failed to preprocess the input image." << std::endl; + return false; + } + 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 classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.h b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.h new file mode 100644 index 000000000..b664950c8 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec.h @@ -0,0 +1,110 @@ +// 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/fastdeploy_model.h" +#include "fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.h" +#include "fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.h" + +namespace fastdeploy { +namespace vision { +namespace classification { +/*! @brief PPShiTuV2Recognizer model object used when to load a PPShiTuV2Recognizer model exported by PP-ShiTuV2 Rec model. + */ +class FASTDEPLOY_DECL PPShiTuV2Recognizer : public FastDeployModel { + 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 PPLCNet/inference.pdmodel + * \param[in] params_file Path of parameter file, e.g PPLCNet/inference.pdiparams, if the model format is ONNX, this parameter will be ignored + * \param[in] config_file Path of configuration file for deployment, e.g PPLCNet/inference_cls.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 + */ + PPShiTuV2Recognizer(const std::string& model_file, + const std::string& params_file, + const std::string& config_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::PADDLE); + + /** \brief Clone a new PPShiTuV2Recognizer with less memory usage when multiple instances of the same model are created + * + * \return new PPShiTuV2Recognizer* type unique pointer + */ + virtual std::unique_ptr Clone() const; + + /// Get model's name + virtual std::string ModelName() const { return "PPShiTuV2Recognizer"; } + + /** \brief DEPRECATED Predict the feature vector result for an input image, remove at 1.0 version + * + * \param[in] im The input image data, comes from cv::imread() + * \param[in] result The output feature vector result will be writen to this structure + * \return true if the prediction successed, otherwise false + */ + virtual bool Predict(cv::Mat* im, ClassifyResult* result); + + /** \brief Predict the classification result for an input image + * + * \param[in] img The input image data, comes from cv::imread() + * \param[in] result The output feature vector result + * \return true if the prediction successed, otherwise false + */ + virtual bool Predict(const cv::Mat& img, ClassifyResult* result); + + /** \brief Predict the feature vector 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 feature vector(namely ClassifyResult.feature) result list + * \return true if the prediction successed, otherwise false + */ + virtual bool BatchPredict(const std::vector& imgs, + std::vector* results); + + /** \brief Predict the feature vector result for an input image + * + * \param[in] mat The input mat + * \param[in] result The output feature vector result + * \return true if the prediction successed, otherwise false + */ + virtual bool Predict(const FDMat& mat, ClassifyResult* result); + + /** \brief Predict the feature vector results for a batch of input images + * + * \param[in] mats, The input mat list + * \param[in] results The output feature vector result list + * \return true if the prediction successed, otherwise false + */ + virtual bool BatchPredict(const std::vector& mats, + std::vector* results); + + /// Get preprocessor reference of PPShiTuV2Recognizer + virtual PPShiTuV2RecognizerPreprocessor& GetPreprocessor() { + return preprocessor_; + } + + /// Get postprocessor reference of PPShiTuV2Recognizer + virtual PPShiTuV2RecognizerPostprocessor& GetPostprocessor() { + return postprocessor_; + } + + protected: + bool Initialize(); + PPShiTuV2RecognizerPreprocessor preprocessor_; + PPShiTuV2RecognizerPostprocessor postprocessor_; +}; + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.cc b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.cc new file mode 100644 index 000000000..909f2b5d4 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.cc @@ -0,0 +1,58 @@ +// 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/classification/ppshitu/ppshituv2_rec_postprocessor.h" +#include +#include +#include "fastdeploy/vision/utils/utils.h" + +namespace fastdeploy { +namespace vision { +namespace classification { + +bool PPShiTuV2RecognizerPostprocessor::Run( + const std::vector& tensors, + std::vector* results) { + int batch = tensors[0].shape[0]; // e.g [batch, 512] + int num_feature = tensors[0].shape[1]; + const float* tensor_data = reinterpret_cast(tensors[0].Data()); + + results->resize(batch); + + // post processing per batch=1 + for (int i = 0; i < batch; ++i) { + (*results)[i].feature.resize(num_feature); + const float* tensor_data_i_start = tensor_data + i * num_feature; + std::memcpy((*results)[i].feature.data(), tensor_data_i_start, + num_feature * sizeof(float)); + if (feature_norm_) { + FeatureNorm((*results)[i].feature); + } + } + + return true; +} + +void PPShiTuV2RecognizerPostprocessor::FeatureNorm( + std::vector& feature) { + float feature_sqrt = std::sqrt(std::inner_product( + feature.begin(), feature.end(), feature.begin(), 0.0f)); + for (int i = 0; i < feature.size(); ++i) { + feature[i] /= feature_sqrt; + } +} + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.h b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.h new file mode 100644 index 000000000..55aed35d8 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_postprocessor.h @@ -0,0 +1,49 @@ +// Copyright (c) 2023 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 classification { +/*! @brief Postprocessor object for PP-ShiTuV2 Recognizer model. + */ +class FASTDEPLOY_DECL PPShiTuV2RecognizerPostprocessor { + public: + PPShiTuV2RecognizerPostprocessor() = default; + + /** \brief Process the result of runtime and fill to ClassifyResult structure + * + * \param[in] tensors The inference result from runtime + * \param[in] result The output result of feature vector (see ClassifyResult.feature member) + * \return true if the postprocess successed, otherwise false + */ + bool Run(const std::vector& tensors, + std::vector* results); + /// Set the value of feature_norm_ for Postprocessor + void SetFeatureNorm(bool feature_norm) { feature_norm_ = feature_norm; } + /// Get the value of feature_norm_ from Postprocessor, default to true. + bool GetFeatureNorm() { return feature_norm_; } + + private: + void FeatureNorm(std::vector &feature); + bool feature_norm_ = true; +}; + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.cc b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.cc new file mode 100644 index 000000000..acb35c61b --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2023 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/classification/ppshitu/ppshituv2_rec_preprocessor.h" + +#include "yaml-cpp/yaml.h" + +namespace fastdeploy { +namespace vision { +namespace classification { + +PPShiTuV2RecognizerPreprocessor::PPShiTuV2RecognizerPreprocessor( + const std::string& config_file) { + this->config_file_ = config_file; + FDASSERT(BuildPreprocessPipelineFromConfig(), + "Failed to create PPShiTuV2RecognizerPreprocessor."); + initialized_ = true; +} + +bool PPShiTuV2RecognizerPreprocessor::BuildPreprocessPipelineFromConfig() { + processors_.clear(); + YAML::Node cfg; + try { + cfg = YAML::LoadFile(config_file_); + } catch (YAML::BadFile& e) { + FDERROR << "Failed to load yaml file " << config_file_ + << ", maybe you should check this file." << std::endl; + return false; + } + auto preprocess_cfg = cfg["PreProcess"]["transform_ops"]; + processors_.push_back(std::make_shared()); + for (const auto& op : preprocess_cfg) { + FDASSERT(op.IsMap(), + "Require the transform information in yaml be Map type."); + auto op_name = op.begin()->first.as(); + if (op_name == "ResizeImage") { + if (op.begin()->second["resize_short"]) { + int target_size = op.begin()->second["resize_short"].as(); + bool use_scale = false; + int interp = 1; + processors_.push_back( + std::make_shared(target_size, 1, use_scale)); + } else if (op.begin()->second["size"]) { + int width = 0; + int height = 0; + if (op.begin()->second["size"].IsScalar()) { + auto size = op.begin()->second["size"].as(); + width = size; + height = size; + } else { + auto size = op.begin()->second["size"].as>(); + width = size[0]; + height = size[1]; + } + processors_.push_back( + std::make_shared(width, height, -1.0, -1.0, 1, false)); + } else { + FDERROR << "Invalid params for ResizeImage for both 'size' and " + "'resize_short' are None" + << std::endl; + } + + } else if (op_name == "CropImage") { + int width = op.begin()->second["size"].as(); + int height = op.begin()->second["size"].as(); + processors_.push_back(std::make_shared(width, height)); + } else if (op_name == "NormalizeImage") { + if (!disable_normalize_) { + auto mean = op.begin()->second["mean"].as>(); + auto std = op.begin()->second["std"].as>(); + auto scale = op.begin()->second["scale"].as(); + FDASSERT( + (scale - 0.00392157) < 1e-06 && (scale - 0.00392157) > -1e-06, + "Only support scale in Normalize be 0.00392157, means the pixel " + "is in range of [0, 255]."); + processors_.push_back(std::make_shared(mean, std)); + } + } else if (op_name == "ToCHWImage") { + if (!disable_permute_) { + processors_.push_back(std::make_shared()); + } + } else { + FDERROR << "Unexcepted preprocess operator: " << op_name << "." + << std::endl; + return false; + } + } + + // Fusion will improve performance + FuseTransforms(&processors_); + return true; +} + +void PPShiTuV2RecognizerPreprocessor::DisableNormalize() { + this->disable_normalize_ = true; + // the DisableNormalize function will be invalid if the configuration file is + // loaded during preprocessing + if (!BuildPreprocessPipelineFromConfig()) { + FDERROR << "Failed to build preprocess pipeline from configuration file." + << std::endl; + } +} +void PPShiTuV2RecognizerPreprocessor::DisablePermute() { + this->disable_permute_ = true; + // the DisablePermute function will be invalid if the configuration file is + // loaded during preprocessing + if (!BuildPreprocessPipelineFromConfig()) { + FDERROR << "Failed to build preprocess pipeline from configuration file." + << std::endl; + } +} + +bool PPShiTuV2RecognizerPreprocessor::Apply(FDMatBatch* image_batch, + std::vector* outputs) { + if (!initialized_) { + FDERROR << "The preprocessor is not initialized." << std::endl; + return false; + } + for (size_t j = 0; j < processors_.size(); ++j) { + image_batch->proc_lib = proc_lib_; + if (initial_resize_on_cpu_ && j == 0 && + processors_[j]->Name().find("Resize") == 0) { + image_batch->proc_lib = ProcLib::OPENCV; + } + if (!(*(processors_[j].get()))(image_batch)) { + FDERROR << "Failed to processs image in " << processors_[j]->Name() << "." + << std::endl; + return false; + } + } + + outputs->resize(1); + FDTensor* tensor = image_batch->Tensor(); + (*outputs)[0].SetExternalData(tensor->Shape(), tensor->Dtype(), + tensor->Data(), tensor->device, + tensor->device_id); + return true; +} + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.h b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.h new file mode 100644 index 000000000..1c0f73bc8 --- /dev/null +++ b/fastdeploy/vision/classification/ppshitu/ppshituv2_rec_preprocessor.h @@ -0,0 +1,72 @@ +// Copyright (c) 2023 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/manager.h" +#include "fastdeploy/vision/common/processors/transform.h" +#include "fastdeploy/vision/common/result.h" + +namespace fastdeploy { +namespace vision { +namespace classification { + +/*! @brief Preprocessor object for PP-ShiTuV2 Recognizer model. + */ +class FASTDEPLOY_DECL PPShiTuV2RecognizerPreprocessor : public ProcessorManager { + public: + /** \brief Create a preprocessor instance for PP-ShiTuV2 Recognizer model + * + * \param[in] config_file Path of configuration file for deployment, e.g PPLCNet/infer_cfg.yml + */ + explicit PPShiTuV2RecognizerPreprocessor(const std::string& config_file); + + /** \brief Implement the virtual function of ProcessorManager, Apply() is the + * body of Run(). Apply() contains the main logic of preprocessing, Run() is + * called by users to execute preprocessing + * + * \param[in] image_batch The input image batch + * \param[in] outputs The output tensors which will feed in runtime + * \return true if the preprocess successed, otherwise false + */ + virtual bool Apply(FDMatBatch* image_batch, + std::vector* outputs); + + /// This function will disable normalize in preprocessing step. + void DisableNormalize(); + /// This function will disable hwc2chw in preprocessing step. + void DisablePermute(); + + /** \brief When the initial operator is Resize, and input image size is large, + * maybe it's better to run resize on CPU, because the HostToDevice memcpy + * is time consuming. Set this true to run the initial resize on CPU. + * + * \param[in] v ture or false + */ + void InitialResizeOnCpu(bool v) { initial_resize_on_cpu_ = v; } + + private: + bool BuildPreprocessPipelineFromConfig(); + bool initialized_ = false; + std::vector> processors_; + // for recording the switch of hwc2chw + bool disable_permute_ = false; + // for recording the switch of normalize + bool disable_normalize_ = false; + // read config file + std::string config_file_; + bool initial_resize_on_cpu_ = false; +}; + +} // namespace classification +} // namespace vision +} // namespace fastdeploy diff --git a/fastdeploy/vision/common/result.cc b/fastdeploy/vision/common/result.cc index 05bc75ba5..5897c9df8 100644 --- a/fastdeploy/vision/common/result.cc +++ b/fastdeploy/vision/common/result.cc @@ -19,16 +19,21 @@ namespace vision { void ClassifyResult::Free() { std::vector().swap(label_ids); std::vector().swap(scores); + std::vector().swap(feature); } void ClassifyResult::Clear() { label_ids.clear(); scores.clear(); + feature.clear(); } void ClassifyResult::Resize(int size) { label_ids.resize(size); scores.resize(size); + // TODO(qiuyanjun): feature not perform resize now. + // may need the code below for future. + // feature.resize(size); } std::string ClassifyResult::Str() { @@ -38,9 +43,25 @@ std::string ClassifyResult::Str() { out = out + std::to_string(label_ids[i]) + ", "; } out += "\nscores: "; - for (size_t i = 0; i < label_ids.size(); ++i) { + for (size_t i = 0; i < scores.size(); ++i) { out = out + std::to_string(scores[i]) + ", "; } + if (!feature.empty()) { + out += "\nfeature: size ("; + out += std::to_string(feature.size()) + "), only show first 100 values.\n"; + for (size_t i = 0; i < feature.size(); ++i) { + // only show first 100 values. + if ((i + 1) <= 100) { + out = out + std::to_string(feature[i]) + ", "; + if ((i + 1) % 10 == 0 && (i + 1) < 100) { + out += "\n"; + } + if ((i + 1) == 100) { + out += "\n......"; + } + } + } + } out += "\n)"; return out; } @@ -49,6 +70,7 @@ ClassifyResult& ClassifyResult::operator=(ClassifyResult&& other) { if (&other != this) { label_ids = std::move(other.label_ids); scores = std::move(other.scores); + feature = std::move(other.feature); } return *this; } @@ -154,15 +176,19 @@ std::string DetectionResult::Str() { if (!contain_masks) { out = "DetectionResult: [xmin, ymin, xmax, ymax, score, label_id]\n"; if (!rotated_boxes.empty()) { - out = "DetectionResult: [x1, y1, x2, y2, x3, y3, x4, y4, score, label_id]\n"; + out = + "DetectionResult: [x1, y1, x2, y2, x3, y3, x4, y4, score, " + "label_id]\n"; } } else { out = "DetectionResult: [xmin, ymin, xmax, ymax, score, label_id, " "mask_shape]\n"; if (!rotated_boxes.empty()) { - out = "DetectionResult: [x1, y1, x2, y2, x3, y3, x4, y4, score, label_id, mask_shape]\n"; - } + out = + "DetectionResult: [x1, y1, x2, y2, x3, y3, x4, y4, score, label_id, " + "mask_shape]\n"; + } } for (size_t i = 0; i < boxes.size(); ++i) { out = out + std::to_string(boxes[i][0]) + "," + @@ -646,8 +672,8 @@ std::string OCRResult::Str() { out = out + "]"; if (rec_scores.size() > 0) { - out = out + "rec text: " + text[n] + - " rec score:" + std::to_string(rec_scores[n]) + " "; + out = out + "rec text: " + text[n] + " rec score:" + + std::to_string(rec_scores[n]) + " "; } if (cls_labels.size() > 0) { out = out + "cls label: " + std::to_string(cls_labels[n]) + @@ -687,8 +713,8 @@ std::string OCRResult::Str() { cls_scores.size() > 0) { std::string out; for (int i = 0; i < rec_scores.size(); i++) { - out = out + "rec text: " + text[i] + - " rec score:" + std::to_string(rec_scores[i]) + " "; + out = out + "rec text: " + text[i] + " rec score:" + + std::to_string(rec_scores[i]) + " "; out = out + "cls label: " + std::to_string(cls_labels[i]) + " cls score: " + std::to_string(cls_scores[i]); out = out + "\n"; @@ -707,8 +733,8 @@ std::string OCRResult::Str() { cls_scores.size() == 0) { std::string out; for (int i = 0; i < rec_scores.size(); i++) { - out = out + "rec text: " + text[i] + - " rec score:" + std::to_string(rec_scores[i]) + " "; + out = out + "rec text: " + text[i] + " rec score:" + + std::to_string(rec_scores[i]) + " "; out = out + "\n"; } return out; @@ -755,9 +781,9 @@ std::string HeadPoseResult::Str() { std::string out; out = "HeadPoseResult: [yaw, pitch, roll]\n"; - out = out + "yaw: " + std::to_string(euler_angles[0]) + "\n" + - "pitch: " + std::to_string(euler_angles[1]) + "\n" + - "roll: " + std::to_string(euler_angles[2]) + "\n"; + out = out + "yaw: " + std::to_string(euler_angles[0]) + "\n" + "pitch: " + + std::to_string(euler_angles[1]) + "\n" + "roll: " + + std::to_string(euler_angles[2]) + "\n"; return out; } diff --git a/fastdeploy/vision/common/result.h b/fastdeploy/vision/common/result.h index 6ef96d140..6a2a4c929 100755 --- a/fastdeploy/vision/common/result.h +++ b/fastdeploy/vision/common/result.h @@ -49,6 +49,8 @@ struct FASTDEPLOY_DECL ClassifyResult : public BaseResult { std::vector label_ids; /// The confidence for each classify result std::vector scores; + /// The feature vector of recognizer, e.g, PP-ShiTuV2 Recognizer + std::vector feature; ResultType type = ResultType::CLASSIFY; /// Resize ClassifyResult data buffer diff --git a/fastdeploy/vision/detection/ppdet/base.cc b/fastdeploy/vision/detection/ppdet/base.cc old mode 100755 new mode 100644 index c0ba9a711..a0a9bf801 --- a/fastdeploy/vision/detection/ppdet/base.cc +++ b/fastdeploy/vision/detection/ppdet/base.cc @@ -18,7 +18,6 @@ PPDetBase::PPDetBase(const std::string& model_file, runtime_option.model_format = model_format; runtime_option.model_file = model_file; runtime_option.params_file = params_file; - } std::unique_ptr PPDetBase::Clone() const { @@ -83,20 +82,25 @@ bool PPDetBase::BatchPredict(const std::vector& imgs, return true; } -bool PPDetBase::CheckArch(){ - std::vector archs = {"SOLOv2","YOLO","SSD","RetinaNet","RCNN","Face","GFL","YOLOX","YOLOv5","YOLOv6","YOLOv7","RTMDet","FCOS","TTFNet","TOOD","DETR"}; - auto arch_ = preprocessor_.GetArch(); - for (auto item : archs) { - if (arch_ == item) { - return true; - } +bool PPDetBase::CheckArch() { + // Add "PicoDet" arch for backward compability with the + // old ppdet model, such as picodet from PaddleClas + // PP-ShiTuV2 pipeline. + std::vector archs = { + "SOLOv2", "YOLO", "SSD", "RetinaNet", "RCNN", "Face", + "GFL", "YOLOX", "YOLOv5", "YOLOv6", "YOLOv7", "RTMDet", + "FCOS", "TTFNet", "TOOD", "DETR", "PicoDet"}; + auto arch_ = preprocessor_.GetArch(); + for (auto item : archs) { + if (arch_ == item) { + return true; } - FDWARNING << "Please set model arch," - << "support value : SOLOv2, YOLO, SSD, RetinaNet, RCNN, Face , GFL , RTMDet ,"\ - <<"FCOS , TTFNet , TOOD , DETR." << std::endl; - return false; - - + } + FDWARNING << "Please set model arch," + << "support value : SOLOv2, YOLO, SSD, RetinaNet, " + << "RCNN, Face , GFL , RTMDet ," + << "FCOS , TTFNet , TOOD , DETR, PicoDet" << std::endl; + return false; } } // namespace detection diff --git a/fastdeploy/vision/detection/ppdet/model.h b/fastdeploy/vision/detection/ppdet/model.h index 2ecab7520..ec6b9fbfd 100755 --- a/fastdeploy/vision/detection/ppdet/model.h +++ b/fastdeploy/vision/detection/ppdet/model.h @@ -443,10 +443,11 @@ class FASTDEPLOY_DECL GFL : public PPDetBase { class FASTDEPLOY_DECL PaddleDetectionModel : public PPDetBase { public: - PaddleDetectionModel(const std::string& model_file, const std::string& params_file, - const std::string& config_file, - const RuntimeOption& custom_option = RuntimeOption(), - const ModelFormat& model_format = ModelFormat::PADDLE) + PaddleDetectionModel(const std::string& model_file, + const std::string& params_file, + const std::string& config_file, + const RuntimeOption& custom_option = RuntimeOption(), + const ModelFormat& model_format = ModelFormat::PADDLE) : PPDetBase(model_file, params_file, config_file, custom_option, model_format) { CheckArch(); @@ -472,8 +473,13 @@ class FASTDEPLOY_DECL PPYOLOER : public PPDetBase { const ModelFormat& model_format = ModelFormat::PADDLE) : PPDetBase(model_file, params_file, config_file, custom_option, model_format) { - valid_cpu_backends = { Backend::PDINFER}; - valid_gpu_backends = {Backend::PDINFER}; + valid_cpu_backends = {Backend::PDINFER, Backend::OPENVINO, Backend::ORT, + Backend::LITE}; + valid_gpu_backends = {Backend::PDINFER, Backend::ORT, Backend::TRT}; + valid_timvx_backends = {Backend::LITE}; + valid_kunlunxin_backends = {Backend::LITE}; + valid_rknpu_backends = {Backend::RKNPU2}; + valid_ascend_backends = {Backend::LITE}; valid_sophgonpu_backends = {Backend::SOPHGOTPU}; initialized = Initialize(); } diff --git a/fastdeploy/vision/vision_pybind.cc b/fastdeploy/vision/vision_pybind.cc old mode 100755 new mode 100644 index b8ed6c15e..664e6cc12 --- a/fastdeploy/vision/vision_pybind.cc +++ b/fastdeploy/vision/vision_pybind.cc @@ -62,18 +62,26 @@ void BindVision(pybind11::module& m) { .def(pybind11::init()) .def_readwrite("label_ids", &vision::ClassifyResult::label_ids) .def_readwrite("scores", &vision::ClassifyResult::scores) + .def_readwrite("feature", &vision::ClassifyResult::feature) .def(pybind11::pickle( [](const vision::ClassifyResult& c) { - return pybind11::make_tuple(c.label_ids, c.scores); + if (c.feature.empty()) { + return pybind11::make_tuple(c.label_ids, c.scores); + } + return pybind11::make_tuple(c.label_ids, c.scores, c.feature); }, [](pybind11::tuple t) { - if (t.size() != 2) + if ((t.size() != 2) && (t.size() != 3)) { throw std::runtime_error( "vision::ClassifyResult pickle with invalid state!"); + } vision::ClassifyResult c; c.label_ids = t[0].cast>(); c.scores = t[1].cast>(); + if (t.size() == 3) { + c.feature = t[2].cast>(); + } return c; })) diff --git a/python/fastdeploy/vision/classification/__init__.py b/python/fastdeploy/vision/classification/__init__.py index 4ca2097d0..7e22ee789 100644 --- a/python/fastdeploy/vision/classification/__init__.py +++ b/python/fastdeploy/vision/classification/__init__.py @@ -15,6 +15,10 @@ from .contrib.yolov5cls import YOLOv5Cls from .ppcls import * +from .ppshitu import PPShiTuV2Detector +from .ppshitu import PPShiTuV2Recognizer +from .ppshitu import PPShiTuV2RecognizerPreprocessor +from .ppshitu import PPShiTuV2RecognizerPostprocessor from .contrib.resnet import ResNet PPLCNet = PaddleClasModel diff --git a/python/fastdeploy/vision/classification/ppshitu/__init__.py b/python/fastdeploy/vision/classification/ppshitu/__init__.py new file mode 100644 index 000000000..7802cb67b --- /dev/null +++ b/python/fastdeploy/vision/classification/ppshitu/__init__.py @@ -0,0 +1,131 @@ +from __future__ import absolute_import +import logging +from .... import FastDeployModel, ModelFormat +from .... import c_lib_wrap as C +from ...common import ProcessorManager +from ...detection.ppdet import PicoDet + + +class PPShiTuV2Detector(PicoDet): + """Detect main body from an input image. + """ + ... + + +class PPShiTuV2RecognizerPreprocessor(ProcessorManager): + def __init__(self, config_file): + """Create a preprocessor for PPShiTuV2Recognizer from configuration file + + :param config_file: (str)Path of configuration file, e.g PPLCNet/inference_cls.yaml + """ + super(PPShiTuV2RecognizerPreprocessor, self).__init__() + self._manager = C.vision.classification.PPShiTuV2RecognizerPreprocessor( + config_file) + + def disable_normalize(self): + """ + This function will disable normalize in preprocessing step. + """ + self._manager.disable_normalize() + + def disable_permute(self): + """ + This function will disable hwc2chw in preprocessing step. + """ + self._manager.disable_permute() + + def initial_resize_on_cpu(self, v): + """ + When the initial operator is Resize, and input image size is large, + maybe it's better to run resize on CPU, because the HostToDevice memcpy + is time consuming. Set this True to run the initial resize on CPU. + :param: v: True or False + """ + self._manager.initial_resize_on_cpu(v) + + +class PPShiTuV2RecognizerPostprocessor: + def __init__(self, topk=1): + """Create a postprocessor for PPShiTuV2Recognizer + + """ + self._postprocessor = C.vision.classification.PPShiTuV2RecognizerPostprocessor( + ) + + def run(self, runtime_results): + """Postprocess the runtime results for PPShiTuV2Recognizer + + :param: runtime_results: (list of FDTensor)The output FDTensor results from runtime + :return: list of ClassifyResult, the feature vector is ClassifyResult.feature (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) + + +class PPShiTuV2Recognizer(FastDeployModel): + def __init__(self, + model_file, + params_file, + config_file, + runtime_option=None, + model_format=ModelFormat.PADDLE): + """Load a image PPShiTuV2Recognizer model exported by PaddleClas. + + :param model_file: (str)Path of model file, e.g PPLCNet/inference.pdmodel + :param params_file: (str)Path of parameters file, e.g PPLCNet/inference.pdiparams, if the model_fomat is ModelFormat.ONNX, this param will be ignored, can be set as empty string + :param config_file: (str) Path of configuration file for deploy, e.g PPLCNet/inference_cls.yaml + :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 + """ + + super(PPShiTuV2Recognizer, self).__init__(runtime_option) + self._model = C.vision.classification.PPShiTuV2Recognizer( + model_file, params_file, config_file, self._runtime_option, + model_format) + assert self.initialized, "PPShiTuV2Recognizer model initialize failed." + + def clone(self): + """Clone PPShiTuV2Recognizer object + + :return: a new PPShiTuV2Recognizer object + """ + + class PPShiTuV2RecognizerCloneModel(PPShiTuV2Recognizer): + def __init__(self, model): + self._model = model + + clone_model = PPShiTuV2RecognizerCloneModel(self._model.clone()) + return clone_model + + def predict(self, im): + """Extract feature from an input image + + :param im: (numpy.ndarray) The input image data, a 3-D array with layout HWC, BGR format + :return: ClassifyResult + """ + + return self._model.predict(im) + + def batch_predict(self, images): + """Extract features from 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 ClassifyResult, the feature vector is ClassifyResult.feature + """ + + return self._model.batch_predict(images) + + @property + def preprocessor(self): + """Get PPShiTuV2RecognizerPreprocessor object of the loaded model + + :return PPShiTuV2RecognizerPreprocessor + """ + return self._model.preprocessor + + @property + def postprocessor(self): + """Get PPShiTuV2RecognizerPostprocessor object of the loaded model + + :return PPShiTuV2RecognizerPostprocessor + """ + return self._model.postprocessor