From 33d3ada6ef97c5cfdff92c701fdbab8f6aa7802f Mon Sep 17 00:00:00 2001 From: DefTruth <31974251+DefTruth@users.noreply.github.com> Date: Mon, 15 Aug 2022 13:28:37 +0800 Subject: [PATCH 1/6] [feature][docs] add prebuilt windows python whl and cpp libs (#113) [feature][docs] add windows python whl and cpp libs --- docs/compile/prebuilt_libraries.md | 10 +++++----- docs/compile/prebuilt_wheels.md | 11 ++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/compile/prebuilt_libraries.md b/docs/compile/prebuilt_libraries.md index 6cec3721acd..bd58fc4b0b8 100644 --- a/docs/compile/prebuilt_libraries.md +++ b/docs/compile/prebuilt_libraries.md @@ -19,17 +19,17 @@ FastDeploy提供了在Windows/Linux/Mac上的预先编译CPP部署库,开发 ### Windows 10 x64平台 -| 部署库下载地址 | 硬件 | -| :------------- | :--- | -| [comming...] | CPU | -| [comming...] | CPU/GPU | +| 部署库下载地址 | 硬件 | 说明 | +| :------------- | :--- | :--- | +| [fastdeploy-win-x64-0.2.0](https://bj.bcebos.com/paddlehub/fastdeploy/cpp/fastdeploy-win-x64-0.2.0.zip) | CPU | Visual Studio 16 2019 编译产出 | +| [fastdeploy-win-x64-gpu-0.2.0](https://bj.bcebos.com/paddlehub/fastdeploy/cpp/fastdeploy-win-x64-gpu-0.2.0.zip) | CPU/GPU | Visual Studio 16 2019,cuda 11.2, cudnn 8.2编译产出 | ### Linux aarch64平台 | 安装包 | 硬件 | | :---- | :-- | | [comming...] | CPU | -| [comming...] | Jetson | +| [comming...] | Jetson | ### Mac OSX平台 diff --git a/docs/compile/prebuilt_wheels.md b/docs/compile/prebuilt_wheels.md index 14ba7d40044..e3ada892e11 100644 --- a/docs/compile/prebuilt_wheels.md +++ b/docs/compile/prebuilt_wheels.md @@ -38,15 +38,20 @@ python -m pip install fastdeploy_python-0.2.0-cp38-cp38-manylinux1_x86_64.whl | CPU 安装包 | 硬件 | Python版本 | | :---- | :-- | :------ | -| [comming...] | CPU | 3.8 | -| [comming...] | CPU | 3.9 | +| [fastdeploy_python-0.2.0-cp38-cp38-win_amd64.whl](https://bj.bcebos.com/paddlehub/fastdeploy/wheels/fastdeploy_python-0.2.0-cp38-cp38-win_amd64.whl) | CPU | 3.8 | +| [fastdeploy_python-0.2.0-cp39-cp39-win_amd64.whl](https://bj.bcebos.com/paddlehub/fastdeploy/wheels/fastdeploy_python-0.2.0-cp39-cp39-win_amd64.whl) | CPU | 3.9 | + +| GPU 安装包 | 硬件 | Python版本 | +| :---- | :-- | :------ | +| [fastdeploy_gpu_python-0.2.0-cp38-cp38-win_amd64.whl](https://bj.bcebos.com/paddlehub/fastdeploy/wheels/fastdeploy_gpu_python-0.2.0-cp38-cp38-win_amd64.whl) | CPU/GPU | 3.8 | +| [fastdeploy_gpu_python-0.2.0-cp39-cp39-win_amd64.whl](https://bj.bcebos.com/paddlehub/fastdeploy/wheels/fastdeploy_gpu_python-0.2.0-cp39-cp39-win_amd64.whl) | CPU/GPU | 3.9 | ### Linux aarch64平台 | 安装包 | 硬件 | Python版本 | | :---- | :-- | :------ | | [comming...] | CPU | 3.7 | -| [comming...] | CPU | 3.8 | +| [comming...] | CPU | 3.8 | | [comming...] | CPU | 3.9 | ### Mac OSX平台 From 835bb39b107779f60defe5084b72364047140227 Mon Sep 17 00:00:00 2001 From: Jack Zhou Date: Mon, 15 Aug 2022 13:28:48 +0800 Subject: [PATCH 2/6] Add ernie ie task (#100) --- FastDeploy.cmake.in | 4 + csrc/fastdeploy/core/config.h.in | 8 + .../ernie/cpp/CMakeLists.txt | 25 +++ .../information_extraction/ernie/cpp/infer.cc | 182 ++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 examples/text/information_extraction/ernie/cpp/CMakeLists.txt create mode 100644 examples/text/information_extraction/ernie/cpp/infer.cc diff --git a/FastDeploy.cmake.in b/FastDeploy.cmake.in index 082fa30f30b..ccd1039be29 100644 --- a/FastDeploy.cmake.in +++ b/FastDeploy.cmake.in @@ -95,6 +95,10 @@ endif() if (ENABLE_TEXT) # Add dependency libs later + find_library(FASTER_TOKENIZER_LIB core_tokenizers ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/lib NO_DEFAULT_PATH) + list(APPEND FASTDEPLOY_LIBS ${FASTER_TOKENIZER_LIB}) + list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/include) + list(APPEND FASTDEPLOY_INCS ${CMAKE_CURRENT_LIST_DIR}/third_libs/install/faster_tokenizer/third_party/include) endif() if(ENABLE_PADDLE_FRONTEND) diff --git a/csrc/fastdeploy/core/config.h.in b/csrc/fastdeploy/core/config.h.in index 7713925867a..b29113f1fdb 100644 --- a/csrc/fastdeploy/core/config.h.in +++ b/csrc/fastdeploy/core/config.h.in @@ -45,6 +45,10 @@ #cmakedefine ENABLE_VISION #endif +#ifndef ENABLE_TEXT +#cmakedefine ENABLE_TEXT +#endif + #ifndef ENABLE_OPENCV_CUDA #cmakedefine ENABLE_OPENCV_CUDA #endif @@ -52,3 +56,7 @@ #ifndef ENABLE_VISION_VISUALIZE #cmakedefine ENABLE_VISION_VISUALIZE #endif + +#ifndef ENABLE_FDTENSOR_FUNC +#cmakedefine ENABLE_FDTENSOR_FUNC +#endif diff --git a/examples/text/information_extraction/ernie/cpp/CMakeLists.txt b/examples/text/information_extraction/ernie/cpp/CMakeLists.txt new file mode 100644 index 00000000000..1189820cb79 --- /dev/null +++ b/examples/text/information_extraction/ernie/cpp/CMakeLists.txt @@ -0,0 +1,25 @@ +# 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. + +PROJECT(infer_demo C CXX) +CMAKE_MINIMUM_REQUIRED (VERSION 3.12) + +option(FASTDEPLOY_INSTALL_DIR "Path of downloaded fastdeploy sdk.") + +include(${FASTDEPLOY_INSTALL_DIR}/FastDeploy.cmake) + +include_directories(${FASTDEPLOY_INCS}) + +add_executable(infer_ernie_demo ${PROJECT_SOURCE_DIR}/infer.cc) +target_link_libraries(infer_ernie_demo ${FASTDEPLOY_LIBS}) diff --git a/examples/text/information_extraction/ernie/cpp/infer.cc b/examples/text/information_extraction/ernie/cpp/infer.cc new file mode 100644 index 00000000000..7f3b9318664 --- /dev/null +++ b/examples/text/information_extraction/ernie/cpp/infer.cc @@ -0,0 +1,182 @@ +// 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 +#include + +#include "fastdeploy/function/reduce.h" +#include "fastdeploy/function/softmax.h" +#include "fastdeploy/text.h" +#include "tokenizers/ernie_faster_tokenizer.h" + +using namespace paddlenlp; + +void LoadTransitionFromFile(const std::string& file, + std::vector* transitions, int* num_tags) { + std::ifstream fin(file); + std::string curr_transition; + float transition; + int i = 0; + while (fin) { + std::getline(fin, curr_transition); + std::istringstream iss(curr_transition); + while (iss) { + iss >> transition; + transitions->push_back(transition); + } + if (curr_transition != "") { + ++i; + } + } + *num_tags = i; +} + +template +void ViterbiDecode(const fastdeploy::FDTensor& slot_logits, + const fastdeploy::FDTensor& trans, + fastdeploy::FDTensor* best_path) { + int batch_size = slot_logits.shape[0]; + int seq_len = slot_logits.shape[1]; + int num_tags = slot_logits.shape[2]; + best_path->Allocate({batch_size, seq_len}, fastdeploy::FDDataType::INT64); + + const T* slot_logits_ptr = reinterpret_cast(slot_logits.Data()); + const T* trans_ptr = reinterpret_cast(trans.Data()); + int64_t* best_path_ptr = reinterpret_cast(best_path->Data()); + std::vector scores(num_tags); + std::copy(slot_logits_ptr, slot_logits_ptr + num_tags, scores.begin()); + std::vector> M(num_tags, std::vector(num_tags)); + for (int b = 0; b < batch_size; ++b) { + std::vector> paths; + const T* curr_slot_logits_ptr = slot_logits_ptr + b * seq_len * num_tags; + int64_t* curr_best_path_ptr = best_path_ptr + b * seq_len; + for (int t = 1; t < seq_len; t++) { + for (size_t i = 0; i < num_tags; i++) { + for (size_t j = 0; j < num_tags; j++) { + auto trans_idx = i * num_tags * num_tags + j * num_tags; + auto slot_logit_idx = t * num_tags + j; + M[i][j] = scores[i] + trans_ptr[trans_idx] + + curr_slot_logits_ptr[slot_logit_idx]; + } + } + std::vector idxs; + for (size_t i = 0; i < num_tags; i++) { + T max = 0.0f; + int idx = 0; + for (size_t j = 0; j < num_tags; j++) { + if (M[j][i] > max) { + max = M[j][i]; + idx = j; + } + } + scores[i] = max; + idxs.push_back(idx); + } + paths.push_back(idxs); + } + int scores_max_index = 0; + float scores_max = 0.0f; + for (size_t i = 0; i < scores.size(); i++) { + if (scores[i] > scores_max) { + scores_max = scores[i]; + scores_max_index = i; + } + } + curr_best_path_ptr[seq_len - 1] = scores_max_index; + for (int i = seq_len - 2; i >= 0; i--) { + int index = curr_best_path_ptr[i + 1]; + curr_best_path_ptr[i] = paths[i][index]; + } + } +} + +int main() { + // 1. Define a ernie faster tokenizer + faster_tokenizer::tokenizers_impl::ErnieFasterTokenizer tokenizer( + "ernie_vocab.txt"); + std::vector strings_list = { + "导航去科技园二号楼", "屏幕亮度为我减小一点吧"}; + std::vector encodings; + tokenizer.EncodeBatchStrings(strings_list, &encodings); + size_t batch_size = strings_list.size(); + size_t seq_len = encodings[0].GetLen(); + for (auto&& encoding : encodings) { + std::cout << encoding.DebugString() << std::endl; + } + // 2. Initialize runtime + fastdeploy::RuntimeOption runtime_option; + runtime_option.SetModelPath("nano_static/model.pdmodel", + "nano_static/model.pdiparams"); + fastdeploy::Runtime runtime; + runtime.Init(runtime_option); + + // 3. Construct input vector + // 3.1 Convert encodings to input_ids, token_type_ids + std::vector input_ids, token_type_ids; + for (int i = 0; i < encodings.size(); ++i) { + auto&& curr_input_ids = encodings[i].GetIds(); + auto&& curr_type_ids = encodings[i].GetTypeIds(); + input_ids.insert(input_ids.end(), curr_input_ids.begin(), + curr_input_ids.end()); + token_type_ids.insert(token_type_ids.end(), curr_type_ids.begin(), + curr_type_ids.end()); + } + // 3.2 Set data to input vector + std::vector inputs(runtime.NumInputs()); + void* inputs_ptrs[] = {input_ids.data(), token_type_ids.data()}; + for (int i = 0; i < runtime.NumInputs(); ++i) { + inputs[i].SetExternalData({batch_size, seq_len}, + fastdeploy::FDDataType::INT64, inputs_ptrs[i]); + inputs[i].name = runtime.GetInputInfo(i).name; + } + + // 4. Infer + std::vector outputs(runtime.NumOutputs()); + runtime.Infer(inputs, &outputs); + + // 5. Postprocess + fastdeploy::FDTensor domain_probs, intent_probs; + fastdeploy::Softmax(outputs[0], &domain_probs); + fastdeploy::Softmax(outputs[1], &intent_probs); + + fastdeploy::FDTensor domain_max_probs, intent_max_probs; + fastdeploy::Max(domain_probs, &domain_max_probs, {-1}, true); + fastdeploy::Max(intent_probs, &intent_max_probs, {-1}, true); + + std::vector transition; + int num_tags; + LoadTransitionFromFile("joint_transition.txt", &transition, &num_tags); + fastdeploy::FDTensor trans; + trans.SetExternalData({num_tags, num_tags}, fastdeploy::FDDataType::FP32, + transition.data()); + + fastdeploy::FDTensor best_path; + ViterbiDecode(outputs[2], trans, &best_path); + // 6. Print result + domain_max_probs.PrintInfo(); + intent_max_probs.PrintInfo(); + + batch_size = best_path.shape[0]; + seq_len = best_path.shape[1]; + const int64_t* best_path_ptr = + reinterpret_cast(best_path.Data()); + for (int i = 0; i < batch_size; ++i) { + std::cout << "best_path[" << i << "] = "; + for (int j = 0; j < seq_len; ++j) { + std::cout << best_path_ptr[i * seq_len + j] << ", "; + } + std::cout << std::endl; + } + best_path.PrintInfo(); + return 0; +} From 773d6bb938b77b8753feca11ed8607bf480860c3 Mon Sep 17 00:00:00 2001 From: ziqi-jin <67993288+ziqi-jin@users.noreply.github.com> Date: Mon, 15 Aug 2022 13:29:23 +0800 Subject: [PATCH 3/6] Modify API Result Docs (#112) * first commit for yolov7 * pybind for yolov7 * CPP README.md * CPP README.md * modified yolov7.cc * README.md * python file modify * delete license in fastdeploy/ * repush the conflict part * README.md modified * README.md modified * file path modified * file path modified * file path modified * file path modified * file path modified * README modified * README modified * move some helpers to private * add examples for yolov7 * api.md modified * api.md modified * api.md modified * YOLOv7 * yolov7 release link * yolov7 release link * yolov7 release link * copyright * change some helpers to private * change variables to const and fix documents. * gitignore * Transfer some funtions to private member of class * Transfer some funtions to private member of class * Merge from develop (#9) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * first commit for yolor * for merge * Develop (#11) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Yolor (#16) * Develop (#11) (#12) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Develop (#13) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * Develop (#14) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> * add is_dynamic for YOLO series (#22) * first commit test photo * yolov7 doc * yolov7 doc * yolov7 doc * yolov7 doc * add yolov5 docs * modify yolov5 doc * first commit for retinaface * first commit for retinaface * firt commit for ultraface * firt commit for ultraface * firt commit for yolov5face * firt commit for modnet and arcface * firt commit for modnet and arcface * first commit for partial_fc * first commit for partial_fc * first commit for yolox * first commit for yolov6 * first commit for nano_det * first commit for scrfd * first commit for scrfd * first commit for retinaface * first commit for ultraface * first commit for yolov5face * first commit for yolox yolov6 nano * rm jpg * first commit for modnet and modify nano * yolor scaledyolov4 v5lite * first commit for insightface * first commit for insightface * first commit for insightface * docs * docs * docs * docs * docs * add print for detect and modify docs * docs * docs * docs * docs test for insightface * docs test for insightface again * docs test for insightface * modify all wrong expressions in docs * modify all wrong expressions in docs * modify all wrong expressions in docs * modify all wrong expressions in docs * modify docs expressions * fix expression of detection part * fix expression of detection part * fix expression of detection part * add face recognition result doc * modify result docs * modify result docs * modify result docs Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> --- docs/api/vision_results/README.md | 5 ++-- .../vision_results/classification_result.md | 4 ++-- docs/api/vision_results/detection_result.md | 6 ++--- .../vision_results/face_detection_result.md | 8 +++---- .../vision_results/face_recognition_result.md | 24 +++++++++++++++++++ docs/api/vision_results/matting_result.md | 10 ++++---- examples/vision/README.md | 1 + 7 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 docs/api/vision_results/face_recognition_result.md diff --git a/docs/api/vision_results/README.md b/docs/api/vision_results/README.md index 844388cca86..64ea4fc671b 100644 --- a/docs/api/vision_results/README.md +++ b/docs/api/vision_results/README.md @@ -6,5 +6,6 @@ FastDeploy根据视觉模型的任务类型,定义了不同的结构体(`csrcs | :----- | :--- | :---- | :------- | | ClassificationResult | [C++/Python文档](./classification_result.md) | 图像分类返回结果 | ResNet50、MobileNetV3等 | | DetectionResult | [C++/Python文档](./detection_result.md) | 目标检测返回结果 | PPYOLOE、YOLOv7系列模型等 | -| FaceDetectionResult | [C++/Python文档](./face_detection_result.md) | 目标检测返回结果 | PPYOLOE、YOLOv7系列模型等 | -| MattingResult | [C++/Python文档](./matting_result.md) | 目标检测返回结果 | PPYOLOE、YOLOv7系列模型等 | +| FaceDetectionResult | [C++/Python文档](./face_detection_result.md) | 目标检测返回结果 | SCRFD、RetinaFace系列模型等 | +| FaceRecognitionResult | [C++/Python文档](./face_recognition_result.md) | 目标检测返回结果 | ArcFace、CosFace系列模型等 | +| MattingResult | [C++/Python文档](./matting_result.md) | 目标检测返回结果 | MODNet系列模型等 | diff --git a/docs/api/vision_results/classification_result.md b/docs/api/vision_results/classification_result.md index 113db39608a..bf94d0ff159 100644 --- a/docs/api/vision_results/classification_result.md +++ b/docs/api/vision_results/classification_result.md @@ -2,7 +2,7 @@ ClassifyResult代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明图像的分类结果和置信度。 -## C++ 结构体 +## C++ 定义 `fastdeploy::vision::ClassifyResult` @@ -20,7 +20,7 @@ struct ClassifyResult { - **Clear()**: 成员函数,用于清除结构体中存储的结果 - **Str()**: 成员函数,将结构体中的信息以字符串形式输出(用于Debug) -## Python结构体 +## Python 定义 `fastdeploy.vision.ClassifyResult` diff --git a/docs/api/vision_results/detection_result.md b/docs/api/vision_results/detection_result.md index e44a27b34c3..a702d49899f 100644 --- a/docs/api/vision_results/detection_result.md +++ b/docs/api/vision_results/detection_result.md @@ -2,7 +2,7 @@ DetectionResult代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明图像检测出来的目标框、目标类别和目标置信度。 -## C++ 结构体 +## C++ 定义 `fastdeploy::vision::DetectionResult` @@ -22,10 +22,10 @@ struct DetectionResult { - **Clear()**: 成员函数,用于清除结构体中存储的结果 - **Str()**: 成员函数,将结构体中的信息以字符串形式输出(用于Debug) -## Python结构体 +## Python 定义 `fastdeploy.vision.DetectionResult` - **boxes**(list of list(float)): 成员变量,表示单张图片检测出来的所有目标框坐标。boxes是一个list,其每个元素为一个长度为4的list, 表示为一个框,每个框以4个float数值依次表示xmin, ymin, xmax, ymax, 即左上角和右下角坐标 - **scores**(list of float): 成员变量,表示单张图片检测出来的所有目标置信度 -- **label_ids(list of int): 成员变量,表示单张图片检测出来的所有目标类别 +- **label_ids**(list of int): 成员变量,表示单张图片检测出来的所有目标类别 diff --git a/docs/api/vision_results/face_detection_result.md b/docs/api/vision_results/face_detection_result.md index 6c9c09f0073..000b42a6be0 100644 --- a/docs/api/vision_results/face_detection_result.md +++ b/docs/api/vision_results/face_detection_result.md @@ -1,8 +1,8 @@ # FaceDetectionResult 人脸检测结果 -FaceDetectionResult 代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明图像检测出来的目标框、目标类别和目标置信度。 +FaceDetectionResult 代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明人脸检测出来的目标框、人脸landmarks,目标置信度和每张人脸的landmark数量。 -## C++ 结构体 +## C++ 定义 `fastdeploy::vision::FaceDetectionResult` @@ -11,7 +11,6 @@ struct FaceDetectionResult { std::vector> boxes; std::vector> landmarks; std::vector scores; - ResultType type = ResultType::FACE_DETECTION; int landmarks_per_face; void Clear(); std::string Str(); @@ -25,10 +24,11 @@ struct FaceDetectionResult { - **Clear()**: 成员函数,用于清除结构体中存储的结果 - **Str()**: 成员函数,将结构体中的信息以字符串形式输出(用于Debug) -## Python结构体 +## Python 定义 `fastdeploy.vision.FaceDetectionResult` - **boxes**(list of list(float)): 成员变量,表示单张图片检测出来的所有目标框坐标。boxes是一个list,其每个元素为一个长度为4的list, 表示为一个框,每个框以4个float数值依次表示xmin, ymin, xmax, ymax, 即左上角和右下角坐标 - **scores**(list of float): 成员变量,表示单张图片检测出来的所有目标置信度 - **landmarks**: 成员变量,表示单张图片检测出来的所有人脸的关键点 +- **landmarks_per_face**: 成员变量,表示每个人脸框中的关键点的数量。 diff --git a/docs/api/vision_results/face_recognition_result.md b/docs/api/vision_results/face_recognition_result.md new file mode 100644 index 00000000000..83160561843 --- /dev/null +++ b/docs/api/vision_results/face_recognition_result.md @@ -0,0 +1,24 @@ +# FaceRecognitionResult 人脸识别结果 + +FaceRecognitionResult 代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明人脸识别模型对图像特征的embedding。 +## C++ 定义 + +`fastdeploy::vision::FaceRecognitionResult` + +``` +struct FaceRecognitionResult { + std::vector embedding; + void Clear(); + std::string Str(); +}; +``` + +- **embedding**: 成员变量,表示人脸识别模型最终的提取的特征embedding,可以用来计算人脸之间的特征相似度。 +- **Clear()**: 成员函数,用于清除结构体中存储的结果 +- **Str()**: 成员函数,将结构体中的信息以字符串形式输出(用于Debug) + +## Python 定义 + +`fastdeploy.vision.FaceRecognitionResult` + +- **embedding**: 成员变量,表示人脸识别模型最终提取的特征embedding,可以用来计算人脸之间的特征相似度。 diff --git a/docs/api/vision_results/matting_result.md b/docs/api/vision_results/matting_result.md index 3418400ecaa..67bcbc79d21 100644 --- a/docs/api/vision_results/matting_result.md +++ b/docs/api/vision_results/matting_result.md @@ -1,15 +1,15 @@ # MattingResult 抠图结果 -MattingResult 代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明图像检测出来的目标框、目标类别和目标置信度。 +MattingResult 代码定义在`csrcs/fastdeploy/vision/common/result.h`中,用于表明模型预测的alpha透明度的值,预测的前景等。 -## C++ 结构体 +## C++ 定义 `fastdeploy::vision::MattingResult` ``` struct MattingResult { - std::vector alpha; // h x w - std::vector foreground; // h x w x c (c=3 default) + std::vector alpha; + std::vector foreground; std::vector shape; bool contain_foreground = false; void Clear(); @@ -25,7 +25,7 @@ struct MattingResult { - **Str()**: 成员函数,将结构体中的信息以字符串形式输出(用于Debug) -## Python结构体 +## Python 定义 `fastdeploy.vision.MattingResult` diff --git a/examples/vision/README.md b/examples/vision/README.md index 9f05d2d7f6d..d95a315d798 100644 --- a/examples/vision/README.md +++ b/examples/vision/README.md @@ -8,6 +8,7 @@ | Segmentation | 语义分割,输入图像,给出图像中每个像素的分类及置信度 | [SegmentationResult](../../docs/api/vision_results/segmentation_result.md) | | Classification | 图像分类,输入图像,给出图像的分类结果和置信度 | [ClassifyResult](../../docs/api/vision_results/classification_result.md) | | FaceDetection | 人脸检测,输入图像,检测图像中人脸位置,并返回检测框坐标及人脸关键点 | [FaceDetectionResult](../../docs/api/vision_results/face_detection_result.md) | +| FaceRecognition | 人脸识别,输入图像,返回可用于相似度计算的人脸特征的embedding | [FaceRecognitionResult](../../docs/api/vision_results/face_recognition_result.md) | | Matting | 抠图,输入图像,返回图片的前景每个像素点的Alpha值 | [MattingResult](../../docs/api/vision_results/matting_result.md) | ## FastDeploy API设计 From a016ef99ceb57b461930b837b534317af567f3fd Mon Sep 17 00:00:00 2001 From: huangjianhui <852142024@qq.com> Date: Mon, 15 Aug 2022 15:24:38 +0800 Subject: [PATCH 4/6] Add PaddleSeg doc and infer.cc demo (#114) * Update README.md * Update README.md * Update README.md * Create README.md * Update README.md * Update README.md * Update README.md * Update README.md * Add evaluation calculate time and fix some bugs * Update classification __init__ * Move to ppseg * Add segmentation doc * Add PaddleClas infer.py * Update PaddleClas infer.py * Delete .infer.py.swp * Add PaddleClas infer.cc * Update README.md * Update README.md * Update README.md * Update infer.py * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Add PaddleSeg doc and infer.cc demo * Update README.md * Update README.md * Update README.md Co-authored-by: Jason --- .../vision/segmentation/ppseg/model.cc | 2 +- .../classification/paddleclas/README.md | 2 +- .../paddleclas/python/README.md | 15 ++-- .../detection/paddledetection/cpp/README.md | 2 +- .../vision/segmentation/paddleseg/README.md | 58 +++++------- .../segmentation/paddleseg/cpp/README.md | 62 +++++++------ .../segmentation/paddleseg/cpp/infer.cc | 89 +++++++++++-------- .../segmentation/paddleseg/python/README.md | 58 ++++++------ .../segmentation/paddleseg/python/infer.py | 19 ++-- .../vision/segmentation/ppseg/__init__.py | 4 +- 10 files changed, 160 insertions(+), 151 deletions(-) diff --git a/csrc/fastdeploy/vision/segmentation/ppseg/model.cc b/csrc/fastdeploy/vision/segmentation/ppseg/model.cc index be5c241f7d3..9604d665c13 100644 --- a/csrc/fastdeploy/vision/segmentation/ppseg/model.cc +++ b/csrc/fastdeploy/vision/segmentation/ppseg/model.cc @@ -14,7 +14,7 @@ PaddleSegModel::PaddleSegModel(const std::string& model_file, const Frontend& model_format) { config_file_ = config_file; valid_cpu_backends = {Backend::PDINFER, Backend::ORT}; - valid_gpu_backends = {Backend::PDINFER, Backend::ORT}; + valid_gpu_backends = {Backend::PDINFER, Backend::ORT, Backend::TRT}; runtime_option = custom_option; runtime_option.model_format = model_format; runtime_option.model_file = model_file; diff --git a/examples/vision/classification/paddleclas/README.md b/examples/vision/classification/paddleclas/README.md index 1f837761645..9a62f07f0ba 100644 --- a/examples/vision/classification/paddleclas/README.md +++ b/examples/vision/classification/paddleclas/README.md @@ -21,7 +21,7 @@ PaddleClas模型导出,请参考其文档说明[模型导出](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/inference_deployment/export_model.md#2-%E5%88%86%E7%B1%BB%E6%A8%A1%E5%9E%8B%E5%AF%BC%E5%87%BA) -注意:PaddleClas导出的模型仅包含`inference.pdmodel`和`inference.pdiparams`两个文档,但为了满足部署的需求,同时也需准备其提供的通用[inference_cls.yaml](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/deploy/configs/inference_cls.yaml)文件,FastDeploy会从yaml文件中获取模型在推理时需要的预处理信息,开发者可直接下载此文件使用。但需根据自己的需求修改yaml文件中的配置参数,具体可比照PaddleClas模型训练[config](https://github.com/PaddlePaddle/PaddleClas/tree/release/2.4/ppcls/configs/ImageNet)中的infer部分的配置信息进行修改。 +注意:PaddleClas导出的模型仅包含`inference.pdmodel`和`inference.pdiparams`两个文件,但为了满足部署的需求,同时也需准备其提供的通用[inference_cls.yaml](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/deploy/configs/inference_cls.yaml)文件,FastDeploy会从yaml文件中获取模型在推理时需要的预处理信息,开发者可直接下载此文件使用。但需根据自己的需求修改yaml文件中的配置参数,具体可比照PaddleClas模型训练[config](https://github.com/PaddlePaddle/PaddleClas/tree/release/2.4/ppcls/configs/ImageNet)中的infer部分的配置信息进行修改。 ## 下载预训练模型 diff --git a/examples/vision/classification/paddleclas/python/README.md b/examples/vision/classification/paddleclas/python/README.md index c6bb35d2ee5..77ad787973f 100644 --- a/examples/vision/classification/paddleclas/python/README.md +++ b/examples/vision/classification/paddleclas/python/README.md @@ -8,22 +8,21 @@ 本目录下提供`infer.py`快速完成ResNet50_vd在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。执行如下脚本即可完成 ``` +#下载部署示例代码 +git clone https://github.com/PaddlePaddle/FastDeploy.git +cd FastDeploy/examples/vision/classification/paddleclas/python + # 下载ResNet50_vd模型文件和测试图片 wget https://bj.bcebos.com/paddlehub/fastdeploy/ResNet50_vd_infer.tgz tar -xvf ResNet50_vd_infer.tgz wget https://gitee.com/paddlepaddle/PaddleClas/raw/release/2.4/deploy/images/ImageNet/ILSVRC2012_val_00000010.jpeg - -#下载部署示例代码 -git clone https://github.com/PaddlePaddle/FastDeploy.git -cd examples/vision/classification/paddleclas/python - # CPU推理 -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device cpu +python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device cpu --topk 1 # GPU推理 -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu +python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu --topk 1 # GPU上使用TensorRT推理 (注意:TensorRT推理第一次运行,有序列化模型的操作,有一定耗时,需要耐心等待) -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu --use_trt True +python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu --use_trt True --topk 1 ``` 运行完成后返回结果如下所示 diff --git a/examples/vision/detection/paddledetection/cpp/README.md b/examples/vision/detection/paddledetection/cpp/README.md index 4ed39929b85..64e2dc99734 100644 --- a/examples/vision/detection/paddledetection/cpp/README.md +++ b/examples/vision/detection/paddledetection/cpp/README.md @@ -15,7 +15,7 @@ wget https://bj.bcebos.com/paddlehub/fastdeploy/libs/0.2.0/fastdeploy-linux-x64- tar xvf fastdeploy-linux-x64-gpu-0.2.0.tgz cd fastdeploy-linux-x64-gpu-0.2.0/examples/vision/detection/paddledetection mkdir build && cd build -cmake .. -DFASTDEPLOY_INSTALL_DIR=${PWD}/../../../../../../fastdeploy-linux-x64-gpu-0.2.0 +cmake .. -DFASTDEPLOY_INSTALL_DIR=${PWD}/../../../../../../../fastdeploy-linux-x64-gpu-0.2.0 make -j # 下载PPYOLOE模型文件和测试图片 diff --git a/examples/vision/segmentation/paddleseg/README.md b/examples/vision/segmentation/paddleseg/README.md index 1f837761645..413e10b8a2c 100644 --- a/examples/vision/segmentation/paddleseg/README.md +++ b/examples/vision/segmentation/paddleseg/README.md @@ -1,54 +1,36 @@ -# PaddleClas 模型部署 +# PaddleSeg 模型部署 ## 模型版本说明 -- [PaddleClas Release/2.4](https://github.com/PaddlePaddle/PaddleClas/tree/release/2.4) +- [PaddleSeg Release/2.6](https://github.com/PaddlePaddle/PaddleSeg/tree/release/2.6) 目前FastDeploy支持如下模型的部署 -- [PP-LCNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/PP-LCNet.md) -- [PP-LCNetV2系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/PP-LCNetV2.md) -- [EfficientNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/EfficientNet_and_ResNeXt101_wsl.md) -- [GhostNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/Mobile.md) -- [MobileNet系列模型(包含v1,v2,v3)](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/Mobile.md) -- [ShuffleNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/Mobile.md) -- [SqueezeNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/Others.md) -- [Inception系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/Inception.md) -- [PP-HGNet系列模型](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/models/PP-HGNet.md) -- [ResNet系列模型(包含vd系列)](https://github.com/PaddlePaddle/PaddleClas/blob/develop/docs/zh_CN/models/ResNet_and_vd.md) +- [U-Net系列模型](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/configs/unet/README.md) +- [PP-LiteSeg系列模型](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/configs/pp_liteseg/README.md) +- [PP-HumanSeg系列模型](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/contrib/PP-HumanSeg/README.md) +- [FCN系列模型](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/configs/fcn/README.md) +- [DeepLabV3系列模型](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/configs/deeplabv3/README.md) -## 准备PaddleClas部署模型 +## 准备PaddleSeg部署模型 -PaddleClas模型导出,请参考其文档说明[模型导出](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/inference_deployment/export_model.md#2-%E5%88%86%E7%B1%BB%E6%A8%A1%E5%9E%8B%E5%AF%BC%E5%87%BA) +PaddleSeg模型导出,请参考其文档说明[模型导出](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/docs/model_export_cn.md) -注意:PaddleClas导出的模型仅包含`inference.pdmodel`和`inference.pdiparams`两个文档,但为了满足部署的需求,同时也需准备其提供的通用[inference_cls.yaml](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/deploy/configs/inference_cls.yaml)文件,FastDeploy会从yaml文件中获取模型在推理时需要的预处理信息,开发者可直接下载此文件使用。但需根据自己的需求修改yaml文件中的配置参数,具体可比照PaddleClas模型训练[config](https://github.com/PaddlePaddle/PaddleClas/tree/release/2.4/ppcls/configs/ImageNet)中的infer部分的配置信息进行修改。 +注意:在使用PaddleSeg模型导出时,可指定`--input_shape`参数,若预测输入图片尺寸并不固定,建议使用默认值即不指定该参数。PaddleSeg导出的模型包含`model.pdmodel`、`model.pdiparams`和`deploy.yaml`三个文件,FastDeploy会从yaml文件中获取模型在推理时需要的预处理信息。 ## 下载预训练模型 -为了方便开发者的测试,下面提供了PaddleClas导出的部分模型(含inference_cls.yaml文件),开发者可直接下载使用。 - -| 模型 | 参数文件大小 |输入Shape | Top1 | Top5 | -|:---------------------------------------------------------------- |:----- |:----- | :----- | :----- | -| [PPLCNet_x1_0](https://bj.bcebos.com/paddlehub/fastdeploy/PPLCNet_x1_0_infer.tgz) | 12MB | 224x224 |71.32% | 90.03% | -| [PPLCNetV2_base](https://bj.bcebos.com/paddlehub/fastdeploy/PPLCNetV2_base_infer.tgz) | 26MB | 224x224 |77.04% | 93.27% | -| [EfficientNetB7](https://bj.bcebos.com/paddlehub/fastdeploy/EfficientNetB7_infer.tgz) | 255MB | 600x600 | 84.3% | 96.9% | -| [EfficientNetB0_small](https://bj.bcebos.com/paddlehub/fastdeploy/EfficientNetB0_small_infer.tgz)| 18MB | 224x224 | 75.8% | 75.8% | -| [GhostNet_x1_3_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/GhostNet_x1_3_ssld_infer.tgz) | 29MB | 224x224 | 75.7% | 92.5% | -| [GhostNet_x0_5_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/GhostNet_x0_5_infer.tgz) | 10MB | 224x224 | 66.8% | 86.9% | -| [MobileNetV1_x0_25](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV1_x0_25_infer.tgz) | 1.9MB | 224x224 | 51.4% | 75.5% | -| [MobileNetV1_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV1_ssld_infer.tgz) | 17MB | 224x224 | 77.9% | 93.9% | -| [MobileNetV2_x0_25](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV2_x0_25_infer.tgz) | 5.9MB | 224x224 | 53.2% | 76.5% | -| [MobileNetV2_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV2_ssld_infer.tgz) | 14MB | 224x224 | 76.74% | 93.39% | -| [MobileNetV3_small_x0_35_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV3_small_x0_35_ssld_infer.tgz) | 6.4MB | 224x224 | 55.55% | 77.71% | -| [MobileNetV3_large_x1_0_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/MobileNetV3_large_x1_0_ssld_infer.tgz) | 22MB | 224x224 | 78.96% | 94.48% | -| [ShuffleNetV2_x0_25](https://bj.bcebos.com/paddlehub/fastdeploy/ShuffleNetV2_x0_25_infer.tgz) | 2.4MB | 224x224 | 49.9% | 73.79% | -| [ShuffleNetV2_x2_0](https://bj.bcebos.com/paddlehub/fastdeploy/ShuffleNetV2_x2_0_infer.tgz) | 29MB | 224x224 | 73.15% | 91.2% | -| [SqueezeNet1_1](https://bj.bcebos.com/paddlehub/fastdeploy/SqueezeNet1_1_infer.tgz) | 4.8MB | 224x224 | 60.1% | 81.9% | -| [InceptionV3](https://bj.bcebos.com/paddlehub/fastdeploy/InceptionV3_infer.tgz) | 92MB | 299x299 | 79.14% | 94.59% | -| [PPHGNet_tiny_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/PPHGNet_tiny_ssld_infer.tgz) | 57MB | 224x224 | 81.95% | 96.12% | -| [PPHGNet_base_ssld](https://bj.bcebos.com/paddlehub/fastdeploy/PPHGNet_base_ssld_infer.tgz) | 274MB | 224x224 | 85.0% | 97.35% | -| [ResNet50_vd](https://bj.bcebos.com/paddlehub/fastdeploy/ResNet50_vd_infer.tgz) | 98MB | 224x224 | 79.12% | 94.44% | +为了方便开发者的测试,下面提供了PaddleSeg导出的部分模型(导出方式为:**不指定**`input_shape`和`with_softmax`,**指定**`without_argmax`),开发者可直接下载使用。 + +| 模型 | 参数文件大小 |输入Shape | mIoU | mIoU (flip) | mIoU (ms+flip) | +|:---------------------------------------------------------------- |:----- |:----- | :----- | :----- | :----- | +| [Unet-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/Unet_cityscapes_without_argmax_infer.tgz) | 52MB | 1024x512 | 65.00% | 66.02% | 66.89% | +| [PP-LiteSeg-T(STDC1)-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/PP_LiteSeg_T_STDC1_cityscapes_without_argmax_infer.tgz) | 31MB | 1024x512 |73.10% | 73.89% | - | +| [PP-HumanSegV1-Lite](https://bj.bcebos.com/paddlehub/fastdeploy/PP_HumanSegV1_Lite_infer.tgz) | 543KB | 192x192 | 86.2% | - | - | +| [PP-HumanSegV1-Server](https://bj.bcebos.com/paddlehub/fastdeploy/PP_HumanSegV1_Server_infer.tgz) | 103MB | 512x512 | 96.47% | - | - | +| [FCN-HRNet-W18-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/FCN_HRNet_W18_cityscapes_without_argmax_infer.tgz) | 37MB | 1024x512 | 78.97% | 79.49% | 79.74% | +| [Deeplabv3-ResNet50-OS8-cityscapes](https://bj.bcebos.com/paddlehub/fastdeploy/Deeplabv3_ResNet50_OS8_cityscapes_without_argmax_infer.tgz) | 150MB | 1024x512 | 79.90% | 80.22% | 80.47% | ## 详细部署文档 diff --git a/examples/vision/segmentation/paddleseg/cpp/README.md b/examples/vision/segmentation/paddleseg/cpp/README.md index 302f3f74f36..8e5a9627b16 100644 --- a/examples/vision/segmentation/paddleseg/cpp/README.md +++ b/examples/vision/segmentation/paddleseg/cpp/README.md @@ -1,6 +1,6 @@ -# YOLOv7 C++部署示例 +# PaddleSeg C++部署示例 -本目录下提供`infer.cc`快速完成YOLOv7在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。 +本目录下提供`infer.cc`快速完成Unet在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。 在部署前,需确认以下两个步骤 @@ -12,51 +12,58 @@ ``` mkdir build cd build -wget https://xxx.tgz -tar xvf fastdeploy-linux-x64-0.2.0.tgz -cmake .. -DFASTDEPLOY_INSTALL_DIR=${PWD}/fastdeploy-linux-x64-0.2.0 +wget https://bj.bcebos.com/paddlehub/fastdeploy/libs/0.2.0/fastdeploy-linux-x64-gpu-0.2.0.tgz +tar xvf fastdeploy-linux-x64-gpu-0.2.0.tgz +cd fastdeploy-linux-x64-gpu-0.2.0/examples/vision/segmentation/paddleseg/cpp/build +cmake .. -DFASTDEPLOY_INSTALL_DIR=${PWD}/../../../../../../../fastdeploy-linux-x64-gpu-0.2.0 make -j -#下载官方转换好的yolov7模型文件和测试图片 -wget https://bj.bcebos.com/paddlehub/fastdeploy/yolov7.onnx -wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000087038.jpg +# 下载Unet模型文件和测试图片 +wget https://bj.bcebos.com/paddlehub/fastdeploy/Unet_cityscapes_without_argmax_infer.tgz +tar -xvf Unet_cityscapes_without_argmax_infer.tgz +wget https://paddleseg.bj.bcebos.com/dygraph/demo/cityscapes_demo.png # CPU推理 -./infer_demo yolov7.onnx 000000087038.jpg 0 +./infer_demo Unet_cityscapes_without_argmax_infer infer.cc cityscapes_demo.png 0 # GPU推理 -./infer_demo yolov7.onnx 000000087038.jpg 1 +./infer_demo Unet_cityscapes_without_argmax_infer infer.cc cityscapes_demo.png 1 # GPU上TensorRT推理 -./infer_demo yolov7.onnx 000000087038.jpg 2 +./infer_demo Unet_cityscapes_without_argmax_infer infer.cc cityscapes_demo.png 2 ``` -## YOLOv7 C++接口 +运行完成可视化结果如下图所示 +
+ +
-### YOLOv7类 +## PaddleSeg C++接口 + +### PaddleSeg类 ``` -fastdeploy::vision::detection::YOLOv7( +fastdeploy::vision::segmentation::PaddleSegModel( const string& model_file, const string& params_file = "", + const string& config_file, const RuntimeOption& runtime_option = RuntimeOption(), - const Frontend& model_format = Frontend::ONNX) + const Frontend& model_format = Frontend::PADDLE) ``` -YOLOv7模型加载和初始化,其中model_file为导出的ONNX模型格式。 +PaddleSegModel模型加载和初始化,其中model_file为导出的Paddle模型格式。 **参数** > * **model_file**(str): 模型文件路径 -> * **params_file**(str): 参数文件路径,当模型格式为ONNX时,此参数传入空字符串即可 +> * **params_file**(str): 参数文件路径 +> * **config_file**(str): 推理部署配置文件 > * **runtime_option**(RuntimeOption): 后端推理配置,默认为None,即采用默认配置 -> * **model_format**(Frontend): 模型格式,默认为ONNX格式 +> * **model_format**(Frontend): 模型格式,默认为Paddle格式 #### Predict函数 > ``` -> YOLOv7::Predict(cv::Mat* im, DetectionResult* result, -> float conf_threshold = 0.25, -> float nms_iou_threshold = 0.5) +> PaddleSegModel::Predict(cv::Mat* im, DetectionResult* result) > ``` > > 模型预测接口,输入图像直接输出检测结果。 @@ -64,13 +71,16 @@ YOLOv7模型加载和初始化,其中model_file为导出的ONNX模型格式。 > **参数** > > > * **im**: 输入图像,注意需为HWC,BGR格式 -> > * **result**: 检测结果,包括检测框,各个框的置信度, DetectionResult说明参考[视觉模型预测结果](../../../../../docs/api/vision_results/) -> > * **conf_threshold**: 检测框置信度过滤阈值 -> > * **nms_iou_threshold**: NMS处理过程中iou阈值 +> > * **result**: 分割结果,包括分割预测的标签以及标签对应的概率值, SegmentationResult说明参考[视觉模型预测结果](../../../../../docs/api/vision_results/) + +### 类成员属性 +#### 预处理参数 +用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 -### 类成员变量 +> > * **is_vertical_screen**(bool): PP-HumanSeg系列模型通过设置此参数为`True`表明输入图片是竖屏,即height大于width的图片 -> > * **size**(vector): 通过此参数修改预处理过程中resize的大小,包含两个整型元素,表示[width, height], 默认值为[640, 640] +#### 后处理参数 +> > * **with_softmax**(bool): 当模型导出时,并未指定`with_softmax`参数,可通过此设置此参数为`True`,将预测的输出分割标签(label_map)对应的概率结果(score_map)做softmax归一化处理 - [模型介绍](../../) - [Python部署](../python) diff --git a/examples/vision/segmentation/paddleseg/cpp/infer.cc b/examples/vision/segmentation/paddleseg/cpp/infer.cc index bd07ba988da..1f20ea9c87f 100644 --- a/examples/vision/segmentation/paddleseg/cpp/infer.cc +++ b/examples/vision/segmentation/paddleseg/cpp/infer.cc @@ -14,34 +14,45 @@ #include "fastdeploy/vision.h" -void CpuInfer(const std::string& model_file, const std::string& params_file, - const std::string& config_file, const std::string& image_file) { - auto option = fastdeploy::RuntimeOption(); - option.UseCpu() auto model = - fastdeploy::vision::classification::PaddleClasModel( - model_file, params_file, config_file, option); +#ifdef WIN32 +const char sep = '\\'; +#else +const char sep = '/'; +#endif + +void CpuInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto config_file = model_dir + sep + "deploy.yaml"; + auto model = fastdeploy::vision::segmentation::PaddleSegModel( + model_file, params_file, config_file); if (!model.Initialized()) { std::cerr << "Failed to initialize." << std::endl; return; } auto im = cv::imread(image_file); + auto im_bak = im.clone(); - fastdeploy::vision::ClassifyResult res; + fastdeploy::vision::SegmentationResult res; if (!model.Predict(&im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } - // print res - res.Str(); + auto vis_im = fastdeploy::vision::Visualize::VisSegmentation(im_bak, res); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; } -void GpuInfer(const std::string& model_file, const std::string& params_file, - const std::string& config_file, const std::string& image_file) { +void GpuInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto config_file = model_dir + sep + "deploy.yaml"; + auto option = fastdeploy::RuntimeOption(); option.UseGpu(); - auto model = fastdeploy::vision::classification::PaddleClasModel( + auto model = fastdeploy::vision::segmentation::PaddleSegModel( model_file, params_file, config_file, option); if (!model.Initialized()) { std::cerr << "Failed to initialize." << std::endl; @@ -49,25 +60,30 @@ void GpuInfer(const std::string& model_file, const std::string& params_file, } auto im = cv::imread(image_file); + auto im_bak = im.clone(); - fastdeploy::vision::ClassifyResult res; + fastdeploy::vision::SegmentationResult res; if (!model.Predict(&im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } - // print res - res.Str(); + auto vis_im = fastdeploy::vision::Visualize::VisSegmentation(im_bak, res); + cv::imwrite("vis_result.jpg", vis_im); + std::cout << "Visualized result saved in ./vis_result.jpg" << std::endl; } -void TrtInfer(const std::string& model_file, const std::string& params_file, - const std::string& config_file, const std::string& image_file) { +void TrtInfer(const std::string& model_dir, const std::string& image_file) { + auto model_file = model_dir + sep + "model.pdmodel"; + auto params_file = model_dir + sep + "model.pdiparams"; + auto config_file = model_dir + sep + "deploy.yaml"; + auto option = fastdeploy::RuntimeOption(); option.UseGpu(); option.UseTrtBackend(); - option.SetTrtInputShape("inputs", [ 1, 3, 224, 224 ], [ 1, 3, 224, 224 ], - [ 1, 3, 224, 224 ]); - auto model = fastdeploy::vision::classification::PaddleClasModel( + option.SetTrtInputShape("x", {1, 3, 256, 256}, {1, 3, 1024, 1024}, + {1, 3, 2048, 2048}); + auto model = fastdeploy::vision::segmentation::PaddleSegModel( model_file, params_file, config_file, option); if (!model.Initialized()) { std::cerr << "Failed to initialize." << std::endl; @@ -75,40 +91,37 @@ void TrtInfer(const std::string& model_file, const std::string& params_file, } auto im = cv::imread(image_file); + auto im_bak = im.clone(); - fastdeploy::vision::ClassifyResult res; + fastdeploy::vision::SegmentationResult res; if (!model.Predict(&im, &res)) { std::cerr << "Failed to predict." << std::endl; return; } - // print res - res.Str(); + auto vis_im = fastdeploy::vision::Visualize::VisSegmentation(im_bak, res); + 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 ./ResNet50_vd ./test.jpeg 0" - << std::endl; + std::cout + << "Usage: infer_demo path/to/model_dir path/to/image run_option, " + "e.g ./infer_model ./ppseg_model_dir ./test.jpeg 0" + << std::endl; std::cout << "The data type of run_option is int, 0: run with cpu; 1: run " "with gpu; 2: run with gpu and use tensorrt backend." << std::endl; return -1; } - std::string model_file = - argv[1] + "/" + "model.pdmodel" std::string params_file = - argv[1] + "/" + "model.pdiparams" std::string config_file = - argv[1] + "/" + "inference_cls.yaml" std::string image_file = - argv[2] if (std::atoi(argv[3]) == 0) { - CpuInfer(model_file, params_file, config_file, image_file); - } - else if (std::atoi(argv[3]) == 1) { - GpuInfer(model_file, params_file, config_file, image_file); - } - else if (std::atoi(argv[3]) == 2) { - TrtInfer(model_file, params_file, config_file, image_file); + if (std::atoi(argv[3]) == 0) { + CpuInfer(argv[1], argv[2]); + } else if (std::atoi(argv[3]) == 1) { + GpuInfer(argv[1], argv[2]); + } else if (std::atoi(argv[3]) == 2) { + TrtInfer(argv[1], argv[2]); } return 0; } diff --git a/examples/vision/segmentation/paddleseg/python/README.md b/examples/vision/segmentation/paddleseg/python/README.md index 1259c150992..a4456488491 100644 --- a/examples/vision/segmentation/paddleseg/python/README.md +++ b/examples/vision/segmentation/paddleseg/python/README.md @@ -1,46 +1,43 @@ -# PaddleClas模型 Python部署示例 +# PaddleSeg Python部署示例 在部署前,需确认以下两个步骤 - 1. 软硬件环境满足要求,参考[FastDeploy环境要求](../../../../../docs/quick_start/requirements.md) - 2. FastDeploy Python whl包安装,参考[FastDeploy Python安装](../../../../../docs/quick_start/install.md) -本目录下提供`infer.py`快速完成ResNet50_vd在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。执行如下脚本即可完成 +本目录下提供`infer.py`快速完成Unet在CPU/GPU,以及GPU上通过TensorRT加速部署的示例。执行如下脚本即可完成 ``` -# 下载ResNet50_vd模型文件和测试图片 -wget https://bj.bcebos.com/paddlehub/fastdeploy/ResNet50_vd_infer.tgz -tar -xvf ResNet50_vd_infer.tgz -wget https://gitee.com/paddlepaddle/PaddleClas/raw/release/2.4/deploy/images/ImageNet/ILSVRC2012_val_00000010.jpeg - - #下载部署示例代码 git clone https://github.com/PaddlePaddle/FastDeploy.git -cd examples/vision/classification/paddleclas/python +cd FastDeploy/examples/vision/segmentation/paddleseg/python + +# 下载Unet模型文件和测试图片 +wget https://bj.bcebos.com/paddlehub/fastdeploy/Unet_cityscapes_without_argmax_infer.tgz +tar -xvf Unet_cityscapes_without_argmax_infer.tgz +wget https://paddleseg.bj.bcebos.com/dygraph/demo/cityscapes_demo.png + # CPU推理 -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device cpu +python infer.py --model Unet_cityscapes_without_argmax_infer --image cityscapes_demo.png --device cpu # GPU推理 -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu +python infer.py --model Unet_cityscapes_without_argmax_infer --image cityscapes_demo.png --device gpu # GPU上使用TensorRT推理 (注意:TensorRT推理第一次运行,有序列化模型的操作,有一定耗时,需要耐心等待) -python infer.py --model ResNet50_vd_infer --image ILSVRC2012_val_00000010.jpeg --device gpu --use_trt True +python infer.py --model Unet_cityscapes_without_argmax_infer --image cityscapes_demo.png --device gpu --use_trt True ``` -运行完成后返回结果如下所示 -``` -ClassifyResult( -label_ids: 153, -scores: 0.686229, -) -``` +运行完成可视化结果如下图所示 +
+ +
-## PaddleClasModel Python接口 +## PaddleSegModel Python接口 ``` -fd.vision.classification.PaddleClasModel(model_file, params_file, config_file, runtime_option=None, model_format=Frontend.PADDLE) +fd.vision.segmentation.PaddleSegModel(model_file, params_file, config_file, runtime_option=None, model_format=Frontend.PADDLE) ``` -PaddleClas模型加载和初始化,其中model_file, params_file为训练模型导出的Paddle inference文件,具体请参考其文档说明[模型导出](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/docs/zh_CN/inference_deployment/export_model.md#2-%E5%88%86%E7%B1%BB%E6%A8%A1%E5%9E%8B%E5%AF%BC%E5%87%BA) +PaddleSeg模型加载和初始化,其中model_file, params_file以及config_file为训练模型导出的Paddle inference文件,具体请参考其文档说明[模型导出](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/docs/model_export_cn.md) **参数** @@ -53,7 +50,7 @@ PaddleClas模型加载和初始化,其中model_file, params_file为训练模 ### predict函数 > ``` -> PaddleClasModel.predict(input_image, topk=1) +> PaddleSegModel.predict(input_image) > ``` > > 模型预测结口,输入图像直接输出检测结果。 @@ -61,15 +58,22 @@ PaddleClas模型加载和初始化,其中model_file, params_file为训练模 > **参数** > > > * **input_image**(np.ndarray): 输入数据,注意需为HWC,BGR格式 -> > * **topk**(int):返回预测概率最高的topk个分类结果 > **返回** > -> > 返回`fastdeploy.vision.ClassifyResult`结构体,结构体说明参考文档[视觉模型预测结果](../../../../../docs/api/vision_results/) +> > 返回`fastdeploy.vision.SegmentationResult`结构体,结构体说明参考文档[视觉模型预测结果](../../../../../docs/api/vision_results/) + +### 类成员属性 +#### 预处理参数 +用户可按照自己的实际需求,修改下列预处理参数,从而影响最终的推理和部署效果 + +> > * **is_vertical_screen**(bool): PP-HumanSeg系列模型通过设置此参数为`true`表明输入图片是竖屏,即height大于width的图片 +#### 后处理参数 +> > * **with_softmax**(bool): 当模型导出时,并未指定`with_softmax`参数,可通过此设置此参数为`true`,将预测的输出分割标签(label_map)对应的概率结果(score_map)做softmax归一化处理 ## 其它文档 -- [PaddleClas 模型介绍](..) -- [PaddleClas C++部署](../cpp) +- [PaddleSeg 模型介绍](..) +- [PaddleSeg C++部署](../cpp) - [模型预测结果说明](../../../../../docs/api/vision_results/) diff --git a/examples/vision/segmentation/paddleseg/python/infer.py b/examples/vision/segmentation/paddleseg/python/infer.py index 88c272bcac7..28903e92957 100644 --- a/examples/vision/segmentation/paddleseg/python/infer.py +++ b/examples/vision/segmentation/paddleseg/python/infer.py @@ -8,11 +8,9 @@ def parse_arguments(): import ast parser = argparse.ArgumentParser() parser.add_argument( - "--model", required=True, help="Path of PaddleClas model.") + "--model", required=True, help="Path of PaddleSeg model.") parser.add_argument( "--image", type=str, required=True, help="Path of test image file.") - parser.add_argument( - "--topk", type=int, default=1, help="Return topk results.") parser.add_argument( "--device", type=str, @@ -43,14 +41,17 @@ def build_option(args): # 配置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.PaddleClasModel(model_file, params_file, config_file, runtime_option=runtime_option) -model = fd.vision.classification.ResNet50vd( +model_file = os.path.join(args.model, "model.pdmodel") +params_file = os.path.join(args.model, "model.pdiparams") +config_file = os.path.join(args.model, "deploy.yaml") +model = fd.vision.segmentation.PaddleSegModel( model_file, params_file, config_file, runtime_option=runtime_option) # 预测图片分类结果 im = cv2.imread(args.image) -result = model.predict(im, args.topk) +result = model.predict(im) print(result) + +# 可视化结果 +vis_im = fd.vision.visualize.vis_segmentation(im, result) +cv2.imwrite("vis_img.png", vis_im) diff --git a/fastdeploy/vision/segmentation/ppseg/__init__.py b/fastdeploy/vision/segmentation/ppseg/__init__.py index 9d3cfaf4d78..bc516351d0e 100644 --- a/fastdeploy/vision/segmentation/ppseg/__init__.py +++ b/fastdeploy/vision/segmentation/ppseg/__init__.py @@ -23,9 +23,9 @@ def __init__(self, model_file, params_file, config_file, - backend_option=None, + runtime_option=None, model_format=Frontend.PADDLE): - super(Model, self).__init__(backend_option) + super(PaddleSegModel, self).__init__(runtime_option) assert model_format == Frontend.PADDLE, "PaddleSeg only support model format of Frontend.Paddle now." self._model = C.vision.segmentation.PaddleSegModel( From 62760a4eb69de6635e2fc7d89fe58250b4e7ce0e Mon Sep 17 00:00:00 2001 From: ziqi-jin <67993288+ziqi-jin@users.noreply.github.com> Date: Mon, 15 Aug 2022 16:58:46 +0800 Subject: [PATCH 5/6] Fix the expression of data type for api docs (#115) * first commit for yolov7 * pybind for yolov7 * CPP README.md * CPP README.md * modified yolov7.cc * README.md * python file modify * delete license in fastdeploy/ * repush the conflict part * README.md modified * README.md modified * file path modified * file path modified * file path modified * file path modified * file path modified * README modified * README modified * move some helpers to private * add examples for yolov7 * api.md modified * api.md modified * api.md modified * YOLOv7 * yolov7 release link * yolov7 release link * yolov7 release link * copyright * change some helpers to private * change variables to const and fix documents. * gitignore * Transfer some funtions to private member of class * Transfer some funtions to private member of class * Merge from develop (#9) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * first commit for yolor * for merge * Develop (#11) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Yolor (#16) * Develop (#11) (#12) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Develop (#13) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * Develop (#14) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> * add is_dynamic for YOLO series (#22) * modify api docs * modify api docs Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> --- docs/api/vision_results/face_detection_result.md | 4 ++-- docs/api/vision_results/face_recognition_result.md | 2 +- docs/api/vision_results/matting_result.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/api/vision_results/face_detection_result.md b/docs/api/vision_results/face_detection_result.md index 000b42a6be0..2e1a13143d8 100644 --- a/docs/api/vision_results/face_detection_result.md +++ b/docs/api/vision_results/face_detection_result.md @@ -30,5 +30,5 @@ struct FaceDetectionResult { - **boxes**(list of list(float)): 成员变量,表示单张图片检测出来的所有目标框坐标。boxes是一个list,其每个元素为一个长度为4的list, 表示为一个框,每个框以4个float数值依次表示xmin, ymin, xmax, ymax, 即左上角和右下角坐标 - **scores**(list of float): 成员变量,表示单张图片检测出来的所有目标置信度 -- **landmarks**: 成员变量,表示单张图片检测出来的所有人脸的关键点 -- **landmarks_per_face**: 成员变量,表示每个人脸框中的关键点的数量。 +- **landmarks**(list of list(float)): 成员变量,表示单张图片检测出来的所有人脸的关键点 +- **landmarks_per_face**(int): 成员变量,表示每个人脸框中的关键点的数量。 diff --git a/docs/api/vision_results/face_recognition_result.md b/docs/api/vision_results/face_recognition_result.md index 83160561843..54d6eabb145 100644 --- a/docs/api/vision_results/face_recognition_result.md +++ b/docs/api/vision_results/face_recognition_result.md @@ -21,4 +21,4 @@ struct FaceRecognitionResult { `fastdeploy.vision.FaceRecognitionResult` -- **embedding**: 成员变量,表示人脸识别模型最终提取的特征embedding,可以用来计算人脸之间的特征相似度。 +- **embedding**(list of float): 成员变量,表示人脸识别模型最终提取的特征embedding,可以用来计算人脸之间的特征相似度。 diff --git a/docs/api/vision_results/matting_result.md b/docs/api/vision_results/matting_result.md index 67bcbc79d21..5a61365c268 100644 --- a/docs/api/vision_results/matting_result.md +++ b/docs/api/vision_results/matting_result.md @@ -29,7 +29,7 @@ struct MattingResult { `fastdeploy.vision.MattingResult` -- **alpha**: 是一维向量,为预测的alpha透明度的值,值域为[0.,1.],长度为hxw,h,w为输入图像的高和宽 -- **foreground**: 是一维向量,为预测的前景,值域为[0.,255.],长度为hxwxc,h,w为输入图像的高和宽,c一般为3,foreground不是一定有的,只有模型本身预测了前景,这个属性才会有效 -- **contain_foreground**: 表示预测的结果是否包含前景 -- **shape**: 表示输出结果的shape,当contain_foreground为false,shape只包含(h,w),当contain_foreground为true,shape包含(h,w,c), c一般为3 +- **alpha**(list of float): 是一维向量,为预测的alpha透明度的值,值域为[0.,1.],长度为hxw,h,w为输入图像的高和宽 +- **foreground**(list of float): 是一维向量,为预测的前景,值域为[0.,255.],长度为hxwxc,h,w为输入图像的高和宽,c一般为3,foreground不是一定有的,只有模型本身预测了前景,这个属性才会有效 +- **contain_foreground**(bool): 表示预测的结果是否包含前景 +- **shape**(list of int): 表示输出结果的shape,当contain_foreground为false,shape只包含(h,w),当contain_foreground为true,shape包含(h,w,c), c一般为3 From fcf85cfe6222660bd9685e4383f51dd7484454e6 Mon Sep 17 00:00:00 2001 From: DefTruth <31974251+DefTruth@users.noreply.github.com> Date: Mon, 15 Aug 2022 19:47:31 +0800 Subject: [PATCH 6/6] [feature][docs] update README.md and logo (#116) * update (#21) * [feature][docs] add prebuilt windows python whl and cpp libs (#113) [feature][docs] add windows python whl and cpp libs * Add ernie ie task (#100) * Modify API Result Docs (#112) * first commit for yolov7 * pybind for yolov7 * CPP README.md * CPP README.md * modified yolov7.cc * README.md * python file modify * delete license in fastdeploy/ * repush the conflict part * README.md modified * README.md modified * file path modified * file path modified * file path modified * file path modified * file path modified * README modified * README modified * move some helpers to private * add examples for yolov7 * api.md modified * api.md modified * api.md modified * YOLOv7 * yolov7 release link * yolov7 release link * yolov7 release link * copyright * change some helpers to private * change variables to const and fix documents. * gitignore * Transfer some funtions to private member of class * Transfer some funtions to private member of class * Merge from develop (#9) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * first commit for yolor * for merge * Develop (#11) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Yolor (#16) * Develop (#11) (#12) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * Develop (#13) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * documents * Develop (#14) * Fix compile problem in different python version (#26) * fix some usage problem in linux * Fix compile problem Co-authored-by: root * Add PaddleDetetion/PPYOLOE model support (#22) * add ppdet/ppyoloe * Add demo code and documents * add convert processor to vision (#27) * update .gitignore * Added checking for cmake include dir * fixed missing trt_backend option bug when init from trt * remove un-need data layout and add pre-check for dtype * changed RGB2BRG to BGR2RGB in ppcls model * add model_zoo yolov6 c++/python demo * fixed CMakeLists.txt typos * update yolov6 cpp/README.md * add yolox c++/pybind and model_zoo demo * move some helpers to private * fixed CMakeLists.txt typos * add normalize with alpha and beta * add version notes for yolov5/yolov6/yolox * add copyright to yolov5.cc * revert normalize * fixed some bugs in yolox * fixed examples/CMakeLists.txt to avoid conflicts * add convert processor to vision * format examples/CMakeLists summary * Fix bug while the inference result is empty with YOLOv5 (#29) * Add multi-label function for yolov5 * Update README.md Update doc * Update fastdeploy_runtime.cc fix variable option.trt_max_shape wrong name * Update runtime_option.md Update resnet model dynamic shape setting name from images to x * Fix bug when inference result boxes are empty * Delete detection.py Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> * add is_dynamic for YOLO series (#22) * first commit test photo * yolov7 doc * yolov7 doc * yolov7 doc * yolov7 doc * add yolov5 docs * modify yolov5 doc * first commit for retinaface * first commit for retinaface * firt commit for ultraface * firt commit for ultraface * firt commit for yolov5face * firt commit for modnet and arcface * firt commit for modnet and arcface * first commit for partial_fc * first commit for partial_fc * first commit for yolox * first commit for yolov6 * first commit for nano_det * first commit for scrfd * first commit for scrfd * first commit for retinaface * first commit for ultraface * first commit for yolov5face * first commit for yolox yolov6 nano * rm jpg * first commit for modnet and modify nano * yolor scaledyolov4 v5lite * first commit for insightface * first commit for insightface * first commit for insightface * docs * docs * docs * docs * docs * add print for detect and modify docs * docs * docs * docs * docs test for insightface * docs test for insightface again * docs test for insightface * modify all wrong expressions in docs * modify all wrong expressions in docs * modify all wrong expressions in docs * modify all wrong expressions in docs * modify docs expressions * fix expression of detection part * fix expression of detection part * fix expression of detection part * add face recognition result doc * modify result docs * modify result docs * modify result docs Co-authored-by: Jason Co-authored-by: root Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com> Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> Co-authored-by: Jack Zhou Co-authored-by: ziqi-jin <67993288+ziqi-jin@users.noreply.github.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * feature][docs] update README.md and logo * feature][docs] update README.md and logo * feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][docs] update README.md and logo * [feature][win] fix typos and rm un-need file Co-authored-by: Jack Zhou Co-authored-by: ziqi-jin <67993288+ziqi-jin@users.noreply.github.com> Co-authored-by: Jason Co-authored-by: root Co-authored-by: huangjianhui <852142024@qq.com> Co-authored-by: Jason <928090362@qq.com> --- README.md | 271 +++++++++++------- .../vision_results/face_detection_result.md | 1 + docs/compile/prebuilt_libraries.md | 2 +- docs/logo/fastdeploy-opaque.png | Bin 0 -> 147535 bytes 4 files changed, 162 insertions(+), 112 deletions(-) create mode 100644 docs/logo/fastdeploy-opaque.png diff --git a/README.md b/README.md index 5619db16009..8046fe0cba9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ -# ⚡️FastDeploy +![⚡️FastDeploy](docs/logo/fastdeploy-opaque.png)

------------------------------------------------------------------------------------------- -

@@ -19,147 +17,196 @@ **⚡️FastDeploy**是一款**简单易用**的推理部署工具箱。覆盖业界主流**优质预训练模型**并提供**开箱即用**的开发体验,包括图像分类、目标检测、图像分割、人脸检测、人体关键点识别、文字识别等多任务,满足开发者**多场景**,**多硬件**、**多平台**的快速部署需求。 ## 发版历史 -- [v0.2.0] 2022.08.18 全面开源服务端部署代码,支持40+视觉模型在CPU/GPU,以及通过GPU TensorRT加速部署 - -## 服务端模型 - -| 任务场景 | 模型 | CPU | NVIDIA GPU | TensorRT | -| -------- | ------------------------------------------------------------ | ------- | ---------- | ------------------- | -| 图像分类 | [PaddleClas/ResNet50](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/PPLCNet](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/EfficientNet](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/GhostNet](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/MobileNetV1](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/MobileNetV2](./examples/vision/classification/paddleclas) | √ | √ | √ | -| | [PaddleClas/ShuffleNetV2](./examples/vision/classification/paddleclas) | √ | √ | √ | -| 目标检测 | [PaddleDetection/PPYOLOE](./examples/vision/detection/paddledetection) | √ | √ | √ | -| | [PaddleDetection/PicoDet](./examples/vision/detection/paddledetection) | √ | √ | √ | -| | [PaddleDetection/YOLOX](./examples/vision/detection/paddledetection) | √ | √ | √ | -| | [PaddleDetection/YOLOv3](./examples/vision/detection/paddledetection) | √ | √ | √ | -| | [PaddleDetection/PPYOLO](./examples/vision/detection/paddledetection) | √ | √ | - | -| | [PaddleDetection/PPYOLOv2](./examples/vision/detection/paddledetection) | √ | √ | - | -| | [PaddleDetection/FasterRCNN](./examples/vision/detection/paddledetection) | √ | √ | - | -| | [WongKinYiu/YOLOv7](./examples/vision/detection/yolov7) | √ | √ | √ | - -## 快速开始 - -#### 安装FastDeploy Python - -用户根据开发环境选择安装版本,更多安装环境参考[安装文档](docs/quick_start/install.md). - -``` +- [v0.2.0] 2022.08.18 全面开源服务端部署代码,支持40+视觉模型在CPU/GPU,以及通过TensorRT加速部署 + +## 内容目录 +* [服务端模型列表](#fastdeploy-server-models) +* [服务端快速开始](#fastdeploy-quick-start) + * [快速安装](#fastdeploy-quick-start) + * [Python预测示例](#fastdeploy-quick-start-python) + * [C++预测示例](#fastdeploy-quick-start-cpp) +* [轻量化SDK快速实现端侧AI推理部署](#fastdeploy-edge-sdk) + * [边缘侧部署](#fastdeploy-edge-sdk-arm-linux) + * [移动端部署](#fastdeploy-edge-sdk-ios-android) + * [自定义模型部署](#fastdeploy-edge-sdk-custom) +* [社区交流](#fastdeploy-community) +* [Acknowledge](#fastdeploy-acknowledge) +* [License](#fastdeploy-license) +## 1. 服务端模型列表 🔥🔥🔥 + +

+ +符号说明: (1) ✅: 已经支持; (2) ❔: 计划未来支持; (3) ❌: 暂不支持; (4) contrib: 外部模型 +| 任务场景 | 模型 | API | Linux | Linux | Windows | Windows | MacOS | MacOS | Linux | +| :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | +| --- | --- | --- | X86 CPU | NVIDIA GPU | Intel CPU | NVIDIA GPU | Intel CPU | Arm CPU | NVIDIA Jetson | +| Classification | [PaddleClas/ResNet50](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/PPLCNet](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/PPLCNetv2](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/EfficientNet](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/GhostNet](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/MobileNetV1](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/MobileNetV2](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/MobileNetV3](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/ShuffleNetV2](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/SqueeezeNetV1.1](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/Inceptionv3](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/PPHGNet](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Classification | [PaddleClas/SwinTransformer](./examples/vision/classification/paddleclas) | [Python](./examples/vision/classification/paddleclas/python)/[C++](./examples/vision/classification/paddleclas/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/PPYOLOE](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/PicoDet](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/YOLOX](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/YOLOv3](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/PPYOLO](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/PPYOLOv2](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [PaddleDetection/FasterRCNN](./examples/vision/detection/paddledetection) | [Python](./examples/vision/detection/paddledetection/python)/[C++](./examples/vision/detection/paddledetection/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOX](./examples/vision/detection/yolox) | [Python](./examples/vision/detection/yolox/python)/[C++](./examples/vision/detection/yolox/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOv7](./examples/vision/detection/yolov7) | [Python](./examples/vision/detection/yolov7/python)/[C++](./examples/vision/detection/yolov7/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOv6](./examples/vision/detection/yolov6) | [Python](./examples/vision/detection/yolov6/python)/[C++](./examples/vision/detection/yolov6/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOv5](./examples/vision/detection/yolov5) | [Python](./examples/vision/detection/yolov5/python)/[C++](./examples/vision/detection/yolov5/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOR](./examples/vision/detection/yolor) | [Python](./examples/vision/detection/yolor/python)/[C++](./examples/vision/detection/yolor/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/ScaledYOLOv4](./examples/vision/detection/scaledyolov4) | [Python](./examples/vision/detection/scaledyolov4/python)/[C++](./examples/vision/detection/scaledyolov4/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/YOLOv5Lite](./examples/vision/detection/yolov5lite) | [Python](./examples/vision/detection/yolov5lite/python)/[C++](./examples/vision/detection/yolov5lite/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Detection | [Contrib/NanoDetPlus](./examples/vision/detection/nanodet_plus) | [Python](./examples/vision/detection/nanodet_plus/python)/[C++](./examples/vision/detection/nanodet_plus/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/PPLiteSeg](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/PPHumanSegLite](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/HRNet](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/PPHumanSegServer](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/Unet](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Segmentation | [PaddleSeg/Deeplabv3](./examples/vision/segmentation/paddleseg) | [Python](./examples/vision/segmentation/paddleseg/python)/[C++](./examples/vision/segmentation/paddleseg/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceDetection | [Contrib/RetinaFace](./examples/vision/facedet/retinaface) | [Python](./examples/vision/facedet/retinaface/python)/[C++](./examples/vision/facedet/retinaface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceDetection | [Contrib/UltraFace](./examples/vision/facedet/utltraface) | [ Python](./examples/vision/facedet/utltraface/python)/[C++](./examples/vision/facedet/utltraface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceDetection | [Contrib/YOLOv5Face](./examples/vision/facedet/yolov5face) | [Python](./examples/vision/facedet/yolov5face/python)/[C++](./examples/vision/facedet/yolov5face/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceDetection | [Contrib/SCRFD](./examples/vision/facedet/scrfd) | [Python](./examples/vision/facedet/scrfd/python)/[C++](./examples/vision/facedet/scrfd/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceRecognition | [Contrib/ArcFace](./examples/vision/faceid/insightface) | [Python](./examples/vision/faceid/insightface/python)/[C++](./examples/vision/faceid/insightface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceRecognition | [Contrib/CosFace](./examples/vision/faceid/insightface) | [Python](./examples/vision/faceid/insightface/python)/[C++](./examples/vision/faceid/insightface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceRecognition | [Contrib/PartialFC](./examples/vision/faceid/insightface) | [Python](./examples/vision/faceid/insightface/python)/[C++](./examples/vision/faceid/insightface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| FaceRecognition | [Contrib/VPL](./examples/vision/faceid/insightface) | [Python](./examples/vision/faceid/insightface/python)/[C++](./examples/vision/faceid/insightface/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | +| Matting | [Contrib/MODNet](./examples/vision/matting/modnet) | [Python](./examples/vision/matting/modnet/python)/[C++](./examples/vision/matting/modnet/cpp) | ✅ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | + + +## 2. 服务端快速开始 +
+ +
+💡 快速安装 FastDeploy Python/C++ 库 + +用户根据自己的python版本选择安装对应的wheel包,详细的wheel目录请参考 [python安装文档](docs/compile/prebuilt_wheels.md) . + +```bash pip install https://bj.bcebos.com/paddlehub/fastdeploy/wheels/fastdeploy_python-0.2.0-cp38-cp38-manylinux1_x86_64.whl ``` - -准备目标检测模型和测试图片 +或获取C++预编译库,更多可用的预编译库请参考 [C++预编译库下载](docs/compile/prebuilt_libraries.md) +```bash +wget https://bj.bcebos.com/paddlehub/fastdeploy/cpp/fastdeploy-linux-x64-0.2.0.tgz ``` +准备目标检测模型和测试图片 +```bash wget https://bj.bcebos.com/paddlehub/fastdeploy/ppyoloe_crn_l_300e_coco.tgz tar xvf ppyoloe_crn_l_300e_coco.tgz wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg ``` +
-加载模型预测 -``` -import fastdeploy.vision as vis -import cv2 +### 2.1 Python预测示例 +
-model = vis.detection.PPYOLOE("ppyoloe_crn_l_300e_coco/model.pdmodel", - "ppyoloe_crn_l_300e_coco/model.pdiparams", - "ppyoloe_crn_l_300e_coco/infer_cfg.yml") +```python +import cv2 +import fastdeploy.vision as vision +model = vision.detection.PPYOLOE("model.pdmodel", "model.pdiparams", "infer_cfg.yml") im = cv2.imread("000000014439.jpg") result = model.predict(im.copy()) print(result) -vis_im = fd.vision.vis_detection(im, result, score_threshold=0.5) +vis_im = vision.vis_detection(im, result, score_threshold=0.5) cv2.imwrite("vis_image.jpg", vis_im) ``` +### 2.2 C++预测示例 +
-预测完成,可视化结果保存至`vis_image.jpg`,同时输出检测结果如下 -``` -DetectionResult: [xmin, ymin, xmax, ymax, score, label_id] -415.047363,89.311523, 506.009613, 283.863129, 0.950423, 0 -163.665710,81.914894, 198.585342, 166.760880, 0.896433, 0 -581.788635,113.027596, 612.623474, 198.521713, 0.842597, 0 -267.217224,89.777321, 298.796051, 169.361496, 0.837951, 0 -104.465599,45.482410, 127.688835, 93.533875, 0.773348, 0 -... -``` - -## 更多服务端部署示例 +```C++ +#include "fastdeploy/vision.h" -FastDeploy提供了大量部署示例供开发者参考,支持模型在CPU、GPU以及TensorRT的部署 +int main(int argc, char* argv[]) { + namespace vision = fastdeploy::vision; + auto model = vision::detection::PPYOLOE("model.pdmodel", "model.pdiparams", "infer_cfg.yml"); + auto im = cv::imread("000000014439.jpg"); -- [PaddleDetection模型部署](examples/vision/detection/paddledetection) -- [PaddleClas模型部署](examples/vision/classification/paddleclas) -- [PaddleSeg模型部署](examples/vision/segmentation/paddleseg) -- [YOLOv7部署](examples/vision/detection/yolov7) -- [YOLOv6部署](examples/vision/detection/yolov6) -- [YOLOv5部署](examples/vision/detection/yolov5) -- [人脸检测模型部署](examples/vision/facedet) -- [更多视觉模型部署示例...](examples/vision) + vision::DetectionResult res; + model.Predict(&im, &res) -### 📱轻量化SDK快速实现端侧AI推理部署 + auto vis_im = vision::Visualize::VisDetection(im, res, 0.5); + cv::imwrite("vis_image.jpg", vis_im); +} +``` +更多部署案例请参考[视觉模型部署示例](examples/vision) . +## 3. 轻量化SDK快速实现端侧AI推理部署 📱 +
| 任务场景 | 模型 | 大小(MB) | 边缘端 | 移动端 | 移动端 | -| ------------------ | ---------------------------- | --------------------- | --------------------- | ---------------------- | --------------------- | -| ---- | --- | --- | Linux | Android | iOS | -| ----- | ---- | --- | ARM CPU | ARM CPU | ARM CPU | -| Classfication | PP-LCNet | 11.9 | ✅ | ✅ | ✅ | -| | PP-LCNetv2 | 26.6 | ✅ | ✅ | ✅ | -| | EfficientNet | 31.4 | ✅ | ✅ | ✅ | -| | GhostNet | 20.8 | ✅ | ✅ | ✅ | -| | MobileNetV1 | 17 | ✅ | ✅ | ✅ | -| | MobileNetV2 | 14.2 | ✅ | ✅ | ✅ | -| | MobileNetV3 | 22 | ✅ | ✅ | ✅ | -| | ShuffleNetV2 | 9.2 | ✅ | ✅ | ✅ | -| | SqueezeNetV1.1 | 5 | ✅ | ✅ | ✅ | -| | Inceptionv3 | 95.5 | ✅ | ✅ | ✅ | -| | PP-HGNet | 59 | ✅ | ✅ | ✅ | -| | SwinTransformer_224_win7 | 352.7 | ✅ | ✅ | ✅ | -| Detection | PP-PicoDet_s_320_coco | 4.1 | ✅ | ✅ | ✅ | -| | PP-PicoDet_s_320_lcnet | 4.9 | ✅ | ✅ | ✅ | -| | CenterNet | 4.8 | ✅ | ✅ | ✅ | -| | YOLOv3_MobileNetV3 | 94.6 | ✅ | ✅ | ✅ | -| | PP-YOLO_tiny_650e_coco | 4.4 | ✅ | ✅ | ✅ | -| | SSD_MobileNetV1_300_120e_voc | 23.3 | ✅ | ✅ | ✅ | -| | PP-YOLO_ResNet50vd | 188.5 | ✅ | ✅ | ✅ | -| | PP-YOLOv2_ResNet50vd | 218.7 | ✅ | ✅ | ✅ | -| | PP-YOLO_crn_l_300e_coco | 209.1 | ✅ | ✅ | ✅ | -| | YOLOv5s | 29.3 | ✅ | ✅ | ✅ | -| Face Detection | BlazeFace | 1.5 | ✅ | ✅ | ✅ | -| Face Localisation | RetinaFace | 1.7 | ✅ | ❌ | ❌ | -| Keypoint Detection | PP-TinyPose | 5.5 | ✅ | ✅ | ✅ | -| Segmentation | PP-LiteSeg(STDC1) | 32.2 | ✅ | ✅ | ✅ | -| | PP-HumanSeg-Lite | 0.556 | ✅ | ✅ | ✅ | -| | HRNet-w18 | 38.7 | ✅ | ✅ | ✅ | -| | PP-HumanSeg-Server | 107.2 | ✅ | ✅ | ✅ | -| | Unet | 53.7 | ❌ | ✅ | ❌ | -| OCR | PP-OCRv1 | 2.3+4.4 | ✅ | ✅ | ✅ | -| | PP-OCRv2 | 2.3+4.4 | ✅ | ✅ | ✅ | -| | PP-OCRv3 | 2.4+10.6 | ✅ | ✅ | ✅ | -| | PP-OCRv3-tiny | 2.4+10.7 | ✅ | ✅ | ✅ | - - -#### 边缘侧部署 - -- ARM Linux 系统 +| :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | +| --- | --- | --- | Linux | Android | iOS | +| --- | --- | --- | ARM CPU | ARM CPU | ARM CPU | +| Classification | PP-LCNet | 11.9 | ✅ | ✅ | ✅ | +| Classification | PP-LCNetv2 | 26.6 | ✅ | ✅ | ✅ | +| Classification | EfficientNet | 31.4 | ✅ | ✅ | ✅ | +| Classification | GhostNet | 20.8 | ✅ | ✅ | ✅ | +| Classification | MobileNetV1 | 17 | ✅ | ✅ | ✅ | +| Classification | MobileNetV2 | 14.2 | ✅ | ✅ | ✅ | +| Classification | MobileNetV3 | 22 | ✅ | ✅ | ✅ | +| Classification | ShuffleNetV2 | 9.2 | ✅ | ✅ | ✅ | +| Classification | SqueezeNetV1.1 | 5 | ✅ | ✅ | ✅ | +| Classification | Inceptionv3 | 95.5 | ✅ | ✅ | ✅ | +| Classification | PP-HGNet | 59 | ✅ | ✅ | ✅ | +| Classification | SwinTransformer_224_win7 | 352.7 | ✅ | ✅ | ✅ | +| Detection | PP-PicoDet_s_320_coco | 4.1 | ✅ | ✅ | ✅ | +| Detection | PP-PicoDet_s_320_lcnet | 4.9 | ✅ | ✅ | ✅ | +| Detection | CenterNet | 4.8 | ✅ | ✅ | ✅ | +| Detection | YOLOv3_MobileNetV3 | 94.6 | ✅ | ✅ | ✅ | +| Detection | PP-YOLO_tiny_650e_coco | 4.4 | ✅ | ✅ | ✅ | +| Detection | SSD_MobileNetV1_300_120e_voc | 23.3 | ✅ | ✅ | ✅ | +| Detection | PP-YOLO_ResNet50vd | 188.5 | ✅ | ✅ | ✅ | +| Detection | PP-YOLOv2_ResNet50vd | 218.7 | ✅ | ✅ | ✅ | +| Detection | PP-YOLO_crn_l_300e_coco | 209.1 | ✅ | ✅ | ✅ | +| Detection | YOLOv5s | 29.3 | ✅ | ✅ | ✅ | +| FaceDetection | BlazeFace | 1.5 | ✅ | ✅ | ✅ | +| FaceDetection | RetinaFace | 1.7 | ✅ | ❌ | ❌ | +| KeypointsDetection | PP-TinyPose | 5.5 | ✅ | ✅ | ✅ | +| Segmentation | PP-LiteSeg(STDC1) | 32.2 | ✅ | ✅ | ✅ | +| Segmentation | PP-HumanSeg-Lite | 0.556 | ✅ | ✅ | ✅ | +| Segmentation | HRNet-w18 | 38.7 | ✅ | ✅ | ✅ | +| Segmentation | PP-HumanSeg-Server | 107.2 | ✅ | ✅ | ✅ | +| Segmentation | Unet | 53.7 | ❌ | ✅ | ❌ | +| OCR | PP-OCRv1 | 2.3+4.4 | ✅ | ✅ | ✅ | +| OCR | PP-OCRv2 | 2.3+4.4 | ✅ | ✅ | ✅ | +| OCR | PP-OCRv3 | 2.4+10.6 | ✅ | ✅ | ✅ | +| OCR | PP-OCRv3-tiny | 2.4+10.7 | ✅ | ✅ | ✅ | + +### 3.1 边缘侧部署 +
+ +- ARM Linux 系统 - [C++ Inference部署(含视频流)](./docs/ARM-Linux-CPP-SDK-Inference.md) - [C++ 服务化部署](./docs/ARM-Linux-CPP-SDK-Serving.md) - [Python Inference部署](./docs/ARM-Linux-Python-SDK-Inference.md) - [Python 服务化部署](./docs/ARM-Linux-Python-SDK-Serving.md) -#### 移动端部署 +### 3.2 移动端部署 +
- [iOS 系统部署](./docs/iOS-SDK.md) - [Android 系统部署](./docs/Android-SDK.md) -#### 自定义模型部署 +### 3.3 自定义模型部署 +
- [快速实现个性化模型替换](./docs/Replace-Model-With-Anther-One.md) -## 社区交流 +## 4. 社区交流 +
- **加入社区👬:** 微信扫描二维码后,填写问卷加入交流群,与开发者共同讨论推理部署痛点问题 @@ -167,11 +214,13 @@ FastDeploy提供了大量部署示例供开发者参考,支持模型在CPU、G -## Acknowledge +## 5. Acknowledge +
本项目中SDK生成和下载使用了[EasyEdge](https://ai.baidu.com/easyedge/app/openSource)中的免费开放能力,再次表示感谢。 -## License +## 6. License +
FastDeploy遵循[Apache-2.0开源协议](./LICENSE)。 diff --git a/docs/api/vision_results/face_detection_result.md b/docs/api/vision_results/face_detection_result.md index 2e1a13143d8..30029a7f0fa 100644 --- a/docs/api/vision_results/face_detection_result.md +++ b/docs/api/vision_results/face_detection_result.md @@ -32,3 +32,4 @@ struct FaceDetectionResult { - **scores**(list of float): 成员变量,表示单张图片检测出来的所有目标置信度 - **landmarks**(list of list(float)): 成员变量,表示单张图片检测出来的所有人脸的关键点 - **landmarks_per_face**(int): 成员变量,表示每个人脸框中的关键点的数量。 + diff --git a/docs/compile/prebuilt_libraries.md b/docs/compile/prebuilt_libraries.md index bd58fc4b0b8..905eb6d5295 100644 --- a/docs/compile/prebuilt_libraries.md +++ b/docs/compile/prebuilt_libraries.md @@ -1,4 +1,4 @@ -# FastDeploy 预编编译Python Wheel包 +# FastDeploy 预编译 C++ 库 FastDeploy提供了在Windows/Linux/Mac上的预先编译CPP部署库,开发者可以直接下载后使用,也可以自行编译代码。 diff --git a/docs/logo/fastdeploy-opaque.png b/docs/logo/fastdeploy-opaque.png new file mode 100644 index 0000000000000000000000000000000000000000..16289dcf555f5a1ceb32f720a71054ec6c5200d0 GIT binary patch literal 147535 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

x3n9U7)WcMH58P+4*QS0g1hr)@PZA9 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