first commit

This commit is contained in:
Jason
2022-06-27 18:23:21 +08:00
commit 978484c84f
25 changed files with 6446 additions and 0 deletions

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

199
README.md Normal file
View File

@@ -0,0 +1,199 @@
# FastDeploy
</p>
------------------------------------------------------------------------------------------
<p align="center">
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-Apache%202-dfd.svg"></a>
<a href="https://github.com/PaddlePaddle/FastDeploy/releases"><img src="https://img.shields.io/github/v/release/PaddlePaddle/FastDeploy?color=ffa"></a>
<a href=""><img src="https://img.shields.io/badge/python-3.7+-aff.svg"></a>
<a href=""><img src="https://img.shields.io/badge/os-linux%2C%20win%2C%20mac-pink.svg"></a>
<a href="https://github.com/PaddlePaddle/FastDeploy/graphs/contributors"><img src="https://img.shields.io/github/contributors/PaddlePaddle/FastDeploy?color=9ea"></a>
<a href="https://github.com/PaddlePaddle/FastDeploy/commits"><img src="https://img.shields.io/github/commit-activity/m/PaddlePaddle/FastDeploy?color=3af"></a>
<a href="https://pypi.org/project/FastDeploy-python/"><img src="https://img.shields.io/pypi/dm/FastDeploy-python?color=9cf"></a>
<a href="https://github.com/PaddlePaddle/FastDeploy/issues"><img src="https://img.shields.io/github/issues/PaddlePaddle/FastDeploy?color=9cc"></a>
<a href="https://github.com/PaddlePaddle/FastDeploy/stargazers"><img src="https://img.shields.io/github/stars/PaddlePaddle/FastDeploy?color=ccf"></a>
</p>
<h4 align="center">
<a href=#特性> 特性 </a> |
<a href=#SDK安装> 安装 </a> |
<a href=#SDK使用> 快速开始 </a> |
<a href=#社区交流> 社区交流 </a>
</h4>
**FastDeploy**是一款**简单易用**的推理部署工具箱。覆盖业界主流**优质预训练模型**并提供**开箱即用**的开发体验,包括图像分类、目标检测、图像分割、人脸检测、人体关键点识别、文字识别等多任务,满足开发者**多场景****多硬件**、**多平台**的快速部署需求。
## News 📢
* 🔥 2022.6.30 B站[飞桨直播课](https://space.bilibili.com/476867757)FastDeploy天使用户邀测沟通会与开发者共同讨论推理部署痛点问题。
* 🔥 2022.6.27 [**FastDeploy v0.1**](https://github.com/PaddlePaddle/FastDeploy/releases/tag/v0.1)邀测版发布!🎉
* 💎 第一批发布对于40个重点模型在8种重点软硬件环境的支持的SDK
* 😊 支持网页端、pip包两种下载使用方式
## 特性
### 📦开箱即用的推理部署工具链,支持云边端、多硬件、多平台部署
- 网页端点选下载、PIP 安装一行命令快速下载多种类型SDK安装包
- 云端(含服务器、数据中心):
- 支持一行命令启动 Serving 服务(含网页图形化展示)
- 支持一行命令启动图像、本地视频流、本地摄像头、网络视频流预测
- 支持 Window、Linux 操作系统
- 支持 Python、C++ 编程语言
- 边缘端:
- 支持 NVIDIA Jetson 等边缘设备,支持视频流预测服务
- 端侧(含移动端)
- 支持 iOS、Android 移动端
- 支持 ARM CPU 端侧设备
- 支持主流硬件
- 支持 Intel CPU 系列(含酷睿、至强等)
- 支持 ARM CPU 全系含高通、MTK、RK等
- 支持 NVIDIA GPU 全系(含 V100、T4、Jetson 等)
### 🤗丰富的预训练模型轻松下载SDK搞定推理部署
<font size=0.5>
|<font size=2> 模型| <font size=2> 任务 |<font size=2> 大小(MB) | <font size=2>端侧 | <font size=2>移动端 |<font size=2> 移动端 |<font size=2>边缘端 |<font size=2>服务器+云端 | <font size=2>服务器+云端 |<font size=2> 服务器+云端 |<font size=2> 服务器+云端 |
|---|---|---|---|---|---|---|---|---|---|---|
|----- | ---- |----- |<font size=2> Linux | <font size=2> Android |<font size=2> iOS | <font size=2> Linux |<font size=2> Linux |<font size=2> Linux |<font size=2> Windows |<font size=2> Windows |
|----- | ---- |--- | <font size=2> ARM CPU |<font size=2> ARM CPU | <font size=2> ARM CPU |<font size=2> Jetson |<font size=2> X86 CPU |<font size=2> GPU |<font size=2> X86 CPU |<font size=2> GPU |
| <font size=2> [PP-LCNet](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 11.9 |✅|✅|✅|✅|✅|✅|✅|✅|
| <font size=2> [PP-LCNetv2](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 26.6 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [EfficientNet](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication |31.4 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [GhostNet](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 20.8 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [MobileNetV1](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 17 |✅|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [MobileNetV2](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 14.2 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [MobileNetV3](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 22 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [ShuffleNetV2](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md)|Classfication | 9.2 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [SqueezeNetV1.1](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication |5 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [Inceptionv3](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication |95.5 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-HGNet](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 59 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [ResNet50_vd](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 102.5 |❌|❌|❌|✅|✅|✅|✅|✅|
|<font size=2> [SwinTransformer_224_win7](https://github.com/PaddlePaddle/PaddleClas/blob/release/2.3/docs/zh_CN/models_training/classification.md) |Classfication | 352.7 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-PicoDet_s_320_coco](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 4.1 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-PicoDet_s_320_lcnet](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 4.9 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [CenterNet](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection |4.8 |✅|✅|✅|✅ |✅ |✅|✅|✅|
|<font size=2> [YOLOv3_MobileNetV3](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 94.6 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-YOLO_tiny_650e_coco](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection |4.4 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [SSD_MobileNetV1_300_120e_voc](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 23.3 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [YOLOX_Nano_300e_coco](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 3.7 |❌|❌|❌|✅|✅ |✅|✅|✅|
|<font size=2> [PP-YOLO_ResNet50vd](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 188.5|✅ |✅ |✅ |✅ |✅ |✅|✅|✅|
|<font size=2> [PP-YOLOv2_ResNet50vd](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 218.7 |✅|✅|✅|✅|✅ |✅|✅|✅|
|<font size=2> [PP-YOLO_crn_l_300e_coco](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 209.1 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [YOLOv5s](https://github.com/Sharpiless/PaddleDetection-Yolov5) |Detection | 29.3|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [Faster R-CNN_r50_fpn_1x_coco](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Detection | 167.2 |❌|❌|❌|✅|✅|✅|✅|✅|
|<font size=2> [BlazeFace](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Face Detection |1.5|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [RetinaFace](https://github.com/GuoQuanhao/RetinaFace-Paddle) |Face Localisation |1.7| ✅|❌|❌|✅|✅|✅|✅|✅|
|<font size=2> [PP-TinyPose](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/docs/tutorials/GETTING_STARTED_cn.md) |Keypoint Detection| 5.5 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-LiteSeg(STDC1)](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/configs/pp_liteseg/README.md)|Segmentation | 32.2|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-HumanSeg-Lite](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/contrib/PP-HumanSeg/README_cn.md) |Segmentation | 0.556|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [HRNet-w18](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/docs/train/train_cn.md) |Segmentation | 38.7|✅|✅|✅|❌|✅|✅|✅|✅|
|<font size=2> [Mask R-CNN_r50_fpn_1x_coco](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/contrib/PP-HumanSeg/README_cn.md)|Segmentation| 107.2|❌|❌|❌|✅|✅|✅|✅|✅|
|<font size=2> [PP-HumanSeg-Server](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/contrib/PP-HumanSeg/README_cn.md)|Segmentation | 107.2|✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [Unet](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/docs/train/train_cn.md) |Segmentation | 53.7|❌|✅|❌|❌|✅|✅|✅|❌|
|<font size=2> [Deeplabv3-ResNet50](https://github.com/PaddlePaddle/PaddleSeg/blob/develop/docs/train/train_cn.md)|Segmentation |156.5|❌|❌|❌|❌|✅|✅|✅|✅|
|<font size=2> [PP-OCRv1](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.5/doc/doc_ch/ppocr_introduction.md) |OCR | 2.3+4.4 |✅|✅|✅|✅|✅|✅|✅|✅|
|<font size=2> [PP-OCRv2](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.5/doc/doc_ch/ppocr_introduction.md) |OCR | 2.3+4.4 |✅|✅|✅|✅|✅|✅|✅|✅|
| <font size=2> [PP-OCRv3](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.5/doc/doc_ch/PP-OCRv3_introduction.md) |OCR | 2.4+10.6 |✅|✅|✅|✅|✅|✅|✅|✅|
| <font size=2> [PP-OCRv3-tiny](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.5/doc/doc_ch/models_list.md) |OCR |2.4+10.7 |✅|✅|✅|✅|✅|✅|✅|✅|
</font>
## SDK安装
### 方式1网页版下载安装
- 可以登录[EasyEdge网页端](https://ai.baidu.com/easyedge/app/openSource)下载SDK
### 方式2pip安装
开发者可以通过pip安装`fastdeploy-python`来获取最新的下载链接
- 环境依赖
python >= 3.6
- 安装方式
```
pip install fastdeploy-python --upgrade
```
- 使用方式
- 列出FastDeploy当前支持的所有模型
```
fastdeploy --list_models
```
- 下载模型在具体平台和对应硬件上的部署SDK以及示例
```
fastdeploy --download_sdk \
--model PP-PicoDet-s_320 \
--platform Linux \
--soc x86-NVIDIA-GPU \
--save_dir .
```
- 参数说明
- `list_models`: 列出FastDeploy当前最新支持的所有模型
- `download_sdk`: 下载模型在具体平台和对应硬件上的部署SDK以及示例
- `model`: 模型名,如"PP-PicoDet-s_320",可通过`list_models`查看所有的可选项
- `platform`: 部署平台,支持 Windows/Linux/Android/iOS
- `soc`: 部署硬件支持Intel-x86_64/x86-NVIDIA-GPU/ARM/Jetson
- `save_dir`: SDK下载保存目录
## SDK使用
### 1 云+服务器部署
- Linux 系统(X86 CPU、NVIDIA GPU)
- [C++ Inference部署含视频流](./docs/Linux-CPP-SDK-Inference.md)
- [C++ 服务化部署](./docs/Linux-CPP-SDK-Serving.md)
- [Python Inference部署](./docs/Linux-Python-SDK-Inference.md)
- [Python 服务化部署](./docs/Linux-Python-SDK-Serving.md)
- Window系统(X86 CPU、NVIDIA GPU)
- [C++ Inference部署含视频流](./docs/Windows-CPP-SDK-Inference.md)
- [C++ 服务化部署](./docs/Windows-CPP-SDK-Serving.md)
- [Python Inference部署](./docs/Windows-Python-SDK-Inference.md)
- [Python 服务化部署](./docs/Windows-Python-SDK-Serving.md)
### 2 边缘侧部署
- ArmLinux 系统NVIDIA Jetson Nano/TX2/Xavier
- [C++ Inference部署含视频流](./docs/Jetson-Linux-CPP-SDK-Inference.md)
- [C++ 服务化部署](./docs/Jetson-Linux-CPP-SDK-Serving.md)
### 3 端侧部署
- ArmLinux 系统(ARM CPU)
- [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)
### 4 移动端部署
- [iOS 系统部署](./docs/iOS-SDK.md)
- [Android 系统部署](./docs/Android-SDK.md)
### 5 自定义模型部署
- [快速实现个性化模型替换](./docs/Replace-Model-With-Anther-One.md)
## 社区交流
- **加入社区👬:** 微信扫描二维码后,填写问卷加入交流群,与开发者共同讨论推理部署痛点问题
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854075-2c0f9997-ed18-4b17-9aaf-1b43266d3996.jpeg" width = "200" height = "200" />
</div>
## Acknowledge
本项目中SDK生成和下载使用了[EasyEdge](https://ai.baidu.com/easyedge/app/openSource)中的免费开放能力,再次表示感谢。
## License
FastDeploy遵循[Apache-2.0开源协议](./LICENSE)。

6
commit-prepare.sh Normal file
View File

@@ -0,0 +1,6 @@
path=$(cd `dirname $0`; pwd)
cd $path
pip install pre-commit
pip install yapf
pre-commit install

View File

@@ -0,0 +1,404 @@
# 简介
本文档介绍FastDeploy中的模型SDK在ARM Linux C++环境下 1推理部署步骤 2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中ARM Linux Python请参考[ARM Linux Python环境下的推理部署](./ARM-Linux-Python-SDK-Inference.md)文档。
**注意**部分模型如Tinypose、OCR等仅支持图像推理不支持视频推理。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. 硬件支持](#1-硬件支持)
* [2. 软件环境](#2-软件环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 预测图像](#21-预测图像)
* [2.2 预测视频流](#22-预测视频流)
* [预测API流程详解](#预测api流程详解)
* [1. SDK参数运行配置](#1-sdk参数运行配置)
* [2. 初始化Predictor](#2-初始化predictor)
* [3. 预测推理](#3-预测推理)
* [3.1 预测图像](#31-预测图像)
* [3.2 预测视频](#32-预测视频)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. 硬件支持
目前支持的ARM架构aarch64 、armv7hf
## 2. 软件环境
1.运行二进制文件-环境要求
* gcc: 5.4 以上 (GLIBCXX_3.4.22)
* Linux下查看gcc版本命名可能因系统差异命令会不同`gcc --version`
* Linux下C++基础库GLIBCXX的命令因系统差异库路径会有不同`strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX`
* glibc2.23以上
* Linux查看命令`ldd --version`
2.二次开发编译-环境要求
编译源代码时除gcc、GLIBCXX、glibc满足`1.运行二进制文件-环境要求`cmake需满足
* cmake: 3.0 以上
* Linux查看命令`cmake --version`
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下
```
.EasyEdge-Linux-m43157-b97741-x86
├── RES                 # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_ocr_linux_cpp_aarch64_ARM_gcc5.4_v1.5.1_20220530.tar.gz #armv8架构硬件的C++包,根据自己硬件,选择对应的压缩包解压即可
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
└── baidu_easyedge_ocr_linux_cpp_armv7l_armv7hf_ARM_gcc5.4_v1.5.1_20220530.tar.gz #armv7架构硬件的C++包,根据自己硬件,选择对应的压缩包解压即可
└── python # Python SDK 文件
```
**注意**
1. 【OCR需要编译】因为OCR任务的特殊性本次SDK没有提供bin文件夹可执行文件。开发者根据需要满足文档中gcc和cmake要求后`src/demo*`路径编译获取可执行文件,具体可参考。
2. 【OCR仅支持图像推理不支持视频流推理】
3. ARM-Linux-Python的环境要求和使用请参考[ARM Linux Python环境下的推理部署](./ARM-Linux-Python-SDK.md)文档。
## 2. 测试Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1 预测图像
```bash
./easyedge_image_inference {模型RES文件夹路径} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855351-68d1a4f0-6226-4484-b190-65f1ac2c7128.png" width="400"></div>
```bash
> ./easyedge_image_inference ../../../../RES 2.jpeg
2019-02-13 16:46:12,659 INFO [EasyEdge] [easyedge.cpp:34] 140606189016192 Baidu EasyEdge Linux Development Kit 0.2.1(20190213)
2019-02-13 16:46:14,083 INFO [EasyEdge] [paddlev2_edge_predictor.cpp:60] 140606189016192 Allocate graph success.
2019-02-13 16:46:14,326 DEBUG [EasyEdge] [paddlev2_edge_predictor.cpp:143] 140606189016192 Inference costs 168 ms
1, 1:txt_frame, p:0.994905 loc: 0.168161, 0.153654, 0.920856, 0.779621
Done
```
### 2.2 预测视频流
```
./easyedge_video_inference {模型RES文件夹路径} {video_type} {video_src_path}
```
其中 video_type 支持三种:
```
video_type : 1 // 本地视频文件
video_type : 2 // 摄像头的index
video_type : 3 // 网络视频流
```
video_src_path: 为 video_type 数值所对应的本地视频路径 、本地摄像头id、网络视频流地址
```
本地视频文件: ./easyedge_video_inference {模型RES文件夹路径} 1 /my_video_file.mp4
本地摄像头: ./easyedge_video_inference {模型RES文件夹路径} 2 1 #/dev/video1
网络视频流: ./easyedge_video_inference {模型RES文件夹路径} 3 rtmp://192.168.x.x:8733/live/src
```
注:以上路径是假模拟路径,开发者需要根据自己实际图像/视频,准备测试图像,并填写正确的测试路径。
# 预测API流程详解
本章节主要结合[2.测试Demo](#4)的Demo示例介绍推理API方便开发者学习后二次开发。更详细的API请参考`include/easyedge/easyedge*.h`文件。图像、视频的推理包含以下3个API如下代码片段`step`注释所示。
> ❗注意:<br>
> 1`src`文件夹中包含完整可编译的cmake工程实例建议开发者先行了解[cmake工程基本知识](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)。 <br>
> 2请优先参考SDK中自带的Demo工程的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
```cpp
// step 1: SDK配置运行参数
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
// step 2: 创建并初始化Predictor这这里选择合适的引擎
auto predictor = global_controller()->CreateEdgePredictor(config);
// step 3-1: 预测图像
auto img = cv::imread({图片路径});
std::vector<EdgeResultData> results;
predictor->infer(img, results);
// step 3-2: 预测视频
std::vector<EdgeResultData> results;
FrameTensor frame_tensor;
VideoConfig video_config;
video_config.source_type = static_cast<SourceType>(video_type); // source_type 定义参考头文件 easyedge_video.h
video_config.source_value = video_src;
/*
... more video_configs, 根据需要配置video_config的各选项
*/
auto video_decoding = CreateVideoDecoding(video_config);
while (video_decoding->next(frame_tensor) == EDGE_OK) {
results.clear();
if (frame_tensor.is_needed) {
predictor->infer(frame_tensor.frame, results);
render(frame_tensor.frame, results, predictor->model_info().kind);
}
//video_decoding->display(frame_tensor); // 显示当前frame需在video_config中开启配置
//video_decoding->save(frame_tensor); // 存储当前frame到视频需在video_config中开启配置
}
```
若需自定义library search path或者gcc路径修改对应Demo工程下的CMakeList.txt即可。
## 1. SDK参数运行配置
SDK的参数通过`EdgePredictorConfig::set_config``global_controller()->set_config`配置。本Demo 中设置了模型路径,其他参数保留默认参数。更详细的支持运行参数等,可以参考开发工具包中的头文件(`include/easyedge/easyedge_xxxx_config.h`)的详细说明。
配置参数使用方法如下:
```
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
```
## 2. 初始化Predictor
* 接口
```cpp
auto predictor = global_controller()->CreateEdgePredictor(config);
predictor->init();
```
若返回非0请查看输出日志排查错误原因。
## 3. 预测推理
### 3.1 预测图像
> 在Demo中展示了预测接口infer()传入cv::Mat& image图像内容并将推理结果赋值给std::vector<EdgeResultData>& result。更多关于infer()的使用,可以根据参考`easyedge.h`头文件中的实际情况、参数说明自行传入需要的内容做推理
* 接口输入
```cpp
/**
* @brief
* 通用接口
* @param image: must be BGR , HWC format (opencv default)
* @param result
* @return
*/
virtual int infer(cv::Mat& image, std::vector<EdgeResultData>& result) = 0;
```
图片的格式务必为opencv默认的BGR, HWC格式。
* 接口返回
`EdgeResultData`中可以获取对应的分类信息、位置信息。
```cpp
struct EdgeResultData {
int index; // 分类结果的index
std::string label; // 分类结果的label
float prob; // 置信度
// 物体检测 或 图像分割时使用:
float x1, y1, x2, y2; // (x1, y1): 左上角, x2, y2): 右下角; 均为0~1的长宽比例值。
// 图像分割时使用:
cv::Mat mask; // 0, 1 的mask
std::string mask_rle; // Run Length Encoding游程编码的mask
};
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
*** 关于图像分割mask_rle ***
该字段返回了mask的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析
### 3.2 预测视频
SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类`VideoDecoding`,此类提供了获取视频帧数据的便利函数。通过`VideoConfig`结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。
* 接口输入
class`VideoDecoding`
```
/**
* @brief 获取输入源的下一帧
* @param frame_tensor
* @return
*/
virtual int next(FrameTensor &frame_tensor) = 0;
/**
* @brief 显示当前frame_tensor中的视频帧
* @param frame_tensor
* @return
*/
virtual int display(const FrameTensor &frame_tensor) = 0;
/**
* @brief 将当前frame_tensor中的视频帧写为本地视频文件
* @param frame_tensor
* @return
*/
virtual int save(FrameTensor &frame_tensor) = 0;
/**
* @brief 获取视频的fps属性
* @return
*/
virtual int get_fps() = 0;
/**
* @brief 获取视频的width属性
* @return
*/
virtual int get_width() = 0;
/**
* @brief 获取视频的height属性
* @return
*/
virtual int get_height() = 0;
```
struct `VideoConfig`
```
/**
* @brief 视频源、抽帧策略、存储策略的设置选项
*/
struct VideoConfig {
SourceType source_type; // 输入源类型
std::string source_value; // 输入源地址如视频文件路径、摄像头index、网络流地址
int skip_frames{0}; // 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true
int retrieve_all{false}; // 是否抽取所有frame以便于作为显示和存储对于不满足skip_frames策略的frame把所抽取帧的is_needed置为false
int input_fps{0}; // 在采取抽帧之前设置视频的fps
Resolution resolution{Resolution::kAuto}; // 采样分辨率只对camera有效
bool enable_display{false}; // 默认不支持。
std::string window_name{"EasyEdge"};
bool display_all{false}; // 是否显示所有frame若为false仅显示根据skip_frames抽取的frame
bool enable_save{false};
std::string save_path; // frame存储为视频文件的路径
bool save_all{false}; // 是否存储所有frame若为false仅存储根据skip_frames抽取的frame
std::map<std::string, std::string> conf;
};
```
| 序号 | 字段 | 含义 |
| --- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `source_type` | 输入源类型支持视频文件、摄像头、网络视频流三种值分别为1、2、3 |
| 2 | `source_value` | 若`source_type`为视频文件,该值为指向视频文件的完整路径;若`source_type`为摄像头该值为摄像头的index如对于`/dev/video0`的摄像头则index为0若`source_type`为网络视频流,则为该视频流的完整地址。 |
| 3 | `skip_frames` | 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true标记为is_needed的帧是用来做预测的帧。反之直接跳过该帧不经过预测。 |
| 4 | `retrieve_all` | 若置该项为true则无论是否设置跳帧所有的帧都会被抽取返回以作为显示或存储用。 |
| 5 | `input_fps` | 用于抽帧前设置fps |
| 6 | `resolution` | 设置摄像头采样的分辨率,其值请参考`easyedge_video.h`中的定义,注意该分辨率调整仅对输入源为摄像头时有效 |
| 7 | `conf` | 高级选项。部分配置会通过该map来设置 |
*** 注意:***
1. `VideoConfig`不支持`display`功能。如果需要使用`VideoConfig`的`display`功能需要自行编译带有GTK选项的OpenCV。
2. 使用摄像头抽帧时,如果通过`resolution`设置了分辨率调整,但是不起作用,请添加如下选项:
```
video_config.conf["backend"] = "2";
```
3. 部分设备上的CSI摄像头尚未兼容如遇到问题可以通过工单、QQ交流群或微信交流群反馈。
具体接口调用流程可以参考SDK中的`demo_video_inference`。
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
3. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,318 @@
# 简介
本文档介绍FastDeploy中的模型SDK在ARM Linux C++环境下1服务化推理部署步骤2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中ARM Linux Python请参考[ARM Linux Python环境下的HTTP推理部署](./ARM-Linux-Python-SDK-Serving.md)文档。
**注意**部分模型如OCR等不支持服务化推理。
<!--ts-->
* [简介](#简介)
* [安装准备](#安装准备)
* [1. 硬件支持](#1-硬件支持)
* [2. 软件环境](#2-软件环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试 HTTP Demo](#2-测试-http-demo)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式一:不使用图片base64格式](#21-http-请求方式一不使用图片base64格式)
* [2.2 http 请求方法二:使用图片base64格式](#22-http-请求方法二使用图片base64格式)
* [3. http返回数据](#3-http返回数据)
* [FAQ](#faq)
<!--te-->
# 安装准备
## 1. 硬件支持
目前支持的ARM架构aarch64 、armv7hf
## 2. 软件环境
1.运行二进制文件-环境要求
* gcc: 5.4 以上 (GLIBCXX_3.4.22)
* Linux下查看gcc版本命名可能因系统差异命令会不同`gcc --version`
* Linux下C++基础库GLIBCXX的命令可能因系统差异路径会有不同可检测自己环境下的情况`strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX`
* glibc2.23以上
* Linux查看命令`ldd --version`
2.二次开发编译-环境要求
编译源代码时除了gcc、GLIBCXX、glibc满足`1.运行二进制文件-环境要求`还需要cmake满足要求。
* cmake: 3.0 以上
* Linux查看命令`cmake --version`
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压后SDK目录结构如下
```
.EasyEdge-Linux-m43157-b97741-x86
├── RES                 # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp                 # C++ SDK 文件结构
└── baidu_easyedge_linux_cpp_x86_64_CPU.Generic_gcc5.4_v1.4.0_20220325.tar.gz
├── bin         # 可直接运行的二进制文件
├── include     # 二次开发用的头文件
├── lib         # 二次开发用的所依赖的库
├── src         # 二次开发用的示例工程
└── thirdparty  # 第三方依赖
└── python # Python SDK 文件
```
## 2. 测试 HTTP Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1 启动HTTP预测服务
```
./easyedge_serving {模型RES文件夹路径}
```
启动后日志中会显示如下设备IP和24401端口号信息
```
HTTP is now serving at 0.0.0.0:24401
```
此时,开发者可以打开浏览器,输入链接地址`http://0.0.0.0:24401`(这里的`设备IP和24401端口号`根据开发者电脑显示修改),选择图片来进行测试。
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855495-cd8d46ec-2492-4297-b3e4-2bda4cd6727c.png" width="600"></div>
同时可以调用HTTP接口来访问服务具体参考下文的[二次开发](#10)接口说明。
# HTTP API流程详解
本章节主要结合[2.1 HTTP Demo]()的API介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。http服务包含服务端和客户端目前支持的能力包括以下几种方式Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动可直接使用`bin/easyedge_serving`,或参考`src/demo_serving.cpp`文件修改相关逻辑
```cpp
/**
* @brief 开启一个简单的demo http服务。
* 该方法会block直到收到sigint/sigterm。
* http服务里图片的解码运行在cpu之上可能会降低推理速度。
* @tparam ConfigT
* @param config
* @param host
* @param port
* @param service_id service_id user parameter, uri '/get/service_id' will respond this value with 'text/plain'
* @param instance_num 实例数量,根据内存/显存/时延要求调整
* @return
*/
template<typename ConfigT>
int start_http_server(
const ConfigT &config,
const std::string &host,
int port,
const std::string &service_id,
int instance_num = 1);
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式一:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容(无需base64, 无需json)
Python请求示例
```Python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
### 2.2 http 请求方法二:使用图片base64格式
HTTP方法POST
Header如下
| 参数 | 值 |
| ------------ | ---------------- |
| Content-Type | application/json |
**Body请求填写**
* 分类网络:
body 中请求示例
```
{
"image": "<base64数据>"
"top_num": 5
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| ------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| top_num | 否 | number | - | 返回分类数量,不填该参数,则默认返回全部分类结果 |
* 检测和分割网络:
Body请求示例
```
{
"image": "<base64数据>"
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| --------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| threshold | 否 | number | - | 默认为推荐阈值,也可自行根据需要进行设置 |
Python请求示例
```Python
import base64
import requests
def main():
with open("图像路径", 'rb') as f:
result = requests.post("http://{服务ip地址}:24401/", json={
"image": base64.b64encode(f.read()).decode("utf8")
})
# print(result.request.body)
# print(result.request.headers)
print(result.content)
if __name__ == '__main__':
main()
```
## 3. http返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 使用libcurl请求http服务时速度明显变慢
这是因为libcurl请求continue导致server等待数据的问题添加空的header即可
```bash
headers = curl_slist_append(headers, "Expect:");
```
3. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
4. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,371 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例介绍FastDeploy中的模型SDK 在**ARM Linux Python** 环境下:1)图像推理部署步骤; 2介绍模型推流全流程API方便开发者了解项目后二次开发。其中ARM Linux C++请参考[ARM Linux C++环境下的推理部署](./ARM-Linux-CPP-SDK-Inference.md)文档。
**注意**部分模型如Tinypose、OCR等仅支持图像推理不支持视频推理。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1.SDK下载](#1sdk下载)
* [2.硬件支持](#2硬件支持)
* [3.python环境](#3python环境)
* [4.安装依赖](#4安装依赖)
* [4.1.安装paddlepaddle](#41安装paddlepaddle)
* [4.2.安装EasyEdge Python Wheel 包](#42安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1.文件结构说明](#1文件结构说明)
* [2.测试Demo](#2测试demo)
* [2.1预测图像](#21预测图像)
* [Demo API介绍](#demo-api介绍)
* [1.基础流程](#1基础流程)
* [2.初始化](#2初始化)
* [3.SDK参数配置](#3sdk参数配置)
* [4.预测图像](#4预测图像)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1.SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。
```shell
EasyEdge-Linux-x86--[部署芯片]
├──...
├──python # Linux Python SDK
├── # 特定Python版本的EasyEdge Wheel包, 二次开发可使用
├── BaiduAI_EasyEdge_SDK-1.3.1-cp36-cp36m-linux_aarch64.whl
├── infer_demo # demo体验完整文件
│ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ └── demo_serving.py # 提供http服务的demo文件
├── tensor_demo # 学习自定义算法前后处理时使用
│ └── demo_xxx.py
```
## 2.硬件支持
目前支持的ARM架构aarch64 、armv7hf
## 3.python环境
> ARM Linux SDK仅支持Python 3.6
使用如下命令获取已安装的Python版本号。如果本机的版本不匹配建议使用[pyenv](https://github.com/pyenv/pyenv)、[anaconda](https://www.anaconda.com/)等Python版本管理工具对SDK所在目录进行配置。
```shell
$python3 --version
```
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
$python3 -m pip --version
```
## 4.安装依赖
### 4.1.安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。
`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install http://aipe-easyedge-public.bj.bcebos.com/easydeploy/paddlelite-2.11-cp36-cp36m-linux_aarch64.whl
```
### 4.2.安装EasyEdge Python Wheel 包
`python`目录下安装特定Python版本的EasyEdge Wheel包。`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-1.3.1-cp36-cp36m-linux_aarch64.whl
```
# 快速开始
## 1.文件结构说明
Python SDK文件结构如下
```shell
.EasyEdge-Linux-x86--[部署芯片]
├── RES # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json # Android、iOS系统APP名字需要
│ ├── label_list.txt # 模型标签文件
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ └── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── python # Python SDK 文件
├── BaiduAI_EasyEdge_SDK-1.3.1-cp36-cp36m-linux_aarch64.whl #EasyEdge Python Wheel 包
├── infer_demo
├── demo_armv8_cpu.py # 图像推理
├── demo_serving.py # HTTP服务化推理
└── tensor_demo # 学习自定义算法前后处理时使用
├── demo_armv8_cpu.py
```
## 2.测试Demo
> 模型资源文件默认已经打包在开发者下载的SDK包中 默认为`RES`目录。
### 2.1预测图像
使用infer_demo文件夹下的demo文件。
```bash
python3 demo_x86_cpu.py {模型RES文件夹} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854068-28d27c0a-ef83-43ee-9e89-b65eed99b476.jpg" width="300"></div>
```shell
2022-06-14 14:40:16 INFO [EasyEdge] [demo_nvidia_gpu.py:38] 140518522509120: Init paddlefluid engine...
2022-06-14 14:40:20 INFO [EasyEdge] [demo_nvidia_gpu.py:38] 140518522509120: Paddle version: 2.2.2
{'confidence': 0.9012349843978882, 'index': 8, 'label': 'n01514859 hen'}
```
可以看到,运行结果为`index8labelhen`通过imagenet [类别映射表](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),可以找到对应的类别,即 'hen',由此说明我们的预测结果正确。
# Demo API介绍
本章节主要结合[测试Demo](#2测试Demo)的Demo示例介绍推理API方便开发者学习后二次开发。
## 1.基础流程
> ❗注意请优先参考SDK中自带demo的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
`infer_demo/demo_xx_xx.py`
```python
# 引入EasyEdge运行库
import BaiduAI.EasyEdge as edge
# 创建并初始化一个预测Progam选择合适的引擎
pred = edge.Program()
pred.init(model_dir={RES文件夹路径}, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
# 预测图像
res = pred.infer_image({numpy.ndarray的图片})
# 关闭结束预测Progam
pred.close()
```
`infer_demo/demo_serving.py`
```python
import BaiduAI.EasyEdge as edge
from BaiduAI.EasyEdge.serving import Serving
# 创建并初始化Http服务
server = Serving(model_dir={RES文件夹路径}, license=serial_key)
# 运行Http服务
# 请参考同级目录下demo_xx_xx.py里:
# pred.init(model_dir=xx, device=xx, engine=xx, device_id=xx)
# 对以下参数device\device_id和engine进行修改
server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# server.run(host=host, port=port, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
```
## 2.初始化
* 接口
```python
def init(self,
model_dir,
device=Device.CPU,
engine=Engine.PADDLE_FLUID,
config_file='conf.json',
preprocess_file='preprocess_args.json',
model_file='model',
params_file='params',
label_file='label_list.txt',
infer_cfg_file='infer_cfg.json',
device_id=0,
thread_num=1
):
"""
Args:
model_dir: str
device: BaiduAI.EasyEdge.Device比如Device.CPU
engine: BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID
config_file: str
preprocess_file: str
model_file: str
params_file: str
label_file: str 标签文件
infer_cfg_file: 包含预处理、后处理信息的文件
device_id: int 设备ID
thread_num: int CPU的线程数
Raises:
RuntimeError, IOError
Returns:
bool: True if success
"""
```
若返回不是True请查看输出日志排查错误原因。
## 3.SDK参数配置
使用 CPU 预测时,可以通过在 init 中设置 thread_num 使用多线程预测。如:
```python
pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID, thread_num=4)
```
使用 GPU 预测时,可以通过在 init 中设置 device_id 指定需要的GPU device id。如
```python
pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID, device_id=0)
```
## 4.预测图像
* 接口
```python
def infer_image(self, img,
threshold=0.3,
channel_order='HWC',
color_format='BGR',
data_type='numpy'):
"""
Args:
img: np.ndarray or bytes
threshold: float
only return result with confidence larger than threshold
channel_order: string
channel order HWC or CHW
color_format: string
color format order RGB or BGR
data_type: string
仅在图像分割时有意义。 'numpy' or 'string'
'numpy': 返回已解析的mask
'string': 返回未解析的mask游程编码
Returns:
list
"""
```
* 返回格式: `[dict1, dict2, ...]`
| 字段 | 类型 | 取值 | 说明 |
| ---------- | -------------------- | --------- | ------------------------ |
| confidence | float | 0~1 | 分类或检测的置信度 |
| label | string | | 分类或检测的类别 |
| index | number | | 分类或检测的类别 |
| x1, y1 | float | 0~1 | 物体检测,矩形的左上角坐标 (相对长宽的比例值) |
| x2, y2 | float | 0~1 | 物体检测,矩形的右下角坐标(相对长宽的比例值) |
| mask | string/numpy.ndarray | 图像分割的mask | |
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
可以参考 demo 文件中使用 opencv 绘制矩形的逻辑。
***结果示例***
i) 图像分类
```json
{
"index": 736,
"label": "table",
"confidence": 0.9
}
```
ii) 物体检测
```json
{
"index": 8,
"label": "cat",
"confidence": 1.0,
"x1": 0.21289,
"y1": 0.12671,
"x2": 0.91504,
"y2": 0.91211,
}
```
iii) 图像分割
```json
{
"name": "cat",
"score": 1.0,
"location": {
"left": ...,
"top": ...,
"width": ...,
"height": ...,
},
"mask": ...
}
```
mask字段中data_type为`numpy`时,返回图像掩码的二维数组
```
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
data_type为`string`时mask的游程编码解析方式可参考 [demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
# FAQ
1.执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,266 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例介绍FastDeploy中的模型SDK 在**ARM Linux Python** 环境下: 1)**服务化**推理部署步骤; 2介绍模型推流全流程API方便开发者了解项目后二次开发。其中ARM Linux Python请参考[ARM Linux C++环境下的HTTP推理部署](./ARM-Linux-CPP-SDK-Serving.md)文档。
**注意**部分模型如OCR等不支持服务化推理。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1.SDK下载](#1sdk下载)
* [2.硬件支持](#2硬件支持)
* [3.Python环境](#3python环境)
* [4.安装依赖](#4安装依赖)
* [4.1.安装paddlepaddle](#41安装paddlepaddle)
* [4.2.安装EasyEdge Python Wheel 包](#42安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1.文件结构说明](#1文件结构说明)
* [2.测试Serving服务](#2测试serving服务)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式不使用图片base64格式](#21-http-请求方式不使用图片base64格式)
* [3. http返回数据](#3-http返回数据)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1.SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压缩后的文件结构如下。
```shell
EasyEdge-Linux-x86-[部署芯片]
├── RES # 模型文件资源文件夹,可替换为其他模型
├── README.md
├── cpp # C++ SDK
└── python # Python SDK
```
## 2.硬件支持
目前支持的ARM架构aarch64 、armv7hf
## 3.Python环境
> ARM Linux SDK仅支持Python 3.6
使用如下命令获取已安装的Python版本号。如果本机的版本不匹配需要根据ARM Linux下Python安装方式进行安装。不建议在ARM Linux下使用conda因为ARM Linux场景通常资源很有限
```shell
$python3 --version
```
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
$python3 -m pip --version
```
## 4.安装依赖
### 4.1.安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。
`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install http://aipe-easyedge-public.bj.bcebos.com/easydeploy/paddlelite-2.11-cp36-cp36m-linux_aarch64.whl
```
### 4.2.安装EasyEdge Python Wheel 包
`python`目录下安装特定Python版本的EasyEdge Wheel包。`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-1.3.1-cp36-cp36m-linux_aarch64.whl
```
# 二.快速开始
## 1.文件结构说明
Python SDK文件结构如下
```shell
EasyEdge-Linux-x86--[部署芯片]
├──...
├──python # Linux Python SDK
├── # 特定Python版本的EasyEdge Wheel包, 二次开发可使用
├── BBaiduAI_EasyEdge_SDK-1.3.1-cp36-cp36m-linux_aarch64.whl
├── infer_demo # demo体验完整文件
│ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ └── demo_serving.py # 提供http服务的demo文件
├── tensor_demo # 学习自定义算法前后处理时使用
│ └── demo_xxx.py
```
## 2.测试Serving服务
> 模型资源文件默认已经打包在开发者下载的SDK包中 默认为`RES`目录。
### 2.1 启动HTTP预测服务
指定对应的模型文件夹(默认为`RES`、设备ip和指定端口号运行如下命令。
```shell
python3 demo_serving.py {模型RES文件夹} {host, default 0.0.0.0} {port, default 24401}
```
成功启动后,终端中会显示如下字样。
```shell
...
* Running on {host ip}:24401
```
如果是在局域网内的机器上部署,开发者此时可以打开浏览器,输入`http://{host ip}:24401`,选择图片来进行测试,运行效果如下。
<img src="https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png" style="zoom:50%;" />
如果是在远程机器上部署,那么可以参考`demo_serving.py`中的 `http_client_test()函数`请求http服务来执行推理。
# 三. HTTP API流程详解
## 1. 开启http服务
http服务的启动使用`demo_serving.py`文件
```python
class Serving(object):
"""
SDK local serving
"""
def __init__(self, model_dir, license='', model_filename='model', params_filename='params'):
self.program = None
self.model_dir = model_dir
self.model_filename = model_filename
self.params_filename = params_filename
self.program_lock = threading.Lock()
self.license_key = license
# 只有ObjectTracking会初始化video_processor
self.video_processor = None
def run(self, host, port, device, engine=Engine.PADDLE_FLUID, service_id=0, device_id=0, **kwargs):
"""
Args:
host : str
port : str
device : BaiduAI.EasyEdge.Device比如Device.CPU
engine : BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID
"""
self.run_serving_with_flask(host, port, device, engine, service_id, device_id, **kwargs)
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容
Python请求示例
```python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
## 3. http返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
# FAQ
1.执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

404
docs/Android-SDK.md Normal file
View File

@@ -0,0 +1,404 @@
# 简介
本文档介绍FastDeploy中的模型SDK在Android环境下1推理操作步骤2介绍模型SDK使用说明方便开发者了解项目后二次开发。
<!--ts-->
* [简介](#简介)
* [系统支持说明](#系统支持说明)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. APP 标准版测试](#2-app-标准版测试)
* [2.1 扫码体验](#21-扫码体验)
* [2.2 源码运行](#22-源码运行)
* [3. 精简版测试](#3-精简版测试)
* [SDK使用说明](#sdk使用说明)
* [1. 集成指南](#1-集成指南)
* [1.1 依赖库集成](#11-依赖库集成)
* [1.2 添加权限](#12-添加权限)
* [1.3 混淆规则(可选)](#13-混淆规则可选)
* [2. API调用流程示例](#2-api调用流程示例)
* [2.1 初始化](#21-初始化)
* [2.2 预测图像](#22-预测图像)
* [错误码](#错误码)
<!--te-->
# 系统支持说明
1. Android 版本支持范围Android 5.0API21<= Android < Android 10API 29)。
2. 硬件支持情况支持 arm64-v8a armeabi-v7a暂不支持模拟器
* 官网测试机型红米k30Vivo v1981a华为oxp-an00华为cdy-an90华为pct-al10荣耀yal-al00OPPO Reno5 Pro 5G
3. 其他说明
* 图像分割类算法】(1图像分割类算法暂未提供实时摄像头推理功能开发者可根据自己需要进行安卓开发2PP-Humanseg-Lite模型设计初衷为横屏视频会议等场景本次安卓SDK仅支持竖屏场景开发者可根据自己需要开发横屏功能
* OCR模型OCR任务第一次启动任务第一张推理时间久属于正常情况因为涉及到模型加载预处理等工作)。
> 预测图像时运行内存不能过小一般大于模型资源文件夹大小的3倍。
# 快速开始
## 1. 项目结构说明
根据开发者模型部署芯片操作系统需要在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载SDK目录结构如下
```
.EasyEdge-Android-SDK
├── app
│ ├── src/main
│ │ ├── assets
│ │ │ ├── demo
│ │ │ │ └── conf.json # APP名字
│ │ │ ├── infer # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ │ │ │ ├── model # 模型结构文件
│ │ │ │ ├── params # 模型参数文件
│ │ │ │ ├── label_list.txt # 模型标签文件
│ │ │ │ └── infer_cfg.json # 模型前后处理等配置文件
│ │ ├── java/com.baidu.ai.edge/demo
│ │ │ ├── infertest # 通用ARM精简版测试
│ │ │ │ ├── TestInferClassifyTask.java # 图像分类
│ │ │ │ ├── TestInferDetectionTask.java # 物体检测
│ │ │ │ ├── TestInferSegmentTask.java # 实例分割
│ │ │ │ ├── TestInferPoseTask.java # 姿态估计
│ │ │ │ ├── TestInferOcrTask.java # OCR
│ │ │ │ └── MainActivity.java # 精简版启动 Activity
│ │ │ ├── MainActivity.java # Demo APP 启动 Activity
│ │ │ ├── CameraActivity.java # 摄像头UI逻辑
│ │ │ └── ...
│ │ └── ...
│ ├── libs
│ │ ├── armeabi-v7a # v7a的依赖库
│ │ ├── arm64-v8a # v8a的依赖库
│ │ └── easyedge-sdk.jar # jar文件
│ └── ...
├── camera_ui # UI模块包含相机逻辑
├── README.md
└── ... # 其他 gradle 等工程文件
```
## 2. APP 标准版测试
考虑部分Android开发板没有摄像头因此本项目开发了标准版和精简版两种标准版会调用Android系统的摄像头采集摄像头来进行AI模型推理精简版在没有摄像头的开发板上运行需要开发者准备图像开发者根据硬件情况选择对应的版本
### 2.1 扫码体验
扫描二维码二维码见下载网页`体验Demo`无需任何依赖手机上下载即可直接体验
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854064-a31755d1-52b9-416d-b35d-885b7338a6cc.png" width="600"></div>
### 2.2 源码运行
1下载对应的SDK解压工程。</br>
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854071-f4c17de8-83c2-434e-882d-c175f4202a2d.png" width="600"></div>
2打开Android Studio 点击 "Import Project..."File->New-> "Import Project...", 选择解压后的目录。</br>
3手机链接Android Studio并打开开发者模式。不了解开发者模式的开发者可浏览器搜索</br>
4此时点击运行按钮手机上会有新app安装完毕运行效果和二维码扫描的一样。</br>
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854049-988414c7-116a-4261-a0c7-2705cc199538.png" width="400"></div>
## 3. 精简版测试
* 考虑部分Android开发板没有摄像头本项目提供了精简版本精简版忽略摄像头等UI逻辑可兼容如无摄像头的开发板测试。
* 精简版对应的测试图像路径,在代码`src/main/java/com.baidu.ai.edge/demo/TestInfer*.java`中进行了设置开发者可以准备图像到对应路径测试也可以修改java代码测试。
* 支持以下硬件环境的精简版测试通用ARM图像分类、物体检测、实例分割、姿态估计、文字识别。
示例代码位于 app 模块下 infertest 目录,修改 app/src/main/AndroidManifest.xml 中的启动 Activity 开启测试。
修改前:
```
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
infertest.MainActivity
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".CameraActivity"
android:screenOrientation="portrait" >
</activity>
```
修改后:
```
<!-- 以通用ARM为例 -->
<activity android:name=".infertest.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
```
注意:修改后,因为没有测试数据,需要开发者准备一张测试图像,放到 `app/src/main/asserts/` 路径下,并按照`app/src/main/java/com/baidu/ai/edge/demo/infertest/TestInfer*.java`中的图像命名要求对图像进行命名。
<div align="center">
| Demo APP 检测模型运行示例 | 精简版检测模型运行示例 |
| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| ![Demo APP](https://user-images.githubusercontent.com/54695910/175855181-595fd449-7351-4ec6-a3b8-68c021b152f6.jpeg) | ![精简版](https://user-images.githubusercontent.com/54695910/175855176-075f0c8a-b05d-4d60-a2a1-3f0204c6386e.jpeg) |
</div>
# SDK使用说明
本节介绍如何将 SDK 接入开发者的项目中使用。
## 1. 集成指南
步骤一:依赖库集成
步骤二:添加必要权限
步骤三:混淆配置(可选)
### 1.1 依赖库集成
A. 项目中未集成其他 jar 包和 so 文件:
```
// 1. 复制 app/libs 至项目的 app/libs 目录
// 2. 参考 app/build.gradle 配置 NDK 可用架构和 so 依赖库目录
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
```
B. 项目中已集成其他 jar 包,未集成 so 文件:
```
// 1. 复制 app/libs/easyedge-sdk.jar 与其他 jar 包同目录
// 2. 复制 app/libs 下 armeabi-v7a 和 arm64-v8a 目录至 app/src/main/jniLibs 目录下
// 3. 参考 app/build.gradle 配置 NDK 可用架构
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
```
C. 项目中已集成其他 jar 包和 so 文件:
```
// 1. 复制 app/libs/easyedge-sdk.jar 与其他 jar 包同目录
// 2. 融合 app/libs 下 armeabi-v7a 和 arm64-v8a 下的 so 文件与其他同架构 so 文件同目录
// 3. 参考 app/build.gradle 配置 NDK 可用架构
android {
...
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a' // 只支持 v7a 和 v8a 两种架构,有其他架构需删除
}
}
}
```
### 1.2 添加权限
参考 app/src/main/AndroidManifest.xml 中配置的权限。
```
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
```
### 1.3 混淆规则(可选)
请不要混淆 jar 包文件,参考 app/proguard-rules.pro 配置。
```
-keep class com.baidu.ai.edge.core.*.*{ *; }
```
## 2. API调用流程示例
以通用ARM的图像分类预测流程为例详细说明请参考后续章节
```
try {
// step 1-1: 准备配置类
InferConfig config = new InferConfig(context.getAssets(), "infer");
// step 1-2: 准备预测 Manager
InferManager manager = new InferManager(context, config, "");
// step 2-1: 准备待预测的图像,必须为 Bitmap.Config.ARGB_8888 格式,一般为默认格式
Bitmap image = getFromSomeWhere();
// step 2-2: 预测图像
List<ClassificationResultModel> results = manager.classify(image, 0.3f);
// step 3: 解析结果
for (ClassificationResultModel resultModel : results) {
Log.i(TAG, "labelIndex=" + resultModel.getLabelIndex()
+ ", labelName=" + resultModel.getLabel()
+ ", confidence=" + resultModel.getConfidence());
}
// step 4: 释放资源。预测完毕请及时释放资源
manager.destroy();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
```
### 2.1 初始化
**准备配置类**
芯片与配置类对应关系:
- 通用ARMInferConfig
```
// 示例
// 参数二为芯片对应的模型资源文件夹名称
InferConfig config = new InferConfig(context.getAssets(), "infer");
```
**准备预测 Manager**
芯片与 Manager 对应关系:
- 通用ARMInferManager
```
// 示例
// 参数二为配置类对象
// 参数三保持空字符串即可
InferManager manager = new InferManager(context, config, "");
```
> **注意**
>
> 1. 同一时刻只能有且唯一有效的 Manager若要新建一个 Manager之前创建的 Manager 需先调用 destroy() 销毁;
> 2. Manager 的任何方法都不能在 UI 线程调用;
> 3. Manager 的任何成员变量及方法由于线程同步问题,都必须在同一个线程中执行;
### 2.2 预测图像
本节介绍各种模型类型的预测函数及结果解析。
> **注意**
> 预测函数可以多次调用,但必须在同一个线程中,不支持并发
> 预测函数中的 confidence 非必需,默认使用模型推荐值。填 0 可返回所有结果
> 待预测的图像必须为 Bitmap.Config.ARGB_8888 格式的 Bitmap
**图像分类**
```
// 预测函数
List<ClassificationResultModel> classify(Bitmap bitmap) throws BaseException;
List<ClassificationResultModel> classify(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
ClassificationResultModel
- label: 分类标签定义在label_list.txt中
- labelIndex: 分类标签对应的序号
- confidence: 置信度0-1
```
**物体检测**
```
// 预测函数
List<DetectionResultModel> detect(Bitmap bitmap) throws BaseException;
List<DetectionResultModel> detect(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
DetectionResultModel
- label: 标签定义在label_list.txt中
- confidence: 置信度0-1
- bounds: Rect包含左上角和右下角坐标指示物体在图像中的位置
```
**实例分割**
```
// 预测函数
List<SegmentationResultModel> segment(Bitmap bitmap) throws BaseException;
List<SegmentationResultModel> segment(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
SegmentationResultModel
- label: 标签定义在label_list.txt中
- confidence: 置信度0-1
- lableIndex: 标签对应的序号
- box: Rect指示物体在图像中的位置
- mask: byte[]表示原图大小的01掩码绘制1的像素即可得到当前对象区域
- maskLEcode: mask的游程编码
```
> 关于 maskLEcode 的解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
**姿态估计**
```
// 预测函数
List<PoseResultModel> pose(Bitmap bitmap) throws BaseException;
// 返回结果
PoseResultModel
- label: 标签定义在label_list.txt中
- confidence: 置信度0-1
- points: Pair<Point, Point>, 2个点构成一条线
```
**文字识别**
```
// 预测函数
List<OcrResultModel> ocr(Bitmap bitmap) throws BaseException;
List<OcrResultModel> ocr(Bitmap bitmap, float confidence) throws BaseException;
// 返回结果
OcrResultModel
- label: 识别出的文字
- confidence: 置信度0-1
- points: List<Point>, 文字所在区域的点位
```
# 错误码
| 错误码 | 错误描述 | 详细描述及解决方法 |
| ---- | ------------------------------ | ------------------------------------------------------------------------------------ |
| 1001 | assets 目录下用户指定的配置文件不存在 | SDK可以使用assets目录下config.json作为配置文件。如果传入的config.json不在assets目录下则有此报错 |
| 1002 | 用户传入的配置文件作为json解析格式不准确如缺少某些字段 | 正常情况下demo中的config.json不要修改 |
| 19xx | Sdk内部错误 | 请与百度人员联系 |
| 2001 | XxxxMANAGER 只允许一个实例 | 如已有XxxxMANAGER对象请调用destory方法 |
| 2002 | XxxxMANAGER 已经调用过destory方法 | 在一个已经调用destory方法的DETECT_MANAGER对象上不允许再调用任何方法 |
| 2003 | 传入的assets下模型文件路径为null | XxxxConfig.getModelFileAssetPath() 返回为null。由setModelFileAssetPath(null导致 |
| 2011 | libedge-xxxx.so 加载失败 | System.loadLibrary("edge-xxxx"); libedge-xxxx.so 没有在apk中。CPU架构仅支持armeabi-v7a arm-v8a |
| 2012 | JNI内存错误 | heap的内存不够 |
| 2103 | license过期 | license失效或者系统时间有异常 |
| 2601 | assets 目录下模型文件打开失败 | 请根据报错信息检查模型文件是否存在 |
| 2611 | 检测图片时,传递至引擎的图片二进制与长宽不符合 | 具体见报错信息 |
| 27xx | Sdk内部错误 | 请与百度人员联系 |
| 28xx | 引擎内部错误 | 请与百度人员联系 |
| 29xx | Sdk内部错误 | 请与百度人员联系 |
| 3000 | so加载错误 | 请确认所有so文件存在于apk中 |
| 3001 | 模型加载错误 | 请确认模型放置于能被加载到的合法路径中并确保config.json配置正确 |
| 3002 | 模型卸载错误 | 请与百度人员联系 |
| 3003 | 调用模型错误 | 在模型未加载正确或者so库未加载正确的情况下调用了分类接口 |
| 50xx | 在线模式调用异常 | 请与百度人员联系 |

View File

@@ -0,0 +1,382 @@
# 简介
本文档介绍FastDeploy中的模型SDK 在**Jetson Linux C++** 环境下1 图像和视频 推理部署步骤, 2介绍推理全流程API方便开发者了解项目后二次开发。如果开发者对Jetson的服务化部署感兴趣可以参考[Jetson CPP Serving](./Jetson-Linux-CPP-SDK-Serving.md)文档。
**注意**OCR目前只支持**图像**推理部署。
<!--ts-->
* [简介](#简介)
* [环境要求](#环境要求)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 预测图像](#21-预测图像)
* [2.2 预测视频流](#22-预测视频流)
* [预测API流程详解](#预测api流程详解)
* [1. SDK参数运行配置](#1-sdk参数运行配置)
* [2. 初始化Predictor](#2-初始化predictor)
* [3. 预测推理](#3-预测推理)
* [3.1 预测图像](#31-预测图像)
* [3.2 预测视频](#32-预测视频)
* [FAQ](#faq)
<!--te-->
# 环境要求
* Jetpack: 4.6安装Jetpack参考[NVIDIA 官网-Jetpack4.6安装指南](https://developer.nvidia.com/jetpack-sdk-46),或者参考采购的硬件厂商提供的安装方式进行安装。![]()
| 序号 | 硬件 | Jetpack安装方式 | 下载链接 | ---- |
| --- | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| 1 | Jetson Xavier NX | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jetson_xavier_nx/jetson-nx-jp46-sd-card-image.zip) | ---- |
| 2 | Jetson Nano | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jeston_nano/jetson-nano-jp46-sd-card-image.zip) | ---- |
| 3 | Jetson Nano 2GB | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jeston_nano_2gb/jetson-nano-2gb-jp46-sd-card-image.zip) | ---- |
| 4 | agx xavier等 | NVIDIA SDK Manager | [Download NVIDIA SDK](https://developer.nvidia.com/nvsdk-manager) | ---- |
| 5 | 非官方版本如emmc版 | 参考采购的硬件公司提供的安装指南 | ---- | ---- |
注意本项目SDK要求 `CUDA=10.2``cuDNN=8.2``TensorRT=8.0``gcc>=7.5``cmake 在 3.0以上` ,安装 Jetpack4.6系统包后CUDA、cuDNN、TensorRT、gcc和cmake版本就已经满足要求无需在进行安装。
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压后SDK目录结构如下
```
.EasyEdge-Linux-硬件芯片
├── RES # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_linux_cpp_x86_64_CPU.Generic_gcc5.4_v1.4.0_20220325.tar.gz
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
```
## 2. 测试Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1 预测图像
```bash
./easyedge_image_inference {模型RES文件夹路径} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855351-68d1a4f0-6226-4484-b190-65f1ac2c7128.png" width="400"></div>
```bash
> ./easyedge_image_inference ../../../../RES 2.jpeg
2019-02-13 16:46:12,659 INFO [EasyEdge] [easyedge.cpp:34] 140606189016192 Baidu EasyEdge Linux Development Kit 0.2.1(20190213)
2019-02-13 16:46:14,083 INFO [EasyEdge] [paddlev2_edge_predictor.cpp:60] 140606189016192 Allocate graph success.
2019-02-13 16:46:14,326 DEBUG [EasyEdge] [paddlev2_edge_predictor.cpp:143] 140606189016192 Inference costs 168 ms
1, 1:txt_frame, p:0.994905 loc: 0.168161, 0.153654, 0.920856, 0.779621
Done
```
### 2.2 预测视频流
```
./easyedge_video_inference {模型RES文件夹路径} {video_type} {video_src_path}
```
其中 video_type 支持三种:
```
video_type : 1 // 本地视频文件
video_type : 2 // 摄像头的index
video_type : 3 // 网络视频流
```
video_src_path: 为 video_type 数值所对应的本地视频路径 、本地摄像头id、网络视频流地址
```
本地视频文件: ./easyedge_video_inference {模型RES文件夹路径} 1 /my_video_file.mp4
本地摄像头: ./easyedge_video_inference {模型RES文件夹路径} 2 1 #/dev/video1
网络视频流: ./easyedge_video_inference {模型RES文件夹路径} 3 rtmp://192.168.x.x:8733/live/src
```
注:以上路径是假模拟路径,开发者需要根据自己实际图像/视频,准备测试图像,并填写正确的测试路径。
# 预测API流程详解
本章节主要结合[2.测试Demo](#4)的Demo示例介绍推理API方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。图像、视频的推理包含以下3个API如代码step注释所示
> ❗注意:<br>
> 1`src`文件夹中包含完整可编译的cmake工程实例建议开发者先行了解[cmake工程基本知识](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)。 <br>
> 2请优先参考SDK中自带的Demo工程的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
```cpp
// step 1: SDK配置运行参数
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
// step 2: 创建并初始化Predictor这这里选择合适的引擎
auto predictor = global_controller()->CreateEdgePredictor(config);
// step 3-1: 预测图像
auto img = cv::imread({图片路径});
std::vector<EdgeResultData> results;
predictor->infer(img, results);
// step 3-2: 预测视频
std::vector<EdgeResultData> results;
FrameTensor frame_tensor;
VideoConfig video_config;
video_config.source_type = static_cast<SourceType>(video_type); // source_type 定义参考头文件 easyedge_video.h
video_config.source_value = video_src;
/*
... more video_configs, 根据需要配置video_config的各选项
*/
auto video_decoding = CreateVideoDecoding(video_config);
while (video_decoding->next(frame_tensor) == EDGE_OK) {
results.clear();
if (frame_tensor.is_needed) {
predictor->infer(frame_tensor.frame, results);
render(frame_tensor.frame, results, predictor->model_info().kind);
}
//video_decoding->display(frame_tensor); // 显示当前frame需在video_config中开启配置
//video_decoding->save(frame_tensor); // 存储当前frame到视频需在video_config中开启配置
}
```
若需自定义library search path或者gcc路径修改对应Demo工程下的CMakeList.txt即可。
## 1. SDK参数运行配置
SDK的参数通过`EdgePredictorConfig::set_config``global_controller()->set_config`配置。本Demo 中设置了模型路径,其他参数保留默认参数。更详细的支持运行参数等,可以参考开发工具包中的头文件(`include/easyedge/easyedge_xxxx_config.h`)的详细说明。
配置参数使用方法如下:
```
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
```
## 2. 初始化Predictor
* 接口
```cpp
auto predictor = global_controller()->CreateEdgePredictor(config);
predictor->init();
```
若返回非0请查看输出日志排查错误原因。
## 3. 预测推理
### 3.1 预测图像
> 在Demo中展示了预测接口infer()传入cv::Mat& image图像内容并将推理结果赋值给std::vector<EdgeResultData>& result。更多关于infer()的使用,可以根据参考`easyedge.h`头文件中的实际情况、参数说明自行传入需要的内容做推理
* 接口输入
```cpp
/**
* @brief
* 通用接口
* @param image: must be BGR , HWC format (opencv default)
* @param result
* @return
*/
virtual int infer(cv::Mat& image, std::vector<EdgeResultData>& result) = 0;
```
图片的格式务必为opencv默认的BGR, HWC格式。
* 接口返回
`EdgeResultData`中可以获取对应的分类信息、位置信息。
```cpp
struct EdgeResultData {
int index; // 分类结果的index
std::string label; // 分类结果的label
float prob; // 置信度
// 物体检测 或 图像分割时使用:
float x1, y1, x2, y2; // (x1, y1): 左上角, x2, y2): 右下角; 均为0~1的长宽比例值。
// 图像分割时使用:
cv::Mat mask; // 0, 1 的mask
std::string mask_rle; // Run Length Encoding游程编码的mask
};
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
*** 关于图像分割mask_rle ***
该字段返回了mask的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析
### 3.2 预测视频
SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类`VideoDecoding`,此类提供了获取视频帧数据的便利函数。通过`VideoConfig`结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。
* 接口输入
class`VideoDecoding`
```
/**
* @brief 获取输入源的下一帧
* @param frame_tensor
* @return
*/
virtual int next(FrameTensor &frame_tensor) = 0;
/**
* @brief 显示当前frame_tensor中的视频帧
* @param frame_tensor
* @return
*/
virtual int display(const FrameTensor &frame_tensor) = 0;
/**
* @brief 将当前frame_tensor中的视频帧写为本地视频文件
* @param frame_tensor
* @return
*/
virtual int save(FrameTensor &frame_tensor) = 0;
/**
* @brief 获取视频的fps属性
* @return
*/
virtual int get_fps() = 0;
/**
* @brief 获取视频的width属性
* @return
*/
virtual int get_width() = 0;
/**
* @brief 获取视频的height属性
* @return
*/
virtual int get_height() = 0;
```
struct `VideoConfig`
```
/**
* @brief 视频源、抽帧策略、存储策略的设置选项
*/
struct VideoConfig {
SourceType source_type; // 输入源类型
std::string source_value; // 输入源地址如视频文件路径、摄像头index、网络流地址
int skip_frames{0}; // 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true
int retrieve_all{false}; // 是否抽取所有frame以便于作为显示和存储对于不满足skip_frames策略的frame把所抽取帧的is_needed置为false
int input_fps{0}; // 在采取抽帧之前设置视频的fps
Resolution resolution{Resolution::kAuto}; // 采样分辨率只对camera有效
bool enable_display{false}; // 默认不支持。
std::string window_name{"EasyEdge"};
bool display_all{false}; // 是否显示所有frame若为false仅显示根据skip_frames抽取的frame
bool enable_save{false};
std::string save_path; // frame存储为视频文件的路径
bool save_all{false}; // 是否存储所有frame若为false仅存储根据skip_frames抽取的frame
std::map<std::string, std::string> conf;
};
```
| 序号 | 字段 | 含义 |
| --- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `source_type` | 输入源类型支持视频文件、摄像头、网络视频流三种值分别为1、2、3 |
| 2 | `source_value` | 若`source_type`为视频文件,该值为指向视频文件的完整路径;若`source_type`为摄像头该值为摄像头的index如对于`/dev/video0`的摄像头则index为0若`source_type`为网络视频流,则为该视频流的完整地址。 |
| 3 | `skip_frames` | 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true标记为is_needed的帧是用来做预测的帧。反之直接跳过该帧不经过预测。 |
| 4 | `retrieve_all` | 若置该项为true则无论是否设置跳帧所有的帧都会被抽取返回以作为显示或存储用。 |
| 5 | `input_fps` | 用于抽帧前设置fps |
| 6 | `resolution` | 设置摄像头采样的分辨率,其值请参考`easyedge_video.h`中的定义,注意该分辨率调整仅对输入源为摄像头时有效 |
| 7 | `conf` | 高级选项。部分配置会通过该map来设置 |
*** 注意:***
1. `VideoConfig`不支持`display`功能。如果需要使用`VideoConfig`的`display`功能需要自行编译带有GTK选项的OpenCV。
2. 使用摄像头抽帧时,如果通过`resolution`设置了分辨率调整,但是不起作用,请添加如下选项:
```
video_config.conf["backend"] = "2";
```
3.部分设备上的CSI摄像头尚未兼容如遇到问题可以通过工单、QQ交流群或微信交流群反馈。
具体接口调用流程可以参考SDK中的`demo_video_inference`。
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
3. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,293 @@
# 简介
本文档介绍FastDeploy中的模型SDK在**Jetson Linux C++** 环境下1 **服务化**推理部署步骤2介绍推理全流程API方便开发者了解项目后二次开发。如果开发者对Jetson图像/视频部署感兴趣,可以参考[Jetson CPP Inference](./Jetson-Linux-CPP-SDK-Inference.md)文档。
**注意**OCR目前不支持服务化推理部署。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试 HTTP Demo](#2-测试-http-demo)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [HTTP API介绍](#http-api介绍)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式一:不使用图片base64格式](#21-http-请求方式一不使用图片base64格式)
* [2.2 http 请求方法二:使用图片base64格式](#22-http-请求方法二使用图片base64格式)
* [3. http 返回数据](#3-http-返回数据)
* [FAQ](#faq)
<!--te-->
# 环境准备
* Jetpack: 4.6 。安装Jetpack 4.6,参考[NVIDIA 官网-Jetpack4.6安装指南](https://developer.nvidia.com/jetpack-sdk-46),或者参考采购的硬件厂商提供的安装方式进行安装。![]()
| 序号 | 硬件 | Jetpack安装方式 | 下载链接 | ---- |
| --- | ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| 1 | Jetson Xavier NX | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jetson_xavier_nx/jetson-nx-jp46-sd-card-image.zip) | ---- |
| 2 | Jetson Nano | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jeston_nano/jetson-nano-jp46-sd-card-image.zip) | ---- |
| 3 | Jetson Nano 2GB | SD Card Image | [Download SD Card Image](https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/jeston_nano_2gb/jetson-nano-2gb-jp46-sd-card-image.zip) | ---- |
| 4 | agx xavier等 | NVIDIA SDK Manager | [Download NVIDIA SDK](https://developer.nvidia.com/nvsdk-manager) | ---- |
| 5 | 非官方版本如emmc版 | 参考采购的硬件公司提供的安装指南 | ---- | ---- |
注意本项目SDK要求 `CUDA=10.2``cuDNN=8.2``TensorRT=8.0``gcc>=7.5``cmake 在 3.0以上` ,安装 Jetpack4.6系统包后CUDA、cuDNN、TensorRT、gcc和cmake版本就已经满足要求无需在进行安装。
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压后SDK目录结构如下
```
.EasyEdge-Linux-硬件芯片
├── RES # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_linux_cpp_x86_64_CPU.Generic_gcc5.4_v1.4.0_20220325.tar.gz
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
```
## 2. 测试 HTTP Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1 启动HTTP预测服务
```
./easyedge_serving {模型RES文件夹路径}
```
启动后日志中会显示如下设备IP和24401端口号信息
```
HTTP is now serving at 0.0.0.0:24401
```
此时,开发者可以打开浏览器,输入链接地址`http://0.0.0.0:24401`(这里的`设备IP和24401端口号`根据开发者电脑显示修改),选择图片来进行测试。
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855495-cd8d46ec-2492-4297-b3e4-2bda4cd6727c.png" width="600"></div>
同时可以调用HTTP接口来访问服务具体参考下文的[二次开发](#10)接口说明。
# HTTP API介绍
本章节主要结合[2.1 HTTP Demo]()的API介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。http服务包含服务端和客户端目前支持的能力包括以下几种方式Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动可直接使用`bin/easyedge_serving`,或参考`src/demo_serving.cpp`文件修改相关逻辑
```cpp
/**
* @brief 开启一个简单的demo http服务。
* 该方法会block直到收到sigint/sigterm。
* http服务里图片的解码运行在cpu之上可能会降低推理速度。
* @tparam ConfigT
* @param config
* @param host
* @param port
* @param service_id service_id user parameter, uri '/get/service_id' will respond this value with 'text/plain'
* @param instance_num 实例数量,根据内存/显存/时延要求调整
* @return
*/
template<typename ConfigT>
int start_http_server(
const ConfigT &config,
const std::string &host,
int port,
const std::string &service_id,
int instance_num = 1);
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式一:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容(无需base64, 无需json)
Python请求示例
```Python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
### 2.2 http 请求方法二:使用图片base64格式
HTTP方法POST
Header如下
| 参数 | 值 |
| ------------ | ---------------- |
| Content-Type | application/json |
**Body请求填写**
* 分类网络:
body 中请求示例
```
{
"image": "<base64数据>"
"top_num": 5
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| ------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| top_num | 否 | number | - | 返回分类数量,不填该参数,则默认返回全部分类结果 |
* 检测和分割网络:
Body请求示例
```
{
"image": "<base64数据>"
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| --------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| threshold | 否 | number | - | 默认为推荐阈值,也可自行根据需要进行设置 |
Python请求示例
```Python
import base64
import requests
def main():
with open("图像路径", 'rb') as f:
result = requests.post("http://{服务ip地址}:24401/", json={
"image": base64.b64encode(f.read()).decode("utf8")
})
# print(result.request.body)
# print(result.request.headers)
print(result.content)
if __name__ == '__main__':
main()
```
## 3. http 返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于分割模型 ***
其中mask为分割模型的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 使用libcurl请求http服务时速度明显变慢
这是因为libcurl请求continue导致server等待数据的问题添加空的header即可
```bash
headers = curl_slist_append(headers, "Expect:");
```
3. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
4. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,412 @@
# 简介
本文档介绍FastDeploy中的模型SDK**Intel X86-CPU/ NVIDIA GPU、Linux** 操作系统下的C++ 1图像和视频的推理部署步骤2介绍推理全流程API方便了解项目后二次开发。如果对Linux操作系统下的 Python部署感兴趣请参考[Linux Python环境下的推理部署](./Linux-Python-SDK-Inference.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. 硬件支持](#1-硬件支持)
* [2. 软件环境](#2-软件环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1. 预测图像](#21-预测图像)
* [2.2. 预测视频流](#22-预测视频流)
* [3. 编译Demo](#3-编译demo)
* [预测API流程详解](#预测api流程详解)
* [1. SDK参数运行配置](#1-sdk参数运行配置)
* [2. 初始化Predictor](#2-初始化predictor)
* [3. 预测推理](#3-预测推理)
* [3.1 预测图像](#31-预测图像)
* [3.2 预测视频](#32-预测视频)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1.硬件支持
* NVIDIA GPU: x86_64
* cuda支持版本CUDA10.0/10.1/10.2 + cuDNN 7 (cuDNN版本>=7.6.5
* cuda支持版本CUDA11.0 + cuDNN v8.0.4
* CPUIntel x86_64
## 2. 软件环境
1.运行二进制文件-环境要求
* gcc: 5.4 以上 (GLIBCXX_3.4.22)
* Linux下查看gcc版本命名可能因系统差异命令会不同`gcc --version`
* Linux下C++基础库GLIBCXX的命令可能因系统差异路径会有不同可检测自己环境下的情况`strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX`
* glibc2.23以上
* Linux查看命令`ldd --version`
2.二次开发编译-环境要求
编译源代码时除了gcc、GLIBCXX、glibc满足`1.运行二进制文件-环境要求`还需要cmake满足要求。
* cmake: 3.0 以上
* Linux查看命令`cmake --version`
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下
```
.EasyEdge-Linux-硬件芯片
├── RES # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_linux_cpp_x86_64_CPU.Generic_gcc5.4_v1.4.0_20220325.tar.gz
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
└── python # Python SDK 文件
```
## 2. 测试Demo
**注意** OCR算法目前没有提供
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1. 预测图像
```bash
./easyedge_image_inference {模型RES文件夹路径} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855351-68d1a4f0-6226-4484-b190-65f1ac2c7128.png" width="400"></div>
```bash
> ./easyedge_image_inference ../../../../RES 2.jpeg
2019-02-13 16:46:12,659 INFO [EasyEdge] [easyedge.cpp:34] 140606189016192 Baidu EasyEdge Linux Development Kit 0.2.1(20190213)
2019-02-13 16:46:14,083 INFO [EasyEdge] [paddlev2_edge_predictor.cpp:60] 140606189016192 Allocate graph success.
2019-02-13 16:46:14,326 DEBUG [EasyEdge] [paddlev2_edge_predictor.cpp:143] 140606189016192 Inference costs 168 ms
1, 1:txt_frame, p:0.994905 loc: 0.168161, 0.153654, 0.920856, 0.779621
Done
```
### 2.2. 预测视频流
```
./easyedge_video_inference {模型RES文件夹路径} {video_type} {video_src_path}
```
其中 video_type 支持三种:
```
video_type : 1 // 本地视频文件
video_type : 2 // 摄像头的index
video_type : 3 // 网络视频流
```
video_src_path: 为 video_type 数值所对应的本地视频路径 、本地摄像头id、网络视频流地址
```
本地视频文件: ./easyedge_video_inference {模型RES文件夹路径} 1 /my_video_file.mp4
本地摄像头: ./easyedge_video_inference {模型RES文件夹路径} 2 1 #/dev/video1
网络视频流: ./easyedge_video_inference {模型RES文件夹路径} 3 rtmp://192.168.x.x:8733/live/src
```
注:以上路径是假模拟路径,开发者需要根据自己实际图像/视频,准备测试图像,并填写正确的测试路径。
## 3. 编译Demo
通过[项目结构说明](#3)了解到,`bin`路径下的可执行文件 由`src`下的对应文件编译得到。 通过以下命令,即可完成`src`下的源码编译。
```
cd src
mkdir build && cd build
cmake .. && make
```
至此会在build文件夹下生成编译好的可执行文件如图像推理的二进制文件`build/demo_image_inference/easyedge_image_inference`
# 预测API流程详解
本章节主要结合[2.测试Demo](#4)的Demo示例介绍推理API方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。图像、视频的推理包含以下3个API查看下面的cpp代码中的step注释说明。
> ❗注意:<br>
> 1`src`文件夹中包含完整可编译的cmake工程实例建议开发者先行了解[cmake工程基本知识](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)。 <br>
> 2请优先参考SDK中自带的Demo工程的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
```cpp
// step 1: SDK配置运行参数
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
// step 2: 创建并初始化Predictor这这里选择合适的引擎
auto predictor = global_controller()->CreateEdgePredictor(config);
// step 3-1: 预测图像
auto img = cv::imread({图片路径});
std::vector<EdgeResultData> results;
predictor->infer(img, results);
// step 3-2: 预测视频
std::vector<EdgeResultData> results;
FrameTensor frame_tensor;
VideoConfig video_config;
video_config.source_type = static_cast<SourceType>(video_type); // source_type 定义参考头文件 easyedge_video.h
video_config.source_value = video_src;
/*
... more video_configs, 根据需要配置video_config的各选项
*/
auto video_decoding = CreateVideoDecoding(video_config);
while (video_decoding->next(frame_tensor) == EDGE_OK) {
results.clear();
if (frame_tensor.is_needed) {
predictor->infer(frame_tensor.frame, results);
render(frame_tensor.frame, results, predictor->model_info().kind);
}
//video_decoding->display(frame_tensor); // 显示当前frame需在video_config中开启配置
//video_decoding->save(frame_tensor); // 存储当前frame到视频需在video_config中开启配置
}
```
若需自定义library search path或者gcc路径修改对应Demo工程下的CMakeList.txt即可。
## 1. SDK参数运行配置
SDK的参数通过`EdgePredictorConfig::set_config``global_controller()->set_config`配置。本Demo 中设置了模型路径,其他参数保留默认参数。更详细的支持运行参数等,可以参考开发工具包中的头文件(`include/easyedge/easyedge_xxxx_config.h`)的详细说明。
配置参数使用方法如下:
```
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
```
## 2. 初始化Predictor
* 接口
```cpp
auto predictor = global_controller()->CreateEdgePredictor(config);
predictor->init();
```
若返回非0请查看输出日志排查错误原因。
## 3. 预测推理
### 3.1 预测图像
> 在Demo中展示了预测接口infer()传入cv::Mat& image图像内容并将推理结果赋值给std::vector<EdgeResultData>& result。更多关于infer()的使用,可以根据参考`easyedge.h`头文件中的实际情况、参数说明自行传入需要的内容做推理
* 接口输入
```cpp
/**
* @brief
* 通用接口
* @param image: must be BGR , HWC format (opencv default)
* @param result
* @return
*/
virtual int infer(cv::Mat& image, std::vector<EdgeResultData>& result) = 0;
```
图片的格式务必为opencv默认的BGR, HWC格式。
* 接口返回
`EdgeResultData`中可以获取对应的分类信息、位置信息。
```cpp
struct EdgeResultData {
int index; // 分类结果的index
std::string label; // 分类结果的label
float prob; // 置信度
// 物体检测 或 图像分割时使用:
float x1, y1, x2, y2; // (x1, y1): 左上角, x2, y2): 右下角; 均为0~1的长宽比例值。
// 图像分割时使用:
cv::Mat mask; // 0, 1 的mask
std::string mask_rle; // Run Length Encoding游程编码的mask
};
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
*** 关于图像分割mask_rle ***
该字段返回了mask的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析
### 3.2 预测视频
SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类`VideoDecoding`,此类提供了获取视频帧数据的便利函数。通过`VideoConfig`结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。
* 接口输入
class`VideoDecoding`
```
/**
* @brief 获取输入源的下一帧
* @param frame_tensor
* @return
*/
virtual int next(FrameTensor &frame_tensor) = 0;
/**
* @brief 显示当前frame_tensor中的视频帧
* @param frame_tensor
* @return
*/
virtual int display(const FrameTensor &frame_tensor) = 0;
/**
* @brief 将当前frame_tensor中的视频帧写为本地视频文件
* @param frame_tensor
* @return
*/
virtual int save(FrameTensor &frame_tensor) = 0;
/**
* @brief 获取视频的fps属性
* @return
*/
virtual int get_fps() = 0;
/**
* @brief 获取视频的width属性
* @return
*/
virtual int get_width() = 0;
/**
* @brief 获取视频的height属性
* @return
*/
virtual int get_height() = 0;
```
struct `VideoConfig`
```
/**
* @brief 视频源、抽帧策略、存储策略的设置选项
*/
struct VideoConfig {
SourceType source_type; // 输入源类型
std::string source_value; // 输入源地址如视频文件路径、摄像头index、网络流地址
int skip_frames{0}; // 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true
int retrieve_all{false}; // 是否抽取所有frame以便于作为显示和存储对于不满足skip_frames策略的frame把所抽取帧的is_needed置为false
int input_fps{0}; // 在采取抽帧之前设置视频的fps
Resolution resolution{Resolution::kAuto}; // 采样分辨率只对camera有效
bool enable_display{false}; // 默认不支持。
std::string window_name{"EasyEdge"};
bool display_all{false}; // 是否显示所有frame若为false仅显示根据skip_frames抽取的frame
bool enable_save{false};
std::string save_path; // frame存储为视频文件的路径
bool save_all{false}; // 是否存储所有frame若为false仅存储根据skip_frames抽取的frame
std::map<std::string, std::string> conf;
};
```
| 序号 | 字段 | 含义 |
| --- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `source_type` | 输入源类型支持视频文件、摄像头、网络视频流三种值分别为1、2、3 |
| 2 | `source_value` | 若`source_type`为视频文件,该值为指向视频文件的完整路径;若`source_type`为摄像头该值为摄像头的index如对于`/dev/video0`的摄像头则index为0若`source_type`为网络视频流,则为该视频流的完整地址。 |
| 3 | `skip_frames` | 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true标记为is_needed的帧是用来做预测的帧。反之直接跳过该帧不经过预测。 |
| 4 | `retrieve_all` | 若置该项为true则无论是否设置跳帧所有的帧都会被抽取返回以作为显示或存储用。 |
| 5 | `input_fps` | 用于抽帧前设置fps |
| 6 | `resolution` | 设置摄像头采样的分辨率,其值请参考`easyedge_video.h`中的定义,注意该分辨率调整仅对输入源为摄像头时有效 |
| 7 | `conf` | 高级选项。部分配置会通过该map来设置 |
*** 注意:***
1. `VideoConfig`不支持`display`功能。如果需要使用`VideoConfig`的`display`功能需要自行编译带有GTK选项的OpenCV。
2. 使用摄像头抽帧时,如果通过`resolution`设置了分辨率调整,但是不起作用,请添加如下选项:
```
video_config.conf["backend"] = "2";
```
3.部分设备上的CSI摄像头尚未兼容如遇到问题可以通过工单、QQ交流群或微信交流群反馈。
具体接口调用流程可以参考SDK中的`demo_video_inference`。
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
3. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,329 @@
# 简介
本文档介绍FastDeploy中的模型SDK在**X86 CPU/ NVIDIA GPU、Linux操作系统** 的C++环境1HTTP服务化推理部署步骤2介绍推理全流程API方便开发者了解项目后二次开发。
如果开发者对Python语言的相关能力感兴趣可以参考Linux Python请参考[Linux Python环境下的推理部署](./Linux-Python-SDK-Serving.md)文档。
**【注意】**OCR Demo 暂不支持服务化部署。
<!--ts-->
* [简介](#简介)
* [安装准备](#安装准备)
* [1. 硬件支持](#1-硬件支持)
* [2. 软件环境](#2-软件环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试 HTTP Demo](#2-测试-http-demo)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [3. 编译Demo](#3-编译demo)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式一:不使用图片base64格式](#21-http-请求方式一不使用图片base64格式)
* [2.2 http 请求方法二:使用图片base64格式](#22-http-请求方法二使用图片base64格式)
* [3. http返回数据](#3-http返回数据)
* [FAQ](#faq)
<!--te-->
# 安装准备
## 1.硬件支持
- NVIDIA GPU: x86_64
- cuda支持版本CUDA10.0/10.1/10.2 + cuDNN 7 (cuDNN版本>=7.6.5
- cuda支持版本CUDA11.0 + cuDNN v8.0.4
- CPUIntel x86_64
## 2. 软件环境
1.运行二进制文件-环境要求
- gcc: 5.4 以上 (GLIBCXX_3.4.22)
- Linux下查看gcc版本命名可能因系统差异命令会不同`gcc --version`
- Linux下C++基础库GLIBCXX的命令可能因系统差异路径会有不同可检测自己环境下的情况`strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX`
- glibc2.23以上
- Linux查看命令`ldd --version`
2.二次开发编译-环境要求
编译源代码时除了gcc、GLIBCXX、glibc满足`1.运行二进制文件-环境要求`还需要cmake满足要求。
- cmake: 3.0 以上
- Linux查看命令`cmake --version`
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下
```
.EasyEdge-Linux-硬件芯片
├── RES # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
├── ReadMe.txt
├── cpp # C++ SDK 文件结构
└── baidu_easyedge_linux_cpp_x86_64_CPU.Generic_gcc5.4_v1.4.0_20220325.tar.gz
├── ReadMe.txt
├── bin # 可直接运行的二进制文件
├── include # 二次开发用的头文件
├── lib # 二次开发用的所依赖的库
├── src # 二次开发用的示例工程
└── thirdparty # 第三方依赖
└── python # Python SDK 文件
```
```
```
## 2. 测试 HTTP Demo
> 模型资源文件即压缩包中的RES文件夹默认已经打包在开发者下载的SDK包中请先将tar包整体拷贝到具体运行的设备中再解压缩使用。
SDK中已经包含预先编译的二进制可直接运行。以下运行示例均是`cd cpp/bin`路径下执行的结果。
### 2.1. 启动HTTP预测服务
```
./easyedge_serving {模型RES文件夹路径}
```
启动后日志中会显示如下设备IP和24401端口号信息
```
HTTP is now serving at 0.0.0.0:24401
```
此时,开发者可以打开浏览器,输入链接地址`http://0.0.0.0:24401`(这里的`设备IP和24401端口号`根据开发者电脑显示修改),选择图片来进行测试。
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175855495-cd8d46ec-2492-4297-b3e4-2bda4cd6727c.png" width="600"></div>
同时可以调用HTTP接口来访问服务具体参考下文的[二次开发](#10)接口说明。
## 3. 编译Demo
通过[项目结构说明](#3)了解到,`bin`路径下的可执行文件是由`src`下的对应文件编译得到的。 该部分说明C++编译命令。
```
cd src
mkdir build && cd build
cmake .. && make
```
至此会在build文件夹下生成编译好的可执行文件如图像推理的二进制文件`build/demo_serving/easyedge_serving`
# HTTP API流程详解
本章节主要结合[2.1 HTTP Demo](#4)的API介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。http服务包含服务端和客户端目前支持的能力包括以下几种方式Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动可直接使用`bin/easyedge_serving`,或参考`src/demo_serving.cpp`文件修改相关逻辑
```cpp
/**
* @brief 开启一个简单的demo http服务。
* 该方法会block直到收到sigint/sigterm。
* http服务里图片的解码运行在cpu之上可能会降低推理速度。
* @tparam ConfigT
* @param config
* @param host
* @param port
* @param service_id service_id user parameter, uri '/get/service_id' will respond this value with 'text/plain'
* @param instance_num 实例数量,根据内存/显存/时延要求调整
* @return
*/
template<typename ConfigT>
int start_http_server(
const ConfigT &config,
const std::string &host,
int port,
const std::string &service_id,
int instance_num = 1);
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式一:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容(无需base64, 无需json)
Python请求示例
```Python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
### 2.2 http 请求方法二:使用图片base64格式
HTTP方法POST
Header如下
| 参数 | 值 |
| ------------ | ---------------- |
| Content-Type | application/json |
**Body请求填写**
* 分类网络:
body 中请求示例
```
{
"image": "<base64数据>"
"top_num": 5
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| ------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| top_num | 否 | number | - | 返回分类数量,不填该参数,则默认返回全部分类结果 |
* 检测和分割网络:
Body请求示例
```
{
"image": "<base64数据>"
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| --------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| threshold | 否 | number | - | 默认为推荐阈值,也可自行根据需要进行设置 |
Python请求示例
```python
import base64
import requests
def main():
with open("图像路径", 'rb') as f:
result = requests.post("http://{服务ip地址}:24401/", json={
"image": base64.b64encode(f.read()).decode("utf8")
})
# print(result.request.body)
# print(result.request.headers)
print(result.content)
if __name__ == '__main__':
main()
```
### 3. http返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于分割模型 ***
其中mask为分割模型的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)
# FAQ
1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
2. 使用libcurl请求http服务时速度明显变慢
这是因为libcurl请求continue导致server等待数据的问题添加空的header即可
```bash
headers = curl_slist_append(headers, "Expect:");
```
3. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
4. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译。

View File

@@ -0,0 +1,369 @@
# 简介
本文档介绍FastDeploy中的模型SDK在**Intel x86_64 / NVIDIA GPU Linux Python** 环境下: 1)图像推理部署步骤; 2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中Linux C++请参考[Linux CPP环境下的推理部署](./Linux-CPP-SDK-Inference.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. Python环境](#2-python环境)
* [3. 安装依赖](#3-安装依赖)
* [3.1 安装paddlepaddle](#31-安装paddlepaddle)
* [3.2 安装EasyEdge Python Wheel 包](#32-安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1. 文件结构说明](#1-文件结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 预测图像](#21-预测图像)
* [预测API流程详解](#预测api流程详解)
* [1. 基础流程](#1-基础流程)
* [2. 初始化](#2-初始化)
* [3. SDK参数配置](#3-sdk参数配置)
* [4. 预测图像](#4-预测图像)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压后SDK目录结构如下
```shell
EasyEdge-Linux-x86-[部署芯片]
├── RES # 模型文件资源文件夹,可替换为其他模型
├── README.md
├── cpp # C++ SDK
└── python # Python SDK
```
## 2. Python环境
> 当前SDK仅支持Python 3.5, 3.6, 3.7
使用如下命令获取已安装的Python版本号。如果本机的版本不匹配建议使用[pyenv](https://github.com/pyenv/pyenv)、[anaconda](https://www.anaconda.com/)等Python版本管理工具对SDK所在目录进行配置。
```shell
$python3 --version
```
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
$python3 -m pip --version
```
## 3. 安装依赖
### 3.1 安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。
`x86_64 CPU` 平台可以使用如下命令进行安装:
```shell
python3 -m pip install paddlepaddle==2.2.2 -i https://mirror.baidu.com/pypi/simple
```
NVIDIA GPU平台的详细安装教程可以参考[官网Paddle安装教程](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)。
> 使用 NVIDIA GPU 预测时,必须满足:
>
> 1. 机器已安装 cuda, cudnn
> 2. 已正确安装对应 cuda 版本的paddle 版本
> 3. 通过设置环境变量`FLAGS_fraction_of_gpu_memory_to_use`设置合理的初始内存使用比例
### 3.2 安装EasyEdge Python Wheel 包
`python`目录下安装特定Python版本的EasyEdge Wheel包。对`x86_64 CPU``x86_64 Nvidia GPU平台 `可以使用如下命令进行安装,具体名称以 Python SDK 包中的 whl 为准。
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-{SDK版本号}-cp{Python版本号}-cp{Python版本号}m-linux_x86_64.whl
```
`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-{版本号}-cp36-cp36m-linux_aarch64.whl
```
# 快速开始
## 1. 文件结构说明
Python SDK文件结构如下
```shell
EasyEdge-Linux-x86--[部署芯片]
├──...
├──python # Linux Python SDK
├── # 特定Python版本的EasyEdge Wheel包, 二次开发可使用
├── BaiduAI_EasyEdge_SDK-1.2.8-cp35-cp35m-linux_x86_64.whl
├── BaiduAI_EasyEdge_SDK-1.2.8-cp36-cp36m-linux_x86_64.whl
├── BaiduAI_EasyEdge_SDK-1.2.8-cp37-cp37m-linux_x86_64.whl
├── infer_demo # demo体验完整文件
│ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ └── demo_serving.py # 提供http服务的demo文件
├── tensor_demo # tensor in/out demo文件
│ └── demo_xxx.py
```
## 2. 测试Demo
> 模型资源文件默认已经打包在开发者下载的SDK包中 默认为`RES`目录。
### 2.1 预测图像
使用infer_demo文件夹下的demo文件。
```bash
python3 demo_x86_cpu.py {模型RES文件夹} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854068-28d27c0a-ef83-43ee-9e89-b65eed99b476.jpg" width="400"></div>
```shell
2022-06-14 14:40:16 INFO [EasyEdge] [demo_nvidia_gpu.py:38] 140518522509120: Init paddlefluid engine...
2022-06-14 14:40:20 INFO [EasyEdge] [demo_nvidia_gpu.py:38] 140518522509120: Paddle version: 2.2.2
{'confidence': 0.9012349843978882, 'index': 8, 'label': 'n01514859 hen'}
```
可以看到,运行结果为`index8labelhen`通过imagenet [类别映射表](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),可以找到对应的类别,即 'hen',由此说明我们的预测结果正确。
# 预测API流程详解
本章节主要结合前文的Demo示例来介绍推理API方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`infer_demo/demo_xx_xx.py`文件查看下面的Python代码中的step注释说明。
## 1. 基础流程
> ❗注意请优先参考SDK中自带demo的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
`infer_demo/demo_xx_xx.py`
```python
# 引入EasyEdge运行库
import BaiduAI.EasyEdge as edge
# 创建并初始化一个预测Progam选择合适的引擎
pred = edge.Program()
pred.init(model_dir={RES文件夹路径}, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
# 预测图像
res = pred.infer_image({numpy.ndarray的图片})
# 关闭结束预测Progam
pred.close()
```
`infer_demo/demo_serving.py`
```python
import BaiduAI.EasyEdge as edge
from BaiduAI.EasyEdge.serving import Serving
# 创建并初始化Http服务
server = Serving(model_dir={RES文件夹路径}, license=serial_key)
# 运行Http服务
# 请参考同级目录下demo_xx_xx.py里:
# pred.init(model_dir=xx, device=xx, engine=xx, device_id=xx)
# 对以下参数device\device_id和engine进行修改
server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# server.run(host=host, port=port, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
```
## 2. 初始化
- 接口
```python
def init(self,
model_dir,
device=Device.CPU,
engine=Engine.PADDLE_FLUID,
config_file='conf.json',
preprocess_file='preprocess_args.json',
model_file='model',
params_file='params',
label_file='label_list.txt',
infer_cfg_file='infer_cfg.json',
device_id=0,
thread_num=1
):
"""
Args:
model_dir: str
device: BaiduAI.EasyEdge.Device比如Device.CPU
engine: BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID
config_file: str
preprocess_file: str
model_file: str
params_file: str
label_file: str 标签文件
infer_cfg_file: 包含预处理、后处理信息的文件
device_id: int 设备ID
thread_num: int CPU的线程数
Raises:
RuntimeError, IOError
Returns:
bool: True if success
"""
```
若返回不是True请查看输出日志排查错误原因。
## 3. SDK参数配置
使用 CPU 预测时,可以通过在 init 中设置 thread_num 使用多线程预测。如:
```python
pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID, thread_num=4)
```
使用 GPU 预测时,可以通过在 init 中设置 device_id 指定需要的GPU device id。如
```python
pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID, device_id=0)
```
## 4. 预测图像
- 接口
```python
def infer_image(self, img,
threshold=0.3,
channel_order='HWC',
color_format='BGR',
data_type='numpy')
"""
Args:
img: np.ndarray or bytes
threshold: float
only return result with confidence larger than threshold
channel_order: string
channel order HWC or CHW
color_format: string
color format order RGB or BGR
data_type: string
仅在图像分割时有意义。 'numpy' or 'string'
'numpy': 返回已解析的mask
'string': 返回未解析的mask游程编码
Returns:
list
"""
```
| 字段 | 类型 | 取值 | 说明 |
| ---------- | -------------------- | --------- | ------------------------ |
| confidence | float | 0~1 | 分类或检测的置信度 |
| label | string | | 分类或检测的类别 |
| index | number | | 分类或检测的类别 |
| x1, y1 | float | 0~1 | 物体检测,矩形的左上角坐标 (相对长宽的比例值) |
| x2, y2 | float | 0~1 | 物体检测,矩形的右下角坐标(相对长宽的比例值) |
| mask | string/numpy.ndarray | 图像分割的mask | |
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
可以参考 demo 文件中使用 opencv 绘制矩形的逻辑。
***结果示例***
i) 图像分类
```json
{
"index": 736,
"label": "table",
"confidence": 0.9
}
```
ii) 物体检测
```json
{
"index": 8,
"label": "cat",
"confidence": 1.0,
"x1": 0.21289,
"y1": 0.12671,
"x2": 0.91504,
"y2": 0.91211,
}
```
iii) 图像分割
```json
{
"name": "cat",
"score": 1.0,
"location": {
"left": ...,
"top": ...,
"width": ...,
"height": ...,
},
"mask": ...
}
```
mask字段中data_type为`numpy`时,返回图像掩码的二维数组
```text
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
data_type为`string`mask的游程编码解析方式可参考 [demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
# FAQ
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
       安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,268 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例,介绍 FastDeploy中的模型SDK ,在**Intel x86_64 / NVIDIA GPU Linux Python** 环境下: 1)SDK **服务化**推理部署步骤; 2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中Linux C++请参考[Linux C++环境下的服务化推理部署](./Linux-CPP-SDK-Serving.md)文档。
**【注意】**OCR Demo 暂不支持服务化部署。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. Python环境](#2-python环境)
* [3. 安装依赖](#3-安装依赖)
* [3.1 安装paddlepaddle](#31-安装paddlepaddle)
* [3.2 安装EasyEdge Python Wheel 包](#32-安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1. 文件结构说明](#1-文件结构说明)
* [2. 测试Serving服务](#2-测试serving服务)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式:不使用图片base64格式](#21-http-请求方式不使用图片base64格式)
* [3. http 返回数据](#3-http-返回数据)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压后SDK目录结构如下
```shell
EasyEdge-Linux-x86-[部署芯片]
├── RES # 模型文件资源文件夹,可替换为其他模型
├── README.md
├── cpp # C++ SDK
└── python # Python SDK
```
## 2. Python环境
> 当前SDK仅支持Python 3.5, 3.6, 3.7
使用如下命令获取已安装的Python版本号。如果本机的版本不匹配建议使用[pyenv](https://github.com/pyenv/pyenv)、[anaconda](https://www.anaconda.com/)等Python版本管理工具对SDK所在目录进行配置。
```shell
$python3 --version
```
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
$python3 -m pip --version
```
## 3. 安装依赖
### 3.1 安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。
1.`x86_64 CPU` 平台可以使用如下命令进行安装:
```shell
python3 -m pip install paddlepaddle==2.2.2 -i https://mirror.baidu.com/pypi/simple
```
2.`x86_64 NVIDIA GPU` 支持的CUDA和CUDNN版本与PaddlePaddle框架保持一致如下
* CUDA 工具包10.1/10.2配合cuDNN 7 (cuDNN版本>=7.6.5, 如需多卡支持需配合NCCL2.7及更高)
* CUDA 工具包11.0配合cuDNN v8.0.4(如需多卡支持需配合NCCL2.7及更高)
* CUDA 工具包11.1配合cuDNN v8.1.1(如需多卡支持需配合NCCL2.7及更高)
* CUDA 工具包11.2配合cuDNN v8.1.1(如需多卡支持需配合NCCL2.7及更高)
具体安装命令,参考[官网Paddle安装教程](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)。
> 使用 NVIDIA GPU 预测时,必须满足:
>
> 1. 机器已安装 cuda, cudnn
> 2. 已正确安装对应 cuda 版本的paddle 版本
> 3. 通过设置环境变量`FLAGS_fraction_of_gpu_memory_to_use`设置合理的初始内存使用比例
### 3.2 安装EasyEdge Python Wheel 包
在`python`目录下安装特定Python版本的EasyEdge Wheel包。对`x86_64 CPU` 或 `x86_64 Nvidia GPU平台 `可以使用如下命令进行安装,具体名称以 Python SDK 包中的 whl 为准。
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-{SDK版本号}-cp{Python版本号}-cp{Python版本号}m-linux_x86_64.whl
```
`armv8 CPU平台`可以使用如下命令进行安装:
```shell
python3 -m pip install -U BaiduAI_EasyEdge_SDK-{SDK版本号}-cp36-cp36m-linux_aarch64.whl
```
# 快速开始
## 1. 文件结构说明
Python SDK文件结构如下
```shell
EasyEdge-Linux-x86--[部署芯片]
├──...
├──python # Linux Python SDK
├── # 特定Python版本的EasyEdge Wheel包, 二次开发可使用
├── BaiduAI_EasyEdge_SDK-1.2.8-cp35-cp35m-linux_x86_64.whl
├── BaiduAI_EasyEdge_SDK-1.2.8-cp36-cp36m-linux_x86_64.whl
├── BaiduAI_EasyEdge_SDK-1.2.8-cp37-cp37m-linux_x86_64.whl
├── infer_demo # demo体验完整文件
│ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ └── demo_serving.py # 提供http服务的demo文件
├── tensor_demo # 学习自定义算法前后处理时使用
│ └── demo_xxx.py
```
## 2. 测试Serving服务
> 模型资源文件默认已经打包在开发者下载的SDK包中 默认为`RES`目录。
### 2.1 启动HTTP预测服务
指定对应的模型文件夹(默认为`RES`、设备ip和指定端口号运行如下命令。
```shell
python3 demo_serving.py {模型RES文件夹} {host, default 0.0.0.0} {port, default 24401}
```
成功启动后,终端中会显示如下字样。
```shell
...
* Running on {host ip}:24401
```
如果是在局域网内的机器上部署,开发者此时可以打开浏览器,输入`http://{host ip}:24401`,选择图片来进行测试,运行效果如下。
<img src="https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png" style="zoom:50%;" />
如果是在远程机器上部署,那么可以参考`demo_serving.py`中的 `http_client_test()函数`请求http服务来执行推理。
# HTTP API流程详解
本章节主要结合前文的Demo示例来对API进行介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考对应的Python文件。http服务包含服务端和客户端Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动使用`demo_serving.py`文件
```python
class Serving(object):
""" SDK local serving """
def __init__(self, model_dir, license='', model_filename='model', params_filename='params'):
self.program = None
self.model_dir = model_dir
self.model_filename = model_filename
self.params_filename = params_filename
self.program_lock = threading.Lock()
self.license_key = license
# 只有ObjectTracking会初始化video_processor
self.video_processor = None
def run(self, host, port, device, engine=Engine.PADDLE_FLUID, service_id=0, device_id=0, **kwargs):
""" Args: host : str port : str device : BaiduAI.EasyEdge.Device比如Device.CPU engine : BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID """
self.run_serving_with_flask(host, port, device, engine, service_id, device_id, **kwargs)
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容。
Python请求示例
```python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
## 3. http 返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
***关于分割模型***
其中mask为分割模型的游程编码解析方式可参考 [demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
# FAQ
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,266 @@
<a name="0"></a>
# 简介
本文档介绍如何将FastDeploy的Demo模型替换成开发者自己训练的AI模型。**注意**FastDeploy下载的SDK和Demo仅支持相同算法模型的替换。本文档要求开发者已经将Demo和SDK运行跑通如果要了解运行跑通Demo和SDK指导文档可以参考[SDK使用文档](https://github.com/PaddlePaddle/FastDeploy/blob/develop/README.md#sdk使用)
* [简介](#0)<br>
* [模型替换](#1)<br>
* [1.模型准备](#2)<br>
* [1.1 Paddle模型](#3)<br>
* [1.2 Paddle OCR模型增加一步特殊转换](#4)<br>
* [1.2.1 下载模型转换工具](#5)<br>
* [1.2.2 下载模型转换工具](#6)<br>
* [1.3 其他框架模型](#7)<br>
* [2.模型名修改和label文件准备](#8)<br>
* [2.1 非OCR模型名修改](#9)<br>
* [2.2 OCR模型名修改](#10)<br>
* [2.3 模型label文件](#11)<br>
* [3.修改配置文件](#12)<br>
* [测试效果](#13)<br>
* [完整配置文件说明](#14)<br>
* [1.配置文件字段含义](#15)<br>
* [2.预处理顺序](#16)<br>
* [FAQ](#17)<br>
**注意事项:**
1. PP-PicoDet模型 在FastDeploy中支持PP-Picodet模型是将后处理写到网络里面的方式即后处理+NMS都在网络结构里面。Paddle Detection导出静态模型时有3种方法选择将后处理和NMS导入到网络里面即可参考[导出部分](https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.4/configs/picodet#%E5%AF%BC%E5%87%BA%E5%8F%8A%E8%BD%AC%E6%8D%A2%E6%A8%A1%E5%9E%8B)。详细网络区别可以通过netron工具对比。
2. PP-Picodet模型在FastDeploy中支持PP-Picodet模型是将前处理写在网络外面的方式。Paddle Detection中的TinyPose算法中会将PP-PicoDet模型的前处理写入网络中。如果要使用FastDeploy的SDK进行模型替换需要将前处理写到网络外面。参考[Detection中的导出命令](https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.4/configs/keypoint/tiny_pose#%E5%B0%86%E8%AE%AD%E7%BB%83%E7%9A%84%E6%A8%A1%E5%9E%8B%E5%AE%9E%E7%8E%B0%E7%AB%AF%E4%BE%A7%E9%83%A8%E7%BD%B2)将TestReader.fuse_normalize=False即可
<a name="1"></a>
# 模型替换
开发者从PaddleDetection、PaddleClas、PaddleOCR、PaddleSeg等飞桨开发套件导出来的对应模型完成 [1.模型准备](#)、[1.模型名修改和模型label](#)、[3.修改配置文件](#) 3步操作需要相同算法才可替换可完成自定义模型的模型文件运行时指定新的模型文件即可在自己训练的模型上实现相应的预测推理任务。
* Linux下模型资源文件夹路径`EasyEdge-Linux-**/RES/`
* Windows下模型资源文件夹路径`EasyEdge-Windows-**/data/model/`
* Android下模型资源文件夹路径`EasyEdge-Android-**/app/src/assets/infer/`` app/src/assets/demo/conf.json`
* iOS下模型资源文件夹路径`EasyEdge-iOS-**/RES/easyedge/`
主要涉及到下面4个模型相关的文件mode、params、label_list.txt、infer_cfg.json和一个APP名相关的配置文件仅Android、iOS、HTTP需要APP名字非必需。
* ```
├── RES、model、infer # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
```
> ❗注意OCR模型在ARM CPU硬件上包括Android、Linux、iOS 三款操作系统),因为任务的特殊性,替换在 [1.模型准备](#)、[1.模型名修改和模型label](#) 不同于其他任务模型,详细参考下面步骤。
<a name="2"></a>
## 1.模型准备
<a name="3"></a>
### 1.1 Paddle模型
* 通过PaddleDetection、PaddleClas、PaddleOCR、PaddleSeg等导出来飞桨模型文件包括如下文件可能存在导出时修改了名字的情况后缀`.pdmodel`为模型网络结构文件,后缀`.pdiparams`为模型权重文件):
```
model.pdmodel # 模型网络结构
model.pdiparams # 模型权重
model.yml # 模型的配置文件(包括预处理参数、模型定义等)
```
<a name="4"></a>
### 1.2 OCR模型特殊转换仅在ARM CPU上需要
因为推理引擎版本的问题OCR模型需要在[1.1 Paddle模型](#3)导出`.pdmodel`和`.pdiparams`模型后多增加一步模型转换的特殊处理主要执行下面2步
<a name="5"></a>
#### 1.2.1 下载模型转换工具
Linux 模型转换工具下载链接:[opt_linux](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.11/opt_linux)</br>
M1 模型转换工具下载链接:[opt_m1](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.11/opt_m1)</br>
mac 模型转换工具下载链接:[opt_mac](https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.11/opt_mac)</br>
<a name="6"></a>
#### 1.2.2 模型转换
以下命令以mac为例完成模型转换。
```
* 转换 OCR 检测模型命名:
./opt_mac --model_dir=./ch_PP-OCRv3_det_infer/ --valid_targets=arm --optimize_out_type=naive_buffer --optimize_out=./ocr_det
* 转换 OCR 识别模型命名:
./opt_mac --model_dir=./ch_PP-OCRv3_rec_infer/ --valid_targets=arm --optimize_out_type=naive_buffer --optimize_out=./ocr_rec
```
产出:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175856746-501b05ad-6fba-482e-8e72-fdd68fe52101.png" width="400"></div>
<a name="7"></a>
### 1.3 其他框架模型
* 如果开发着是PyTorch、TensorFLow、Caffe、ONNX等其他框架模型可以参考[X2Paddle](https://github.com/PaddlePaddle/X2Paddle)官网完成模型转换,即可得到对应的`model.pdmodel`和`model.pdiparams`模型文件。
<a name="8"></a>
## 2.模型名修改和label文件准备
<a name="9"></a>
### 2.1 非OCR模型名修改
按照下面的规则,修改套件导出来的模型名和标签文件,并替换到模型资源文件中。
```
1. model.pdmodel 修改成 model
2. model.pdiparams 修改成 params
```
<a name="10"></a>
### 2.2 OCR模型名修改
```
1. ocr_det.nb 修改成 model # 将 检测模型 修改名称成 model
2. ocr_rec.nb 修改成 params # 将 识别模型 修改名称成 model
```
<a name="11"></a>
### 2.3 模型label文件
同时需要准备模型文件对应的label文件`label_list.txt`。label文件可以参考原Demo中`label_list.txt`的格式准备。
<a name="12"></a>
## 3. 修改模型相关配置文件
1infer_cfg.json 文件修改
所有程序开发者都需要关注该配置文件。开发者在自己数据/任务中训练模型,可能会修改输入图像尺寸、修改阈值等操作,因此需要根据训练情况修改`Res文件夹下的infer_cfg.json`文件中的对应。CV任务涉及到的配置文件修改包括如下字段
```
1. "best_threshold": 0.3, #网络输出的阈值,根据开发者模型实际情况修改
2. "resize": [512, 512], #[w, h]网络输入图像尺寸,用户根据实际情况修改。
```
2conf.json 文件修改
仅Android、iOS、HTTP服务应用开发者需要关注该配置文件。开发者根据自己应用程序命名需要参考已有`conf.json`即可。
通常开发者修改FastDeploy项目中的模型涉及到主要是这几个配置信息的修改。FastDeploy详细的配置文件介绍参考[完整配置文件说明](#8)。
<a name="13"></a>
# 测试效果
将自定义准备的`RES`文件按照第2、3步完成修改后参考可以参考[SDK使用文档](https://github.com/PaddlePaddle/FastDeploy/blob/develop/README.md#sdk%E4%BD%BF%E7%94%A8)完成自己模型上的不同预测体验。
<a name="14"></a>
# 完整配置文件说明
<a name="15"></a>
## 1. 配置文件字段含义
模型资源文件`infer_cfg.json`涉及到大量不同算法的前后处理等信息,下表是相关的字段介绍,通常开发者如果没有修改算法前出处理,不需要关心这些字段。非标记【必须】的可不填。
```json
{
"version": 1,
"model_info": {
"best_threshold": 0.3, // 默认0.3
"model_kind": 1, // 【必须】 1-分类2-检测6-实例分割12-追踪14-语义分割401-人脸402-姿态10001-决策
},
"pre_process": { // 【必须】
// 归一化, 预处理会把图像 (origin_img - mean) * scale
"skip_norm": false, // 默认为false, 如果设置为true不做mean scale处理
"mean": [123, 123, 123], // 【必须一般不需要动】图像均值已经根据Paddle套件均值做了转换处理开发者如果没有修改套件参数可以不用关注。X-mean/ scale
"scale": [0.017, 0.017, 0.017], // 【必须,一般不需要动】
"color_format": "RGB", // BGR 【必须,一般不需要动】
"channel_order": "CHW", // HWC
// 大小相关
"resize": [300, 300], // w, h 【必须】
"rescale_mode": "keep_size", // 默认keep_size keep_ratio, keep_ratio2, keep_raw_size, warp_affine
"max_size": 1366, // keep_ratio 用。如果没有提供,则用 resize[0]
"target_size": 800, // keep_ratio 用。如果没有提供,则用 resize[1]
"raw_size_range": [100, 10000], // keep_raw_size 用
"warp_affine_keep_res": // warp_affine模式使用默认为false
"center_crop_size": [224, 224] // w, h, 如果需要做center_crop则提供否则无需提供该字段
"padding": false,
"padding_mode": "padding_align32", // 【非必须】默认padding_align32, 其他可指定padding_fill_size
"padding_fill_size": [416, 416], // 【非必须】仅padding_fill_size模式下需要提供, [fill_size_w, fill_size_h], 这里padding fill对齐paddle detection实现在bottom和right方向实现补齐
"padding_fill_value": [114, 114, 114] // 【非必须】仅padding_fill_size模式下需要提供
// 其他
"letterbox": true,
},
"post_process": {
"box_normed": true, // 默认为true, 如果为false 则表示该模型的box坐标输出不是归一化的
}
}
```
<a name="16"></a>
## 2. 预处理顺序(没有的流程自动略过)
1. 灰度图 -> rgb图变换
2. resize 尺寸变换
3. center_crop
4. rgb/bgr变换
5. padding_fill_size
6. letterbox画个厚边框填上黑色
7. chw/hwc变换
8. 归一化mean, scale
9. padding_align32
rescale_mode说明
* keep_size: 将图片缩放到resize指定的大小
* keep_ratio:将图片按比例缩放长边不超过max_size短边不超过target_size
* keep_raw_size:保持原图尺寸但必须在raw_size_range之间
* warp_affine: 仿射变换可以设置warp_affine_keep_res指定是否keep_res在keep_res为false场景下宽高通过resize字段指定
<a name="17"></a>
# FAQ
### 1. 如何处理一些 undefined reference / error while loading shared libraries?
> 如:./easyedge_demo: error while loading shared libraries: libeasyedge.so.1: cannot open shared object file: No such file or directory
遇到该问题时请找到具体的库的位置设置LD_LIBRARY_PATH或者安装缺少的库。
> 示例一libverify.so.1: cannot open shared object file: No such file or directory
> 链接找不到libveirfy.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../lib 解决(实际冒号后面添加的路径以libverify.so文件所在的路径为准)
> 示例二libopencv_videoio.so.4.5: cannot open shared object file: No such file or directory
> 链接找不到libopencv_videoio.so文件一般可通过 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../../thirdparty/opencv/lib 解决(实际冒号后面添加的路径以libopencv_videoio.so所在路径为准)
> 示例三GLIBCXX_X.X.X not found
> 链接无法找到glibc版本请确保系统gcc版本>=SDK的gcc版本。升级gcc/glibc可以百度搜索相关文献。
### 2. 使用libcurl请求http服务时速度明显变慢
这是因为libcurl请求continue导致server等待数据的问题添加空的header即可
```bash
headers = curl_slist_append(headers, "Expect:");
```
### 3. 运行二进制时,提示 libverify.so cannot open shared object file
可能cmake没有正确设置rpath, 可以设置LD_LIBRARY_PATH为sdk的lib文件夹后再运行
```bash
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib ./easyedge_demo
```
### 4. 编译时报错file format not recognized
可能是因为在复制SDK时文件信息丢失。请将整个压缩包复制到目标设备中再解压缩、编译

View File

@@ -0,0 +1,389 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例介绍FastDeploy中的模型SDK ,在**Intel x86_64 / NVIDIA GPU Windows C++** 环境下1SDK 图像和视频推理部署步骤2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中Windows Python请参考[Windows Python环境下的推理部署](./Windows-Python-SDK-Inference.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. CPP环境](#2-cpp环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试EasyEdge服务](#2-测试easyedge服务)
* [3. 预测图像](#3-预测图像)
* [4. 预测视频流](#4-预测视频流)
* [5. 编译Demo](#5-编译demo)
* [预测API流程详解](#预测api流程详解)
* [1. SDK参数运行配置](#1-sdk参数运行配置)
* [2. 初始化Predictor](#2-初始化predictor)
* [3. 预测推理](#3-预测推理)
* [3.1 预测图像](#31-预测图像)
* [3.2 预测视频](#32-预测视频)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压缩后的文件结构如`快速开始`中[1项目介绍说明](#1-项目结构说明)介绍。
## 2. CPP环境
> 建议使用Microsoft Visual Studio 2015及以上版本获取核心 C 和 C++ 支持,安装时请选择“使用 C++ 的桌面开发”工作负载。
# 快速开始
## 1. 项目结构说明
```shell
EasyEdge-win-xxx
├── data
│ ├── model # 模型文件资源文件夹,可替换为其他模型
│ └── config # 配置文件
├── bin # demo二进制程序
│ ├── xxx_image # 预测图像demo
│ ├── xxx_video # 预测视频流demo
│ └── xxx_serving # 启动http预测服务demo
├── dll # demo二进制程序依赖的动态库
├── ... # 二次开发依赖的文件
├── python # Python SDK文件
├── EasyEdge.exe # EasyEdge服务
└── README.md # 环境说明
```
## 2. 测试EasyEdge服务
> 模型资源文件默认已经打包在开发者下载的SDK包中请先将zip包整体拷贝到具体运行的设备中再解压缩使用。
SDK下载完成后双击打开EasyEdge.exe启动推理服务输入要绑定的Host ip及端口号Port点击启动服务。
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854086-d507c288-56c8-4fa9-a00c-9d3cfeaac1c8.png" alt="图片" style="zoom: 67%;" />
</div>
服务启动后,打开浏览器输入`http://{Host ip}:{Port}`,添加图片或者视频来进行测试。
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png" style="zoom:67%;" />
</div>
## 3. 预测图像
除了通过上述方式外您还可以使用bin目录下的可执行文件来体验单一的功能。在dll目录下点击右键选择"在终端打开",执行如下命令。
> 需要将bin目录下的可执行文件移动到dll目录下执行或者将dll目录添加到系统环境变量中。
```bash
.\easyedge_image_inference {模型model文件夹} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854068-28d27c0a-ef83-43ee-9e89-b65eed99b476.jpg" width="400"></div>
```shell
2022-06-20 10:36:57,602 INFO [EasyEdge] 9788 EasyEdge Windows Development Kit 1.5.2(Build CPU.Generic 20220607) Release
e[37m--- Fused 0 subgraphs into layer_norm op.e[0m
2022-06-20 10:36:58,008 INFO [EasyEdge] 9788 Allocate graph success.
Results of image ..\demo.jpg:
8, n01514859 hen, p:0.953429
save result image to ..\demo.jpg.result-cpp.jpg
Done
```
可以看到,运行结果为`index8labelhen`通过imagenet [类别映射表](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),可以找到对应的类别,即 'hen',由此说明我们的预测结果正确。
## 4. 预测视频流
```
.\easyedge_video_inference {模型model文件夹} {video_type} {video_src}
```
其中video_type支持三种视频流类型它们分别是1本地视频文件 2本地摄像头id3网络视频流地址。
```
/**
* @brief 输入源类型
*/
enum class SourceType {
kVideoFile = 1, // 本地视频文件
kCameraId = 2, // 摄像头的index
kNetworkStream = 3, // 网络视频流
};
```
video_src 即为文件路径。
## 5. 编译Demo
在[项目结构说明](#1-项目结构说明)中,`bin`路径下的可执行文件是由`src`下的对应文件编译得到的,具体的编译命令如下。
```
cd src
mkdir build && cd build
cmake .. && make
```
编译完成后在build文件夹下会生成编译好的可执行文件如图像推理的二进制文件`build/demo_serving/easyedge_serving`
# 预测API流程详解
本章节主要结合前文的Demo示例来介绍推理API方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。图像、视频的推理包含以下3个API查看下面的cpp代码中的step注释说明。
> ❗注意:
> 1`src`文件夹中包含完整可编译的cmake工程实例建议开发者先行了解[cmake工程基本知识](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)。
> 2请优先参考SDK中自带的Demo工程的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
```cpp
// step 1: SDK配置运行参数
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
// step 2: 创建并初始化Predictor这这里选择合适的引擎
auto predictor = global_controller()->CreateEdgePredictor(config);
// step 3-1: 预测图像
auto img = cv::imread({图片路径});
std::vector<EdgeResultData> results;
predictor->infer(img, results);
// step 3-2: 预测视频
std::vector<EdgeResultData> results;
FrameTensor frame_tensor;
VideoConfig video_config;
video_config.source_type = static_cast<SourceType>(video_type); // source_type 定义参考头文件 easyedge_video.h
video_config.source_value = video_src;
/*
... more video_configs, 根据需要配置video_config的各选项
*/
auto video_decoding = CreateVideoDecoding(video_config);
while (video_decoding->next(frame_tensor) == EDGE_OK) {
results.clear();
if (frame_tensor.is_needed) {
predictor->infer(frame_tensor.frame, results);
render(frame_tensor.frame, results, predictor->model_info().kind);
}
//video_decoding->display(frame_tensor); // 显示当前frame需在video_config中开启配置
//video_decoding->save(frame_tensor); // 存储当前frame到视频需在video_config中开启配置
}
```
若需自定义library search path或者gcc路径修改对应Demo工程下的CMakeList.txt即可。
## 1. SDK参数运行配置
SDK的参数通过`EdgePredictorConfig::set_config``global_controller()->set_config`配置。本Demo 中设置了模型路径,其他参数保留默认参数。更详细的支持运行参数等,可以参考开发工具包中的头文件(`include/easyedge/easyedge_xxxx_config.h`)的详细说明。
配置参数使用方法如下:
```
EdgePredictorConfig config;
config.model_dir = {模型文件目录};
```
## 2. 初始化Predictor
- 接口
```cpp
auto predictor = global_controller()->CreateEdgePredictor(config);
predictor->init();
```
若返回非0请查看输出日志排查错误原因。
## 3. 预测推理
### 3.1 预测图像
> 在Demo中展示了预测接口infer()传入cv::Mat& image图像内容并将推理结果赋值给std::vector& result。更多关于infer()的使用,可以根据参考`easyedge.h`头文件中的实际情况、参数说明自行传入需要的内容做推理
- 接口输入
```cpp
/**
* @brief
* 通用接口
* @param image: must be BGR , HWC format (opencv default)
* @param result
* @return
*/
virtual int infer(cv::Mat& image, std::vector<EdgeResultData>& result) = 0;
```
图片的格式务必为opencv默认的BGR, HWC格式。
- 接口返回
`EdgeResultData`中可以获取对应的分类信息、位置信息。
```cpp
struct EdgeResultData {
int index; // 分类结果的index
std::string label; // 分类结果的label
float prob; // 置信度
// 物体检测 或 图像分割时使用:
float x1, y1, x2, y2; // (x1, y1): 左上角, x2, y2): 右下角; 均为0~1的长宽比例值。
// 图像分割时使用:
cv::Mat mask; // 0, 1 的mask
std::string mask_rle; // Run Length Encoding游程编码的mask
};
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于图像分割mask ***
```
cv::Mat mask为图像掩码的二维数组
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
*** 关于图像分割mask_rle ***
该字段返回了mask的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
以上字段可以参考demo文件中使用opencv绘制的逻辑进行解析。
### 3.2 预测视频
SDK 提供了支持摄像头读取、视频文件和网络视频流的解析工具类`VideoDecoding`,此类提供了获取视频帧数据的便利函数。通过`VideoConfig`结构体可以控制视频/摄像头的解析策略、抽帧策略、分辨率调整、结果视频存储等功能。对于抽取到的视频帧可以直接作为SDK infer 接口的参数进行预测。
- 接口输入
class`VideoDecoding`
```
/**
* @brief 获取输入源的下一帧
* @param frame_tensor
* @return
*/
virtual int next(FrameTensor &frame_tensor) = 0;
/**
* @brief 显示当前frame_tensor中的视频帧
* @param frame_tensor
* @return
*/
virtual int display(const FrameTensor &frame_tensor) = 0;
/**
* @brief 将当前frame_tensor中的视频帧写为本地视频文件
* @param frame_tensor
* @return
*/
virtual int save(FrameTensor &frame_tensor) = 0;
/**
* @brief 获取视频的fps属性
* @return
*/
virtual int get_fps() = 0;
/**
* @brief 获取视频的width属性
* @return
*/
virtual int get_width() = 0;
/**
* @brief 获取视频的height属性
* @return
*/
virtual int get_height() = 0;
```
struct `VideoConfig`
```
/**
* @brief 视频源、抽帧策略、存储策略的设置选项
*/
struct VideoConfig {
SourceType source_type; // 输入源类型
std::string source_value; // 输入源地址如视频文件路径、摄像头index、网络流地址
int skip_frames{0}; // 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true
int retrieve_all{false}; // 是否抽取所有frame以便于作为显示和存储对于不满足skip_frames策略的frame把所抽取帧的is_needed置为false
int input_fps{0}; // 在采取抽帧之前设置视频的fps
Resolution resolution{Resolution::kAuto}; // 采样分辨率只对camera有效
bool enable_display{false}; // 默认不支持。
std::string window_name{"EasyEdge"};
bool display_all{false}; // 是否显示所有frame若为false仅显示根据skip_frames抽取的frame
bool enable_save{false};
std::string save_path; // frame存储为视频文件的路径
bool save_all{false}; // 是否存储所有frame若为false仅存储根据skip_frames抽取的frame
std::map<std::string, std::string> conf;
};
```
| 序号 | 字段 | 含义 |
| --- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `source_type` | 输入源类型支持视频文件、摄像头、网络视频流三种值分别为1、2、3 |
| 2 | `source_value` | 若`source_type`为视频文件,该值为指向视频文件的完整路径;若`source_type`为摄像头该值为摄像头的index如对于`/dev/video0`的摄像头则index为0若`source_type`为网络视频流,则为该视频流的完整地址。 |
| 3 | `skip_frames` | 设置跳帧每隔skip_frames帧抽取一帧并把该抽取帧的is_needed置为true标记为is_needed的帧是用来做预测的帧。反之直接跳过该帧不经过预测。 |
| 4 | `retrieve_all` | 若置该项为true则无论是否设置跳帧所有的帧都会被抽取返回以作为显示或存储用。 |
| 5 | `input_fps` | 用于抽帧前设置fps |
| 6 | `resolution` | 设置摄像头采样的分辨率,其值请参考`easyedge_video.h`中的定义,注意该分辨率调整仅对输入源为摄像头时有效 |
| 7 | `conf` | 高级选项。部分配置会通过该map来设置 |
*** 注意:***
1. `VideoConfig`不支持`display`功能。如果需要使用`VideoConfig`的`display`功能需要自行编译带有GTK选项的OpenCV。
2. 使用摄像头抽帧时,如果通过`resolution`设置了分辨率调整,但是不起作用,请添加如下选项:
```
video_config.conf["backend"] = "2";
```
3. 部分设备上的CSI摄像头尚未兼容如遇到问题可以通过工单、QQ交流群或微信交流群反馈。
具体接口调用流程可以参考SDK中的`demo_video_inference`。
# FAQ
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,275 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例本文档介绍FastDeploy中的模型SDK在**Intel x86_64 / NVIDIA GPU、Windows操作系统** 的C++环境1HTTP服务化推理部署步骤2介绍推理全流程API方便开发者了解项目后二次开发。
如果开发者对Python语言的相关能力感兴趣可以参考Windows Python请参考[Windows Python环境下的推理部署](./Windows-Python-SDK-Serving.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. CPP环境](#2-cpp环境)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试EasyEdge服务](#2-测试easyedge服务)
* [3. 启动HTTP预测服务](#3-启动http预测服务)
* [4. 编译Demo](#4-编译demo)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式一:不使用图片base64格式](#21-http-请求方式一不使用图片base64格式)
* [2.2 http 请求方法二:使用图片base64格式](#22-http-请求方法二使用图片base64格式)
* [3. http 返回数据](#3-http-返回数据)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压缩后的文件结构如`快速开始`中[1项目介绍说明](#1-%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E)介绍。
```shell
```
## 2. CPP环境
> 建议使用Microsoft Visual Studio 2015及以上版本获取核心 C 和 C++ 支持,安装时请选择“使用 C++ 的桌面开发”工作负载。
# 快速开始
## 1. 项目结构说明
```shell
EasyEdge-win-xxx
├── data
│ ├── model # 模型文件资源文件夹,可替换为其他模型
│ └── config # 配置文件
├── bin # demo二进制程序
│ ├── xxx_image # 预测图像demo
│ ├── xxx_video # 预测视频流demo
│ └── xxx_serving # 启动http预测服务demo
├── dll # demo二进制程序依赖的动态库
├── ... # 二次开发依赖的文件
├── python # Python SDK文件
├── EasyEdge.exe # EasyEdge服务
└── README.md # 环境说明
```
## 2. 测试EasyEdge服务
> 模型资源文件默认已经打包在开发者下载的SDK包中请先将zip包整体拷贝到具体运行的设备中再解压缩使用。
SDK下载完成后双击打开EasyEdge.exe启动推理服务输入要绑定的Host ip及端口号Port点击启动服务。
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854086-d507c288-56c8-4fa9-a00c-9d3cfeaac1c8.png" alt="图片" style="zoom: 67%;" />
</div>
服务启动后,打开浏览器输入`http://{Host ip}:{Port}`,添加图片或者视频来进行测试。
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png" style="zoom:67%;" />
</div>
## 3. 启动HTTP预测服务
除了通过上述方式外您还可以使用bin目录下的可执行文件来体验单一的功能。在dll目录下点击右键选择"在终端打开",执行如下命令。
> 需要将bin目录下的可执行文件移动到dll目录下执行或者将dll目录添加到系统环境变量中。
```
.\easyedge_serving {模型model文件夹路径}
```
启动后,日志中会显示如下字样。
```
HTTP is now serving at 0.0.0.0:24401
```
此时,开发者可以打开浏览器,`http://127.0.0.1:24401`,执行和之前一样的操作即可。
![](https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png)
## 4. 编译Demo
在[项目结构说明](#1项目结构说明)中,`bin`路径下的可执行文件是由`src`下的对应文件编译得到的,具体的编译命令如下。
```
cd src
mkdir build && cd build
cmake .. && make
```
编译完成后在build文件夹下会生成编译好的可执行文件如图像推理的二进制文件`build/demo_serving/easyedge_serving`
# HTTP API流程详解
本章节主要结合[2.1 HTTP Demo](#4)的API介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`include/easyedge/easyedge*.h`文件。http服务包含服务端和客户端目前支持的能力包括以下几种方式Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动可直接使用`bin/easyedge_serving`,或参考`src/demo_serving.cpp`文件修改相关逻辑
```cpp
/**
* @brief 开启一个简单的demo http服务。
* 该方法会block直到收到sigint/sigterm。
* http服务里图片的解码运行在cpu之上可能会降低推理速度。
* @tparam ConfigT
* @param config
* @param host
* @param port
* @param service_id service_id user parameter, uri '/get/service_id' will respond this value with 'text/plain'
* @param instance_num 实例数量,根据内存/显存/时延要求调整
* @return
*/
template<typename ConfigT>
int start_http_server(
const ConfigT &config,
const std::string &host,
int port,
const std::string &service_id,
int instance_num = 1);
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式一:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容(无需base64, 无需json)
Python请求示例
```Python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
### 2.2 http 请求方法二:使用图片base64格式
HTTP方法POST
Header如下
| 参数 | 值 |
| ------------ | ---------------- |
| Content-Type | application/json |
**Body请求填写**
- 分类网络:
body 中请求示例
```
{
"image": "<base64数据>"
"top_num": 5
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| ------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| top_num | 否 | number | - | 返回分类数量,不填该参数,则默认返回全部分类结果 |
- 检测和分割网络:
Body请求示例
```
{
"image": "<base64数据>"
}
```
body中参数详情
| 参数 | 是否必选 | 类型 | 可选值范围 | 说明 |
| --------- | ---- | ------ | ----- | ----------------------------------------------------------------------------------- |
| image | 是 | string | - | 图像数据base64编码要求base64图片编码后大小不超过4M,最短边至少15px最长边最大4096px支持jpg/png/bmp格式 **注意去掉头部** |
| threshold | 否 | number | - | 默认为推荐阈值,也可自行根据需要进行设置 |
## 3. http 返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
*** 关于矩形坐标 ***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
*** 关于分割模型 ***
其中mask为分割模型的游程编码解析方式可参考 [http demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
# FAQ
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,381 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例,介绍 FastDeploy中的模型SDK ,在**Intel x86_64 / NVIDIA GPU Windows Python** 环境下: 1)图像推理部署步骤; 2介绍模型推流全流程API方便开发者了解项目后二次开发。
其中Windows Python请参考[Windows C++环境下的推理部署](./Windows-CPP-SDK-Inference.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. Python环境](#2-python环境)
* [3. 安装依赖](#3-安装依赖)
* [3.1 安装paddlepaddle](#31-安装paddlepaddle)
* [3.2 安装EasyEdge Python Wheel 包](#32-安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1. 文件结构说明](#1-文件结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 预测图像](#21-预测图像)
* [预测API流程详解](#预测api流程详解)
* [1. 基础流程](#1-基础流程)
* [2. 初始化](#2-初始化)
* [3. SDK参数配置](#3-sdk参数配置)
* [4. 预测图像](#4-预测图像)
* [FAQ](#faq)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压缩后的文件结构如下所示
```shell
EasyEdge-win-[部署芯片]
├── data # 模型文件资源文件夹,可替换为其他模型
├── ... # C++/C# 相关文件
├── python # Python SDK文件
├── EasyEdge.exe # 主程序
└── README.md # 环境说明
```
<a name="3"></a>
## 2. Python环境
> 当前SDK仅支持Python 3.7
打开命令行工具使用如下命令获取已安装的Python版本号。如果还没有安装Python环境可以前往[官网](https://www.python.org/)下载Python 3.7对应的安装程序,特别要注意勾上`Add Python 3.7 to PATH`然后点“Install Now”即可完成安装。
```shell
python --version
```
如果本机的版本不匹配,建议使用[pyenv](https://github.com/pyenv/pyenv)、[anaconda](https://www.anaconda.com/)等Python版本管理工具对Python SDK所在目录进行配置。
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
python -m pip --version
```
## 3. 安装依赖
### 3.1 安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。`x86_64 CPU` 平台可以使用如下命令进行安装:
```shell
python -m pip install paddlepaddle==2.2.2 -i https://mirror.baidu.com/pypi/simple
```
`NVIDIA GPU平台`的详细安装教程可以参考[官网Paddle安装教程](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)。
> 使用 NVIDIA GPU 预测时,必须满足:
>
> 1. 机器已安装 cuda, cudnn
>
> 2. 已正确安装对应 cuda 版本的paddle 版本
> 3. 通过设置环境变量`FLAGS_fraction_of_gpu_memory_to_use`设置合理的初始内存使用比例
<a name="6"></a>
### 3.2 安装EasyEdge Python Wheel 包
`python`目录下安装Python3.7版本对应的EasyEdge Wheel包。对`x86_64 CPU``x86_64 Nvidia GPU平台 `可以使用如下命令进行安装,具体名称以 Python SDK 包中的 whl 为准。
```shell
python -m pip install -U BaiduAI_EasyEdge_SDK-{SDK版本号}-cp37-cp37m-win_amd64.whl
```
<a name="7"></a>
# 快速开始
<a name="8"></a>
## 1. 文件结构说明
Python SDK文件结构如下
```shell
EasyEdge-win-[部署芯片]
├── data # 模型文件资源文件夹,可替换为其他模型
│ ├── model # 模型文件资源文件夹,可替换为其他模型
│ └── config # 配置文件
├── ... # C++/C# 相关文件
├── python # Python SDK文件
│ ├── # 特定Python 3.7版本的EasyEdge Wheel包, 二次开发可使用
│ ├── BaiduAI_EasyEdge_SDK-${SDK版本号}-cp37-cp37m-win_amd64.whl
│ ├── requirements.txt #
│ ├── infer_demo # demo体验完整文件
│ │ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ │ └── demo_serving.py # 提供http服务的demo文件
│ └── tensor_demo # tensor in/out demo文件
```
<a name="9"></a>
## 2. 测试Demo
<a name="10"></a>
### 2.1 预测图像
根据部署平台使用infer_demo文件夹下的demo文件执行如下命令。
```shell
python demo_x86_cpu.py {模型model文件夹} {测试图片路径}
```
运行效果示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854068-28d27c0a-ef83-43ee-9e89-b65eed99b476.jpg" width="400"></div>
```shell
2022-06-14 18:35:44 DEBUG [EasyEdge] [demo_x86_cpu.py:41] 19424: Config:: w: 256, h: 256; mean: [123.675, 116.28, 103.53]; scale: [0.01712475 0.017507 0.01742919]
2022-06-14 18:35:44 INFO [EasyEdge] [demo_x86_cpu.py:41] 19424: Init paddlefluid engine...
2022-06-14 18:35:45 INFO [EasyEdge] [demo_x86_cpu.py:41] 19424: Paddle version: 2.2.2
2022-06-14 18:35:45 DEBUG [EasyEdge] [demo_x86_cpu.py:41] 19424: CPU thread num set to 1
2022-06-14 18:35:45 DEBUG [EasyEdge] [demo_x86_cpu.py:55] 19424: resize to w257, h256
2022-06-14 18:35:45 DEBUG [EasyEdge] [demo_x86_cpu.py:55] 19424: Switch to CHW
2022-06-14 18:35:45 DEBUG [EasyEdge] [demo_x86_cpu.py:55] 19424: Infer cost: 70.1(66.1) ms
{'confidence': 0.9012351036071777, 'index': 8, 'label': 'n01514859 hen'}
```
可以看到,运行结果为`index8labelhen`通过imagenet [类别映射表](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),可以找到对应的类别,即 'hen',由此说明我们的预测结果正确。
# 预测API流程详解
本章节主要结合前文的Demo示例来介绍推理API方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考`infer_demo/demo_xx_xx.py`文件查看下面的Python代码中的step注释说明。
## 1. 基础流程
> ❗注意请优先参考SDK中自带demo的使用流程和说明。遇到错误请优先参考文件中的注释、解释、日志说明。
`infer_demo/demo_xx_xx.py`
```python
# 引入EasyEdge运行库
import BaiduAI.EasyEdge as edge
# 创建并初始化一个预测Progam选择合适的引擎
pred = edge.Program()
pred.init(model_dir={RES文件夹路径}, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
# 预测图像
res = pred.infer_image({numpy.ndarray的图片})
# 关闭结束预测Progam
pred.close()
```
`infer_demo/demo_serving.py`
```python
import BaiduAI.EasyEdge as edge
from BaiduAI.EasyEdge.serving import Serving
# 创建并初始化Http服务
server = Serving(model_dir={RES文件夹路径}, license=serial_key)
# 运行Http服务
# 请参考同级目录下demo_xx_xx.py里:
# pred.init(model_dir=xx, device=xx, engine=xx, device_id=xx)
# 对以下参数device\device_id和engine进行修改
server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 CPU
# server.run(host=host, port=port, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID) # x86_64 Nvidia GPU
# server.run(host=host, port=port, device=edge.Device.CPU, engine=edge.Engine.PADDLE_LITE) # armv8 CPU
```
## 2. 初始化
- 接口
```python
def init(self,
model_dir,
device=Device.CPU,
engine=Engine.PADDLE_FLUID,
config_file='conf.json',
preprocess_file='preprocess_args.json',
model_file='model',
params_file='params',
label_file='label_list.txt',
infer_cfg_file='infer_cfg.json',
device_id=0,
thread_num=1
):
"""
Args:
model_dir: str
device: BaiduAI.EasyEdge.Device比如Device.CPU
engine: BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID
config_file: str
preprocess_file: str
model_file: str
params_file: str
label_file: str 标签文件
infer_cfg_file: 包含预处理、后处理信息的文件
device_id: int 设备ID
thread_num: int CPU的线程数
Raises:
RuntimeError, IOError
Returns:
bool: True if success
"""
```
若返回不是True请查看输出日志排查错误原因。
## 3. SDK参数配置
使用 CPU 预测时,可以通过在 init 中设置 thread_num 使用多线程预测。如:
```python
pred.init(model_dir=_model_dir, device=edge.Device.CPU, engine=edge.Engine.PADDLE_FLUID, thread_num=4)
```
使用 GPU 预测时,可以通过在 init 中设置 device_id 指定需要的GPU device id。如
```python
pred.init(model_dir=_model_dir, device=edge.Device.GPU, engine=edge.Engine.PADDLE_FLUID, device_id=0)
```
## 4. 预测图像
- 接口
```python
def infer_image(self, img,
threshold=0.3,
channel_order='HWC',
color_format='BGR',
data_type='numpy')
"""
Args:
img: np.ndarray or bytes
threshold: float
only return result with confidence larger than threshold
channel_order: string
channel order HWC or CHW
color_format: string
color format order RGB or BGR
data_type: string
仅在图像分割时有意义。 'numpy' or 'string'
'numpy': 返回已解析的mask
'string': 返回未解析的mask游程编码
Returns:
list
"""
```
| 字段 | 类型 | 取值 | 说明 |
| ---------- | -------------------- | --------- | ------------------------ |
| confidence | float | 0~1 | 分类或检测的置信度 |
| label | string | | 分类或检测的类别 |
| index | number | | 分类或检测的类别 |
| x1, y1 | float | 0~1 | 物体检测,矩形的左上角坐标 (相对长宽的比例值) |
| x2, y2 | float | 0~1 | 物体检测,矩形的右下角坐标(相对长宽的比例值) |
| mask | string/numpy.ndarray | 图像分割的mask | |
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
可以参考 demo 文件中使用 opencv 绘制矩形的逻辑。
***结果示例***
i) 图像分类
```json
{
"index": 736,
"label": "table",
"confidence": 0.9
}
```
ii) 物体检测
```json
{
"index": 8,
"label": "cat",
"confidence": 1.0,
"x1": 0.21289,
"y1": 0.12671,
"x2": 0.91504,
"y2": 0.91211,
}
```
iii) 图像分割
```json
{
"name": "cat",
"score": 1.0,
"location": {
"left": ...,
"top": ...,
"width": ...,
"height": ...,
},
"mask": ...
}
```
mask字段中data_type为`numpy`时,返回图像掩码的二维数组
```text
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
其中1代表为目标区域0代表非目标区域
```
data_type为`string`mask的游程编码解析方式可参考 [demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
# FAQ
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

View File

@@ -0,0 +1,262 @@
# 简介
本文档以[千分类模型_MobileNetV3](https://ai.baidu.com/easyedge/app/openSource)为例介绍FastDeploy中的模型SDK在**Intel x86_64 /NVIDIA GPU、Windows操作系统** 的Python环境1HTTP服务化推理部署步骤2介绍推理全流程API方便开发者了解项目后二次开发。
如果开发者对C++语言的相关能力感兴趣可以参考Windows C++请参考[Windows C++环境下的推理部署](./Windows-CPP-SDK-Serving.md)文档。
<!--ts-->
* [简介](#简介)
* [环境准备](#环境准备)
* [1. SDK下载](#1-sdk下载)
* [2. Python环境](#2-python环境)
* [3. 安装依赖](#3-安装依赖)
* [3.1 安装paddlepaddle](#31-安装paddlepaddle)
* [3.2 安装EasyEdge Python Wheel 包](#32-安装easyedge-python-wheel-包)
* [快速开始](#快速开始)
* [1. 文件结构说明](#1-文件结构说明)
* [2. 测试Demo](#2-测试demo)
* [2.1 启动HTTP预测服务](#21-启动http预测服务)
* [HTTP API流程详解](#http-api流程详解)
* [1. 开启http服务](#1-开启http服务)
* [2. 请求http服务](#2-请求http服务)
* [2.1 http 请求方式:不使用图片base64格式](#21-http-请求方式不使用图片base64格式)
* [3. http返回数据](#3-http返回数据)
<!--te-->
# 环境准备
## 1. SDK下载
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。解压缩后的文件结构如下所示
```shell
EasyEdge-win-[部署芯片]
├── data # 模型文件资源文件夹,可替换为其他模型
├── ... # C++/C# 相关文件
├── python # Python SDK文件
├── EasyEdge.exe # 主程序
└── README.md # 环境说明
```
## 2. Python环境
> 当前SDK仅支持Python 3.7
打开命令行工具使用如下命令获取已安装的Python版本号。如果还没有安装Python环境可以前往[官网](https://www.python.org/)下载Python 3.7对应的安装程序,特别要注意勾上`Add Python 3.7 to PATH`然后点“Install Now”即可完成安装。
```shell
python --version
```
如果本机的版本不匹配,建议使用[pyenv](https://github.com/pyenv/pyenv)、[anaconda](https://www.anaconda.com/)等Python版本管理工具对Python SDK所在目录进行配置。
接着使用如下命令确认pip的版本是否满足要求要求pip版本为20.2.2或更高版本。详细的pip安装过程可以参考[官网教程](https://pip.pypa.io/en/stable/installation/)。
```shell
python -m pip --version
```
## 3. 安装依赖
### 3.1 安装paddlepaddle
根据具体的部署芯片CPU/GPU安装对应的PaddlePaddle的whl包。`x86_64 CPU` 平台可以使用如下命令进行安装:
```shell
python -m pip install paddlepaddle==2.2.2 -i https://mirror.baidu.com/pypi/simple
```
`NVIDIA GPU平台`的详细安装教程可以参考[官网Paddle安装教程](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)。
> 使用 NVIDIA GPU 预测时,必须满足:
>
> 1. 机器已安装 cuda, cudnn
>
> 2. 已正确安装对应 cuda 版本的paddle 版本
> 3. 通过设置环境变量`FLAGS_fraction_of_gpu_memory_to_use`设置合理的初始内存使用比例
### 3.2 安装EasyEdge Python Wheel 包
`python`目录下安装Python3.7版本对应的EasyEdge Wheel包。对`x86_64 CPU``x86_64 Nvidia GPU平台 `可以使用如下命令进行安装,具体名称以 Python SDK 包中的 whl 为准。
```shell
python -m pip install -U BaiduAI_EasyEdge_SDK-{SDK版本号}-cp37-cp37m-win_amd64.whl
```
# 快速开始
## 1. 文件结构说明
Python SDK文件结构如下
```shell
EasyEdge-win-[部署芯片]
├── data # 模型文件资源文件夹,可替换为其他模型
│ ├── model # 模型文件资源文件夹,可替换为其他模型
│ └── config # 配置文件
├── ... # C++/C# 相关文件
├── python # Python SDK文件
│ ├── # 特定Python 3.7版本的EasyEdge Wheel包, 二次开发可使用
│ ├── BaiduAI_EasyEdge_SDK-${SDK版本号}-cp37-cp37m-win_amd64.whl
│ ├── requirements.txt #
│ ├── infer_demo # demo体验完整文件
│ │ ├── demo_xxx.py # 包含前后处理的端到端推理demo文件
│ │ └── demo_serving.py # 提供http服务的demo文件
│ └── tensor_demo # tensor in/out demo文件
```
## 2. 测试Demo
### 2.1 启动HTTP预测服务
```shell
python demo_serving.py {模型model文件夹} {host, default 0.0.0.0} {port, default 24401}
```
成功启动后,终端中会显示如下字样。
```shell
2022-06-14 18:45:15 INFO [EasyEdge] [demo_serving.py:50] 21212: Init paddlefluid engine...
2022-06-14 18:45:16 INFO [EasyEdge] [demo_serving.py:50] 21212: Paddle version: 2.2.2
* Serving Flask app 'Serving' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on all addresses (0.0.0.0)
WARNING: This is a development server. Do not use it in a production deployment.
* Running on http://127.0.0.1:24401
* Running on http://192.168.3.17:24401 (Press CTRL+C to quit)
```
开发者此时可以打开浏览器,输入`http://{host ip}:24401`,选择图片或者视频来进行测试,运行效果如下。
<div align="center">
<img src="https://user-images.githubusercontent.com/54695910/175854073-fb8189e5-0ffb-472c-a17d-0f35aa6a8418.png" style="zoom:50%;" />
</div>
# HTTP API流程详解
本章节主要结合前文的Demo示例来对API进行介绍方便开发者学习并将运行库嵌入到开发者的程序当中更详细的API请参考对应的Python文件。http服务包含服务端和客户端Demo中提供了不使用图片base格式的`方式一:浏览器请求的方式`,其他几种方式开发者根据个人需要,选择开发。
## 1. 开启http服务
http服务的启动使用`demo_serving.py`文件
```python
class Serving(object):
""" SDK local serving """
def __init__(self, model_dir, license='', model_filename='model', params_filename='params'):
self.program = None
self.model_dir = model_dir
self.model_filename = model_filename
self.params_filename = params_filename
self.program_lock = threading.Lock()
self.license_key = license
# 只有ObjectTracking会初始化video_processor
self.video_processor = None
def run(self, host, port, device, engine=Engine.PADDLE_FLUID, service_id=0, device_id=0, **kwargs):
""" Args: host : str port : str device : BaiduAI.EasyEdge.Device比如Device.CPU engine : BaiduAI.EasyEdge.Engine 比如: Engine.PADDLE_FLUID """
self.run_serving_with_flask(host, port, device, engine, service_id, device_id, **kwargs)
```
## 2. 请求http服务
> 开发者可以打开浏览器,`http://{设备ip}:24401`,选择图片来进行测试。
### 2.1 http 请求方式:不使用图片base64格式
URL中的get参数
| 参数 | 说明 | 默认值 |
| --------- | --------- | ---------------- |
| threshold | 阈值过滤, 0~1 | 如不提供,则会使用模型的推荐阈值 |
HTTP POST Body即为图片的二进制内容。
Python请求示例
```python
import requests
with open('./1.jpg', 'rb') as f:
img = f.read()
result = requests.post(
'http://127.0.0.1:24401/',
params={'threshold': 0.1},
data=img).json()
```
## 3. http返回数据
| 字段 | 类型说明 | 其他 |
| ---------- | ------ | ------------------------------------ |
| error_code | Number | 0为成功,非0参考message获得具体错误信息 |
| results | Array | 内容为具体的识别结果。其中字段的具体含义请参考`预测图像-返回格式`一节 |
| cost_ms | Number | 预测耗时ms不含网络交互时间 |
返回示例
```json
{
"cost_ms": 52,
"error_code": 0,
"results": [
{
"confidence": 0.94482421875,
"index": 1,
"label": "IronMan",
"x1": 0.059185408055782318,
"x2": 0.18795496225357056,
"y1": 0.14762254059314728,
"y2": 0.52510076761245728,
"mask": "...", // 图像分割模型字段
"trackId": 0, // 目标追踪模型字段
},
]
}
```
***关于矩形坐标***
x1 * 图片宽度 = 检测框的左上角的横坐标
y1 * 图片高度 = 检测框的左上角的纵坐标
x2 * 图片宽度 = 检测框的右下角的横坐标
y2 * 图片高度 = 检测框的右下角的纵坐标
***关于分割模型***
其中mask为分割模型的游程编码解析方式可参考 [demo](https://github.com/Baidu-AIP/EasyDL-Segmentation-Demo)。
**FAQ**
1. 执行infer_demo文件时提示your generated code is out of date and must be regenerated with protoc >= 3.19.0
进入当前项目首先卸载protobuf
```shell
python3 -m pip uninstall protobuf
```
安装低版本protobuf
```shell
python3 -m pip install protobuf==3.19.0
```

212
docs/iOS-SDK.md Normal file
View File

@@ -0,0 +1,212 @@
# 简介
本文档介绍FastDeploy中的模型SDK在iOS环境下1推理部署步骤2介绍SDK使用说明方便开发者了解项目后二次开发。
<!--ts-->
* [简介](#简介)
* [系统支持说明](#系统支持说明)
* [1. 系统支持说明](#1-系统支持说明)
* [2. SDK大小说明](#2-sdk大小说明)
* [快速开始](#快速开始)
* [1. 项目结构说明](#1-项目结构说明)
* [2. 测试Demo](#2-测试demo)
* [SDK使用说明](#sdk使用说明)
* [1. 集成指南](#1-集成指南)
* [1.1 依赖库集成](#11-依赖库集成)
* [2. 调用流程示例](#2-调用流程示例)
* [2.1 初始化](#21-初始化)
* [2.2 预测图像](#22-预测图像)
* [FAQ](#faq)
<!--te-->
# 系统支持说明
## 1. 系统支持说明
1. 系统支持iOS 9.0及以上。
2. 硬件支持:支持 arm64 (Starndard architectures),暂不支持模拟器。
* 官方验证过的手机机型大部分ARM 架构的手机、平板及开发板。
3.其他说明
* 3.1 【图像分割类模型】1图像分割类Demo暂未提供实时摄像头录制拍摄的能力开发者可根据自己需要进行安卓开发完成2PP-Humanseg-Lite模型设计初衷为横屏视频会议等场景本次安卓开发仅支持述评场景开发者可根据自己需要开发横屏的Android功能。<br>
* 3.2 【OCR模型】OCR任务第一次启动任务第一张推理时间久属于正常情况因为涉及到模型加载、预处理等工作<br>
## 2. SDK大小说明
1. 模型资源文件大小影响 SDK 大小
2. SDK 包及 IPA 安装包虽然比较大,但最终安装到设备后所占大小会缩小很多。这与 multi architechtures、bitcode 和 AppStore 的优化有关。
# 快速开始
## 1. 项目结构说明
根据开发者模型、部署芯片、操作系统需要,在图像界面[飞桨开源模型](https://ai.baidu.com/easyedge/app/openSource)或[GIthub](https://github.com/PaddlePaddle/FastDeploy)中选择对应的SDK进行下载。SDK目录结构如下
```
.EasyEdge-iOS-SDK
├── EasyDLDemo # Demo工程文件
├── LIB # 依赖库
├── RES
│ ├── easyedge      # 模型资源文件夹一套模型适配不同硬件、OS和部署方式
│ ├── conf.json        # Android、iOS系统APP名字需要
│ ├── model # 模型结构文件
│ ├── params # 模型参数文件
│ ├── label_list.txt # 模型标签文件
│ ├── infer_cfg.json # 模型前后处理等配置文件
└── DOC # 文档
```
## 2. 测试Demo
按如下步骤可直接运行 SDK 体验 Demo
步骤一:用 Xcode 打开 `EasyDLDemo/EasyDLDemo.xcodeproj`
步骤二配置开发者自己的签名不了解签名机制的可以看FAQ [iOS签名介绍](#100)</br>
步骤三:连接手机运行,不支持模拟器
检测模型运行示例:
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854078-4f1f761d-0629-411a-92cc-6f4180164ca5.png" width="400"></div>
# SDK使用说明
本节介绍如何将 SDK 接入开发者的项目中使用。
## 1. 集成指南
步骤一:依赖库集成
步骤二:`import <EasyDL/EasyDL.h>`
### 1.1 依赖库集成
1. 复制 LIB 目录至项目合适的位置
2. 配置 Build Settings 中 Search paths: 以 SDK 中 LIB 目录路径为例
- Framework Search Paths`${PROJECT_DIR}/../LIB/lib`
- Header Search Paths`${PROJECT_DIR}/../LIB/include`
- Library Search Paths`${PROJECT_DIR}/../LIB/lib`
> 集成过程如出现错误,请参考 Demo 工程对依赖库的引用
## 2. 调用流程示例
以通用ARM的图像分类预测流程为例详细说明请参考后续章节
```
NSError *err;
// step 1: 初始化模型
EasyDLModel *model = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
// step 2: 准备待预测的图像
UIImage *image = ...;
// step 3: 预测图像
NSArray *results = [model detectUIImage:image withFilterScore:0 andError:&err];
// step 4: 解析结果
for (id res in results) {
EasyDLClassfiData *clsData = (EasyDLClassfiData *) res;
NSLog(@"labelIndex=%d, labelName=%@, confidence=%f", clsData.category, clsData.label, clsData.accuracy);
}
```
### 2.1 初始化
```
// 示例
// 参数一为模型资源文件夹名称
EasyDLModel *model = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
```
> 模型资源文件夹需以 folder reference 方式加入 Xcode 工程,如 `RES/easyedge` 文件夹在 Demo 工程中表现为蓝色
### 2.2 预测图像
所有模型类型通过以下接口获取预测结果:
```
// 返回的数组类型不定
NSArray *results = [model detectUIImage:image withFilterScore:0 andError:&err];
```
返回的数组类型如下,具体可参考 `EasyDLResultData.h` 中的定义:
| 模型类型 | 类型 |
| --- | ---- |
| 图像分类 | EasyDLClassfiData |
| 物体检测/人脸检测 | EasyDLObjectDetectionData |
| 实例分割 | EasyDLObjSegmentationData |
| 姿态估计 | EasyDLPoseData |
| 文字识别 | EasyDLOcrData |
# FAQ
1. 如何多线程并发预测?
SDK内部已经能充分利用多核的计算能力。不建议使用并发来预测。
如果开发者想并发使用,请务必注意`EasyDLModel`所有的方法都不是线程安全的。请初始化多个实例进行并发使用,如
```c
- (void)testMultiThread {
UIImage *img = [UIImage imageNamed:@"1.jpeg"];
NSError *err;
EasyDLModel * model1 = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
EasyDLModel * model2 = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
dispatch_queue_t queue1 = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("testQueue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
NSError *detectErr;
for(int i = 0; i < 1000; ++i) {
NSArray * res = [model1 detectUIImage:img withFilterScore:0 andError:&detectErr];
NSLog(@"1: %@", res[0]);
}
});
dispatch_async(queue2, ^{
NSError *detectErr;
for(int i = 0; i < 1000; ++i) {
NSArray * res = [model2 detectUIImage:img withFilterScore:0 andError:&detectErr];
NSLog(@"2: %@", res[0]);
}
});
}
```
2. 编译时出现 Undefined symbols for architecture arm64: ...
* 出现 `cxx11, vtable` 字样:请引入 `libc++.tbd`
* 出现 `cv::Mat` 字样:请引入 `opencv2.framework`
* 出现 `CoreML`, `VNRequest` 字样:请引入`CoreML.framework` 并务必`#import <CoreML/CoreML.h> `
3. 运行时报错 Image not found: xxx ...
请Embed具体报错的库。
4. 编译时报错Invalid bitcode version
这个可能是开发者使用的 Xcode 低于12导致可以升级至12版本。
5. 错误说明
SDK 的方法会返回 NSError直接返回的 NSError 的错误码定义在 `EasyDLDefine.h - EEasyDLErrorCode` 中。NSError 附带 message (有时候会附带 NSUnderlyingError开发者可根据 code 和 message 进行错误判断和处理。
6. iOS签名说明
iOS 签名是苹果生态对 APP 开发者做的限定对于个人开发者是免费的对于企业开发者譬如APP要上架应用市场是收费的。此处仅简单说明作为普通开发者第一次尝试使用 Xcode编译代码需要进行的签名操作。<br>
1在Xcode/Preferences/Accounts 中添加个人Apple ID;<br>
2在对应的EasyDLDemo中做如下图设置<br>
<div align=center><img src="https://user-images.githubusercontent.com/54695910/175854089-aa1d1af8-7daa-43ae-868d-32041c27ad86.jpg" width="600"></div>
32后会在手机上安装好对应APP还需要在手机上`设置/通用/设备管理/开发者应用/信任appleID`,才能运行该 APP。

199
fastdeploy/__init__.py Normal file
View File

@@ -0,0 +1,199 @@
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
from six import text_type as _text_type
from .download import download, download_and_decompress
import argparse
# Since the source code is not fully open sourced,
# currently we will provide the prebuilt library
# and demo codes
import os
__version__ = "0.1.0"
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument(
'--model',
type=_text_type,
default=None,
help='Name of model, which can be listed by --list_models')
parser.add_argument(
'--platform',
type=_text_type,
default=None,
help='Define platform, supports Windows/Linux/Android/iOS.')
parser.add_argument(
'--soc',
type=_text_type,
default=None,
help='Define soc for the platform, supports x86/x86-NVIDIA_GPU/ARM/jetson.'
)
parser.add_argument(
'--save_dir',
type=_text_type,
default=".",
help='Path to download and extract deployment SDK.')
parser.add_argument(
'--list_models',
required=False,
action="store_true",
default=False,
help='List all the supported models.')
parser.add_argument(
'--download_sdk',
required=False,
action="store_true",
default=False,
help='List all the supported models.')
return parser.parse_args()
def read_sources():
user_dir = os.path.expanduser('~')
print("Updating the newest sdk information...")
source_cfgs = "https://bj.bcebos.com/paddlehub/fastdeploy/fastdeploy_newest_sources.cfg.1"
if os.path.exists(os.path.join(user_dir, "fastdeploy_newest_sources.cfg.1")):
os.remove(os.path.join(user_dir, "fastdeploy_newest_sources.cfg.1"))
download(source_cfgs, user_dir)
categories = dict()
res = dict()
with open(os.path.join(user_dir, "fastdeploy_newest_sources.cfg.1")) as f:
for line in f:
if line.strip().startswith("#"):
continue
if line.strip() == "":
continue
category, model, plat, soc, url = line.strip().split('\t')
if category not in categories:
categories[category] = set()
categories[category].add(model)
if model not in res:
res[model] = dict()
if plat not in res[model]:
res[model][plat] = dict()
if soc not in res[model][plat]:
res[model][plat][soc] = dict()
res[model][plat][soc] = url
return categories, res
def main():
args = parse_arguments()
if not args.list_models and not args.download_sdk:
print(
"Please use flag --list_models to show all the supported models, or use flag --download_sdk to download the specify SDK to deploy you model."
)
return
categories, all_sources = read_sources()
all_models = list(all_sources.keys())
all_models.sort()
if args.list_models:
print("Currently, FastDeploy supports {} models, list as below,\n".format(
len(all_models)))
for k, v in categories.items():
print("\nModel Category: {}".format(k))
print("_"*100)
models = list(categories[k])
models.sort()
i = 0
while i < len(models):
if i == len(models) - 1:
print(models[i].center(30))
i += 1
elif i == len(models) - 2:
print(models[i].center(30), models[i+1].center(30))
i += 2
else:
print(models[i].center(30), models[i+1].center(30), models[i+2].center(30))
i += 3
return
if not os.path.exists(args.save_dir):
print("The specified save_dir: {} is not exist.".format(args.save_dir))
return
if args.model is None or args.model == "":
print(
"Please define --model to choose which kind of model to deploy, use --list_models to show all the supported models."
)
return
if args.model not in all_sources:
print(
"{} is not supported, use --list_models to list all the models FastDeploy supported.".
format(args.model))
return
if args.platform is None or args.platform == "":
print(
"Please define --platform to choose which platform to deploy, supports windows/linux/android/ios."
)
return
if args.platform not in all_sources[args.model]:
print(
"The model:{} only supports platform of {}, {} is not supported now.".
format(args.model,
list(all_sources[args.model].keys()), args.platform))
return
if args.soc is None or args.soc == "":
print(
"Please define --soc to choose which hardware to deploy, for model:{} and platform:{}, the available socs are {}.".
format(args.model, args.platform,
list(all_sources[args.model][args.platform].keys())))
return
if args.soc not in all_sources[args.model][args.platform]:
print(
"The model:{} in platform:{} only supports soc of {}, {} is not supported now.".
format(args.model, args.platform,
list(all_sources[args.model][args.platform].keys()),
args.soc))
return
print("\nDownloading SDK:",
all_sources[args.model][args.platform][args.soc])
save_dir = args.save_dir
sdk_name = os.path.split(all_sources[args.model][args.platform][args.soc])[
-1].strip()
if all_sources[args.model][args.platform][args.soc].count(".zip") > 0:
sdk_name = os.path.split(all_sources[args.model][args.platform][
args.soc])[-1].strip().split(".zip")[0]
new_save_dir = os.path.join(args.save_dir, sdk_name)
if not os.path.exists(new_save_dir):
os.mkdir(new_save_dir)
save_dir = new_save_dir
download_and_decompress(
all_sources[args.model][args.platform][args.soc],
new_save_dir,
rename=sdk_name + ".zip")
os.remove(os.path.join(new_save_dir, sdk_name + ".zip"))
print("Done. All the files of SDK have been extracted in {}.".format(
new_save_dir))
if __name__ == "__main__":
main()

18
fastdeploy/__main__.py Normal file
View File

@@ -0,0 +1,18 @@
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import fastdeploy
if __name__ == "__main__":
fastdeploy.main()

186
fastdeploy/download.py Normal file
View File

@@ -0,0 +1,186 @@
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import os.path as osp
import shutil
import requests
import time
import zipfile
import hashlib
import tqdm
import logging
DOWNLOAD_RETRY_LIMIT = 3
def md5check(fullname, md5sum=None):
if md5sum is None:
return True
logging.info("File {} md5 checking...".format(fullname))
md5 = hashlib.md5()
with open(fullname, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
md5.update(chunk)
calc_md5sum = md5.hexdigest()
if calc_md5sum != md5sum:
logging.info("File {} md5 check failed, {}(calc) != "
"{}(base)".format(fullname, calc_md5sum, md5sum))
return False
return True
def move_and_merge_tree(src, dst):
"""
Move src directory to dst, if dst is already exists,
merge src to dst
"""
if not osp.exists(dst):
shutil.move(src, dst)
else:
if not osp.isdir(src):
shutil.move(src, dst)
return
for fp in os.listdir(src):
src_fp = osp.join(src, fp)
dst_fp = osp.join(dst, fp)
if osp.isdir(src_fp):
if osp.isdir(dst_fp):
move_and_merge_tree(src_fp, dst_fp)
else:
shutil.move(src_fp, dst_fp)
elif osp.isfile(src_fp) and \
not osp.isfile(dst_fp):
shutil.move(src_fp, dst_fp)
def download(url, path, rename=None, md5sum=None, show_progress=False):
"""
Download from url, save to path.
url (str): download url
path (str): download to given path
"""
if not osp.exists(path):
os.makedirs(path)
fname = osp.split(url)[-1]
fullname = osp.join(path, fname)
if rename is not None:
fullname = osp.join(path, rename)
retry_cnt = 0
while not (osp.exists(fullname) and md5check(fullname, md5sum)):
if retry_cnt < DOWNLOAD_RETRY_LIMIT:
retry_cnt += 1
else:
logging.debug("{} download failed.".format(fname))
raise RuntimeError("Download from {} failed. "
"Retry limit reached".format(url))
logging.info("Downloading {} from {}".format(fname, url))
req = requests.get(url, stream=True)
if req.status_code != 200:
raise RuntimeError("Downloading from {} failed with code "
"{}!".format(url, req.status_code))
# For protecting download interupted, download to
# tmp_fullname firstly, move tmp_fullname to fullname
# after download finished
tmp_fullname = fullname + "_tmp"
total_size = req.headers.get('content-length')
with open(tmp_fullname, 'wb') as f:
if total_size and show_progress:
for chunk in tqdm.tqdm(
req.iter_content(chunk_size=1024),
total=(int(total_size) + 1023) // 1024,
unit='KB'):
f.write(chunk)
else:
for chunk in req.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
shutil.move(tmp_fullname, fullname)
logging.debug("{} download completed.".format(fname))
return fullname
def decompress(fname):
"""
Decompress for zip and tar file
"""
logging.info("Decompressing {}...".format(fname))
# For protecting decompressing interupted,
# decompress to fpath_tmp directory firstly, if decompress
# successed, move decompress files to fpath and delete
# fpath_tmp and remove download compress file.
fpath = osp.split(fname)[0]
fpath_tmp = osp.join(fpath, 'tmp')
if osp.isdir(fpath_tmp):
shutil.rmtree(fpath_tmp)
os.makedirs(fpath_tmp)
if fname.find('.tar') >= 0 or fname.find('.tgz') >= 0:
with tarfile.open(fname) as tf:
tf.extractall(path=fpath_tmp)
elif fname.find('.zip') >= 0:
with zipfile.ZipFile(fname) as zf:
zf.extractall(path=fpath_tmp)
else:
raise TypeError("Unsupport compress file type {}".format(fname))
for f in os.listdir(fpath_tmp):
src_dir = osp.join(fpath_tmp, f)
dst_dir = osp.join(fpath, f)
move_and_merge_tree(src_dir, dst_dir)
shutil.rmtree(fpath_tmp)
logging.debug("{} decompressed.".format(fname))
return dst_dir
def url2dir(url, path, rename=None):
full_name = download(url, path, rename, show_progress=True)
print("SDK is donwloaded, now extracting...")
if url.count(".tgz") > 0 or url.count(".tar") > 0 or url.count("zip") > 0:
return decompress(full_name)
def download_and_decompress(url, path='.', rename=None):
fname = osp.split(url)[-1]
fullname = osp.join(path, fname)
# if url.endswith(('tgz', 'tar.gz', 'tar', 'zip')):
# fullname = osp.join(path, fname.split('.')[0])
nranks = 0
if nranks <= 1:
dst_dir = url2dir(url, path, rename)
if dst_dir is not None:
fullname = dst_dir
else:
lock_path = fullname + '.lock'
if not os.path.exists(fullname):
with open(lock_path, 'w'):
os.utime(lock_path, None)
if local_rank == 0:
dst_dir = url2dir(url, path, rename)
if dst_dir is not None:
fullname = dst_dir
os.remove(lock_path)
else:
while os.path.exists(lock_path):
time.sleep(1)
return

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
tqdm
six

34
setup.py Normal file
View File

@@ -0,0 +1,34 @@
import setuptools
import fastdeploy
import io
import os
with open("requirements.txt") as fin:
REQUIRED_PACKAGES = fin.read()
def read(*names, **kwargs):
with io.open(
os.path.join(os.path.dirname(__file__), *names),
encoding=kwargs.get("encoding", "utf8")) as fp:
return fp.read()
setuptools.setup(
name="fastdeploy-python",
version=fastdeploy.__version__,
author="FastDeploy",
author_email="fastdeploy@baidu.com",
description="FastDeploy is a toolkit to deploy deeplearning models.",
long_description=read("README.md"),
long_description_content_type="text/markdown",
url="https://github.com/PaddlePaddle/FastDeploy",
packages=setuptools.find_packages(),
install_requires=REQUIRED_PACKAGES,
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
],
license='Apache 2.0',
entry_points={
'console_scripts': ['fastdeploy=fastdeploy.__init__:main', ]
})