未验证 提交 d80081ad 编写于 作者: 走神的阿圆's avatar 走神的阿圆 提交者: GitHub

Merge branch 'develop' into add_stat

......@@ -38,8 +38,8 @@
* [超参优化AutoDL Finetuner使用](./autofinetune)
该样例展示了PaddleHub超参优化AutoDL Finetuner如何使用,给出了自动搜素图像分类/文本分类任务的较佳超参数示例。
* [服务化部署Hub Serving使用](./serving)
该样例文件夹下展示了服务化部署Hub Serving如何使用,将PaddleHub支持的可预测Module如何服务化部署。
* [服务化部署PaddleHub Serving使用](./serving)
该样例文件夹下展示了服务化部署PaddleHub Serving如何使用,将PaddleHub支持的可预测Module如何服务化部署。
**NOTE:**
以上任务示例均是利用PaddleHub提供的数据集,若您想在自定义数据集上完成相应任务,请查看[PaddleHub适配自定义数据完成FineTune](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E9%80%82%E9%85%8D%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E5%AE%8C%E6%88%90FineTune)
......
......@@ -87,12 +87,13 @@ if __name__ == '__main__':
add_crf=True)
# Data to be predicted
# If using python 2, prefix "u" is necessary
data = [
["我们变而以书会友,以书结缘,把欧美、港台流行的食品类图谱、画册、工具书汇集一堂。"],
["为了跟踪国际最新食品工艺、流行趋势,大量搜集海外专业书刊资料是提高技艺的捷径。"],
["其中线装古籍逾千册;民国出版物几百种;珍本四册、稀见本四百余册,出版时间跨越三百余年。"],
["有的古木交柯,春机荣欣,从诗人句中得之,而入画中,观之令人心驰。"],
["不过重在晋趣,略增明人气息,妙在集古有道、不露痕迹罢了。"],
[u"我们变而以书会友,以书结缘,把欧美、港台流行的食品类图谱、画册、工具书汇集一堂。"],
[u"为了跟踪国际最新食品工艺、流行趋势,大量搜集海外专业书刊资料是提高技艺的捷径。"],
[u"其中线装古籍逾千册;民国出版物几百种;珍本四册、稀见本四百余册,出版时间跨越三百余年。"],
[u"有的古木交柯,春机荣欣,从诗人句中得之,而入画中,观之令人心驰。"],
[u"不过重在晋趣,略增明人气息,妙在集古有道、不露痕迹罢了。"],
]
# Add 0x02 between characters to match the format of training data,
......
## 数据格式
input: {files: {"image": [file_1, file_2, ...]}}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m vgg11_imagenet
```
## python脚本
```shell
$ python vgg11_imagenet_serving_demo.py
```
## 结果示例
```python
{
"results": "[[{'Egyptian cat': 0.540287435054779}], [{'daisy': 0.9976677298545837}]]"
}
```
结果含有生成图片的base64编码,可提取生成图片,示例python脚本生成图片位置为当前目录下的output文件夹下。
## 数据格式
#### 模型所需参数可通过嵌套字典形式传递
input: {files: {"image": [file_1, file_2, ...]}, data: {...}}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m stgan_celeba
```
## python脚本
```shell
$ python yolov3_coco2017_serving_demo.py
```
## 结果示例
```python
[
{
"path": "cat.jpg",
"data": [
{
"left": 322.2323,
"right": 1420.4119,
"top": 208.81363,
"bottom": 996.04395,
"label": "cat",
"confidence": 0.9289875
}
]
},
{
"path": "dog.jpg",
"data": [
{
"left": 204.74722,
"right": 746.02637,
"top": 122.793274,
"bottom": 566.6292,
"label": "dog",
"confidence": 0.86698055
}
]
}
]
```
结果含有生成图片的base64编码,可提取生成图片,示例python脚本生成图片位置为当前目录下的output文件夹下。
## 数据格式
input: {"text": [text_1, text_2, ...]}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m lm_lstm
```
## python脚本
```shell
$ python lm_lstm_serving_demo.py
```
## 结果示例
```python
{
"results": [
{
"perplexity": 4.584166451916099,
"text": "the plant which is owned by <unk> & <unk> co. was under contract with <unk> to make the cigarette filter"
},
{
"perplexity": 6.038358983397484,
"text": "more common <unk> fibers are <unk> and are more easily rejected by the body dr. <unk> explained"
}
]
}
```
## 数据格式
input: {"text": [text_1, text_2, ...]}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m lac
```
## python脚本
#### 不携带用户自定义词典
```shell
$ python lac_no_dict_serving_demo.py
```
#### 携带用户自定义词典
```shell
$ python lac_with_dict_serving_demo.py
```
## 结果示例
```python
{
"results": [
{
"tag": [
"TIME",
"v",
"q",
"n"
],
"word": [
"今天",
"是",
"个",
"好日子"
]
},
{
"tag": [
"n",
"v",
"TIME",
"v",
"v"
],
"word": [
"天气预报",
"说",
"今天",
"要",
"下雨"
]
}
]
}
```
## 数据格式
input: {files: {"image": [file_1, file_2, ...]}}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m yolov3_coco2017
```
## python脚本
```shell
$ python yolov3_coco2017_serving_demo.py
```
## 结果示例
```python
[
{
"path": "cat.jpg",
"data": [
{
"left": 322.2323,
"right": 1420.4119,
"top": 208.81363,
"bottom": 996.04395,
"label": "cat",
"confidence": 0.9289875
}
]
},
{
"path": "dog.jpg",
"data": [
{
"left": 204.74722,
"right": 746.02637,
"top": 122.793274,
"bottom": 566.6292,
"label": "dog",
"confidence": 0.86698055
}
]
}
]
```
结果含有生成图片的base64编码,可提取生成图片,示例python脚本生成图片位置为当前目录下的output文件夹下。
# PaddleHub-Serving
## 1. 简介
利用PaddleHub-Serving可以完成模型服务化部署,主要包括利用Bert as Service实现embedding服务化,利用预测模型实现预测服务化。
# PaddleHub Serving
## 简介
### 背景
使用PaddleHub能够完成预训练模型的管理和预测,但开发者还经常面临将模型部署上线以对外提供服务的需求,而利用PaddleHub Serving可便捷的将模型部署上线,开发者只需要关注如何处理输入数据和输出结果即可。
### 主要功能
PaddleHub Serving是基于PaddleHub的一键模型服务部署工具,能够通过简单的Hub命令行工具轻松启动一个模型预测在线服务。
## 2. Bert as Service
* [Bert as Service介绍与示例](bert_service)
PaddleHub Serving主要包括利用Bert Service实现embedding服务化,以及利用预测模型实现预训练模型预测服务化两大功能,未来还将支持开发者使用PaddleHub Fine-tune API的模型服务化。
该示例展示了利用Bert as Service进行远程embedding服务化部署和在线预测,获取文本embedding结果。
## Bert Service
`Bert Service`是基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)框架的快速部署模型远程计算服务方案,可将embedding过程通过调用API接口的方式实现,减少了对机器资源的依赖。使用PaddleHub可在服务器上一键部署`Bert Service`服务,在另外的普通机器上通过客户端接口即可轻松的获取文本对应的embedding数据。
## 3. Serving
模型预测服务化有以下示例:
关于其具体信息和demo请参见[Bert Service](../../tutorial/bert_service.md)
* [图像分类-基于vgg11_imagent](./Classification_vgg11_imagenet)
该示例展示了利用`Bert Service`进行远程embedding服务化部署和在线预测,并获取文本embedding结果。
该示例展示了利用vgg11_imagent完成图像分类服务化部署和在线预测,获取图像分类结果。
## 预训练模型一键服务部署
预训练模型一键服务部署是基于PaddleHub的预训练模型快速部署的服务化方案,能够将模型预测以API接口的方式实现。
* [图像生成-基于stgan_celeba](./GAN_stgan_celeba)
关于预训练模型一键服务部署的具体信息请参见[PaddleHub Serving](../../tutorial/serving.md)
该示例展示了利用stgan_celeba生成图像服务化部署和在线预测,获取指定风格的生成图像。
预训练模型一键服务部署包括以下示例:
* [英文词法分析-基于lm_lstm](./Language_Model_lm_lstm)
* [图像分类-基于vgg11_imagent](module_serving/classification_vgg11_imagenet)
该示例展示了利用lm_lstm完成英文语法分析服务化部署和在线预测,获取文本的流利程度
&emsp;&emsp;该示例展示了利用vgg11_imagent完成图像分类服务化部署和在线预测,获取图像分类结果
* [中文词法分析-基于lac](./Lexical_Analysis_lac)
* [图像生成-基于stgan_celeba](module_serving/GAN_stgan_celeba)
该示例展示了利用lac完成中文文本分词服务化部署和在线预测,获取文本的分词结果,并可通过用户自定义词典干预分词结果
&emsp;&emsp;该示例展示了利用stgan_celeba生成图像服务化部署和在线预测,获取指定风格的生成图像
* [目标检测-基于yolov3_coco2017](./Object_Detection_yolov3_coco2017)
* [文本审核-基于porn_detection_lstm](module_serving/text_censorship_porn_detection_lstm)
该示例展示了利用yolov3_coco2017完成目标检测服务化部署和在线预测,获取检测结果和覆盖识别框的图片
&emsp;&emsp;该示例展示了利用porn_detection_lstm完成中文文本黄色敏感信息鉴定的服务化部署和在线预测,获取文本是否敏感及其置信度
* [中文语义分析-基于simnet_bow](./Semantic_Model_simnet_bow)
* [中文词法分析-基于lac](module_serving/lexical_analysis_lac)
该示例展示了利用simnet_bow完成中文文本相似度检测服务化部署和在线预测,获取文本的相似程度。
&emsp;&emsp;该示例展示了利用lac完成中文文本分词服务化部署和在线预测,获取文本的分词结果,并可通过用户自定义词典干预分词结果。
* [图像分割-基于deeplabv3p_xception65_humanseg](./Semantic_Segmentation_deeplabv3p_xception65_humanseg)
* [目标检测-基于yolov3_darknet53_coco2017](module_serving/object_detection_yolov3_darknet53_coco2017)
该示例展示了利用deeplabv3p_xception65_humanseg完成图像分割服务化部署和在线预测,获取识别结果和分割后的图像
&emsp;&emsp;该示例展示了利用yolov3_darknet53_coco2017完成目标检测服务化部署和在线预测,获取检测结果和覆盖识别框的图片
* [中文情感分析-基于senta_lstm](./Sentiment_Analysis_senta_lstm)
* [中文语义分析-基于simnet_bow](module_serving/semantic_model_simnet_bow)
该示例展示了利用senta_lstm完成中文文本情感分析服务化部署和在线预测,获取文本的情感分析结果。
&emsp;&emsp;该示例展示了利用simnet_bow完成中文文本相似度检测服务化部署和在线预测,获取文本的相似程度。
* [图像分割-基于deeplabv3p_xception65_humanseg](module_serving/semantic_segmentation_deeplabv3p_xception65_humanseg)
&emsp;&emsp;该示例展示了利用deeplabv3p_xception65_humanseg完成图像分割服务化部署和在线预测,获取识别结果和分割后的图像。
* [中文情感分析-基于simnet_bow](module_serving/semantic_model_simnet_bow)
&emsp;&emsp;该示例展示了利用senta_lstm完成中文文本情感分析服务化部署和在线预测,获取文本的情感分析结果。
关于Paddle Serving预训练模型一键服务部署功能的具体信息请参见[Module Serving](module_serving)
## 数据格式
input: {"text1": [text_a1, text_a2, ...], "text2": [text_b1, text_b2, ...]}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m simnet_bow
```
## python脚本
```shell
$ python simnet_bow_serving_demo.py
```
## 结果示例
```python
{
"results": [
{
"similarity": 0.8445,
"text_1": "这道题太难了",
"text_2": "这道题是上一年的考题"
},
{
"similarity": 0.9275,
"text_1": "这道题太难了",
"text_2": "这道题不简单"
},
{
"similarity": 0.9083,
"text_1": "这道题太难了",
"text_2": "这道题很有意思"
}
]
}
```
## 数据格式
input: {files: {"image": [file_1, file_2, ...]}}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m deeplabv3p_xception65_humanseg
```
## python脚本
```shell
$ python deeplabv3p_xception65_humanseg_serving_demo.py
```
## 结果示例
```python
[
{
"origin": "girl.jpg",
"processed": "humanseg_output/girl_2.png"
}
]
```
结果含有生成图片的base64编码,可提取生成图片,示例python脚本生成图片位置为当前目录下的output文件夹中。
## 数据格式
input: {"text": [text_1, text_2, ...]}
output: {"results":[result_1, result_2, ...]}
## Serving快速启动命令
```shell
$ hub serving start -m senta_lstm
```
## python脚本
``` shell
$ python senta_lstm_serving_demo.py
```
## 结果示例
```python
{
"results": [
{
"negative_probs": 0.7079,
"positive_probs": 0.2921,
"sentiment_key": "negative",
"sentiment_label": 0,
"text": "我不爱吃甜食"
},
{
"negative_probs": 0.0149,
"positive_probs": 0.9851,
"sentiment_key": "positive",
"sentiment_label": 1,
"text": "我喜欢躺在床上看电影"
}
]
}
```
# Bert Service
## 1. 简介
### 1.1 什么是Bert Service
`Bert Service`是基于Paddle Serving框架的快速部署模型远程计算服务方案,可将embedding过程通过调用API接口的方式实现,减少了对机器资源的依赖。使用PaddleHub可在服务器上一键部署`Bert Service`服务,在另外的普通机器上通过客户端接口即可轻松的获取文本对应的embedding数据。
## 简介
### 什么是Bert Service
`Bert Service`是基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)框架的快速部署模型远程计算服务方案,可将embedding过程通过调用API接口的方式实现,减少了对机器资源的依赖。使用PaddleHub可在服务器上一键部署`Bert Service`服务,在另外的普通机器上通过客户端接口即可轻松的获取文本对应的embedding数据。
整体流程图如下:
**NOTE:** 关于`Bert Service`的更多信息请参见[Bert Serving](../../../tutorial/bert_service.md)
<div align="center">
<img src="./img/bs.png" aligh="center" width="100%" alt="BS流程图" />
</div>
### 1.2 为什么使用Bert Service
* 算力有限的集群环境中,可利用一台或几台高性能机器部署`Bert Service`服务端,为全部机器提供在线embedding功能。
* 实际的生产服务器不适宜承担大批量embedding工作,通过API接口可减少资源占用。
* 专注下游深度学习任务,可利用PaddleHub的`Bert Service`大幅减少embedding代码。
`Bert as Service`具有几个突出的优点:
* 代码精短,易于使用。简单的pip安装方式,服务端仅需一行命令即可启动,客户端仅需一行代码即可获取embedding结果。
* 更高性能,更高效率。通过Paddle AnalysisPredictor API对模型的计算图进行优化,提升了计算速度并减小了显存占用。
* 随"机"应变,灵活扩展。可根据机器资源选择不同数量的服务端,并根据实际需求快速、灵活地进行增减,同时支持各张显卡执行不同的模型计算任务。
* 删繁就简,专注任务。`Bert Service`基于PaddlePaddle和PaddleHub开发,将模型的下载和安装等管理工作交由PaddleHub,开发者可以专注于主要任务,还可以无缝对接PaddleHub继续进行文本分类、序列标注等下游任务。
## 2. 环境准备
### 2.1 环境要求
下表是使用`Bert Service`的环境要求,带有*号标志项为非必需依赖,可根据实际使用需求选择安装。
|项目|版本|说明|
|:-:|:-:|:-:|
|操作系统|Linux|目前仅支持Linux操作系统|
|PaddleHub|>=1.4.0|无|
|PaddlePaddle|>=1.6.1|若使用GPU计算,则对应使用PaddlePaddle-gpu版本|
|GCC|>=4.8|无|
|CUDA*|>=8|若使用GPU,需使用CUDA8以上版本|
|paddle-gpu-serving*|>=0.8.0|在`Bert Service`服务端需依赖此包|
|ujson*|>=1.35|在`Bert Service`客户端需依赖此包|
### 2.2 安装步骤
a) 安装PaddlePaddle,利用pip下载CPU版本命令如下。GPU版本、Docker方式安装等其他更具体的安装过程见[开始使用PaddlePaddle](https://paddlepaddle.org.cn/install/quick)
```shell
$ # 安装paddlepaddle的CPU版本
$ pip install paddlepaddle
```
b) 安装PaddleHub
```shell
$ pip install paddlehub
```
c) server端,需另外安装`paddle-gpu-serving`,以获取快速部署服务的能力
```shell
$ pip install paddle-gpu-serving
```
d) client端,需另外安装ujson
```shell
$ pip install ujson
```
## 3. 支持模型
目前`Bert Service`支持的语义模型如下表,可根据需要选择模型进行部署embedding服务,未来还将支持更多模型。
|模型|网络|
|:-|:-:|
|[ernie](https://paddlepaddle.org.cn/hubdetail?name=ERNIE&en_category=SemanticModel)|ERNIE|
|[ernie_tiny](https://paddlepaddle.org.cn/hubdetail?name=ernie_tiny&en_category=SemanticModel)|ERNIE|
|[ernie_v2_eng_large](https://paddlepaddle.org.cn/hubdetail?name=ernie_v2_eng_large&en_category=SemanticModel)|ERNIE|
|[ernie_v2_eng_base](https://paddlepaddle.org.cn/hubdetail?name=ernie_v2_eng_base&en_category=SemanticModel)|ERNIE|
|[roberta_wwm_ext_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=roberta_wwm_ext_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[roberta_wwm_ext_chinese_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=roberta_wwm_ext_chinese_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_wwm_ext_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_wwm_ext_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_uncased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_uncased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_uncased_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=bert_uncased_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_cased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_cased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_cased_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=bert_cased_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_multi_cased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_multi_cased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
## 4. 服务端(server)
### 4.1 简介
server端接收client端发送的数据,执行模型计算过程并将计算结果返回给client端。
server端启动时会按照指定的模型名称从PaddleHub获取对应的模型文件进行加载,无需提前下载模型或指定模型路径,对模型的管理工作由PaddleHub负责。在加载模型后在指定的端口启动`BRPC`服务,保持端口监听,当接收到数据后便执行模型计算,并将计算结果通过`BRPC`返回并发送至client端。
### 4.2 启动
使用PaddleHub的命令行工具可一键启动`Bert Service`,命令如下:
```shell
$ hub serving start bert_service -m ernie_tiny -p 8866 --use_gpu --gpu 0
```
启动成功则显示
```shell
Server[baidu::paddle_serving::predictor::bert_service::BertServiceImpl] is serving on port=8866.
```
整个启动过程如下图:
<div align="center">
&emsp;&emsp;<img src="https://github.com/ShenYuhan/ml-python/blob/master/short_start_fast.gif" aligh="center" width="70%" alt="启动BS" />
</div>
其中各参数说明如下表:
<div align="center">
|参数|说明|是否必填|
|:--:|:--:|:----:|
|hub serving start bert_service|启动`Bert Service`服务端。|必填项|
|--module/-m|指定启动的模型,如果指定的模型不存在,则自动通过PaddleHub下载指定模型。|必填项|
|--port/-p|指定启动的端口,每个端口对应一个模型,可基于不同端口进行多次启动,以实现多个模型的服务部署。|必填项|
|--use_gpu|若指定此项则使用GPU进行工作,反之仅使用CPU。注意需安装GPU版本的PaddlePaddle。|非必填项,默认为不指定|
|--gpu|指定使用的GPU卡号,如未指定use_gpu则填写此项无效,每个服务对应一张卡,部署多个服务时需指定不同卡|非必填项,默认为0号显卡|
</div>
### 4.3 关闭
通过在启动服务端的命令行页面使用Ctrl+C终止`Bert Service`运行,关闭成功则显示:
```shell
Paddle Inference Server exit successfully!
```
## 5.客户端(client)
### 5.1 简介
client端接收文本数据,并获取server端返回的模型计算的embedding结果。
client端利用PaddleHub的语义理解任务将原始文本按照不同模型的数据预处理方案将文本ID化,并生成对应的sentence type、position、input masks数据,将这些信息封装成json数据,通过http协议按照指定的IP端口信息发送至server端,等待并获取模型生成结果。
### 5.2 启动
连接服务端方法原型为:
```python
def connect(input_text,
model_name,
max_seq_len=128,
show_ids=False,
do_lower_case=True,
server="127.0.0.1:8866",
retry=3)
```
其中各参数说明如下表:
|参数|说明|类型|样例|
|:--:|:--:|:--:|:--:|
|input_text|输入文本,要获取embedding的原始文本|二维list类型,内部元素为string类型的文本|[['样例1'],['样例2']]|
|model_name|指定使用的模型名称|string|"ernie"|
|max_seq_len|计算时的样例长度,样例长度不足时采用补零策略,超出此参数则超出部分会被截断|int|128|
|show_ids|是否展现数据预处理后的样例信息,指定为True则显示样例信息,反之则不显示|bool|False|
|do_lower_case|是否将英文字母转换成小写,指定为True则将所有英文字母转换为小写,反之则保持原状|bool|True|
|server|要访问的server地址,包括ip地址及端口号|string|"127.0.0.1:8866"|
|retry|连接失败后的最大重试次数|int|3|
## 6. Demo
## Demo——利用Bert Service部署ernie_tiny在线embedding服务
在这里,我们将展示一个实际场景中可能使用的demo,我们利用PaddleHub在一台GPU机器上部署`ernie_tiny`模型服务,并在另一台CPU机器上尝试访问,获取一首七言绝句的embedding。
### 6.1 安装环境依赖
### Step1:安装环境依赖
首先需要安装环境依赖,根据第2节内容分别在两台机器上安装相应依赖。
### 6.2 启动Bert Service服务端
### Step2:启动Bert Service服务端
确保环境依赖安装正确后,在要部署服务的GPU机器上使用PaddleHub命令行工具启动`Bert Service`服务端,命令如下:
```shell
$ hub serving start bert_service -m ernie_tiny --use_gpu --gpu 0 --port 8866
```
启动成功后打印
启动成功后打印
```shell
Server[baidu::paddle_serving::predictor::bert_service::BertServiceImpl] is serving on port=8866.
```
这样就启动了`ernie_tiny`的在线服务,监听8866端口,并在0号GPU上进行任务。
### 6.3 使用Bert Service客户端进行远程调用
### Step3:使用Bert Service客户端进行远程调用
部署好服务端后,就可以用普通机器作为客户端测试在线embedding功能。
首先导入客户端依赖。
......@@ -182,7 +28,7 @@ Server[baidu::paddle_serving::predictor::bert_service::BertServiceImpl] is servi
from paddlehub.serving.bert_serving import bs_client
```
接着启动并初始化`bert service`客户端`BSClient`(这里的server为虚拟地址,需根据自己实际ip设置)
接着启动并初始化`bert service`客户端`BSClient`(这里的server为虚拟地址,需根据自己实际ip设置)
```python
bc = bs_client.BSClient(module_name="ernie_tiny", server="127.0.0.1:8866")
```
......@@ -200,7 +46,7 @@ result = bc.get_result(input_text=input_text)
```python
[[0.9993321895599361, 0.9994612336158751, 0.9999646544456481, 0.732795298099517, -0.34387934207916204, ... ]]
```
客户端代码demo文件见[示例](bert_service_client.py)
客户端代码demo文件见[示例](../paddlehub/serving/bert_serving/bert_service.py)
运行命令如下:
```shell
$ python bert_service_client.py
......@@ -214,30 +60,12 @@ $ python bert_service_client.py
</div>
### 6.4 关闭Bert Service服务端
### Step4:关闭Bert Service服务端
如要停止`Bert Service`服务端程序,可在其启动命令行页面使用Ctrl+C方式关闭,关闭成功会打印如下日志:
```shell
Paddle Inference Server exit successfully!
```
这样,我们就利用一台GPU机器就完成了`Bert Service`的部署,并利用另一台普通机器进行了测试,可见通过`Bert Service`能够方便地进行在线embedding服务的快速部署。
## 7. FAQ
> Q : 如何在一台服务器部署多个模型?
> A : 可通过多次启动`Bert Service`,分配不同端口实现。如果使用GPU,需要指定不同的显卡。如同时部署`ernie`和`bert_chinese_L-12_H-768_A-12`,分别执行命令如下:
> ```shell
> $ hub serving start bert_service -m ernie -p 8866
> $ hub serving start bert_service -m bert_chinese_L-12_H-768_A-12 -p 8867
> ```
> Q : 启动时显示"Check out http://yq01-gpu-255-129-12-00.epc.baidu.com:8887 in web
browser.",这个页面有什么作用。
> A : 这是`BRPC`的内置服务,主要用于查看请求数、资源占用等信息,可对server端性能有大致了解,具体信息可查看[BRPC内置服务](https://github.com/apache/incubator-brpc/blob/master/docs/cn/builtin_service.md)。
> Q : 为什么输入文本的格式为[["文本1"], ["文本2"], ],而不是["文本1", "文本2", ]?
> A : 因为Bert模型可以对一轮对话生成向量表示,例如[["问题1","回答1"],["问题2","回答2"]],为了防止使用时混乱,每个样本使用一个list表示,一个样本list内部可以是1条string或2条string,如下面的文本:
> ```python
> input_text = [
> ["你今天吃饭了吗","我已经吃过饭了"],
> ["今天天气怎么样","今天天气不错"],
> ]
> ```
## 预训练模型一键服务部署
除了`Bert Service`外,PaddleHub Serving还具有预训练模型一键服务部署功能,能够将预训练模型快捷部署上线,对外提供可靠的在线预测服务,具体信息请参见[Module Serving](../../../tutorial/serving.md)
# 部署图像生成服务-以stgan_celeba为例
## 简介
图像生成是指根据预先设置的标签,生成对应图像的过程。stgan_celeba通过在GAN中加入encoder-decoder,可实现人脸属性的转换。关于stgan_celeba的具体信息请参见[stgan_celeba](https://paddlepaddle.org.cn/hubdetail?name=stgan_celeba&en_category=GANs)
使用PaddleHub Serving可以轻松部署一个在线图像生成服务API,可将此API接入自己的web网站,也可接入应用程序,如美图类应用,实现传照片修饰脸的功能。
下面就带领大家使用PaddleHub Serving,通过简单几步部署一个图像生成服务。
## Step1:启动PaddleHub Serving
启动命令如下:
```shell
$ hub serving start -m stgan_celeba
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading stgan_celeba successful.
```
这样就完成了一个图像生成服务化API的部署,默认端口号为8866。
## Step2:测试图像生成在线API
我们用来测试的样例图片为:
<p align="center">
<img src="../../../../docs/imgs/man.png" width="30%" />
</p>
根据stgan_celeba所需信息,准备的数据包括图像文件和生成图像风格,格式为:
```python
files = [("image", file_a), ("image", file_b)]
data = {"info": ["info_a_1, info_a_2", "info_b_1, info_b_2"], "style": ["style_a", "style_b"]}
```
**NOTE:** 文件列表每个元素第一个参数为"image"。
info为图像描述,根据示例图像信息,info应为"Male,Black_Hair,Eyeglasses,No_Beard",即"男性,黑发,戴眼镜,没有胡子"。
image为要生成的图像风格,我们选取"Bald"(秃顶的)作为生成图像的风格。
代码如下:
```python
>>> # 指定要使用的图片文件并生成列表[("image", img_1), ("image", img_2), ... ]
>>> file_list = ["../img/man.png"]
>>> files = [("image", (open(item, "rb"))) for item in file_list]
>>> # 为每张图片对应指定info和style
>>> data = {"info": ["Male,Black_Hair,Eyeglasses,No_Beard"], "style": ["Bald"]}
```
## Step3:获取并验证结果
然后就可以发送请求到图像生成服务API,并得到结果,代码如下:
```python
>>> url = "http://127.0.0.1:8866/predict/image/stgan_celeba"
>>> r = requests.post(url=url, data=data, files=files)
```
stgan_celeba返回的结果包括生成图像的base64编码格式,经过转换可以得到生成图像,代码如下:
```python
>>> for item in results:
... with open(output_path, "wb") as fp:
... fp.write(base64.b64decode(item["base64"].split(',')[-1]))
```
查看指定输出文件夹,就能看到生成图像了,如图:
<p align="center">
<img src="./stgan_output/Bald_man.png" width="30%" />
</p>
这样我们就完成了对图像生成服务化的部署和测试。
完整的测试代码见[stgan_celeba_serving_demo.py](stgan_celeba_serving_demo.py)
......@@ -6,20 +6,21 @@ import os
if __name__ == "__main__":
# 指定要使用的图片文件并生成列表[("image", img_1), ("image", img_2), ... ]
file_list = ["../img/woman.png"]
file_list = ["../img/man.png"]
files = [("image", (open(item, "rb"))) for item in file_list]
# 为每张图片对应指定info和style
data = {"info": ["Female,Brown_Hair"], "style": ["Aged"]}
data = {"info": ["Male,Black_Hair"], "style": ["Bald"]}
# 指定图片生成方法为stgan_celeba并发送post请求
url = "http://127.0.0.1:8866/predict/image/stgan_celeba"
r = requests.post(url=url, data=data, files=files)
print(r.text)
results = eval(r.json()["results"])
# 保存生成的图片到output文件夹,打印模型输出结果
if not os.path.exists("output"):
os.mkdir("output")
if not os.path.exists("stgan_output"):
os.mkdir("stgan_output")
for item in results:
output_path = os.path.join("output", item["path"].split("/")[-1])
output_path = os.path.join("stgan_output", item["path"].split("/")[-1])
with open(output_path, "wb") as fp:
fp.write(base64.b64decode(item["base64"].split(',')[-1]))
item.pop("base64")
......
# PaddleHub Serving模型一键服务部署
## 简介
### 为什么使用一键服务部署
使用PaddleHub能够快速进行模型预测,但开发者常面临本地预测过程迁移线上的需求。无论是对外开放服务端口,还是在局域网中搭建预测服务,都需要PaddleHub具有快速部署模型预测服务的能力。在这个背景下,模型一键服务部署工具——PaddleHub Serving应运而生。开发者通过一行命令即可快速启动一个模型预测在线服务,而无需关注网络框架选择和实现。
### 什么是一键服务部署
PaddleHub Serving是基于PaddleHub的一键模型服务部署工具,能够通过简单的Hub命令行工具轻松启动一个模型预测在线服务,前端通过Flask和Gunicorn完成网络请求的处理,后端直接调用PaddleHub预测接口,同时支持使用多进程方式利用多核提高并发能力,保证预测服务的性能。
### 支持模型
目前PaddleHub Serving支持PaddleHub所有可直接用于预测的模型进行服务部署,包括`lac``senta_bilstm`等NLP类模型,以及`yolov3_darknett53_coco2017``vgg16_imagenet`等CV类模型,未来还将支持开发者使用PaddleHub Fine-tune API得到的模型用于快捷服务部署。
**NOTE:** 关于PaddleHub Serving一键服务部署的具体信息请参见[PaddleHub Serving](../../../tutorial/serving.md)
## Demo
获取PaddleHub Serving的一键服务部署场景示例,可参见下列demo:
* [图像分类-基于vgg11_imagent](../module_serving/classification_vgg11_imagenet)
&emsp;&emsp;该示例展示了利用vgg11_imagent完成图像分类服务化部署和在线预测,获取图像分类结果。
* [图像生成-基于stgan_celeba](../module_serving/GAN_stgan_celeba)
&emsp;&emsp;该示例展示了利用stgan_celeba生成图像服务化部署和在线预测,获取指定风格的生成图像。
* [文本审核-基于porn_detection_lstm](../module_serving/text_censorship_porn_detection_lstm)
&emsp;&emsp;该示例展示了利用porn_detection_lstm完成中文文本黄色敏感信息鉴定的服务化部署和在线预测,获取文本是否敏感及其置信度。
* [中文词法分析-基于lac](../module_serving/lexical_analysis_lac)
&emsp;&emsp;该示例展示了利用lac完成中文文本分词服务化部署和在线预测,获取文本的分词结果,并可通过用户自定义词典干预分词结果。
* [目标检测-基于yolov3_darknet53_coco2017](../module_serving/object_detection_yolov3_darknet53_coco2017)
&emsp;&emsp;该示例展示了利用yolov3_darknet53_coco2017完成目标检测服务化部署和在线预测,获取检测结果和覆盖识别框的图片。
* [中文语义分析-基于simnet_bow](../module_serving/semantic_model_simnet_bow)
&emsp;&emsp;该示例展示了利用simnet_bow完成中文文本相似度检测服务化部署和在线预测,获取文本的相似程度。
* [图像分割-基于deeplabv3p_xception65_humanseg](../module_serving/semantic_segmentation_deeplabv3p_xception65_humanseg)
&emsp;&emsp;该示例展示了利用deeplabv3p_xception65_humanseg完成图像分割服务化部署和在线预测,获取识别结果和分割后的图像。
* [中文情感分析-基于simnet_bow](../module_serving/semantic_model_simnet_bow)
&emsp;&emsp;该示例展示了利用senta_lstm完成中文文本情感分析服务化部署和在线预测,获取文本的情感分析结果。
## Bert Service
除了预训练模型一键服务部署功能之外,PaddleHub Serving还具有`Bert Service`功能,支持ernie_tiny、bert等模型快速部署,对外提供可靠的在线embedding服务,具体信息请参见[Bert Service](../../../tutorial/bert_service.md)
# 部署图像分类服务-以vgg11_imagenent为例
## 简介
图像分类是指通过模型,预测给定的图片所属类别,vgg11_imagenent就是一种有效的图像分类模型。关于vgg11_imagenent的具体信息请参见[vgg11_imagenent](https://paddlepaddle.org.cn/hubdetail?name=vgg11_imagenet&en_category=ImageClassification)
使用PaddleHub Serving可以部署一个在线图片分类服务,既可以对用户暴露直接预测接口,也可以利用此接口实现一个web网站,甚至可以集成到移动端应用程序中实现拍照识别功能。
这里就带领大家使用PaddleHub Serving,通过简单几步部署一个图像分类服务。
## Step1:启动PaddleHub Serving
启动命令如下:
```shell
$ hub serving start -m vgg11_imagenet
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading vgg11_imagenet successful.
```
这样就完成了一个图像分类服务化API的部署,默认端口号为8866。
## Step2:测试图像分类在线API
我们用来测试的样例图片为:
<p align="center">
<img src="../../../../docs/imgs/cat.jpg" width="45%" />
</p>
<p align="center">
<img src="../../../../docs/imgs/flower.jpg" width="45%"/>
</p>
准备的数据格式为:
```python
files = [("image", file_1), ("image", file_2)]
```
**NOTE:** 每个元素第一个参数为"image"。
代码如下:
```python
>>> file_list = ["../img/cat.jpg", "../img/flower.jpg"]
>>> files = [("image", (open(item, "rb"))) for item in file_list]
```
## Step3:获取并验证结果
然后就可以发送请求到图像分类服务API,并得到结果了,代码如下:
```python
>>> # 指定检测方法为vgg11_imagenet并发送post请求
>>> url = "http://127.0.0.1:8866/predict/image/vgg11_imagenet"
>>> r = requests.post(url=url, files=files)
```
vgg11_imagenent返回的结果为图像分类结果及其对应的概率,我们尝试打印接口返回结果:
```python
>>> print(json.dumps(r.json(), indent=4, ensure_ascii=False))
{
"results": "[[{'Egyptian cat': 0.540287435054779}], [{'daisy': 0.9976677298545837}]]"
}
```
这样我们就完成了对图像分类预测服务化部署和测试。
完整的测试代码见[vgg11_imagenent_serving_demo.py](vgg11_imagenet_serving_demo.py)
# 部署词法分析服务-以lac为例
## 简介
`Lexical Analysis of Chinese`,简称`LAC`,是一个联合的词法分析模型,能整体性地完成中文分词、词性标注、专名识别任务。关于`LAC`的具体信息请参见[LAC](https://paddlepaddle.org.cn/hubdetail?name=lac&en_category=LexicalAnalysis)
使用PaddleHub Serving可以部署一个在线词法分析服务,可以将此接口用于词法分析、在线分词等在线web应用。
这里就带领大家使用PaddleHub Serving,通过简单几步部署一个词法分析在线服务。
## Step1:启动PaddleHub Serving
启动命令如下
```shell
$ hub serving start -m lac
```
启动时会显示加载模型过程,启动成功后显示
```shell
Loading lac successful.
```
这样就完成了一个词法分析服务化API的部署,默认端口号为8866。
## Step2:测试语言模型在线API
### 不使用自定义词典
在服务部署好之后,我们可以进行测试,用来测试的文本为`今天是个好日子``天气预报说今天要下雨`
准备的数据格式为:
```python
{"text": [text_1, text_2, ...]}
```
**NOTE:** 字典的key为"text"。
根据文本和数据格式,代码如下:
```python
>>> # 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
>>> text_list = ["今天是个好日子", "天气预报说今天要下雨"]
>>> text = {"text": text_list}
```
## Step3:获取并验证结果
接下来发送请求到词法分析API,并得到结果,代码如下:
```python
# 指定预测方法为lac并发送post请求
>>> url = "http://127.0.0.1:8866/predict/text/lac"
>>> r = requests.post(url=url, data=text)
```
`LAC`模型返回的结果为每个文本分词后的结果,我们尝试打印接口返回结果:
```python
# 打印预测结果
>>> print(json.dumps(r.json(), indent=4, ensure_ascii=False))
{
"results": [
{
"tag": [
"TIME",
"v",
"q",
"n"
],
"word": [
"今天",
"是",
"个",
"好日子"
]
},
{
"tag": [
"n",
"v",
"TIME",
"v",
"v"
],
"word": [
"天气预报",
"说",
"今天",
"要",
"下雨"
]
}
]
}
```
这样我们就完成了对词法分析的预测服务化部署和测试。
完整的测试代码见[lac_serving_demo.py](lac_serving_demo.py)
### 使用自定义词典
`LAC`模型在预测时还可以使用自定义词典干预默认分词结果,这种情况只需要将自定义词典以文件的形式附加到request请求即可,数据格式如下:
```python
{"user_dict": user_dict.txt}
```
根据数据格式,具体代码如下:
```python
>>> # 指定自定义词典{"user_dict": dict.txt}
>>> file = {"user_dict": open("dict.txt", "rb")}
>>> # 请求接口时以文件的形式附加自定义词典,其余和不使用自定义词典的请求方式相同,此处不再赘述
>>> url = "http://127.0.0.1:8866/predict/text/lac"
>>> r = requests.post(url=url, files=file, data=text)
```
完整的测试代码见[lac_with_dict_serving_demo.py](lac_with_dict_serving_demo.py)
......@@ -3,7 +3,7 @@ import requests
import json
if __name__ == "__main__":
# 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
# 指定用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = ["今天是个好日子", "天气预报说今天要下雨"]
text = {"text": text_list}
# 指定预测方法为lac并发送post请求
......
......@@ -3,7 +3,7 @@ import requests
import json
if __name__ == "__main__":
# 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
# 指定用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = ["今天是个好日子", "天气预报说今天要下雨"]
text = {"text": text_list}
# 指定自定义词典{"user_dict": dict.txt}
......
# 部署图像分类服务-以yolov3_darknet53_coco2017为例
## 简介
目标检测作为深度学习常见任务,在各种场景下都有所使用。使用`yolov3_darknet53_coco2017`模型可以进行目标检测任务,关于`yolov3_darknet53_coco2017`的具体信息请参见[yolov3_darknet53_coco2017](https://paddlepaddle.org.cn/hubdetail?name=yolov3_darknet53_coco2017&en_category=ObjectDetection)
使用PaddleHub Serving可以轻松部署一个在线目标检测服务API,可将此API接入自己的web网站进行在线目标检测,也可接入移动端应用程序,实现识图、圈人等功能。
下面就带领大家使用PaddleHub Serving,通过简单几步部署一个目标检测服务。
## Step1:启动PaddleHub Serving
启动命令如下:
```shell
$ hub serving start -m yolov3_darknet53_coco2017
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading yolov3_darknet53_coco2017 successful.
```
这样就完成了一个图像生成服务化API的部署,默认端口号为8866。
## Step2:测试图像生成在线API
我们用来测试的样例图片为:
<p align="center">
<img src="../../../../docs/imgs/cat.jpg" width="65%" />
</p>
<p align="center">
<img src="../../../../docs/imgs/dog.jpg" width="65%" />
</p>
准备的数据格式为:
```python
files = [("image", file_1), ("image", file_2)]
```
**NOTE:** 文件列表每个元素第一个参数为"image"。
代码如下:
```python
>>> # 指定要检测的图片并生成列表[("image", img_1), ("image", img_2), ... ]
>>> file_list = ["../img/cat.jpg", "../img/dog.jpg"]
>>> files = [("image", (open(item, "rb"))) for item in file_list]
```
## Step3:获取并验证结果
然后就可以发送请求到目标检测服务API,并得到结果,代码如下:
```python
>>> # 指定检测方法为yolov3_darknet53_coco2017并发送post请求
>>> url = "http://127.0.0.1:8866/predict/image/yolov3_darknet53_coco2017"
>>> r = requests.post(url=url, files=files)
```
我们可以打印接口返回结果:
```python
>>> results = eval(r.json()["results"])
>>> print(json.dumps(results, indent=4, ensure_ascii=False))
[
{
"path": "cat.jpg",
"data": [
{
"left": 319.489,
"right": 1422.8364,
"top": 208.94229,
"bottom": 993.8552,
"label": "cat",
"confidence": 0.9174191
}
]
},
{
"path": "dog.jpg",
"data": [
{
"left": 200.6918,
"right": 748.96204,
"top": 122.74927,
"bottom": 566.2066,
"label": "dog",
"confidence": 0.83619183
},
{
"left": 506.8462,
"right": 623.2322,
"top": 378.0084,
"bottom": 416.116,
"label": "tie",
"confidence": 0.5082839
}
]
}
]
```
根据结果可以看出准确识别了请求的图片。
yolov3_darknet53_coco2017返回的结果还包括标注检测框的图像的base64编码格式,经过转换可以得到生成图像,代码如下:
```python
>>> for item in results:
... with open(output_path, "wb") as fp:
... fp.write(base64.b64decode(item["base64"].split(',')[-1]))
```
查看指定输出文件夹,就能看到生成图像了,如图:
<p align="center">
<img src="./output/cat.jpg" width="65%" />
</p>
<p align="center">
<img src="./output/dog.jpg" width="65%" />
</p>
这样我们就完成了对目标检测服务化的部署和测试。
完整的测试代码见[yolov3_darknet53_coco2017_serving_demo.py](yolov3_darknet53_coco2017_serving_demo.py)
......@@ -9,7 +9,7 @@ if __name__ == "__main__":
file_list = ["../img/cat.jpg", "../img/dog.jpg"]
files = [("image", (open(item, "rb"))) for item in file_list]
# 指定检测方法为yolov3_coco2017并发送post请求
url = "http://127.0.0.1:8866/predict/image/yolov3_coco2017"
url = "http://127.0.0.1:8866/predict/image/yolov3_darknet53_coco2017"
r = requests.post(url=url, files=files)
results = eval(r.json()["results"])
......
# 部署语义模型服务-以simnet_bow为例
## 简介
`simnet_bow`是一个计算短文本相似度的模型,可以根据用户输入的两个文本,计算出相似度得分。关于`simnet_bow`的具体信息请参见[simnet_bow](https://paddlepaddle.org.cn/hubdetail?name=simnet_bow&en_category=SemanticModel)
使用PaddleHub Serving可以部署一个在线语义模型服务,可以将此接口用于在线文本相似度分析、智能问答检索等应用。
这里就带领大家使用PaddleHub Serving,通过简单几步部署一个语义模型在线服务。
## Step1:启动PaddleHub Serving
启动命令如下:
```shell
$ hub serving start -m simnet_bow
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading lac successful.
```
这样就完成了一个语义模型服务化API的部署,默认端口号为8866。
## Step2:测试语义模型在线API
在服务部署好之后,我们可以进行测试,用来测试的文本对分别为`[这道题太难了:这道题是上一年的考题], [这道题太难了:这道题不简单], [这道题太难了:这道题很有意思]`
准备的数据格式为:
```python
{"text_1": [text_a1, text_a2, ... ], "text_2": [text_b1, text_b2, ... ]}
```
**NOTE:** 字典的key分别为"text_1"和"text_2",与`simnet_bow`模型使用的输入数据一致。
根据文本和数据格式,代码如下:
```python
>>> # 指定用于用于匹配的文本并生成字典{"text_1": [text_a1, text_a2, ... ]
>>> # "text_2": [text_b1, text_b2, ... ]}
>>> text = {
>>> "text_1": ["这道题太难了", "这道题太难了", "这道题太难了"],
>>> "text_2": ["这道题是上一年的考题", "这道题不简单", "这道题很有意思"]
>>> }
```
## Step3:获取并验证结果
接下来发送请求到语义模型API,并得到结果,代码如下:
```python
>>> # 指定匹配方法为simnet_bow并发送post请求
>>> url = "http://127.0.0.1:8866/predict/text/simnet_bow"
>>> r = requests.post(url=url, data=text)
```
`simnet_bow`模型返回的结果为每对文本对比后的相似度,我们尝试打印接口返回结果:
```python
# 打印预测结果
>>> print(json.dumps(r.json(), indent=4, ensure_ascii=False))
{
"results": [
{
"similarity": 0.8445,
"text_1": "这道题太难了",
"text_2": "这道题是上一年的考题"
},
{
"similarity": 0.9275,
"text_1": "这道题太难了",
"text_2": "这道题不简单"
},
{
"similarity": 0.9083,
"text_1": "这道题太难了",
"text_2": "这道题很有意思"
}
]
}
```
这样我们就完成了对语义模型simnet_bow的预测服务化部署和测试。
完整的测试代码见[simnet_bow_serving_demo.py](simnet_bow_serving_demo.py)
......@@ -3,7 +3,7 @@ import requests
import json
if __name__ == "__main__":
# 指定用于用于匹配的文本并生成字典{"text_1": [text_a1, text_a2, ... ]
# 指定用于匹配的文本并生成字典{"text_1": [text_a1, text_a2, ... ]
# "text_2": [text_b1, text_b2, ... ]}
text = {
"text_1": ["这道题太难了", "这道题太难了", "这道题太难了"],
......
# 部署图像分割服务-以deeplabv3p_xception65_humanseg为例
## 简介
图像分割是深度学习的常见任务。使用`deeplabv3p_xception65_humanseg`模型可以进行人像分割任务,关于`deeplabv3p_xception65_humanseg`的具体信息请参见[deeplabv3p_xception65_humanseg](https://paddlepaddle.org.cn/hubdetail?name=deeplabv3p_xception65_humanseg&en_category=ImageSegmentation)
使用PaddleHub Serving可以轻松部署一个在线图像分割服务API,可将此API接入自己的web网站进行在线图像分割,也可接入移动端应用程序,实现拍照分割等功能。
下面就带领大家使用PaddleHub Serving,通过简单几步部署一个目标检测服务。
## Step1:启动PaddleHub Serving
启动命令如下
```shell
$ hub serving start -m deeplabv3p_xception65_humanseg
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading deeplabv3p_xception65_humanseg successful.
```
这样就完成了一个图像分割服务化API的部署,默认端口号为8866。
## Step2:测试图像分割在线API
我们用来测试的样例图片为:
<p align="center">
<img src="../img/girl.jpg" width="65%" />
</p>
准备的数据格式为:
```python
files = [("image", file_1), ("image", file_2)]
```
**NOTE:** 文件列表每个元素第一个参数为"image"。
代码如下
```python
>>> # 指定要检测的图片并生成列表[("image", img_1), ("image", img_2), ... ]
>>> file_list = ["../../../../docs/imgs/girl.jpg"]
>>> files = [("image", (open(item, "rb"))) for item in file_list]
```
## Step3:获取并验证结果
然后就可以发送请求到图像分割服务API,并得到结果,代码如下:
```python
>>> # 指定检测方法为deeplabv3p_xception65_humanseg并发送post请求
>>> url = "http://127.0.0.1:8866/predict/image/deeplabv3p_xception65_humanseg"
>>> r = requests.post(url=url, files=files)
```
我们可以打印接口返回结果:
```python
>>> results = eval(r.json()["results"])
>>> print(json.dumps(results, indent=4, ensure_ascii=False))
[
{
"origin": "girl.jpg",
"processed": "humanseg_output/girl.png"
}
]
```
deeplabv3p_xception65_humanseg返回的结果还包括人像分割后的图像的base64编码格式,经过转换可以得到生成图像,代码如下:
```python
>>> for item in results:
... with open(output_path, "wb") as fp:
... fp.write(base64.b64decode(item["base64"].split(',')[-1]))
```
查看指定输出文件夹,就能看到生成图像了,如图:
<p align="center">
<img src="./output/girl.png" width="65%" />
</p>
这样我们就完成了对图像分割模型deeplabv3p_xception65_humanseg服务化的部署和测试。
完整的测试代码见[deeplabv3p_xception65_humanseg_serving_demo.py](deeplabv3p_xception65_humanseg_serving_demo.py)
# 部署情感分析服务-以senta_lstm为例
## 简介
情感分析针对带有主观描述的中文文本,可自动判断该文本的情感极性类别并给出相应的置信度。利用`senta_lstm`模型可以完成中文情感分析任务,关于`senta_lstm`的具体信息请参见[senta_lstm]
(https://paddlepaddle.org.cn/hubdetail?name=senta_lstm&en_category=SentimentAnalysis)。
使用PaddleHub Serving可以部署一个在线情感分析服务,可以将此接口用于分析评论、智能客服等应用。
这里就带领大家使用PaddleHub Serving,通过简单几步部署一个情感分析在线服务。
## Step1:启动PaddleHub Serving
启动命令如下
```shell
$ hub serving start -m senta_lstm
```
启动时会显示加载模型过程,启动成功后显示
```shell
Loading senta_lstm successful.
```
这样就完成了一个词法分析服务化API的部署,默认端口号为8866。
## Step2:测试词法分析在线API
在服务部署好之后,我们可以进行测试,用来测试的文本为`我不爱吃甜食``我喜欢躺在床上看电影`
准备的数据格式为:
```python
{"text": [text_1, text_2, ...]}
```
**NOTE:** 字典的key为"text"。
根据文本和数据格式,代码如下:
```python
>>> # 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
>>> text_list = ["我不爱吃甜食", "我喜欢躺在床上看电影"]
>>> text = {"text": text_list}
```
## Step3:获取并验证结果
接下来发送请求到词法分析API,并得到结果,代码如下:
```python
# 指定预测方法为lac并发送post请求
>>> url = "http://127.0.0.1:8866/predict/text/senta_lstm"
>>> r = requests.post(url=url, data=text)
```
`LAC`模型返回的结果为每个文本分词后的结果,我们尝试打印接口返回结果:
```python
# 打印预测结果
>>> print(json.dumps(r.json(), indent=4, ensure_ascii=False))
{
"results": [
{
"tag": [
"TIME",
"v",
"q",
"n"
],
"word": [
"今天",
"是",
"个",
"好日子"
]
},
{
"tag": [
"n",
"v",
"TIME",
"v",
"v"
],
"word": [
"天气预报",
"说",
"今天",
"要",
"下雨"
]
}
]
}
```
这样我们就完成了对词法分析的预测服务化部署和测试。
完整的测试代码见[senta_lstm_serving_demo.py](senta_lstm_serving_demo.py)
......@@ -3,7 +3,7 @@ import requests
import json
if __name__ == "__main__":
# 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
# 指定用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = ["我不爱吃甜食", "我喜欢躺在床上看电影"]
text = {"text": text_list}
# 指定预测方法为senta_lstm并发送post请求
......
# 部署文本审核服务-以porn_detection_lstm为例
## 简介
在网站建设等场景中经常需要对敏感信息进行鉴定和过滤,采用文本审核模型`porn_detection_lstm`可自动判别文本是否涉黄并给出相应的置信度,关于`porn_detection_lstm`的具体信息请参见[porn_detection_lstm](https://paddlepaddle.org
.cn/hubdetail?name=porn_detection_lstm&en_category=TextCensorship)
使用PaddleHub Serving可以部署一个在线文本审核服务,可以将此接口用于防止低俗交友、色情文本等应用。
这里就带领大家使用PaddleHub Serving,通过简单几步部署一个文本审核在线服务。
## Step1:启动PaddleHub Serving
启动命令如下:
```shell
$ hub serving start -m porn_detection_lstm
```
启动时会显示加载模型过程,启动成功后显示:
```shell
Loading porn_detection_lstm successful.
```
这样就完成了一个文本审核服务化API的部署,默认端口号为8866。
## Step2:测试文本审核在线API
在服务部署好之后,我们可以进行测试,用来测试的文本为`黄片下载``中国黄页`
准备的数据格式为:
```python
{"text": [text_1, text_2, ...]}
```
**NOTE:** 字典的key为"text"。
根据文本和数据格式,代码如下:
```python
>>> # 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
>>> text_list = ["黄片下载", "中国黄页"]
>>> text = {"text": text_list}
```
## Step3:获取并验证结果
接下来发送请求到文本审核API,并得到结果,代码如下:
```python
# 指定预测方法为lac并发送post请求
>>> url = "http://127.0.0.1:8866/predict/text/porn_detection_lstm"
>>> r = requests.post(url=url, data=text)
```
`porn_detection_lstm`模型返回的结果为每个文本鉴定后的结果,我们尝试打印接口返回结果:
```python
# 打印预测结果
>>> print(json.dumps(r.json(), indent=4, ensure_ascii=False))
{
"results": [
{
"not_porn_probs": 0.0121,
"porn_detection_key": "porn",
"porn_detection_label": 1,
"porn_probs": 0.9879,
"text": "黄片下载"
},
{
"not_porn_probs": 0.9954,
"porn_detection_key": "not_porn",
"porn_detection_label": 0,
"porn_probs": 0.0046,
"text": "中国黄页"
}
]
}
```
可以看出正确得到了两个文本的预测结果。
这样我们就完成了对文本审核模型的预测服务化部署和测试。
完整的测试代码见[porn_detection_lstm_serving_demo.py](porn_detection_lstm_serving_demo.py)
......@@ -3,14 +3,11 @@ import requests
import json
if __name__ == "__main__":
# 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = [
"the plant which is owned by <unk> & <unk> co. was under contract with <unk> to make the cigarette filter",
"more common <unk> fibers are <unk> and are more easily rejected by the body dr. <unk> explained"
]
# 指定用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = ["黄片下载", "中国黄页"]
text = {"text": text_list}
# 指定预测方法为lm_lstm并发送post请求
url = "http://127.0.0.1:8866/predict/text/lm_lstm"
# 指定预测方法为lac并发送post请求
url = "http://127.0.0.1:8866/predict/text/porn_detection_lstm"
r = requests.post(url=url, data=text)
# 打印预测结果
......
......@@ -69,7 +69,7 @@ class MPIHelper(object):
def split_range(self, array_length):
if self._size == 1:
return 0, array_length
average_count = array_length / self._size
average_count = array_length // self._size
if array_length % self._size == 0:
return average_count * self._rank, average_count * (self._rank + 1)
else:
......
......@@ -223,7 +223,7 @@ class AutoFineTuneCommand(BaseCommand):
"\tsaved_params_dir\n")
print(
"The related infomation about hyperparamemters searched are saved as %s/log_file.txt ."
"The related information about hyperparamemters searched are saved as %s/log_file.txt ."
% autoft._output_dir)
for solution, modeldir in solutions_modeldirs.items():
param = evaluator.convert_params(solution)
......
......@@ -31,6 +31,7 @@ import multiprocessing
import time
import signal
if platform.system() == "Windows":
class StandaloneApplication(object):
......
......@@ -43,7 +43,7 @@ THIRD_PARTY_HOME = os.path.join(gen_hub_home(), "thirdparty")
TMP_HOME = os.path.join(gen_hub_home(), "tmp")
if not os.path.exists(TMP_HOME):
os.mkdir(TMP_HOME)
os.makedirs(TMP_HOME)
@contextlib.contextmanager
......
......@@ -128,7 +128,7 @@ class BaseDataset(object):
def num_labels(self):
return len(self.label_list)
# To compatibility with the usage of ImageClassificationDataset
# To be compatible with ImageClassificationDataset
def label_dict(self):
return {index: key for index, key in enumerate(self.label_list)}
......@@ -167,7 +167,7 @@ class BaseDataset(object):
def _load_label_data(self):
with open(os.path.join(self.base_path, self.label_file), "r") as file:
return file.read().split("\n")
return file.read().strip().split("\n")
def __str__(self):
return "Dataset: %s with %i train examples, %i dev examples and %i test examples" % (
......
......@@ -24,7 +24,11 @@ import copy
import logging
import inspect
from functools import partial
import six
if six.PY2:
from inspect import getargspec as get_args
else:
from inspect import getfullargspec as get_args
import numpy as np
import paddle.fluid as fluid
from tb_paddle import SummaryWriter
......@@ -129,7 +133,7 @@ class TaskHooks():
"name: %s has existed in hook_type:%s, use modify method to modify it"
% (name, hook_type))
else:
args_num = len(inspect.getfullargspec(func).args)
args_num = len(get_args(func).args)
if args_num != self._hook_params_num[hook_type]:
raise ValueError(
"The number of parameters to the hook hook_type:%s should be %i"
......@@ -249,16 +253,11 @@ class BaseTask(object):
self.exe = fluid.Executor(place=self.place)
self.build_strategy = fluid.BuildStrategy()
# log item
if not os.path.exists(self.config.checkpoint_dir):
mkdir(self.config.checkpoint_dir)
tb_log_dir = os.path.join(self.config.checkpoint_dir, "visualization")
self.tb_writer = SummaryWriter(tb_log_dir)
# run environment
self._phases = []
self._envs = {}
self._predict_data = None
self._tb_writer = None
# event hooks
self._hooks = TaskHooks()
......@@ -559,6 +558,15 @@ class BaseTask(object):
return [metric.name for metric in self.metrics] + [self.loss.name]
return [output.name for output in self.outputs]
@property
def tb_writer(self):
if not os.path.exists(self.config.checkpoint_dir):
mkdir(self.config.checkpoint_dir)
tb_log_dir = os.path.join(self.config.checkpoint_dir, "visualization")
if not self._tb_writer:
self._tb_writer = SummaryWriter(tb_log_dir)
return self._tb_writer
def create_event_function(self, hook_type):
def hook_function(self, *args):
for name, func in self._hooks[hook_type].items():
......
......@@ -26,6 +26,7 @@ import json
from collections import OrderedDict
import io
import numpy as np
import paddle.fluid as fluid
from .base_task import BaseTask
......@@ -517,13 +518,13 @@ class ReadingComprehensionTask(BaseTask):
null_score_diff_threshold=self.null_score_diff_threshold,
is_english=self.is_english)
if self.phase == 'val' or self.phase == 'dev':
with open(
with io.open(
self.data_reader.dataset.dev_path, 'r',
encoding="utf8") as dataset_file:
dataset_json = json.load(dataset_file)
dataset = dataset_json['data']
elif self.phase == 'test':
with open(
with io.open(
self.data_reader.dataset.test_path, 'r',
encoding="utf8") as dataset_file:
dataset_json = json.load(dataset_file)
......
......@@ -232,6 +232,6 @@ class SequenceLabelTask(BaseTask):
for length in seq_lens:
seq_infers = batch_infers[current_id:current_id + length]
seq_result = list(map(id2label.get, seq_infers[1:-1]))
current_id += self.max_seq_len
current_id += length if self.add_crf else self.max_seq_len
results.append(seq_result)
return results
......@@ -23,13 +23,14 @@ import shutil
from functools import cmp_to_key
import tarfile
import paddlehub as hub
from paddlehub.common import utils
from paddlehub.common.downloader import default_downloader
from paddlehub.common.dir import MODULE_HOME
from paddlehub.common.cml_utils import TablePrinter
from paddlehub.module import module_desc_pb2
import paddlehub as hub
from paddlehub.common.logger import logger
from paddlehub.common import tmp_dir
from paddlehub.module import module_desc_pb2
class LocalModuleManager(object):
......@@ -87,12 +88,96 @@ class LocalModuleManager(object):
extra=None):
md5_value = installed_module_version = None
from_user_dir = True if module_dir else False
if module_name:
self.all_modules(update=True)
module_info = self.modules_dict.get(module_name, None)
if module_info:
if not module_version or module_version == self.modules_dict[
module_name][1]:
with tmp_dir() as _dir:
if module_name:
self.all_modules(update=True)
module_info = self.modules_dict.get(module_name, None)
if module_info:
if not module_version or module_version == self.modules_dict[
module_name][1]:
module_dir = self.modules_dict[module_name][0]
module_tag = module_name if not module_version else '%s-%s' % (
module_name, module_version)
tips = "Module %s already installed in %s" % (
module_tag, module_dir)
return True, tips, self.modules_dict[module_name]
search_result = hub.HubServer().get_module_url(
module_name, version=module_version, extra=extra)
name = search_result.get('name', None)
url = search_result.get('url', None)
md5_value = search_result.get('md5', None)
installed_module_version = search_result.get('version', None)
if not url or (module_version is not None
and installed_module_version != module_version
) or (name != module_name):
if hub.HubServer()._server_check() is False:
tips = "Request Hub-Server unsuccessfully, please check your network."
return False, tips, None
module_versions_info = hub.HubServer().search_module_info(
module_name)
if module_versions_info is not None and len(
module_versions_info) > 0:
if utils.is_windows():
placeholders = [20, 8, 14, 14]
else:
placeholders = [30, 8, 16, 16]
tp = TablePrinter(
titles=[
"ResourceName", "Version", "PaddlePaddle",
"PaddleHub"
],
placeholders=placeholders)
module_versions_info.sort(
key=cmp_to_key(utils.sort_version_key))
for resource_name, resource_version, paddle_version, \
hub_version in module_versions_info:
colors = ["yellow", None, None, None]
tp.add_line(
contents=[
resource_name, resource_version,
utils.strflist_version(paddle_version),
utils.strflist_version(hub_version)
],
colors=colors)
tips = "The version of PaddlePaddle or PaddleHub " \
"can not match module, please upgrade your " \
"PaddlePaddle or PaddleHub according to the form " \
"below." + tp.get_text()
else:
tips = "Can't find module %s" % module_name
if module_version:
tips += " with version %s" % module_version
return False, tips, None
result, tips, module_zip_file = default_downloader.download_file(
url=url,
save_path=_dir,
save_name=module_name,
replace=True,
print_progress=True)
result, tips, module_dir = default_downloader.uncompress(
file=module_zip_file,
dirname=MODULE_HOME,
delete_file=True,
print_progress=True)
if module_package:
with tarfile.open(module_package, "r:gz") as tar:
file_names = tar.getnames()
size = len(file_names) - 1
module_dir = os.path.join(_dir, file_names[0])
for index, file_name in enumerate(file_names):
tar.extract(file_name, _dir)
if module_dir:
if not module_name:
module_name = hub.Module(directory=module_dir).name
self.all_modules(update=False)
module_info = self.modules_dict.get(module_name, None)
if module_info:
module_dir = self.modules_dict[module_name][0]
module_tag = module_name if not module_version else '%s-%s' % (
module_name, module_version)
......@@ -100,114 +185,27 @@ class LocalModuleManager(object):
module_dir)
return True, tips, self.modules_dict[module_name]
search_result = hub.HubServer().get_module_url(
module_name, version=module_version, extra=extra)
name = search_result.get('name', None)
url = search_result.get('url', None)
md5_value = search_result.get('md5', None)
installed_module_version = search_result.get('version', None)
if not url or (module_version is not None
and installed_module_version != module_version) or (
name != module_name):
if hub.HubServer()._server_check() is False:
tips = "Request Hub-Server unsuccessfully, please check your network."
return False, tips, None
module_versions_info = hub.HubServer().search_module_info(
module_name)
if module_versions_info is not None and len(
module_versions_info) > 0:
if utils.is_windows():
placeholders = [20, 8, 14, 14]
else:
placeholders = [30, 8, 16, 16]
tp = TablePrinter(
titles=[
"ResourceName", "Version", "PaddlePaddle",
"PaddleHub"
],
placeholders=placeholders)
module_versions_info.sort(
key=cmp_to_key(utils.sort_version_key))
for resource_name, resource_version, paddle_version, \
hub_version in module_versions_info:
colors = ["yellow", None, None, None]
tp.add_line(
contents=[
resource_name, resource_version,
utils.strflist_version(paddle_version),
utils.strflist_version(hub_version)
],
colors=colors)
tips = "The version of PaddlePaddle or PaddleHub " \
"can not match module, please upgrade your " \
"PaddlePaddle or PaddleHub according to the form " \
"below." + tp.get_text()
if module_dir:
if md5_value:
with open(
os.path.join(MODULE_HOME, module_dir, "md5.txt"),
"w") as fp:
fp.write(md5_value)
save_path = os.path.join(MODULE_HOME, module_name)
if os.path.exists(save_path):
shutil.rmtree(save_path)
if from_user_dir:
shutil.copytree(module_dir, save_path)
else:
tips = "Can't find module %s" % module_name
if module_version:
tips += " with version %s" % module_version
return False, tips, None
result, tips, module_zip_file = default_downloader.download_file(
url=url,
save_path=hub.CACHE_HOME,
save_name=module_name,
replace=True,
print_progress=True)
result, tips, module_dir = default_downloader.uncompress(
file=module_zip_file,
dirname=MODULE_HOME,
delete_file=True,
print_progress=True)
if module_package:
with tarfile.open(module_package, "r:gz") as tar:
file_names = tar.getnames()
size = len(file_names) - 1
module_dir = os.path.split(file_names[0])[1]
module_dir = os.path.join(hub.CACHE_HOME, module_dir)
# remove cache
if os.path.exists(module_dir):
shutil.rmtree(module_dir)
for index, file_name in enumerate(file_names):
tar.extract(file_name, hub.CACHE_HOME)
if module_dir:
if not module_name:
module_name = hub.Module(directory=module_dir).name
self.all_modules(update=False)
module_info = self.modules_dict.get(module_name, None)
if module_info:
module_dir = self.modules_dict[module_name][0]
module_tag = module_name if not module_version else '%s-%s' % (
module_name, module_version)
tips = "Module %s already installed in %s" % (module_tag,
module_dir)
return True, tips, self.modules_dict[module_name]
if module_dir:
if md5_value:
with open(
os.path.join(MODULE_HOME, module_dir, "md5.txt"),
"w") as fp:
fp.write(md5_value)
save_path = os.path.join(MODULE_HOME, module_name)
if os.path.exists(save_path):
shutil.move(save_path)
if from_user_dir:
shutil.copytree(module_dir, save_path)
else:
shutil.move(module_dir, save_path)
module_dir = save_path
tips = "Successfully installed %s" % module_name
if installed_module_version:
tips += "-%s" % installed_module_version
return True, tips, (module_dir, installed_module_version)
tips = "Download %s-%s failed" % (module_name, module_version)
return False, tips, module_dir
shutil.move(module_dir, save_path)
module_dir = save_path
tips = "Successfully installed %s" % module_name
if installed_module_version:
tips += "-%s" % installed_module_version
return True, tips, (module_dir, installed_module_version)
tips = "Download %s-%s failed" % (module_name, module_version)
return False, tips, module_dir
def uninstall_module(self, module_name, module_version=None):
self.all_modules(update=True)
......
......@@ -120,9 +120,10 @@ def runable(func):
class Module(object):
def __new__(cls, name=None, directory=None, module_dir=None, version=None):
module = None
_record = {}
def __new__(cls, name=None, directory=None, module_dir=None, version=None):
if cls.__name__ == "Module":
if name:
module = cls.init_with_name(name=name, version=version)
......@@ -139,17 +140,18 @@ class Module(object):
else:
directory = module_dir
module = cls.init_with_directory(directory=directory)
if not module:
module = object.__new__(cls)
else:
CacheUpdater("update_cache", module.name, module.version).start()
else:
module = object.__new__(cls)
return module
def __init__(self, name=None, directory=None, module_dir=None,
version=None):
if not directory:
# Avoid module being initialized multiple times
if not directory or id(self) in Module._record:
return
Module._record[id(self)] = True
mod = self.__class__.__module__ + "." + self.__class__.__name__
if mod in _module_runable_func:
......
......@@ -170,7 +170,7 @@ class WSSPTokenizer(object):
self.inv_vocab = {v: k for k, v in self.vocab.items()}
self.ws = ws
self.lower = lower
self.dict = pickle.load(open(word_dict, 'rb'), encoding='utf8')
self.dict = pickle.load(open(word_dict, 'rb'))
self.sp_model = spm.SentencePieceProcessor()
self.window_size = 5
self.sp_model.Load(sp_model_dir)
......
......@@ -133,7 +133,7 @@ def predict_gan(module, input_img, id, batch_size, extra={}):
def predict_object_detection(module, input_img, id, batch_size, extra={}):
output_folder = "output"
output_folder = "detection_result"
global use_gpu
method_name = module.desc.attr.map.data['default_signature'].s
predict_method = getattr(module, method_name)
......
......@@ -115,7 +115,7 @@
+ 'id="file_text"'
+ 'onblur="blur_input_text()"'
+ 'onfocus="focus_input_text()"'
+ 'name="input_text">'
+ 'name="text">'
+ '在此键入文本或上传文本文件'
+ '</textarea>'
+ '</td>'
......@@ -237,14 +237,15 @@
alert("Connection error:"+request.error);
},
success: function(data) {
html = get_result_html(data["result"]);
console.log(data);
html = get_result_html(data["results"]);
document.getElementById("result_text").value = html;
}
});
}
function sub_img() {
var formParam = {
"input_img": document.getElementById("file_img").src,
"image": document.getElementById("file_img").src,
"input_file":document.getElementById("file").value
};
to_url = "/predict/image/" + document.getElementById("inputGroupSelect02").value;
......@@ -258,9 +259,13 @@
alert("Connection error:"+request.error);
},
success: function(data) {
data = data["result"];
document.getElementById("result_text").value = data["desc"];
document.getElementById("result_img").src = data["output_img"];
data = data.results;
data = data.replace(/'/g, '"');
data = JSON.parse(data);
data = data[0];
document.getElementById("result_text").value = JSON.stringify(data.data[0]);
document.getElementById("result_img").src = data.base64;
}
});
}
......
......@@ -3,30 +3,22 @@
{
"module": "lac",
"version": "1.0.0",
"batch_size": 200,
"queue_size": 200,
"category": "NLP"
"batch_size": 200
},
{
"module": "senta_lstm",
"version": "1.0.0",
"batch_size": 1,
"queue_size": 200,
"category": "NLP"
"batch_size": 1
},
{
"module": "yolov3_darknet53_coco2017",
"version": "1.0.0",
"batch_size": 1,
"queue_size": 10,
"category": "CV"
"batch_size": 1
},
{
"module": "faster_rcnn_coco2017",
"version": "1.0.0",
"batch_size": 1,
"queue_size": 10,
"category": "CV"
"batch_size": 1
}
],
"use_gpu": false,
......
......@@ -25,4 +25,7 @@ pandas ; python_version >= "3"
pandas < 0.25.0 ; python_version < "3"
# gunicorn not support windows
gunicorn >= 19.10.0; sys_platform == "darwin" or sys_platform == "linux"
gunicorn >= 19.10.0; sys_platform != "win32"
# moviepy 1.0.1 not support imageio>2.5
moviepy < 1.0.0 ; python_version < "3"
# Bert Service
## 简介
### 什么是Bert Service
`Bert Service`是基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)框架的快速部署模型远程计算服务方案,可将embedding过程通过调用API接口的方式实现,减少了对机器资源的依赖。使用PaddleHub可在服务器上一键部署`Bert Service`服务,在另外的普通机器上通过客户端接口即可轻松的获取文本对应的embedding数据。
整体流程图如下:
<div align="center">
<img src="../docs/imgs/bs.png" aligh="center" width="100%" alt="BS流程图" />
</div>
### 为什么使用Bert Service
* 算力有限的集群环境中,可利用一台或几台高性能机器部署`Bert Service`服务端,为全部机器提供在线embedding功能。
* 实际的生产服务器不适宜承担大批量embedding工作,通过API接口可减少资源占用。
* 专注下游深度学习任务,可利用PaddleHub的`Bert Service`大幅减少embedding代码。
`Bert Service`具有几个突出的优点:
* 代码精短,易于使用。简单的pip安装方式,服务端仅需一行命令即可启动,客户端仅需一行代码即可获取embedding结果。
* 更高性能,更高效率。通过Paddle AnalysisPredictor API对模型的计算图进行优化,提升了计算速度并减小了显存占用。
* 随"机"应变,灵活扩展。可根据机器资源选择不同数量的服务端,并根据实际需求快速、灵活地进行增减,同时支持各张显卡执行不同的模型计算任务。
* 删繁就简,专注任务。`Bert Service`基于PaddlePaddle和PaddleHub开发,将模型的下载和安装等管理工作交由PaddleHub,开发者可以专注于主要任务,还可以无缝对接PaddleHub继续进行文本分类、序列标注等下游任务。
使用Bert Service搭建服务主要分为下面三个步骤:
## Step1:准备环境
### 环境要求
下表是使用`Bert Service`的环境要求,带有*号标志项为非必需依赖,可根据实际使用需求选择安装。
|项目|版本|说明|
|:-:|:-:|:-:|
|操作系统|Linux|目前仅支持Linux操作系统|
|PaddleHub|>=1.4.0|无|
|PaddlePaddle|>=1.6.1|若使用GPU计算,则对应使用PaddlePaddle-gpu版本|
|GCC|>=4.8|无|
|CUDA*|>=8|若使用GPU,需使用CUDA8以上版本|
|paddle-gpu-serving*|>=0.8.2|在`Bert Service`服务端需依赖此包|
|ujson*|>=1.35|在`Bert Service`客户端需依赖此包|
### 安装步骤
a) 安装PaddlePaddle,利用pip下载CPU版本命令如下。GPU版本、Docker方式安装等其他更具体的安装过程见[开始使用PaddlePaddle](https://paddlepaddle.org.cn/install/quick)
```shell
$ # 安装paddlepaddle的CPU版本
$ pip install paddlepaddle
```
b) 安装PaddleHub
```shell
$ pip install paddlehub
```
c) server端,需另外安装`paddle-gpu-serving`,以获取快速部署服务的能力
```shell
$ pip install paddle-gpu-serving
```
d) client端,需另外安装ujson
```shell
$ pip install ujson
```
### 支持模型
目前`Bert Service`支持的语义模型如下表,可根据需要选择模型进行部署embedding服务,未来还将支持更多模型。
|模型|网络|
|:-|:-:|
|[ernie](https://paddlepaddle.org.cn/hubdetail?name=ERNIE&en_category=SemanticModel)|ERNIE|
|[ernie_tiny](https://paddlepaddle.org.cn/hubdetail?name=ernie_tiny&en_category=SemanticModel)|ERNIE|
|[ernie_v2_eng_large](https://paddlepaddle.org.cn/hubdetail?name=ernie_v2_eng_large&en_category=SemanticModel)|ERNIE|
|[ernie_v2_eng_base](https://paddlepaddle.org.cn/hubdetail?name=ernie_v2_eng_base&en_category=SemanticModel)|ERNIE|
|[roberta_wwm_ext_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=roberta_wwm_ext_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[roberta_wwm_ext_chinese_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=roberta_wwm_ext_chinese_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_wwm_ext_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_wwm_ext_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_uncased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_uncased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_uncased_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=bert_uncased_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_cased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_cased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_cased_L-24_H-1024_A-16](https://paddlepaddle.org.cn/hubdetail?name=bert_cased_L-24_H-1024_A-16&en_category=SemanticModel)|BERT|
|[bert_multi_cased_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_multi_cased_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
|[bert_chinese_L-12_H-768_A-12](https://paddlepaddle.org.cn/hubdetail?name=bert_chinese_L-12_H-768_A-12&en_category=SemanticModel)|BERT|
## Step2:启动服务端(server)
### 简介
server端接收client端发送的数据,执行模型计算过程并将计算结果返回给client端。
server端启动时会按照指定的模型名称从PaddleHub获取对应的模型文件进行加载,无需提前下载模型或指定模型路径,对模型的管理工作由PaddleHub负责。在加载模型后在指定的端口启动`BRPC`服务,保持端口监听,当接收到数据后便执行模型计算,并将计算结果通过`BRPC`返回并发送至client端。
### 启动
使用PaddleHub的命令行工具可一键启动`Bert Service`,命令如下:
```shell
$ hub serving start bert_service -m ernie_tiny -p 8866 --use_gpu --gpu 0
```
启动成功则显示
```shell
Server[baidu::paddle_serving::predictor::bert_service::BertServiceImpl] is serving on port=8866.
```
整个启动过程如下图:
<div align="center">
&emsp;&emsp;<img src="https://github.com/ShenYuhan/ml-python/blob/master/short_start_fast.gif" aligh="center" width="70%" alt="启动BS" />
</div>
其中各参数说明如下表:
<div align="center">
|参数|说明|是否必填|
|:--:|:--:|:----:|
|hub serving start bert_service|启动`Bert Service`服务端。|必填项|
|--module/-m|指定启动的模型,如果指定的模型不存在,则自动通过PaddleHub下载指定模型。|必填项|
|--port/-p|指定启动的端口,每个端口对应一个模型,可基于不同端口进行多次启动,以实现多个模型的服务部署。|必填项|
|--use_gpu|若指定此项则使用GPU进行工作,反之仅使用CPU。注意需安装GPU版本的PaddlePaddle。|非必填项,默认为不指定|
|--gpu|指定使用的GPU卡号,如未指定use_gpu则填写此项无效,每个服务对应一张卡,部署多个服务时需指定不同卡|非必填项,默认为0号显卡|
</div>
### 关闭
通过在启动服务端的命令行页面使用Ctrl+C终止`Bert Service`运行,关闭成功则显示:
```shell
Paddle Inference Server exit successfully!
```
## Step3:启动客户端(client)
### 简介
client端接收文本数据,并获取server端返回的模型计算的embedding结果。
client端利用PaddleHub的语义理解任务将原始文本按照不同模型的数据预处理方案将文本ID化,并生成对应的sentence type、position、input masks数据,将这些信息封装成json数据,通过http协议按照指定的IP端口信息发送至server端,等待并获取模型生成结果。
### 启动
服务端类BSClient初始化方法原型为:
```python
BSClient.__init__(self,
module_name,
server,
max_seq_len=20,
show_ids=False,
do_lower_case=True,
retry=3)
# 获取embedding方法原型为
BSClient.get_result(self, input_text)
```
其中各参数说明如下表:
|参数|说明|类型|样例|
|:--:|:--:|:--:|:--:|
|module_name|指定使用的模型名称|string|"ernie"|
|server|要访问的server地址,包括ip地址及端口号|string|"127.0.0.1:8866"|
|max_seq_len|计算时的样例长度,样例长度不足时采用补零策略,超出此参数则超出部分会被截断|int|128|
|show_ids|是否展现数据预处理后的样例信息,指定为True则显示样例信息,反之则不显示|bool|False|
|do_lower_case|是否将英文字母转换成小写,指定为True则将所有英文字母转换为小写,反之则保持原状|bool|True|
|retry|连接失败后的最大重试次数|int|3|
|input_text|输入文本,要获取embedding的原始文本|二维list类型,内部元素为string类型的文本|[['样例1'],['样例2']]|
## Demo——利用Bert Service部署ernie_tiny在线embedding服务
在这里,我们将展示一个实际场景中可能使用的demo,我们利用PaddleHub在一台GPU机器上部署`ernie_tiny`模型服务,并在另一台CPU机器上尝试访问,获取一首七言绝句的embedding。
### Step1:安装环境依赖
首先需要安装环境依赖,根据第2节内容分别在两台机器上安装相应依赖。
### Step2:启动Bert Service服务端
确保环境依赖安装正确后,在要部署服务的GPU机器上使用PaddleHub命令行工具启动`Bert Service`服务端,命令如下:
```shell
$ hub serving start bert_service -m ernie_tiny --use_gpu --gpu 0 --port 8866
```
启动成功后打印
```shell
Server[baidu::paddle_serving::predictor::bert_service::BertServiceImpl] is serving on port=8866.
```
这样就启动了`ernie_tiny`的在线服务,监听8866端口,并在0号GPU上进行任务。
### Step3:使用Bert Service客户端进行远程调用
部署好服务端后,就可以用普通机器作为客户端测试在线embedding功能。
首先导入客户端依赖。
```python
from paddlehub.serving.bert_serving import bs_client
```
接着启动并初始化`bert service`客户端`BSClient`(这里的server为虚拟地址,需根据自己实际ip设置)
```python
bc = bs_client.BSClient(module_name="ernie_tiny", server="127.0.0.1:8866")
```
然后输入文本信息。
```python
input_text = [["西风吹老洞庭波"], ["一夜湘君白发多"], ["醉后不知天在水"], ["满船清梦压星河"], ]
```
最后利用客户端接口`get_result`发送文本到服务端,以获取embedding结果。
```python
result = bc.get_result(input_text=input_text)
```
这样,就得到了embedding结果(此处只展示部分结果)。
```python
[[0.9993321895599361, 0.9994612336158751, 0.9999646544456481, 0.732795298099517, -0.34387934207916204, ... ]]
```
客户端代码demo文件见[示例](../paddlehub/serving/bert_serving/bert_service.py)
运行命令如下:
```shell
$ python bert_service_client.py
```
运行过程如下图:
<div align="center">
&emsp;&emsp;<img src="https://github.com/ShenYuhan/ml-python/blob/master/short_client_fast.gif" aligh="center" width="70%" alt="启动BS" />
</div>
### Step4:关闭Bert Service服务端
如要停止`Bert Service`服务端程序,可在其启动命令行页面使用Ctrl+C方式关闭,关闭成功会打印如下日志:
```shell
Paddle Inference Server exit successfully!
```
这样,我们就利用一台GPU机器就完成了`Bert Service`的部署,并利用另一台普通机器进行了测试,可见通过`Bert Service`能够方便地进行在线embedding服务的快速部署。
## 预训练模型一键服务部署
除了`Bert Service`外,PaddleHub Serving还具有预训练模型一键服务部署功能,能够将预训练模型快捷部署上线,对外提供可靠的在线预测服务,具体信息请参见[Module Serving](./serving.md)
## FAQ
Q : 如何在一台服务器部署多个模型?
A : 可通过多次启动`Bert Service`,分配不同端口实现。如果使用GPU,需要指定不同的显卡。如同时部署`ernie``bert_chinese_L-12_H-768_A-12`,分别执行命令如下:
```shell
$ hub serving start bert_service -m ernie -p 8866
$ hub serving start bert_service -m bert_chinese_L-12_H-768_A-12 -p 8867
```
Q : 启动时显示"Check out http://yq01-gpu-255-129-12-00.epc.baidu.com:8887 in web
browser.",这个页面有什么作用。
A : 这是`BRPC`的内置服务,主要用于查看请求数、资源占用等信息,可对server端性能有大致了解,具体信息可查看[BRPC内置服务](https://github.com/apache/incubator-brpc/blob/master/docs/cn/builtin_service.md)
Q : 为什么输入文本的格式为[["文本1"], ["文本2"], ],而不是["文本1", "文本2", ]?
A : 因为Bert模型可以对一轮对话生成向量表示,例如[["问题1","回答1"],["问题2","回答2"]],为了防止使用时混乱,每个样本使用一个list表示,一个样本list内部可以是1条string或2条string,如下面的文本:
```python
input_text = [
["你今天吃饭了吗","我已经吃过饭了"],
["今天天气怎么样","今天天气不错"],
]
```
# PaddleHub Serving模型一键服务部署
## 简介
### 为什么使用一键服务部署
使用PaddleHub能够快速进行模型预测,但开发者常面临本地预测过程迁移线上的需求。无论是对外开放服务端口,还是在局域网中搭建预测服务,都需要PaddleHub具有快速部署模型预测服务的能力。在这个背景下,模型一键服务部署工具——PaddleHub Serving应运而生。开发者通过一行命令即可快速启动一个模型预测在线服务,而无需关注网络框架选择和实现。
### 什么是一键服务部署
PaddleHub Serving是基于PaddleHub的一键模型服务部署工具,能够通过简单的Hub命令行工具轻松启动一个模型预测在线服务,前端通过Flask和Gunicorn完成网络请求的处理,后端直接调用PaddleHub预测接口,同时支持使用多进程方式利用多核提高并发能力,保证预测服务的性能。
### 支持模型
目前PaddleHub Serving支持对PaddleHub所有可直接预测的模型进行服务部署,包括`lac``senta_bilstm`等NLP类模型,以及`yolov3_darknet53_coco2017``vgg16_imagenet`等CV类模型,更多模型请参见[PaddleHub支持模型列表](https://paddlepaddle.org.cn/hublist)。未来还将支持开发者使用PaddleHub Fine-tune API得到的模型用于快捷服务部署。
### 所需环境
下表是使用PaddleHub Serving的环境要求及注意事项。
|项目|建议版本|说明|
|:-:|:-:|:-:|
|操作系统|Linux/Darwin/Windows|建议使用Linux或Darwin,对多线程启动方式支持性较好|
|PaddleHub|>=1.4.0|无|
|PaddlePaddle|>=1.6.1|若使用GPU计算,则对应使用PaddlePaddle-gpu版本|
## 使用
### Step1:启动服务端部署
PaddleHub Serving有两种启动方式,分别是使用命令行启动,以及使用配置文件启动。
#### 命令行命令启动
启动命令
```shell
$ hub serving start --modules [Module1==Version1, Module2==Version2, ...] \
--port XXXX \
--use_gpu \
--use_multiprocess
```
**参数**
|参数|用途|
|-|-|
|--modules/-m|PaddleHub Serving预安装模型,以多个Module==Version键值对的形式列出<br>*`当不指定Version时,默认选择最新版本`*|
|--port/-p|服务端口,默认为8866|
|--use_gpu|使用GPU进行预测,必须安装paddlepaddle-gpu|
|--use_multiprocess|是否启用并发方式,默认为单进程方式|
#### 配置文件启动
启动命令
```shell
$ hub serving start --config config.json
```
`config.json`格式如下:
```json
{
"modules_info": [
{
"module": "MODULE_NAME_1",
"version": "MODULE_VERSION_1",
"batch_size": "BATCH_SIZE_1"
},
{
"module": "MODULE_NAME_2",
"version": "MODULE_VERSION_2",
"batch_size": "BATCH_SIZE_2"
}
],
"use_gpu": false,
"port": 8866,
"use_multiprocess": false
}
```
**参数**
|参数|用途|
|-|-|
|--modules_info|PaddleHub Serving预安装模型,以字典列表形式列出,其中:<br>`module`为预测服务使用的模型名<br>`version`为预测模型的版本<br>`batch_size`为预测批次大小
|--use_gpu|使用GPU进行预测,必须安装paddlepaddle-gpu|
|--port/-p|服务端口,默认为8866|
|--use_multiprocess|是否启用并发方式,默认为单进程方式,推荐多核CPU机器使用此方式|
### Step2:访问服务端
在使用PaddleHub Serving部署服务端的模型预测服务后,就可以在客户端访问预测接口以获取结果了,接口url格式为:
http://0.0.0.0:8866/predict/<CATEGORY\>/\<MODULE>
其中,\<CATEGORY>为text或image,与模型种类对应,\<MODULE>为模型名。
通过发送一个POST请求,即可获取预测结果,下面我们将展示一个具体的demo,以说明使用PaddleHub Serving部署和使用流程。
### Step3:利用PaddleHub Serving进行个性化开发
使用PaddleHub Serving进行模型服务部署后,可以利用得到的接口进行开发,如对外提供web服务,或接入到应用程序中,以降低客户端预测压力,提高性能,下面展示了一个web页面demo:
<p align="center">
<img src="../docs/imgs/web_demo.png" width="60%" />
</p>
## Demo——部署一个在线lac分词服务
### Step1:部署lac在线服务
现在,我们要部署一个lac在线服务,以通过接口获取文本的分词结果。
首先,任意选择一种启动方式,两种方式分别为:
```shell
$ hub serving start -m lac
```
```shell
$ hub serving start -c serving_config.json
```
其中`serving_config.json`的内容如下:
```json
{
"modules_info": [
{
"module": "lac",
"version": "1.0.0",
"batch_size": 1
}
],
"use_gpu": false,
"port": 8866,
"use_multiprocess": false
}
```
启动成功界面如图:
<p align="center">
<img src="../docs/imgs/start_serving_lac.png" width="100%" />
</p>
这样我们就在8866端口部署了lac的在线分词服务。
*此处warning为Flask提示,不影响使用*
### Step2:访问lac预测接口
在服务部署好之后,我们可以进行测试,用来测试的文本为`今天是个好日子``天气预报说今天要下雨`
客户端代码如下
```python
# coding: utf8
import requests
import json
if __name__ == "__main__":
# 指定用于用于预测的文本并生成字典{"text": [text_1, text_2, ... ]}
text_list = ["今天是个好日子", "天气预报说今天要下雨"]
text = {"text": text_list}
# 指定预测方法为lac并发送post请求
url = "http://0.0.0.0:8866/predict/text/lac"
r = requests.post(url=url, data=text)
# 打印预测结果
print(json.dumps(r.json(), indent=4, ensure_ascii=False))
```
运行后得到结果
```python
{
"results": [
{
"tag": [
"TIME", "v", "q", "n"
],
"word": [
"今天", "是", "个", "好日子"
]
},
{
"tag": [
"n", "v", "TIME", "v", "v"
],
"word": [
"天气预报", "说", "今天", "要", "下雨"
]
}
]
}
```
此Demo的具体信息和代码请参见[LAC Serving](../demo/serving/module_serving/lexical_analysis_lac)。另外,下面展示了一些其他的一键服务部署Demo。
## Demo——其他模型的一键部署服务
获取其他PaddleHub Serving的一键服务部署场景示例,可参见下列demo
* [图像分类-基于vgg11_imagent](../demo/serving/module_serving/classification_vgg11_imagenet)
&emsp;&emsp;该示例展示了利用vgg11_imagent完成图像分类服务化部署和在线预测,获取图像分类结果。
* [图像生成-基于stgan_celeba](../demo/serving/module_serving/GAN_stgan_celeba)
&emsp;&emsp;该示例展示了利用stgan_celeba生成图像服务化部署和在线预测,获取指定风格的生成图像。
* [文本审核-基于porn_detection_lstm](../demo/serving/module_serving/text_censorship_porn_detection_lstm)
&emsp;&emsp;该示例展示了利用porn_detection_lstm完成中文文本黄色敏感信息鉴定的服务化部署和在线预测,获取文本是否敏感及其置信度。
* [中文词法分析-基于lac](../demo/serving/module_serving/lexical_analysis_lac)
&emsp;&emsp;该示例展示了利用lac完成中文文本分词服务化部署和在线预测,获取文本的分词结果,并可通过用户自定义词典干预分词结果。
* [目标检测-基于yolov3_darknet53_coco2017](.../demo/serving/serving/object_detection_yolov3_darknet53_coco2017)
&emsp;&emsp;该示例展示了利用yolov3_darknet53_coco2017完成目标检测服务化部署和在线预测,获取检测结果和覆盖识别框的图片。
* [中文语义分析-基于simnet_bow](../demo/serving/module_serving/semantic_model_simnet_bow)
&emsp;&emsp;该示例展示了利用simnet_bow完成中文文本相似度检测服务化部署和在线预测,获取文本的相似程度。
* [图像分割-基于deeplabv3p_xception65_humanseg](../demo/serving/module_serving/semantic_segmentation_deeplabv3p_xception65_humanseg)
&emsp;&emsp;该示例展示了利用deeplabv3p_xception65_humanseg完成图像分割服务化部署和在线预测,获取识别结果和分割后的图像。
* [中文情感分析-基于simnet_bow](../demo/serving/module_serving/semantic_model_simnet_bow)
&emsp;&emsp;该示例展示了利用senta_lstm完成中文文本情感分析服务化部署和在线预测,获取文本的情感分析结果。
## Bert Service
除了预训练模型一键服务部署功能之外,PaddleHub Serving还具有`Bert Service`功能,支持ernie_tiny、bert等模型快速部署,对外提供可靠的在线embedding服务,具体信息请参见[Bert Service](./bert_service.md)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册